root/lib/libedit/TEST/wtc1.c
#include <sys/wait.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <limits.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "../histedit.h"


static int continuation;
volatile sig_atomic_t gotsig;
static const char hfile[] = ".whistory";

static wchar_t *
prompt(EditLine *el)
{
        static wchar_t a[] = L"\1\033[7m\1Edit$\1\033[0m\1 ";
        static wchar_t b[] = L"Edit> ";

        return continuation ? b : a;
}


static void
sig(int i)
{
        gotsig = i;
}

const char *
my_wcstombs(const wchar_t *wstr)
{
        static struct {
                char *str;
                int len;
        } buf;

        int needed = wcstombs(0, wstr, 0) + 1;
        if (needed > buf.len) {
                buf.str = malloc(needed);
                buf.len = needed;
        }
        wcstombs(buf.str, wstr, needed);
        buf.str[needed - 1] = 0;

        return buf.str;
}


static unsigned char
complete(EditLine *el, int ch)
{
        DIR *dd = opendir(".");
        struct dirent *dp;
        const wchar_t *ptr;
        char *buf, *bptr;
        const LineInfoW *lf = el_wline(el);
        int len, mblen, i;
        unsigned char res = 0;
        wchar_t dir[1024];

        /* Find the last word */
        for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr)
                continue;
        len = lf->cursor - ++ptr;

        /* Convert last word to multibyte encoding, so we can compare to it */
        wctomb(NULL, 0); /* Reset shift state */
        mblen = MB_LEN_MAX * len + 1;
        buf = bptr = malloc(mblen);
        if (buf == NULL)
                err(1, "malloc");
        for (i = 0; i < len; ++i) {
                /* Note: really should test for -1 return from wctomb */
                bptr += wctomb(bptr, ptr[i]);
        }
        *bptr = 0; /* Terminate multibyte string */
        mblen = bptr - buf;

        /* Scan directory for matching name */
        for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
                if (mblen > strlen(dp->d_name))
                        continue;
                if (strncmp(dp->d_name, buf, mblen) == 0) {
                        mbstowcs(dir, &dp->d_name[mblen],
                            sizeof(dir) / sizeof(*dir));
                        if (el_winsertstr(el, dir) == -1)
                                res = CC_ERROR;
                        else
                                res = CC_REFRESH;
                        break;
                }
        }

        closedir(dd);
        free(buf);
        return res;
}


