#include #include #include #include #include #include #include #include #include #include #include #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 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; }