From 75d35a370343c1fb6f274d4631225321e727287f Mon Sep 17 00:00:00 2001 From: "David E. O'Brien" Date: Thu, 31 Mar 2011 01:13:05 +0000 Subject: [PATCH] Vendor import NetBSD's libedit of "2005/08/02 12:11:14 UTC". Obtained from: NetBSD --- Makefile | 75 +- TEST/Makefile | 13 + TEST/test.c | 87 ++- chared.c | 342 +++++---- chared.h | 55 +- common.c | 218 +++--- config.h | 18 + editline.3 | 191 ++++- editrc.5 | 44 +- el.c | 108 ++- el.h | 31 +- emacs.c | 109 +-- filecomplete.c | 539 ++++++++++++++ filecomplete.h | 51 ++ hist.c | 64 +- hist.h | 12 +- histedit.h | 57 +- history.c | 268 +++++-- key.c | 53 +- key.h | 23 +- makelist | 10 +- map.c | 317 +++++---- map.h | 10 +- parse.c | 41 +- parse.h | 10 +- prompt.c | 19 +- prompt.h | 8 +- read.c | 177 +++-- read.h | 4 +- readline.c | 1625 +++++++++++++++++++++++-------------------- readline/Makefile | 14 +- readline/readline.h | 91 ++- refresh.c | 54 +- refresh.h | 8 +- search.c | 207 +++--- search.h | 14 +- shlib_version | 4 +- sig.c | 19 +- sig.h | 11 +- sys.h | 54 +- term.c | 81 ++- term.h | 29 +- tokenizer.c | 131 ++-- tokenizer.h | 54 -- tty.c | 160 ++++- tty.h | 16 +- vi.c | 826 +++++++++++++--------- 47 files changed, 4022 insertions(+), 2330 deletions(-) create mode 100644 TEST/Makefile create mode 100644 config.h create mode 100644 filecomplete.c create mode 100644 filecomplete.h delete mode 100644 tokenizer.h diff --git a/Makefile b/Makefile index 837ed0e044df..2d902bef676f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,15 @@ -# $NetBSD: Makefile,v 1.20 2001/01/05 21:15:49 jdolecek Exp $ +# $NetBSD: Makefile,v 1.34 2005/05/28 12:02:53 lukem Exp $ # @(#)Makefile 8.1 (Berkeley) 6/4/93 +USE_SHLIBDIR= yes + +WARNS= 3 LIB= edit -OSRCS= chared.c common.c el.c emacs.c fcns.c help.c hist.c key.c map.c \ +LIBDPLIBS= termcap ${.CURDIR}/../libterm + +OSRCS= chared.c common.c el.c emacs.c fcns.c filecomplete.c help.c hist.c \ + key.c map.c \ parse.c prompt.c read.c refresh.c search.c sig.c term.c tty.c vi.c MAN= editline.3 editrc.5 @@ -13,75 +19,86 @@ MLINKS= editline.3 el_init.3 editline.3 el_end.3 editline.3 el_reset.3 \ editline.3 el_parse.3 editline.3 el_set.3 editline.3 el_get.3 \ editline.3 el_source.3 editline.3 el_resize.3 editline.3 el_line.3 \ editline.3 el_insertstr.3 editline.3 el_deletestr.3 \ - editline.3 history_init.3 editline.3 history_end.3 editline.3 history.3 + editline.3 history_init.3 editline.3 history_end.3 \ + editline.3 history.3 \ + editline.3 tok_init.3 editline.3 tok_end.3 editline.3 tok_reset.3 \ + editline.3 tok_line.3 editline.3 tok_str.3 # For speed and debugging #SRCS= ${OSRCS} tokenizer.c history.c readline.c # For protection SRCS= editline.c tokenizer.c history.c readline.c -SRCS+= common.h emacs.h fcns.h help.h vi.h - LIBEDITDIR?=${.CURDIR} INCS= histedit.h INCSDIR=/usr/include -CLEANFILES+=common.h editline.c emacs.h fcns.c fcns.h help.c help.h vi.h +CLEANFILES+=editline.c CLEANFILES+=common.h.tmp editline.c.tmp emacs.h.tmp fcns.c.tmp fcns.h.tmp CLEANFILES+=help.c.tmp help.h.tmp vi.h.tmp +CLEANFILES+=test.o test CPPFLAGS+=-I. -I${LIBEDITDIR} CPPFLAGS+=-I. -I${.CURDIR} CPPFLAGS+=#-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH -CPPFLAGS+=#-DDEBUG_PASTE +CPPFLAGS+=#-DDEBUG_PASTE -DDEBUG_EDIT AHDR=vi.h emacs.h common.h ASRC=${LIBEDITDIR}/vi.c ${LIBEDITDIR}/emacs.c ${LIBEDITDIR}/common.c +DPSRCS+= ${AHDR} fcns.h help.h fcns.c help.c +CLEANFILES+= ${AHDR} fcns.h help.h fcns.c help.c + SUBDIR= readline -vi.h: vi.c makelist - sh ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/vi.c > ${.TARGET}.tmp && \ +vi.h: vi.c makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/vi.c \ + > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -emacs.h: emacs.c makelist - sh ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/emacs.c > ${.TARGET}.tmp && \ +emacs.h: emacs.c makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/emacs.c \ + > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -common.h: common.c makelist - sh ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/common.c > ${.TARGET}.tmp && \ +common.h: common.c makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -h ${LIBEDITDIR}/common.c \ + > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -fcns.h: ${AHDR} makelist - sh ${LIBEDITDIR}/makelist -fh ${AHDR} > ${.TARGET}.tmp && \ +fcns.h: ${AHDR} makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -fh ${AHDR} > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -fcns.c: ${AHDR} fcns.h makelist - sh ${LIBEDITDIR}/makelist -fc ${AHDR} > ${.TARGET}.tmp && \ +fcns.c: ${AHDR} fcns.h help.h makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -fc ${AHDR} > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -help.c: ${ASRC} makelist - sh ${LIBEDITDIR}/makelist -bc ${ASRC} > ${.TARGET}.tmp && \ +help.c: ${ASRC} makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -bc ${ASRC} > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -help.h: ${ASRC} makelist - sh ${LIBEDITDIR}/makelist -bh ${ASRC} > ${.TARGET}.tmp && \ +help.h: ${ASRC} makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -bh ${ASRC} > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} -editline.c: ${OSRCS} - sh ${LIBEDITDIR}/makelist -e ${.ALLSRC:T} > ${.TARGET}.tmp && \ +editline.c: ${OSRCS} makelist Makefile + ${_MKTARGET_CREATE} + ${HOST_SH} ${LIBEDITDIR}/makelist -e ${OSRCS:T} > ${.TARGET}.tmp && \ mv ${.TARGET}.tmp ${.TARGET} test.o: ${LIBEDITDIR}/TEST/test.c test: libedit.a test.o + ${_MKTARGET_LINK} ${CC} ${LDFLAGS} ${.ALLSRC} -o ${.TARGET} libedit.a ${LDADD} -ltermcap -# minimal dependency to make "make depend" optional -editline.o editline.po editline.so editline.ln: \ - common.h emacs.h fcns.c fcns.h help.c help.h vi.h -readline.o readline.po readline.so readline.ln: \ - common.h emacs.h fcns.h help.h vi.h - .include .include diff --git a/TEST/Makefile b/TEST/Makefile new file mode 100644 index 000000000000..0118710e7f7a --- /dev/null +++ b/TEST/Makefile @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.2 2003/12/05 13:37:48 lukem Exp $ + +NOMAN=1 +PROG=test +CPPFLAGS=-I${.CURDIR}/.. +LDADD+=-ledit -ltermcap +DPADD+=${LIBEDIT} ${LIBTERMCAP} + +.ifdef DEBUG +CPPFLAGS+=-DDEBUG +.endif + +.include diff --git a/TEST/test.c b/TEST/test.c index 267cccf21dae..f17897ff5c0e 100644 --- a/TEST/test.c +++ b/TEST/test.c @@ -1,4 +1,4 @@ -/* $NetBSD: test.c,v 1.9 2000/09/04 23:36:41 lukem Exp $ */ +/* $NetBSD: test.c,v 1.18 2005/06/01 11:37:52 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,7 +32,7 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #ifndef lint __COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\ The Regents of the University of California. All rights reserved.\n"); @@ -46,14 +42,13 @@ __COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\ #if 0 static char sccsid[] = "@(#)test.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: test.c,v 1.9 2000/09/04 23:36:41 lukem Exp $"); +__RCSID("$NetBSD: test.c,v 1.18 2005/06/01 11:37:52 lukem Exp $"); #endif #endif /* not lint && not SCCSID */ /* * test.c: A little test program */ -#include "sys.h" #include #include #include @@ -64,12 +59,11 @@ __RCSID("$NetBSD: test.c,v 1.9 2000/09/04 23:36:41 lukem Exp $"); #include #include "histedit.h" -#include "tokenizer.h" static int continuation = 0; -static EditLine *el = NULL; +volatile sig_atomic_t gotsig = 0; -static u_char complete(EditLine *, int); +static unsigned char complete(EditLine *, int); int main(int, char **); static char *prompt(EditLine *); static void sig(int); @@ -77,8 +71,8 @@ static void sig(int); static char * prompt(EditLine *el) { - static char a[] = "Edit$"; - static char b[] = "Edit>"; + static char a[] = "Edit$ "; + static char b[] = "Edit> "; return (continuation ? b : a); } @@ -86,9 +80,7 @@ prompt(EditLine *el) static void sig(int i) { - - (void) fprintf(stderr, "Got signal %d.\n", i); - el_reset(el); + gotsig = i; } static unsigned char @@ -103,7 +95,8 @@ complete(EditLine *el, int ch) /* * Find the last word */ - for (ptr = lf->cursor - 1; !isspace(*ptr) && ptr > lf->buffer; ptr--) + for (ptr = lf->cursor - 1; + !isspace((unsigned char)*ptr) && ptr > lf->buffer; ptr--) continue; len = lf->cursor - ++ptr; @@ -126,10 +119,14 @@ complete(EditLine *el, int ch) int main(int argc, char *argv[]) { + EditLine *el = NULL; int num; const char *buf; Tokenizer *tok; - int lastevent = 0, ncontinuation; +#if 0 + int lastevent = 0; +#endif + int ncontinuation; History *hist; HistEvent ev; @@ -173,17 +170,41 @@ main(int argc, char *argv[]) el_source(el, NULL); while ((buf = el_gets(el, &num)) != NULL && num != 0) { - int ac; - char **av; + int ac, cc, co; #ifdef DEBUG - (void) fprintf(stderr, "got %d %s", num, buf); + int i; #endif + const char **av; + const LineInfo *li; + li = el_line(el); +#ifdef DEBUG + (void) fprintf(stderr, "==> got %d %s", num, buf); + (void) fprintf(stderr, " > li `%.*s_%.*s'\n", + (li->cursor - li->buffer), li->buffer, + (li->lastchar - 1 - li->cursor), + (li->cursor >= li->lastchar) ? "" : li->cursor); + +#endif + if (gotsig) { + (void) fprintf(stderr, "Got signal %d.\n", gotsig); + gotsig = 0; + el_reset(el); + } + if (!continuation && num == 1) continue; - if (tok_line(tok, buf, &ac, &av) > 0) - ncontinuation = 1; - + ac = cc = co = 0; + ncontinuation = tok_line(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 #if 0 if (continuation) { /* @@ -191,7 +212,7 @@ main(int argc, char *argv[]) * moved around in history. */ if (history(hist, &ev, H_SET, lastevent) == -1) - err(1, "%d: %s\n", lastevent, ev.str); + err(1, "%d: %s", lastevent, ev.str); history(hist, &ev, H_ADD , buf); } else { history(hist, &ev, H_ENTER, buf); @@ -204,6 +225,18 @@ main(int argc, char *argv[]) continuation = ncontinuation; ncontinuation = 0; + if (continuation) + continue; +#ifdef DEBUG + for (i = 0; i < ac; i++) { + (void) fprintf(stderr, " > arg# %2d ", i); + if (i != cc) + (void) fprintf(stderr, "`%s'\n", av[i]); + else + (void) fprintf(stderr, "`%.*s_%s'\n", + co, av[i], av[i] + co); + } +#endif if (strcmp(av[0], "history") == 0) { int rv; @@ -239,7 +272,7 @@ main(int argc, char *argv[]) } else if (el_parse(el, ac, av) == -1) { switch (fork()) { case 0: - execvp(av[0], av); + execvp(av[0], (char *const *)__UNCONST(av)); perror(av[0]); _exit(1); /*NOTREACHED*/ diff --git a/chared.c b/chared.c index 790f8ffb9ae6..a3121da80259 100644 --- a/chared.c +++ b/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.14 2001/05/17 01:02:17 christos Exp $ */ +/* $NetBSD: chared.c,v 1.24 2005/08/01 23:00:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,23 +32,23 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: chared.c,v 1.14 2001/05/17 01:02:17 christos Exp $"); +__RCSID("$NetBSD: chared.c,v 1.24 2005/08/01 23:00:15 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * chared.c: Character editor utilities */ -#include "sys.h" - #include #include "el.h" +private void ch__clearmacro __P((EditLine *)); + /* value to leave unused in line buffer */ #define EL_LEAVE 2 @@ -60,17 +56,36 @@ __RCSID("$NetBSD: chared.c,v 1.14 2001/05/17 01:02:17 christos Exp $"); * Handle state for the vi undo command */ protected void -cv_undo(EditLine *el,int action, size_t size, char *ptr) +cv_undo(EditLine *el) { c_undo_t *vu = &el->el_chared.c_undo; - vu->action = action; - vu->ptr = ptr; - vu->isize = size; - (void) memcpy(vu->buf, vu->ptr, size); -#ifdef DEBUG_UNDO - (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n", - vu->ptr, vu->isize, vu->dsize); -#endif + c_redo_t *r = &el->el_chared.c_redo; + unsigned int size; + + /* Save entire line for undo */ + size = el->el_line.lastchar - el->el_line.buffer; + vu->len = size; + vu->cursor = el->el_line.cursor - el->el_line.buffer; + memcpy(vu->buf, el->el_line.buffer, size); + + /* save command info for redo */ + r->count = el->el_state.doingarg ? el->el_state.argument : 0; + r->action = el->el_chared.c_vcmd.action; + r->pos = r->buf; + r->cmd = el->el_state.thiscmd; + r->ch = el->el_state.thisch; +} + +/* cv_yank(): + * Save yank/delete data for paste + */ +protected void +cv_yank(EditLine *el, const char *ptr, int size) +{ + c_kill_t *k = &el->el_chared.c_kill; + + memcpy(k->buf, ptr, size +0u); + k->last = k->buf + size; } @@ -82,8 +97,10 @@ c_insert(EditLine *el, int num) { char *cp; - if (el->el_line.lastchar + num >= el->el_line.limit) - return; /* can't go past end of buffer */ + if (el->el_line.lastchar + num >= el->el_line.limit) { + if (!ch_enlargebufs(el, num +0u)) + return; /* can't go past end of buffer */ + } if (el->el_line.cursor < el->el_line.lastchar) { /* if I must move chars */ @@ -104,12 +121,14 @@ c_delafter(EditLine *el, int num) if (el->el_line.cursor + num > el->el_line.lastchar) num = el->el_line.lastchar - el->el_line.cursor; + if (el->el_map.current != el->el_map.emacs) { + cv_undo(el); + cv_yank(el, el->el_line.cursor, num); + } + if (num > 0) { char *cp; - if (el->el_map.current != el->el_map.emacs) - cv_undo(el, INSERT, (size_t)num, el->el_line.cursor); - for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) *cp = cp[num]; @@ -118,6 +137,21 @@ c_delafter(EditLine *el, int num) } +/* c_delafter1(): + * Delete the character after the cursor, do not yank + */ +protected void +c_delafter1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* c_delbefore(): * Delete num characters before the cursor */ @@ -128,13 +162,14 @@ c_delbefore(EditLine *el, int num) if (el->el_line.cursor - num < el->el_line.buffer) num = el->el_line.cursor - el->el_line.buffer; + if (el->el_map.current != el->el_map.emacs) { + cv_undo(el); + cv_yank(el, el->el_line.cursor - num, num); + } + if (num > 0) { char *cp; - if (el->el_map.current != el->el_map.emacs) - cv_undo(el, INSERT, (size_t)num, - el->el_line.cursor - num); - for (cp = el->el_line.cursor - num; cp <= el->el_line.lastchar; cp++) @@ -145,13 +180,28 @@ c_delbefore(EditLine *el, int num) } +/* c_delbefore1(): + * Delete the character before the cursor, do not yank + */ +protected void +c_delbefore1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* ce__isword(): * Return if p is part of a word according to emacs */ protected int ce__isword(int p) { - return (isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL); + return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL); } @@ -160,6 +210,20 @@ ce__isword(int p) */ protected int cv__isword(int p) +{ + if (isalnum(p) || p == '_') + return 1; + if (isgraph(p)) + return 2; + return 0; +} + + +/* cv__isWord(): + * Return if p is part of a big word according to vi + */ +protected int +cv__isWord(int p) { return (!isspace(p)); } @@ -223,7 +287,7 @@ cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int)) * vi historically deletes with cw only the word preserving the * trailing whitespace! This is not what 'w' does.. */ - if (el->el_chared.c_vcmd.action != (DELETE|INSERT)) + if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT)) while ((p < high) && isspace((unsigned char) *p)) p++; } @@ -240,26 +304,19 @@ cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int)) * Find the previous word vi style */ protected char * -cv_prev_word(EditLine *el, char *p, char *low, int n, int (*wtest)(int)) +cv_prev_word(char *p, char *low, int n, int (*wtest)(int)) { int test; + p--; while (n--) { - p--; - /* - * vi historically deletes with cb only the word preserving the - * leading whitespace! This is not what 'b' does.. - */ - if (el->el_chared.c_vcmd.action != (DELETE|INSERT)) - while ((p > low) && isspace((unsigned char) *p)) - p--; + while ((p > low) && isspace((unsigned char) *p)) + p--; test = (*wtest)((unsigned char) *p); while ((p >= low) && (*wtest)((unsigned char) *p) == test) p--; - p++; - while (isspace((unsigned char) *p)) - p++; } + p++; /* p now points where we want it */ if (p < low) @@ -310,47 +367,34 @@ protected void cv_delfini(EditLine *el) { int size; - int oaction; + int action = el->el_chared.c_vcmd.action; - if (el->el_chared.c_vcmd.action & INSERT) + if (action & INSERT) el->el_map.current = el->el_map.key; - oaction = el->el_chared.c_vcmd.action; - el->el_chared.c_vcmd.action = NOP; - if (el->el_chared.c_vcmd.pos == 0) + /* sanity */ return; - - if (el->el_line.cursor > el->el_chared.c_vcmd.pos) { - size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos); - c_delbefore(el, size); - el->el_line.cursor = el->el_chared.c_vcmd.pos; - re_refresh_cursor(el); - } else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) { - size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor); - c_delafter(el, size); - } else { + size = el->el_line.cursor - el->el_chared.c_vcmd.pos; + if (size == 0) size = 1; - c_delafter(el, size); + el->el_line.cursor = el->el_chared.c_vcmd.pos; + if (action & YANK) { + if (size > 0) + cv_yank(el, el->el_line.cursor, size); + else + cv_yank(el, el->el_line.cursor + size, -size); + } else { + if (size > 0) { + c_delafter(el, size); + re_refresh_cursor(el); + } else { + c_delbefore(el, -size); + el->el_line.cursor += size; + } } - switch (oaction) { - case DELETE|INSERT: - el->el_chared.c_undo.action = DELETE|INSERT; - break; - case DELETE: - el->el_chared.c_undo.action = INSERT; - break; - case NOP: - case INSERT: - default: - EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction)); - break; - } - - - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.dsize = size; + el->el_chared.c_vcmd.action = NOP; } @@ -380,21 +424,19 @@ ce__endword(char *p, char *high, int n) * Go to the end of this word according to vi */ protected char * -cv__endword(char *p, char *high, int n) +cv__endword(char *p, char *high, int n, int (*wtest)(int)) { + int test; + p++; while (n--) { while ((p < high) && isspace((unsigned char) *p)) p++; - if (isalnum((unsigned char) *p)) - while ((p < high) && isalnum((unsigned char) *p)) - p++; - else - while ((p < high) && !(isspace((unsigned char) *p) || - isalnum((unsigned char) *p))) - p++; + test = (*wtest)((unsigned char) *p); + while ((p < high) && (*wtest)((unsigned char) *p) == test) + p++; } p--; return (p); @@ -406,6 +448,8 @@ cv__endword(char *p, char *high, int n) protected int ch_init(EditLine *el) { + c_macro_t *ma = &el->el_chared.c_macro; + el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ); if (el->el_line.buffer == NULL) return (-1); @@ -413,20 +457,23 @@ ch_init(EditLine *el) (void) memset(el->el_line.buffer, 0, EL_BUFSIZ); el->el_line.cursor = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer; - el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2]; + el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ); if (el->el_chared.c_undo.buf == NULL) return (-1); (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ); - el->el_chared.c_undo.action = NOP; - el->el_chared.c_undo.isize = 0; - el->el_chared.c_undo.dsize = 0; - el->el_chared.c_undo.ptr = el->el_line.buffer; + el->el_chared.c_undo.len = -1; + el->el_chared.c_undo.cursor = 0; + el->el_chared.c_redo.buf = (char *) el_malloc(EL_BUFSIZ); + if (el->el_chared.c_redo.buf == NULL) + return (-1); + el->el_chared.c_redo.pos = el->el_chared.c_redo.buf; + el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ; + el->el_chared.c_redo.cmd = ED_UNASSIGNED; el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = el->el_line.buffer; - el->el_chared.c_vcmd.ins = el->el_line.buffer; el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ); if (el->el_chared.c_kill.buf == NULL) @@ -443,11 +490,10 @@ ch_init(EditLine *el) el->el_state.argument = 1; el->el_state.lastcmd = ED_UNASSIGNED; - el->el_chared.c_macro.nline = NULL; - el->el_chared.c_macro.level = -1; - el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO * - sizeof(char *)); - if (el->el_chared.c_macro.macro == NULL) + ma->level = -1; + ma->offset = 0; + ma->macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *)); + if (ma->macro == NULL) return (-1); return (0); } @@ -456,19 +502,16 @@ ch_init(EditLine *el) * Reset the character editor */ protected void -ch_reset(EditLine *el) +ch_reset(EditLine *el, int mclear) { el->el_line.cursor = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer; - el->el_chared.c_undo.action = NOP; - el->el_chared.c_undo.isize = 0; - el->el_chared.c_undo.dsize = 0; - el->el_chared.c_undo.ptr = el->el_line.buffer; + el->el_chared.c_undo.len = -1; + el->el_chared.c_undo.cursor = 0; el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = el->el_line.buffer; - el->el_chared.c_vcmd.ins = el->el_line.buffer; el->el_chared.c_kill.mark = el->el_line.buffer; @@ -480,9 +523,17 @@ ch_reset(EditLine *el) el->el_state.argument = 1; el->el_state.lastcmd = ED_UNASSIGNED; - el->el_chared.c_macro.level = -1; + if (mclear) + ch__clearmacro(el); +} - el->el_history.eventno = 0; +private void +ch__clearmacro(el) + EditLine *el; +{ + c_macro_t *ma = &el->el_chared.c_macro; + while (ma->level >= 0) + el_free((ptr_t)ma->macro[ma->level--]); } /* ch_enlargebufs(): @@ -523,7 +574,8 @@ ch_enlargebufs(el, addlen) el->el_line.buffer = newbuffer; el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf); el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf); - el->el_line.limit = &newbuffer[newsz - EL_LEAVE]; + /* don't set new size until all buffers are enlarged */ + el->el_line.limit = &newbuffer[sz - EL_LEAVE]; /* * Reallocate kill buffer. @@ -552,14 +604,22 @@ ch_enlargebufs(el, addlen) /* zero the newly added memory, leave old data in */ (void) memset(&newbuffer[sz], 0, newsz - sz); - - el->el_chared.c_undo.ptr = el->el_line.buffer + - (el->el_chared.c_undo.ptr - oldbuf); el->el_chared.c_undo.buf = newbuffer; + + newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz); + if (!newbuffer) + return 0; + el->el_chared.c_redo.pos = newbuffer + + (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf); + el->el_chared.c_redo.lim = newbuffer + + (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf); + el->el_chared.c_redo.buf = newbuffer; if (!hist_enlargebuf(el, sz, newsz)) return 0; + /* Safe to set enlarged buffer size */ + el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; return 1; } @@ -574,11 +634,16 @@ ch_end(EditLine *el) el->el_line.limit = NULL; el_free((ptr_t) el->el_chared.c_undo.buf); el->el_chared.c_undo.buf = NULL; + el_free((ptr_t) el->el_chared.c_redo.buf); + el->el_chared.c_redo.buf = NULL; + el->el_chared.c_redo.pos = NULL; + el->el_chared.c_redo.lim = NULL; + el->el_chared.c_redo.cmd = ED_UNASSIGNED; el_free((ptr_t) el->el_chared.c_kill.buf); el->el_chared.c_kill.buf = NULL; + ch_reset(el, 1); el_free((ptr_t) el->el_chared.c_macro.macro); el->el_chared.c_macro.macro = NULL; - ch_reset(el); } @@ -626,51 +691,64 @@ el_deletestr(EditLine *el, int n) * Get a string */ protected int -c_gets(EditLine *el, char *buf) +c_gets(EditLine *el, char *buf, const char *prompt) { char ch; - int len = 0; + int len; + char *cp = el->el_line.buffer; + + if (prompt) { + len = strlen(prompt); + memcpy(cp, prompt, len + 0u); + cp += len; + } + len = 0; + + for (;;) { + el->el_line.cursor = cp; + *cp = ' '; + el->el_line.lastchar = cp + 1; + re_refresh(el); + + if (el_getc(el, &ch) != 1) { + ed_end_of_file(el, 0); + len = -1; + break; + } - for (ch = 0; ch == 0;) { - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); switch (ch) { + case 0010: /* Delete and backspace */ case 0177: - if (len > 1) { - *el->el_line.cursor-- = '\0'; - el->el_line.lastchar = el->el_line.cursor; - buf[len--] = '\0'; - } else { - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; - return (CC_REFRESH); + if (len <= 0) { + len = -1; + break; } - re_refresh(el); - ch = 0; - break; + cp--; + continue; case 0033: /* ESC */ case '\r': /* Newline */ case '\n': + buf[len] = ch; break; default: - if (len >= EL_BUFSIZ) + if (len >= EL_BUFSIZ - 16) term_beep(el); else { buf[len++] = ch; - *el->el_line.cursor++ = ch; - el->el_line.lastchar = el->el_line.cursor; + *cp++ = ch; } - re_refresh(el); - ch = 0; - break; + continue; } + break; } - buf[len] = ch; - return (len); + + el->el_line.buffer[0] = '\0'; + el->el_line.lastchar = el->el_line.buffer; + el->el_line.cursor = el->el_line.buffer; + return len; } diff --git a/chared.h b/chared.h index 2eb9ad328863..e2786b25979d 100644 --- a/chared.h +++ b/chared.h @@ -1,4 +1,4 @@ -/* $NetBSD: chared.h,v 1.6 2001/01/10 07:45:41 jdolecek Exp $ */ +/* $NetBSD: chared.h,v 1.15 2005/08/01 23:00:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -66,28 +62,36 @@ typedef struct c_macro_t { int level; + int offset; char **macro; - char *nline; } c_macro_t; /* - * Undo information for both vi and emacs + * Undo information for vi - no undo in emacs (yet) */ typedef struct c_undo_t { - int action; - size_t isize; - size_t dsize; - char *ptr; - char *buf; + int len; /* length of saved line */ + int cursor; /* position of saved cursor */ + char *buf; /* full saved text */ } c_undo_t; +/* redo for vi */ +typedef struct c_redo_t { + char *buf; /* redo insert key sequence */ + char *pos; + char *lim; + el_action_t cmd; /* command to redo */ + char ch; /* char that invoked it */ + int count; + int action; /* from cv_action() */ +} c_redo_t; + /* * Current action information for vi */ typedef struct c_vcmd_t { int action; char *pos; - char *ins; } c_vcmd_t; /* @@ -106,6 +110,7 @@ typedef struct c_kill_t { typedef struct el_chared_t { c_undo_t c_undo; c_kill_t c_kill; + c_redo_t c_redo; c_vcmd_t c_vcmd; c_macro_t c_macro; } el_chared_t; @@ -120,10 +125,10 @@ typedef struct el_chared_t { #define NOP 0x00 #define DELETE 0x01 #define INSERT 0x02 -#define CHANGE 0x04 +#define YANK 0x04 -#define CHAR_FWD 0 -#define CHAR_BACK 1 +#define CHAR_FWD (+1) +#define CHAR_BACK (-1) #define MODE_INSERT 0 #define MODE_REPLACE 1 @@ -137,23 +142,27 @@ typedef struct el_chared_t { protected int cv__isword(int); +protected int cv__isWord(int); protected void cv_delfini(EditLine *); -protected char *cv__endword(char *, char *, int); +protected char *cv__endword(char *, char *, int, int (*)(int)); protected int ce__isword(int); -protected void cv_undo(EditLine *, int, size_t, char *); +protected void cv_undo(EditLine *); +protected void cv_yank(EditLine *, const char *, int); protected char *cv_next_word(EditLine*, char *, char *, int, int (*)(int)); -protected char *cv_prev_word(EditLine*, char *, char *, int, int (*)(int)); +protected char *cv_prev_word(char *, char *, int, int (*)(int)); protected char *c__next_word(char *, char *, int, int (*)(int)); protected char *c__prev_word(char *, char *, int, int (*)(int)); protected void c_insert(EditLine *, int); protected void c_delbefore(EditLine *, int); +protected void c_delbefore1(EditLine *); protected void c_delafter(EditLine *, int); -protected int c_gets(EditLine *, char *); +protected void c_delafter1(EditLine *); +protected int c_gets(EditLine *, char *, const char *); protected int c_hpos(EditLine *); protected int ch_init(EditLine *); -protected void ch_reset(EditLine *); -protected int ch_enlargebufs __P((EditLine *, size_t)); +protected void ch_reset(EditLine *, int); +protected int ch_enlargebufs(EditLine *, size_t); protected void ch_end(EditLine *); #endif /* _h_el_chared */ diff --git a/common.c b/common.c index dfb8a710d1bd..15b3aa2f9309 100644 --- a/common.c +++ b/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.10 2001/01/10 07:45:41 jdolecek Exp $ */ +/* $NetBSD: common.c,v 1.17 2005/08/01 23:00:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: common.c,v 1.10 2001/01/10 07:45:41 jdolecek Exp $"); +__RCSID("$NetBSD: common.c,v 1.17 2005/08/01 23:00:15 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * common.c: Common Editor functions */ -#include "sys.h" #include "el.h" /* ed_end_of_file(): @@ -57,7 +52,7 @@ __RCSID("$NetBSD: common.c,v 1.10 2001/01/10 07:45:41 jdolecek Exp $"); */ protected el_action_t /*ARGSUSED*/ -ed_end_of_file(EditLine *el, int c) +ed_end_of_file(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); @@ -73,7 +68,7 @@ ed_end_of_file(EditLine *el, int c) protected el_action_t ed_insert(EditLine *el, int c) { - int i; + int count = el->el_state.argument; if (c == '\0') return (CC_ERROR); @@ -81,42 +76,28 @@ ed_insert(EditLine *el, int c) if (el->el_line.lastchar + el->el_state.argument >= el->el_line.limit) { /* end of buffer space, try to allocate more */ - if (!ch_enlargebufs(el, (size_t) el->el_state.argument)) + if (!ch_enlargebufs(el, (size_t) count)) return CC_ERROR; /* error allocating more */ } - if (el->el_state.argument == 1) { - if (el->el_state.inputmode != MODE_INSERT) { - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] = - *el->el_line.cursor; - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] = - '\0'; - c_delafter(el, 1); - } - c_insert(el, 1); + if (count == 1) { + if (el->el_state.inputmode == MODE_INSERT + || el->el_line.cursor >= el->el_line.lastchar) + c_insert(el, 1); *el->el_line.cursor++ = c; - el->el_state.doingarg = 0; /* just in case */ re_fastaddc(el); /* fast refresh for one char. */ } else { - if (el->el_state.inputmode != MODE_INSERT) { - for (i = 0; i < el->el_state.argument; i++) - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] = - el->el_line.cursor[i]; + if (el->el_state.inputmode != MODE_REPLACE_1) + c_insert(el, el->el_state.argument); - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] = - '\0'; - c_delafter(el, el->el_state.argument); - } - c_insert(el, el->el_state.argument); - - while (el->el_state.argument--) + while (count-- && el->el_line.cursor < el->el_line.lastchar) *el->el_line.cursor++ = c; re_refresh(el); } if (el->el_state.inputmode == MODE_REPLACE_1) - (void) vi_command_mode(el, 0); + return vi_command_mode(el, 0); return (CC_NORM); } @@ -128,7 +109,7 @@ ed_insert(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_word(EditLine *el, int c) +ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -156,7 +137,7 @@ ed_delete_prev_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_next_char(EditLine *el, int c) +ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) { #ifdef notdef /* XXX */ #define EL el->el_line @@ -207,7 +188,7 @@ ed_delete_next_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_kill_line(EditLine *el, int c) +ed_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -228,7 +209,7 @@ ed_kill_line(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_end(EditLine *el, int c) +ed_move_to_end(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.lastchar; @@ -236,7 +217,7 @@ ed_move_to_end(EditLine *el, int c) #ifdef VI_MOVE el->el_line.cursor--; #endif - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -251,7 +232,7 @@ ed_move_to_end(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_beg(EditLine *el, int c) +ed_move_to_beg(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -260,7 +241,7 @@ ed_move_to_beg(EditLine *el, int c) /* We want FIRST non space character */ while (isspace((unsigned char) *el->el_line.cursor)) el->el_line.cursor++; - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -300,18 +281,22 @@ ed_transpose_chars(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_char(EditLine *el, int c) +ed_next_char(EditLine *el, int c __attribute__((__unused__))) { + char *lim = el->el_line.lastchar; - if (el->el_line.cursor >= el->el_line.lastchar) + if (el->el_line.cursor >= lim || + (el->el_line.cursor == lim - 1 && + el->el_map.type == MAP_VI && + el->el_chared.c_vcmd.action == NOP)) return (CC_ERROR); el->el_line.cursor += el->el_state.argument; - if (el->el_line.cursor > el->el_line.lastchar) - el->el_line.cursor = el->el_line.lastchar; + if (el->el_line.cursor > lim) + el->el_line.cursor = lim; if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -325,7 +310,7 @@ ed_next_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_prev_word(EditLine *el, int c) +ed_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) @@ -337,7 +322,7 @@ ed_prev_word(EditLine *el, int c) ce__isword); if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -351,7 +336,7 @@ ed_prev_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_prev_char(EditLine *el, int c) +ed_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor > el->el_line.buffer) { @@ -360,7 +345,7 @@ ed_prev_char(EditLine *el, int c) el->el_line.cursor = el->el_line.buffer; if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -412,25 +397,9 @@ ed_digit(EditLine *el, int c) (el->el_state.argument * 10) + (c - '0'); } return (CC_ARGHACK); - } else { - if (el->el_line.lastchar + 1 >= el->el_line.limit) { - if (!ch_enlargebufs(el, 1)) - return (CC_ERROR); - } - - if (el->el_state.inputmode != MODE_INSERT) { - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] = - *el->el_line.cursor; - el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] = - '\0'; - c_delafter(el, 1); - } - c_insert(el, 1); - *el->el_line.cursor++ = c; - el->el_state.doingarg = 0; - re_fastaddc(el); } - return (CC_NORM); + + return ed_insert(el, c); } @@ -464,12 +433,10 @@ ed_argument_digit(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_unassigned(EditLine *el, int c) +ed_unassigned(EditLine *el, int c __attribute__((__unused__))) { - term_beep(el); - term__flush(); - return (CC_NORM); + return (CC_ERROR); } @@ -483,7 +450,8 @@ ed_unassigned(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigint(EditLine *el, int c) +ed_tty_sigint(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -496,7 +464,8 @@ ed_tty_sigint(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_dsusp(EditLine *el, int c) +ed_tty_dsusp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -509,7 +478,8 @@ ed_tty_dsusp(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_flush_output(EditLine *el, int c) +ed_tty_flush_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -522,7 +492,8 @@ ed_tty_flush_output(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigquit(EditLine *el, int c) +ed_tty_sigquit(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -535,7 +506,8 @@ ed_tty_sigquit(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigtstp(EditLine *el, int c) +ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -548,7 +520,8 @@ ed_tty_sigtstp(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_stop_output(EditLine *el, int c) +ed_tty_stop_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -561,7 +534,8 @@ ed_tty_stop_output(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_tty_start_output(EditLine *el, int c) +ed_tty_start_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -574,14 +548,12 @@ ed_tty_start_output(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_newline(EditLine *el, int c) +ed_newline(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); *el->el_line.lastchar++ = '\n'; *el->el_line.lastchar = '\0'; - if (el->el_map.type == MAP_VI) - el->el_chared.c_vcmd.ins = el->el_line.buffer; return (CC_NEWLINE); } @@ -592,7 +564,7 @@ ed_newline(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_char(EditLine *el, int c) +ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) @@ -612,7 +584,7 @@ ed_delete_prev_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_clear_screen(EditLine *el, int c) +ed_clear_screen(EditLine *el, int c __attribute__((__unused__))) { term_clear_screen(el); /* clear the whole real screen */ @@ -627,7 +599,8 @@ ed_clear_screen(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_redisplay(EditLine *el, int c) +ed_redisplay(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_REDISPLAY); @@ -640,10 +613,10 @@ ed_redisplay(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_start_over(EditLine *el, int c) +ed_start_over(EditLine *el, int c __attribute__((__unused__))) { - ch_reset(el); + ch_reset(el, 0); return (CC_REFRESH); } @@ -654,7 +627,8 @@ ed_start_over(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_sequence_lead_in(EditLine *el, int c) +ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -667,11 +641,12 @@ ed_sequence_lead_in(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_prev_history(EditLine *el, int c) +ed_prev_history(EditLine *el, int c __attribute__((__unused__))) { char beep = 0; + int sv_event = el->el_history.eventno; - el->el_chared.c_undo.action = NOP; + el->el_chared.c_undo.len = -1; *el->el_line.lastchar = '\0'; /* just in case */ if (el->el_history.eventno == 0) { /* save the current buffer @@ -684,15 +659,17 @@ ed_prev_history(EditLine *el, int c) el->el_history.eventno += el->el_state.argument; if (hist_get(el) == CC_ERROR) { + if (el->el_map.type == MAP_VI) { + el->el_history.eventno = sv_event; + return CC_ERROR; + } beep = 1; /* el->el_history.eventno was fixed by first call */ (void) hist_get(el); } - re_refresh(el); if (beep) - return (CC_ERROR); - else - return (CC_NORM); /* was CC_UP_HIST */ + return CC_REFRESH_BEEP; + return CC_REFRESH; } @@ -702,19 +679,24 @@ ed_prev_history(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_history(EditLine *el, int c) +ed_next_history(EditLine *el, int c __attribute__((__unused__))) { + el_action_t beep = CC_REFRESH, rval; - el->el_chared.c_undo.action = NOP; + el->el_chared.c_undo.len = -1; *el->el_line.lastchar = '\0'; /* just in case */ el->el_history.eventno -= el->el_state.argument; if (el->el_history.eventno < 0) { el->el_history.eventno = 0; - return (CC_ERROR);/* make it beep */ + beep = CC_REFRESH_BEEP; } - return (hist_get(el)); + rval = hist_get(el); + if (rval == CC_REFRESH) + return beep; + return rval; + } @@ -724,14 +706,14 @@ ed_next_history(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_search_prev_history(EditLine *el, int c) +ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; bool_t found = 0; el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_undo.action = NOP; + el->el_chared.c_undo.len = -1; *el->el_line.lastchar = '\0'; /* just in case */ if (el->el_history.eventno < 0) { #ifdef DEBUG_EDIT @@ -792,14 +774,14 @@ ed_search_prev_history(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_search_next_history(EditLine *el, int c) +ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; bool_t found = 0; el->el_chared.c_vcmd.action = NOP; - el->el_chared.c_undo.action = NOP; + el->el_chared.c_undo.len = -1; *el->el_line.lastchar = '\0'; /* just in case */ if (el->el_history.eventno == 0) @@ -846,7 +828,7 @@ ed_search_next_history(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_prev_line(EditLine *el, int c) +ed_prev_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -889,7 +871,7 @@ ed_prev_line(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_line(EditLine *el, int c) +ed_next_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -923,30 +905,18 @@ ed_next_line(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_command(EditLine *el, int c) +ed_command(EditLine *el, int c __attribute__((__unused__))) { char tmpbuf[EL_BUFSIZ]; int tmplen; - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; + tmplen = c_gets(el, tmpbuf, "\n: "); + term__putc('\n'); - c_insert(el, 3); /* prompt + ": " */ - *el->el_line.cursor++ = '\n'; - *el->el_line.cursor++ = ':'; - *el->el_line.cursor++ = ' '; - re_refresh(el); + if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1) + term_beep(el); - tmplen = c_gets(el, tmpbuf); - tmpbuf[tmplen] = '\0'; - - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; - - if (parse_line(el, tmpbuf) == -1) - return (CC_ERROR); - else - return (CC_REFRESH); + el->el_map.current = el->el_map.key; + re_clear_display(el); + return CC_REFRESH; } diff --git a/config.h b/config.h new file mode 100644 index 000000000000..e2fc0cad9b7f --- /dev/null +++ b/config.h @@ -0,0 +1,18 @@ +/* config.h. Generated automatically by configure. */ +/* #undef SUNOS */ + +#define HAVE_SYS_CDEFS_H 1 +#define HAVE_TERMCAP_H 1 +/* #undef HAVE_CURSES_H */ +/* #undef HAVE_NCURSES_H */ +/* #undef HAVE_TERM_H */ +#define HAVE_VIS_H 1 +#define HAVE_ISSETUGID 1 + +#define HAVE_STRLCAT 1 +#define HAVE_STRLCPY 1 +#define HAVE_FGETLN 1 +#define HAVE_STRVIS 1 +#define HAVE_STRUNVIS 1 + +#include "sys.h" diff --git a/editline.3 b/editline.3 index f74849114f58..3d4ccb1068ab 100644 --- a/editline.3 +++ b/editline.3 @@ -1,6 +1,6 @@ -.\" $NetBSD: editline.3,v 1.22 2001/09/27 19:29:50 christos Exp $ +.\" $NetBSD: editline.3,v 1.48 2005/07/14 15:02:37 wiz Exp $ .\" -.\" Copyright (c) 1997-1999 The NetBSD Foundation, Inc. +.\" Copyright (c) 1997-2003 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This file was contributed to The NetBSD Foundation by Luke Mewburn. @@ -33,7 +33,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 12, 1999 +.Dd July 14, 2005 .Os .Dt EDITLINE 3 .Sh NAME @@ -53,12 +53,17 @@ .Nm el_deletestr , .Nm history_init , .Nm history_end , -.Nm history -.Nd line editor and history functions +.Nm history , +.Nm tok_init , +.Nm tok_end , +.Nm tok_reset , +.Nm tok_line , +.Nm tok_str +.Nd line editor, history and tokenization functions .Sh LIBRARY .Lb libedit .Sh SYNOPSIS -.Fd #include +.In histedit.h .Ft EditLine * .Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr" .Ft void @@ -72,7 +77,7 @@ .Ft void .Fn el_push "EditLine *e" "const char *str" .Ft int -.Fn el_parse "EditLine *e" "int argc" "char *argv[]" +.Fn el_parse "EditLine *e" "int argc" "const char *argv[]" .Ft int .Fn el_set "EditLine *e" "int op" "..." .Ft int @@ -93,10 +98,20 @@ .Fn history_end "History *h" .Ft int .Fn history "History *h" "HistEvent *ev" "int op" "..." +.Ft Tokenizer * +.Fn tok_init "const char *IFS" +.Ft void +.Fn tok_end "Tokenizer *t" +.Ft void +.Fn tok_reset "Tokenizer *t" +.Ft int +.Fn tok_line "Tokenizer *t" "const LineInfo *li" "int *argc" "const char **argv[]" "int *cursorc" "int *cursoro" +.Ft int +.Fn tok_str "Tokenizer *t" "const char *str" "int *argc" "const char **argv[]" .Sh DESCRIPTION The .Nm -library provides generic line editing and history functions, +library provides generic line editing, history and tokenization functions, similar to those found in .Xr sh 1 . .Pp @@ -152,7 +167,7 @@ if no characters were read or if an error occurred. Read a character from the tty. .Fa ch is modified to contain the character read. -Returns the number of characters read if successful, -1 otherwise. +Returns the number of characters read if successful, \-1 otherwise. .It Fn el_push Pushes .Fa str @@ -174,7 +189,7 @@ to execute builtin .Nm commands. If the command is prefixed with -.Dq prog: +.Dq prog : then .Fn el_parse will only execute the command if @@ -184,7 +199,7 @@ matches the argument supplied to .Fn el_init . The return value is --1 if the command is unknown, +\-1 if the command is unknown, 0 if there was no error or .Dq prog didn't match, or @@ -303,7 +318,7 @@ for more information. .It Dv EL_ADDFN , Xo .Fa "const char *name" , .Fa "const char *help" , -.Fa "unsigned char (*func)(EditLine *e, int ch) +.Fa "unsigned char (*func)(EditLine *e, int ch)" .Xc Add a user defined function, .Fn func , @@ -336,7 +351,7 @@ Refresh display. Refresh display, and beep. .It Dv CC_CURSOR Cursor moved, so update and perform -.Dv CC_REFRESH. +.Dv CC_REFRESH . .It Dv CC_REDISPLAY Redisplay entire input line. This is useful if a key binding outputs extra information. @@ -362,7 +377,7 @@ is non-zero, editing is enabled (the default). Note that this is only an indication, and does not affect the operation of -.Nm "" . +.Nm . At this time, it is the caller's responsibility to check this (using @@ -379,6 +394,13 @@ and .Fn el_getc . The builtin function can be set or restored with the special function name ``EL_BUILTIN_GETCFN''. +.It Dv EL_CLIENTDATA , Fa "void *data" +Register +.Fa data +to be associated with this EditLine structure. +It can be retrieved with the corresponding +.Fn el_get +call. .El .It Fn el_get Get @@ -387,6 +409,7 @@ parameters. .Fa op determines which parameter to retrieve into .Fa result . +Returns 0 if successful, \-1 otherwise. .Pp The following values for .Fa op @@ -413,6 +436,19 @@ Return non-zero if editing is enabled. .It Dv EL_GETCFN, Fa "int (**f)(EditLine *, char *)" Return a pointer to the function that read characters, which is equal to ``EL_BUILTIN_GETCFN'' in the case of the default builtin function. +.It Dv EL_CLIENTDATA , Fa "void **data" +Retrieve +.Fa data +previously registered with the corresponding +.Fn el_set +call. +.It Dv EL_UNBUFFERED, Fa "int" +Sets or clears unbuffered mode. +In this mode, +.Fn el_gets +will return immediately after processing a single character. +.It Dv EL_PREP_TERM, Fa "int" +Sets or clears terminal editing mode. .El .It Fn el_source Initialise @@ -455,11 +491,21 @@ typedef struct lineinfo { const char *lastchar; /* address of last character */ } LineInfo; .Ed +.Pp +.Fa buffer +is not NUL terminated. +This function may be called after +.Fn el_gets +to obtain the +.Fa LineInfo +structure pertaining to line returned by that function, +and from within user defined functions added with +.Dv EL_ADDFN . .It Fn el_insertstr Insert .Fa str into the line at the cursor. -Returns -1 if +Returns \-1 if .Fa str is empty or won't fit, and 0 otherwise. .It Fn el_deletestr @@ -539,7 +585,11 @@ Set the cursor to point to the requested element. .It Dv H_ADD , Fa "const char *str" Append .Fa str -to the current element of the history, or create an element with +to the current element of the history, or perform the +.Dv H_ENTER +operation with argument +.Fa str +if there is no current element. .It Dv H_APPEND , Fa "const char *str" Append .Fa str @@ -549,6 +599,17 @@ Add .Fa str as a new element to the history, and, if necessary, removing the oldest entry to keep the list to the created size. +If +.Dv H_SETUNIQUE +was has been called with a non-zero arguments, the element +will not be entered into the history if its contents match +the ones of the current history element. +If the element is entered +.Fn history +returns 1, if it is ignored as a duplicate returns 0. +Finally +.Fn history +returns \-1 if an error occurred. .It Dv H_PREV_STR , Fa "const char *str" Return the closest previous event that starts with .Fa str . @@ -567,22 +628,109 @@ Load the history list stored in .It Dv H_SAVE , Fa "const char *file" Save the history list to .Fa file . +.It Dv H_SETUNIQUE , Fa "int unique" +Set if the adjacent identical event strings should not be entered into +the history. +.It Dv H_GETUNIQUE +Retrieve the current setting if if adjacent elements should be entered into +the history. +.It Dv H_DEL , Fa "int num" +Delete the event numbered +.Fa e . +This function is only provided for +.Xr readline 3 +compatibility. +The caller is responsible for free'ing the string in the returned +.Fa HistEvent . .El .Pp .Fn history -returns 0 if the operation +returns \*[Gt]= 0 if the operation .Fa op -succeeds. Otherwise, -1 is returned and +succeeds. +Otherwise, \-1 is returned and .Fa ev is updated to contain more details about the error. .El +.Sh TOKENIZATION FUNCTIONS +The tokenization functions use a common data structure, +.Fa Tokenizer , +which is created by +.Fn tok_init +and freed by +.Fn tok_end . +.Pp +The following functions are available: +.Bl -tag -width 4n +.It Fn tok_init +Initialise the tokenizer, and return a data structure +to be used by all other tokenizer functions. +.Fa IFS +contains the Input Field Separators, which defaults to +.Aq space , +.Aq tab , +and +.Aq newline +if +.Dv NULL . +.It Fn tok_end +Clean up and finish with +.Fa t , +assumed to have been created with +.Fn tok_init . +.It Fn tok_reset +Reset the tokenizer state. +Use after a line has been successfully tokenized +by +.Fn tok_line +or +.Fn tok_str +and before a new line is to be tokenized. +.It Fn tok_line +Tokenize +.Fa li , +If successful, modify: +.Fa argv +to contain the words, +.Fa argc +to contain the number of words, +.Fa cursorc +(if not +.Dv NULL ) +to contain the index of the word containing the cursor, +and +.Fa cursoro +(if not +.Dv NULL ) +to contain the offset within +.Fa argv[cursorc] +of the cursor. +.Pp +Returns +0 if successful, +\-1 for an internal error, +1 for an unmatched single quote, +2 for an unmatched double quote, +and +3 for a backslash quoted +.Aq newline . +A positive exit code indicates that another line should be read +and tokenization attempted again. +. +.It Fn tok_str +A simpler form of +.Fn tok_line ; +.Fa str +is a NUL terminated string to tokenize. +.El +. .\"XXX.Sh EXAMPLES .\"XXX: provide some examples .Sh SEE ALSO -.Xr editrc 5 , .Xr sh 1 , .Xr signal 3 , -.Xr termcap 3 +.Xr termcap 3 , +.Xr editrc 5 .Sh HISTORY The .Nm @@ -610,9 +758,6 @@ and .Dv EL_RPROMPT . Jaromir Dolecek implemented the readline emulation. .Sh BUGS -The tokenization functions are not publically defined in -.Fd . -.Pp At this time, it is the responsibility of the caller to check the result of the .Dv EL_EDITMODE diff --git a/editrc.5 b/editrc.5 index b11226189398..d2462ebcd8d5 100644 --- a/editrc.5 +++ b/editrc.5 @@ -1,4 +1,4 @@ -.\" $NetBSD: editrc.5,v 1.11 2001/06/19 13:42:09 wiz Exp $ +.\" $NetBSD: editrc.5,v 1.19 2003/11/01 23:35:33 christos Exp $ .\" .\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -33,7 +33,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 8, 2000 +.Dd October 18, 2003 .Os .Dt EDITRC 5 .Sh NAME @@ -62,7 +62,7 @@ for more information. .Ar prog is the program name string that a program defines when it calls .Xr el_init 3 -to setup +to set up .Xr editline 3 , which is usually .Va argv[0] . @@ -122,7 +122,7 @@ Options include: Bind all keys to the standard GNU Emacs-like bindings. .It Fl v Bind all keys to the standard -.Xr vi 1 -like +.Xr vi 1 Ns -like bindings. .It Fl a List or change key bindings in the @@ -222,7 +222,7 @@ or indicating that the terminal does or does not have that capability. .Pp .Fl s -returns an emptry string for non-existent capabilities, rather than +returns an empty string for non-existent capabilities, rather than causing an error. .Fl v causes messages to be verbose. @@ -230,11 +230,27 @@ causes messages to be verbose. Enable or disable the .Nm editline functionality in a program. -.It Ic history -List the history. +.It Ic history Ar list | Ar size Dv n | Ar unique Dv n +The +.Ar list +command lists all entries in the history. +The +.Ar size +command sets the history size to +.Dv n +entries. +The +.Ar unique +command controls if history should keep duplicate entries. +If +.Dv n +is non zero, only keep unique history entries. +If +.Dv n +is zero, then keep all entries (the default). .It Ic telltc List the values of all the terminal capabilities (see -.Xr termcap 5 ). +.Xr termcap 5 ) . .It Ic settc Ar cap Ar val Set the terminal capability .Ar cap @@ -251,6 +267,7 @@ No sanity checking is done. .Op Ar +mode .Op Ar -mode .Op Ar mode +.Op Ar char=c .Xc Control which tty modes that .Nm @@ -291,6 +308,15 @@ fixes on or off or removes control of .Ar mode in the chosen set. +.Pp +.Ic Setty +can also be used to set tty characters to particular values using +.Ar char=value . +If +.Ar value +is empty +then the character is set to +.Dv _POSIX_VDISABLE . .El .Sh EDITOR COMMANDS The following editor commands are available for use in key bindings: @@ -380,7 +406,7 @@ Cut the entire line and save in cut buffer. Cut area between mark and cursor and save in cut buffer. .It Ic em-copy-region Copy area between mark and cursor to cut buffer. -.It Ic em-gosmacs-traspose +.It Ic em-gosmacs-transpose Exchange the two characters before the cursor. .It Ic em-next-word Move next to end of current word. diff --git a/el.c b/el.c index 3cff2861a563..57ca25568819 100644 --- a/el.c +++ b/el.c @@ -1,4 +1,4 @@ -/* $NetBSD: el.c,v 1.23 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: el.c,v 1.40 2005/08/01 23:00:15 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,20 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #else -__RCSID("$NetBSD: el.c,v 1.23 2001/09/27 19:29:50 christos Exp $"); +__RCSID("$NetBSD: el.c,v 1.40 2005/08/01 23:00:15 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * el.c: EditLine interface functions */ -#include "sys.h" - #include #include #include @@ -65,9 +59,6 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) { EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); -#ifdef DEBUG - char *tty; -#endif if (el == NULL) return (NULL); @@ -77,14 +68,21 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_infd = fileno(fin); el->el_outfile = fout; el->el_errfile = ferr; - el->el_prog = strdup(prog); + if ((el->el_prog = el_strdup(prog)) == NULL) { + el_free(el); + return NULL; + } /* * Initialize all the modules. Order is important!!! */ el->el_flags = 0; - (void) term_init(el); + if (term_init(el) == -1) { + el_free(el->el_prog); + el_free(el); + return NULL; + } (void) key_init(el); (void) map_init(el); if (tty_init(el) == -1) @@ -135,7 +133,7 @@ el_reset(EditLine *el) { tty_cookedmode(el); - ch_reset(el); /* XXX: Do we want that? */ + ch_reset(el, 0); /* XXX: Do we want that? */ } @@ -146,7 +144,7 @@ public int el_set(EditLine *el, int op, ...) { va_list va; - int rv; + int rv = 0; if (el == NULL) return (-1); @@ -171,7 +169,6 @@ el_set(EditLine *el, int op, ...) el->el_flags |= HANDLE_SIGNALS; else el->el_flags &= ~HANDLE_SIGNALS; - rv = 0; break; case EL_BIND: @@ -180,7 +177,7 @@ el_set(EditLine *el, int op, ...) case EL_ECHOTC: case EL_SETTY: { - char *argv[20]; + const char *argv[20]; int i; for (i = 1; i < 20; i++) @@ -255,8 +252,34 @@ el_set(EditLine *el, int op, ...) break; } + case EL_CLIENTDATA: + el->el_data = va_arg(va, void *); + break; + + case EL_UNBUFFERED: + rv = va_arg(va, int); + if (rv && !(el->el_flags & UNBUFFERED)) { + el->el_flags |= UNBUFFERED; + read_prepare(el); + } else if (!rv && (el->el_flags & UNBUFFERED)) { + el->el_flags &= ~UNBUFFERED; + read_finish(el); + } + rv = 0; + break; + + case EL_PREP_TERM: + rv = va_arg(va, int); + if (rv) + (void) tty_rawmode(el); + else + (void) tty_cookedmode(el); + rv = 0; + break; + default: rv = -1; + break; } va_end(va); @@ -277,11 +300,11 @@ el_get(EditLine *el, int op, void *ret) switch (op) { case EL_PROMPT: case EL_RPROMPT: - rv = prompt_get(el, (el_pfunc_t *) & ret, op); + rv = prompt_get(el, (void *) &ret, op); break; case EL_EDITOR: - rv = map_get_editor(el, (const char **) &ret); + rv = map_get_editor(el, (void *) &ret); break; case EL_SIGNAL: @@ -294,21 +317,22 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; -#if 0 /* XXX */ case EL_TERMINAL: - rv = term_get(el, (const char *) &ret); + term_get(el, (const char **)ret); + rv = 0; break; +#if 0 /* XXX */ case EL_BIND: case EL_TELLTC: case EL_SETTC: case EL_ECHOTC: case EL_SETTY: { - char *argv[20]; + const char *argv[20]; int i; - for (i = 1; i < 20; i++) + for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++) if ((argv[i] = va_arg(va, char *)) == NULL) break; @@ -370,6 +394,16 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; + case EL_CLIENTDATA: + *((void **)ret) = el->el_data; + rv = 0; + break; + + case EL_UNBUFFERED: + *((int *) ret) = (!(el->el_flags & UNBUFFERED)); + rv = 0; + break; + default: rv = -1; } @@ -388,7 +422,6 @@ el_line(EditLine *el) return (const LineInfo *) (void *) &el->el_line; } -static const char elpath[] = "/.editrc"; /* el_source(): * Source a file @@ -398,10 +431,14 @@ el_source(EditLine *el, const char *fname) { FILE *fp; size_t len; - char *ptr, path[MAXPATHLEN]; + char *ptr; fp = NULL; if (fname == NULL) { +#ifdef HAVE_ISSETUGID + static const char elpath[] = "/.editrc"; + char path[MAXPATHLEN]; + if (issetugid()) return (-1); if ((ptr = getenv("HOME")) == NULL) @@ -411,6 +448,14 @@ el_source(EditLine *el, const char *fname) if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) return (-1); fname = path; +#else + /* + * If issetugid() is missing, always return an error, in order + * to keep from inadvertently opening up the user to a security + * hole. + */ + return (-1); +#endif } if (fp == NULL) fp = fopen(fname, "r"); @@ -469,7 +514,7 @@ el_beep(EditLine *el) */ protected int /*ARGSUSED*/ -el_editmode(EditLine *el, int argc, char **argv) +el_editmode(EditLine *el, int argc, const char **argv) { const char *how; @@ -477,10 +522,13 @@ el_editmode(EditLine *el, int argc, char **argv) return (-1); how = argv[1]; - if (strcmp(how, "on") == 0) + if (strcmp(how, "on") == 0) { el->el_flags &= ~EDIT_DISABLED; - else if (strcmp(how, "off") == 0) + tty_rawmode(el); + } else if (strcmp(how, "off") == 0) { + tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; + } else { (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); return (-1); diff --git a/el.h b/el.h index ac28d0c20fda..bfa9cfa9a9c3 100644 --- a/el.h +++ b/el.h @@ -1,4 +1,4 @@ -/* $NetBSD: el.h,v 1.9 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -55,9 +51,10 @@ #define EL_BUFSIZ 1024 /* Maximum line size */ -#define HANDLE_SIGNALS 1<<0 -#define NO_TTY 1<<1 -#define EDIT_DISABLED 1<<2 +#define HANDLE_SIGNALS 0x01 +#define NO_TTY 0x02 +#define EDIT_DISABLED 0x04 +#define UNBUFFERED 0x08 typedef int bool_t; /* True or not */ @@ -72,7 +69,7 @@ typedef struct el_line_t { char *buffer; /* Input line */ char *cursor; /* Cursor position */ char *lastchar; /* Last character */ - const char *limit; /* Max position */ + const char *limit; /* Max position */ } el_line_t; /* @@ -84,11 +81,14 @@ typedef struct el_state_t { int argument; /* Numeric argument */ int metanext; /* Is the next char a meta char */ el_action_t lastcmd; /* Previous command */ + el_action_t thiscmd; /* this command */ + char thisch; /* char that generated it */ } el_state_t; /* * Until we come up with something better... */ +#define el_strdup(a) strdup(a) #define el_malloc(a) malloc(a) #define el_realloc(a,b) realloc(a, b) #define el_free(a) free(a) @@ -117,6 +117,7 @@ struct editline { coord_t el_cursor; /* Cursor location */ char **el_display; /* Real screen image = what is there */ char **el_vdisplay; /* Virtual screen image = what we see */ + void *el_data; /* Client data */ el_line_t el_line; /* The current line information */ el_state_t el_state; /* Current editor state */ el_term_t el_term; /* Terminal dependent stuff */ @@ -133,11 +134,15 @@ struct editline { el_read_t el_read; /* Character reading stuff */ }; -protected int el_editmode(EditLine *, int, char **); +protected int el_editmode(EditLine *, int, const char **); #ifdef DEBUG -#define EL_ABORT(a) (void) (fprintf(el->el_errfile, "%s, %d: ", \ - __FILE__, __LINE__), fprintf a, abort()) +#define EL_ABORT(a) do { \ + fprintf(el->el_errfile, "%s, %d: ", \ + __FILE__, __LINE__); \ + fprintf a; \ + abort(); \ + } while( /*CONSTCOND*/0); #else #define EL_ABORT(a) abort() #endif diff --git a/emacs.c b/emacs.c index cc18411ae6ab..895bc3ebb66d 100644 --- a/emacs.c +++ b/emacs.c @@ -1,4 +1,4 @@ -/* $NetBSD: emacs.c,v 1.9 2001/01/10 07:45:41 jdolecek Exp $ */ +/* $NetBSD: emacs.c,v 1.19 2004/10/28 21:14:52 dsl Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: emacs.c,v 1.9 2001/01/10 07:45:41 jdolecek Exp $"); +__RCSID("$NetBSD: emacs.c,v 1.19 2004/10/28 21:14:52 dsl Exp $"); #endif #endif /* not lint && not SCCSID */ /* * emacs.c: Emacs functions */ -#include "sys.h" #include "el.h" /* em_delete_or_list(): @@ -57,7 +52,7 @@ __RCSID("$NetBSD: emacs.c,v 1.9 2001/01/10 07:45:41 jdolecek Exp $"); */ protected el_action_t /*ARGSUSED*/ -em_delete_or_list(EditLine *el, int c) +em_delete_or_list(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) { @@ -76,7 +71,10 @@ em_delete_or_list(EditLine *el, int c) return (CC_ERROR); } } else { - c_delafter(el, el->el_state.argument); /* delete after dot */ + if (el->el_state.doingarg) + c_delafter(el, el->el_state.argument); + else + c_delafter1(el); if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; /* bounds check */ @@ -91,7 +89,7 @@ em_delete_or_list(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_delete_next_word(EditLine *el, int c) +em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -120,14 +118,12 @@ em_delete_next_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_yank(EditLine *el, int c) +em_yank(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; - if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { - if (!ch_enlargebufs(el, 1)) - return (CC_ERROR); - } + if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) + return (CC_NORM); if (el->el_line.lastchar + (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= @@ -157,7 +153,7 @@ em_yank(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_kill_line(EditLine *el, int c) +em_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -179,7 +175,7 @@ em_kill_line(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_kill_region(EditLine *el, int c) +em_kill_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -212,11 +208,11 @@ em_kill_region(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_copy_region(EditLine *el, int c) +em_copy_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; - if (el->el_chared.c_kill.mark) + if (!el->el_chared.c_kill.mark) return (CC_ERROR); if (el->el_chared.c_kill.mark > el->el_line.cursor) { @@ -236,12 +232,12 @@ em_copy_region(EditLine *el, int c) } -/* em_gosmacs_traspose(): +/* em_gosmacs_transpose(): * Exchange the two characters before the cursor * Gosling emacs transpose chars [^T] */ protected el_action_t -em_gosmacs_traspose(EditLine *el, int c) +em_gosmacs_transpose(EditLine *el, int c) { if (el->el_line.cursor > &el->el_line.buffer[1]) { @@ -261,7 +257,7 @@ em_gosmacs_traspose(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_next_word(EditLine *el, int c) +em_next_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) return (CC_ERROR); @@ -272,7 +268,7 @@ em_next_word(EditLine *el, int c) ce__isword); if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -286,7 +282,7 @@ em_next_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_upper_case(EditLine *el, int c) +em_upper_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -294,8 +290,8 @@ em_upper_case(EditLine *el, int c) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -310,7 +306,7 @@ em_upper_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_capitol_case(EditLine *el, int c) +em_capitol_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -318,16 +314,16 @@ em_capitol_case(EditLine *el, int c) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) { - if (isalpha((unsigned char) *cp)) { - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (isalpha((unsigned char)*cp)) { + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); cp++; break; } } for (; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -342,7 +338,7 @@ em_capitol_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_lower_case(EditLine *el, int c) +em_lower_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -350,8 +346,8 @@ em_lower_case(EditLine *el, int c) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -366,7 +362,7 @@ em_lower_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_set_mark(EditLine *el, int c) +em_set_mark(EditLine *el, int c __attribute__((__unused__))) { el->el_chared.c_kill.mark = el->el_line.cursor; @@ -380,7 +376,7 @@ em_set_mark(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_exchange_mark(EditLine *el, int c) +em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) { char *cp; @@ -397,7 +393,7 @@ em_exchange_mark(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_universal_argument(EditLine *el, int c) +em_universal_argument(EditLine *el, int c __attribute__((__unused__))) { /* multiply current argument by 4 */ if (el->el_state.argument > 1000000) @@ -414,7 +410,7 @@ em_universal_argument(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_meta_next(EditLine *el, int c) +em_meta_next(EditLine *el, int c __attribute__((__unused__))) { el->el_state.metanext = 1; @@ -427,7 +423,7 @@ em_meta_next(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_toggle_overwrite(EditLine *el, int c) +em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) { el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? @@ -441,7 +437,7 @@ em_toggle_overwrite(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_copy_prev_word(EditLine *el, int c) +em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *oldc, *dp; @@ -468,7 +464,7 @@ em_copy_prev_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_next(EditLine *el, int c) +em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; @@ -481,9 +477,32 @@ em_inc_search_next(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_prev(EditLine *el, int c) +em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); } + + +/* em_delete_prev_char(): + * Delete the character to the left of the cursor + * [^?] + */ +protected el_action_t +/*ARGSUSED*/ +em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +{ + + if (el->el_line.cursor <= el->el_line.buffer) + return (CC_ERROR); + + if (el->el_state.doingarg) + c_delbefore(el, el->el_state.argument); + else + c_delbefore1(el); + el->el_line.cursor -= el->el_state.argument; + if (el->el_line.cursor < el->el_line.buffer) + el->el_line.cursor = el->el_line.buffer; + return (CC_REFRESH); +} diff --git a/filecomplete.c b/filecomplete.c new file mode 100644 index 000000000000..e0738a7e52b2 --- /dev/null +++ b/filecomplete.c @@ -0,0 +1,539 @@ +/* $NetBSD: filecomplete.c,v 1.7 2005/06/11 18:18:59 christos Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#if !defined(lint) && !defined(SCCSID) +__RCSID("$NetBSD: filecomplete.c,v 1.7 2005/06/11 18:18:59 christos Exp $"); +#endif /* not lint && not SCCSID */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_VIS_H +#include +#else +#include "np/vis.h" +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif +#include "el.h" +#include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "filecomplete.h" + +static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', + '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; + + +/********************************/ +/* completion functions */ + +/* + * does tilde expansion of strings of type ``~user/foo'' + * if ``user'' isn't valid user name or ``txt'' doesn't start + * w/ '~', returns pointer to strdup()ed copy of ``txt'' + * + * it's callers's responsibility to free() returned string + */ +char * +fn_tilde_expand(const char *txt) +{ + struct passwd pwres, *pass; + char *temp; + size_t len = 0; + char pwbuf[1024]; + + if (txt[0] != '~') + return (strdup(txt)); + + temp = strchr(txt + 1, '/'); + if (temp == NULL) { + temp = strdup(txt + 1); + if (temp == NULL) + return NULL; + } else { + len = temp - txt + 1; /* text until string after slash */ + temp = malloc(len); + if (temp == NULL) + return NULL; + (void)strncpy(temp, txt + 1, len - 2); + temp[len - 2] = '\0'; + } + if (temp[0] == 0) { + if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } else { + if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } + free(temp); /* value no more needed */ + if (pass == NULL) + return (strdup(txt)); + + /* update pointer txt to point at string immedially following */ + /* first slash */ + txt += len; + + temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); + + return (temp); +} + + +/* + * return first found file name starting by the ``text'' or NULL if no + * such file can be found + * value of ``state'' is ignored + * + * it's caller's responsibility to free returned string + */ +char * +fn_filename_completion_function(const char *text, int state) +{ + static DIR *dir = NULL; + static char *filename = NULL, *dirname = NULL, *dirpath = NULL; + static size_t filename_len = 0; + struct dirent *entry; + char *temp; + size_t len; + + if (state == 0 || dir == NULL) { + temp = strrchr(text, '/'); + if (temp) { + char *nptr; + temp++; + nptr = realloc(filename, strlen(temp) + 1); + if (nptr == NULL) { + free(filename); + return NULL; + } + filename = nptr; + (void)strcpy(filename, temp); + len = temp - text; /* including last slash */ + nptr = realloc(dirname, len + 1); + if (nptr == NULL) { + free(filename); + return NULL; + } + dirname = nptr; + (void)strncpy(dirname, text, len); + dirname[len] = '\0'; + } else { + if (*text == 0) + filename = NULL; + else { + filename = strdup(text); + if (filename == NULL) + return NULL; + } + dirname = NULL; + } + + if (dir != NULL) { + (void)closedir(dir); + dir = NULL; + } + + /* support for ``~user'' syntax */ + free(dirpath); + + if (dirname == NULL && (dirname = strdup("./")) == NULL) + return NULL; + + if (*dirname == '~') + dirpath = fn_tilde_expand(dirname); + else + dirpath = strdup(dirname); + + if (dirpath == NULL) + return NULL; + + dir = opendir(dirpath); + if (!dir) + return (NULL); /* cannot open the directory */ + + /* will be used in cycle */ + filename_len = filename ? strlen(filename) : 0; + } + + /* find the match */ + while ((entry = readdir(dir)) != NULL) { + /* skip . and .. */ + if (entry->d_name[0] == '.' && (!entry->d_name[1] + || (entry->d_name[1] == '.' && !entry->d_name[2]))) + continue; + if (filename_len == 0) + break; + /* otherwise, get first entry where first */ + /* filename_len characters are equal */ + if (entry->d_name[0] == filename[0] +#if defined(__SVR4) || defined(__linux__) + && strlen(entry->d_name) >= filename_len +#else + && entry->d_namlen >= filename_len +#endif + && strncmp(entry->d_name, filename, + filename_len) == 0) + break; + } + + if (entry) { /* match found */ + +#if defined(__SVR4) || defined(__linux__) + len = strlen(entry->d_name); +#else + len = entry->d_namlen; +#endif + + temp = malloc(strlen(dirname) + len + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s%s", dirname, entry->d_name); + } else { + (void)closedir(dir); + dir = NULL; + temp = NULL; + } + + return (temp); +} + + +static const char * +append_char_function(const char *name) +{ + struct stat stbuf; + char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; + const char *rs = ""; + + if (stat(expname ? expname : name, &stbuf) == -1) + goto out; + if (S_ISDIR(stbuf.st_mode)) + rs = "/"; +out: + if (expname) + free(expname); + return rs; +} +/* + * returns list of completions for text given + * non-static for readline. + */ +char ** completion_matches(const char *, char *(*)(const char *, int)); +char ** +completion_matches(const char *text, char *(*genfunc)(const char *, int)) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + size_t matches; + + matches = 0; + match_list_len = 1; + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { + /* allow for list terminator here */ + if (matches + 3 >= match_list_len) { + char **nmatch_list; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; + nmatch_list = realloc(match_list, + match_list_len * sizeof(char *)); + if (nmatch_list == NULL) { + free(match_list); + return NULL; + } + match_list = nmatch_list; + + } + match_list[++matches] = retstr; + } + + if (!match_list) + return NULL; /* nothing found */ + + /* find least denominator and insert it to match_list[0] */ + which = 2; + prevstr = match_list[1]; + max_equal = strlen(prevstr); + for (; which <= matches; which++) { + for (i = 0; i < max_equal && + prevstr[i] == match_list[which][i]; i++) + continue; + max_equal = i; + } + + retstr = malloc(max_equal + 1); + if (retstr == NULL) { + free(match_list); + return NULL; + } + (void)strncpy(retstr, match_list[1], max_equal); + retstr[max_equal] = '\0'; + match_list[0] = retstr; + + /* add NULL as last pointer to the array */ + match_list[matches + 1] = (char *) NULL; + + return (match_list); +} + +/* + * Sort function for qsort(). Just wrapper around strcasecmp(). + */ +static int +_fn_qsort_string_compare(const void *i1, const void *i2) +{ + const char *s1 = ((const char * const *)i1)[0]; + const char *s2 = ((const char * const *)i2)[0]; + + return strcasecmp(s1, s2); +} + +/* + * Display list of strings in columnar format on readline's output stream. + * 'matches' is list of strings, 'len' is number of strings in 'matches', + * 'max' is maximum length of string in 'matches'. + */ +void +fn_display_match_list (EditLine *el, char **matches, int len, int max) +{ + int i, idx, limit, count; + int screenwidth = el->el_term.t_size.h; + + /* + * Find out how many entries can be put on one line, count + * with two spaces between strings. + */ + limit = screenwidth / (max + 2); + if (limit == 0) + limit = 1; + + /* how many lines of output */ + count = len / limit; + if (count * limit < len) + count++; + + /* Sort the items if they are not already sorted. */ + qsort(&matches[1], (size_t)(len - 1), sizeof(char *), + _fn_qsort_string_compare); + + idx = 1; + for(; count > 0; count--) { + for(i = 0; i < limit && matches[idx]; i++, idx++) + (void)fprintf(el->el_outfile, "%-*s ", max, + matches[idx]); + (void)fprintf(el->el_outfile, "\n"); + } +} + +/* + * Complete the word at or before point, + * 'what_to_do' says what to do with the completion. + * \t means do standard completion. + * `?' means list the possible completions. + * `*' means insert all of the possible completions. + * `!' means to do standard completion, and list all possible completions if + * there is more than one. + * + * Note: '*' support is not implemented + * '!' could never be invoked + */ +int +fn_complete(EditLine *el, + char *(*complet_func)(const char *, int), + char **(*attempted_completion_function)(const char *, int, int), + const char *word_break, const char *special_prefixes, + const char *(*app_func)(const char *), int query_items, + int *completion_type, int *over, int *point, int *end) +{ + const LineInfo *li; + char *temp, **matches; + const char *ctemp; + size_t len; + int what_to_do = '\t'; + + if (el->el_state.lastcmd == el->el_state.thiscmd) + what_to_do = '?'; + + /* readline's rl_complete() has to be told what we did... */ + if (completion_type != NULL) + *completion_type = what_to_do; + + if (!complet_func) + complet_func = fn_filename_completion_function; + if (!app_func) + app_func = append_char_function; + + /* We now look backwards for the start of a filename/variable word */ + li = el_line(el); + ctemp = (const char *) li->cursor; + while (ctemp > li->buffer + && !strchr(word_break, ctemp[-1]) + && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) + ctemp--; + + len = li->cursor - ctemp; + temp = alloca(len + 1); + (void)strncpy(temp, ctemp, len); + temp[len] = '\0'; + + /* these can be used by function called in completion_matches() */ + /* or (*attempted_completion_function)() */ + if (point != 0) + *point = li->cursor - li->buffer; + if (end != NULL) + *end = li->lastchar - li->buffer; + + if (attempted_completion_function) { + int cur_off = li->cursor - li->buffer; + matches = (*attempted_completion_function) (temp, + (int)(cur_off - len), cur_off); + } else + matches = 0; + if (!attempted_completion_function || + (over != NULL && *over && !matches)) + matches = completion_matches(temp, complet_func); + + if (over != NULL) + *over = 0; + + if (matches) { + int i, retval = CC_REFRESH; + int matches_num, maxlen, match_len, match_display=1; + + /* + * Only replace the completed string with common part of + * possible matches if there is possible completion. + */ + if (matches[0][0] != '\0') { + el_deletestr(el, (int) len); + el_insertstr(el, matches[0]); + } + + if (what_to_do == '?') + goto display_matches; + + if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { + /* + * We found exact match. Add a space after + * it, unless we do filename completion and the + * object is a directory. + */ + el_insertstr(el, (*append_char_function)(matches[0])); + } else if (what_to_do == '!') { + display_matches: + /* + * More than one match and requested to list possible + * matches. + */ + + for(i=1, maxlen=0; matches[i]; i++) { + match_len = strlen(matches[i]); + if (match_len > maxlen) + maxlen = match_len; + } + matches_num = i - 1; + + /* newline to get on next line from command line */ + (void)fprintf(el->el_outfile, "\n"); + + /* + * If there are too many items, ask user for display + * confirmation. + */ + if (matches_num > query_items) { + (void)fprintf(el->el_outfile, + "Display all %d possibilities? (y or n) ", + matches_num); + (void)fflush(el->el_outfile); + if (getc(stdin) != 'y') + match_display = 0; + (void)fprintf(el->el_outfile, "\n"); + } + + if (match_display) + fn_display_match_list(el, matches, matches_num, + maxlen); + retval = CC_REDISPLAY; + } else if (matches[0][0]) { + /* + * There was some common match, but the name was + * not complete enough. Next tab will print possible + * completions. + */ + el_beep(el); + } else { + /* lcd is not a valid object - further specification */ + /* is needed */ + el_beep(el); + retval = CC_NORM; + } + + /* free elements of array and the array itself */ + for (i = 0; matches[i]; i++) + free(matches[i]); + free(matches), matches = NULL; + + return (retval); + } + return (CC_NORM); +} + +/* + * el-compatible wrapper around rl_complete; needed for key binding + */ +/* ARGSUSED */ +unsigned char +_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) +{ + return (unsigned char)fn_complete(el, NULL, NULL, + break_chars, NULL, NULL, 100, + NULL, NULL, NULL, NULL); +} diff --git a/filecomplete.h b/filecomplete.h new file mode 100644 index 000000000000..335ec7296e69 --- /dev/null +++ b/filecomplete.h @@ -0,0 +1,51 @@ +/* $NetBSD: filecomplete.h,v 1.4 2005/06/11 18:18:59 christos Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FILECOMPLETE_H_ +#define _FILECOMPLETE_H_ + +int fn_complete(EditLine *, + char *(*)(const char *, int), + char **(*)(const char *, int, int), + const char *, const char *, const char *(*)(const char *), int, + int *, int *, int *, int *); + +void fn_display_match_list(EditLine *, char **, int, int); +char *fn_tilde_expand(const char *); +char *fn_filename_completion_function(const char *, int); + +#endif diff --git a/hist.c b/hist.c index 31589b825e8d..282edcaf78f4 100644 --- a/hist.c +++ b/hist.c @@ -1,4 +1,4 @@ -/* $NetBSD: hist.c,v 1.9 2001/05/17 01:02:17 christos Exp $ */ +/* $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: hist.c,v 1.9 2001/05/17 01:02:17 christos Exp $"); +__RCSID("$NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * hist.c: History access functions */ -#include "sys.h" #include #include "el.h" @@ -133,18 +128,16 @@ hist_get(EditLine *el) el->el_history.eventno = h; return (CC_ERROR); } - (void) strncpy(el->el_line.buffer, hp, + (void) strlcpy(el->el_line.buffer, hp, (size_t)(el->el_line.limit - el->el_line.buffer)); el->el_line.lastchar = el->el_line.buffer + strlen(el->el_line.buffer); - if (el->el_line.lastchar > el->el_line.buffer) { - if (el->el_line.lastchar[-1] == '\n') - el->el_line.lastchar--; - if (el->el_line.lastchar[-1] == ' ') - el->el_line.lastchar--; - if (el->el_line.lastchar < el->el_line.buffer) - el->el_line.lastchar = el->el_line.buffer; - } + if (el->el_line.lastchar > el->el_line.buffer + && el->el_line.lastchar[-1] == '\n') + el->el_line.lastchar--; + if (el->el_line.lastchar > el->el_line.buffer + && el->el_line.lastchar[-1] == ' ') + el->el_line.lastchar--; #ifdef KSHVI if (el->el_map.type == MAP_VI) el->el_line.cursor = el->el_line.buffer; @@ -156,21 +149,40 @@ hist_get(EditLine *el) } -/* hist_list() - * List history entries +/* hist_command() + * process a history command */ protected int -/*ARGSUSED*/ -hist_list(EditLine *el, int argc, char **argv) +hist_command(EditLine *el, int argc, const char **argv) { const char *str; + int num; + HistEvent ev; if (el->el_history.ref == NULL) return (-1); - for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) - (void) fprintf(el->el_outfile, "%d %s", - el->el_history.ev.num, str); - return (0); + + if (argc == 1 || strcmp(argv[1], "list") == 0) { + /* List history entries */ + + for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) + (void) fprintf(el->el_outfile, "%d %s", + el->el_history.ev.num, str); + return (0); + } + + if (argc != 3) + return (-1); + + num = (int)strtol(argv[2], NULL, 0); + + if (strcmp(argv[1], "size") == 0) + return history(el->el_history.ref, &ev, H_SETSIZE, num); + + if (strcmp(argv[1], "unique") == 0) + return history(el->el_history.ref, &ev, H_SETUNIQUE, num); + + return -1; } /* hist_enlargebuf() diff --git a/hist.h b/hist.h index 9023e612311d..46e14634adf8 100644 --- a/hist.h +++ b/hist.h @@ -1,4 +1,4 @@ -/* $NetBSD: hist.h,v 1.6 2001/01/10 07:45:41 jdolecek Exp $ */ +/* $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -66,7 +62,7 @@ typedef struct el_history_t { #define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL) #define HIST_LAST(el) HIST_FUN(el, H_LAST, NULL) #define HIST_PREV(el) HIST_FUN(el, H_PREV, NULL) -#define HIST_EVENT(el, num) HIST_FUN(el, H_EVENT, num) +#define HIST_SET(el, num) HIST_FUN(el, H_SET, num) #define HIST_LOAD(el, fname) HIST_FUN(el, H_LOAD fname) #define HIST_SAVE(el, fname) HIST_FUN(el, H_SAVE fname) @@ -74,7 +70,7 @@ protected int hist_init(EditLine *); protected void hist_end(EditLine *); protected el_action_t hist_get(EditLine *); protected int hist_set(EditLine *, hist_fun_t, ptr_t); -protected int hist_list(EditLine *, int, char **); +protected int hist_command(EditLine *, int, const char **); protected int hist_enlargebuf(EditLine *, size_t, size_t); #endif /* _h_el_hist */ diff --git a/histedit.h b/histedit.h index 9c3a2dc24014..40f0dd10e88e 100644 --- a/histedit.h +++ b/histedit.h @@ -1,4 +1,4 @@ -/* $NetBSD: histedit.h,v 1.17 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: histedit.h,v 1.28 2005/07/14 15:00:58 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -44,12 +40,20 @@ #ifndef _HISTEDIT_H_ #define _HISTEDIT_H_ +#define LIBEDIT_MAJOR 2 +#define LIBEDIT_MINOR 9 + #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* * ==== Editing ==== */ + typedef struct editline EditLine; /* @@ -61,7 +65,6 @@ typedef struct lineinfo { const char *lastchar; } LineInfo; - /* * EditLine editor function return codes. * For user-defined function interface @@ -81,16 +84,15 @@ typedef struct lineinfo { * Initialization, cleanup, and resetting */ EditLine *el_init(const char *, FILE *, FILE *, FILE *); -void el_reset(EditLine *); void el_end(EditLine *); - +void el_reset(EditLine *); /* * Get a line, a character or push a string back in the input queue */ const char *el_gets(EditLine *, int *); int el_getc(EditLine *, char *); -void el_push(EditLine *, const char *); +void el_push(EditLine *, char *); /* * Beep! @@ -101,13 +103,14 @@ void el_beep(EditLine *); * High level function internals control * Parses argc, argv array and executes builtin editline commands */ -int el_parse(EditLine *, int, char **); +int el_parse(EditLine *, int, const char **); /* * Low level editline access functions */ int el_set(EditLine *, int, ...); int el_get(EditLine *, int, void *); +unsigned char _el_fn_complete(EditLine *, int); /* * el_set/el_get parameters @@ -127,6 +130,9 @@ int el_get(EditLine *, int, void *); #define EL_EDITMODE 11 /* , int); */ #define EL_RPROMPT 12 /* , el_pfunc_t); */ #define EL_GETCFN 13 /* , el_rfunc_t); */ +#define EL_CLIENTDATA 14 /* , void *); */ +#define EL_UNBUFFERED 15 /* , int); */ +#define EL_PREP_TERM 16 /* , int); */ #define EL_BUILTIN_GETCFN (NULL) @@ -142,7 +148,6 @@ int el_source(EditLine *, const char *); */ void el_resize(EditLine *); - /* * User-defined function interface. */ @@ -150,6 +155,7 @@ const LineInfo *el_line(EditLine *); int el_insertstr(EditLine *, const char *); void el_deletestr(EditLine *, int); + /* * ==== History ==== */ @@ -177,7 +183,7 @@ int history(History *, HistEvent *, int, ...); #define H_PREV 5 /* , void); */ #define H_NEXT 6 /* , void); */ #define H_CURR 8 /* , const int); */ -#define H_SET 7 /* , void); */ +#define H_SET 7 /* , int); */ #define H_ADD 9 /* , const char *); */ #define H_ENTER 10 /* , const char *); */ #define H_APPEND 11 /* , const char *); */ @@ -189,5 +195,30 @@ int history(History *, HistEvent *, int, ...); #define H_LOAD 17 /* , const char *); */ #define H_SAVE 18 /* , const char *); */ #define H_CLEAR 19 /* , void); */ +#define H_SETUNIQUE 20 /* , int); */ +#define H_GETUNIQUE 21 /* , void); */ +#define H_DEL 22 /* , int); */ + + +/* + * ==== Tokenization ==== + */ + +typedef struct tokenizer Tokenizer; + +/* + * String tokenization functions, using simplified sh(1) quoting rules + */ +Tokenizer *tok_init(const char *); +void tok_end(Tokenizer *); +void tok_reset(Tokenizer *); +int tok_line(Tokenizer *, const LineInfo *, + int *, const char ***, int *, int *); +int tok_str(Tokenizer *, const char *, + int *, const char ***); + +#ifdef __cplusplus +} +#endif #endif /* _HISTEDIT_H_ */ diff --git a/history.c b/history.c index d048898023e9..6d880cfa2e43 100644 --- a/history.c +++ b/history.c @@ -1,4 +1,4 @@ -/* $NetBSD: history.c,v 1.18 2001/09/29 17:52:10 jdolecek Exp $ */ +/* $NetBSD: history.c,v 1.31 2005/08/01 14:34:06 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,24 +32,26 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: history.c,v 1.18 2001/09/29 17:52:10 jdolecek Exp $"); +__RCSID("$NetBSD: history.c,v 1.31 2005/08/01 14:34:06 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * hist.c: History access functions */ -#include "sys.h" - #include #include #include +#ifdef HAVE_VIS_H #include +#else +#include "np/vis.h" +#endif #include static const char hist_cookie[] = "_HiStOrY_V2_\n"; @@ -74,10 +72,12 @@ struct history { history_gfun_t h_prev; /* Get the previous element */ history_gfun_t h_curr; /* Get the current element */ history_sfun_t h_set; /* Set the current element */ + history_sfun_t h_del; /* Set the given element */ history_vfun_t h_clear; /* Clear the history list */ history_efun_t h_enter; /* Add an element */ history_efun_t h_add; /* Append to an element */ }; + #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) @@ -87,14 +87,24 @@ struct history { #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) +#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) +#define h_strdup(a) strdup(a) #define h_malloc(a) malloc(a) #define h_realloc(a, b) realloc((a), (b)) #define h_free(a) free(a) +typedef struct { + int num; + char *str; +} HistEventPrivate; + + private int history_setsize(History *, HistEvent *, int); private int history_getsize(History *, HistEvent *); +private int history_setunique(History *, HistEvent *, int); +private int history_getunique(History *, HistEvent *); private int history_set_fun(History *, History *); private int history_load(History *, const char *); private int history_save(History *, const char *); @@ -113,31 +123,41 @@ typedef struct hentry_t { HistEvent ev; /* What we return */ struct hentry_t *next; /* Next entry */ struct hentry_t *prev; /* Previous entry */ -} hentry_t; +} hentry_t; typedef struct history_t { - hentry_t list; /* Fake list header element */ - hentry_t *cursor; /* Current element in the list */ - int max; /* Maximum number of events */ - int cur; /* Current number of events */ + hentry_t list; /* Fake list header element */ + hentry_t *cursor; /* Current element in the list */ + int max; /* Maximum number of events */ + int cur; /* Current number of events */ int eventid; /* For generation of unique event id */ -} history_t; + int flags; /* History flags */ +#define H_UNIQUE 1 /* Store only unique elements */ +} history_t; -private int history_def_first(ptr_t, HistEvent *); -private int history_def_last(ptr_t, HistEvent *); private int history_def_next(ptr_t, HistEvent *); +private int history_def_first(ptr_t, HistEvent *); private int history_def_prev(ptr_t, HistEvent *); +private int history_def_last(ptr_t, HistEvent *); private int history_def_curr(ptr_t, HistEvent *); -private int history_def_set(ptr_t, HistEvent *, const int n); +private int history_def_set(ptr_t, HistEvent *, const int); +private void history_def_clear(ptr_t, HistEvent *); private int history_def_enter(ptr_t, HistEvent *, const char *); private int history_def_add(ptr_t, HistEvent *, const char *); -private void history_def_init(ptr_t *, HistEvent *, int); -private void history_def_clear(ptr_t, HistEvent *); +private int history_def_del(ptr_t, HistEvent *, const int); + +private int history_def_init(ptr_t *, HistEvent *, int); private int history_def_insert(history_t *, HistEvent *, const char *); private void history_def_delete(history_t *, HistEvent *, hentry_t *); -#define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num)) -#define history_def_getsize(p) (((history_t *) p)->cur) +#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) +#define history_def_getsize(p) (((history_t *)p)->cur) +#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) +#define history_def_setunique(p, uni) \ + if (uni) \ + (((history_t *)p)->flags) |= H_UNIQUE; \ + else \ + (((history_t *)p)->flags) &= ~H_UNIQUE #define he_strerror(code) he_errlist[code] #define he_seterrev(evp, code) {\ @@ -230,20 +250,19 @@ history_def_next(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->next; - else { + if (h->cursor == &h->list) { he_seterrev(ev, _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->next == &h->list) { he_seterrev(ev, _HE_END_REACHED); return (-1); } + h->cursor = h->cursor->next; + *ev = h->cursor->ev; + return (0); } @@ -256,21 +275,20 @@ history_def_prev(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->prev; - else { + if (h->cursor == &h->list) { he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->prev == &h->list) { he_seterrev(ev, _HE_START_REACHED); return (-1); } + h->cursor = h->cursor->prev; + *ev = h->cursor->ev; + return (0); } @@ -331,39 +349,59 @@ history_def_add(ptr_t p, HistEvent *ev, const char *str) history_t *h = (history_t *) p; size_t len; char *s; + HistEventPrivate *evp = (void *)&h->cursor->ev; if (h->cursor == &h->list) return (history_def_enter(p, ev, str)); - len = strlen(h->cursor->ev.str) + strlen(str) + 1; + len = strlen(evp->str) + strlen(str) + 1; s = (char *) h_malloc(len); - if (!s) { + if (s == NULL) { he_seterrev(ev, _HE_MALLOC_FAILED); return (-1); } (void) strlcpy(s, h->cursor->ev.str, len); (void) strlcat(s, str, len); - /* LINTED const cast */ - h_free((ptr_t) h->cursor->ev.str); - h->cursor->ev.str = s; + h_free((ptr_t)evp->str); + evp->str = s; *ev = h->cursor->ev; return (0); } +/* history_def_del(): + * Delete element hp of the h list + */ +/* ARGSUSED */ +private int +history_def_del(ptr_t p, HistEvent *ev __attribute__((__unused__)), + const int num) +{ + history_t *h = (history_t *) p; + if (history_def_set(h, ev, num) != 0) + return (-1); + ev->str = strdup(h->cursor->ev.str); + ev->num = h->cursor->ev.num; + history_def_delete(h, ev, h->cursor); + return (0); +} + + /* history_def_delete(): * Delete element hp of the h list */ /* ARGSUSED */ private void -history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp) +history_def_delete(history_t *h, + HistEvent *ev __attribute__((__unused__)), hentry_t *hp) { - + HistEventPrivate *evp = (void *)&hp->ev; if (hp == &h->list) abort(); + if (h->cursor == hp) + h->cursor = hp->prev; hp->prev->next = hp->next; hp->next->prev = hp->prev; - /* LINTED const cast */ - h_free((ptr_t) hp->ev.str); + h_free((ptr_t) evp->str); h_free(hp); h->cur--; } @@ -377,11 +415,11 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str) { h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); - if (h->cursor) - h->cursor->ev.str = strdup(str); - if (!h->cursor || !h->cursor->ev.str) { - he_seterrev(ev, _HE_MALLOC_FAILED); - return (-1); + if (h->cursor == NULL) + goto oomem; + if ((h->cursor->ev.str = h_strdup(str)) == NULL) { + h_free((ptr_t)h->cursor); + goto oomem; } h->cursor->ev.num = ++h->eventid; h->cursor->next = h->list.next; @@ -392,6 +430,9 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str) *ev = h->cursor->ev; return (0); +oomem: + he_seterrev(ev, _HE_MALLOC_FAILED); + return (-1); } @@ -403,6 +444,10 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) { history_t *h = (history_t *) p; + if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && + strcmp(h->list.next->ev.str, str) == 0) + return (0); + if (history_def_insert(h, ev, str) == -1) return (-1); /* error, keep error message */ @@ -413,7 +458,7 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) while (h->cur > h->max && h->cur > 0) history_def_delete(h, ev, h->list.prev); - return (0); + return (1); } @@ -421,10 +466,12 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) * Default history initialization function */ /* ARGSUSED */ -private void -history_def_init(ptr_t *p, HistEvent *ev, int n) +private int +history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) { history_t *h = (history_t *) h_malloc(sizeof(history_t)); + if (h == NULL) + return -1; if (n <= 0) n = 0; @@ -435,7 +482,9 @@ history_def_init(ptr_t *p, HistEvent *ev, int n) h->list.ev.str = NULL; h->list.ev.num = 0; h->cursor = &h->list; + h->flags = 0; *p = (ptr_t) h; + return 0; } @@ -464,10 +513,15 @@ history_def_clear(ptr_t p, HistEvent *ev) public History * history_init(void) { - History *h = (History *) h_malloc(sizeof(History)); HistEvent ev; + History *h = (History *) h_malloc(sizeof(History)); + if (h == NULL) + return NULL; - history_def_init(&h->h_ref, &ev, 0); + if (history_def_init(&h->h_ref, &ev, 0) == -1) { + h_free((ptr_t)h); + return NULL; + } h->h_ent = -1; h->h_next = history_def_next; h->h_first = history_def_first; @@ -478,6 +532,7 @@ history_init(void) h->h_clear = history_def_clear; h->h_enter = history_def_enter; h->h_add = history_def_add; + h->h_del = history_def_del; return (h); } @@ -493,6 +548,7 @@ history_end(History *h) if (h->h_next == history_def_next) history_def_clear(h->h_ref, &ev); + h_free(h); } @@ -523,18 +579,46 @@ history_setsize(History *h, HistEvent *ev, int num) private int history_getsize(History *h, HistEvent *ev) { - int retval = 0; + if (h->h_next != history_def_next) { + he_seterrev(ev, _HE_NOT_ALLOWED); + return (-1); + } + ev->num = history_def_getsize(h->h_ref); + if (ev->num < -1) { + he_seterrev(ev, _HE_SIZE_NEGATIVE); + return (-1); + } + return (0); +} + + +/* history_setunique(): + * Set if adjacent equal events should not be entered in history. + */ +private int +history_setunique(History *h, HistEvent *ev, int uni) +{ if (h->h_next != history_def_next) { he_seterrev(ev, _HE_NOT_ALLOWED); return (-1); } - retval = history_def_getsize(h->h_ref); - if (retval < -1) { - he_seterrev(ev, _HE_SIZE_NEGATIVE); + history_def_setunique(h->h_ref, uni); + return (0); +} + + +/* history_getunique(): + * Get if adjacent equal events should not be entered in history. + */ +private int +history_getunique(History *h, HistEvent *ev) +{ + if (h->h_next != history_def_next) { + he_seterrev(ev, _HE_NOT_ALLOWED); return (-1); } - ev->num = retval; + ev->num = history_def_getunique(h->h_ref); return (0); } @@ -550,7 +634,7 @@ history_set_fun(History *h, History *nh) if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || - nh->h_ref == NULL) { + nh->h_del == NULL || nh->h_ref == NULL) { if (h->h_next != history_def_next) { history_def_init(&h->h_ref, &ev, 0); h->h_first = history_def_first; @@ -562,6 +646,7 @@ history_set_fun(History *h, History *nh) h->h_clear = history_def_clear; h->h_enter = history_def_enter; h->h_add = history_def_add; + h->h_del = history_def_del; } return (-1); } @@ -578,6 +663,7 @@ history_set_fun(History *h, History *nh) h->h_clear = nh->h_clear; h->h_enter = nh->h_enter; h->h_add = nh->h_add; + h->h_del = nh->h_del; return (0); } @@ -606,6 +692,8 @@ history_load(History *h, const char *fname) goto done; ptr = h_malloc(max_size = 1024); + if (ptr == NULL) + goto done; for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { char c = line[sz]; @@ -615,15 +703,24 @@ history_load(History *h, const char *fname) line[sz] = '\0'; if (max_size < sz) { - max_size = (sz + 1023) & ~1023; - ptr = h_realloc(ptr, max_size); + char *nptr; + max_size = (sz + 1024) & ~1023; + nptr = h_realloc(ptr, max_size); + if (nptr == NULL) { + i = -1; + goto oomem; + } + ptr = nptr; } (void) strunvis(ptr, line); line[sz] = c; - HENTER(h, &ev, ptr); + if (HENTER(h, &ev, ptr) == -1) { + h_free((ptr_t)ptr); + return -1; + } } - h_free(ptr); - +oomem: + h_free((ptr_t)ptr); done: (void) fclose(fp); return (i); @@ -638,28 +735,40 @@ history_save(History *h, const char *fname) { FILE *fp; HistEvent ev; - int i = 0, retval; + int i = -1, retval; size_t len, max_size; char *ptr; if ((fp = fopen(fname, "w")) == NULL) return (-1); - (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR); - (void) fputs(hist_cookie, fp); + if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) + goto done; + if (fputs(hist_cookie, fp) == EOF) + goto done; ptr = h_malloc(max_size = 1024); - for (retval = HLAST(h, &ev); + if (ptr == NULL) + goto done; + for (i = 0, retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++) { len = strlen(ev.str) * 4; if (len >= max_size) { - max_size = (len + 1023) & 1023; - ptr = h_realloc(ptr, max_size); + char *nptr; + max_size = (len + 1024) & ~1023; + nptr = h_realloc(ptr, max_size); + if (nptr == NULL) { + i = -1; + goto oomem; + } + ptr = nptr; } (void) strvis(ptr, ev.str, VIS_WHITE); - (void) fprintf(fp, "%s\n", ev.str); + (void) fprintf(fp, "%s\n", ptr); } - h_free(ptr); +oomem: + h_free((ptr_t)ptr); +done: (void) fclose(fp); return (i); } @@ -758,11 +867,23 @@ history(History *h, HistEvent *ev, int fun, ...) retval = history_setsize(h, ev, va_arg(va, int)); break; + case H_GETUNIQUE: + retval = history_getunique(h, ev); + break; + + case H_SETUNIQUE: + retval = history_setunique(h, ev, va_arg(va, int)); + break; + case H_ADD: str = va_arg(va, const char *); retval = HADD(h, ev, str); break; + case H_DEL: + retval = HDEL(h, ev, va_arg(va, const int)); + break; + case H_ENTER: str = va_arg(va, const char *); if ((retval = HENTER(h, ev, str)) != -1) @@ -847,6 +968,7 @@ history(History *h, HistEvent *ev, int fun, ...) hf.h_clear = va_arg(va, history_vfun_t); hf.h_enter = va_arg(va, history_efun_t); hf.h_add = va_arg(va, history_efun_t); + hf.h_del = va_arg(va, history_sfun_t); if ((retval = history_set_fun(h, &hf)) == -1) he_seterrev(ev, _HE_PARAM_MISSING); diff --git a/key.c b/key.c index 716ffed1a44b..226a62f3c7a6 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.12 2001/05/17 01:02:17 christos Exp $ */ +/* $NetBSD: key.c,v 1.16 2005/07/06 21:13:02 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,12 +32,12 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: key.c,v 1.12 2001/05/17 01:02:17 christos Exp $"); +__RCSID("$NetBSD: key.c,v 1.16 2005/07/06 21:13:02 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -66,7 +62,6 @@ __RCSID("$NetBSD: key.c,v 1.12 2001/05/17 01:02:17 christos Exp $"); * 1) It is not possible to have one key that is a * substr of another. */ -#include "sys.h" #include #include @@ -90,9 +85,11 @@ private int node_trav(EditLine *, key_node_t *, char *, private int node__try(EditLine *, key_node_t *, const char *, key_value_t *, int); private key_node_t *node__get(int); +private void node__free(key_node_t *); private void node__put(EditLine *, key_node_t *); -private int node__delete(EditLine *, key_node_t **, char *); -private int node_lookup(EditLine *, char *, key_node_t *, int); +private int node__delete(EditLine *, key_node_t **, const char *); +private int node_lookup(EditLine *, const char *, key_node_t *, + int); private int node_enum(EditLine *, key_node_t *, int); private int key__decode_char(char *, int, int); @@ -114,7 +111,6 @@ key_init(EditLine *el) return (0); } - /* key_end(): * Free the key maps */ @@ -124,8 +120,7 @@ key_end(EditLine *el) el_free((ptr_t) el->el_key.buf); el->el_key.buf = NULL; - /* XXX: provide a function to clear the keys */ - el->el_key.map = NULL; + node__free(el->el_key.map); } @@ -219,7 +214,7 @@ key_add(EditLine *el, const char *key, key_value_t *val, int ntype) * */ protected void -key_clear(EditLine *el, el_action_t *map, char *in) +key_clear(EditLine *el, el_action_t *map, const char *in) { if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && @@ -236,7 +231,7 @@ key_clear(EditLine *el, el_action_t *map, char *in) * they exists. */ protected int -key_delete(EditLine *el, char *key) +key_delete(EditLine *el, const char *key) { if (key[0] == '\0') { @@ -257,7 +252,7 @@ key_delete(EditLine *el, char *key) * Print entire el->el_key.map if null */ protected void -key_print(EditLine *el, char *key) +key_print(EditLine *el, const char *key) { /* do nothing if el->el_key.map is empty and null key specified */ @@ -356,7 +351,8 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int break; case XK_STR: case XK_EXE: - ptr->val.str = strdup(val->str); + if ((ptr->val.str = el_strdup(val->str)) == NULL) + return -1; break; default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); @@ -376,7 +372,7 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int * Delete node that matches str */ private int -node__delete(EditLine *el, key_node_t **inptr, char *str) +node__delete(EditLine *el, key_node_t **inptr, const char *str) { key_node_t *ptr; key_node_t *prev_ptr = NULL; @@ -471,14 +467,22 @@ node__get(int ch) return (ptr); } - +private void +node__free(key_node_t *k) +{ + if (k == NULL) + return; + node__free(k->sibling); + node__free(k->next); + el_free((ptr_t) k); +} /* node_lookup(): * look for the str starting at node ptr. * Print if last node */ private int -node_lookup(EditLine *el, char *str, key_node_t *ptr, int cnt) +node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) { int ncnt; @@ -568,7 +572,7 @@ node_enum(EditLine *el, key_node_t *ptr, int cnt) * function specified by val */ protected void -key_kprint(EditLine *el, char *key, key_value_t *val, int ntype) +key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) { el_bindings_t *fp; char unparsbuf[EL_BUFSIZ]; @@ -644,9 +648,10 @@ key__decode_char(char *buf, int cnt, int ch) * Make a printable version of the ey */ protected char * -key__decode_str(char *str, char *buf, char *sep) +key__decode_str(const char *str, char *buf, const char *sep) { - char *b, *p; + char *b; + const char *p; b = buf; if (sep[0] != '\0') diff --git a/key.h b/key.h index 2212f4d5eb55..39a075c504e1 100644 --- a/key.h +++ b/key.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.5 2001/01/23 15:55:30 jdolecek Exp $ */ +/* $NetBSD: key.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -62,6 +58,10 @@ typedef struct el_key_t { #define XK_NOD 2 #define XK_EXE 3 +#undef key_end +#undef key_clear +#undef key_print + protected int key_init(EditLine *); protected void key_end(EditLine *); protected key_value_t *key_map_cmd(EditLine *, int); @@ -69,10 +69,11 @@ protected key_value_t *key_map_str(EditLine *, char *); protected void key_reset(EditLine *); protected int key_get(EditLine *, char *, key_value_t *); protected void key_add(EditLine *, const char *, key_value_t *, int); -protected void key_clear(EditLine *, el_action_t *, char *); -protected int key_delete(EditLine *, char *); -protected void key_print(EditLine *, char *); -protected void key_kprint(EditLine *, char *, key_value_t *, int); -protected char *key__decode_str(char *, char *, char *); +protected void key_clear(EditLine *, el_action_t *, const char *); +protected int key_delete(EditLine *, const char *); +protected void key_print(EditLine *, const char *); +protected void key_kprint(EditLine *, const char *, key_value_t *, + int); +protected char *key__decode_str(const char *, char *, const char *); #endif /* _h_el_key */ diff --git a/makelist b/makelist index 8e9835309d66..766d3b2eceed 100644 --- a/makelist +++ b/makelist @@ -1,5 +1,5 @@ #!/bin/sh - -# $NetBSD: makelist,v 1.7 2001/01/09 19:22:31 jdolecek Exp $ +# $NetBSD: makelist,v 1.9 2005/05/16 13:14:43 lukem Exp $ # # Copyright (c) 1992, 1993 # The Regents of the University of California. All rights reserved. @@ -15,11 +15,7 @@ # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. -# 4. Neither the name of the University nor the names of its contributors +# 3. Neither the name of the University nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # @@ -39,7 +35,7 @@ # makelist.sh: Automatically generate header files... -AWK=/usr/bin/awk +AWK=awk USAGE="Usage: $0 -h|-e|-fc|-fh|-bc|-bh|-m " if [ "x$1" = "x" ] diff --git a/map.c b/map.c index f9fcfdf0d534..8693fd696cb3 100644 --- a/map.c +++ b/map.c @@ -1,4 +1,4 @@ -/* $NetBSD: map.c,v 1.14 2001/01/09 17:22:09 jdolecek Exp $ */ +/* $NetBSD: map.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,25 +32,24 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: map.c,v 1.14 2001/01/09 17:22:09 jdolecek Exp $"); +__RCSID("$NetBSD: map.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $"); #endif #endif /* not lint && not SCCSID */ /* * map.c: Editor function definitions */ -#include "sys.h" #include #include "el.h" #define N_KEYS 256 -private void map_print_key(EditLine *, el_action_t *, char *); +private void map_print_key(EditLine *, el_action_t *, const char *); private void map_print_some_keys(EditLine *, el_action_t *, int, int); private void map_print_all_keys(EditLine *); private void map_init_nls(EditLine *); @@ -72,7 +67,7 @@ private const el_action_t el_map_emacs[] = { /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ + /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ @@ -191,7 +186,7 @@ private const el_action_t el_map_emacs[] = { /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ + /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_UNASSIGNED, /* M-^@ */ /* 129 */ ED_UNASSIGNED, /* M-^A */ /* 130 */ ED_UNASSIGNED, /* M-^B */ @@ -380,7 +375,7 @@ private const el_action_t el_map_vi_insert[] = { /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ + /* 8 */ VI_DELETE_PREV_CHAR, /* ^H */ /* BackSpace key */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* Tab Key */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ @@ -500,135 +495,135 @@ private const el_action_t el_map_vi_insert[] = { /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ - /* 128 */ ED_UNASSIGNED, /* M-^@ */ - /* 129 */ ED_UNASSIGNED, /* M-^A */ - /* 130 */ ED_UNASSIGNED, /* M-^B */ - /* 131 */ ED_UNASSIGNED, /* M-^C */ - /* 132 */ ED_UNASSIGNED, /* M-^D */ - /* 133 */ ED_UNASSIGNED, /* M-^E */ - /* 134 */ ED_UNASSIGNED, /* M-^F */ - /* 135 */ ED_UNASSIGNED, /* M-^G */ - /* 136 */ ED_UNASSIGNED, /* M-^H */ - /* 137 */ ED_UNASSIGNED, /* M-^I */ - /* 138 */ ED_UNASSIGNED, /* M-^J */ - /* 139 */ ED_UNASSIGNED, /* M-^K */ - /* 140 */ ED_UNASSIGNED, /* M-^L */ - /* 141 */ ED_UNASSIGNED, /* M-^M */ - /* 142 */ ED_UNASSIGNED, /* M-^N */ - /* 143 */ ED_UNASSIGNED, /* M-^O */ - /* 144 */ ED_UNASSIGNED, /* M-^P */ - /* 145 */ ED_UNASSIGNED, /* M-^Q */ - /* 146 */ ED_UNASSIGNED, /* M-^R */ - /* 147 */ ED_UNASSIGNED, /* M-^S */ - /* 148 */ ED_UNASSIGNED, /* M-^T */ - /* 149 */ ED_UNASSIGNED, /* M-^U */ - /* 150 */ ED_UNASSIGNED, /* M-^V */ - /* 151 */ ED_UNASSIGNED, /* M-^W */ - /* 152 */ ED_UNASSIGNED, /* M-^X */ - /* 153 */ ED_UNASSIGNED, /* M-^Y */ - /* 154 */ ED_UNASSIGNED, /* M-^Z */ - /* 155 */ ED_UNASSIGNED, /* M-^[ */ - /* 156 */ ED_UNASSIGNED, /* M-^\ */ - /* 157 */ ED_UNASSIGNED, /* M-^] */ - /* 158 */ ED_UNASSIGNED, /* M-^^ */ - /* 159 */ ED_UNASSIGNED, /* M-^_ */ - /* 160 */ ED_UNASSIGNED, /* M-SPACE */ - /* 161 */ ED_UNASSIGNED, /* M-! */ - /* 162 */ ED_UNASSIGNED, /* M-" */ - /* 163 */ ED_UNASSIGNED, /* M-# */ - /* 164 */ ED_UNASSIGNED, /* M-$ */ - /* 165 */ ED_UNASSIGNED, /* M-% */ - /* 166 */ ED_UNASSIGNED, /* M-& */ - /* 167 */ ED_UNASSIGNED, /* M-' */ - /* 168 */ ED_UNASSIGNED, /* M-( */ - /* 169 */ ED_UNASSIGNED, /* M-) */ - /* 170 */ ED_UNASSIGNED, /* M-* */ - /* 171 */ ED_UNASSIGNED, /* M-+ */ - /* 172 */ ED_UNASSIGNED, /* M-, */ - /* 173 */ ED_UNASSIGNED, /* M-- */ - /* 174 */ ED_UNASSIGNED, /* M-. */ - /* 175 */ ED_UNASSIGNED, /* M-/ */ - /* 176 */ ED_UNASSIGNED, /* M-0 */ - /* 177 */ ED_UNASSIGNED, /* M-1 */ - /* 178 */ ED_UNASSIGNED, /* M-2 */ - /* 179 */ ED_UNASSIGNED, /* M-3 */ - /* 180 */ ED_UNASSIGNED, /* M-4 */ - /* 181 */ ED_UNASSIGNED, /* M-5 */ - /* 182 */ ED_UNASSIGNED, /* M-6 */ - /* 183 */ ED_UNASSIGNED, /* M-7 */ - /* 184 */ ED_UNASSIGNED, /* M-8 */ - /* 185 */ ED_UNASSIGNED, /* M-9 */ - /* 186 */ ED_UNASSIGNED, /* M-: */ - /* 187 */ ED_UNASSIGNED, /* M-; */ - /* 188 */ ED_UNASSIGNED, /* M-< */ - /* 189 */ ED_UNASSIGNED, /* M-= */ - /* 190 */ ED_UNASSIGNED, /* M-> */ - /* 191 */ ED_UNASSIGNED, /* M-? */ - /* 192 */ ED_UNASSIGNED, /* M-@ */ - /* 193 */ ED_UNASSIGNED, /* M-A */ - /* 194 */ ED_UNASSIGNED, /* M-B */ - /* 195 */ ED_UNASSIGNED, /* M-C */ - /* 196 */ ED_UNASSIGNED, /* M-D */ - /* 197 */ ED_UNASSIGNED, /* M-E */ - /* 198 */ ED_UNASSIGNED, /* M-F */ - /* 199 */ ED_UNASSIGNED, /* M-G */ - /* 200 */ ED_UNASSIGNED, /* M-H */ - /* 201 */ ED_UNASSIGNED, /* M-I */ - /* 202 */ ED_UNASSIGNED, /* M-J */ - /* 203 */ ED_UNASSIGNED, /* M-K */ - /* 204 */ ED_UNASSIGNED, /* M-L */ - /* 205 */ ED_UNASSIGNED, /* M-M */ - /* 206 */ ED_UNASSIGNED, /* M-N */ - /* 207 */ ED_UNASSIGNED, /* M-O */ - /* 208 */ ED_UNASSIGNED, /* M-P */ - /* 209 */ ED_UNASSIGNED, /* M-Q */ - /* 210 */ ED_UNASSIGNED, /* M-R */ - /* 211 */ ED_UNASSIGNED, /* M-S */ - /* 212 */ ED_UNASSIGNED, /* M-T */ - /* 213 */ ED_UNASSIGNED, /* M-U */ - /* 214 */ ED_UNASSIGNED, /* M-V */ - /* 215 */ ED_UNASSIGNED, /* M-W */ - /* 216 */ ED_UNASSIGNED, /* M-X */ - /* 217 */ ED_UNASSIGNED, /* M-Y */ - /* 218 */ ED_UNASSIGNED, /* M-Z */ - /* 219 */ ED_UNASSIGNED, /* M-[ */ - /* 220 */ ED_UNASSIGNED, /* M-\ */ - /* 221 */ ED_UNASSIGNED, /* M-] */ - /* 222 */ ED_UNASSIGNED, /* M-^ */ - /* 223 */ ED_UNASSIGNED, /* M-_ */ - /* 224 */ ED_UNASSIGNED, /* M-` */ - /* 225 */ ED_UNASSIGNED, /* M-a */ - /* 226 */ ED_UNASSIGNED, /* M-b */ - /* 227 */ ED_UNASSIGNED, /* M-c */ - /* 228 */ ED_UNASSIGNED, /* M-d */ - /* 229 */ ED_UNASSIGNED, /* M-e */ - /* 230 */ ED_UNASSIGNED, /* M-f */ - /* 231 */ ED_UNASSIGNED, /* M-g */ - /* 232 */ ED_UNASSIGNED, /* M-h */ - /* 233 */ ED_UNASSIGNED, /* M-i */ - /* 234 */ ED_UNASSIGNED, /* M-j */ - /* 235 */ ED_UNASSIGNED, /* M-k */ - /* 236 */ ED_UNASSIGNED, /* M-l */ - /* 237 */ ED_UNASSIGNED, /* M-m */ - /* 238 */ ED_UNASSIGNED, /* M-n */ - /* 239 */ ED_UNASSIGNED, /* M-o */ - /* 240 */ ED_UNASSIGNED, /* M-p */ - /* 241 */ ED_UNASSIGNED, /* M-q */ - /* 242 */ ED_UNASSIGNED, /* M-r */ - /* 243 */ ED_UNASSIGNED, /* M-s */ - /* 244 */ ED_UNASSIGNED, /* M-t */ - /* 245 */ ED_UNASSIGNED, /* M-u */ - /* 246 */ ED_UNASSIGNED, /* M-v */ - /* 247 */ ED_UNASSIGNED, /* M-w */ - /* 248 */ ED_UNASSIGNED, /* M-x */ - /* 249 */ ED_UNASSIGNED, /* M-y */ - /* 250 */ ED_UNASSIGNED, /* M-z */ - /* 251 */ ED_UNASSIGNED, /* M-{ */ - /* 252 */ ED_UNASSIGNED, /* M-| */ - /* 253 */ ED_UNASSIGNED, /* M-} */ - /* 254 */ ED_UNASSIGNED, /* M-~ */ - /* 255 */ ED_UNASSIGNED /* M-^? */ + /* 127 */ VI_DELETE_PREV_CHAR, /* ^? */ + /* 128 */ ED_INSERT, /* M-^@ */ + /* 129 */ ED_INSERT, /* M-^A */ + /* 130 */ ED_INSERT, /* M-^B */ + /* 131 */ ED_INSERT, /* M-^C */ + /* 132 */ ED_INSERT, /* M-^D */ + /* 133 */ ED_INSERT, /* M-^E */ + /* 134 */ ED_INSERT, /* M-^F */ + /* 135 */ ED_INSERT, /* M-^G */ + /* 136 */ ED_INSERT, /* M-^H */ + /* 137 */ ED_INSERT, /* M-^I */ + /* 138 */ ED_INSERT, /* M-^J */ + /* 139 */ ED_INSERT, /* M-^K */ + /* 140 */ ED_INSERT, /* M-^L */ + /* 141 */ ED_INSERT, /* M-^M */ + /* 142 */ ED_INSERT, /* M-^N */ + /* 143 */ ED_INSERT, /* M-^O */ + /* 144 */ ED_INSERT, /* M-^P */ + /* 145 */ ED_INSERT, /* M-^Q */ + /* 146 */ ED_INSERT, /* M-^R */ + /* 147 */ ED_INSERT, /* M-^S */ + /* 148 */ ED_INSERT, /* M-^T */ + /* 149 */ ED_INSERT, /* M-^U */ + /* 150 */ ED_INSERT, /* M-^V */ + /* 151 */ ED_INSERT, /* M-^W */ + /* 152 */ ED_INSERT, /* M-^X */ + /* 153 */ ED_INSERT, /* M-^Y */ + /* 154 */ ED_INSERT, /* M-^Z */ + /* 155 */ ED_INSERT, /* M-^[ */ + /* 156 */ ED_INSERT, /* M-^\ */ + /* 157 */ ED_INSERT, /* M-^] */ + /* 158 */ ED_INSERT, /* M-^^ */ + /* 159 */ ED_INSERT, /* M-^_ */ + /* 160 */ ED_INSERT, /* M-SPACE */ + /* 161 */ ED_INSERT, /* M-! */ + /* 162 */ ED_INSERT, /* M-" */ + /* 163 */ ED_INSERT, /* M-# */ + /* 164 */ ED_INSERT, /* M-$ */ + /* 165 */ ED_INSERT, /* M-% */ + /* 166 */ ED_INSERT, /* M-& */ + /* 167 */ ED_INSERT, /* M-' */ + /* 168 */ ED_INSERT, /* M-( */ + /* 169 */ ED_INSERT, /* M-) */ + /* 170 */ ED_INSERT, /* M-* */ + /* 171 */ ED_INSERT, /* M-+ */ + /* 172 */ ED_INSERT, /* M-, */ + /* 173 */ ED_INSERT, /* M-- */ + /* 174 */ ED_INSERT, /* M-. */ + /* 175 */ ED_INSERT, /* M-/ */ + /* 176 */ ED_INSERT, /* M-0 */ + /* 177 */ ED_INSERT, /* M-1 */ + /* 178 */ ED_INSERT, /* M-2 */ + /* 179 */ ED_INSERT, /* M-3 */ + /* 180 */ ED_INSERT, /* M-4 */ + /* 181 */ ED_INSERT, /* M-5 */ + /* 182 */ ED_INSERT, /* M-6 */ + /* 183 */ ED_INSERT, /* M-7 */ + /* 184 */ ED_INSERT, /* M-8 */ + /* 185 */ ED_INSERT, /* M-9 */ + /* 186 */ ED_INSERT, /* M-: */ + /* 187 */ ED_INSERT, /* M-; */ + /* 188 */ ED_INSERT, /* M-< */ + /* 189 */ ED_INSERT, /* M-= */ + /* 190 */ ED_INSERT, /* M-> */ + /* 191 */ ED_INSERT, /* M-? */ + /* 192 */ ED_INSERT, /* M-@ */ + /* 193 */ ED_INSERT, /* M-A */ + /* 194 */ ED_INSERT, /* M-B */ + /* 195 */ ED_INSERT, /* M-C */ + /* 196 */ ED_INSERT, /* M-D */ + /* 197 */ ED_INSERT, /* M-E */ + /* 198 */ ED_INSERT, /* M-F */ + /* 199 */ ED_INSERT, /* M-G */ + /* 200 */ ED_INSERT, /* M-H */ + /* 201 */ ED_INSERT, /* M-I */ + /* 202 */ ED_INSERT, /* M-J */ + /* 203 */ ED_INSERT, /* M-K */ + /* 204 */ ED_INSERT, /* M-L */ + /* 205 */ ED_INSERT, /* M-M */ + /* 206 */ ED_INSERT, /* M-N */ + /* 207 */ ED_INSERT, /* M-O */ + /* 208 */ ED_INSERT, /* M-P */ + /* 209 */ ED_INSERT, /* M-Q */ + /* 210 */ ED_INSERT, /* M-R */ + /* 211 */ ED_INSERT, /* M-S */ + /* 212 */ ED_INSERT, /* M-T */ + /* 213 */ ED_INSERT, /* M-U */ + /* 214 */ ED_INSERT, /* M-V */ + /* 215 */ ED_INSERT, /* M-W */ + /* 216 */ ED_INSERT, /* M-X */ + /* 217 */ ED_INSERT, /* M-Y */ + /* 218 */ ED_INSERT, /* M-Z */ + /* 219 */ ED_INSERT, /* M-[ */ + /* 220 */ ED_INSERT, /* M-\ */ + /* 221 */ ED_INSERT, /* M-] */ + /* 222 */ ED_INSERT, /* M-^ */ + /* 223 */ ED_INSERT, /* M-_ */ + /* 224 */ ED_INSERT, /* M-` */ + /* 225 */ ED_INSERT, /* M-a */ + /* 226 */ ED_INSERT, /* M-b */ + /* 227 */ ED_INSERT, /* M-c */ + /* 228 */ ED_INSERT, /* M-d */ + /* 229 */ ED_INSERT, /* M-e */ + /* 230 */ ED_INSERT, /* M-f */ + /* 231 */ ED_INSERT, /* M-g */ + /* 232 */ ED_INSERT, /* M-h */ + /* 233 */ ED_INSERT, /* M-i */ + /* 234 */ ED_INSERT, /* M-j */ + /* 235 */ ED_INSERT, /* M-k */ + /* 236 */ ED_INSERT, /* M-l */ + /* 237 */ ED_INSERT, /* M-m */ + /* 238 */ ED_INSERT, /* M-n */ + /* 239 */ ED_INSERT, /* M-o */ + /* 240 */ ED_INSERT, /* M-p */ + /* 241 */ ED_INSERT, /* M-q */ + /* 242 */ ED_INSERT, /* M-r */ + /* 243 */ ED_INSERT, /* M-s */ + /* 244 */ ED_INSERT, /* M-t */ + /* 245 */ ED_INSERT, /* M-u */ + /* 246 */ ED_INSERT, /* M-v */ + /* 247 */ ED_INSERT, /* M-w */ + /* 248 */ ED_INSERT, /* M-x */ + /* 249 */ ED_INSERT, /* M-y */ + /* 250 */ ED_INSERT, /* M-z */ + /* 251 */ ED_INSERT, /* M-{ */ + /* 252 */ ED_INSERT, /* M-| */ + /* 253 */ ED_INSERT, /* M-} */ + /* 254 */ ED_INSERT, /* M-~ */ + /* 255 */ ED_INSERT /* M-^? */ }; private const el_action_t el_map_vi_command[] = { @@ -640,7 +635,7 @@ private const el_action_t el_map_vi_command[] = { /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_UNASSIGNED, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_PREV_CHAR, /* ^H */ + /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ @@ -667,9 +662,9 @@ private const el_action_t el_map_vi_command[] = { /* 32 */ ED_NEXT_CHAR, /* SPACE */ /* 33 */ ED_UNASSIGNED, /* ! */ /* 34 */ ED_UNASSIGNED, /* " */ - /* 35 */ ED_UNASSIGNED, /* # */ + /* 35 */ VI_COMMENT_OUT, /* # */ /* 36 */ ED_MOVE_TO_END, /* $ */ - /* 37 */ ED_UNASSIGNED, /* % */ + /* 37 */ VI_MATCH, /* % */ /* 38 */ ED_UNASSIGNED, /* & */ /* 39 */ ED_UNASSIGNED, /* ' */ /* 40 */ ED_UNASSIGNED, /* ( */ @@ -678,7 +673,7 @@ private const el_action_t el_map_vi_command[] = { /* 43 */ ED_NEXT_HISTORY, /* + */ /* 44 */ VI_REPEAT_PREV_CHAR, /* , */ /* 45 */ ED_PREV_HISTORY, /* - */ - /* 46 */ ED_UNASSIGNED, /* . */ + /* 46 */ VI_REDO, /* . */ /* 47 */ VI_SEARCH_PREV, /* / */ /* 48 */ VI_ZERO, /* 0 */ /* 49 */ ED_ARGUMENT_DIGIT, /* 1 */ @@ -696,14 +691,14 @@ private const el_action_t el_map_vi_command[] = { /* 61 */ ED_UNASSIGNED, /* = */ /* 62 */ ED_UNASSIGNED, /* > */ /* 63 */ VI_SEARCH_NEXT, /* ? */ - /* 64 */ ED_UNASSIGNED, /* @ */ + /* 64 */ VI_ALIAS, /* @ */ /* 65 */ VI_ADD_AT_EOL, /* A */ - /* 66 */ VI_PREV_SPACE_WORD, /* B */ + /* 66 */ VI_PREV_BIG_WORD, /* B */ /* 67 */ VI_CHANGE_TO_EOL, /* C */ /* 68 */ ED_KILL_LINE, /* D */ - /* 69 */ VI_TO_END_WORD, /* E */ + /* 69 */ VI_END_BIG_WORD, /* E */ /* 70 */ VI_PREV_CHAR, /* F */ - /* 71 */ ED_UNASSIGNED, /* G */ + /* 71 */ VI_TO_HISTORY_LINE, /* G */ /* 72 */ ED_UNASSIGNED, /* H */ /* 73 */ VI_INSERT_AT_BOL, /* I */ /* 74 */ ED_SEARCH_NEXT_HISTORY, /* J */ @@ -717,17 +712,17 @@ private const el_action_t el_map_vi_command[] = { /* 82 */ VI_REPLACE_MODE, /* R */ /* 83 */ VI_SUBSTITUTE_LINE, /* S */ /* 84 */ VI_TO_PREV_CHAR, /* T */ - /* 85 */ ED_UNASSIGNED, /* U */ + /* 85 */ VI_UNDO_LINE, /* U */ /* 86 */ ED_UNASSIGNED, /* V */ - /* 87 */ VI_NEXT_SPACE_WORD, /* W */ + /* 87 */ VI_NEXT_BIG_WORD, /* W */ /* 88 */ ED_DELETE_PREV_CHAR, /* X */ - /* 89 */ ED_UNASSIGNED, /* Y */ + /* 89 */ VI_YANK_END, /* Y */ /* 90 */ ED_UNASSIGNED, /* Z */ /* 91 */ ED_SEQUENCE_LEAD_IN, /* [ */ /* 92 */ ED_UNASSIGNED, /* \ */ /* 93 */ ED_UNASSIGNED, /* ] */ /* 94 */ ED_MOVE_TO_BEG, /* ^ */ - /* 95 */ ED_UNASSIGNED, /* _ */ + /* 95 */ VI_HISTORY_WORD, /* _ */ /* 96 */ ED_UNASSIGNED, /* ` */ /* 97 */ VI_ADD, /* a */ /* 98 */ VI_PREV_WORD, /* b */ @@ -750,13 +745,13 @@ private const el_action_t el_map_vi_command[] = { /* 115 */ VI_SUBSTITUTE_CHAR, /* s */ /* 116 */ VI_TO_NEXT_CHAR, /* t */ /* 117 */ VI_UNDO, /* u */ - /* 118 */ ED_UNASSIGNED, /* v */ + /* 118 */ VI_HISTEDIT, /* v */ /* 119 */ VI_NEXT_WORD, /* w */ /* 120 */ ED_DELETE_NEXT_CHAR, /* x */ - /* 121 */ ED_UNASSIGNED, /* y */ + /* 121 */ VI_YANK, /* y */ /* 122 */ ED_UNASSIGNED, /* z */ /* 123 */ ED_UNASSIGNED, /* { */ - /* 124 */ ED_UNASSIGNED, /* | */ + /* 124 */ VI_TO_COLUMN, /* | */ /* 125 */ ED_UNASSIGNED, /* } */ /* 126 */ VI_CHANGE_CASE, /* ~ */ /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ @@ -1127,7 +1122,7 @@ map_get_editor(EditLine *el, const char **editor) * Print the function description for 1 key */ private void -map_print_key(EditLine *el, el_action_t *map, char *in) +map_print_key(EditLine *el, el_action_t *map, const char *in) { char outbuf[EL_BUFSIZ]; el_bindings_t *bp; @@ -1240,14 +1235,14 @@ map_print_all_keys(EditLine *el) * Add/remove/change bindings */ protected int -map_bind(EditLine *el, int argc, char **argv) +map_bind(EditLine *el, int argc, const char **argv) { el_action_t *map; int ntype, rem; - char *p; + const char *p; char inbuf[EL_BUFSIZ]; char outbuf[EL_BUFSIZ]; - char *in = NULL; + const char *in = NULL; char *out = NULL; el_bindings_t *bp; int cmd; diff --git a/map.h b/map.h index ed4b2537f65a..3b08f48be7a1 100644 --- a/map.h +++ b/map.h @@ -1,4 +1,4 @@ -/* $NetBSD: map.h,v 1.6 2001/01/09 17:22:09 jdolecek Exp $ */ +/* $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -67,7 +63,7 @@ typedef struct el_map_t { #define MAP_EMACS 0 #define MAP_VI 1 -protected int map_bind(EditLine *, int, char **); +protected int map_bind(EditLine *, int, const char **); protected int map_init(EditLine *); protected void map_end(EditLine *); protected void map_init_vi(EditLine *); diff --git a/parse.c b/parse.c index 3beeb1bbbdef..5552308ba6fe 100644 --- a/parse.c +++ b/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.14 2001/01/23 15:55:30 jdolecek Exp $ */ +/* $NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,12 +32,12 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: parse.c,v 1.14 2001/01/23 15:55:30 jdolecek Exp $"); +__RCSID("$NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -58,19 +54,17 @@ __RCSID("$NetBSD: parse.c,v 1.14 2001/01/23 15:55:30 jdolecek Exp $"); * settc * setty */ -#include "sys.h" #include "el.h" -#include "tokenizer.h" #include private const struct { - char *name; - int (*func)(EditLine *, int, char **); + const char *name; + int (*func)(EditLine *, int, const char **); } cmds[] = { { "bind", map_bind }, { "echotc", term_echotc }, { "edit", el_editmode }, - { "history", hist_list }, + { "history", hist_command }, { "telltc", term_telltc }, { "settc", term_settc }, { "setty", tty_stty }, @@ -84,12 +78,12 @@ private const struct { protected int parse_line(EditLine *el, const char *line) { - char **argv; + const char **argv; int argc; Tokenizer *tok; tok = tok_init(NULL); - tok_line(tok, line, &argc, &argv); + tok_str(tok, line, &argc, &argv); argc = el_parse(el, argc, argv); tok_end(tok); return (argc); @@ -100,9 +94,9 @@ parse_line(EditLine *el, const char *line) * Command dispatcher */ public int -el_parse(EditLine *el, int argc, char *argv[]) +el_parse(EditLine *el, int argc, const char *argv[]) { - char *ptr; + const char *ptr; int i; if (argc < 1) @@ -142,7 +136,7 @@ el_parse(EditLine *el, int argc, char *argv[]) * the appropriate character or -1 if the escape is not valid */ protected int -parse__escape(const char **const ptr) +parse__escape(const char **ptr) { const char *p; int c; @@ -207,7 +201,7 @@ parse__escape(const char **const ptr) c = *p; break; } - } else if (*p == '^' && isalpha((unsigned char) p[1])) { + } else if (*p == '^') { p++; c = (*p == '?') ? '\177' : (*p & 0237); } else @@ -215,6 +209,7 @@ parse__escape(const char **const ptr) *ptr = ++p; return (c); } + /* parse__string(): * Parse the escapes from in and put the raw string out */ @@ -237,6 +232,14 @@ parse__string(char *out, const char *in) *out++ = n; break; + case 'M': + if (in[1] == '-' && in[2] != '\0') { + *out++ = '\033'; + in += 2; + break; + } + /*FALLTHROUGH*/ + default: *out++ = *in++; break; diff --git a/parse.h b/parse.h index 4aaef2f834a4..58dced1aeaa2 100644 --- a/parse.h +++ b/parse.h @@ -1,4 +1,4 @@ -/* $NetBSD: parse.h,v 1.4 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: parse.h,v 1.6 2005/05/29 04:58:15 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -45,7 +41,7 @@ #define _h_el_parse protected int parse_line(EditLine *, const char *); -protected int parse__escape(const char ** const); +protected int parse__escape(const char **); protected char *parse__string(char *, const char *); protected int parse_cmd(EditLine *, const char *); diff --git a/prompt.c b/prompt.c index b41ac5b56f02..ec8855570f50 100644 --- a/prompt.c +++ b/prompt.c @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.c,v 1.8 2001/01/10 07:45:41 jdolecek Exp $ */ +/* $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: prompt.c,v 1.8 2001/01/10 07:45:41 jdolecek Exp $"); +__RCSID("$NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $"); #endif #endif /* not lint && not SCCSID */ /* * prompt.c: Prompt printing functions */ -#include "sys.h" #include #include "el.h" @@ -60,7 +55,7 @@ private char *prompt_default_r(EditLine *); */ private char * /*ARGSUSED*/ -prompt_default(EditLine *el) +prompt_default(EditLine *el __attribute__((__unused__))) { static char a[3] = {'?', ' ', '\0'}; @@ -73,7 +68,7 @@ prompt_default(EditLine *el) */ private char * /*ARGSUSED*/ -prompt_default_r(EditLine *el) +prompt_default_r(EditLine *el __attribute__((__unused__))) { static char a[1] = {'\0'}; @@ -128,7 +123,7 @@ prompt_init(EditLine *el) */ protected void /*ARGSUSED*/ -prompt_end(EditLine *el) +prompt_end(EditLine *el __attribute__((__unused__))) { } diff --git a/prompt.h b/prompt.h index 08810e22a0cb..d18110861f8d 100644 --- a/prompt.h +++ b/prompt.h @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.h,v 1.5 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/read.c b/read.c index 0103fb335979..610aac28194a 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.20 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: read.c,v 1.39 2005/08/02 12:11:14 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,12 +32,12 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: read.c,v 1.20 2001/09/27 19:29:50 christos Exp $"); +__RCSID("$NetBSD: read.c,v 1.39 2005/08/02 12:11:14 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -49,8 +45,8 @@ __RCSID("$NetBSD: read.c,v 1.20 2001/09/27 19:29:50 christos Exp $"); * read.c: Clean this junk up! This is horrible code. * Terminal read functions */ -#include "sys.h" #include +#include #include #include #include "el.h" @@ -98,6 +94,10 @@ el_read_getfn(EditLine *el) } +#ifndef MIN +#define MIN(A,B) ((A) < (B) ? (A) : (B)) +#endif + #ifdef DEBUG_EDIT private void read_debug(EditLine *el) @@ -122,7 +122,7 @@ read_debug(EditLine *el) */ /* ARGSUSED */ private int -read__fixio(int fd, int e) +read__fixio(int fd __attribute__((__unused__)), int e) { switch (e) { @@ -187,10 +187,6 @@ read_preread(EditLine *el) { int chrs = 0; - if (el->el_chared.c_macro.nline) { - el_free((ptr_t) el->el_chared.c_macro.nline); - el->el_chared.c_macro.nline = NULL; - } if (el->el_tty.t_mode == ED_IO) return (0); @@ -203,8 +199,7 @@ read_preread(EditLine *el) (size_t) MIN(chrs, EL_BUFSIZ - 1)); if (chrs > 0) { buf[chrs] = '\0'; - el->el_chared.c_macro.nline = strdup(buf); - el_push(el, el->el_chared.c_macro.nline); + el_push(el, buf); } } #endif /* FIONREAD */ @@ -217,18 +212,18 @@ read_preread(EditLine *el) * Push a macro */ public void -el_push(EditLine *el, const char *str) +el_push(EditLine *el, char *str) { c_macro_t *ma = &el->el_chared.c_macro; if (str != NULL && ma->level + 1 < EL_MAXMACRO) { ma->level++; - /* LINTED const cast */ - ma->macro[ma->level] = (char *) str; - } else { - term_beep(el); - term__flush(); + if ((ma->macro[ma->level] = el_strdup(str)) != NULL) + return; + ma->level--; } + term_beep(el); + term__flush(); } @@ -238,10 +233,10 @@ el_push(EditLine *el, const char *str) private int read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) { - el_action_t cmd = ED_UNASSIGNED; + el_action_t cmd; int num; - while (cmd == ED_UNASSIGNED || cmd == ED_SEQUENCE_LEAD_IN) { + do { if ((num = el_getc(el, ch)) != 1) /* if EOF or error */ return (num); @@ -280,7 +275,7 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) } if (el->el_map.alt == NULL) el->el_map.current = el->el_map.key; - } + } while (cmd == ED_SEQUENCE_LEAD_IN); *cmdnum = cmd; return (OKCMD); } @@ -325,14 +320,16 @@ el_getc(EditLine *el, char *cp) if (ma->level < 0) break; - if (*ma->macro[ma->level] == 0) { - ma->level--; + if (ma->macro[ma->level][ma->offset] == '\0') { + el_free(ma->macro[ma->level--]); + ma->offset = 0; continue; } - *cp = *ma->macro[ma->level]++ & 0377; - if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode - * On */ - ma->level--; + *cp = ma->macro[ma->level][ma->offset++] & 0377; + if (ma->macro[ma->level][ma->offset] == '\0') { + /* Needed for QuoteMode On */ + el_free(ma->macro[ma->level--]); + ma->offset = 0; } return (1); } @@ -353,6 +350,35 @@ el_getc(EditLine *el, char *cp) return (num_read); } +protected void +read_prepare(EditLine *el) +{ + if (el->el_flags & HANDLE_SIGNALS) + sig_set(el); + if (el->el_flags & NO_TTY) + return; + if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) + tty_rawmode(el); + + /* This is relatively cheap, and things go terribly wrong if + we have the wrong size. */ + el_resize(el); + re_clear_display(el); /* reset the display stuff */ + ch_reset(el, 0); + re_refresh(el); /* print the prompt */ + + if (el->el_flags & UNBUFFERED) + term__flush(); +} + +protected void +read_finish(EditLine *el) +{ + if ((el->el_flags & UNBUFFERED) == 0) + (void) tty_cookedmode(el); + if (el->el_flags & HANDLE_SIGNALS) + sig_clr(el); +} public const char * el_gets(EditLine *el, int *nread) @@ -361,13 +387,11 @@ el_gets(EditLine *el, int *nread) el_action_t cmdnum = 0; int num; /* how many chars we have read at NL */ char ch; + int crlf = 0; #ifdef FIONREAD c_macro_t *ma = &el->el_chared.c_macro; #endif /* FIONREAD */ - if (el->el_flags & HANDLE_SIGNALS) - sig_set(el); - if (el->el_flags & NO_TTY) { char *cp = el->el_line.buffer; size_t idx; @@ -381,6 +405,8 @@ el_gets(EditLine *el, int *nread) cp = &el->el_line.buffer[idx]; } cp++; + if (el->el_flags & UNBUFFERED) + break; if (cp[-1] == '\r' || cp[-1] == '\n') break; } @@ -391,8 +417,7 @@ el_gets(EditLine *el, int *nread) *nread = el->el_line.cursor - el->el_line.buffer; return (el->el_line.buffer); } - re_clear_display(el); /* reset the display stuff */ - ch_reset(el); + #ifdef FIONREAD if (el->el_tty.t_mode == EX_IO && ma->level < 0) { @@ -409,11 +434,16 @@ el_gets(EditLine *el, int *nread) } #endif /* FIONREAD */ - re_refresh(el); /* print the prompt */ + if ((el->el_flags & UNBUFFERED) == 0) + read_prepare(el); if (el->el_flags & EDIT_DISABLED) { - char *cp = el->el_line.buffer; + char *cp; size_t idx; + if ((el->el_flags & UNBUFFERED) == 0) + cp = el->el_line.buffer; + else + cp = el->el_line.lastchar; term__flush(); @@ -425,8 +455,13 @@ el_gets(EditLine *el, int *nread) break; cp = &el->el_line.buffer[idx]; } + if (*cp == 4) /* ought to be stty eof */ + break; cp++; - if (cp[-1] == '\r' || cp[-1] == '\n') + crlf = cp[-1] == '\r' || cp[-1] == '\n'; + if (el->el_flags & UNBUFFERED) + break; + if (crlf) break; } @@ -436,6 +471,7 @@ el_gets(EditLine *el, int *nread) *nread = el->el_line.cursor - el->el_line.buffer; return (el->el_line.buffer); } + for (num = OKCMD; num == OKCMD;) { /* while still editing this * line */ #ifdef DEBUG_EDIT @@ -449,7 +485,7 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ break; } - if ((int) cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ + if ((unsigned int)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, "ERROR: illegal command from key 0%o\r\n", ch); @@ -471,7 +507,24 @@ el_gets(EditLine *el, int *nread) "Error command = %d\n", cmdnum); } #endif /* DEBUG_READ */ + /* vi redo needs these way down the levels... */ + el->el_state.thiscmd = cmdnum; + el->el_state.thisch = ch; + if (el->el_map.type == MAP_VI && + el->el_map.current == el->el_map.key && + el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { + if (cmdnum == VI_DELETE_PREV_CHAR && + el->el_chared.c_redo.pos != el->el_chared.c_redo.buf + && isprint((unsigned char)el->el_chared.c_redo.pos[-1])) + el->el_chared.c_redo.pos--; + else + *el->el_chared.c_redo.pos++ = ch; + } retval = (*el->el_map.func[cmdnum]) (el, ch); +#ifdef DEBUG_READ + (void) fprintf(el->el_errfile, + "Returned state %d\n", retval ); +#endif /* DEBUG_READ */ /* save the last command here */ el->el_state.lastcmd = cmdnum; @@ -479,8 +532,6 @@ el_gets(EditLine *el, int *nread) /* use any return value */ switch (retval) { case CC_CURSOR: - el->el_state.argument = 1; - el->el_state.doingarg = 0; re_refresh_cursor(el); break; @@ -490,29 +541,29 @@ el_gets(EditLine *el, int *nread) /* FALLTHROUGH */ case CC_REFRESH: - el->el_state.argument = 1; - el->el_state.doingarg = 0; re_refresh(el); break; case CC_REFRESH_BEEP: - el->el_state.argument = 1; - el->el_state.doingarg = 0; re_refresh(el); term_beep(el); break; case CC_NORM: /* normal char */ - el->el_state.argument = 1; - el->el_state.doingarg = 0; break; case CC_ARGHACK: /* Suggested by Rich Salz */ /* */ - break; /* keep going... */ + continue; /* keep going... */ case CC_EOF: /* end of file typed */ - num = 0; + if ((el->el_flags & UNBUFFERED) == 0) + num = 0; + else if (num == -1) { + *el->el_line.lastchar++ = CONTROL('d'); + el->el_line.cursor = el->el_line.lastchar; + num = 1; + } break; case CC_NEWLINE: /* normal end of line */ @@ -526,10 +577,8 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ /* put (real) cursor in a known place */ re_clear_display(el); /* reset the display stuff */ - ch_reset(el); /* reset the input pointers */ + ch_reset(el, 1); /* reset the input pointers */ re_refresh(el); /* print the prompt again */ - el->el_state.argument = 1; - el->el_state.doingarg = 0; break; case CC_ERROR: @@ -538,20 +587,26 @@ el_gets(EditLine *el, int *nread) (void) fprintf(el->el_errfile, "*** editor ERROR ***\r\n\n"); #endif /* DEBUG_READ */ - el->el_state.argument = 1; - el->el_state.doingarg = 0; term_beep(el); term__flush(); break; } + el->el_state.argument = 1; + el->el_state.doingarg = 0; + el->el_chared.c_vcmd.action = NOP; + if (el->el_flags & UNBUFFERED) + break; } - /* make sure the tty is set up correctly */ - (void) tty_cookedmode(el); term__flush(); /* flush any buffered output */ - if (el->el_flags & HANDLE_SIGNALS) - sig_clr(el); - if (nread) - *nread = num; + /* make sure the tty is set up correctly */ + if ((el->el_flags & UNBUFFERED) == 0) { + read_finish(el); + if (nread) + *nread = num; + } else { + if (nread) + *nread = el->el_line.lastchar - el->el_line.buffer; + } return (num ? el->el_line.buffer : NULL); } diff --git a/read.h b/read.h index b01e77db2398..1982f47253bc 100644 --- a/read.h +++ b/read.h @@ -1,4 +1,4 @@ -/* $NetBSD: read.h,v 1.1 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: read.h,v 1.4 2004/02/27 14:52:18 christos Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -49,6 +49,8 @@ typedef struct el_read_t { } el_read_t; protected int read_init(EditLine *); +protected void read_prepare(EditLine *); +protected void read_finish(EditLine *); protected int el_read_setfn(EditLine *, el_rfunc_t); protected el_rfunc_t el_read_getfn(EditLine *); diff --git a/readline.c b/readline.c index 660697622402..7c752d12dfc1 100644 --- a/readline.c +++ b/readline.c @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.19 2001/01/10 08:10:45 jdolecek Exp $ */ +/* $NetBSD: readline.c,v 1.58 2005/07/14 15:00:58 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,9 +36,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.19 2001/01/10 08:10:45 jdolecek Exp $"); +__RCSID("$NetBSD: readline.c,v 1.58 2005/07/14 15:00:58 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -51,44 +51,79 @@ __RCSID("$NetBSD: readline.c,v 1.19 2001/01/10 08:10:45 jdolecek Exp $"); #include #include #include -#include "histedit.h" -#include "readline/readline.h" -#include "sys.h" +#include +#include +#ifdef HAVE_VIS_H +#include +#else +#include "np/vis.h" +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "readline/readline.h" +#include "filecomplete.h" /* for rl_complete() */ -#define TAB '\r' +#define TAB '\r' /* see comment at the #ifdef for sense of this */ -#define GDB_411_HACK +/* #define GDB_411_HACK */ /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ const char *rl_library_version = "EditLine wrapper"; -char *rl_readline_name = ""; +static char empty[] = { '\0' }; +static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; +static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', + '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; +char *rl_readline_name = empty; FILE *rl_instream = NULL; FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; +VCPFunction *rl_linefunc = NULL; +int rl_done = 0; +VFunction *rl_event_hook = NULL; int history_base = 1; /* probably never subject to change */ int history_length = 0; int max_input_history = 0; char history_expansion_char = '!'; char history_subst_char = '^'; -char *history_no_expand_chars = " \t\n=("; +char *history_no_expand_chars = expand_chars; Function *history_inhibit_expansion_function = NULL; +char *history_arg_extract(int start, int end, const char *str); int rl_inhibit_completion = 0; int rl_attempted_completion_over = 0; -char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; +char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; char *rl_completer_quote_characters = NULL; -CPFunction *rl_completion_entry_function = NULL; +Function *rl_completion_entry_function = NULL; CPPFunction *rl_attempted_completion_function = NULL; +Function *rl_pre_input_hook = NULL; +Function *rl_startup1_hook = NULL; +Function *rl_getc_function = NULL; +char *rl_terminal_name = NULL; +int rl_already_prompted = 0; +int rl_filename_completion_desired = 0; +int rl_ignore_completion_duplicates = 0; +int rl_catch_signals = 1; +VFunction *rl_redisplay_function = NULL; +Function *rl_startup_hook = NULL; +VFunction *rl_completion_display_matches_hook = NULL; +VFunction *rl_prep_term_function = NULL; +VFunction *rl_deprep_term_function = NULL; +/* + * The current prompt string. + */ +char *rl_prompt = NULL; /* * This is set to character indicating type of completion being done by * rl_complete_internal(); this is available for application completion @@ -107,7 +142,7 @@ int rl_completion_query_items = 100; * in the parsed text when it is passed to the completion function. * Shell uses this to help determine what kind of completing to do. */ -char *rl_special_prefixes = (char *)NULL; +char *rl_special_prefixes = NULL; /* * This is the character appended to the completed words if at the end of @@ -117,35 +152,29 @@ int rl_completion_append_character = ' '; /* stuff below is used internally by libedit for readline emulation */ -/* if not zero, non-unique completions always show list of possible matches */ -static int _rl_complete_show_all = 0; - static History *h = NULL; static EditLine *e = NULL; -static int el_rl_complete_cmdnum = 0; +static Function *map[256]; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); +static unsigned char _el_rl_tstp(EditLine *, int); static char *_get_prompt(EditLine *); static HIST_ENTRY *_move_history(int); -static int _history_search_gen(const char *, int, int); -static int _history_expand_command(const char *, size_t, char **); +static int _history_expand_command(const char *, size_t, size_t, + char **); static char *_rl_compat_sub(const char *, const char *, - const char *, int); -static int rl_complete_internal(int); -static int _rl_qsort_string_compare(const void *, const void *); - -/* - * needed for prompt switching in readline() - */ -static char *el_rl_prompt = NULL; + const char *, int); +static int _rl_event_read_char(EditLine *, char *); +static void _rl_update_pos(void); /* ARGSUSED */ static char * -_get_prompt(EditLine *el) +_get_prompt(EditLine *el __attribute__((__unused__))) { - return (el_rl_prompt); + rl_already_prompted = 1; + return (rl_prompt); } @@ -162,7 +191,7 @@ _move_history(int op) return (HIST_ENTRY *) NULL; rl_he.line = ev.str; - rl_he.data = ""; + rl_he.data = NULL; return (&rl_he); } @@ -180,7 +209,6 @@ rl_initialize(void) { HistEvent ev; const LineInfo *li; - int i; int editmode = 1; struct termios t; @@ -215,33 +243,39 @@ rl_initialize(void) el_set(e, EL_HIST, history, h); /* for proper prompt printing in readline() */ - el_rl_prompt = strdup(""); + rl_prompt = strdup(""); + if (rl_prompt == NULL) { + history_end(h); + el_end(e); + return -1; + } el_set(e, EL_PROMPT, _get_prompt); - el_set(e, EL_SIGNAL, 1); + el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ /* so this can be overriden */ el_set(e, EL_EDITOR, "emacs"); + if (rl_terminal_name != NULL) + el_set(e, EL_TERMINAL, rl_terminal_name); + else + el_get(e, EL_TERMINAL, &rl_terminal_name); /* - * Word completition - this has to go AFTER rebinding keys + * Word completion - this has to go AFTER rebinding keys * to emacs-style. */ el_set(e, EL_ADDFN, "rl_complete", - "ReadLine compatible completition function", + "ReadLine compatible completion function", _el_rl_complete); el_set(e, EL_BIND, "^I", "rl_complete", NULL); /* - * Find out where the rl_complete function was added; this is - * used later to detect that lastcmd was also rl_complete. + * Send TSTP when ^Z is pressed. */ - for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { - if (e->el_map.func[i] == _el_rl_complete) { - el_rl_complete_cmdnum = i; - break; - } - } + el_set(e, EL_ADDFN, "rl_tstp", + "ReadLine compatible suspend function", + _el_rl_tstp); + el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); /* read settings from configuration file */ el_source(e, NULL); @@ -251,9 +285,12 @@ rl_initialize(void) * and rl_line_buffer directly. */ li = el_line(e); - /* LINTED const cast */ - rl_line_buffer = (char *) li->buffer; - rl_point = rl_end = 0; + /* a cheesy way to get rid of const cast. */ + rl_line_buffer = memchr(li->buffer, *li->buffer, 1); + _rl_update_pos(); + + if (rl_startup_hook) + (*rl_startup_hook)(NULL, 0); return (0); } @@ -269,38 +306,58 @@ readline(const char *prompt) HistEvent ev; int count; const char *ret; + char *buf; + static int used_event_hook; if (e == NULL || h == NULL) rl_initialize(); + rl_done = 0; + /* update prompt accordingly to what has been passed */ if (!prompt) prompt = ""; - if (strcmp(el_rl_prompt, prompt) != 0) { - free(el_rl_prompt); - el_rl_prompt = strdup(prompt); + if (strcmp(rl_prompt, prompt) != 0) { + free(rl_prompt); + rl_prompt = strdup(prompt); + if (rl_prompt == NULL) + return NULL; } + + if (rl_pre_input_hook) + (*rl_pre_input_hook)(NULL, 0); + + if (rl_event_hook && !(e->el_flags&NO_TTY)) { + el_set(e, EL_GETCFN, _rl_event_read_char); + used_event_hook = 1; + } + + if (!rl_event_hook && used_event_hook) { + el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); + used_event_hook = 0; + } + + rl_already_prompted = 0; + /* get one line from input stream */ ret = el_gets(e, &count); if (ret && count > 0) { - char *foo; int lastidx; - foo = strdup(ret); + buf = strdup(ret); + if (buf == NULL) + return NULL; lastidx = count - 1; - if (foo[lastidx] == '\n') - foo[lastidx] = '\0'; - - ret = foo; + if (buf[lastidx] == '\n') + buf[lastidx] = '\0'; } else - ret = NULL; + buf = NULL; history(h, &ev, H_GETSIZE); history_length = ev.num; - /* LINTED const cast */ - return (char *) ret; + return buf; } /* @@ -321,59 +378,178 @@ using_history(void) /* * substitute ``what'' with ``with'', returning resulting string; if - * globally == 1, substitutes all occurences of what, otherwise only the + * globally == 1, substitutes all occurrences of what, otherwise only the * first one */ static char * _rl_compat_sub(const char *str, const char *what, const char *with, int globally) { - char *result; - const char *temp, *new; - int len, with_len, what_len, add; - size_t size, i; + const char *s; + char *r, *result; + size_t len, with_len, what_len; - result = malloc((size = 16)); - temp = str; + len = strlen(str); with_len = strlen(with); what_len = strlen(what); - len = 0; - do { - new = strstr(temp, what); - if (new) { - i = new - temp; - add = i + with_len; - if (i + add + 1 >= size) { - size += add + 1; - result = realloc(result, size); - } - (void) strncpy(&result[len], temp, i); - len += i; - (void) strcpy(&result[len], with); /* safe */ - len += with_len; - temp = new + what_len; - } else { - add = strlen(temp); - if (len + add + 1 >= size) { - size += add + 1; - result = realloc(result, size); - } - (void) strcpy(&result[len], temp); /* safe */ - len += add; - temp = NULL; - } - } while (temp && globally); - result[len] = '\0'; - return (result); + /* calculate length we need for result */ + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + len += with_len - what_len; + if (!globally) + break; + s += what_len; + } else + s++; + } + r = result = malloc(len + 1); + if (result == NULL) + return NULL; + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + (void)strncpy(r, with, with_len); + r += with_len; + s += what_len; + if (!globally) { + (void)strcpy(r, s); + return(result); + } + } else + *r++ = *s++; + } + *r = 0; + return(result); } +static char *last_search_pat; /* last !?pat[?] search pattern */ +static char *last_search_match; /* last !?pat[?] that matched */ + +const char * +get_history_event(const char *cmd, int *cindex, int qchar) +{ + int idx, sign, sub, num, begin, ret; + size_t len; + char *pat; + const char *rptr; + HistEvent ev; + + idx = *cindex; + if (cmd[idx++] != history_expansion_char) + return(NULL); + + /* find out which event to take */ + if (cmd[idx] == history_expansion_char || cmd[idx] == 0) { + if (history(h, &ev, H_FIRST) != 0) + return(NULL); + *cindex = cmd[idx]? (idx + 1):idx; + return(ev.str); + } + sign = 0; + if (cmd[idx] == '-') { + sign = 1; + idx++; + } + + if ('0' <= cmd[idx] && cmd[idx] <= '9') { + HIST_ENTRY *rl_he; + + num = 0; + while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { + num = num * 10 + cmd[idx] - '0'; + idx++; + } + if (sign) + num = history_length - num + 1; + + if (!(rl_he = history_get(num))) + return(NULL); + + *cindex = idx; + return(rl_he->line); + } + sub = 0; + if (cmd[idx] == '?') { + sub = 1; + idx++; + } + begin = idx; + while (cmd[idx]) { + if (cmd[idx] == '\n') + break; + if (sub && cmd[idx] == '?') + break; + if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' + || cmd[idx] == '\t' || cmd[idx] == qchar)) + break; + idx++; + } + len = idx - begin; + if (sub && cmd[idx] == '?') + idx++; + if (sub && len == 0 && last_search_pat && *last_search_pat) + pat = last_search_pat; + else if (len == 0) + return(NULL); + else { + if ((pat = malloc(len + 1)) == NULL) + return NULL; + (void)strncpy(pat, cmd + begin, len); + pat[len] = '\0'; + } + + if (history(h, &ev, H_CURR) != 0) { + if (pat != last_search_pat) + free(pat); + return (NULL); + } + num = ev.num; + + if (sub) { + if (pat != last_search_pat) { + if (last_search_pat) + free(last_search_pat); + last_search_pat = pat; + } + ret = history_search(pat, -1); + } else + ret = history_search_prefix(pat, -1); + + if (ret == -1) { + /* restore to end of list on failed search */ + history(h, &ev, H_FIRST); + (void)fprintf(rl_outstream, "%s: Event not found\n", pat); + if (pat != last_search_pat) + free(pat); + return(NULL); + } + + if (sub && len) { + if (last_search_match && last_search_match != pat) + free(last_search_match); + last_search_match = pat; + } + + if (pat != last_search_pat) + free(pat); + + if (history(h, &ev, H_CURR) != 0) + return(NULL); + *cindex = idx; + rptr = ev.str; + + /* roll back to original position */ + (void)history(h, &ev, H_SET, num); + + return rptr; +} /* * the real function doing history expansion - takes as argument command * to do and data upon which the command should be executed * does expansion the way I've understood readline documentation - * word designator ``%'' isn't supported (yet ?) * * returns 0 if data was not modified, 1 if it was and 2 if the string * should be only printed and not executed; in case of error, @@ -381,142 +557,145 @@ _rl_compat_sub(const char *str, const char *what, const char *with, * it's callers responsibility to free() string returned in *result */ static int -_history_expand_command(const char *command, size_t cmdlen, char **result) +_history_expand_command(const char *command, size_t offs, size_t cmdlen, + char **result) { - char **arr, *tempcmd, *line, *search = NULL, *cmd; - const char *event_data = NULL; + char *tmp, *search = NULL, *aptr; + const char *ptr, *cmd; static char *from = NULL, *to = NULL; - int start = -1, end = -1, max, i, idx; - int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; - int event_num = 0, retval; - size_t cmdsize; + int start, end, idx, has_mods = 0; + int p_on = 0, g_on = 0; *result = NULL; + aptr = NULL; + ptr = NULL; - cmd = alloca(cmdlen + 1); - (void) strncpy(cmd, command, cmdlen); - cmd[cmdlen] = 0; + /* First get event specifier */ + idx = 0; - idx = 1; - /* find out which event to take */ - if (cmd[idx] == history_expansion_char) { - event_num = history_length; - idx++; + if (strchr(":^*$", command[offs + 1])) { + char str[4]; + /* + * "!:" is shorthand for "!!:". + * "!^", "!*" and "!$" are shorthand for + * "!!:^", "!!:*" and "!!:$" respectively. + */ + str[0] = str[1] = '!'; + str[2] = '0'; + ptr = get_history_event(str, &idx, 0); + idx = (command[offs + 1] == ':')? 1:0; + has_mods = 1; } else { - int off, num; - size_t len; - off = idx; - while (cmd[off] && !strchr(":^$*-%", cmd[off])) - off++; - num = atoi(&cmd[idx]); - if (num != 0) { - event_num = num; - if (num < 0) - event_num += history_length + 1; + if (command[offs + 1] == '#') { + /* use command so far */ + if ((aptr = malloc(offs + 1)) == NULL) + return -1; + (void)strncpy(aptr, command, offs); + aptr[offs] = '\0'; + idx = 1; } else { - int prefix = 1, curr_num; - HistEvent ev; + int qchar; - len = off - idx; - if (cmd[idx] == '?') { - idx++, len--; - if (cmd[off - 1] == '?') - len--; - else if (cmd[off] != '\n' && cmd[off] != '\0') - return (-1); - prefix = 0; - } - search = alloca(len + 1); - (void) strncpy(search, &cmd[idx], len); - search[len] = '\0'; - - if (history(h, &ev, H_CURR) != 0) - return (-1); - curr_num = ev.num; - - if (prefix) - retval = history_search_prefix(search, -1); - else - retval = history_search(search, -1); - - if (retval == -1) { - fprintf(rl_outstream, "%s: Event not found\n", - search); - return (-1); - } - if (history(h, &ev, H_CURR) != 0) - return (-1); - event_data = ev.str; - - /* roll back to original position */ - history(h, &ev, H_NEXT_EVENT, curr_num); + qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; + ptr = get_history_event(command + offs, &idx, qchar); } - idx = off; + has_mods = command[offs + idx] == ':'; } - if (!event_data && event_num >= 0) { - HIST_ENTRY *rl_he; - rl_he = history_get(event_num); - if (!rl_he) - return (0); - event_data = rl_he->line; + if (ptr == NULL && aptr == NULL) + return(-1); + + if (!has_mods) { + *result = strdup(aptr? aptr : ptr); + if (aptr) + free(aptr); + return(1); + } + + cmd = command + offs + idx + 1; + + /* Now parse any word designators */ + + if (*cmd == '%') /* last word matched by ?pat? */ + tmp = strdup(last_search_match? last_search_match:""); + else if (strchr("^*$-0123456789", *cmd)) { + start = end = -1; + if (*cmd == '^') + start = end = 1, cmd++; + else if (*cmd == '$') + start = -1, cmd++; + else if (*cmd == '*') + start = 1, cmd++; + else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { + start = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + start = start * 10 + *cmd++ - '0'; + + if (*cmd == '-') { + if (isdigit((unsigned char) cmd[1])) { + cmd++; + end = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + end = end * 10 + *cmd++ - '0'; + } else if (cmd[1] == '$') { + cmd += 2; + end = -1; + } else { + cmd++; + end = -2; + } + } else if (*cmd == '*') + end = -1, cmd++; + else + end = start; + } + tmp = history_arg_extract(start, end, aptr? aptr:ptr); + if (tmp == NULL) { + (void)fprintf(rl_outstream, "%s: Bad word specifier", + command + offs + idx); + if (aptr) + free(aptr); + return(-1); + } } else - return (-1); + tmp = strdup(aptr? aptr:ptr); - if (cmd[idx] != ':') - return (-1); - cmd += idx + 1; + if (aptr) + free(aptr); - /* recognize cmd */ - if (*cmd == '^') - start = end = 1, cmd++; - else if (*cmd == '$') - start = end = -1, cmd++; - else if (*cmd == '*') - start = 1, end = -1, cmd++; - else if (isdigit((unsigned char) *cmd)) { - const char *temp; - int shifted = 0; - - start = atoi(cmd); - temp = cmd; - for (; isdigit((unsigned char) *cmd); cmd++); - if (temp != cmd) - shifted = 1; - if (shifted && *cmd == '-') { - if (!isdigit((unsigned char) *(cmd + 1))) - end = -2; - else { - end = atoi(cmd + 1); - for (; isdigit((unsigned char) *cmd); cmd++); - } - } else if (shifted && *cmd == '*') - end = -1, cmd++; - else if (shifted) - end = start; + if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) { + *result = tmp; + return(1); } - if (*cmd == ':') - cmd++; - line = strdup(event_data); for (; *cmd; cmd++) { if (*cmd == ':') continue; - else if (*cmd == 'h') - h_on = 1 | g_on, g_on = 0; - else if (*cmd == 't') - t_on = 1 | g_on, g_on = 0; - else if (*cmd == 'r') - r_on = 1 | g_on, g_on = 0; - else if (*cmd == 'e') - e_on = 1 | g_on, g_on = 0; - else if (*cmd == 'p') - p_on = 1 | g_on, g_on = 0; + else if (*cmd == 'h') { /* remove trailing path */ + if ((aptr = strrchr(tmp, '/')) != NULL) + *aptr = 0; + } else if (*cmd == 't') { /* remove leading path */ + if ((aptr = strrchr(tmp, '/')) != NULL) { + aptr = strdup(aptr + 1); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'r') { /* remove trailing suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) + *aptr = 0; + } else if (*cmd == 'e') { /* remove all but suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) { + aptr = strdup(aptr); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'p') /* print only */ + p_on = 1; else if (*cmd == 'g') g_on = 2; else if (*cmd == 's' || *cmd == '&') { char *what, *with, delim; - int len, from_len; + size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) @@ -525,23 +704,35 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) delim = *(++cmd), cmd++; size = 16; what = realloc(from, size); + if (what == NULL) { + free(from); + return 0; + } len = 0; for (; *cmd && *cmd != delim; cmd++) { - if (*cmd == '\\' - && *(cmd + 1) == delim) + if (*cmd == '\\' && cmd[1] == delim) cmd++; - if (len >= size) - what = realloc(what, - (size <<= 1)); + if (len >= size) { + char *nwhat; + nwhat = realloc(what, + (size <<= 1)); + if (nwhat == NULL) { + free(what); + return 0; + } + what = nwhat; + } what[len++] = *cmd; } what[len] = '\0'; from = what; if (*what == '\0') { free(what); - if (search) + if (search) { from = strdup(search); - else { + if (from == NULL) + return 0; + } else { from = NULL; return (-1); } @@ -552,16 +743,26 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) size = 16; with = realloc(to, size); + if (with == NULL) { + free(to); + return -1; + } len = 0; from_len = strlen(from); for (; *cmd && *cmd != delim; cmd++) { if (len + from_len + 1 >= size) { + char *nwith; size += from_len + 1; - with = realloc(with, size); + nwith = realloc(with, size); + if (nwith == NULL) { + free(with); + return -1; + } + with = nwith; } if (*cmd == '&') { /* safe */ - (void) strcpy(&with[len], from); + (void)strcpy(&with[len], from); len += from_len; continue; } @@ -573,79 +774,18 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } with[len] = '\0'; to = with; - - tempcmd = _rl_compat_sub(line, from, to, - (g_on) ? 1 : 0); - free(line); - line = tempcmd; - g_on = 0; } + + aptr = _rl_compat_sub(tmp, from, to, g_on); + if (aptr) { + free(tmp); + tmp = aptr; + } + g_on = 0; } } - - arr = history_tokenize(line); - free(line); /* no more needed */ - if (arr && *arr == NULL) - free(arr), arr = NULL; - if (!arr) - return (-1); - - /* find out max valid idx to array of array */ - max = 0; - for (i = 0; arr[i]; i++) - max++; - max--; - - /* set boundaries to something relevant */ - if (start < 0) - start = 1; - if (end < 0) - end = max - ((end < -1) ? 1 : 0); - - /* check boundaries ... */ - if (start > max || end > max || start > end) - return (-1); - - for (i = 0; i <= max; i++) { - char *temp; - if (h_on && (i == 1 || h_on > 1) && - (temp = strrchr(arr[i], '/'))) - *(temp + 1) = '\0'; - if (t_on && (i == 1 || t_on > 1) && - (temp = strrchr(arr[i], '/'))) - (void) strcpy(arr[i], temp + 1); - if (r_on && (i == 1 || r_on > 1) && - (temp = strrchr(arr[i], '.'))) - *temp = '\0'; - if (e_on && (i == 1 || e_on > 1) && - (temp = strrchr(arr[i], '.'))) - (void) strcpy(arr[i], temp); - } - - cmdsize = 1, cmdlen = 0; - tempcmd = malloc(cmdsize); - for (i = start; start <= i && i <= end; i++) { - int arr_len; - - arr_len = strlen(arr[i]); - if (cmdlen + arr_len + 1 >= cmdsize) { - cmdsize += arr_len + 1; - tempcmd = realloc(tempcmd, cmdsize); - } - (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ - cmdlen += arr_len; - tempcmd[cmdlen++] = ' '; /* add a space */ - } - while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) - cmdlen--; - tempcmd[cmdlen] = '\0'; - - *result = tempcmd; - - for (i = 0; i <= max; i++) - free(arr[i]); - free(arr), arr = (char **) NULL; - return (p_on) ? 2 : 1; + *result = tmp; + return (p_on? 2:1); } @@ -655,28 +795,45 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) int history_expand(char *str, char **output) { - int i, retval = 0, idx; - size_t size; - char *temp, *result; + int ret = 0; + size_t idx, i, size; + char *tmp, *result; if (h == NULL || e == NULL) rl_initialize(); - *output = strdup(str); /* do it early */ + if (history_expansion_char == 0) { + *output = strdup(str); + return(0); + } + *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - temp = alloca(4 + strlen(str) + 1); - temp[0] = temp[1] = history_expansion_char; - temp[2] = ':'; - temp[3] = 's'; - (void) strcpy(temp + 4, str); - str = temp; + *output = malloc(strlen(str) + 4 + 1); + if (*output == NULL) + return 0; + (*output)[0] = (*output)[1] = history_expansion_char; + (*output)[2] = ':'; + (*output)[3] = 's'; + (void)strcpy((*output) + 4, str); + str = *output; + } else { + *output = strdup(str); + if (*output == NULL) + return 0; } -#define ADD_STRING(what, len) \ + +#define ADD_STRING(what, len) \ { \ - if (idx + len + 1 > size) \ - result = realloc(result, (size += len + 1)); \ + if (idx + len + 1 > size) { \ + char *nresult = realloc(result, (size += len + 1));\ + if (nresult == NULL) { \ + free(*output); \ + return 0; \ + } \ + result = nresult; \ + } \ (void)strncpy(&result[idx], what, len); \ idx += len; \ result[idx] = '\0'; \ @@ -685,35 +842,35 @@ history_expand(char *str, char **output) result = NULL; size = idx = 0; for (i = 0; str[i];) { - int start, j, loop_again; - size_t len; + int qchar, loop_again; + size_t len, start, j; + qchar = 0; loop_again = 1; start = j = i; loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { - (void) strcpy(&str[j], &str[j + 1]); + (void)strcpy(&str[j], &str[j + 1]); continue; } if (!loop_again) { - if (str[j] == '?') { - while (str[j] && str[++j] != '?'); - if (str[j] == '?') - j++; - } else if (isspace((unsigned char) str[j])) + if (isspace((unsigned char) str[j]) + || str[j] == qchar) break; } if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || - (*history_inhibit_expansion_function)(str, j) == 0)) + (*history_inhibit_expansion_function)(str, + (int)j) == 0)) break; } - if (str[j] && str[j + 1] != '#' && loop_again) { + if (str[j] && loop_again) { i = j; + qchar = (j > 0 && str[j - 1] == '"' )? '"':0; j++; if (str[j] == history_expansion_char) j++; @@ -721,61 +878,116 @@ history_expand(char *str, char **output) goto loop; } len = i - start; - temp = &str[start]; - ADD_STRING(temp, len); + tmp = &str[start]; + ADD_STRING(tmp, len); - if (str[i] == '\0' || str[i] != history_expansion_char - || str[i + 1] == '#') { + if (str[i] == '\0' || str[i] != history_expansion_char) { len = j - i; - temp = &str[i]; - ADD_STRING(temp, len); + tmp = &str[i]; + ADD_STRING(tmp, len); if (start == 0) - retval = 0; + ret = 0; else - retval = 1; + ret = 1; break; } - retval = _history_expand_command(&str[i], (size_t) (j - i), - &temp); - if (retval != -1) { - len = strlen(temp); - ADD_STRING(temp, len); + ret = _history_expand_command (str, i, (j - i), &tmp); + if (ret > 0 && tmp) { + len = strlen(tmp); + ADD_STRING(tmp, len); + free(tmp); } i = j; - } /* for(i ...) */ + } - if (retval == 2) { - add_history(temp); + /* ret is 2 for "print only" option */ + if (ret == 2) { + add_history(result); #ifdef GDB_411_HACK /* gdb 4.11 has been shipped with readline, where */ /* history_expand() returned -1 when the line */ /* should not be executed; in readline 2.1+ */ /* it should return 2 in such a case */ - retval = -1; + ret = -1; #endif } free(*output); *output = result; - return (retval); + return (ret); } +/* +* Return a string consisting of arguments of "str" from "start" to "end". +*/ +char * +history_arg_extract(int start, int end, const char *str) +{ + size_t i, len, max; + char **arr, *result; + + arr = history_tokenize(str); + if (!arr) + return(NULL); + if (arr && *arr == NULL) { + free(arr); + return(NULL); + } + + for (max = 0; arr[max]; max++) + continue; + max--; + + if (start == '$') + start = max; + if (end == '$') + end = max; + if (end < 0) + end = max + end + 1; + if (start < 0) + start = end; + + if (start < 0 || end < 0 || start > max || end > max || start > end) + return(NULL); + + for (i = start, len = 0; i <= end; i++) + len += strlen(arr[i]) + 1; + len++; + result = malloc(len); + if (result == NULL) + return NULL; + + for (i = start, len = 0; i <= end; i++) { + (void)strcpy(result + len, arr[i]); + len += strlen(arr[i]); + if (i < end) + result[len++] = ' '; + } + result[len] = 0; + + for (i = 0; arr[i]; i++) + free(arr[i]); + free(arr); + + return(result); +} /* - * Parse the string into individual tokens, similarily to how shell would do it. + * Parse the string into individual tokens, + * similar to how shell would do it. */ char ** history_tokenize(const char *str) { - int size = 1, result_idx = 0, i, start; + int size = 1, idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; - for (i = 0; str[i]; i++) { + for (i = 0; str[i];) { while (isspace((unsigned char) str[i])) i++; start = i; - for (; str[i]; i++) { + for (; str[i];) { if (str[i] == '\\') { if (str[i+1] != '\0') i++; @@ -787,20 +999,35 @@ history_tokenize(const char *str) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; + if (str[i]) + i++; } - if (result_idx + 2 >= size) { + if (idx + 2 >= size) { + char **nresult; size <<= 1; - result = realloc(result, size * sizeof(char *)); + nresult = realloc(result, size * sizeof(char *)); + if (nresult == NULL) { + free(result); + return NULL; + } + result = nresult; } len = i - start; temp = malloc(len + 1); - (void) strncpy(temp, &str[start], len); + if (temp == NULL) { + for (i = 0; i < idx; i++) + free(result[i]); + free(result); + return NULL; + } + (void)strncpy(temp, &str[start], len); temp[len] = '\0'; - result[result_idx++] = temp; - result[result_idx] = NULL; + result[idx++] = temp; + result[idx] = NULL; + if (str[i]) + i++; } - return (result); } @@ -884,28 +1111,29 @@ history_get(int num) { static HIST_ENTRY she; HistEvent ev; - int i = 1, curr_num; + int curr_num; if (h == NULL || e == NULL) rl_initialize(); - /* rewind to beginning */ + /* save current position */ if (history(h, &ev, H_CURR) != 0) return (NULL); curr_num = ev.num; - if (history(h, &ev, H_LAST) != 0) + + /* start from most recent */ + if (history(h, &ev, H_FIRST) != 0) return (NULL); /* error */ - while (i < num && history(h, &ev, H_PREV) == 0) - i++; - if (i != num) - return (NULL); /* not so many entries */ + + /* look backwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVENT, num)) + return (NULL); she.line = ev.str; she.data = NULL; - /* rewind history to the same event it was before */ - (void) history(h, &ev, H_FIRST); - (void) history(h, &ev, H_NEXT_EVENT, curr_num); + /* restore pointer to where it was */ + (void)history(h, &ev, H_SET, curr_num); return (&she); } @@ -922,11 +1150,33 @@ add_history(const char *line) if (h == NULL || e == NULL) rl_initialize(); - (void) history(h, &ev, H_ENTER, line); + (void)history(h, &ev, H_ENTER, line); if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; - return (!(history_length > 0)); /* return 0 if all is okay */ + return (!(history_length > 0)); /* return 0 if all is okay */ +} + + +/* + * remove the specified entry from the history list and return it. + */ +HIST_ENTRY * +remove_history(int num) +{ + static HIST_ENTRY she; + HistEvent ev; + + if (h == NULL || e == NULL) + rl_initialize(); + + if (history(h, &ev, H_DEL, num) != 0) + return NULL; + + she.line = ev.str; + she.data = NULL; + + return &she; } @@ -1008,22 +1258,17 @@ int history_set_pos(int pos) { HistEvent ev; - int off, curr_num; + int curr_num; if (pos > history_length || pos < 0) return (-1); history(h, &ev, H_CURR); curr_num = ev.num; - history(h, &ev, H_FIRST); - off = 0; - while (off < pos && history(h, &ev, H_NEXT) == 0) - off++; - if (off != pos) { /* do a rollback in case of error */ - history(h, &ev, H_FIRST); - history(h, &ev, H_NEXT_EVENT, curr_num); - return (-1); + if (history(h, &ev, H_SET, pos)) { + history(h, &ev, H_SET, curr_num); + return(-1); } return (0); } @@ -1052,10 +1297,10 @@ next_history(void) /* - * generic history search function + * searches for first history event containing the str */ -static int -_history_search_gen(const char *str, int direction, int pos) +int +history_search(const char *str, int direction) { HistEvent ev; const char *strp; @@ -1066,38 +1311,25 @@ _history_search_gen(const char *str, int direction, int pos) curr_num = ev.num; for (;;) { - strp = strstr(ev.str, str); - if (strp && (pos < 0 || &ev.str[pos] == strp)) + if ((strp = strstr(ev.str, str)) != NULL) return (int) (strp - ev.str); - if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) + if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } - - history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - + history(h, &ev, H_SET, curr_num); return (-1); } -/* - * searches for first history event containing the str - */ -int -history_search(const char *str, int direction) -{ - - return (_history_search_gen(str, direction, -1)); -} - - /* * searches for first history event beginning with str */ int history_search_prefix(const char *str, int direction) { + HistEvent ev; - return (_history_search_gen(str, direction, 0)); + return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); } @@ -1107,7 +1339,8 @@ history_search_prefix(const char *str, int direction) */ /* ARGSUSED */ int -history_search_pos(const char *str, int direction, int pos) +history_search_pos(const char *str, + int direction __attribute__((__unused__)), int pos) { HistEvent ev; int curr_num, off; @@ -1138,140 +1371,20 @@ history_search_pos(const char *str, int direction, int pos) /********************************/ -/* completition functions */ +/* completion functions */ -/* - * does tilde expansion of strings of type ``~user/foo'' - * if ``user'' isn't valid user name or ``txt'' doesn't start - * w/ '~', returns pointer to strdup()ed copy of ``txt'' - * - * it's callers's responsibility to free() returned string - */ char * -tilde_expand(char *txt) +tilde_expand(char *name) { - struct passwd *pass; - char *temp; - size_t len = 0; - - if (txt[0] != '~') - return (strdup(txt)); - - temp = strchr(txt + 1, '/'); - if (temp == NULL) - temp = strdup(txt + 1); - else { - len = temp - txt + 1; /* text until string after slash */ - temp = malloc(len); - (void) strncpy(temp, txt + 1, len - 2); - temp[len - 2] = '\0'; - } - pass = getpwnam(temp); - free(temp); /* value no more needed */ - if (pass == NULL) - return (strdup(txt)); - - /* update pointer txt to point at string immedially following */ - /* first slash */ - txt += len; - - temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); - (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); - - return (temp); + return fn_tilde_expand(name); } - -/* - * return first found file name starting by the ``text'' or NULL if no - * such file can be found - * value of ``state'' is ignored - * - * it's caller's responsibility to free returned string - */ char * -filename_completion_function(const char *text, int state) +filename_completion_function(const char *name, int state) { - static DIR *dir = NULL; - static char *filename = NULL, *dirname = NULL; - static size_t filename_len = 0; - struct dirent *entry; - char *temp; - size_t len; - - if (state == 0 || dir == NULL) { - if (dir != NULL) { - closedir(dir); - dir = NULL; - } - temp = strrchr(text, '/'); - if (temp) { - temp++; - filename = realloc(filename, strlen(temp) + 1); - (void) strcpy(filename, temp); - len = temp - text; /* including last slash */ - dirname = realloc(dirname, len + 1); - (void) strncpy(dirname, text, len); - dirname[len] = '\0'; - } else { - filename = strdup(text); - dirname = NULL; - } - - /* support for ``~user'' syntax */ - if (dirname && *dirname == '~') { - temp = tilde_expand(dirname); - dirname = realloc(dirname, strlen(temp) + 1); - (void) strcpy(dirname, temp); /* safe */ - free(temp); /* no longer needed */ - } - /* will be used in cycle */ - filename_len = strlen(filename); - if (filename_len == 0) - return (NULL); /* no expansion possible */ - - dir = opendir(dirname ? dirname : "."); - if (!dir) - return (NULL); /* cannot open the directory */ - } - /* find the match */ - while ((entry = readdir(dir)) != NULL) { - /* otherwise, get first entry where first */ - /* filename_len characters are equal */ - if (entry->d_name[0] == filename[0] -#if defined(__SVR4) || defined(__linux__) - && strlen(entry->d_name) >= filename_len -#else - && entry->d_namlen >= filename_len -#endif - && strncmp(entry->d_name, filename, - filename_len) == 0) - break; - } - - if (entry) { /* match found */ - - struct stat stbuf; -#if defined(__SVR4) || defined(__linux__) - len = strlen(entry->d_name) + -#else - len = entry->d_namlen + -#endif - ((dirname) ? strlen(dirname) : 0) + 1 + 1; - temp = malloc(len); - (void) sprintf(temp, "%s%s", - dirname ? dirname : "", entry->d_name); /* safe */ - - /* test, if it's directory */ - if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) - strcat(temp, "/"); /* safe */ - } else - temp = NULL; - - return (temp); + return fn_filename_completion_function(name, state); } - /* * a completion generator for usernames; returns _first_ username * which starts with supplied text @@ -1282,7 +1395,8 @@ filename_completion_function(const char *text, int state) char * username_completion_function(const char *text, int state) { - struct passwd *pwd; + struct passwd *pwd, pwres; + char pwbuf[1024]; if (text[0] == '\0') return (NULL); @@ -1293,7 +1407,8 @@ username_completion_function(const char *text, int state) if (state == 0) setpwent(); - while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] + while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0 + && pwd != NULL && text[0] == pwd->pw_name[0] && strcmp(text, pwd->pw_name) == 0); if (pwd == NULL) { @@ -1305,81 +1420,14 @@ username_completion_function(const char *text, int state) /* - * el-compatible wrapper around rl_complete; needed for key binding + * el-compatible wrapper to send TSTP on ^Z */ /* ARGSUSED */ static unsigned char -_el_rl_complete(EditLine *el, int ch) +_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) { - return (unsigned char) rl_complete(0, ch); -} - - -/* - * returns list of completitions for text given - */ -char ** -completion_matches(const char *text, CPFunction *genfunc) -{ - char **match_list = NULL, *retstr, *prevstr; - size_t match_list_len, max_equal, which, i; - int matches; - - if (h == NULL || e == NULL) - rl_initialize(); - - matches = 0; - match_list_len = 1; - while ((retstr = (*genfunc) (text, matches)) != NULL) { - if (matches + 1 >= match_list_len) { - match_list_len <<= 1; - match_list = realloc(match_list, - match_list_len * sizeof(char *)); - } - match_list[++matches] = retstr; - } - - if (!match_list) - return (char **) NULL; /* nothing found */ - - /* find least denominator and insert it to match_list[0] */ - which = 2; - prevstr = match_list[1]; - max_equal = strlen(prevstr); - for (; which <= matches; which++) { - for (i = 0; i < max_equal && - prevstr[i] == match_list[which][i]; i++) - continue; - max_equal = i; - } - - retstr = malloc(max_equal + 1); - (void) strncpy(retstr, match_list[1], max_equal); - retstr[max_equal] = '\0'; - match_list[0] = retstr; - - /* add NULL as last pointer to the array */ - if (matches + 1 >= match_list_len) - match_list = realloc(match_list, - (match_list_len + 1) * sizeof(char *)); - match_list[matches + 1] = (char *) NULL; - - return (match_list); -} - -/* - * Sort function for qsort(). Just wrapper around strcasecmp(). - */ -static int -_rl_qsort_string_compare(i1, i2) - const void *i1, *i2; -{ - /*LINTED const castaway*/ - const char *s1 = ((const char **)i1)[0]; - /*LINTED const castaway*/ - const char *s2 = ((const char **)i2)[0]; - - return strcasecmp(s1, s2); + (void)kill(0, SIGTSTP); + return CC_NORM; } /* @@ -1388,206 +1436,59 @@ _rl_qsort_string_compare(i1, i2) * 'max' is maximum length of string in 'matches'. */ void -rl_display_match_list (matches, len, max) - char **matches; - int len, max; +rl_display_match_list(char **matches, int len, int max) { - int i, idx, limit, count; - int screenwidth = e->el_term.t_size.h; - /* - * Find out how many entries can be put on one line, count - * with two spaces between strings. - */ - limit = screenwidth / (max + 2); - if (limit == 0) - limit = 1; - - /* how many lines of output */ - count = len / limit; - if (count * limit < len) - count++; - - /* Sort the items if they are not already sorted. */ - qsort(&matches[1], (size_t)(len - 1), sizeof(char *), - _rl_qsort_string_compare); - - idx = 1; - for(; count > 0; count--) { - for(i=0; i < limit && matches[idx]; i++, idx++) - fprintf(e->el_outfile, "%-*s ", max, matches[idx]); - fprintf(e->el_outfile, "\n"); - } + fn_display_match_list(e, matches, len, max); } -/* - * Complete the word at or before point, called by rl_complete() - * 'what_to_do' says what to do with the completion. - * `?' means list the possible completions. - * TAB means do standard completion. - * `*' means insert all of the possible completions. - * `!' means to do standard completion, and list all possible completions if - * there is more than one. - * - * Note: '*' support is not implemented - */ -static int -rl_complete_internal(int what_to_do) +static const char * +/*ARGSUSED*/ +_rl_completion_append_character_function(const char *dummy + __attribute__((__unused__))) { - CPFunction *complet_func; - const LineInfo *li; - char *temp, **matches; - const char *ctemp; - size_t len; - - rl_completion_type = what_to_do; - - if (h == NULL || e == NULL) - rl_initialize(); - - complet_func = rl_completion_entry_function; - if (!complet_func) - complet_func = filename_completion_function; - - /* We now look backwards for the start of a filename/variable word */ - li = el_line(e); - ctemp = (const char *) li->cursor; - while (ctemp > li->buffer - && !strchr(rl_basic_word_break_characters, ctemp[-1]) - && (!rl_special_prefixes - || !strchr(rl_special_prefixes, ctemp[-1]) ) ) - ctemp--; - - len = li->cursor - ctemp; - temp = alloca(len + 1); - (void) strncpy(temp, ctemp, len); - temp[len] = '\0'; - - /* these can be used by function called in completion_matches() */ - /* or (*rl_attempted_completion_function)() */ - rl_point = li->cursor - li->buffer; - rl_end = li->lastchar - li->buffer; - - if (!rl_attempted_completion_function) - matches = completion_matches(temp, complet_func); - else { - int end = li->cursor - li->buffer; - matches = (*rl_attempted_completion_function) (temp, (int) - (end - len), end); - } - - if (matches) { - int i, retval = CC_REFRESH; - int matches_num, maxlen, match_len, match_display=1; - - /* - * Only replace the completed string with common part of - * possible matches if there is possible completion. - */ - if (matches[0][0] != '\0') { - el_deletestr(e, (int) len); - el_insertstr(e, matches[0]); - } - - if (what_to_do == '?') - goto display_matches; - - if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { - /* - * We found exact match. Add a space after - * it, unless we do filename completition and the - * object is a directory. - */ - size_t alen = strlen(matches[0]); - if ((complet_func != filename_completion_function - || (alen > 0 && (matches[0])[alen - 1] != '/')) - && rl_completion_append_character) { - char buf[2]; - buf[0] = rl_completion_append_character; - buf[1] = '\0'; - el_insertstr(e, buf); - } - } else if (what_to_do == '!') { - display_matches: - /* - * More than one match and requested to list possible - * matches. - */ - - for(i=1, maxlen=0; matches[i]; i++) { - match_len = strlen(matches[i]); - if (match_len > maxlen) - maxlen = match_len; - } - matches_num = i - 1; - - /* newline to get on next line from command line */ - fprintf(e->el_outfile, "\n"); - - /* - * If there are too many items, ask user for display - * confirmation. - */ - if (matches_num > rl_completion_query_items) { - fprintf(e->el_outfile, - "Display all %d possibilities? (y or n) ", - matches_num); - fflush(e->el_outfile); - if (getc(stdin) != 'y') - match_display = 0; - fprintf(e->el_outfile, "\n"); - } - - if (match_display) - rl_display_match_list(matches, matches_num, - maxlen); - retval = CC_REDISPLAY; - } else if (matches[0][0]) { - /* - * There was some common match, but the name was - * not complete enough. Next tab will print possible - * completions. - */ - el_beep(e); - } else { - /* lcd is not a valid object - further specification */ - /* is needed */ - el_beep(e); - retval = CC_NORM; - } - - /* free elements of array and the array itself */ - for (i = 0; matches[i]; i++) - free(matches[i]); - free(matches), matches = NULL; - - return (retval); - } - return (CC_NORM); + static char buf[2]; + buf[1] = rl_completion_append_character; + return buf; } /* * complete word at current point */ +/* ARGSUSED */ int -rl_complete(int ignore, int invoking_key) +rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { if (h == NULL || e == NULL) rl_initialize(); if (rl_inhibit_completion) { - rl_insert(ignore, invoking_key); + char arr[2]; + arr[0] = (char)invoking_key; + arr[1] = '\0'; + el_insertstr(e, arr); return (CC_REFRESH); - } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) - return rl_complete_internal('?'); - else if (_rl_complete_show_all) - return rl_complete_internal('!'); - else - return (rl_complete_internal(TAB)); + } + + /* Just look at how many global variables modify this operation! */ + return fn_complete(e, + (CPFunction *)rl_completion_entry_function, + rl_attempted_completion_function, + rl_basic_word_break_characters, rl_special_prefixes, + _rl_completion_append_character_function, rl_completion_query_items, + &rl_completion_type, &rl_attempted_completion_over, + &rl_point, &rl_end); } +/* ARGSUSED */ +static unsigned char +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) +{ + return (unsigned char)rl_complete(0, ch); +} + /* * misc other functions */ @@ -1633,7 +1534,7 @@ rl_read_key(void) */ /* ARGSUSED */ void -rl_reset_terminal(const char *p) +rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) @@ -1662,3 +1563,213 @@ rl_insert(int count, int c) return (0); } + +/*ARGSUSED*/ +int +rl_newline(int count, int c) +{ + /* + * Readline-4.0 appears to ignore the args. + */ + return rl_insert(1, '\n'); +} + +/*ARGSUSED*/ +static unsigned char +rl_bind_wrapper(EditLine *el, unsigned char c) +{ + if (map[c] == NULL) + return CC_ERROR; + + _rl_update_pos(); + + (*map[c])(NULL, c); + + /* If rl_done was set by the above call, deal with it here */ + if (rl_done) + return CC_EOF; + + return CC_NORM; +} + +int +rl_add_defun(const char *name, Function *fun, int c) +{ + char dest[8]; + if (c >= sizeof(map) / sizeof(map[0]) || c < 0) + return -1; + map[(unsigned char)c] = fun; + el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); + vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); + el_set(e, EL_BIND, dest, name); + return 0; +} + +void +rl_callback_read_char() +{ + int count = 0, done = 0; + const char *buf = el_gets(e, &count); + char *wbuf; + + if (buf == NULL || count-- <= 0) + return; + if (count == 0 && buf[0] == CTRL('d')) + done = 1; + if (buf[count] == '\n' || buf[count] == '\r') + done = 2; + + if (done && rl_linefunc != NULL) { + el_set(e, EL_UNBUFFERED, 0); + if (done == 2) { + if ((wbuf = strdup(buf)) != NULL) + wbuf[count] = '\0'; + } else + wbuf = NULL; + (*(void (*)(const char *))rl_linefunc)(wbuf); + el_set(e, EL_UNBUFFERED, 1); + } +} + +void +rl_callback_handler_install (const char *prompt, VCPFunction *linefunc) +{ + if (e == NULL) { + rl_initialize(); + } + if (rl_prompt) + free(rl_prompt); + rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; + rl_linefunc = linefunc; + el_set(e, EL_UNBUFFERED, 1); +} + +void +rl_callback_handler_remove(void) +{ + el_set(e, EL_UNBUFFERED, 0); +} + +void +rl_redisplay(void) +{ + char a[2]; + a[0] = CTRL('r'); + a[1] = '\0'; + el_push(e, a); +} + +int +rl_get_previous_history(int count, int key) +{ + char a[2]; + a[0] = key; + a[1] = '\0'; + while (count--) + el_push(e, a); + return 0; +} + +void +/*ARGSUSED*/ +rl_prep_terminal(int meta_flag) +{ + el_set(e, EL_PREP_TERM, 1); +} + +void +rl_deprep_terminal() +{ + el_set(e, EL_PREP_TERM, 0); +} + +int +rl_read_init_file(const char *s) +{ + return(el_source(e, s)); +} + +int +rl_parse_and_bind(const char *line) +{ + const char **argv; + int argc; + Tokenizer *tok; + + tok = tok_init(NULL); + tok_str(tok, line, &argc, &argv); + argc = el_parse(e, argc, argv); + tok_end(tok); + return (argc ? 1 : 0); +} + +int +rl_variable_bind(const char *var, const char *value) +{ + /* + * The proper return value is undocument, but this is what the + * readline source seems to do. + */ + return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); +} + +void +rl_stuff_char(int c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + el_insertstr(e, buf); +} + +static int +_rl_event_read_char(EditLine *el, char *cp) +{ + int n, num_read = 0; + + *cp = 0; + while (rl_event_hook) { + + (*rl_event_hook)(); + +#if defined(FIONREAD) + if (ioctl(el->el_infd, FIONREAD, &n) < 0) + return(-1); + if (n) + num_read = read(el->el_infd, cp, 1); + else + num_read = 0; +#elif defined(F_SETFL) && defined(O_NDELAY) + if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) + return(-1); + if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) + return(-1); + num_read = read(el->el_infd, cp, 1); + if (fcntl(el->el_infd, F_SETFL, n)) + return(-1); +#else + /* not non-blocking, but what you gonna do? */ + num_read = read(el->el_infd, cp, 1); + return(-1); +#endif + + if (num_read < 0 && errno == EAGAIN) + continue; + if (num_read == 0) + continue; + break; + } + if (!rl_event_hook) + el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); + return(num_read); +} + +static void +_rl_update_pos(void) +{ + const LineInfo *li = el_line(e); + + rl_point = li->cursor - li->buffer; + rl_end = li->lastchar - li->buffer; +} diff --git a/readline/Makefile b/readline/Makefile index ea8f093e174a..3d5111fe3bf2 100644 --- a/readline/Makefile +++ b/readline/Makefile @@ -1,13 +1,13 @@ -# $NetBSD: Makefile,v 1.4 2001/05/16 07:09:26 enami Exp $ +# $NetBSD: Makefile,v 1.7 2003/08/03 09:23:15 lukem Exp $ -.PATH: ${CURDIR}/.. +NOOBJ= # defined + +.include + +.PATH: ${NETBSDSRCDIR}/lib/libedit INCS= readline.h INCSDIR= /usr/include/readline -SYMLINKS= readline.h ${INCSDIR}/history.h - -MKOBJ= no - -incinstall:: linksinstall +INCSYMLINKS= readline.h ${INCSDIR}/history.h .include diff --git a/readline/readline.h b/readline/readline.h index cd59a4cc3b5f..3a7ab6a05570 100644 --- a/readline/readline.h +++ b/readline/readline.h @@ -1,4 +1,4 @@ -/* $NetBSD: readline.h,v 1.1 2001/01/05 21:15:50 jdolecek Exp $ */ +/* $NetBSD: readline.h,v 1.17 2005/07/14 15:00:58 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _READLINE_H_ -#define _READLINE_H_ +#define _READLINE_H_ #include @@ -45,6 +45,7 @@ /* typedefs */ typedef int Function(const char *, int); typedef void VFunction(void); +typedef void VCPFunction(char *); typedef char *CPFunction(const char *, int); typedef char **CPPFunction(const char *, int, int); @@ -53,8 +54,42 @@ typedef struct _hist_entry { const char *data; } HIST_ENTRY; +typedef struct _keymap_entry { + char type; +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + Function *function; +} KEYMAP_ENTRY; + +#define KEYMAP_SIZE 256 + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; +typedef KEYMAP_ENTRY *Keymap; + +#define control_character_threshold 0x20 +#define control_character_bit 0x40 + +#ifndef CTRL +#include +#if !defined(__sun__) && !defined(__hpux__) +#include +#endif +#ifndef CTRL +#define CTRL(c) ((c) & 037) +#endif +#endif +#ifndef UNCTRL +#define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit) +#endif + +#define RUBOUT 0x7f +#define ABORT_CHAR CTRL('G') + /* global variables used by readline enabled applications */ -__BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif extern const char *rl_library_version; extern char *rl_readline_name; extern FILE *rl_instream; @@ -66,12 +101,32 @@ extern int max_input_history; extern char *rl_basic_word_break_characters; extern char *rl_completer_word_break_characters; extern char *rl_completer_quote_characters; -extern CPFunction *rl_completion_entry_function; +extern Function *rl_completion_entry_function; extern CPPFunction *rl_attempted_completion_function; +extern int rl_attempted_completion_over; extern int rl_completion_type; extern int rl_completion_query_items; extern char *rl_special_prefixes; extern int rl_completion_append_character; +extern int rl_inhibit_completion; +extern Function *rl_pre_input_hook; +extern Function *rl_startup_hook; +extern char *rl_terminal_name; +extern int rl_already_prompted; +extern char *rl_prompt; +/* + * The following is not implemented + */ +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, + emacs_meta_keymap, + emacs_ctlx_keymap; +extern int rl_filename_completion_desired; +extern int rl_ignore_completion_duplicates; +extern Function *rl_getc_function; +extern VFunction *rl_redisplay_function; +extern VFunction *rl_completion_display_matches_hook; +extern VFunction *rl_prep_term_function; +extern VFunction *rl_deprep_term_function; /* supported functions */ char *readline(const char *); @@ -86,6 +141,7 @@ int history_is_stifled(void); int where_history(void); HIST_ENTRY *current_history(void); HIST_ENTRY *history_get(int); +HIST_ENTRY *remove_history(int); int history_total_bytes(void); int history_set_pos(int); HIST_ENTRY *previous_history(void); @@ -97,6 +153,8 @@ int read_history(const char *); int write_history(const char *); int history_expand(char *, char **); char **history_tokenize(const char *); +const char *get_history_event(const char *, int *, int); +char *history_arg_extract(int, int, const char *); char *tilde_expand(char *); char *filename_completion_function(const char *, int); @@ -109,6 +167,29 @@ void rl_display_match_list(char **, int, int); int rl_insert(int, int); void rl_reset_terminal(const char *); int rl_bind_key(int, int (*)(int, int)); -__END_DECLS +int rl_newline(int, int); +void rl_callback_read_char(void); +void rl_callback_handler_install(const char *, VCPFunction *); +void rl_callback_handler_remove(void); +void rl_redisplay(void); +int rl_get_previous_history(int, int); +void rl_prep_terminal(int); +void rl_deprep_terminal(void); +int rl_read_init_file(const char *); +int rl_parse_and_bind(const char *); +int rl_variable_bind(const char *, const char *); +void rl_stuff_char(int); +int rl_add_defun(const char *, Function *, int); + +/* + * The following are not implemented + */ +Keymap rl_get_keymap(void); +Keymap rl_make_bare_keymap(void); +int rl_generic_bind(int, const char *, const char *, Keymap); +int rl_bind_key_in_map(int, Function *, Keymap); +#ifdef __cplusplus +} +#endif #endif /* _READLINE_H_ */ diff --git a/refresh.c b/refresh.c index b2ef6e4f84b1..dd710034e7ba 100644 --- a/refresh.c +++ b/refresh.c @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.c,v 1.17 2001/04/13 00:53:11 lukem Exp $ */ +/* $NetBSD: refresh.c,v 1.26 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: refresh.c,v 1.17 2001/04/13 00:53:11 lukem Exp $"); +__RCSID("$NetBSD: refresh.c,v 1.26 2003/08/07 16:44:33 agc Exp $"); #endif #endif /* not lint && not SCCSID */ /* * refresh.c: Lower level screen refreshing functions */ -#include "sys.h" #include #include #include @@ -62,24 +57,24 @@ private void re_insert (EditLine *, char *, int, int, char *, int); private void re_delete(EditLine *, char *, int, int, int); private void re_fastputc(EditLine *, int); private void re__strncopy(char *, char *, size_t); -private void re__copy_and_pad(char *, char *, size_t); +private void re__copy_and_pad(char *, const char *, size_t); #ifdef DEBUG_REFRESH -private void re_printstr(EditLine *, char *, char *, char *); +private void re_printstr(EditLine *, const char *, char *, char *); #define __F el->el_errfile #define ELRE_ASSERT(a, b, c) do \ - if (a) { \ + if (/*CONSTCOND*/ a) { \ (void) fprintf b; \ c; \ } \ - while (0) + while (/*CONSTCOND*/0) #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) /* re_printstr(): * Print a string on the debugging pty */ private void -re_printstr(EditLine *el, char *str, char *f, char *t) +re_printstr(EditLine *el, const char *str, char *f, char *t) { ELRE_DEBUG(1, (__F, "%s:\"", str)); @@ -210,6 +205,14 @@ re_refresh(EditLine *el) el->el_refresh.r_cursor.h = 0; el->el_refresh.r_cursor.v = 0; + if (el->el_line.cursor >= el->el_line.lastchar) { + if (el->el_map.current == el->el_map.alt + && el->el_line.lastchar != el->el_line.buffer) + el->el_line.cursor = el->el_line.lastchar - 1; + else + el->el_line.cursor = el->el_line.lastchar; + } + cur.h = -1; /* set flag in case I'm not set */ cur.v = 0; @@ -319,7 +322,6 @@ re_goto_bottom(EditLine *el) { term_move_to_line(el, el->el_refresh.r_oldcv); - term__putc('\r'); term__putc('\n'); re_clear_display(el); term__flush(); @@ -332,7 +334,8 @@ re_goto_bottom(EditLine *el) */ private void /*ARGSUSED*/ -re_insert(EditLine *el, char *d, int dat, int dlen, char *s, int num) +re_insert(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, char *s, int num) { char *a, *b; @@ -375,7 +378,8 @@ re_insert(EditLine *el, char *d, int dat, int dlen, char *s, int num) */ private void /*ARGSUSED*/ -re_delete(EditLine *el, char *d, int dat, int dlen, int num) +re_delete(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, int num) { char *a, *b; @@ -908,9 +912,9 @@ re_update_line(EditLine *el, char *old, char *new, int i) * Copy string and pad with spaces */ private void -re__copy_and_pad(char *dst, char *src, size_t width) +re__copy_and_pad(char *dst, const char *src, size_t width) { - int i; + size_t i; for (i = 0; i < width; i++) { if (*src == '\0') @@ -934,6 +938,14 @@ re_refresh_cursor(EditLine *el) char *cp, c; int h, v, th; + if (el->el_line.cursor >= el->el_line.lastchar) { + if (el->el_map.current == el->el_map.alt + && el->el_line.lastchar != el->el_line.buffer) + el->el_line.cursor = el->el_line.lastchar - 1; + else + el->el_line.cursor = el->el_line.lastchar; + } + /* first we must find where the cursor is... */ h = el->el_prompt.p_pos.h; v = el->el_prompt.p_pos.v; @@ -1056,8 +1068,8 @@ re_fastaddc(EditLine *el) re_fastputc(el, c); } else { re_fastputc(el, '\\'); - re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0')); - re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0')); + re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0')); + re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0')); re_fastputc(el, (c & 7) + '0'); } term__flush(); diff --git a/refresh.h b/refresh.h index 33c0887c1b38..dd2bd02094ba 100644 --- a/refresh.h +++ b/refresh.h @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.h,v 1.4 2001/01/10 07:45:42 jdolecek Exp $ */ +/* $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/search.c b/search.c index 20fefad87bd4..5516b5505042 100644 --- a/search.c +++ b/search.c @@ -1,4 +1,4 @@ -/* $NetBSD: search.c,v 1.11 2001/01/23 15:55:31 jdolecek Exp $ */ +/* $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,18 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: search.c,v 1.11 2001/01/23 15:55:31 jdolecek Exp $"); +__RCSID("$NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $"); #endif #endif /* not lint && not SCCSID */ /* * search.c: History and character search functions */ -#include "sys.h" #include #if defined(REGEX) #include @@ -77,7 +72,8 @@ search_init(EditLine *el) el->el_search.patlen = 0; el->el_search.patdir = -1; el->el_search.chacha = '\0'; - el->el_search.chadir = -1; + el->el_search.chadir = CHAR_FWD; + el->el_search.chatflg = 0; return (0); } @@ -226,8 +222,11 @@ ce_inc_search(EditLine *el, int dir) if (el->el_search.patlen == 0) { /* first round */ pchar = ':'; #ifdef ANCHOR +#define LEN 2 el->el_search.patbuf[el->el_search.patlen++] = '.'; el->el_search.patbuf[el->el_search.patlen++] = '*'; +#else +#define LEN 0 #endif } done = redo = 0; @@ -236,7 +235,7 @@ ce_inc_search(EditLine *el, int dir) *cp; *el->el_line.lastchar++ = *cp++) continue; *el->el_line.lastchar++ = pchar; - for (cp = &el->el_search.patbuf[1]; + for (cp = &el->el_search.patbuf[LEN]; cp < &el->el_search.patbuf[el->el_search.patlen]; *el->el_line.lastchar++ = *cp++) continue; @@ -249,7 +248,7 @@ ce_inc_search(EditLine *el, int dir) switch (el->el_map.current[(unsigned char) ch]) { case ED_INSERT: case ED_DIGIT: - if (el->el_search.patlen > EL_BUFSIZ - 3) + if (el->el_search.patlen >= EL_BUFSIZ - LEN) term_beep(el); else { el->el_search.patbuf[el->el_search.patlen++] = @@ -270,8 +269,9 @@ ce_inc_search(EditLine *el, int dir) redo++; break; + case EM_DELETE_PREV_CHAR: case ED_DELETE_PREV_CHAR: - if (el->el_search.patlen > 1) + if (el->el_search.patlen > LEN) done++; else term_beep(el); @@ -286,17 +286,18 @@ ce_inc_search(EditLine *el, int dir) case 0027: /* ^W: Append word */ /* No can do if globbing characters in pattern */ - for (cp = &el->el_search.patbuf[1];; cp++) - if (cp >= &el->el_search.patbuf[el->el_search.patlen]) { + for (cp = &el->el_search.patbuf[LEN];; cp++) + if (cp >= &el->el_search.patbuf[ + el->el_search.patlen]) { el->el_line.cursor += - el->el_search.patlen - 1; + el->el_search.patlen - LEN - 1; cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, 1, ce__isword); while (el->el_line.cursor < cp && *el->el_line.cursor != '\n') { - if (el->el_search.patlen > - EL_BUFSIZ - 3) { + if (el->el_search.patlen >= + EL_BUFSIZ - LEN) { term_beep(el); break; } @@ -338,13 +339,13 @@ ce_inc_search(EditLine *el, int dir) /* Can't search if unmatched '[' */ for (cp = &el->el_search.patbuf[el->el_search.patlen-1], ch = ']'; - cp > el->el_search.patbuf; + cp >= &el->el_search.patbuf[LEN]; cp--) if (*cp == '[' || *cp == ']') { ch = *cp; break; } - if (el->el_search.patlen > 1 && ch != '[') { + if (el->el_search.patlen > LEN && ch != '[') { if (redo && newdir == dir) { if (pchar == '?') { /* wrap around */ el->el_history.eventno = @@ -374,9 +375,8 @@ ce_inc_search(EditLine *el, int dir) '\0'; if (el->el_line.cursor < el->el_line.buffer || el->el_line.cursor > el->el_line.lastchar || - (ret = ce_search_line(el, - &el->el_search.patbuf[1], - newdir)) == CC_ERROR) { + (ret = ce_search_line(el, newdir)) + == CC_ERROR) { /* avoid c_setpat */ el->el_state.lastcmd = (el_action_t) newdir; @@ -389,11 +389,11 @@ ce_inc_search(EditLine *el, int dir) el->el_line.lastchar : el->el_line.buffer; (void) ce_search_line(el, - &el->el_search.patbuf[1], newdir); } } - el->el_search.patbuf[--el->el_search.patlen] = + el->el_search.patlen -= LEN; + el->el_search.patbuf[el->el_search.patlen] = '\0'; if (ret == CC_ERROR) { term_beep(el); @@ -449,29 +449,20 @@ cv_search(EditLine *el, int dir) char tmpbuf[EL_BUFSIZ]; int tmplen; - tmplen = 0; #ifdef ANCHOR - tmpbuf[tmplen++] = '.'; - tmpbuf[tmplen++] = '*'; + tmpbuf[0] = '.'; + tmpbuf[1] = '*'; #endif + tmplen = LEN; - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; el->el_search.patdir = dir; - c_insert(el, 2); /* prompt + '\n' */ - *el->el_line.cursor++ = '\n'; - *el->el_line.cursor++ = dir == ED_SEARCH_PREV_HISTORY ? '/' : '?'; - re_refresh(el); + tmplen = c_gets(el, &tmpbuf[LEN], + dir == ED_SEARCH_PREV_HISTORY ? "\n/" : "\n?" ); + if (tmplen == -1) + return CC_REFRESH; -#ifdef ANCHOR -#define LEN 2 -#else -#define LEN 0 -#endif - - tmplen = c_gets(el, &tmpbuf[LEN]) + LEN; + tmplen += LEN; ch = tmpbuf[tmplen]; tmpbuf[tmplen] = '\0'; @@ -480,9 +471,6 @@ cv_search(EditLine *el, int dir) * Use the old pattern, but wild-card it. */ if (el->el_search.patlen == 0) { - el->el_line.buffer[0] = '\0'; - el->el_line.lastchar = el->el_line.buffer; - el->el_line.cursor = el->el_line.buffer; re_refresh(el); return (CC_ERROR); } @@ -513,19 +501,15 @@ cv_search(EditLine *el, int dir) el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */ el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer; if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) : - ed_search_next_history(el, 0)) == CC_ERROR) { + ed_search_next_history(el, 0)) == CC_ERROR) { re_refresh(el); return (CC_ERROR); - } else { - if (ch == 0033) { - re_refresh(el); - *el->el_line.lastchar++ = '\n'; - *el->el_line.lastchar = '\0'; - re_goto_bottom(el); - return (CC_NEWLINE); - } else - return (CC_REFRESH); } + if (ch == 0033) { + re_refresh(el); + return ed_newline(el, 0); + } + return (CC_REFRESH); } @@ -533,24 +517,39 @@ cv_search(EditLine *el, int dir) * Look for a pattern inside a line */ protected el_action_t -ce_search_line(EditLine *el, char *pattern, int dir) +ce_search_line(EditLine *el, int dir) { - char *cp; + char *cp = el->el_line.cursor; + char *pattern = el->el_search.patbuf; + char oc, *ocp; +#ifdef ANCHOR + ocp = &pattern[1]; + oc = *ocp; + *ocp = '^'; +#else + ocp = pattern; + oc = *ocp; +#endif if (dir == ED_SEARCH_PREV_HISTORY) { - for (cp = el->el_line.cursor; cp >= el->el_line.buffer; cp--) - if (el_match(cp, pattern)) { + for (; cp >= el->el_line.buffer; cp--) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } else { - for (cp = el->el_line.cursor; *cp != '\0' && - cp < el->el_line.limit; cp++) - if (el_match(cp, pattern)) { + for (; *cp != '\0' && cp < el->el_line.limit; cp++) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } } @@ -582,69 +581,53 @@ cv_repeat_srch(EditLine *el, int c) } -/* cv_csearch_back(): - * Vi character search reverse +/* cv_csearch(): + * Vi character search */ protected el_action_t -cv_csearch_back(EditLine *el, int ch, int count, int tflag) +cv_csearch(EditLine *el, int direction, int ch, int count, int tflag) { char *cp; + if (ch == 0) + return CC_ERROR; + + if (ch == -1) { + char c; + if (el_getc(el, &c) != 1) + return ed_end_of_file(el, 0); + ch = c; + } + + /* Save for ';' and ',' commands */ + el->el_search.chacha = ch; + el->el_search.chadir = direction; + el->el_search.chatflg = tflag; + cp = el->el_line.cursor; while (count--) { if (*cp == ch) - cp--; - while (cp > el->el_line.buffer && *cp != ch) - cp--; + cp += direction; + for (;;cp += direction) { + if (cp >= el->el_line.lastchar) + return CC_ERROR; + if (cp < el->el_line.buffer) + return CC_ERROR; + if (*cp == ch) + break; + } } - if (cp < el->el_line.buffer || (cp == el->el_line.buffer && *cp != ch)) - return (CC_ERROR); - - if (*cp == ch && tflag) - cp++; + if (tflag) + cp -= direction; el->el_line.cursor = cp; - if (el->el_chared.c_vcmd.action & DELETE) { - el->el_line.cursor++; + if (el->el_chared.c_vcmd.action != NOP) { + if (direction > 0) + el->el_line.cursor++; cv_delfini(el); - return (CC_REFRESH); + return CC_REFRESH; } - re_refresh_cursor(el); - return (CC_NORM); -} - - -/* cv_csearch_fwd(): - * Vi character search forward - */ -protected el_action_t -cv_csearch_fwd(EditLine *el, int ch, int count, int tflag) -{ - char *cp; - - cp = el->el_line.cursor; - while (count--) { - if (*cp == ch) - cp++; - while (cp < el->el_line.lastchar && *cp != ch) - cp++; - } - - if (cp >= el->el_line.lastchar) - return (CC_ERROR); - - if (*cp == ch && tflag) - cp--; - - el->el_line.cursor = cp; - - if (el->el_chared.c_vcmd.action & DELETE) { - el->el_line.cursor++; - cv_delfini(el); - return (CC_REFRESH); - } - re_refresh_cursor(el); - return (CC_NORM); + return CC_CURSOR; } diff --git a/search.h b/search.h index 676bbe2e35b9..2aa8f9850132 100644 --- a/search.h +++ b/search.h @@ -1,4 +1,4 @@ -/* $NetBSD: search.h,v 1.5 2000/09/04 22:06:32 lukem Exp $ */ +/* $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -52,6 +48,7 @@ typedef struct el_search_t { int patdir; /* Direction of the last search */ int chadir; /* Character search direction */ char chacha; /* Character we are looking for */ + char chatflg; /* 0 if f, 1 if t */ } el_search_t; @@ -62,9 +59,8 @@ protected int c_hmatch(EditLine *, const char *); protected void c_setpat(EditLine *); protected el_action_t ce_inc_search(EditLine *, int); protected el_action_t cv_search(EditLine *, int); -protected el_action_t ce_search_line(EditLine *, char *, int); +protected el_action_t ce_search_line(EditLine *, int); protected el_action_t cv_repeat_srch(EditLine *, int); -protected el_action_t cv_csearch_back(EditLine *, int, int, int); -protected el_action_t cv_csearch_fwd(EditLine *, int, int, int); +protected el_action_t cv_csearch(EditLine *, int, int, int, int); #endif /* _h_el_search */ diff --git a/shlib_version b/shlib_version index 24699bb9eb0d..d79ab7d1f014 100644 --- a/shlib_version +++ b/shlib_version @@ -1,5 +1,5 @@ -# $NetBSD: shlib_version,v 1.11 2001/01/01 15:54:07 jdolecek Exp $ +# $NetBSD: shlib_version,v 1.15 2003/12/05 13:37:48 lukem Exp $ # Remember to update distrib/sets/lists/base/shl.* when changing # major=2 -minor=5 +minor=9 diff --git a/sig.c b/sig.c index d7db355de82c..cec431911913 100644 --- a/sig.c +++ b/sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: sig.c,v 1.8 2001/01/09 17:31:04 jdolecek Exp $ */ +/* $NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,12 +32,12 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: sig.c,v 1.8 2001/01/09 17:31:04 jdolecek Exp $"); +__RCSID("$NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -50,7 +46,6 @@ __RCSID("$NetBSD: sig.c,v 1.8 2001/01/09 17:31:04 jdolecek Exp $"); * our policy is to trap all signals, set a good state * and pass the ball to our caller. */ -#include "sys.h" #include "el.h" #include @@ -122,9 +117,9 @@ sig_init(EditLine *el) #undef _DO (void) sigprocmask(SIG_BLOCK, &nset, &oset); -#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(sig_t)) +#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(el_signalhandler_t)) - el->el_signal = (sig_t *) el_malloc(SIGSIZE); + el->el_signal = (el_signalhandler_t *) el_malloc(SIGSIZE); if (el->el_signal == NULL) return (-1); for (i = 0; sighdl[i] != -1; i++) @@ -164,7 +159,7 @@ sig_set(EditLine *el) (void) sigprocmask(SIG_BLOCK, &nset, &oset); for (i = 0; sighdl[i] != -1; i++) { - sig_t s; + el_signalhandler_t s; /* This could happen if we get interrupted */ if ((s = signal(sighdl[i], sig_handler)) != sig_handler) el->el_signal[i] = s; diff --git a/sig.h b/sig.h index e7231b65cf48..0bf1fc37e394 100644 --- a/sig.h +++ b/sig.h @@ -1,4 +1,4 @@ -/* $NetBSD: sig.h,v 1.3 2000/09/04 22:06:32 lukem Exp $ */ +/* $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -62,7 +58,8 @@ _DO(SIGCONT) \ _DO(SIGWINCH) -typedef sig_t *el_signal_t; +typedef void (*el_signalhandler_t)(int); +typedef el_signalhandler_t *el_signal_t; protected void sig_end(EditLine*); protected int sig_init(EditLine*); diff --git a/sys.h b/sys.h index 6255a8d49a00..e593ec41ce7c 100644 --- a/sys.h +++ b/sys.h @@ -1,4 +1,4 @@ -/* $NetBSD: sys.h,v 1.4 2000/09/04 22:06:32 lukem Exp $ */ +/* $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -44,6 +40,24 @@ #ifndef _h_sys #define _h_sys +#ifdef HAVE_SYS_CDEFS_H +#include +#endif + +#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) +# define __attribute__(A) +#endif + +#ifndef __BEGIN_DECLS +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + #ifndef public # define public /* Externally visible functions/variables */ #endif @@ -57,8 +71,6 @@ /* When we want to hide everything */ #endif -#include - #ifndef _PTR_T # define _PTR_T typedef void *ptr_t; @@ -71,23 +83,42 @@ typedef void *ioctl_t; #include +#ifndef HAVE_STRLCAT +#define strlcat libedit_strlcat +size_t strlcat(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_STRLCPY +#define strlcpy libedit_strlcpy +size_t strlcpy(char *dst, const char *src, size_t size); +#endif + +#ifndef HAVE_FGETLN +#define fgetln libedit_fgetln +char *fgetln(FILE *fp, size_t *len); +#endif + #define REGEX /* Use POSIX.2 regular expression functions */ #undef REGEXP /* Use UNIX V8 regular expression functions */ -#ifdef SUNOS +#ifdef notdef # undef REGEX # undef REGEXP # include -typedef void (*sig_t)(int); # ifdef __GNUC__ /* * Broken hdrs. */ +extern int tgetent(const char *bp, char *name); +extern int tgetflag(const char *id); +extern int tgetnum(const char *id); +extern char *tgetstr(const char *id, char **area); +extern char *tgoto(const char *cap, int col, int row); +extern int tputs(const char *str, int affcnt, int (*putc)(int)); extern char *getenv(const char *); extern int fprintf(FILE *, const char *, ...); extern int sigsetmask(int); extern int sigblock(int); -extern int ioctl(int, int, void *); extern int fputc(int, FILE *); extern int fgetc(FILE *); extern int fflush(FILE *); @@ -96,7 +127,6 @@ extern int toupper(int); extern int errno, sys_nerr; extern char *sys_errlist[]; extern void perror(const char *); -extern int read(int, const char*, int); # include # define strerror(e) sys_errlist[e] # endif diff --git a/term.c b/term.c index dfbe30ef0d5a..6eafd9f6010d 100644 --- a/term.c +++ b/term.c @@ -1,4 +1,4 @@ -/* $NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek Exp $ */ +/* $NetBSD: term.c,v 1.40 2004/05/22 23:21:28 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,12 +32,12 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #else -__RCSID("$NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek Exp $"); +__RCSID("$NetBSD: term.c,v 1.40 2004/05/22 23:21:28 christos Exp $"); #endif #endif /* not lint && not SCCSID */ @@ -50,13 +46,24 @@ __RCSID("$NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek Exp $"); * We have to declare a static variable here, since the * termcap putchar routine does not take an argument! */ -#include "sys.h" #include #include #include #include #include +#ifdef HAVE_TERMCAP_H #include +#endif +#ifdef HAVE_CURSES_H +#include +#endif +#ifdef HAVE_NCURSES_H +#include +#endif +/* Solaris's term.h does horrid things. */ +#if (defined(HAVE_TERM_H) && !defined(SUNOS)) +#include +#endif #include #include @@ -261,7 +268,7 @@ private void term_setflags(EditLine *); private int term_rebuffer_display(EditLine *); private void term_free_display(EditLine *); private int term_alloc_display(EditLine *); -private void term_alloc(EditLine *, const struct termcapstr *, char *); +private void term_alloc(EditLine *, const struct termcapstr *, const char *); private void term_init_arrow(EditLine *); private void term_reset_arrow(EditLine *); @@ -341,11 +348,11 @@ term_init(EditLine *el) return (-1); (void) memset(el->el_term.t_val, 0, T_val * sizeof(int)); term_outfile = el->el_outfile; - if (term_set(el, NULL) == -1) - return (-1); + (void) term_set(el, NULL); term_init_arrow(el); return (0); } + /* term_end(): * Clean up the terminal stuff */ @@ -362,6 +369,8 @@ term_end(EditLine *el) el->el_term.t_str = NULL; el_free((ptr_t) el->el_term.t_val); el->el_term.t_val = NULL; + el_free((ptr_t) el->el_term.t_fkey); + el->el_term.t_fkey = NULL; term_free_display(el); } @@ -370,7 +379,7 @@ term_end(EditLine *el) * Maintain a string pool for termcap strings */ private void -term_alloc(EditLine *el, const struct termcapstr *t, char *cap) +term_alloc(EditLine *el, const struct termcapstr *t, const char *cap) { char termbuf[TC_BUFSIZE]; int tlen, clen; @@ -638,7 +647,8 @@ term_move_to_char(EditLine *el, int where) * from col 0 */ if (EL_CAN_TAB ? - (-del > (((unsigned int) where >> 3) + + ((unsigned int)-del > + (((unsigned int) where >> 3) + (where & 07))) : (-del > where)) { term__putc('\r'); /* do a CR */ @@ -658,7 +668,7 @@ term_move_to_char(EditLine *el, int where) * Overstrike num characters */ protected void -term_overwrite(EditLine *el, char *cp, int n) +term_overwrite(EditLine *el, const char *cp, int n) { if (n <= 0) return; /* catch bugs */ @@ -866,12 +876,18 @@ term_clear_to_bottom(EditLine *el) } #endif +protected void +term_get(EditLine *el, const char **term) +{ + *term = el->el_term.t_name; +} + /* term_set(): * Read in the terminal capabilities from the requested terminal */ protected int -term_set(EditLine *el, char *term) +term_set(EditLine *el, const char *term) { int i; char buf[TC_BUFSIZE]; @@ -927,8 +943,11 @@ term_set(EditLine *el, char *term) /* Get the size */ Val(T_co) = tgetnum("co"); Val(T_li) = tgetnum("li"); - for (t = tstr; t->name != NULL; t++) - term_alloc(el, t, tgetstr(t->name, &area)); + for (t = tstr; t->name != NULL; t++) { + /* XXX: some systems tgetstr needs non const */ + term_alloc(el, t, tgetstr(strchr(t->name, *t->name), + &area)); + } } if (Val(T_co) < 2) @@ -947,6 +966,7 @@ term_set(EditLine *el, char *term) return (-1); (void) sigprocmask(SIG_SETMASK, &oset, NULL); term_bind_arrow(el); + el->el_term.t_name = term; return (i <= 0 ? -1 : 0); } @@ -1102,7 +1122,7 @@ term_reset_arrow(EditLine *el) * Set an arrow key binding */ protected int -term_set_arrow(EditLine *el, char *name, key_value_t *fun, int type) +term_set_arrow(EditLine *el, const char *name, key_value_t *fun, int type) { fkey_t *arrow = el->el_term.t_fkey; int i; @@ -1121,7 +1141,7 @@ term_set_arrow(EditLine *el, char *name, key_value_t *fun, int type) * Clear an arrow key binding */ protected int -term_clear_arrow(EditLine *el, char *name) +term_clear_arrow(EditLine *el, const char *name) { fkey_t *arrow = el->el_term.t_fkey; int i; @@ -1139,7 +1159,7 @@ term_clear_arrow(EditLine *el, char *name) * Print the arrow key bindings */ protected void -term_print_arrow(EditLine *el, char *name) +term_print_arrow(EditLine *el, const char *name) { int i; fkey_t *arrow = el->el_term.t_fkey; @@ -1236,7 +1256,8 @@ term__flush(void) */ protected int /*ARGSUSED*/ -term_telltc(EditLine *el, int argc, char **argv) +term_telltc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv __attribute__((__unused__))) { const struct termcapstr *t; char **ts; @@ -1271,11 +1292,12 @@ term_telltc(EditLine *el, int argc, char **argv) */ protected int /*ARGSUSED*/ -term_settc(EditLine *el, int argc, char **argv) +term_settc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { const struct termcapstr *ts; const struct termcapval *tv; - char *what, *how; + const char *what, *how; if (argv == NULL || argv[1] == NULL || argv[2] == NULL) return (-1); @@ -1347,7 +1369,8 @@ term_settc(EditLine *el, int argc, char **argv) */ protected int /*ARGSUSED*/ -term_echotc(EditLine *el, int argc, char **argv) +term_echotc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { char *cap, *scap, *ep; int arg_need, arg_cols, arg_rows; @@ -1406,7 +1429,7 @@ term_echotc(EditLine *el, int argc, char **argv) } (void) fprintf(el->el_outfile, fmtd, 0); #else - (void) fprintf(el->el_outfile, fmtd, el->el_tty.t_speed); + (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); #endif return (0); } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { @@ -1425,8 +1448,10 @@ term_echotc(EditLine *el, int argc, char **argv) scap = el->el_term.t_str[t - tstr]; break; } - if (t->name == NULL) - scap = tgetstr(*argv, &area); + if (t->name == NULL) { + /* XXX: some systems tgetstr needs non const */ + scap = tgetstr(strchr(*argv, **argv), &area); + } if (!scap || scap[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, diff --git a/term.h b/term.h index 57b233262fdf..3ddfe2f1529d 100644 --- a/term.h +++ b/term.h @@ -1,4 +1,4 @@ -/* $NetBSD: term.h,v 1.12 2001/01/04 15:56:32 christos Exp $ */ +/* $NetBSD: term.h,v 1.16 2005/03/15 00:10:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -47,13 +43,14 @@ #include "histedit.h" typedef struct { /* Symbolic function key bindings */ - char *name; /* name of the key */ + const char *name; /* name of the key */ int key; /* Index in termcap table */ key_value_t fun; /* Function bound to it */ int type; /* Type of function */ } fkey_t; typedef struct { + const char *t_name; /* the terminal name */ coord_t t_size; /* # lines and cols */ int t_flags; #define TERM_CAN_INSERT 0x001 /* Has insert cap */ @@ -87,7 +84,7 @@ typedef struct { protected void term_move_to_line(EditLine *, int); protected void term_move_to_char(EditLine *, int); protected void term_clear_EOL(EditLine *, int); -protected void term_overwrite(EditLine *, char *, int); +protected void term_overwrite(EditLine *, const char *, int); protected void term_insertwrite(EditLine *, char *, int); protected void term_deletechars(EditLine *, int); protected void term_clear_screen(EditLine *); @@ -96,14 +93,15 @@ protected int term_change_size(EditLine *, int, int); protected int term_get_size(EditLine *, int *, int *); protected int term_init(EditLine *); protected void term_bind_arrow(EditLine *); -protected void term_print_arrow(EditLine *, char *); -protected int term_clear_arrow(EditLine *, char *); -protected int term_set_arrow(EditLine *, char *, key_value_t *, int); +protected void term_print_arrow(EditLine *, const char *); +protected int term_clear_arrow(EditLine *, const char *); +protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); protected void term_end(EditLine *); -protected int term_set(EditLine *, char *); -protected int term_settc(EditLine *, int, char **); -protected int term_telltc(EditLine *, int, char **); -protected int term_echotc(EditLine *, int, char **); +protected void term_get(EditLine *, const char **); +protected int term_set(EditLine *, const char *); +protected int term_settc(EditLine *, int, const char **); +protected int term_telltc(EditLine *, int, const char **); +protected int term_echotc(EditLine *, int, const char **); protected int term__putc(int); protected void term__flush(void); @@ -117,6 +115,7 @@ protected void term__flush(void); #define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL) #define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB) #define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME) +#define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP) #define EL_HAS_META (EL_FLAGS & TERM_HAS_META) #define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) #define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) diff --git a/tokenizer.c b/tokenizer.c index ed9f3652fa49..b8a263332f8d 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -1,4 +1,4 @@ -/* $NetBSD: tokenizer.c,v 1.7 2001/01/04 15:56:32 christos Exp $ */ +/* $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,22 +32,21 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: tokenizer.c,v 1.7 2001/01/04 15:56:32 christos Exp $"); +__RCSID("$NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $"); #endif #endif /* not lint && not SCCSID */ /* * tokenize.c: Bourne shell like tokenizer */ -#include "sys.h" #include #include -#include "tokenizer.h" +#include "histedit.h" typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone @@ -65,6 +60,7 @@ typedef enum { #define WINCR 20 #define AINCR 10 +#define tok_strdup(a) strdup(a) #define tok_malloc(a) malloc(a) #define tok_free(a) free(a) #define tok_realloc(a, b) realloc(a, b) @@ -110,16 +106,29 @@ tok_init(const char *ifs) { Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer)); - tok->ifs = strdup(ifs ? ifs : IFS); + if (tok == NULL) + return NULL; + tok->ifs = tok_strdup(ifs ? ifs : IFS); + if (tok->ifs == NULL) { + tok_free((ptr_t)tok); + return NULL; + } tok->argc = 0; tok->amax = AINCR; tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax); - if (tok->argv == NULL) - return (NULL); + if (tok->argv == NULL) { + tok_free((ptr_t)tok->ifs); + tok_free((ptr_t)tok); + return NULL; + } tok->argv[0] = NULL; tok->wspace = (char *) tok_malloc(WINCR); - if (tok->wspace == NULL) - return (NULL); + if (tok->wspace == NULL) { + tok_free((ptr_t)tok->argv); + tok_free((ptr_t)tok->ifs); + tok_free((ptr_t)tok); + return NULL; + } tok->wmax = tok->wspace + WINCR; tok->wstart = tok->wspace; tok->wptr = tok->wspace; @@ -161,21 +170,39 @@ tok_end(Tokenizer *tok) /* tok_line(): - * Bourne shell like tokenizing - * Return: - * -1: Internal error - * 3: Quoted return - * 2: Unmatched double quote - * 1: Unmatched single quote - * 0: Ok + * Bourne shell (sh(1)) like tokenizing + * Arguments: + * tok current tokenizer state (setup with tok_init()) + * line line to parse + * Returns: + * -1 Internal error + * 3 Quoted return + * 2 Unmatched double quote + * 1 Unmatched single quote + * 0 Ok + * Modifies (if return value is 0): + * argc number of arguments + * argv argument array + * cursorc if !NULL, argv element containing cursor + * cursorv if !NULL, offset in argv[cursorc] of cursor */ public int -tok_line(Tokenizer *tok, const char *line, int *argc, char ***argv) +tok_line(Tokenizer *tok, const LineInfo *line, + int *argc, const char ***argv, int *cursorc, int *cursoro) { const char *ptr; + int cc, co; - for (;;) { - switch (*(ptr = line++)) { + cc = co = -1; + ptr = line->buffer; + for (ptr = line->buffer; ;ptr++) { + if (ptr >= line->lastchar) + ptr = ""; + if (ptr == line->cursor) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + switch (*ptr) { case '\'': tok->flags |= TOK_KEEP; tok->flags &= ~TOK_EAT; @@ -274,10 +301,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, char ***argv) tok->flags &= ~TOK_EAT; switch (tok->quote) { case Q_none: - tok_finish(tok); - *argv = tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: case Q_double: @@ -307,10 +331,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, char ***argv) tok->flags &= ~TOK_EAT; return (3); } - tok_finish(tok); - *argv = tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: return (1); @@ -370,20 +391,20 @@ tok_line(Tokenizer *tok, const char *line, int *argc, char ***argv) if (tok->wptr >= tok->wmax - 4) { size_t size = tok->wmax - tok->wspace + WINCR; char *s = (char *) tok_realloc(tok->wspace, size); - /* SUPPRESS 22 */ - int offs = s - tok->wspace; if (s == NULL) return (-1); - if (offs != 0) { + if (s != tok->wspace) { int i; - for (i = 0; i < tok->argc; i++) - tok->argv[i] = tok->argv[i] + offs; - tok->wptr = tok->wptr + offs; - tok->wstart = tok->wstart + offs; - tok->wmax = s + size; + for (i = 0; i < tok->argc; i++) { + tok->argv[i] = + (tok->argv[i] - tok->wspace) + s; + } + tok->wptr = (tok->wptr - tok->wspace) + s; + tok->wstart = (tok->wstart - tok->wspace) + s; tok->wspace = s; } + tok->wmax = s + size; } if (tok->argc >= tok->amax - 4) { char **p; @@ -395,4 +416,32 @@ tok_line(Tokenizer *tok, const char *line, int *argc, char ***argv) tok->argv = p; } } + tok_line_outok: + if (cc == -1 && co == -1) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + if (cursorc != NULL) + *cursorc = cc; + if (cursoro != NULL) + *cursoro = co; + tok_finish(tok); + *argv = (const char **)tok->argv; + *argc = tok->argc; + return (0); +} + +/* tok_str(): + * Simpler version of tok_line, taking a NUL terminated line + * and splitting into words, ignoring cursor state. + */ +public int +tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv) +{ + LineInfo li; + + memset(&li, 0, sizeof(li)); + li.buffer = line; + li.cursor = li.lastchar = strchr(line, '\0'); + return (tok_line(tok, &li, argc, argv, NULL, NULL)); } diff --git a/tokenizer.h b/tokenizer.h deleted file mode 100644 index 775891921327..000000000000 --- a/tokenizer.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $NetBSD: tokenizer.h,v 1.4 2000/09/04 22:06:33 lukem Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tokenizer.h 8.1 (Berkeley) 6/4/93 - */ - -/* - * tokenizer.h: Header file for tokenizer routines - */ -#ifndef _h_tokenizer -#define _h_tokenizer - -typedef struct tokenizer Tokenizer; - -Tokenizer *tok_init(const char *); -void tok_reset(Tokenizer *); -void tok_end(Tokenizer *); -int tok_line(Tokenizer *, const char *, int *, char ***); - -#endif /* _h_tokenizer */ diff --git a/tty.c b/tty.c index ebc4fb4d5878..ec673cb99cbd 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.15 2001/05/17 01:02:17 christos Exp $ */ +/* $NetBSD: tty.c,v 1.23 2005/06/01 11:37:52 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,32 +32,32 @@ * SUCH DAMAGE. */ -#include +#include "config.h" #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: tty.c,v 1.15 2001/05/17 01:02:17 christos Exp $"); +__RCSID("$NetBSD: tty.c,v 1.23 2005/06/01 11:37:52 lukem Exp $"); #endif #endif /* not lint && not SCCSID */ /* * tty.c: tty interface stuff */ -#include "sys.h" +#include #include "tty.h" #include "el.h" typedef struct ttymodes_t { const char *m_name; - u_int m_value; + unsigned int m_value; int m_type; } ttymodes_t; typedef struct ttymap_t { int nch, och; /* Internal and termio rep of chars */ el_action_t bind[3]; /* emacs, vi, and vi-cmd */ -} ttymap_t; +} ttymap_t; private const ttyperm_t ttyperm = { @@ -125,11 +121,11 @@ private const ttychar_t ttychar = { private const ttymap_t tty_map[] = { #ifdef VERASE {C_ERASE, VERASE, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE */ #ifdef VERASE2 {C_ERASE2, VERASE2, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE2 */ #ifdef VKILL {C_KILL, VKILL, @@ -456,6 +452,7 @@ private const ttymodes_t ttymodes[] = { #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) #define tty__cooked_mode(td) ((td)->c_lflag & ICANON) +private int tty__getcharindex(int); private void tty__getchar(struct termios *, unsigned char *); private void tty__setchar(struct termios *, unsigned char *); private speed_t tty__getspeed(struct termios *); @@ -569,7 +566,7 @@ tty_init(EditLine *el) */ protected void /*ARGSUSED*/ -tty_end(EditLine *el) +tty_end(EditLine *el __attribute__((__unused__))) { /* XXX: Maybe reset to an initial state? */ @@ -589,6 +586,113 @@ tty__getspeed(struct termios *td) return (spd); } +/* tty__getspeed(): + * Return the index of the asked char in the c_cc array + */ +private int +tty__getcharindex(int i) +{ + switch (i) { +#ifdef VINTR + case C_INTR: + return VINTR; +#endif /* VINTR */ +#ifdef VQUIT + case C_QUIT: + return VQUIT; +#endif /* VQUIT */ +#ifdef VERASE + case C_ERASE: + return VERASE; +#endif /* VERASE */ +#ifdef VKILL + case C_KILL: + return VKILL; +#endif /* VKILL */ +#ifdef VEOF + case C_EOF: + return VEOF; +#endif /* VEOF */ +#ifdef VEOL + case C_EOL: + return VEOL; +#endif /* VEOL */ +#ifdef VEOL2 + case C_EOL2: + return VEOL2; +#endif /* VEOL2 */ +#ifdef VSWTCH + case C_SWTCH: + return VSWTCH; +#endif /* VSWTCH */ +#ifdef VDSWTCH + case C_DSWTCH: + return VDSWTCH; +#endif /* VDSWTCH */ +#ifdef VERASE2 + case C_ERASE2: + return VERASE2; +#endif /* VERASE2 */ +#ifdef VSTART + case C_START: + return VSTART; +#endif /* VSTART */ +#ifdef VSTOP + case C_STOP: + return VSTOP; +#endif /* VSTOP */ +#ifdef VWERASE + case C_WERASE: + return VWERASE; +#endif /* VWERASE */ +#ifdef VSUSP + case C_SUSP: + return VSUSP; +#endif /* VSUSP */ +#ifdef VDSUSP + case C_DSUSP: + return VDSUSP; +#endif /* VDSUSP */ +#ifdef VREPRINT + case C_REPRINT: + return VREPRINT; +#endif /* VREPRINT */ +#ifdef VDISCARD + case C_DISCARD: + return VDISCARD; +#endif /* VDISCARD */ +#ifdef VLNEXT + case C_LNEXT: + return VLNEXT; +#endif /* VLNEXT */ +#ifdef VSTATUS + case C_STATUS: + return VSTATUS; +#endif /* VSTATUS */ +#ifdef VPAGE + case C_PAGE: + return VPAGE; +#endif /* VPAGE */ +#ifdef VPGOFF + case C_PGOFF: + return VPGOFF; +#endif /* VPGOFF */ +#ifdef VKILL2 + case C_KILL2: + return VKILL2; +#endif /* KILL2 */ +#ifdef VMIN + case C_MIN: + return VMIN; +#endif /* VMIN */ +#ifdef VTIME + case C_TIME: + return VTIME; +#endif /* VTIME */ + default: + return -1; + } +} /* tty__getchar(): * Get the tty characters @@ -1042,13 +1146,14 @@ tty_noquotemode(EditLine *el) */ protected int /*ARGSUSED*/ -tty_stty(EditLine *el, int argc, char **argv) +tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) { const ttymodes_t *m; - char x, *d; + char x; int aflag = 0; - char *s; - char *name; + const char *s, *d; + const char *name; + struct termios *tios = &el->el_tty.t_ex; int z = EX_IO; if (argv == NULL) @@ -1063,14 +1168,17 @@ tty_stty(EditLine *el, int argc, char **argv) break; case 'd': argv++; + tios = &el->el_tty.t_ed; z = ED_IO; break; case 'x': argv++; + tios = &el->el_tty.t_ex; z = EX_IO; break; case 'q': argv++; + tios = &el->el_tty.t_ts; z = QU_IO; break; default: @@ -1120,6 +1228,7 @@ tty_stty(EditLine *el, int argc, char **argv) return (0); } while (argv && (s = *argv++)) { + const char *p; switch (*s) { case '+': case '-': @@ -1130,8 +1239,11 @@ tty_stty(EditLine *el, int argc, char **argv) break; } d = s; + p = strchr(s, '='); for (m = ttymodes; m->m_name; m++) - if (strcmp(m->m_name, d) == 0) + if ((p ? strncmp(m->m_name, d, (size_t)(p - d)) : + strcmp(m->m_name, d)) == 0 && + (p == NULL || m->m_type == MD_CHAR)) break; if (!m->m_name) { @@ -1139,6 +1251,16 @@ tty_stty(EditLine *el, int argc, char **argv) "%s: Invalid argument `%s'.\n", name, d); return (-1); } + if (p) { + int c = ffs((int)m->m_value); + int v = *++p ? parse__escape((const char **) &p) : + el->el_tty.t_vdisable; + assert(c-- != 0); + c = tty__getcharindex(c); + assert(c != -1); + tios->c_cc[c] = v; + continue; + } switch (x) { case '+': el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; diff --git a/tty.h b/tty.h index e0f3f63a6277..10e9b98c953b 100644 --- a/tty.h +++ b/tty.h @@ -1,4 +1,4 @@ -/* $NetBSD: tty.h,v 1.8 2000/09/04 22:06:33 lukem Exp $ */ +/* $NetBSD: tty.h,v 1.11 2005/06/01 11:37:52 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -453,16 +449,16 @@ #define MD_NN 5 typedef struct { - char *t_name; - u_int t_setmask; - u_int t_clrmask; + const char *t_name; + unsigned int t_setmask; + unsigned int t_clrmask; } ttyperm_t[NN_IO][MD_NN]; typedef unsigned char ttychar_t[NN_IO][C_NCC]; protected int tty_init(EditLine *); protected void tty_end(EditLine *); -protected int tty_stty(EditLine *, int, char**); +protected int tty_stty(EditLine *, int, const char **); protected int tty_rawmode(EditLine *); protected int tty_cookedmode(EditLine *); protected int tty_quotemode(EditLine *); diff --git a/vi.c b/vi.c index b131db52cfa1..8f4180736dba 100644 --- a/vi.c +++ b/vi.c @@ -1,4 +1,4 @@ -/* $NetBSD: vi.c,v 1.8 2000/09/04 22:06:33 lukem Exp $ */ +/* $NetBSD: vi.c,v 1.21 2005/04/25 01:06:03 matt Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,19 +32,22 @@ * SUCH DAMAGE. */ -#include +#include "config.h" +#include +#include +#include + #if !defined(lint) && !defined(SCCSID) #if 0 static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: vi.c,v 1.8 2000/09/04 22:06:33 lukem Exp $"); +__RCSID("$NetBSD: vi.c,v 1.21 2005/04/25 01:06:03 matt Exp $"); #endif #endif /* not lint && not SCCSID */ /* * vi.c: Vi mode commands. */ -#include "sys.h" #include "el.h" private el_action_t cv_action(EditLine *, int); @@ -60,22 +59,18 @@ private el_action_t cv_paste(EditLine *, int); private el_action_t cv_action(EditLine *el, int c) { - char *cp, *kp; - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { + /* 'cc', 'dd' and (possibly) friends */ + if (c != el->el_chared.c_vcmd.action) + return CC_ERROR; + + if (!(c & YANK)) + cv_undo(el); + cv_yank(el, el->el_line.buffer, + el->el_line.lastchar - el->el_line.buffer); el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = 0; - - el->el_chared.c_undo.isize = 0; - el->el_chared.c_undo.dsize = 0; - kp = el->el_chared.c_undo.buf; - for (cp = el->el_line.buffer; cp < el->el_line.lastchar; cp++) { - *kp++ = *cp; - el->el_chared.c_undo.dsize++; - } - - el->el_chared.c_undo.action = INSERT; - el->el_chared.c_undo.ptr = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer; el->el_line.cursor = el->el_line.buffer; if (c & INSERT) @@ -86,25 +81,8 @@ cv_action(EditLine *el, int c) el->el_chared.c_vcmd.pos = el->el_line.cursor; el->el_chared.c_vcmd.action = c; return (CC_ARGHACK); - -#ifdef notdef - /* - * I don't think that this is needed. But we keep it for now - */ - else - if (el_chared.c_vcmd.action == NOP) { - el->el_chared.c_vcmd.pos = el->el_line.cursor; - el->el_chared.c_vcmd.action = c; - return (CC_ARGHACK); - } else { - el->el_chared.c_vcmd.action = 0; - el->el_chared.c_vcmd.pos = 0; - return (CC_ERROR); - } -#endif } - /* cv_paste(): * Paste previous deletion before or after the cursor */ @@ -112,23 +90,25 @@ private el_action_t cv_paste(EditLine *el, int c) { char *ptr; - c_undo_t *un = &el->el_chared.c_undo; + c_kill_t *k = &el->el_chared.c_kill; + int len = k->last - k->buf; -#ifdef DEBUG_PASTE - (void) fprintf(el->el_errfile, "Paste: %x \"%s\" +%d -%d\n", - un->action, un->buf, un->isize, un->dsize); -#endif - if (un->isize == 0) + if (k->buf == NULL || len == 0) return (CC_ERROR); +#ifdef DEBUG_PASTE + (void) fprintf(el->el_errfile, "Paste: \"%.*s\"\n", len, k->buf); +#endif + + cv_undo(el); if (!c && el->el_line.cursor < el->el_line.lastchar) el->el_line.cursor++; ptr = el->el_line.cursor; - c_insert(el, (int) un->isize); - if (el->el_line.cursor + un->isize > el->el_line.lastchar) + c_insert(el, len); + if (el->el_line.cursor + len > el->el_line.lastchar) return (CC_ERROR); - (void) memcpy(ptr, un->buf, un->isize); + (void) memcpy(ptr, k->buf, len +0u); return (CC_REFRESH); } @@ -139,7 +119,7 @@ cv_paste(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_paste_next(EditLine *el, int c) +vi_paste_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 0)); @@ -152,31 +132,31 @@ vi_paste_next(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_paste_prev(EditLine *el, int c) +vi_paste_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 1)); } -/* vi_prev_space_word(): +/* vi_prev_big_word(): * Vi move to the previous space delimited word * [B] */ protected el_action_t /*ARGSUSED*/ -vi_prev_space_word(EditLine *el, int c) +vi_prev_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.buffer) return (CC_ERROR); - el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, + el->el_line.cursor = cv_prev_word(el->el_line.cursor, el->el_line.buffer, el->el_state.argument, - cv__isword); + cv__isWord); - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -186,22 +166,22 @@ vi_prev_space_word(EditLine *el, int c) /* vi_prev_word(): * Vi move to the previous word - * [B] + * [b] */ protected el_action_t /*ARGSUSED*/ -vi_prev_word(EditLine *el, int c) +vi_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) return (CC_ERROR); - el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, + el->el_line.cursor = cv_prev_word(el->el_line.cursor, el->el_line.buffer, el->el_state.argument, - ce__isword); + cv__isword); - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -209,25 +189,23 @@ vi_prev_word(EditLine *el, int c) } -/* vi_next_space_word(): +/* vi_next_big_word(): * Vi move to the next space delimited word * [W] */ protected el_action_t /*ARGSUSED*/ -vi_next_space_word(EditLine *el, int c) +vi_next_big_word(EditLine *el, int c) { - if (el->el_line.cursor == el->el_line.lastchar) + if (el->el_line.cursor >= el->el_line.lastchar - 1) return (CC_ERROR); el->el_line.cursor = cv_next_word(el, el->el_line.cursor, - el->el_line.lastchar, - el->el_state.argument, - cv__isword); + el->el_line.lastchar, el->el_state.argument, cv__isWord); if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -241,19 +219,17 @@ vi_next_space_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_next_word(EditLine *el, int c) +vi_next_word(EditLine *el, int c __attribute__((__unused__))) { - if (el->el_line.cursor == el->el_line.lastchar) + if (el->el_line.cursor >= el->el_line.lastchar - 1) return (CC_ERROR); el->el_line.cursor = cv_next_word(el, el->el_line.cursor, - el->el_line.lastchar, - el->el_state.argument, - ce__isword); + el->el_line.lastchar, el->el_state.argument, cv__isword); if (el->el_map.type == MAP_VI) - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { cv_delfini(el); return (CC_REFRESH); } @@ -268,19 +244,27 @@ vi_next_word(EditLine *el, int c) protected el_action_t vi_change_case(EditLine *el, int c) { + int i; - if (el->el_line.cursor < el->el_line.lastchar) { - c = *el->el_line.cursor; + if (el->el_line.cursor >= el->el_line.lastchar) + return (CC_ERROR); + cv_undo(el); + for (i = 0; i < el->el_state.argument; i++) { + + c = *(unsigned char *)el->el_line.cursor; if (isupper(c)) - *el->el_line.cursor++ = tolower(c); + *el->el_line.cursor = tolower(c); else if (islower(c)) - *el->el_line.cursor++ = toupper(c); - else - el->el_line.cursor++; + *el->el_line.cursor = toupper(c); + + if (++el->el_line.cursor >= el->el_line.lastchar) { + el->el_line.cursor--; + re_fastaddc(el); + break; + } re_fastaddc(el); - return (CC_NORM); } - return (CC_ERROR); + return CC_NORM; } @@ -290,7 +274,7 @@ vi_change_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_change_meta(EditLine *el, int c) +vi_change_meta(EditLine *el, int c __attribute__((__unused__))) { /* @@ -307,15 +291,11 @@ vi_change_meta(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_insert_at_bol(EditLine *el, int c) +vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; - el->el_chared.c_vcmd.ins = el->el_line.cursor; - - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.action = DELETE; - + cv_undo(el); el->el_map.current = el->el_map.key; return (CC_CURSOR); } @@ -327,16 +307,16 @@ vi_insert_at_bol(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_replace_char(EditLine *el, int c) +vi_replace_char(EditLine *el, int c __attribute__((__unused__))) { + if (el->el_line.cursor >= el->el_line.lastchar) + return CC_ERROR; + el->el_map.current = el->el_map.key; el->el_state.inputmode = MODE_REPLACE_1; - el->el_chared.c_undo.action = CHANGE; - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.isize = 0; - el->el_chared.c_undo.dsize = 0; - return (CC_NORM); + cv_undo(el); + return (CC_ARGHACK); } @@ -346,26 +326,23 @@ vi_replace_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_replace_mode(EditLine *el, int c) +vi_replace_mode(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; el->el_state.inputmode = MODE_REPLACE; - el->el_chared.c_undo.action = CHANGE; - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.isize = 0; - el->el_chared.c_undo.dsize = 0; + cv_undo(el); return (CC_NORM); } /* vi_substitute_char(): * Vi replace character under the cursor and enter insert mode - * [r] + * [s] */ protected el_action_t /*ARGSUSED*/ -vi_substitute_char(EditLine *el, int c) +vi_substitute_char(EditLine *el, int c __attribute__((__unused__))) { c_delafter(el, el->el_state.argument); @@ -380,9 +357,12 @@ vi_substitute_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_line(EditLine *el, int c) +vi_substitute_line(EditLine *el, int c __attribute__((__unused__))) { + cv_undo(el); + cv_yank(el, el->el_line.buffer, + el->el_line.lastchar - el->el_line.buffer); (void) em_kill_line(el, 0); el->el_map.current = el->el_map.key; return (CC_REFRESH); @@ -395,9 +375,12 @@ vi_substitute_line(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_change_to_eol(EditLine *el, int c) +vi_change_to_eol(EditLine *el, int c __attribute__((__unused__))) { + cv_undo(el); + cv_yank(el, el->el_line.cursor, + el->el_line.lastchar - el->el_line.cursor); (void) ed_kill_line(el, 0); el->el_map.current = el->el_map.key; return (CC_REFRESH); @@ -410,15 +393,11 @@ vi_change_to_eol(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_insert(EditLine *el, int c) +vi_insert(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; - - el->el_chared.c_vcmd.ins = el->el_line.cursor; - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.action = DELETE; - + cv_undo(el); return (CC_NORM); } @@ -429,7 +408,7 @@ vi_insert(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_add(EditLine *el, int c) +vi_add(EditLine *el, int c __attribute__((__unused__))) { int ret; @@ -442,9 +421,7 @@ vi_add(EditLine *el, int c) } else ret = CC_NORM; - el->el_chared.c_vcmd.ins = el->el_line.cursor; - el->el_chared.c_undo.ptr = el->el_line.cursor; - el->el_chared.c_undo.action = DELETE; + cv_undo(el); return (ret); } @@ -456,16 +433,12 @@ vi_add(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_add_at_eol(EditLine *el, int c) +vi_add_at_eol(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; el->el_line.cursor = el->el_line.lastchar; - - /* Mark where insertion begins */ - el->el_chared.c_vcmd.ins = el->el_line.lastchar; - el->el_chared.c_undo.ptr = el->el_line.lastchar; - el->el_chared.c_undo.action = DELETE; + cv_undo(el); return (CC_CURSOR); } @@ -476,29 +449,29 @@ vi_add_at_eol(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_delete_meta(EditLine *el, int c) +vi_delete_meta(EditLine *el, int c __attribute__((__unused__))) { return (cv_action(el, DELETE)); } -/* vi_end_word(): +/* vi_end_big_word(): * Vi move to the end of the current space delimited word * [E] */ protected el_action_t /*ARGSUSED*/ -vi_end_word(EditLine *el, int c) +vi_end_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.lastchar) return (CC_ERROR); el->el_line.cursor = cv__endword(el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument); + el->el_line.lastchar, el->el_state.argument, cv__isWord); - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { el->el_line.cursor++; cv_delfini(el); return (CC_REFRESH); @@ -507,22 +480,22 @@ vi_end_word(EditLine *el, int c) } -/* vi_to_end_word(): +/* vi_end_word(): * Vi move to the end of the current word * [e] */ protected el_action_t /*ARGSUSED*/ -vi_to_end_word(EditLine *el, int c) +vi_end_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) return (CC_ERROR); el->el_line.cursor = cv__endword(el->el_line.cursor, - el->el_line.lastchar, el->el_state.argument); + el->el_line.lastchar, el->el_state.argument, cv__isword); - if (el->el_chared.c_vcmd.action & DELETE) { + if (el->el_chared.c_vcmd.action != NOP) { el->el_line.cursor++; cv_delfini(el); return (CC_REFRESH); @@ -537,102 +510,21 @@ vi_to_end_word(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_undo(EditLine *el, int c) +vi_undo(EditLine *el, int c __attribute__((__unused__))) { - char *cp, *kp; - char temp; - int i, size; - c_undo_t *un = &el->el_chared.c_undo; + c_undo_t un = el->el_chared.c_undo; -#ifdef DEBUG_UNDO - (void) fprintf(el->el_errfile, "Undo: %x \"%s\" +%d -%d\n", - un->action, un->buf, un->isize, un->dsize); -#endif - switch (un->action) { - case DELETE: - if (un->dsize == 0) - return (CC_NORM); + if (un.len == -1) + return CC_ERROR; - (void) memcpy(un->buf, un->ptr, un->dsize); - for (cp = un->ptr; cp <= el->el_line.lastchar; cp++) - *cp = cp[un->dsize]; - - el->el_line.lastchar -= un->dsize; - el->el_line.cursor = un->ptr; - - un->action = INSERT; - un->isize = un->dsize; - un->dsize = 0; - break; - - case DELETE | INSERT: - size = un->isize - un->dsize; - if (size > 0) - i = un->dsize; - else - i = un->isize; - cp = un->ptr; - kp = un->buf; - while (i-- > 0) { - temp = *kp; - *kp++ = *cp; - *cp++ = temp; - } - if (size > 0) { - el->el_line.cursor = cp; - c_insert(el, size); - while (size-- > 0 && cp < el->el_line.lastchar) { - temp = *kp; - *kp++ = *cp; - *cp++ = temp; - } - } else if (size < 0) { - size = -size; - for (; cp <= el->el_line.lastchar; cp++) { - *kp++ = *cp; - *cp = cp[size]; - } - el->el_line.lastchar -= size; - } - el->el_line.cursor = un->ptr; - i = un->dsize; - un->dsize = un->isize; - un->isize = i; - break; - - case INSERT: - if (un->isize == 0) - return (CC_NORM); - - el->el_line.cursor = un->ptr; - c_insert(el, (int) un->isize); - (void) memcpy(un->ptr, un->buf, un->isize); - un->action = DELETE; - un->dsize = un->isize; - un->isize = 0; - break; - - case CHANGE: - if (un->isize == 0) - return (CC_NORM); - - el->el_line.cursor = un->ptr; - size = (int) (el->el_line.cursor - el->el_line.lastchar); - if (size < un->isize) - size = un->isize; - cp = un->ptr; - kp = un->buf; - for (i = 0; i < size; i++) { - temp = *kp; - *kp++ = *cp; - *cp++ = temp; - } - un->dsize = 0; - break; - - default: - return (CC_ERROR); - } + /* switch line buffer and undo buffer */ + el->el_chared.c_undo.buf = el->el_line.buffer; + el->el_chared.c_undo.len = el->el_line.lastchar - el->el_line.buffer; + el->el_chared.c_undo.cursor = el->el_line.cursor - el->el_line.buffer; + el->el_line.limit = un.buf + (el->el_line.limit - el->el_line.buffer); + el->el_line.buffer = un.buf; + el->el_line.cursor = un.buf + un.cursor; + el->el_line.lastchar = un.buf + un.len; return (CC_REFRESH); } @@ -644,24 +536,14 @@ vi_undo(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_command_mode(EditLine *el, int c) +vi_command_mode(EditLine *el, int c __attribute__((__unused__))) { - int size; /* [Esc] cancels pending action */ - el->el_chared.c_vcmd.ins = 0; el->el_chared.c_vcmd.action = NOP; el->el_chared.c_vcmd.pos = 0; el->el_state.doingarg = 0; - size = el->el_chared.c_undo.ptr - el->el_line.cursor; - if (size < 0) - size = -size; - if (el->el_chared.c_undo.action == (INSERT | DELETE) || - el->el_chared.c_undo.action == DELETE) - el->el_chared.c_undo.dsize = size; - else - el->el_chared.c_undo.isize = size; el->el_state.inputmode = MODE_INSERT; el->el_map.current = el->el_map.alt; @@ -681,42 +563,32 @@ protected el_action_t vi_zero(EditLine *el, int c) { - if (el->el_state.doingarg) { - if (el->el_state.argument > 1000000) - return (CC_ERROR); - el->el_state.argument = - (el->el_state.argument * 10) + (c - '0'); - return (CC_ARGHACK); - } else { - el->el_line.cursor = el->el_line.buffer; - if (el->el_chared.c_vcmd.action & DELETE) { - cv_delfini(el); - return (CC_REFRESH); - } - return (CC_CURSOR); + if (el->el_state.doingarg) + return ed_argument_digit(el, c); + + el->el_line.cursor = el->el_line.buffer; + if (el->el_chared.c_vcmd.action != NOP) { + cv_delfini(el); + return (CC_REFRESH); } + return (CC_CURSOR); } /* vi_delete_prev_char(): * Vi move to previous character (backspace) - * [^H] + * [^H] in insert mode only */ protected el_action_t /*ARGSUSED*/ -vi_delete_prev_char(EditLine *el, int c) +vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { - if (el->el_chared.c_vcmd.ins == 0) + if (el->el_line.cursor <= el->el_line.buffer) return (CC_ERROR); - if (el->el_chared.c_vcmd.ins > - el->el_line.cursor - el->el_state.argument) - return (CC_ERROR); - - c_delbefore(el, el->el_state.argument); - el->el_line.cursor -= el->el_state.argument; - + c_delbefore1(el); + el->el_line.cursor--; return (CC_REFRESH); } @@ -727,23 +599,35 @@ vi_delete_prev_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_list_or_eof(EditLine *el, int c) +vi_list_or_eof(EditLine *el, int c __attribute__((__unused__))) { -#ifdef notyet - if (el->el_line.cursor == el->el_line.lastchar && - el->el_line.cursor == el->el_line.buffer) { -#endif - term_overwrite(el, STReof, 4); /* then do a EOF */ - term__flush(); - return (CC_EOF); -#ifdef notyet + if (el->el_line.cursor == el->el_line.lastchar) { + if (el->el_line.cursor == el->el_line.buffer) { + term_overwrite(el, STReof, 4); /* then do a EOF */ + term__flush(); + return (CC_EOF); + } else { + /* + * Here we could list completions, but it is an + * error right now + */ + term_beep(el); + return (CC_ERROR); + } } else { +#ifdef notyet re_goto_bottom(el); *el->el_line.lastchar = '\0'; /* just in case */ return (CC_LIST_CHOICES); - } +#else + /* + * Just complain for now. + */ + term_beep(el); + return (CC_ERROR); #endif + } } @@ -753,7 +637,7 @@ vi_list_or_eof(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_kill_line_prev(EditLine *el, int c) +vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -774,7 +658,7 @@ vi_kill_line_prev(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_search_prev(EditLine *el, int c) +vi_search_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_PREV_HISTORY)); @@ -787,7 +671,7 @@ vi_search_prev(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_search_next(EditLine *el, int c) +vi_search_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); @@ -800,7 +684,7 @@ vi_search_next(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_search_next(EditLine *el, int c) +vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -816,7 +700,7 @@ vi_repeat_search_next(EditLine *el, int c) */ /*ARGSUSED*/ protected el_action_t -vi_repeat_search_prev(EditLine *el, int c) +vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -834,18 +718,9 @@ vi_repeat_search_prev(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_next_char(EditLine *el, int c) +vi_next_char(EditLine *el, int c __attribute__((__unused__))) { - char ch; - - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); - - el->el_search.chadir = CHAR_FWD; - el->el_search.chacha = ch; - - return (cv_csearch_fwd(el, ch, el->el_state.argument, 0)); - + return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); } @@ -855,17 +730,9 @@ vi_next_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_prev_char(EditLine *el, int c) +vi_prev_char(EditLine *el, int c __attribute__((__unused__))) { - char ch; - - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); - - el->el_search.chadir = CHAR_BACK; - el->el_search.chacha = ch; - - return (cv_csearch_back(el, ch, el->el_state.argument, 0)); + return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); } @@ -875,15 +742,9 @@ vi_prev_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_to_next_char(EditLine *el, int c) +vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) { - char ch; - - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); - - return (cv_csearch_fwd(el, ch, el->el_state.argument, 1)); - + return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); } @@ -893,14 +754,9 @@ vi_to_next_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_to_prev_char(EditLine *el, int c) +vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) { - char ch; - - if (el_getc(el, &ch) != 1) - return (ed_end_of_file(el, 0)); - - return (cv_csearch_back(el, ch, el->el_state.argument, 1)); + return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); } @@ -910,17 +766,11 @@ vi_to_prev_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_next_char(EditLine *el, int c) +vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) { - if (el->el_search.chacha == 0) - return (CC_ERROR); - - return (el->el_search.chadir == CHAR_FWD - ? cv_csearch_fwd(el, el->el_search.chacha, - el->el_state.argument, 0) - : cv_csearch_back(el, el->el_search.chacha, - el->el_state.argument, 0)); + return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, + el->el_state.argument, el->el_search.chatflg); } @@ -930,13 +780,345 @@ vi_repeat_next_char(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_prev_char(EditLine *el, int c) +vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) +{ + el_action_t r; + int dir = el->el_search.chadir; + + r = cv_csearch(el, -dir, el->el_search.chacha, + el->el_state.argument, el->el_search.chatflg); + el->el_search.chadir = dir; + return r; +} + + +/* vi_match(): + * Vi go to matching () {} or [] + * [%] + */ +protected el_action_t +/*ARGSUSED*/ +vi_match(EditLine *el, int c) +{ + const char match_chars[] = "()[]{}"; + char *cp; + int delta, i, count; + char o_ch, c_ch; + + *el->el_line.lastchar = '\0'; /* just in case */ + + i = strcspn(el->el_line.cursor, match_chars); + o_ch = el->el_line.cursor[i]; + if (o_ch == 0) + return CC_ERROR; + delta = strchr(match_chars, o_ch) - match_chars; + c_ch = match_chars[delta ^ 1]; + count = 1; + delta = 1 - (delta & 1) * 2; + + for (cp = &el->el_line.cursor[i]; count; ) { + cp += delta; + if (cp < el->el_line.buffer || cp >= el->el_line.lastchar) + return CC_ERROR; + if (*cp == o_ch) + count++; + else if (*cp == c_ch) + count--; + } + + el->el_line.cursor = cp; + + if (el->el_chared.c_vcmd.action != NOP) { + /* NB posix says char under cursor should NOT be deleted + for -ve delta - this is different to netbsd vi. */ + if (delta > 0) + el->el_line.cursor++; + cv_delfini(el); + return (CC_REFRESH); + } + return (CC_CURSOR); +} + +/* vi_undo_line(): + * Vi undo all changes to line + * [U] + */ +protected el_action_t +/*ARGSUSED*/ +vi_undo_line(EditLine *el, int c) { - if (el->el_search.chacha == 0) - return (CC_ERROR); - - return el->el_search.chadir == CHAR_BACK ? - cv_csearch_fwd(el, el->el_search.chacha, el->el_state.argument, 0) : - cv_csearch_back(el, el->el_search.chacha, el->el_state.argument, 0); + cv_undo(el); + return hist_get(el); +} + +/* vi_to_column(): + * Vi go to specified column + * [|] + * NB netbsd vi goes to screen column 'n', posix says nth character + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_column(EditLine *el, int c) +{ + + el->el_line.cursor = el->el_line.buffer; + el->el_state.argument--; + return ed_next_char(el, 0); +} + +/* vi_yank_end(): + * Vi yank to end of line + * [Y] + */ +protected el_action_t +/*ARGSUSED*/ +vi_yank_end(EditLine *el, int c) +{ + + cv_yank(el, el->el_line.cursor, + el->el_line.lastchar - el->el_line.cursor); + return CC_REFRESH; +} + +/* vi_yank(): + * Vi yank + * [y] + */ +protected el_action_t +/*ARGSUSED*/ +vi_yank(EditLine *el, int c) +{ + + return cv_action(el, YANK); +} + +/* vi_comment_out(): + * Vi comment out current command + * [c] + */ +protected el_action_t +/*ARGSUSED*/ +vi_comment_out(EditLine *el, int c) +{ + + el->el_line.cursor = el->el_line.buffer; + c_insert(el, 1); + *el->el_line.cursor = '#'; + re_refresh(el); + return ed_newline(el, 0); +} + +/* vi_alias(): + * Vi include shell alias + * [@] + * NB: posix impiles that we should enter insert mode, however + * this is against historical precedent... + */ +protected el_action_t +/*ARGSUSED*/ +vi_alias(EditLine *el, int c) +{ +#ifdef __weak_extern + char alias_name[3]; + char *alias_text; + extern char *get_alias_text(const char *); + __weak_extern(get_alias_text); + + if (get_alias_text == 0) { + return CC_ERROR; + } + + alias_name[0] = '_'; + alias_name[2] = 0; + if (el_getc(el, &alias_name[1]) != 1) + return CC_ERROR; + + alias_text = get_alias_text(alias_name); + if (alias_text != NULL) + el_push(el, alias_text); + return CC_NORM; +#else + return CC_ERROR; +#endif +} + +/* vi_to_history_line(): + * Vi go to specified history file line. + * [G] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_history_line(EditLine *el, int c) +{ + int sv_event_no = el->el_history.eventno; + el_action_t rval; + + + if (el->el_history.eventno == 0) { + (void) strncpy(el->el_history.buf, el->el_line.buffer, + EL_BUFSIZ); + el->el_history.last = el->el_history.buf + + (el->el_line.lastchar - el->el_line.buffer); + } + + /* Lack of a 'count' means oldest, not 1 */ + if (!el->el_state.doingarg) { + el->el_history.eventno = 0x7fffffff; + hist_get(el); + } else { + /* This is brain dead, all the rest of this code counts + * upwards going into the past. Here we need count in the + * other direction (to match the output of fc -l). + * I could change the world, but this seems to suffice. + */ + el->el_history.eventno = 1; + if (hist_get(el) == CC_ERROR) + return CC_ERROR; + el->el_history.eventno = 1 + el->el_history.ev.num + - el->el_state.argument; + if (el->el_history.eventno < 0) { + el->el_history.eventno = sv_event_no; + return CC_ERROR; + } + } + rval = hist_get(el); + if (rval == CC_ERROR) + el->el_history.eventno = sv_event_no; + return rval; +} + +/* vi_histedit(): + * Vi edit history line with vi + * [v] + */ +protected el_action_t +/*ARGSUSED*/ +vi_histedit(EditLine *el, int c) +{ + int fd; + pid_t pid; + int st; + char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; + char *cp; + + if (el->el_state.doingarg) { + if (vi_to_history_line(el, 0) == CC_ERROR) + return CC_ERROR; + } + + fd = mkstemp(tempfile); + if (fd < 0) + return CC_ERROR; + cp = el->el_line.buffer; + write(fd, cp, el->el_line.lastchar - cp +0u); + write(fd, "\n", 1); + pid = fork(); + switch (pid) { + case -1: + close(fd); + unlink(tempfile); + return CC_ERROR; + case 0: + close(fd); + execlp("vi", "vi", tempfile, NULL); + exit(0); + /*NOTREACHED*/ + default: + while (waitpid(pid, &st, 0) != pid) + continue; + lseek(fd, 0ll, SEEK_SET); + st = read(fd, cp, el->el_line.limit - cp +0u); + if (st > 0 && cp[st - 1] == '\n') + st--; + el->el_line.cursor = cp; + el->el_line.lastchar = cp + st; + break; + } + + close(fd); + unlink(tempfile); + /* return CC_REFRESH; */ + return ed_newline(el, 0); +} + +/* vi_history_word(): + * Vi append word from previous input line + * [_] + * Who knows where this one came from! + * '_' in vi means 'entire current line', so 'cc' is a synonym for 'c_' + */ +protected el_action_t +/*ARGSUSED*/ +vi_history_word(EditLine *el, int c) +{ + const char *wp = HIST_FIRST(el); + const char *wep, *wsp; + int len; + char *cp; + const char *lim; + + if (wp == NULL) + return CC_ERROR; + + wep = wsp = 0; + do { + while (isspace((unsigned char)*wp)) + wp++; + if (*wp == 0) + break; + wsp = wp; + while (*wp && !isspace((unsigned char)*wp)) + wp++; + wep = wp; + } while ((!el->el_state.doingarg || --el->el_state.argument > 0) && *wp != 0); + + if (wsp == 0 || (el->el_state.doingarg && el->el_state.argument != 0)) + return CC_ERROR; + + cv_undo(el); + len = wep - wsp; + if (el->el_line.cursor < el->el_line.lastchar) + el->el_line.cursor++; + c_insert(el, len + 1); + cp = el->el_line.cursor; + lim = el->el_line.limit; + if (cp < lim) + *cp++ = ' '; + while (wsp < wep && cp < lim) + *cp++ = *wsp++; + el->el_line.cursor = cp; + + el->el_map.current = el->el_map.key; + return CC_REFRESH; +} + +/* vi_redo(): + * Vi redo last non-motion command + * [.] + */ +protected el_action_t +/*ARGSUSED*/ +vi_redo(EditLine *el, int c) +{ + c_redo_t *r = &el->el_chared.c_redo; + + if (!el->el_state.doingarg && r->count) { + el->el_state.doingarg = 1; + el->el_state.argument = r->count; + } + + el->el_chared.c_vcmd.pos = el->el_line.cursor; + el->el_chared.c_vcmd.action = r->action; + if (r->pos != r->buf) { + if (r->pos + 1 > r->lim) + /* sanity */ + r->pos = r->lim - 1; + r->pos[0] = 0; + el_push(el, r->buf); + } + + el->el_state.thiscmd = r->cmd; + el->el_state.thisch = r->ch; + return (*el->el_map.func[r->cmd])(el, r->ch); }