int
main(int argc, char *argv[])
{
        EditLine *el = NULL;
        int numc, ncontinuation;
        const wchar_t *line;
        TokenizerW *tok;
        HistoryW *hist;
        HistEventW ev;
#ifdef DEBUG
        int i;
#endif

        setlocale(LC_ALL, "");

        (void)signal(SIGINT,  sig);
        (void)signal(SIGQUIT, sig);
        (void)signal(SIGHUP,  sig);
        (void)signal(SIGTERM, sig);

        hist = history_winit();         /* Init built-in history     */
        history_w(hist, &ev, H_SETSIZE, 100);   /* Remember 100 events       */
        history_w(hist, &ev, H_LOAD, hfile);

        tok = tok_winit(NULL);                  /* Init the tokenizer        */

        el = el_init(argv[0], stdin, stdout, stderr);

        el_wset(el, EL_EDITOR, L"vi");          /* Default editor is vi      */
        el_wset(el, EL_SIGNAL, 1);              /* Handle signals gracefully */
        el_wset(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */

        el_wset(el, EL_HIST, history_w, hist);  /* FIXME - history_w? */

                                        /* Add a user-defined function  */
        el_wset(el, EL_ADDFN, L"ed-complete", L"Complete argument", complete);

                                        /* Bind <tab> to it */
        el_wset(el, EL_BIND, L"^I", L"ed-complete", NULL);

        /*
        * Bind j, k in vi command mode to previous and next line, instead
        * of previous and next history.
        */
        el_wset(el, EL_BIND, L"-a", L"k", L"ed-prev-line", NULL);
        el_wset(el, EL_BIND, L"-a", L"j", L"ed-next-line", NULL);

        /* Source the user's defaults file. */
        el_source(el, NULL);

        while((line = el_wgets(el, &numc)) != NULL && numc != 0) {
                int ac, cc, co, rc;
                const wchar_t **av;

                const LineInfoW *li;
                li = el_wline(el);

#ifdef DEBUG
                (void)fwprintf(stderr, L"==> got %d %ls", numc, line);
                (void)fwprintf(stderr, L"  > li `%.*ls_%.*ls'\n",
                    (li->cursor - li->buffer), li->buffer,
                    (li->lastchar - 1 - li->cursor),
                    (li->cursor >= li->lastchar) ? L"" : li->cursor);
#endif

                if (gotsig) {
                        (void)fprintf(stderr, "Got signal %d.\n", (int)gotsig);
                        gotsig = 0;
                        el_reset(el);
                }

                if(!continuation && numc == 1)
                        continue;       /* Only got a linefeed */

                ac = cc = co = 0;
                ncontinuation = tok_wline(tok, li, &ac, &av, &cc, &co);
                if (ncontinuation < 0) {
                        (void) fprintf(stderr, "Internal error\n");
                        continuation = 0;
                        continue;
                }

#ifdef DEBUG
                (void)fprintf(stderr, "  > nc %d ac %d cc %d co %d\n",
                        ncontinuation, ac, cc, co);
#endif
                history_w(hist, &ev, continuation ? H_APPEND : H_ENTER, line);

                continuation = ncontinuation;
                ncontinuation = 0;
                if(continuation)
                        continue;

#ifdef DEBUG
                for (i = 0; i < ac; ++i) {
                        (void)fwprintf(stderr, L"  > arg# %2d ", i);
                        if (i != cc)
                                (void)fwprintf(stderr, L"`%ls'\n", av[i]);
                        else
                                (void)fwprintf(stderr, L"`%.*ls_%ls'\n",
                                    co, av[i], av[i] + co);
                }
#endif

                if (wcscmp (av[0], L"history") == 0) {
                        switch(ac) {
                        case 1:
                                for(rc = history_w(hist, &ev, H_LAST);
                                     rc != -1;
                                     rc = history_w(hist, &ev, H_PREV))
                                        (void)fwprintf(stdout, L"%4d %ls",
                                             ev.num, ev.str);
                                break;
                        case 2:
                                if (wcscmp(av[1], L"clear") == 0)
                                        history_w(hist, &ev, H_CLEAR);
                                else
                                        goto badhist;
                                break;
                        case 3:
                                if (wcscmp(av[1], L"load") == 0)
                                        history_w(hist, &ev, H_LOAD,
                                            my_wcstombs(av[2]));
                                else if (wcscmp(av[1], L"save") == 0)
                                        history_w(hist, &ev, H_SAVE,
                                            my_wcstombs(av[2]));
                                else
                                        goto badhist;
                                break;
                        badhist:
                        default:
                                (void)fprintf(stderr,
                                    "Bad history arguments\n");
                                break;
                        }
                } else if (el_wparse(el, ac, av) == -1) {
                        switch (fork()) {
                        case 0: {
                                Tokenizer *ntok = tok_init(NULL);
                                int nargc;
                                const char **nav;
                                tok_str(ntok, my_wcstombs(line), &nargc, &nav);
                                execvp(nav[0],(char **)nav);
                                perror(nav[0]);
                                _exit(1);
                                /* NOTREACHED */
                                break;
                        }
                        case -1:
                                perror("fork");
                                break;
                        default:
                                if (wait(&rc) == -1)
                                        perror("wait");
                                (void)fprintf(stderr, "Exit %x\n", rc);
                                break;
                        }
                }

                tok_wreset(tok);
        }

        el_end(el);
        tok_wend(tok);
        history_w(hist, &ev, H_SAVE, hfile);
        history_wend(hist);

        fprintf(stdout, "\n");
        return 0;
}