diff options
| -rw-r--r-- | Makefile | 63 | ||||
| -rw-r--r-- | TEST/test.c | 250 | ||||
| -rw-r--r-- | chared.c | 645 | ||||
| -rw-r--r-- | chared.h | 160 | ||||
| -rw-r--r-- | common.c | 998 | ||||
| -rw-r--r-- | editline.3 | 532 | ||||
| -rw-r--r-- | editrc.5 | 292 | ||||
| -rw-r--r-- | el.c | 343 | ||||
| -rw-r--r-- | el.h | 131 | ||||
| -rw-r--r-- | emacs.c | 510 | ||||
| -rw-r--r-- | hist.c | 176 | ||||
| -rw-r--r-- | hist.h | 79 | ||||
| -rw-r--r-- | histedit.h | 178 | ||||
| -rw-r--r-- | history.c | 692 | ||||
| -rw-r--r-- | key.c | 732 | ||||
| -rw-r--r-- | key.h | 82 | ||||
| -rw-r--r-- | makelist | 185 | ||||
| -rw-r--r-- | map.c | 1403 | ||||
| -rw-r--r-- | map.h | 79 | ||||
| -rw-r--r-- | parse.c | 255 | ||||
| -rw-r--r-- | parse.h | 52 | ||||
| -rw-r--r-- | prompt.c | 129 | ||||
| -rw-r--r-- | prompt.h | 61 | ||||
| -rw-r--r-- | read.c | 452 | ||||
| -rw-r--r-- | refresh.c | 1019 | ||||
| -rw-r--r-- | refresh.h | 62 | ||||
| -rw-r--r-- | search.c | 640 | ||||
| -rw-r--r-- | search.h | 70 | ||||
| -rw-r--r-- | shlib_version | 2 | ||||
| -rw-r--r-- | sig.c | 199 | ||||
| -rw-r--r-- | sig.h | 72 | ||||
| -rw-r--r-- | sys.h | 118 | ||||
| -rw-r--r-- | term.c | 1465 | ||||
| -rw-r--r-- | term.h | 120 | ||||
| -rw-r--r-- | termcap.h | 54 | ||||
| -rw-r--r-- | tokenizer.c | 391 | ||||
| -rw-r--r-- | tokenizer.h | 55 | ||||
| -rw-r--r-- | tty.c | 1150 | ||||
| -rw-r--r-- | tty.h | 483 | ||||
| -rw-r--r-- | vi.c | 992 | 
40 files changed, 15371 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000..fadbddf3f6b94 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +#	$NetBSD: Makefile,v 1.8 1997/05/09 07:50:14 mycroft Exp $ +#	@(#)Makefile	8.1 (Berkeley) 6/4/93 + +LIB=	edit + +OSRCS=	chared.c common.c el.c emacs.c fcns.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 + +MLINKS=	editline.3 el_init.3 editline.3 el_end.3 editline.3 el_reset.3 \ +	editline.3 el_gets.3 editline.3 el_getc.3 editline.3 el_push.3 \ +	editline.3 el_parse.3 editline.3 el_set.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 + +# For speed and debugging +#SRCS=   ${OSRCS} tokenizer.c history.c +# For protection +SRCS=	editline.c tokenizer.c history.c + +SRCS+=	common.h emacs.h fcns.h help.h vi.h + +INCS= histedit.h +INCSDIR=/usr/include + +CLEANFILES+=common.h editline.c emacs.h fcns.c fcns.h help.c help.h vi.h +CFLAGS+=-I. -I${.CURDIR}  +CFLAGS+=#-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH +CFLAGS+=#-DDEBUG_PASTE + +AHDR=vi.h emacs.h common.h  +ASRC=${.CURDIR}/vi.c ${.CURDIR}/emacs.c ${.CURDIR}/common.c + +vi.h: vi.c makelist +	sh ${.CURDIR}/makelist -h ${.CURDIR}/vi.c > ${.TARGET} + +emacs.h: emacs.c makelist +	sh ${.CURDIR}/makelist -h ${.CURDIR}/emacs.c > ${.TARGET} + +common.h: common.c makelist +	sh ${.CURDIR}/makelist -h ${.CURDIR}/common.c > ${.TARGET} + +fcns.h: ${AHDR} makelist +	sh ${.CURDIR}/makelist -fh ${AHDR} > ${.TARGET} + +fcns.c: ${AHDR} fcns.h makelist +	sh ${.CURDIR}/makelist -fc ${AHDR} > ${.TARGET} + +help.c: ${ASRC} makelist  +	sh ${.CURDIR}/makelist -bc ${ASRC} > ${.TARGET} + +help.h: ${ASRC} makelist +	sh ${.CURDIR}/makelist -bh ${ASRC} > ${.TARGET} + +editline.c: ${OSRCS} +	sh ${.CURDIR}/makelist -e ${.ALLSRC:T} > ${.TARGET} + +test:	libedit.a test.o  +	${CC} ${CFLAGS} ${.ALLSRC} -o ${.TARGET} libedit.a ${LDADD} -ltermcap + +.include <bsd.lib.mk> diff --git a/TEST/test.c b/TEST/test.c new file mode 100644 index 0000000000000..cc2202df3b3c9 --- /dev/null +++ b/TEST/test.c @@ -0,0 +1,250 @@ +/*	$NetBSD	*/ + +/*- + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1992, 1993\n\ +	The Regents of the University of California.  All rights reserved.\n"; +#endif /* not lint */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)test.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * test.c: A little test program + */ +#include "sys.h" +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <sys/wait.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <dirent.h> + +#include "histedit.h" +#include "tokenizer.h" + +static int continuation = 0; +static EditLine *el = NULL; + +static char * +/*ARGSUSED*/ +prompt(el) +    EditLine *el; +{ +    static char a[] = "Edit$"; +    static char b[] = "Edit>"; +    return continuation ? b : a; +} + +static void +sig(i) +    int i; +{ +    (void) fprintf(stderr, "Got signal %d.\n", i); +    el_reset(el); +} + +static unsigned char +/*ARGSUSED*/ +complete(el, ch) +    EditLine *el; +    int ch; +{ +    DIR *dd = opendir(".");  +    struct dirent *dp; +    const char* ptr; +    const LineInfo *lf = el_line(el); +    int len; + +    /* +     * Find the last word +     */ +    for (ptr = lf->cursor - 1; !isspace(*ptr) && ptr > lf->buffer; ptr--) +	continue; +    len = lf->cursor - ++ptr; + +    for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) { +	if (len > strlen(dp->d_name)) +	    continue; +	if (strncmp(dp->d_name, ptr, len) == 0) { +	    closedir(dd); +	    if (el_insertstr(el, &dp->d_name[len]) == -1) +		return CC_ERROR; +	    else +		return CC_REFRESH; +	} +    } + +    closedir(dd); +    return CC_ERROR; +} + +int +/*ARGSUSED*/ +main(argc, argv) +    int argc; +    char *argv[]; +{ +    int num; +    const char *buf; +    Tokenizer *tok; +    History *hist; + +    (void) signal(SIGINT, sig); +    (void) signal(SIGQUIT, sig); +    (void) signal(SIGHUP, sig); +    (void) signal(SIGTERM, sig); + +    hist = history_init();		/* Init the builtin history	*/ +    history(hist, H_EVENT, 100);	/* Remember 100 events		*/ + +    tok  = tok_init(NULL);		/* Initialize the tokenizer	*/ + +    el = el_init(*argv, stdin, stdout);	/* Initialize editline		*/ + +    el_set(el, EL_EDITOR, "vi");	/* Default editor is vi 	*/ +    el_set(el, EL_SIGNAL, 1);		/* Handle signals gracefully	*/ +    el_set(el, EL_PROMPT, prompt);	/* Set the prompt function	*/ + +    /* Tell editline to use this history interface			*/ +    el_set(el, EL_HIST, history, hist); + +    /* Add a user-defined function 					*/ +    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete); + +    el_set(el, EL_BIND, "^I", "ed-complete", NULL);/* Bind tab to it 	*/ + +    /* +     * Bind j, k in vi command mode to previous and next line, instead +     * of previous and next history. +     */ +    el_set(el, EL_BIND, "-a", "k", "ed-prev-line", NULL); +    el_set(el, EL_BIND, "-a", "j", "ed-next-line", NULL); + +    /* +     * Source the user's defaults file. +     */ +    el_source(el, NULL); + +    while ((buf = el_gets(el, &num)) != NULL && num != 0)  { +	int ac; +	char **av; +#ifdef DEBUG +	(void) fprintf(stderr, "got %d %s", num, buf); +#endif +	if (!continuation && num == 1) +	    continue; + +	if (tok_line(tok, buf, &ac, &av) > 0) { +	    history(hist, continuation ? H_ADD : H_ENTER, buf); +	    continuation = 1; +	    continue; +	} + +	history(hist, continuation ? H_ADD : H_ENTER, buf); + +	continuation = 0; + +	if (strcmp(av[0], "history") == 0) { +	    const struct HistEvent *he; + +	    switch (ac) { +	    case 1: +		for (he = history(hist, H_LAST); he; +		     he = history(hist, H_PREV)) +		    (void) fprintf(stdout, "%4d %s", he->num, he->str); +		break; + +	    case 2: +		if (strcmp(av[1], "clear") == 0) +		     history(hist, H_CLEAR); +		else +		     goto badhist; +		break; + +	    case 3: +		if (strcmp(av[1], "load") == 0) +		     history(hist, H_LOAD, av[2]); +		else if (strcmp(av[1], "save") == 0) +		     history(hist, H_SAVE, av[2]); +		break; + +	    badhist: +	    default: +		(void) fprintf(stderr, "Bad history arguments\n"); +		break; +	    } +	} +	else if (el_parse(el, ac, av) == -1) { +	    switch (fork()) { +	    case 0: +		execvp(av[0], av); +		perror(av[0]); +		_exit(1); +		/*NOTREACHED*/ +		break; + +	    case -1: +		perror("fork"); +		break; + +	    default: +		if (wait(&num) == -1) +		    perror("wait"); +		(void) fprintf(stderr, "Exit %x\n", num); +		break; +	    } +	} + +	tok_reset(tok); +    } + +    el_end(el); +    tok_end(tok); +    history_end(hist); + +    return 0; +} diff --git a/chared.c b/chared.c new file mode 100644 index 0000000000000..82aa089d19b24 --- /dev/null +++ b/chared.c @@ -0,0 +1,645 @@ +/*	$NetBSD: chared.c,v 1.2 1997/01/11 06:47:48 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)chared.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: chared.c,v 1.2 1997/01/11 06:47:48 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/*  + * chared.c: Character editor utilities + */ +#include "sys.h" + +#include <stdlib.h> +#include "el.h" + +/* cv_undo(): + *	Handle state for the vi undo command + */ +protected void +cv_undo(el, action, size, ptr) +    EditLine *el; +    int action, size; +    char *ptr; +{ +    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_insert():  + *	Insert num characters + */ +protected void +c_insert(el, num) +    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.cursor < el->el_line.lastchar) {	 +	/* if I must move chars */ +	for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--) +	    cp[num] = *cp; +    } +    el->el_line.lastchar += num; +} /* end c_insert */ + + +/* c_delafter(): + *	Delete num characters after the cursor + */ +protected void +c_delafter(el, num)	 +    EditLine *el; +    int num; +{ + +    if (el->el_line.cursor + num > el->el_line.lastchar) +	num = el->el_line.lastchar - el->el_line.cursor; + +    if (num > 0) {			 +	char *cp; + +	if (el->el_map.current != el->el_map.emacs)  +	    cv_undo(el, INSERT, num, el->el_line.cursor); + +	for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) +	    *cp = cp[num]; + +	el->el_line.lastchar -= num; +    } +} + + +/* c_delbefore(): + *	Delete num characters before the cursor + */ +protected void +c_delbefore(el, num) +    EditLine *el; +    int num; +{ + +    if (el->el_line.cursor - num < el->el_line.buffer) +	num = el->el_line.cursor - el->el_line.buffer;	 + +    if (num > 0) {		 +	char *cp; + +	if (el->el_map.current != el->el_map.emacs)  +	    cv_undo(el, INSERT, num, el->el_line.cursor - num); + +	for (cp = el->el_line.cursor - num; cp <= el->el_line.lastchar; cp++) +	    *cp = cp[num]; + +	el->el_line.lastchar -= num; +    } +} + + +/* ce__isword(): + *	Return if p is part of a word according to emacs + */ +protected int +ce__isword(p)  +    int p; +{ +    return isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL; +} + + +/* cv__isword(): + *	Return if p is part of a word according to vi + */ +protected int +cv__isword(p)  +    int p; +{ +    return !isspace(p); +} + + +/* c__prev_word(): + *	Find the previous word + */ +protected char * +c__prev_word(p, low, n, wtest)  +    register char *p, *low; +    register int n; +    int (*wtest) __P((int)); +{ +    p--; + +    while (n--) { +	while ((p >= low) && !(*wtest)((unsigned char) *p))  +	    p--; +	while ((p >= low) && (*wtest)((unsigned char) *p))  +	    p--; +    } + +    /* cp now points to one character before the word */ +    p++; +    if (p < low) +	p = low; +    /* cp now points where we want it */ +    return p; +} + + +/* c__next_word(): + *	Find the next word + */ +protected char * +c__next_word(p, high, n, wtest) +    register char *p, *high; +    register int n; +    int (*wtest) __P((int)); +{ +    while (n--) { +	while ((p < high) && !(*wtest)((unsigned char) *p))  +	    p++; +	while ((p < high) && (*wtest)((unsigned char) *p))  +	    p++; +    } +    if (p > high) +	p = high; +    /* p now points where we want it */ +    return p; +} + +/* cv_next_word(): + *	Find the next word vi style + */ +protected char * +cv_next_word(el, p, high, n, wtest) +    EditLine *el; +    register char *p, *high; +    register int n; +    int (*wtest) __P((int)); +{ +    int test; + +    while (n--) { +    	test = (*wtest)((unsigned char) *p); +	while ((p < high) && (*wtest)((unsigned char) *p) == test)  +	    p++; +	/* +	 * 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))  +	    while ((p < high) && isspace((unsigned char) *p))  +		p++; +    } + +    /* p now points where we want it */ +    if (p > high) +	return high; +    else +	return p; +} + + +/* cv_prev_word(): + *	Find the previous word vi style + */ +protected char * +cv_prev_word(el, p, low, n, wtest) +    EditLine *el; +    register char *p, *low; +    register int n; +    int (*wtest) __P((int)); +{ +    int test; + +    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--; +	test = (*wtest)((unsigned char) *p); +	while ((p >= low) && (*wtest)((unsigned char) *p) == test)  +	    p--; +	p++; +	while (isspace((unsigned char) *p))  +		p++; +    } + +    /* p now points where we want it */ +    if (p < low) +	return low; +    else +	return p; +} + + +#ifdef notdef +/* c__number(): + *	Ignore character p points to, return number appearing after that. + * 	A '$' by itself means a big number; "$-" is for negative; '^' means 1. + * 	Return p pointing to last char used. + */ +protected char * +c__number(p, num, dval) +    char *p;	/* character position */ +    int *num;	/* Return value	*/ +    int dval;	/* dval is the number to subtract from like $-3 */ +{ +    register int i; +    register int sign = 1; + +    if (*++p == '^') { +	*num = 1; +	return p; +    } +    if (*p == '$') { +	if (*++p != '-') { +	    *num = 0x7fffffff;	/* Handle $ */ +	    return --p; +	} +	sign = -1;		/* Handle $- */ +	++p; +    } +    for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0') +	continue; +    *num = (sign < 0 ? dval - i : i); +    return --p; +} +#endif + +/* cv_delfini(): + *	Finish vi delete action + */ +protected void +cv_delfini(el)		 +    EditLine *el; +{ +    register int size; +    int oaction; + +    if (el->el_chared.c_vcmd.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)  +	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 = 1; +	c_delafter(el, 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: +	abort(); +	break; +    } +	 + +    el->el_chared.c_undo.ptr = el->el_line.cursor; +    el->el_chared.c_undo.dsize = size; +} + + +#ifdef notdef +/* ce__endword(): + *	Go to the end of this word according to emacs + */ +protected char * +ce__endword(p, high, n) +    char *p, *high; +    int n; +{ +    p++; + +    while (n--) { +	while ((p < high) && isspace((unsigned char) *p)) +	    p++; +	while ((p < high) && !isspace((unsigned char) *p))  +	    p++; +    } + +    p--; +    return p; +} +#endif + + +/* cv__endword(): + *	Go to the end of this word according to vi + */ +protected char * +cv__endword(p, high, n) +    char *p, *high; +    int n; +{ +    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++; +    } +    p--; +    return p; +} + +/* ch_init(): + *	Initialize the character editor + */ +protected int +ch_init(el) +    EditLine *el; +{ +    el->el_line.buffer              = (char *)  el_malloc(EL_BUFSIZ); +    (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_chared.c_undo.buf        = (char *)  el_malloc(EL_BUFSIZ); +    (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_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); +    (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ); +    el->el_chared.c_kill.mark       = el->el_line.buffer; +    el->el_chared.c_kill.last       = el->el_chared.c_kill.buf; + +    el->el_map.current              = el->el_map.key; + +    el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ +    el->el_state.doingarg  = 0; +    el->el_state.metanext  = 0; +    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 *)); +    return 0; +} + +/* ch_reset(): + *	Reset the character editor + */ +protected void +ch_reset(el) +    EditLine *el; +{ +    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_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; + +    el->el_map.current              = el->el_map.key; + +    el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ +    el->el_state.doingarg  = 0; +    el->el_state.metanext  = 0; +    el->el_state.argument  = 1; +    el->el_state.lastcmd   = ED_UNASSIGNED; + +    el->el_chared.c_macro.level     = -1; + +    el->el_history.eventno = 0; +} + + +/* ch_end(): + *	Free the data structures used by the editor + */ +protected void +ch_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_line.buffer); +    el->el_line.buffer = NULL; +    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_kill.buf); +    el->el_chared.c_kill.buf = NULL; +    el_free((ptr_t) el->el_chared.c_macro.macro); +    el->el_chared.c_macro.macro = NULL; +    ch_reset(el); +} + + +/* el_insertstr(): + *	Insert string at cursorI + */ +public int +el_insertstr(el, s) +    EditLine *el; +    char   *s; +{ +    int len; + +    if ((len = strlen(s)) == 0) +	return -1; +    if (el->el_line.lastchar + len >= el->el_line.limit) +	return -1; + +    c_insert(el, len); +    while (*s) +	*el->el_line.cursor++ = *s++; +    return 0; +} + + +/* el_deletestr(): + *	Delete num characters before the cursor + */ +public void +el_deletestr(el, n) +    EditLine *el; +    int     n; +{ +    if (n <= 0) +	return; + +    if (el->el_line.cursor < &el->el_line.buffer[n])  +	return; + +    c_delbefore(el, n);		/* delete before dot */ +    el->el_line.cursor -= n; +    if (el->el_line.cursor < el->el_line.buffer) +	el->el_line.cursor = el->el_line.buffer; +} + +/* c_gets(): + *	Get a string + */ +protected int +c_gets(el, buf) +    EditLine *el; +    char *buf; +{ +    char ch; +    int len = 0; + +    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; +	    } +	    re_refresh(el); +	    ch = 0; +	    break; + +	case 0033:	/* ESC */ +	case '\r':	/* Newline */ +	case '\n': +	    break; + +	default: +	    if (len >= EL_BUFSIZ) +		term_beep(el); +	    else { +		buf[len++] = ch; +		*el->el_line.cursor++ = ch; +		el->el_line.lastchar = el->el_line.cursor; +	    } +	    re_refresh(el); +	    ch = 0; +	    break; +	} +    } +    buf[len] = ch; +    return len; +} + + +/* c_hpos(): + *	Return the current horizontal position of the cursor + */ +protected int +c_hpos(el) +    EditLine *el; +{ +    char *ptr; + +    /* +     * Find how many characters till the beginning of this line. +     */ +    if (el->el_line.cursor == el->el_line.buffer) +	return 0; +    else { +	for (ptr = el->el_line.cursor - 1;  +	     ptr >= el->el_line.buffer && *ptr != '\n'; +	     ptr--) +	    continue; +	return el->el_line.cursor - ptr - 1; +    } +} diff --git a/chared.h b/chared.h new file mode 100644 index 0000000000000..4e7c28587f016 --- /dev/null +++ b/chared.h @@ -0,0 +1,160 @@ +/*	$NetBSD: chared.h,v 1.2 1997/01/11 06:47:49 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. + * + *	@(#)chared.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.chared.h: Character editor interface + */ +#ifndef _h_el_chared +#define _h_el_chared + +#include <ctype.h> +#include <string.h> + +#include "histedit.h" + +#define EL_MAXMACRO 10 + +/* + * This is a issue of basic "vi" look-and-feel. Defining VI_MOVE works + * like real vi: i.e. the transition from command<->insert modes moves + * the cursor. + * + * On the other hand we really don't want to move the cursor, because  + * all the editing commands don't include the character under the cursor. + * Probably the best fix is to make all the editing commands aware of + * this fact. + */ +#define VI_MOVE + + +typedef struct c_macro_t { +    int    level; +    char **macro; +    char  *nline; +} c_macro_t; + +/*  + * Undo information for both vi and emacs + */ +typedef struct c_undo_t { +    int   action; +    int   isize; +    int   dsize; +    char *ptr; +    char *buf; +} c_undo_t; + +/* + * Current action information for vi + */ +typedef struct c_vcmd_t { +    int   action; +    char *pos; +    char *ins; +} c_vcmd_t; + +/* + * Kill buffer for emacs + */ +typedef struct c_kill_t { +    char *buf; +    char *last; +    char *mark; +} c_kill_t; + +/* + * Note that we use both data structures because the user can bind + * commands from both editors! + */ +typedef struct el_chared_t { +    c_undo_t    c_undo; +    c_kill_t    c_kill; +    c_vcmd_t    c_vcmd; +    c_macro_t   c_macro; +} el_chared_t; + + +#define STReof "^D\b\b" +#define STRQQ  "\"\"" + +#define isglob(a) (strchr("*[]?", (a)) != NULL) +#define isword(a) (isprint(a)) + +#define NOP    	  0x00 +#define DELETE 	  0x01 +#define INSERT 	  0x02 +#define CHANGE 	  0x04 + +#define CHAR_FWD	0 +#define CHAR_BACK	1 + +#define MODE_INSERT	0 +#define MODE_REPLACE	1 +#define MODE_REPLACE_1	2 + +#include "common.h" +#include "vi.h" +#include "emacs.h" +#include "search.h" +#include "fcns.h" + + +protected int   cv__isword	__P((int)); +protected void  cv_delfini	__P((EditLine *)); +protected char *cv__endword	__P((char *, char *, int)); +protected int   ce__isword	__P((int)); +protected void  cv_undo		__P((EditLine *, int, int, char *)); +protected char *cv_next_word	__P((EditLine*, char *, char *, int,  +				     int (*)(int))); +protected char *cv_prev_word	__P((EditLine*, char *, char *, int, +				     int (*)(int))); +protected char *c__next_word	__P((char *, char *, int, int (*)(int))); +protected char *c__prev_word	__P((char *, char *, int, int (*)(int))); +protected void  c_insert	__P((EditLine *, int)); +protected void  c_delbefore	__P((EditLine *, int)); +protected void  c_delafter	__P((EditLine *, int)); +protected int   c_gets		__P((EditLine *, char *)); +protected int   c_hpos		__P((EditLine *)); + +protected int   ch_init		__P((EditLine *)); +protected void  ch_reset	__P((EditLine *)); +protected void  ch_end		__P((EditLine *)); + +#endif /* _h_el_chared */ diff --git a/common.c b/common.c new file mode 100644 index 0000000000000..a0636cb552f34 --- /dev/null +++ b/common.c @@ -0,0 +1,998 @@ +/*	$NetBSD: common.c,v 1.3 1997/01/14 04:17:22 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: common.c,v 1.3 1997/01/14 04:17:22 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * common.c: Common Editor functions + */ +#include "sys.h" +#include "el.h" + +/* ed_end_of_file():  + *	Indicate end of file + *	[^D] + */ +protected el_action_t +/*ARGSUSED*/ +ed_end_of_file(el, c) +    EditLine *el; +    int c; +{ +    re_goto_bottom(el); +    *el->el_line.lastchar = '\0'; +    return CC_EOF; +} + + +/* ed_insert():  + *	Add character to the line + *	Insert a character [bound to all insert keys] + */ +protected el_action_t +ed_insert(el, c) +    EditLine *el; +    int c; +{ +    int i; + +    if (c == '\0') +	return CC_ERROR; + +    if (el->el_line.lastchar + el->el_state.argument >=  +	el->el_line.limit) +	return CC_ERROR;	/* end of buffer space */ + +    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); + +	*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]; + +	    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--) +	    *el->el_line.cursor++ = c; +	re_refresh(el); +    } + +    if (el->el_state.inputmode == MODE_REPLACE_1) +	(void) vi_command_mode(el, 0); + +    return CC_NORM; +} + + +/* ed_delete_prev_word():  + *	Delete from beginning of current word to cursor + *	[M-^?] [^W] + */ +protected el_action_t +/*ARGSUSED*/ +ed_delete_prev_word(el, c) +    EditLine *el; +    int c; +{ +    char *cp, *p, *kp; + +    if (el->el_line.cursor == el->el_line.buffer) +	return CC_ERROR; + +    cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,  +		      el->el_state.argument, ce__isword); + +    for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++) +	*kp++ = *p; +    el->el_chared.c_kill.last = kp; + +    c_delbefore(el, el->el_line.cursor - cp);	/* delete before dot */ +    el->el_line.cursor = cp; +    if (el->el_line.cursor < el->el_line.buffer) +	el->el_line.cursor = el->el_line.buffer;	/* bounds check */ +    return CC_REFRESH; +} + + +/* ed_delete_next_char():  + *	Delete character under cursor + *	[^D] [x] + */ +protected el_action_t +/*ARGSUSED*/ +ed_delete_next_char(el, c) +    EditLine *el; +    int c; +{ +#ifdef notdef /* XXX */ +#define EL el->el_line +fprintf(stderr, "\nD(b: %x(%s)  c: %x(%s) last: %x(%s) limit: %x(%s)\n",  +	EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar, EL.lastchar, EL.limit, EL.limit); +#endif +    if (el->el_line.cursor == el->el_line.lastchar) {/* if I'm at the end */ +	if (el->el_map.type == MAP_VI) { +	    if (el->el_line.cursor == el->el_line.buffer) {	 +		/* if I'm also at the beginning */ +#ifdef KSHVI +		return CC_ERROR; +#else +		term_overwrite(el, STReof, 4);/* then do a EOF */ +		term__flush(); +		return CC_EOF; +#endif +	    } +	    else  { +#ifdef KSHVI +		el->el_line.cursor--; +#else +		return CC_ERROR; +#endif +	    } +	} +	else { +	    if (el->el_line.cursor != el->el_line.buffer) +		el->el_line.cursor--; +	    else +		return CC_ERROR; +	} +    } +    c_delafter(el, el->el_state.argument);	/* delete after dot */ +    if (el->el_line.cursor >= el->el_line.lastchar && el->el_line.cursor > el->el_line.buffer) +	el->el_line.cursor = el->el_line.lastchar - 1;	/* bounds check */ +    return CC_REFRESH; +} + + +/* ed_kill_line():  + *	Cut to the end of line + *	[^K] [^K] + */ +protected el_action_t +/*ARGSUSED*/ +ed_kill_line(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    cp = el->el_line.cursor; +    kp = el->el_chared.c_kill.buf; +    while (cp < el->el_line.lastchar) +	*kp++ = *cp++;		/* copy it */ +    el->el_chared.c_kill.last = kp; +    el->el_line.lastchar = el->el_line.cursor; /* zap! -- delete to end */ +    return CC_REFRESH; +} + + +/* ed_move_to_end():  + *	Move cursor to the end of line + *	[^E] [^E] + */ +protected el_action_t +/*ARGSUSED*/ +ed_move_to_end(el, c) +    EditLine *el; +    int c; +{ +    el->el_line.cursor = el->el_line.lastchar; +    if (el->el_map.type == MAP_VI) { +#ifdef VI_MOVE +	el->el_line.cursor--; +#endif +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} +    } +    return CC_CURSOR; +} + + +/* ed_move_to_beg():  + *	Move cursor to the beginning of line + *	[^A] [^A] + */ +protected el_action_t +/*ARGSUSED*/ +ed_move_to_beg(el, c) +    EditLine *el; +    int c; +{ +    el->el_line.cursor = el->el_line.buffer; + +    if (el->el_map.type == MAP_VI) { +        /* We want FIRST non space character */ +        while (isspace(*el->el_line.cursor))  +	    el->el_line.cursor++; +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} +    } + +    return CC_CURSOR; +} + + +/* ed_transpose_chars():  + *	Exchange the character to the left of the cursor with the one under it + *	[^T] [^T] + */ +protected el_action_t +ed_transpose_chars(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor < el->el_line.lastchar) { +	if (el->el_line.lastchar <= &el->el_line.buffer[1]) +	    return CC_ERROR; +	else  +	    el->el_line.cursor++; +    } +    if (el->el_line.cursor > &el->el_line.buffer[1]) { +	/* must have at least two chars entered */ +	c = el->el_line.cursor[-2]; +	el->el_line.cursor[-2] = el->el_line.cursor[-1]; +	el->el_line.cursor[-1] = c; +	return CC_REFRESH; +    } +    else  +	return CC_ERROR; +} + + +/* ed_next_char():  + *	Move to the right one character + *	[^F] [^F] + */ +protected el_action_t +/*ARGSUSED*/ +ed_next_char(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor >= el->el_line.lastchar) +	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_map.type == MAP_VI) +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} + +    return CC_CURSOR; +} + + +/* ed_prev_word():  + *	Move to the beginning of the current word + *	[M-b] [b] + */ +protected el_action_t +/*ARGSUSED*/ +ed_prev_word(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor == el->el_line.buffer) +	return CC_ERROR; + +    el->el_line.cursor = c__prev_word(el->el_line.cursor, el->el_line.buffer,  +				      el->el_state.argument,  +				      ce__isword); + +    if (el->el_map.type == MAP_VI) +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} + +    return CC_CURSOR; +} + + +/* ed_prev_char():  + *	Move to the left one character + *	[^B] [^B] + */ +protected el_action_t +/*ARGSUSED*/ +ed_prev_char(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor > el->el_line.buffer) { +	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; + +	if (el->el_map.type == MAP_VI) +	    if (el->el_chared.c_vcmd.action & DELETE) { +		cv_delfini(el); +		return CC_REFRESH; +	    } + +	return CC_CURSOR; +    } +    else  +	return CC_ERROR; +} + + +/* ed_quoted_insert():  + *	Add the next character typed verbatim + *	[^V] [^V] + */ +protected el_action_t +ed_quoted_insert(el, c) +    EditLine *el; +    int c; +{ +    int     num; +    char    tc; + +    tty_quotemode(el); +    num = el_getc(el, &tc); +    c = (unsigned char) tc; +    tty_noquotemode(el); +    if (num == 1) +	return ed_insert(el, c); +    else +	return ed_end_of_file(el, 0); +} + + +/* ed_digit():  + *	Adds to argument or enters a digit + */ +protected el_action_t +ed_digit(el, c) +    EditLine *el; +    int c; +{ +    if (!isdigit(c)) +	return CC_ERROR; + +    if (el->el_state.doingarg) {	 +	/* if doing an arg, add this in... */ +	if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)	 +	    el->el_state.argument = c - '0'; +	else { +	    if (el->el_state.argument > 1000000) +		return CC_ERROR; +	    el->el_state.argument =  +		(el->el_state.argument * 10) + (c - '0'); +	} +	return CC_ARGHACK; +    } +    else { +	if (el->el_line.lastchar + 1 >= el->el_line.limit) +	    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; +} + + +/* ed_argument_digit():  + *	Digit that starts argument + *	For ESC-n + */ +protected el_action_t +ed_argument_digit(el, c) +    EditLine *el; +    register int c; +{ +    if (!isdigit(c)) +	return CC_ERROR; + +    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'); +    } +    else {			/* else starting an argument */ +	el->el_state.argument = c - '0'; +	el->el_state.doingarg = 1; +    } +    return CC_ARGHACK; +} + + +/* ed_unassigned():  + *	Indicates unbound character + *	Bound to keys that are not assigned + */ +protected el_action_t +/*ARGSUSED*/ +ed_unassigned(el, c) +    EditLine *el; +    int c; +{ +    term_beep(el); +    term__flush(); +    return CC_NORM; +} + + +/** + ** TTY key handling. + **/ + +/* ed_tty_sigint():  + *	Tty interrupt character + *	[^C] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_sigint(el, c) +    EditLine *el; +    int c; +{			 +    return CC_NORM; +} + + +/* ed_tty_dsusp():  + *	Tty delayed suspend character + *	[^Y] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_dsusp(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_tty_flush_output():  + *	Tty flush output characters + *	[^O] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_flush_output(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_tty_sigquit():  + *	Tty quit character + *	[^\] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_sigquit(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_tty_sigtstp():  + *	Tty suspend character + *	[^Z] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_sigtstp(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_tty_stop_output():  + *	Tty disallow output characters + *	[^S] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_stop_output(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_tty_start_output():  + *	Tty allow output characters + *	[^Q] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_start_output(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_newline():  + *	Execute command + *	[^J] + */ +protected el_action_t +/*ARGSUSED*/ +ed_newline(el, c) +    EditLine *el; +    int c; +{ +    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; +} + + +/* ed_delete_prev_char():  + *	Delete the character to the left of the cursor + *	[^?] + */ +protected el_action_t +/*ARGSUSED*/ +ed_delete_prev_char(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor <= el->el_line.buffer)  +	return CC_ERROR; + +    c_delbefore(el, el->el_state.argument);	 +    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; +} + + +/* ed_clear_screen():  + *	Clear screen leaving current line at the top + *	[^L] + */ +protected el_action_t +/*ARGSUSED*/ +ed_clear_screen(el, c) +    EditLine *el; +    int c; +{ +    term_clear_screen(el);	/* clear the whole real screen */ +    re_clear_display(el);		/* reset everything */ +    return CC_REFRESH; +} + + +/* ed_redisplay():  + *	Redisplay everything + *	^R + */ +protected el_action_t +/*ARGSUSED*/ +ed_redisplay(el, c) +    EditLine *el; +    int c; +{ +    return CC_REDISPLAY; +} + + +/* ed_start_over():  + *	Erase current line and start from scratch + *	[^G] + */ +protected el_action_t +/*ARGSUSED*/ +ed_start_over(el, c) +    EditLine *el; +    int c; +{ +    ch_reset(el); +    return CC_REFRESH; +} + + +/* ed_sequence_lead_in():  + *	First character in a bound sequence + *	Placeholder for external keys + */ +protected el_action_t +/*ARGSUSED*/ +ed_sequence_lead_in(el, c) +    EditLine *el; +    int c; +{ +    return CC_NORM; +} + + +/* ed_prev_history():  + *	Move to the previous history line + *	[^P] [k] + */ +protected el_action_t +/*ARGSUSED*/ +ed_prev_history(el, c) +    EditLine *el; +    int c; +{ +    char    beep = 0; + +    el->el_chared.c_undo.action = NOP; +    *el->el_line.lastchar = '\0';		/* just in case */ + +    if (el->el_history.eventno == 0) {	/* save the current buffer away */ +	(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); +    } + +    el->el_history.eventno += el->el_state.argument; + +    if (hist_get(el) == 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 */ +} + + +/* ed_next_history():  + *	Move to the next history line + *	[^N] [j] + */ +protected el_action_t +/*ARGSUSED*/ +ed_next_history(el, c) +    EditLine *el; +    int c; +{ +    el->el_chared.c_undo.action = NOP; +    *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 */ +    } + +    return hist_get(el); +} + + +/* ed_search_prev_history():  + *	Search previous in history for a line matching the current + *	next search history [M-P] [K] + */ +protected el_action_t +/*ARGSUSED*/ +ed_search_prev_history(el, c) +    EditLine *el; +    int c; +{ +    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_line.lastchar = '\0';		/* just in case */ +    if (el->el_history.eventno < 0) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "e_prev_search_hist(): eventno < 0;\n"); +#endif +	el->el_history.eventno = 0; +	return CC_ERROR; +    } + +    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); +    } + + +    if (el->el_history.ref == NULL) +	return CC_ERROR; + +    hp = HIST_FIRST(el); +    if (hp == NULL) +	return CC_ERROR; + +    c_setpat(el);		/* Set search pattern !! */ + +    for (h = 1; h <= el->el_history.eventno; h++) +	hp = HIST_NEXT(el); + +    while (hp != NULL) { +#ifdef SDEBUG +	(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); +#endif +	if ((strncmp(hp, el->el_line.buffer,  +		     el->el_line.lastchar - el->el_line.buffer) ||  +	    hp[el->el_line.lastchar-el->el_line.buffer]) &&  +	    c_hmatch(el, hp)) { +	    found++; +	    break; +	} +	h++; +	hp = HIST_NEXT(el); +    } + +    if (!found) { +#ifdef SDEBUG +	(void) fprintf(el->el_errfile, "not found\n");  +#endif +	return CC_ERROR; +    } + +    el->el_history.eventno = h; + +    return hist_get(el); +} + + +/* ed_search_next_history():  + *	Search next in history for a line matching the current + *	[M-N] [J] + */ +protected el_action_t +/*ARGSUSED*/ +ed_search_next_history(el, c) +    EditLine *el; +    int c; +{ +    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_line.lastchar = '\0';		/* just in case */ + +    if (el->el_history.eventno == 0) +	return CC_ERROR; + +    if (el->el_history.ref == NULL) +	return CC_ERROR; + +    hp = HIST_FIRST(el); +    if (hp == NULL) +	return CC_ERROR; + +    c_setpat(el);		/* Set search pattern !! */ + +    for (h = 1; h < el->el_history.eventno && hp; h++) { +#ifdef SDEBUG +	(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp); +#endif +	if ((strncmp(hp, el->el_line.buffer,  +		     el->el_line.lastchar - el->el_line.buffer) ||  +	     hp[el->el_line.lastchar-el->el_line.buffer]) &&  +	    c_hmatch(el, hp)) +	    found = h; +	hp = HIST_NEXT(el); +    } + +    if (!found) {		/* is it the current history number? */ +	if (!c_hmatch(el, el->el_history.buf)) { +#ifdef SDEBUG +	    (void) fprintf(el->el_errfile, "not found\n");  +#endif +	    return CC_ERROR; +	} +    } + +    el->el_history.eventno = found; + +    return hist_get(el); +} + + +/* ed_prev_line(): + *	Move up one line + *	Could be [k] [^p] + */ +protected el_action_t +/*ARGSUSED*/ +ed_prev_line(el, c) +    EditLine *el; +    int c; +{ +    char *ptr; +    int nchars = c_hpos(el); +     +    /* +     * Move to the line requested +     */ +    if (*(ptr = el->el_line.cursor) == '\n') +	ptr--; + +    for (; ptr >= el->el_line.buffer; ptr--) +	if (*ptr == '\n' && --el->el_state.argument <= 0) +	    break; + +    if (el->el_state.argument > 0) +	return CC_ERROR; + +    /* +     * Move to the beginning of the line +     */ +    for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--) +	continue; +     +    /* +     * Move to the character requested +     */ +    for (ptr++;  +	 nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';  +	 ptr++) +	continue; +     +    el->el_line.cursor = ptr; +    return CC_CURSOR; +} + + +/* ed_next_line(): + *	Move down one line + *	Could be [j] [^n] + */ +protected el_action_t +/*ARGSUSED*/ +ed_next_line(el, c) +    EditLine *el; +    int c; +{ +    char *ptr; +    int nchars = c_hpos(el); + +    /* +     * Move to the line requested +     */ +    for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++) +	if (*ptr == '\n' && --el->el_state.argument <= 0) +	    break; + +    if (el->el_state.argument > 0) +	return CC_ERROR; + +    /* +     * Move to the character requested +     */ +    for (ptr++; +	 nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';  +    	 ptr++) +	continue; +     +    el->el_line.cursor = ptr; +    return CC_CURSOR; +} + + +/* ed_command():  + *	Editline extended command + *	[M-X] [:] + */ +protected el_action_t +/*ARGSUSED*/ +ed_command(el, c) +    EditLine *el; +    int c; +{ +    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; + +    c_insert(el, 3);	/* prompt + ": " */ +    *el->el_line.cursor++ = '\n'; +    *el->el_line.cursor++ = ':'; +    *el->el_line.cursor++ = ' '; +    re_refresh(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; +} diff --git a/editline.3 b/editline.3 new file mode 100644 index 0000000000000..b2858f6a7a95f --- /dev/null +++ b/editline.3 @@ -0,0 +1,532 @@ +.\"	$NetBSD: editline.3,v 1.4 1997/01/14 04:17:23 lukem Exp $ +.\" +.\" Copyright (c) 1997 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This file was contributed to The NetBSD Foundation by Luke Mewburn. +.\" +.\" 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 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. +.\" +.Dd January 11, 1997 +.Os BSD 4.4 +.Dt EDITLINE 3 +.Sh NAME +.Nm editline , +.Nm el_init , +.Nm el_end , +.Nm el_reset , +.Nm el_gets , +.Nm el_getc , +.Nm el_push , +.Nm el_parse , +.Nm el_set , +.Nm el_source , +.Nm el_resize , +.Nm el_line , +.Nm el_insertstr , +.Nm el_deletestr , +.Nm history_init , +.Nm history_end , +.Nm history +.Nd line editor and history functions +.Sh SYNOPSIS +.Fd #include <histedit.h> +.Ft EditLine * +.Fn el_init "const char *prog" "FILE *fin" "FILE *fout" +.Ft void +.Fn el_end "EditLine *e" +.Ft void +.Fn el_reset "EditLine *e" +.Ft const char * +.Fn el_gets "EditLine *e" "int *count" +.Ft int +.Fn el_getc "EditLine *e" "char *ch" +.Ft void +.Fn el_push "EditLine *e" "const char *str" +.Ft int +.Fn el_parse "EditLine *e" "int argc" "char *argv[]" +.Ft int +.Fn el_set "EditLine *e" "int op" "..." +.Ft int +.Fn el_source "EditLine *e" "const char *file" +.Ft void +.Fn el_resize "EditLine *e" +.Ft const LineInfo * +.Fn el_line "EditLine *e" +.Ft int +.Fn el_insertstr "EditLine *e" "char *str" +.Ft void +.Fn el_deletestr "EditLine *e" "int count" +.Ft History * +.Fn history_init +.Ft void +.Fn history_end "History *h" +.Ft HistEvent * +.Fn history "History h" "int op" "..." +.Sh DESCRIPTION +The +.Nm +library provides generic line editing and history functions, +similar to those found in +.Xr sh 1 . +.Pp +These functions are available in the +.Nm libedit +library (which needs the +.Nm libtermcap +library). +Programs should be linked with +.Fl ledit ltermcap . +.Sh LINE EDITING FUNCTIONS +The line editing functions use a common data structure, +.Fa EditLine , +which is created by +.Fn el_init +and freed by +.Fn el_end . +.Pp +The following functions are available: +.Bl -tag -width 4n +.It Fn el_init +Initialise the line editor, and return a data structure +to be used by all other line editing functions. +.Fa prog +is the name of the invoking program, used when reading the +.Xr editrc 5 +file to determine which settings to use. +.Fa fin +and +.Fa fout +are the input and output streams (respectively) to use. +In this documentation, references to +.Dq the tty +are actually to this input/output stream combination. +.It Fn el_end +Clean up and finish with +.Fa e , +assumed to have been created with +.Fn el_init . +.It Fn el_reset +Reset the tty and the parser. +This should be called after an error which may have upset the tty's +state. +.It Fn el_gets +Read a line from the tty. +.Fa count +is modified to contain the number of characters read. +Returns the line read if successful, or +.Dv NULL +if no characters were read or if an error occurred. +.It Fn el_getc +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. +.It Fn el_push +Pushes +.Fa str +back onto the input stream. +This is used by the macro expansion mechanism. +Refer to the description of +.Ic bind +.Fl s +in +.Xr editrc 5 +for more information. +.It Fn el_parse +Parses the +.Fa argv +array (which is +.Fa argc +elements in size) +to execute builtin +.Nm +commands. +If the command is prefixed with +.Dq prog: +then +.Fn el_parse +will only execute the command if +.Dq prog +matches the +.Fa prog +argument supplied to +.Fn el_init . +The return value is +-1 if the command is unknown, +0 if there was no error or +.Dq prog +didn't match, or +1 if the command returned an error. +Refer to +.Xr editrc 5 +for more information. +.Pp +.Em NOTE: +.Va argv[0] +may be modified by +.Fn el_parse . +The colon between +.Dq prog +and the command,  +.Ar command , +will be replaced with a NUL +.Po +.Dq \e0 +.Pc . +.It Fn el_set +Set +.Nm +parameters. +.Fa op +determines which parameter to set, and each operation has its +own parameter list. +.Pp +The following values for +.Fa op +are supported, along with the required argument list: +.Bl -tag -width 4n +.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)" +Define prompt printing function as +.Fa f , +which is to return a string that contains the prompt. +.It Dv EL_TERMINAL , Fa "const char *type" +Define terminal type of the tty to be +.Fa type , +or to +.Ev TERM +if +.Fa type +is +.Dv NULL . +.It Dv EL_EDITOR , Fa "const char *mode" +Set editing mode to +.Fa mode , +which must be one of +.Dq emacs +or +.Dq vi . +.It Dv EL_SIGNAL , Fa "int flag" +If +.Fa flag +is non-zero, +.Nm +will install its own signal handler for the following signals when +reading command input: +.Dv SIGCONT , +.Dv SIGHUP , +.Dv SIGINT , +.Dv SIGQUIT , +.Dv SIGSTOP , +.Dv SIGTERM , +.Dv SIGTSTP , +and +.Dv SIGWINCH . +Otherwise, the current signal handlers will be used. +.It Dv EL_BIND , Xo +.Fa "const char *" , +.Fa "..." , +.Dv NULL +.Xc +Perform the +.Ic bind +builtin command. +Refer to  +.Xr editrc 5 +for more information. +.It Dv EL_ECHOTC , Xo +.Fa "const char *" , +.Fa "..." , +.Dv NULL +.Xc +Perform the +.Ic echotc +builtin command. +Refer to  +.Xr editrc 5 +for more information. +.It Dv EL_SETTC , Xo +.Fa "const char *" , +.Fa "..." , +.Dv NULL +.Xc +Perform the +.Ic settc +builtin command. +Refer to  +.Xr editrc 5 +for more information. +.It Dv EL_SETTY , Xo +.Fa "const char *" , +.Fa "..." , +.Dv NULL +.Xc +Perform the +.Ic setty +builtin command. +Refer to  +.Xr editrc 5 +for more information. +.It Dv EL_TELLTC , Xo +.Fa "const char *" , +.Fa "..." , +.Dv NULL +.Xc +Perform the +.Ic telltc +builtin command. +Refer to  +.Xr editrc 5 +for more information. +.It Dv EL_ADDFN , Xo +.Fa "const char *name" , +.Fa "const char *help" , +.Fa "unsigned char (*func)(EditLine *e, int ch) +.Xc +Add a user defined function, +.Fn func , +referred to as +.Fa name +which is invoked when a key which is bound to +.Fa name +is entered. +.Fa help +is a description of +.Fa name . +At invocation time, +.Fa ch +is the key which caused the invocation. +The return value of +.Fn func +should be one of: +.Bl -tag -width "CC_REDISPLAY" +.It Dv CC_NORM +Add a normal character. +.It Dv CC_NEWLINE +End of line was entered. +.It Dv CC_EOF +EOF was entered. +.It Dv CC_ARGHACK +Expecting further command input as arguments, do nothing visually. +.It Dv CC_REFRESH +Refresh display. +.It Dv CC_CURSOR +Cursor moved, so update and perform +.Dv CC_REFRESH. +.It Dv CC_REDISPLAY +Redisplay entire input line. +This is useful if a key binding outputs extra information. +.It Dv CC_ERROR +An error occurred. +Beep, and flush tty. +.It Dv CC_FATAL +Fatal error, reset tty to known state. +.El +.It Dv EL_HIST , Xo +.Fa "History *(*func)(History *, int op, ...)" , +.Fa "const char *ptr" +.Xc +Defines which history function to use, which is usually +.Fn history . +.Fa ptr +should be the value returned by +.Fn history_init . +.El +.It Fn el_source +Initialise +.Nm +by reading the contents of  +.Fa file . +.Fn el_parse +is called for each line in +.Fa file . +If +.Fa file +is +.Dv NULL , +try +.Pa $PWD/.editrc +then +.Pa $HOME/.editrc . +Refer to +.Xr editrc 5 +for details on the format of +.Fa file . +.It Fn el_resize +Must be called if the terminal size changes. +If +.Dv EL_SIGNAL +has been set with +.Fn el_set , +then this is done automatically. +Otherwise, it's the responsibility of the application to call +.Fn el_resize +on the appropriate occasions. +.It Fn el_line +Return the editing information for the current line in a +.Fa LineInfo +structure, which is defined as follows: +.Bd -literal +typedef struct lineinfo { +    const char *buffer;    /* address of buffer */ +    const char *cursor;    /* address of cursor */ +    const char *lastchar;  /* address of last character */ +} LineInfo; +.Ed +.It Fn el_insertstr +Insert +.Fa str +into the line at the cursor. +Returns -1 if +.Fa str +is empty or won't fit, and 0 otherwise. +.It Fn el_deletestr +Delete +.Fa num +characters before the cursor. +.El +.Sh HISTORY LIST FUNCTIONS +The history functions use a common data structure, +.Fa History , +which is created by +.Fn history_init +and freed by +.Fn history_end . +.Pp +The following functions are available: +.Bl -tag -width 4n +.It Fn history_init +Initialise the history list, and return a data structure +to be used by all other history list functions. +.It Fn history_end +Clean up and finish with +.Fa h , +assumed to have been created with +.Fn history_init . +.It Fn history +Perform operation +.Fa op +on the history list, with optional arguments as needed by the +operation. +The following values for +.Fa op +are supported, along with the required argument list: +.Bl -tag -width 4n +.It Dv H_EVENT , Fa "int size" +Set size of history to +.Fa size +elements. +.It Dv H_END +Cleans up and finishes with +.Fa h , +assumed to be created with +.Fn history_init . +.It Dv H_CLEAR +Clear the history. +.It Dv H_FUNC , Xo +.Fa "void *ptr" , +.Fa "history_gfun_t first" , +.Fa "history_gfun_t next" , +.Fa "history_gfun_t last" , +.Fa "history_gfun_t prev" , +.Fa "history_gfun_t curr" , +.Fa "history_vfun_t clear" , +.Fa "history_efun_t enter" , +.Fa "history_efun_t add" +.Xc +Define functions to perform various history operations. +.Fa ptr +is the argument given to a function when it's invoked. +.It Dv H_FIRST +Return the first element in the history. +.It Dv H_LAST +Return the last element in the history. +.It Dv H_PREV +Return the previous element in the history. +.It Dv H_NEXT +Return the next element in the history. +.It Dv H_CURR +Return the current element in the history. +.It Dv H_ADD , Fa "const char *str" +Append +.Fa str +to the current element of the history, or create an element with +.Dv H_ENTER +if there isn't one. +.It Dv H_ENTER , Fa "const char *str" +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. +.It Dv H_PREV_STR , Fa "const char *str" +Return the closest previous event that starts with +.Fa str . +.It Dv H_NEXT_STR , Fa "const char *str" +Return the closest next event that starts with +.Fa str . +.It Dv H_PREV_EVENT , Fa "int e" +Return the previous event numbered +.Fa e . +.It Dv H_NEXT_EVENT , Fa "int e" +Return the next event numbered +.Fa e . +.It Dv H_LOAD , Fa "const char *file" +Load the history list stored in +.Fa file . +.It Dv H_SAVE , Fa "const char *file" +Save the history list to +.Fa file . +.El +.El +.\"XXX.Sh EXAMPLES +.\"XXX: provide some examples +.Sh SEE ALSO +.Xr editrc 5 , +.Xr sh 1 , +.Xr signal 3 , +.Xr termcap 3 +.Sh HISTORY +The +.Nm +library first appeared in +.Bx 4.4 . +.Sh AUTHORS +The +.Nm +library was written by Christos Zoulas, +and this manual was written by Luke Mewburn. +.Sh BUGS +This documentation is probably incomplete. +.Pp +.Fn el_parse +should not modify the supplied +.Va argv[0] . +.Pp +The tokenization functions are not publically defined in +.Fd <histedit.h> diff --git a/editrc.5 b/editrc.5 new file mode 100644 index 0000000000000..e9b2992aaf06a --- /dev/null +++ b/editrc.5 @@ -0,0 +1,292 @@ +.\"	$NetBSD: editrc.5,v 1.4 1997/04/24 20:20:31 christos Exp $ +.\" +.\" Copyright (c) 1997 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This file was contributed to The NetBSD Foundation by Luke Mewburn. +.\" +.\" 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 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. +.\" +.Dd January 11, 1997 +.Os BSD 4.4 +.Dt EDITRC 5 +.Sh NAME +.Nm editrc +.Nd configuration file for editline library +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +The +.Nm +file defines various settings to be used by the +.Xr editline 3 +library. +.Pp +The format of each line is either: +.Dl prog:command [arg [...]] +or +.Dl command [arg [...]] +.Pp +.Ar command +is one of the +.Xr editline 3 +builtin commands. +Refer to +.Sx BUILTIN COMMANDS +for more information. +.Pp +.Ar prog  +is the program name string that a program defines when it calls +.Xr el_init 3 +to setup +.Xr editline 3 , +which is usually +.Va argv[0] . +.Ar command +will be executed for any program which matches +.Ar prog . +.Pp +.Ar prog +may also be a +.Xr regex 3 +style +regular expression, in which case +.Ar command +will be executed for any program that matches the regular expression. +.Sh BUILTIN COMMANDS +The +.Nm editline +library has some builtin commands, which affect the way +that the line editing and history functions operate. +These are based on similar named builtins present in the +.Xr tcsh 1 +shell. +.Pp +The following builtin commands are available: +.Bl -tag -width 4n +.It Ic bind Xo +.Op Fl a +.Op Fl e +.Op Fl k +.Op Fl l +.Op Fl r +.Op Fl s +.Op Fl v +.Op Ar key Op Ar command +.Xc +Without options, list all bound keys, and the editor command to which +each is bound. +If +.Ar key +is supplied, show the bindings for +.Ar key . +If +.Ar key command +is supplied, bind +.Ar command +to +.Ar key . +Options include: +.Bl -tag -width 4n +.It Fl e +Bind all keys to the standard GNU Emacs-like bindings. +.It Fl v +Bind all keys to the standard  +.Xr vi 1 -like +bindings. +.It Fl a +List or change key bindings in the  +.Xr vi 1 +mode alternate (command mode) key map. +.It Fl k +.Ar key +is interpreted as a symbolic arrow key name, which may be one of +.Sq up , +.Sq down , +.Sq left +or +.Sq right . +.It Fl l +List all editor commands and a short description of each. +.It Fl r +Remove a key's binding. +.It Fl s +.Ar command +is taken as a literal string and treated as terminal input when +.Ar key +is typed. +Bound keys in +.Ar command +are themselves reinterpreted, and this continues for ten levels of +interpretation. +.El +.Pp +.Ar key +and +.Ar command +can contain control characters of the form +.Sm off +.Sq No ^ Ar character +.Sm on +.Po +e.g. +.Sq ^A +.Pc , +and the following backslashed escape sequences: +.Pp +.Bl -tag -compact -offset indent -width 4n +.It Ic \ea +Bell +.It Ic \eb +Backspace +.It Ic \ee +Escape +.It Ic \ef +Formfeed +.It Ic \en +Newline +.It Ic \er +Carriage return +.It Ic \et +Horizontal tab +.It Ic \ev +Vertical tab +.Sm off +.It Sy \e Ar nnn +.Sm on +The ASCII character corresponding to the octal number +.Ar nnn . +.El +.Pp +.Sq \e +nullifies the special meaning of the following character, +if it has any, notably +.Sq \e +and +.Sq ^ . +.It Ic echotc Xo +.Op Fl sv +.Ar arg +.Ar ... +.Xc +Exercise terminal capabilities given in +.Ar arg Ar ... . +If +.Ar arg +is +.Sq baud , +.Sq cols , +.Sq lines , +.Sq rows , +.Sq meta or +.Sq tabs , +the value of that capability is printed, with +.Dq yes +or +.Dq no +indicating that the terminal does or does not have that capability. +.Pp +.Fl s +returns an emptry string for non-existant capabilities, rather than +causing an error. +.Fl v +causes messages to be verbose. +.It Ic history +List the history. +.It Ic telltc +List the values of all the terminal capabilities (see +.Xr termcap 5 ). +.It Ic settc Ar cap Ar val +Set the terminal capability +.Ar cap +to +.Ar val , +as defined in +.Xr termcap 5 . +No sanity checking is done. +.It Ic setty Xo +.Op Fl a +.Op Fl d +.Op Fl q +.Op Fl x +.Op Ar +mode +.Op Ar -mode +.Op Ar mode +.Xc +Control which tty modes that +.Nm +won't allow the user to change. +.Fl d , +.Fl q +or +.Fl x +tells +.Ic setty +to act on the +.Sq edit , +.Sq quote +or +.Sq execute +set of tty modes respectively; defaulting to +.Fl x . +.Pp +Without other arguments, +.Ic setty +lists the modes in the chosen set which are fixed on +.Po +.Sq +mode +.Pc +or off +.Po +.Sq -mode +.Pc . +.Fl a +lists all tty modes in the chosen set regardless of the setting. +With +.Ar +mode , +.Ar -mode +or +.Ar mode , +fixes +.Ar mode +on or off or removes control of +.Ar mode +in the chosen set. +.El +.Sh SEE ALSO +.Xr editline 3 , +.Xr regex 3 , +.Xr termcap 5 +.Sh AUTHORS +The +.Nm editline +library was written by Christos Zoulas, +and this manual was written by Luke Mewburn, +with some sections inspired by +.Xr tcsh 1 . diff --git a/el.c b/el.c new file mode 100644 index 0000000000000..47b302586fba0 --- /dev/null +++ b/el.c @@ -0,0 +1,343 @@ +/*	$NetBSD: el.c,v 1.6 1997/04/24 18:54:16 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)el.c	8.2 (Berkeley) 1/3/94"; +#else +static char rcsid[] = "$NetBSD: el.c,v 1.6 1997/04/24 18:54:16 christos Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * el.c: EditLine interface functions + */ +#include "sys.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <string.h> +#include <stdlib.h> +#ifdef __STDC__ +# include <stdarg.h> +#else +# include <varargs.h> +#endif +#include "el.h" + +/* el_init(): + *	Initialize editline and set default parameters. + */ +public EditLine * +el_init(prog, fin, fout) +    const char *prog; +    FILE *fin, *fout; +{ +    EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); +#ifdef DEBUG +    char *tty; +#endif + +    if (el == NULL) +	return NULL; + +    memset(el, 0, sizeof(EditLine)); + +    el->el_infd  = fileno(fin); +    el->el_outfile = fout; +    el->el_prog = strdup(prog); + +#ifdef DEBUG +    if ((tty = getenv("DEBUGTTY")) != NULL) { +	el->el_errfile = fopen(tty, "w"); +	if (el->el_errfile == NULL) { +		extern errno; +		(void) fprintf(stderr, "Cannot open %s (%s).\n", +			       tty, strerror(errno)); +		return NULL; +	} +    } +    else  +#endif +	el->el_errfile = stderr; + +    /* +     * Initialize all the modules. Order is important!!! +     */ +    (void) term_init(el); +    (void) tty_init(el); +    (void) key_init(el); +    (void) map_init(el); +    (void) ch_init(el); +    (void) search_init(el); +    (void) hist_init(el); +    (void) prompt_init(el); +    (void) sig_init(el); +    el->el_flags = 0; + +    return el; +} /* end el_init */ + + +/* el_end(): + *	Clean up. + */ +public void +el_end(el) +    EditLine *el; +{ +    if (el == NULL) +	return; + +    el_reset(el); + +    term_end(el); +    tty_end(el); +    key_end(el); +    map_end(el); +    ch_end(el); +    search_end(el); +    hist_end(el); +    prompt_end(el); +    sig_end(el); + +    el_free((ptr_t) el->el_prog); +    el_free((ptr_t) el); +} /* end el_end */  + + +/* el_reset(): + *	Reset the tty and the parser + */ +public void +el_reset(el) +    EditLine *el; +{ +    tty_cookedmode(el); +    ch_reset(el);	/* XXX: Do we want that? */ +} + + +/* el_set(): + *	set the editline parameters + */ +public int +#ifdef __STDC__ +el_set(EditLine *el, int op, ...) +#else +el_set(va_alist) +    va_dcl +#endif +{ +    va_list va; +    int rv; +#ifdef __STDC__ +    va_start(va, op); +#else +    EditLine *el; +    int op; + +    va_start(va); +    el = va_arg(va, EditLine *); +    op = va_arg(va, int); +#endif +     +    switch (op) { +    case EL_PROMPT: +	rv = prompt_set(el, va_arg(va, el_pfunc_t)); +	break; + +    case EL_TERMINAL: +	rv = term_set(el, va_arg(va, char *)); +	break; + +    case EL_EDITOR: +	rv = map_set_editor(el, va_arg(va, char *)); +	break; + +    case EL_SIGNAL: +	if (va_arg(va, int)) +	    el->el_flags |= HANDLE_SIGNALS; +	else +	    el->el_flags &= ~HANDLE_SIGNALS; +	rv = 0; +	break; + +    case EL_BIND: +    case EL_TELLTC: +    case EL_SETTC: +    case EL_ECHOTC: +    case EL_SETTY: +	{ +	    char *argv[20]; +	    int i; +	    for (i = 1; i < 20; i++) +		if ((argv[i] = va_arg(va, char *)) == NULL) +		     break; + +	    switch (op) { +	    case EL_BIND: +		argv[0] = "bind"; +		rv = map_bind(el, i, argv); +		break; + +	    case EL_TELLTC: +		argv[0] = "telltc"; +		rv = term_telltc(el, i, argv); +		break; + +	    case EL_SETTC: +		argv[0] = "settc"; +		rv = term_settc(el, i, argv); +		break; + +	    case EL_ECHOTC: +		argv[0] = "echotc"; +		rv = term_echotc(el, i, argv); +		break; + +	    case EL_SETTY: +		argv[0] = "setty"; +		rv = tty_stty(el, i, argv); +		break; + +	    default: +		rv = -1; +		abort(); +		break; +	    } +	} +	break; +     +    case EL_ADDFN: +	{ +	    char 	*name = va_arg(va, char *); +	    char 	*help = va_arg(va, char *); +	    el_func_t    func = va_arg(va, el_func_t); +	    rv = map_addfunc(el, name, help, func); +	} +	break; + +    case EL_HIST: +	{ +	    hist_fun_t func = va_arg(va, hist_fun_t); +	    ptr_t      ptr = va_arg(va, char *); +	    rv = hist_set(el, func, ptr); +	} +	break; + +    default: +	rv = -1; +    } + +    va_end(va); +    return rv; +} /* end el_set */ + + +/* el_line(): + *	Return editing info + */ +public const LineInfo * +el_line(el) +    EditLine *el; +{ +    return (const LineInfo *) &el->el_line; +} + +static const char elpath[] = "/.editrc"; + +/* el_source(): + *	Source a file + */ +public int +el_source(el, fname) +    EditLine *el; +    const char *fname; +{ +    FILE *fp; +    size_t len; +    char *ptr, path[MAXPATHLEN]; + +    if (fname == NULL) { +	fname = &elpath[1]; +	if ((fp = fopen(fname, "r")) == NULL) { +	    if ((ptr = getenv("HOME")) == NULL)  +		return -1; +	    (void)snprintf(path, sizeof(path), "%s%s", ptr, elpath); +	    fname = path; +	} +    } + +    if ((fp = fopen(fname, "r")) == NULL)  +	return -1; + +    while ((ptr = fgetln(fp, &len)) != NULL) { +	if (ptr[len - 1] == '\n') +	    --len; +	ptr[len] = '\0'; +	if (parse_line(el, ptr) == -1) { +	    (void) fclose(fp); +	    return -1; +	} +    } + +    (void) fclose(fp); +    return 0; +} + + +/* el_resize(): + *	Called from program when terminal is resized + */ +public void +el_resize(el) +    EditLine *el; +{ +    int lins, cols; +    sigset_t oset, nset; +    (void) sigemptyset(&nset); +    (void) sigaddset(&nset, SIGWINCH); +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    /* get the correct window size */ +    if (term_get_size(el, &lins, &cols)) +	term_change_size(el, lins, cols); + +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +} diff --git a/el.h b/el.h new file mode 100644 index 0000000000000..ec3d53845b18e --- /dev/null +++ b/el.h @@ -0,0 +1,131 @@ +/*	$NetBSD: el.h,v 1.2 1997/01/11 06:47:53 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. + * + *	@(#)el.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.h: Internal structures. + */ +#ifndef _h_el +#define _h_el +/* + * Local defaults + */ +#define KSHVI +#define VIDEFAULT +#define ANCHOR + +#include <stdio.h> +#include <sys/types.h> + +#define EL_BUFSIZ	1024		/* Maximum line size		*/ + +#define HANDLE_SIGNALS	1 + +typedef int bool_t;			/* True or not			*/ + +typedef unsigned char el_action_t;	/* Index to command array	*/ + +typedef struct coord_t {		/* Position on the screen	*/ +    int h, v; +} coord_t; + +typedef struct el_line_t { +    char *buffer, 			/* Input line 			*/ +	 *cursor, 			/* Cursor position 		*/ +	 *lastchar,			/* Last character 		*/ +	 *limit;			/* Max position			*/ +} el_line_t; + +/* + * Editor state + */ +typedef struct el_state_t { +    int 	inputmode;		/* What mode are we in? 	*/ +    int 	doingarg;		/* Are we getting an argument?	*/ +    int	        argument;		/* Numeric argument 		*/ +    int		metanext;		/* Is the next char a meta char */ +    el_action_t lastcmd;		/* Previous command		*/ +} el_state_t; + +/* + * Until we come up with something better... + */ +#define el_malloc(a)	malloc(a) +#define el_realloc(a,b)	realloc(a, b) +#define el_free(a)	free(a) + +#include "tty.h" +#include "prompt.h" +#include "key.h" +#include "term.h" +#include "refresh.h" +#include "chared.h" +#include "common.h" +#include "search.h" +#include "hist.h" +#include "map.h" +#include "parse.h" +#include "sig.h" +#include "help.h" + +struct editline { +    char	 *el_prog;	/* the program name 			*/ +    FILE         *el_outfile;	/* Stdio stuff				*/ +    FILE         *el_errfile;	/* Stdio stuff				*/ +    int           el_infd;	/* Input file descriptor		*/ +    int		  el_flags;	/* Various flags.			*/ +    coord_t       el_cursor;	/* Cursor location			*/ +    char        **el_display, 	/* Real screen image = what is there	*/ +	        **el_vdisplay;	/* Virtual screen image = what we see	*/ + +    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		*/ +    el_tty_t	  el_tty;	/* Tty dependent stuff			*/ +    el_refresh_t  el_refresh;	/* Refresh stuff			*/ +    el_prompt_t   el_prompt;	/* Prompt stuff				*/ +    el_chared_t	  el_chared;	/* Characted editor stuff		*/ +    el_map_t	  el_map;	/* Key mapping stuff			*/ +    el_key_t	  el_key;	/* Key binding stuff			*/ +    el_history_t  el_history;	/* History stuff			*/ +    el_search_t	  el_search;	/* Search stuff				*/ +    el_signal_t	  el_signal;	/* Signal handling stuff		*/ +}; + +#endif /* _h_el */ diff --git a/emacs.c b/emacs.c new file mode 100644 index 0000000000000..a1f84c298d063 --- /dev/null +++ b/emacs.c @@ -0,0 +1,510 @@ +/*	$NetBSD: emacs.c,v 1.3 1997/01/11 06:47:54 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)emacs.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: emacs.c,v 1.3 1997/01/11 06:47:54 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/*  + * emacs.c: Emacs functions + */ +#include "sys.h" +#include "el.h" + +/* em_delete_or_list(): + *	Delete character under cursor or list completions if at end of line + *	[^D] + */ +protected el_action_t +/*ARGSUSED*/ +em_delete_or_list(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor == el->el_line.lastchar) {	/* if I'm at the end */ +	if (el->el_line.cursor == el->el_line.buffer) {	/* and the beginning */ +	    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 { +	c_delafter(el, el->el_state.argument);	/* delete after dot */ +	if (el->el_line.cursor > el->el_line.lastchar) +	    el->el_line.cursor = el->el_line.lastchar;	/* bounds check */ +	return CC_REFRESH; +    } +} + + +/* em_delete_next_word(): + *	Cut from cursor to end of current word + *	[M-d] + */ +protected el_action_t +/*ARGSUSED*/ +em_delete_next_word(el, c) +    EditLine *el; +    int c; +{ +    char *cp, *p, *kp; + +    if (el->el_line.cursor == el->el_line.lastchar) +	return CC_ERROR; + +    cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,  +		      el->el_state.argument, ce__isword); + +    for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++) +	/* save the text */ +	*kp++ = *p; +    el->el_chared.c_kill.last = kp; + +    c_delafter(el, cp - el->el_line.cursor);		/* delete after dot */ +    if (el->el_line.cursor > el->el_line.lastchar) +	el->el_line.cursor = el->el_line.lastchar;	/* bounds check */ +    return CC_REFRESH; +} + + +/* em_yank(): + *	Paste cut buffer at cursor position + *	[^Y] + */ +protected el_action_t +/*ARGSUSED*/ +em_yank(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) +	return CC_ERROR; + +    if (el->el_line.lastchar +  +	(el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=  +	el->el_line.limit) +	return CC_ERROR; + +    el->el_chared.c_kill.mark = el->el_line.cursor; +    cp = el->el_line.cursor; + +    /* open the space, */ +    c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);	 +    /* copy the chars */ +    for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)	 +	*cp++ = *kp; + +    /* if an arg, cursor at beginning else cursor at end */ +    if (el->el_state.argument == 1)		 +	el->el_line.cursor = cp; + +    return CC_REFRESH; +} + + +/* em_kill_line(): + *	Cut the entire line and save in cut buffer + *	[^U] + */ +protected el_action_t +/*ARGSUSED*/ +em_kill_line(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    cp = el->el_line.buffer; +    kp = el->el_chared.c_kill.buf; +    while (cp < el->el_line.lastchar) +	*kp++ = *cp++;		/* copy it */ +    el->el_chared.c_kill.last = kp; +    el->el_line.lastchar = el->el_line.buffer;	/* zap! -- delete all of it */ +    el->el_line.cursor = el->el_line.buffer; +    return CC_REFRESH; +} + + +/* em_kill_region(): + *	Cut area between mark and cursor and save in cut buffer + *	[^W] + */ +protected el_action_t +/*ARGSUSED*/ +em_kill_region(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    if (!el->el_chared.c_kill.mark) +	return CC_ERROR; + +    if (el->el_chared.c_kill.mark > el->el_line.cursor) { +	cp = el->el_line.cursor; +	kp = el->el_chared.c_kill.buf; +	while (cp < el->el_chared.c_kill.mark) +	    *kp++ = *cp++;	/* copy it */ +	el->el_chared.c_kill.last = kp; +	c_delafter(el, cp - el->el_line.cursor); +    } +    else {			/* mark is before cursor */ +	cp = el->el_chared.c_kill.mark; +	kp = el->el_chared.c_kill.buf; +	while (cp < el->el_line.cursor) +	    *kp++ = *cp++;	/* copy it */ +	el->el_chared.c_kill.last = kp; +	c_delbefore(el, cp - el->el_chared.c_kill.mark); +	el->el_line.cursor = el->el_chared.c_kill.mark; +    } +    return CC_REFRESH; +} + + +/* em_copy_region(): + *	Copy area between mark and cursor to cut buffer + *	[M-W] + */ +protected el_action_t +/*ARGSUSED*/ +em_copy_region(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    if (el->el_chared.c_kill.mark) +	return CC_ERROR; + +    if (el->el_chared.c_kill.mark > el->el_line.cursor) { +	cp = el->el_line.cursor; +	kp = el->el_chared.c_kill.buf; +	while (cp < el->el_chared.c_kill.mark) +	    *kp++ = *cp++;	/* copy it */ +	el->el_chared.c_kill.last = kp; +    } +    else { +	cp = el->el_chared.c_kill.mark; +	kp = el->el_chared.c_kill.buf; +	while (cp < el->el_line.cursor) +	    *kp++ = *cp++;	/* copy it */ +	el->el_chared.c_kill.last = kp; +    } +    return CC_NORM; +} + + +/* em_gosmacs_traspose(): + *	Exchange the two characters before the cursor + *	Gosling emacs transpose chars [^T] + */ +protected el_action_t +em_gosmacs_traspose(el, c) +    EditLine *el; +    int c; +{ + +    if (el->el_line.cursor > &el->el_line.buffer[1]) { +   	/* must have at least two chars entered */ +	c = el->el_line.cursor[-2]; +	el->el_line.cursor[-2] = el->el_line.cursor[-1]; +	el->el_line.cursor[-1] = c; +	return CC_REFRESH; +    } +    else  +	return CC_ERROR; +} + + +/* em_next_word(): + *	Move next to end of current word + *	[M-f] + */ +protected el_action_t +/*ARGSUSED*/ +em_next_word(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor == el->el_line.lastchar) +	return CC_ERROR; + +    el->el_line.cursor = c__next_word(el->el_line.cursor, el->el_line.lastchar,  +				      el->el_state.argument, +				      ce__isword); + +    if (el->el_map.type == MAP_VI)  +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} + +    return CC_CURSOR; +} + +/* em_upper_case(): + *	Uppercase the characters from cursor to end of current word + *	[M-u] + */ +protected el_action_t +/*ARGSUSED*/ +em_upper_case(el, c) +    EditLine *el; +    int c; +{ +    char   *cp, *ep; + +    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,  +		      el->el_state.argument, ce__isword); + +    for (cp = el->el_line.cursor; cp < ep; cp++) +	if (islower(*cp)) +	    *cp = toupper(*cp); + +    el->el_line.cursor = ep; +    if (el->el_line.cursor > el->el_line.lastchar) +	el->el_line.cursor = el->el_line.lastchar; +    return CC_REFRESH; +} + + +/* em_capitol_case(): + *	Capitalize the characters from cursor to end of current word + *	[M-c] + */ +protected el_action_t +/*ARGSUSED*/ +em_capitol_case(el, c) +    EditLine *el; +    int c; +{ +    char   *cp, *ep; + +    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,  +		      el->el_state.argument, ce__isword); + +    for (cp = el->el_line.cursor; cp < ep; cp++) { +	if (isalpha(*cp)) { +	    if (islower(*cp)) +		*cp = toupper(*cp); +	    cp++; +	    break; +	} +    } +    for (; cp < ep; cp++) +	if (isupper(*cp)) +	    *cp = tolower(*cp); + +    el->el_line.cursor = ep; +    if (el->el_line.cursor > el->el_line.lastchar) +	el->el_line.cursor = el->el_line.lastchar; +    return CC_REFRESH; +} + +/* em_lower_case(): + *	Lowercase the characters from cursor to end of current word + *	[M-l] + */ +protected el_action_t +/*ARGSUSED*/ +em_lower_case(el, c) +    EditLine *el; +    int c; +{ +    char   *cp, *ep; + +    ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,  +		      el->el_state.argument, ce__isword); + +    for (cp = el->el_line.cursor; cp < ep; cp++) +	if (isupper(*cp)) +	    *cp = tolower(*cp); + +    el->el_line.cursor = ep; +    if (el->el_line.cursor > el->el_line.lastchar) +	el->el_line.cursor = el->el_line.lastchar; +    return CC_REFRESH; +} + + +/* em_set_mark(): + *	Set the mark at cursor + *	[^@] + */ +protected el_action_t +/*ARGSUSED*/ +em_set_mark(el, c) +    EditLine *el; +    int c; +{ +    el->el_chared.c_kill.mark = el->el_line.cursor; +    return CC_NORM; +} + + +/* em_exchange_mark(): + *	Exchange the cursor and mark  + *	[^X^X] + */ +protected el_action_t +/*ARGSUSED*/ +em_exchange_mark(el, c) +    EditLine *el; +    int c; +{ +    register char *cp; + +    cp = el->el_line.cursor; +    el->el_line.cursor = el->el_chared.c_kill.mark; +    el->el_chared.c_kill.mark = cp; +    return CC_CURSOR; +} + +/* em_universal_argument(): + *	Universal argument (argument times 4) + *	[^U] + */ +protected el_action_t +/*ARGSUSED*/ +em_universal_argument(el, c) +    EditLine *el; +    int c; +{				/* multiply current argument by 4 */ +    if (el->el_state.argument > 1000000) +	return CC_ERROR; +    el->el_state.doingarg = 1; +    el->el_state.argument *= 4; +    return CC_ARGHACK; +} + +/* em_meta_next(): + *	Add 8th bit to next character typed + *	[<ESC>] + */ +protected el_action_t +/*ARGSUSED*/ +em_meta_next(el, c) +    EditLine *el; +    int c; +{ +    el->el_state.metanext = 1;  +    return CC_ARGHACK; +} + + +/* em_toggle_overwrite(): + *	Switch from insert to overwrite mode or vice versa + */ +protected el_action_t +/*ARGSUSED*/ +em_toggle_overwrite(el, c) +    EditLine *el; +    int c; +{ +    el->el_state.inputmode =  +	(el->el_state.inputmode == MODE_INSERT) ? MODE_REPLACE : MODE_INSERT; +    return CC_NORM; +} + + +/* em_copy_prev_word(): + *	Copy current word to cursor + */ +protected el_action_t +/*ARGSUSED*/ +em_copy_prev_word(el, c) +    EditLine *el; +    int c; +{ +    char *cp, *oldc, *dp; + +    if (el->el_line.cursor == el->el_line.buffer) +	return CC_ERROR; + +    oldc = el->el_line.cursor; +    /* does a bounds check */ +    cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,  +		      el->el_state.argument, ce__isword);	 + +    c_insert(el, oldc - cp); +    for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++) +	*dp++ = *cp; + +    el->el_line.cursor = dp;		/* put cursor at end */ + +    return CC_REFRESH; +} + + +/* em_inc_search_next(): + *	Emacs incremental next search + */ +protected el_action_t +/*ARGSUSED*/ +em_inc_search_next(el, c) +    EditLine *el; +    int c; +{ +    el->el_search.patlen = 0; +    return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY); +} + + +/* em_inc_search_prev(): + *	Emacs incremental reverse search + */ +protected el_action_t +/*ARGSUSED*/ +em_inc_search_prev(el, c) +    EditLine *el; +    int c; +{ +    el->el_search.patlen = 0; +    return ce_inc_search(el, ED_SEARCH_PREV_HISTORY); +} diff --git a/hist.c b/hist.c new file mode 100644 index 0000000000000..7e46a48808d89 --- /dev/null +++ b/hist.c @@ -0,0 +1,176 @@ +/*	$NetBSD: hist.c,v 1.2 1997/01/11 06:47:55 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)hist.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: hist.c,v 1.2 1997/01/11 06:47:55 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * hist.c: History access functions + */ +#include "sys.h" +#include <stdlib.h> +#include "el.h" + +/* hist_init(): + *	Initialization function. + */ +protected int +hist_init(el) +    EditLine *el; +{ +    el->el_history.fun  = NULL; +    el->el_history.ref  = NULL; +    el->el_history.buf   = (char *) el_malloc(EL_BUFSIZ); +    el->el_history.last  = el->el_history.buf; +    return 0; +} + + +/* hist_end(): + *	clean up history; + */ +protected void +hist_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_history.buf); +    el->el_history.buf   = NULL; +} + + +/* hist_set(): + *	Set new history interface + */ +protected int +hist_set(el, fun, ptr) +    EditLine *el; +    hist_fun_t fun; +    ptr_t ptr; + +{ +    el->el_history.ref = ptr; +    el->el_history.fun = fun; +    return 0; +} + + +/* hist_get(): + *	Get a history line and update it in the buffer. + *	eventno tells us the event to get. + */ +protected el_action_t +hist_get(el) +    EditLine *el; +{ +    const char    *hp; +    int     h; + +    if (el->el_history.eventno == 0) {	/* if really the current line */ +	(void) strncpy(el->el_line.buffer, el->el_history.buf, EL_BUFSIZ); +	el->el_line.lastchar = el->el_line.buffer +  +		(el->el_history.last - el->el_history.buf); + +#ifdef KSHVI +    if (el->el_map.type == MAP_VI) +	el->el_line.cursor = el->el_line.buffer; +    else +#endif /* KSHVI */ +	el->el_line.cursor = el->el_line.lastchar; + +	return CC_REFRESH; +    } + +    if (el->el_history.ref == NULL) +	return CC_ERROR; + +    hp = HIST_FIRST(el); + +    if (hp == NULL) +	return CC_ERROR; + +    for (h = 1; h < el->el_history.eventno; h++) +	if ((hp = HIST_NEXT(el)) == NULL) { +	    el->el_history.eventno = h; +	    return CC_ERROR; +	} + +    (void) strncpy(el->el_line.buffer, hp, EL_BUFSIZ); +    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; +    } + +#ifdef KSHVI +    if (el->el_map.type == MAP_VI) +	el->el_line.cursor = el->el_line.buffer; +    else +#endif /* KSHVI */ +	el->el_line.cursor = el->el_line.lastchar; + +    return CC_REFRESH; +} + +/* hist_list() + *	List history entries + */ +protected int +/*ARGSUSED*/ +hist_list(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    const char *str; + +    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; +} diff --git a/hist.h b/hist.h new file mode 100644 index 0000000000000..af6d649147423 --- /dev/null +++ b/hist.h @@ -0,0 +1,79 @@ +/*	$NetBSD: hist.h,v 1.3 1997/01/11 06:47:56 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. + * + *	@(#)hist.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.hist.c: History functions + */ +#ifndef _h_el_hist +#define _h_el_hist + +#include "histedit.h" + +typedef const HistEvent *	(*hist_fun_t) __P((ptr_t, int, ...)); + +typedef struct el_history_t { +    char *buf;				/* The history buffer		*/ +    char *last;				/* The last character		*/ +    int eventno;			/* Event we are looking for	*/ +    ptr_t ref;				/* Argument for history fcns	*/ +    hist_fun_t fun;			/* Event access			*/ +    const HistEvent *ev;		/* Event cookie			*/ +} el_history_t; + +#define HIST_FUN(el, fn, arg)	\ +    ((((el)->el_history.ev = \ +       (*(el)->el_history.fun)((el)->el_history.ref, fn, arg)) == NULL) ? \ +     NULL : (el)->el_history.ev->str) + +#define	HIST_NEXT(el)		HIST_FUN(el, H_NEXT, NULL) +#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_LOAD(el, fname)	HIST_FUN(el, H_LOAD fname) +#define	HIST_SAVE(el, fname)	HIST_FUN(el, H_SAVE fname) + +protected int 		hist_init	__P((EditLine *)); +protected void 		hist_end	__P((EditLine *)); +protected el_action_t	hist_get	__P((EditLine *)); +protected int		hist_set	__P((EditLine *, hist_fun_t, ptr_t)); +protected int		hist_list	__P((EditLine *, int, char **)); + +#endif /* _h_el_hist */ diff --git a/histedit.h b/histedit.h new file mode 100644 index 0000000000000..3e138d6953f40 --- /dev/null +++ b/histedit.h @@ -0,0 +1,178 @@ +/*	$NetBSD: histedit.h,v 1.5 1997/04/11 17:52:45 christos 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. + * + *	@(#)histedit.h	8.2 (Berkeley) 1/3/94 + */ + +/* + * histedit.h: Line editor and history interface. + */ +#ifndef _h_editline +#define _h_editline + +#include <sys/types.h> +#include <stdio.h> + +/* + * ==== Editing ==== + */ +typedef struct editline EditLine; + +/* + * For user-defined function interface + */ +typedef struct lineinfo { +    const char *buffer; +    const char *cursor; +    const char *lastchar; +} LineInfo; + + +/* + * EditLine editor function return codes. + * For user-defined function interface + */ +#define	CC_NORM		0 +#define	CC_NEWLINE	1 +#define	CC_EOF		2 +#define CC_ARGHACK	3 +#define CC_REFRESH	4 +#define	CC_CURSOR	5 +#define	CC_ERROR	6 +#define CC_FATAL	7 +#define CC_REDISPLAY	8 + +/* + * Initialization, cleanup, and resetting + */ +EditLine	*el_init	__P((const char *, FILE *, FILE *)); +void		 el_reset	__P((EditLine *)); +void		 el_end		__P((EditLine *)); + + +/* + * Get a line, a character or push a string back in the input queue + */ +const char    *el_gets	__P((EditLine *, int *)); +int		 el_getc	__P((EditLine *, char *)); +void		 el_push	__P((EditLine *, const char *)); + +/* + * High level function internals control + * Parses argc, argv array and executes builtin editline commands + */ +int		 el_parse	__P((EditLine *, int, char **));  + +/* + * Low level editline access function + */ +int 		 el_set		__P((EditLine *, int, ...)); + +/* + * el_set/el_get parameters + */ +#define EL_PROMPT	0	/* , el_pfunc_t);		*/ +#define EL_TERMINAL	1	/* , const char *);		*/ +#define EL_EDITOR	2	/* , const char *);		*/ +#define EL_SIGNAL	3	/* , int);			*/ +#define	EL_BIND		4	/* , const char *, ..., NULL);	*/ +#define	EL_TELLTC	5	/* , const char *, ..., NULL);	*/ +#define	EL_SETTC	6	/* , const char *, ..., NULL);	*/ +#define	EL_ECHOTC	7	/* , const char *, ..., NULL);	*/ +#define	EL_SETTY	8	/* , const char *, ..., NULL);	*/ +#define	EL_ADDFN	9	/* , const char *, const char *	*/ +				/* , el_func_t);		*/ +#define EL_HIST		10	/* , hist_fun_t, const char *);	*/ + +/* + * Source named file or $PWD/.editrc or $HOME/.editrc + */ +int		el_source	__P((EditLine *, const char *)); + +/* + * Must be called when the terminal changes size; If EL_SIGNAL + * is set this is done automatically otherwise it is the responsibility + * of the application + */ +void		 el_resize	__P((EditLine *)); + + +/* + * User-defined function interface. + */ +const LineInfo *el_line	__P((EditLine *)); +int   		  el_insertstr	__P((EditLine *, char *)); +void		  el_deletestr	__P((EditLine *, int)); + +/* + * ==== History ==== + */ + +typedef struct history History; + +typedef struct HistEvent { +    int 	  num; +    const char *str; +} HistEvent; + +/* + * History access functions. + */ +History *		history_init	__P((void)); +void 			history_end	__P((History *)); + +const HistEvent *	history		__P((History *, int, ...)); + +#define H_FUNC		 0	/* , UTSL		*/ +#define H_EVENT		 1	/* , const int);	*/ +#define H_FIRST		 2	/* , void);		*/ +#define H_LAST		 3	/* , void);		*/ +#define H_PREV		 4	/* , void);		*/ +#define H_NEXT		 5	/* , void);		*/ +#define H_CURR		 6	/* , void);		*/ +#define H_ADD		 7	/* , const char*);	*/ +#define H_ENTER		 8	/* , const char*);	*/ +#define H_END		 9	/* , void);		*/ +#define H_NEXT_STR	10	/* , const char*);	*/ +#define H_PREV_STR	11	/* , const char*);	*/ +#define H_NEXT_EVENT	12	/* , const int);	*/ +#define H_PREV_EVENT	13	/* , const int);	*/ +#define H_LOAD		14	/* , const char *);	*/ +#define H_SAVE		15	/* , const char *);	*/ +#define H_CLEAR		16	/* , void);		*/ + +#endif /* _h_editline */ diff --git a/history.c b/history.c new file mode 100644 index 0000000000000..fed15725c93b0 --- /dev/null +++ b/history.c @@ -0,0 +1,692 @@ +/*	$NetBSD: history.c,v 1.5 1997/04/11 17:52:46 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +static char sccsid[] = "@(#)history.c	8.1 (Berkeley) 6/4/93"; +#endif /* not lint && not SCCSID */ + +/* + * hist.c: History access functions + */ +#include "sys.h" + +#include <string.h> +#include <stdlib.h> +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +static const char hist_cookie[] = "_HiStOrY_V1_\n"; + +#include "histedit.h" + +typedef const HistEvent *	(*history_gfun_t) __P((ptr_t)); +typedef const HistEvent *	(*history_efun_t) __P((ptr_t, const char *)); +typedef void 			(*history_vfun_t) __P((ptr_t)); + +struct history { +    ptr_t	   h_ref;		/* Argument for history fcns	*/ +    history_gfun_t h_first;		/* Get the first element	*/ +    history_gfun_t h_next;		/* Get the next element		*/ +    history_gfun_t h_last;		/* Get the last element		*/ +    history_gfun_t h_prev;		/* Get the previous element	*/ +    history_gfun_t h_curr;		/* Get the current 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)  	(*(h)->h_next)((h)->h_ref) +#define	HFIRST(h) 	(*(h)->h_first)((h)->h_ref) +#define	HPREV(h)  	(*(h)->h_prev)((h)->h_ref) +#define	HLAST(h) 	(*(h)->h_last)((h)->h_ref) +#define	HCURR(h) 	(*(h)->h_curr)((h)->h_ref) +#define	HCLEAR(h) 	(*(h)->h_clear)((h)->h_ref) +#define	HENTER(h, str)	(*(h)->h_enter)((h)->h_ref, str) +#define	HADD(h, str)	(*(h)->h_add)((h)->h_ref, str) + +#define h_malloc(a)	malloc(a) +#define h_free(a)	free(a) + + +private int		 history_set_num	__P((History *, int)); +private int		 history_set_fun	__P((History *, History *)); +private int 		 history_load		__P((History *, const char *)); +private int 		 history_save		__P((History *, const char *)); +private const HistEvent *history_prev_event	__P((History *, int)); +private const HistEvent *history_next_event	__P((History *, int)); +private const HistEvent *history_next_string	__P((History *, const char *)); +private const HistEvent *history_prev_string	__P((History *, const char *)); + + +/***********************************************************************/ + +/* + * Builtin- history implementation + */ +typedef struct hentry_t { +    HistEvent ev;		/* What we return		*/ +    struct hentry_t *next;	/* Next entry			*/ +    struct hentry_t *prev;	/* Previous entry		*/ +} 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	*/ +    int	eventno;		/* Current event number		*/ +} history_t; + +private const HistEvent *history_def_first  __P((ptr_t)); +private const HistEvent *history_def_last   __P((ptr_t)); +private const HistEvent *history_def_next   __P((ptr_t)); +private const HistEvent *history_def_prev   __P((ptr_t)); +private const HistEvent *history_def_curr   __P((ptr_t)); +private const HistEvent *history_def_enter  __P((ptr_t, const char *)); +private const HistEvent *history_def_add    __P((ptr_t, const char *)); +private void             history_def_init   __P((ptr_t *, int)); +private void             history_def_clear  __P((ptr_t)); +private const HistEvent *history_def_insert __P((history_t *, const char *)); +private void             history_def_delete __P((history_t *, hentry_t *)); + +#define history_def_set(p, num)	(void) (((history_t *) p)->max = (num)) + + +/* history_def_first(): + *	Default function to return the first event in the history. + */ +private const HistEvent *  +history_def_first(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; +    h->cursor = h->list.next; +    if (h->cursor != &h->list) +	return &h->cursor->ev; +    else +	return NULL; +} + +/* history_def_last(): + *	Default function to return the last event in the history. + */ +private const HistEvent *  +history_def_last(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; +    h->cursor = h->list.prev; +    if (h->cursor != &h->list) +	return &h->cursor->ev; +    else +	return NULL; +} + +/* history_def_next(): + *	Default function to return the next event in the history. + */ +private const HistEvent *  +history_def_next(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; + +    if (h->cursor != &h->list) +	h->cursor = h->cursor->next; +    else +	return NULL; + +    if (h->cursor != &h->list) +	return &h->cursor->ev; +    else +	return NULL; +} + + +/* history_def_prev(): + *	Default function to return the previous event in the history. + */ +private const HistEvent *  +history_def_prev(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; + +    if (h->cursor != &h->list) +	h->cursor = h->cursor->prev; +    else +	return NULL; + +    if (h->cursor != &h->list) +	return &h->cursor->ev; +    else +	return NULL; +} + + +/* history_def_curr(): + *	Default function to return the current event in the history. + */ +private const HistEvent *  +history_def_curr(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; + +    if (h->cursor != &h->list) +	return &h->cursor->ev; +    else +	return NULL; +} + +/* history_def_add(): + *	Append string to element + */ +private const HistEvent * +history_def_add(p, str) +    ptr_t p; +    const char *str; +{ +    history_t *h = (history_t *) p; +    size_t len; +    char *s; + +    if (h->cursor == &h->list) +	return (history_def_enter(p, str)); +    len = strlen(h->cursor->ev.str) + strlen(str) + 1; +    s = (char *) h_malloc(len); +    (void)strcpy(s, h->cursor->ev.str);	/* XXX strcpy is safe */ +    (void)strcat(s, str);			/* XXX strcat is safe */ +    h_free((ptr_t) h->cursor->ev.str); +    h->cursor->ev.str = s; +    return &h->cursor->ev; +} + + +/* history_def_delete(): + *	Delete element hp of the h list + */ +private void +history_def_delete(h, hp) +    history_t *h; +    hentry_t *hp; +{ +    if (hp == &h->list) +	abort(); +    hp->prev->next = hp->next; +    hp->next->prev = hp->prev; +    h_free((ptr_t) hp->ev.str); +    h_free(hp); +    h->cur--; +} + + +/* history_def_insert(): + *	Insert element with string str in the h list + */ +private const HistEvent * +history_def_insert(h, str) +    history_t *h; +    const char *str; +{ +    h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); +    h->cursor->ev.str = strdup(str); +    h->cursor->next = h->list.next; +    h->cursor->prev = &h->list; +    h->list.next->prev = h->cursor; +    h->list.next = h->cursor; +    h->cur++; + +    return &h->cursor->ev; +} + + +/* history_def_enter(): + *	Default function to enter an item in the history + */ +private const HistEvent * +history_def_enter(p, str) +    ptr_t p; +    const char *str; +{ +    history_t *h = (history_t *) p; +    const HistEvent *ev; + + +    ev = history_def_insert(h, str); +    ((HistEvent*) ev)->num = ++h->eventno; + +    /* +     * Always keep at least one entry. +     * This way we don't have to check for the empty list. +     */ +    while (h->cur > h->max + 1)  +	history_def_delete(h, h->list.prev); +    return ev; +} + + +/* history_def_init(): + *	Default history initialization function + */ +private void +history_def_init(p, n) +    ptr_t *p; +    int n; +{ +    history_t *h = (history_t *) h_malloc(sizeof(history_t)); +    if (n <= 0) +	n = 0; +    h->eventno = 0; +    h->cur = 0; +    h->max = n; +    h->list.next = h->list.prev = &h->list; +    h->list.ev.str = NULL; +    h->list.ev.num = 0; +    h->cursor = &h->list; +    *p = (ptr_t) h; +} + + +/* history_def_clear(): + *	Default history cleanup function + */ +private void +history_def_clear(p) +    ptr_t p; +{ +    history_t *h = (history_t *) p; + +    while (h->list.prev != &h->list) +	history_def_delete(h, h->list.prev); +    h->eventno = 0; +    h->cur = 0; +} + + + + +/************************************************************************/ + +/* history_init(): + *	Initialization function. + */ +public History * +history_init() +{ +    History *h = (History *) h_malloc(sizeof(History)); + +    history_def_init(&h->h_ref, 0); + +    h->h_next  = history_def_next; +    h->h_first = history_def_first; +    h->h_last  = history_def_last; +    h->h_prev  = history_def_prev; +    h->h_curr  = history_def_curr; +    h->h_clear = history_def_clear; +    h->h_enter = history_def_enter; +    h->h_add   = history_def_add; + +    return h; +} + + +/* history_end(): + *	clean up history; + */ +public void +history_end(h) +    History *h; +{ +    if (h->h_next == history_def_next) +	history_def_clear(h->h_ref); +} + + + +/* history_set_num(): + *	Set history number of events + */ +private int +history_set_num(h, num) +    History *h; +    int num; +{ +    if (h->h_next != history_def_next || num < 0) +	return -1; +    history_def_set(h->h_ref, num); +    return 0; +} + + +/* history_set_fun(): + *	Set history functions + */ +private int +history_set_fun(h, nh) +    History *h, *nh; +{ +    if (nh->h_first == NULL || nh->h_next == NULL || +        nh->h_last == NULL  || nh->h_prev == NULL || nh->h_curr == NULL || +	nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || +	nh->h_ref == NULL) { +	if (h->h_next != history_def_next) { +	    history_def_init(&h->h_ref, 0); +	    h->h_first = history_def_first; +	    h->h_next  = history_def_next; +	    h->h_last  = history_def_last; +	    h->h_prev  = history_def_prev; +	    h->h_curr  = history_def_curr; +	    h->h_clear = history_def_clear; +	    h->h_enter = history_def_enter; +	    h->h_add   = history_def_add; +	} +	return -1; +    } + +    if (h->h_next == history_def_next) +	history_def_clear(h->h_ref); + +    h->h_first = nh->h_first; +    h->h_next  = nh->h_next; +    h->h_last  = nh->h_last; +    h->h_prev  = nh->h_prev; +    h->h_curr  = nh->h_curr; +    h->h_clear = nh->h_clear; +    h->h_enter = nh->h_enter; +    h->h_add   = nh->h_add; + +    return 0; +} + + +/* history_load(): + *	History load function + */ +private int +history_load(h, fname) +    History *h; +    const char *fname; +{ +    FILE *fp; +    char *line; +    size_t sz; +    int i = -1; + +    if ((fp = fopen(fname, "r")) == NULL) +	return i; + +    if ((line = fgetln(fp, &sz)) == NULL) +	goto done; + +    if (strncmp(line, hist_cookie, sz) != 0) +	goto done; +	 +    for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { +	char c = line[sz]; +	line[sz] = '\0'; +	HENTER(h, line); +	line[sz] = c; +    } + +done: +    (void) fclose(fp); +    return i; +} + + +/* history_save(): + *	History save function + */ +private int +history_save(h, fname) +    History *h; +    const char *fname; +{ +    FILE *fp; +    const HistEvent *ev; +    int i = 0; + +    if ((fp = fopen(fname, "w")) == NULL) +	return -1; + +    (void) fputs(hist_cookie, fp); +    for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++) +	(void) fprintf(fp, "%s", ev->str); +    (void) fclose(fp); +    return i; +} + + +/* history_prev_event(): + *	Find the previous event, with number given + */ +private const HistEvent * +history_prev_event(h, num) +    History *h; +    int num; +{ +    const HistEvent *ev; +    for (ev = HCURR(h); ev != NULL; ev = HPREV(h)) +	if (ev->num == num) +	    return ev; +    return NULL; +} + + +/* history_next_event(): + *	Find the next event, with number given + */ +private const HistEvent * +history_next_event(h, num) +    History *h; +    int num; +{ +    const HistEvent *ev; +    for (ev = HCURR(h); ev != NULL; ev = HNEXT(h)) +	if (ev->num == num) +	    return ev; +    return NULL; +} + + +/* history_prev_string(): + *	Find the previous event beginning with string + */ +private const HistEvent * +history_prev_string(h, str) +    History *h; +    const char* str; +{ +    const HistEvent *ev; +    size_t len = strlen(str); + +    for (ev = HCURR(h); ev != NULL; ev = HNEXT(h)) +	if (strncmp(str, ev->str, len) == 0) +	    return ev; +    return NULL; +} + + + + +/* history_next_string(): + *	Find the next event beginning with string + */ +private const HistEvent * +history_next_string(h, str) +    History *h; +    const char* str; +{ +    const HistEvent *ev; +    size_t len = strlen(str); + +    for (ev = HCURR(h); ev != NULL; ev = HPREV(h)) +	if (strncmp(str, ev->str, len) == 0) +	    return ev; +    return NULL; +} + + +/* history(): + *	User interface to history functions. + */ +const HistEvent * +#ifdef __STDC__ +history(History *h, int fun, ...) +#else +history(va_alist) +    va_dcl +#endif +{ +    va_list va; +    const HistEvent *ev = NULL; +    const char *str; +    static HistEvent sev = { 0, "" }; + +#ifdef __STDC__ +    va_start(va, fun); +#else +    History *h;  +    int fun; +    va_start(va); +    h = va_arg(va, History *); +    fun = va_arg(va, int); +#endif + +    switch (fun) { +    case H_ADD: +	str = va_arg(va, const char *); +	ev = HADD(h, str); +	break; + +    case H_ENTER: +	str = va_arg(va, const char *); +	ev = HENTER(h, str); +	break; + +    case H_FIRST: +	ev = HFIRST(h); +	break; + +    case H_NEXT: +	ev = HNEXT(h); +	break; + +    case H_LAST: +	ev = HLAST(h); +	break; + +    case H_PREV: +	ev = HPREV(h); +	break; + +    case H_CURR: +	ev = HCURR(h); +	break; + +    case H_CLEAR: +	HCLEAR(h); +	break; + +    case H_LOAD: +	sev.num = history_load(h, va_arg(va, const char *)); +	ev = &sev; +	break; + +    case H_SAVE: +	sev.num = history_save(h, va_arg(va, const char *)); +	ev = &sev; +	break; + +    case H_PREV_EVENT: +	ev = history_prev_event(h, va_arg(va, int)); +	break; + +    case H_NEXT_EVENT: +	ev = history_next_event(h, va_arg(va, int)); +	break; + +    case H_PREV_STR: +	ev = history_prev_string(h, va_arg(va, const char*)); +	break; + +    case H_NEXT_STR: +	ev = history_next_string(h, va_arg(va, const char*)); +	break; + +    case H_EVENT: +	if (history_set_num(h, va_arg(va, int)) == 0) { +	    sev.num = -1; +	    ev = &sev; +	} +	break; + +    case H_FUNC: +	{ +	    History hf; +	    hf.h_ref   = va_arg(va, ptr_t); +	    hf.h_first = va_arg(va, history_gfun_t); +	    hf.h_next  = va_arg(va, history_gfun_t); +	    hf.h_last  = va_arg(va, history_gfun_t); +	    hf.h_prev  = va_arg(va, history_gfun_t); +	    hf.h_curr  = va_arg(va, history_gfun_t); +	    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); + +	    if (history_set_fun(h, &hf) == 0) { +		sev.num = -1; +		ev = &sev; +	    } +	} +	break; + +    case H_END: +	history_end(h); +	break; + +    default: +	break; +    } +    va_end(va); +    return ev; +} diff --git a/key.c b/key.c new file mode 100644 index 0000000000000..fab5969d720f4 --- /dev/null +++ b/key.c @@ -0,0 +1,732 @@ +/*	$NetBSD: key.c,v 1.2 1997/01/11 06:47:58 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)key.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: key.c,v 1.2 1997/01/11 06:47:58 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * key.c: This module contains the procedures for maintaining + *	  the extended-key map. + * + *      An extended-key (key) is a sequence of keystrokes introduced  + *	with an sequence introducer and consisting of an arbitrary  + *	number of characters.  This module maintains a map (the el->el_key.map)  + *	to convert these extended-key sequences into input strs  + *	(XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE). + * + *      Warning: + *	  If key is a substr of some other keys, then the longer + *	  keys are lost!!  That is, if the keys "abcd" and "abcef" + *	  are in el->el_key.map, adding the key "abc" will cause the first two + *	  definitions to be lost. + * + *      Restrictions: + *      ------------- + *      1) It is not possible to have one key that is a + *	   substr of another. + */ +#include "sys.h" +#include <string.h> +#include <stdlib.h> + +#include "el.h" + +/*  + * The Nodes of the el->el_key.map.  The el->el_key.map is a linked list  + * of these node elements + */ +struct key_node_t { +    char        ch;		/* single character of key 		*/ +    int         type;		/* node type				*/ +    key_value_t val; 		/* command code or pointer to str, 	*/ +				/* if this is a leaf 			*/ +    struct key_node_t *next;	/* ptr to next char of this key 	*/ +    struct key_node_t *sibling;	/* ptr to another key with same prefix 	*/ +}; + +private	int            node_trav	__P((EditLine *, key_node_t *, char *,  +					     key_value_t *)); +private	int            node__try	__P((key_node_t *, char *,  +					     key_value_t *, int)); +private	key_node_t    *node__get	__P((int)); +private	void	       node__put	__P((key_node_t *)); +private	int	       node__delete	__P((key_node_t **, char *)); +private	int	       node_lookup 	__P((EditLine *, char *, key_node_t *, +					     int)); +private	int	       node_enum	__P((EditLine *, key_node_t *, int)); +private	int	       key__decode_char	__P((char *, int, int)); + +#define KEY_BUFSIZ	EL_BUFSIZ + + +/* key_init(): + *	Initialize the key maps + */ +protected int +key_init(el) +    EditLine *el; +{ +    el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); +    el->el_key.map = NULL; +    key_reset(el); +    return 0; +}  + + +/* key_end(): + *	Free the key maps + */ +protected void +key_end(el) +    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; +}  + + +/* key_map_cmd(): + *	Associate cmd with a key value + */ +protected key_value_t * +key_map_cmd(el, cmd) +    EditLine *el; +    int cmd; +{ +    el->el_key.val.cmd = (el_action_t) cmd; +    return &el->el_key.val; +} + + +/* key_map_str(): + *	Associate str with a key value + */ +protected key_value_t * +key_map_str(el, str) +    EditLine *el; +    char  *str; +{ +    el->el_key.val.str = str; +    return &el->el_key.val; +} + + +/* key_reset(): + *	Takes all nodes on el->el_key.map and puts them on free list.  Then + *	initializes el->el_key.map with arrow keys + *	[Always bind the ansi arrow keys?] + */ +protected void +key_reset(el) +    EditLine *el; +{ +    node__put(el->el_key.map); +    el->el_key.map = NULL; +    return; +} + + +/* key_get(): + *	Calls the recursive function with entry point el->el_key.map + *      Looks up *ch in map and then reads characters until a + *      complete match is found or a mismatch occurs. Returns the + *      type of the match found (XK_STR, XK_CMD, or XK_EXE). + *      Returns NULL in val.str and XK_STR for no match.   + *      The last character read is returned in *ch. + */ +protected int +key_get(el, ch, val) +    EditLine    *el; +    char        *ch; +    key_value_t *val; +{ +    return node_trav(el, el->el_key.map, ch, val); +} + + + +/* key_add(): + *      Adds key to the el->el_key.map and associates the value in val with it. + *      If key is already is in el->el_key.map, the new code is applied to the + *      existing key. Ntype specifies if code is a command, an + *      out str or a unix command. + */ +protected void +key_add(el, key, val, ntype) +    EditLine    *el; +    char        *key; +    key_value_t *val; +    int          ntype; +{ +    if (key[0] == '\0') { +	(void) fprintf(el->el_errfile,  +		       "key_add: Null extended-key not allowed.\n"); +	return; +    } + +    if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { +	(void) fprintf(el->el_errfile, +		       "key_add: sequence-lead-in command not allowed\n"); +	return; +    } + +    if (el->el_key.map == NULL) +	/* tree is initially empty.  Set up new node to match key[0] */ +	el->el_key.map = node__get(key[0]);	/* it is properly initialized */ + +    /* Now recurse through el->el_key.map */ +    (void) node__try(el->el_key.map, key, val, ntype);	 +    return; +} + + +/* key_clear(): + * + */ +protected void +key_clear(el, map, in) +    EditLine *el; +    el_action_t *map; +    char   *in; +{ +    if ((map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) && +	((map == el->el_map.key &&  +	  el->el_map.alt[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN) || +	 (map == el->el_map.alt &&  +	  el->el_map.key[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN))) +	(void) key_delete(el, in); +} + + +/* key_delete(): + *      Delete the key and all longer keys staring with key, if + *      they exists. + */ +protected int +key_delete(el, key) +    EditLine *el; +    char   *key; +{ +    if (key[0] == '\0') { +	(void) fprintf(el->el_errfile,  +		       "key_delete: Null extended-key not allowed.\n"); +	return -1; +    } + +    if (el->el_key.map == NULL) +	return 0; + +    (void) node__delete(&el->el_key.map, key); +    return 0; +} + + +/* key_print(): + *	Print the binding associated with key key. + *	Print entire el->el_key.map if null + */ +protected void +key_print(el, key) +    EditLine *el; +    char   *key; +{ +    /* do nothing if el->el_key.map is empty and null key specified */ +    if (el->el_key.map == NULL && *key == 0) +	return; + +    el->el_key.buf[0] =  '"'; +    if (node_lookup(el, key, el->el_key.map, 1) <= -1) +	/* key is not bound */ +	(void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n", key); +    return; +} + + +/* node_trav(): + *	recursively traverses node in tree until match or mismatch is + * 	found.  May read in more characters. + */ +private int +node_trav(el, ptr, ch, val) +    EditLine     *el; +    key_node_t   *ptr; +    char         *ch; +    key_value_t  *val; +{ +    if (ptr->ch == *ch) { +	/* match found */ +	if (ptr->next) { +	    /* key not complete so get next char */ +	    if (el_getc(el, ch) != 1) {	/* if EOF or error */ +		val->cmd = ED_END_OF_FILE; +		return XK_CMD;/* PWP: Pretend we just read an end-of-file */ +	    } +	    return node_trav(el, ptr->next, ch, val); +	} +	else { +	    *val = ptr->val; +	    if (ptr->type != XK_CMD) +		*ch = '\0'; +	    return ptr->type; +	} +    } +    else { +	/* no match found here */ +	if (ptr->sibling) { +	    /* try next sibling */ +	    return node_trav(el, ptr->sibling, ch, val); +	} +	else { +	    /* no next sibling -- mismatch */ +	    val->str = NULL; +	    return XK_STR; +	} +    } +} + + +/* node__try(): + * 	Find a node that matches *str or allocate a new one + */ +private int +node__try(ptr, str, val, ntype) +    key_node_t   *ptr; +    char         *str; +    key_value_t  *val; +    int           ntype; +{ +    if (ptr->ch != *str) { +	key_node_t *xm; + +	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) +	    if (xm->sibling->ch == *str) +		break; +	if (xm->sibling == NULL) +	    xm->sibling = node__get(*str);	/* setup new node */ +	ptr = xm->sibling; +    } + +    if (*++str == '\0') { +	/* we're there */ +	if (ptr->next != NULL) { +	    node__put(ptr->next);	/* lose longer keys with this prefix */ +	    ptr->next = NULL; +	} +	switch (ptr->type) { +	case XK_CMD: +	case XK_NOD: +	    break; +	case XK_STR: +	case XK_EXE: +	    if (ptr->val.str) +		el_free((ptr_t) ptr->val.str); +	    break; +	default: +	    abort(); +	    break; +	} + +	switch (ptr->type = ntype) { +	case XK_CMD: +	    ptr->val = *val; +	    break; +	case XK_STR: +	case XK_EXE: +	    ptr->val.str = strdup(val->str); +	    break; +	default: +	    abort(); +	    break; +	} +    } +    else { +	/* still more chars to go */ +	if (ptr->next == NULL) +	    ptr->next = node__get(*str);	/* setup new node */ +	(void) node__try(ptr->next, str, val, ntype); +    } +    return 0; +} + + +/* node__delete(): + *	Delete node that matches str + */ +private int +node__delete(inptr, str) +    key_node_t **inptr; +    char   *str; +{ +    key_node_t *ptr; +    key_node_t *prev_ptr = NULL; + +    ptr = *inptr; + +    if (ptr->ch != *str) { +	key_node_t *xm; + +	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) +	    if (xm->sibling->ch == *str) +		break; +	if (xm->sibling == NULL) +	    return 0; +	prev_ptr = xm; +	ptr = xm->sibling; +    } + +    if (*++str == '\0') { +	/* we're there */ +	if (prev_ptr == NULL) +	    *inptr = ptr->sibling; +	else +	    prev_ptr->sibling = ptr->sibling; +	ptr->sibling = NULL; +	node__put(ptr); +	return 1; +    } +    else if (ptr->next != NULL && node__delete(&ptr->next, str) == 1) { +	if (ptr->next != NULL) +	    return 0; +	if (prev_ptr == NULL) +	    *inptr = ptr->sibling; +	else +	    prev_ptr->sibling = ptr->sibling; +	ptr->sibling = NULL; +	node__put(ptr); +	return 1; +    } +    else { +	return 0; +    } +} + +/* node__put(): + *	Puts a tree of nodes onto free list using free(3). + */ +private void +node__put(ptr) +    key_node_t *ptr; +{ +    if (ptr == NULL) +	return; + +    if (ptr->next != NULL) { +	node__put(ptr->next); +	ptr->next = NULL; +    } + +    node__put(ptr->sibling); + +    switch (ptr->type) { +    case XK_CMD: +    case XK_NOD: +	break; +    case XK_EXE: +    case XK_STR: +	if (ptr->val.str != NULL) +	    el_free((ptr_t) ptr->val.str); +	break; +    default: +	abort(); +	break; +    } +    el_free((ptr_t) ptr); +} + + +/* node__get(): + *	Returns pointer to an key_node_t for ch. + */ +private key_node_t * +node__get(ch) +    int    ch; +{ +    key_node_t *ptr; + +    ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t)); +    ptr->ch = ch; +    ptr->type = XK_NOD; +    ptr->val.str = NULL; +    ptr->next = NULL; +    ptr->sibling = NULL; +    return ptr; +} + + + +/* node_lookup(): + *	look for the str starting at node ptr. + *	Print if last node + */ +private int +node_lookup(el, str, ptr, cnt) +    EditLine   *el; +    char       *str; +    key_node_t *ptr; +    int         cnt; +{ +    int     ncnt; + +    if (ptr == NULL) +	return -1;		/* cannot have null ptr */ + +    if (*str == 0) { +	/* no more chars in str.  node_enum from here. */ +	(void) node_enum(el, ptr, cnt); +	return 0; +    } +    else { +	/* If match put this char into el->el_key.buf.  Recurse */ +	if (ptr->ch == *str) { +	    /* match found */ +	    ncnt = key__decode_char(el->el_key.buf, cnt,  +				    (unsigned char) ptr->ch); +	    if (ptr->next != NULL) +		/* not yet at leaf */ +		return node_lookup(el, str + 1, ptr->next, ncnt + 1); +	    else { +		/* next node is null so key should be complete */ +		if (str[1] == 0) { +		    el->el_key.buf[ncnt + 1] = '"'; +		    el->el_key.buf[ncnt + 2] = '\0'; +		    key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); +		    return 0; +		} +		else +		    return -1;/* mismatch -- str still has chars */ +	    } +	} +	else { +	    /* no match found try sibling */ +	    if (ptr->sibling) +		return node_lookup(el, str, ptr->sibling, cnt); +	    else +		return -1; +	} +    } +} + + +/* node_enum(): + *	Traverse the node printing the characters it is bound in buffer + */ +private int +node_enum(el, ptr, cnt) +    EditLine *el; +    key_node_t *ptr; +    int     cnt; +{ +    int     ncnt; + +    if (cnt >= KEY_BUFSIZ - 5) {	/* buffer too small */ +	el->el_key.buf[++cnt] = '"'; +	el->el_key.buf[++cnt] = '\0'; +	(void) fprintf(el->el_errfile,  +		    "Some extended keys too long for internal print buffer"); +	(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf); +	return 0; +    } + +    if (ptr == NULL) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "node_enum: BUG!! Null ptr passed\n!"); +#endif +	return -1; +    } + +    /* put this char at end of str */ +    ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch); +    if (ptr->next == NULL) { +	/* print this key and function */ +	el->el_key.buf[ncnt + 1] = '"'; +	el->el_key.buf[ncnt + 2] = '\0'; +	key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); +    } +    else +	(void) node_enum(el, ptr->next, ncnt + 1); + +    /* go to sibling if there is one */ +    if (ptr->sibling) +	(void) node_enum(el, ptr->sibling, cnt); +    return 0; +} + + +/* key_kprint(): + *	Print the specified key and its associated + *	function specified by val + */ +protected void +key_kprint(el, key, val, ntype) +    EditLine      *el; +    char          *key; +    key_value_t   *val; +    int            ntype; +{ +    el_bindings_t *fp; +    char unparsbuf[EL_BUFSIZ]; +    static char *fmt = "%-15s->  %s\n"; + +    if (val != NULL) +	switch (ntype) { +	case XK_STR: +	case XK_EXE: +	    (void) fprintf(el->el_errfile, fmt, key,  +			   key__decode_str(val->str, unparsbuf,  +					      ntype == XK_STR ? "\"\"" : "[]")); +	    break; +	case XK_CMD: +	    for (fp = el->el_map.help; fp->name; fp++)  +		if (val->cmd == fp->func) { +		    (void) fprintf(el->el_errfile, fmt, key, fp->name); +		    break; +		} +#ifdef DEBUG_KEY +	    if (fp->name == NULL)  +		(void) fprintf(el->el_errfile, "BUG! Command not found.\n"); +#endif + +	    break; +	default: +	    abort(); +	    break; +	} +    else +	(void) fprintf(el->el_errfile, fmt, key, "no input"); +} + + +/* key__decode_char(): + *	Put a printable form of char in buf. + */ +private int +key__decode_char(buf, cnt, ch) +    char *buf; +    int   cnt, ch; +{ +    if (ch == 0) { +	buf[cnt++] = '^'; +	buf[cnt] = '@'; +	return cnt; +    } + +    if (iscntrl(ch)) { +	buf[cnt++] = '^'; +	if (ch == '\177') +	    buf[cnt] = '?'; +	else +	    buf[cnt] = ch | 0100; +    } +    else if (ch == '^') { +	buf[cnt++] = '\\'; +	buf[cnt] = '^'; +    } +    else if (ch == '\\') { +	buf[cnt++] = '\\'; +	buf[cnt] = '\\'; +    } +    else if (ch == ' ' || (isprint(ch) && !isspace(ch))) { +	buf[cnt] = ch; +    } +    else { +	buf[cnt++] = '\\'; +	buf[cnt++] = ((ch >> 6) & 7) + '0'; +	buf[cnt++] = ((ch >> 3) & 7) + '0'; +	buf[cnt] = (ch & 7) + '0'; +    } +    return cnt; +} + +/* key__decode_str(): + *	Make a printable version of the ey + */ +protected char * +key__decode_str(str, buf, sep) +    char   *str; +    char   *buf; +    char   *sep; +{ +    char *b, *p; + +    b = buf; +    if (sep[0] != '\0') +	*b++ = sep[0]; +    if (*str == 0) { +	*b++ = '^'; +	*b++ = '@'; +	if (sep[0] != '\0' && sep[1] != '\0') +	    *b++ = sep[1]; +	*b++ = 0; +	return buf; +    } + +    for (p = str; *p != 0; p++) { +	if (iscntrl((unsigned char) *p)) { +	    *b++ = '^'; +	    if (*p == '\177') +		*b++ = '?'; +	    else +		*b++ = *p | 0100; +	} +	else if (*p == '^' || *p == '\\') { +	    *b++ = '\\'; +	    *b++ = *p; +	} +	else if (*p == ' ' || (isprint((unsigned char) *p) &&  +			       !isspace((unsigned char) *p))) { +	    *b++ = *p; +	} +	else { +	    *b++ = '\\'; +	    *b++ = ((*p >> 6) & 7) + '0'; +	    *b++ = ((*p >> 3) & 7) + '0'; +	    *b++ = (*p & 7) + '0'; +	} +    } +    if (sep[0] != '\0' && sep[1] != '\0') +	*b++ = sep[1]; +    *b++ = 0; +    return buf;			/* should check for overflow */ +} diff --git a/key.h b/key.h new file mode 100644 index 0000000000000..c24ddc54907fc --- /dev/null +++ b/key.h @@ -0,0 +1,82 @@ +/*	$NetBSD: key.h,v 1.2 1997/01/11 06:47:59 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. + * + *	@(#)key.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.key.h: Key macro header + */ +#ifndef _h_el_key +#define _h_el_key + +typedef union key_value_t { +    el_action_t  cmd;	/* If it is a command the #	*/ +    char        *str;	/* If it is a string...		*/ +} key_value_t; + +typedef struct key_node_t key_node_t; + +typedef struct el_key_t { +    char        *buf;	/* Key print buffer		*/ +    key_node_t  *map;	/* Key map			*/ +    key_value_t  val;	/* Local conversion buffer	*/ +} el_key_t; + +#define XK_CMD	0 +#define XK_STR	1 +#define XK_NOD	2 +#define XK_EXE	3 + +protected int 		key_init	__P((EditLine *)); +protected void 		key_end		__P((EditLine *)); +protected key_value_t *	key_map_cmd	__P((EditLine *, int)); +protected key_value_t *	key_map_str	__P((EditLine *, char *)); +protected void		key_reset	__P((EditLine *)); +protected int 		key_get		__P((EditLine *, char *,  +					     key_value_t *)); +protected void		key_add		__P((EditLine *, char *, key_value_t *, +					     int)); +protected void		key_clear	__P((EditLine *, el_action_t *, +					     char *)); +protected int		key_delete	__P((EditLine *, char *)); +protected void		key_print	__P((EditLine *, char *)); +protected void	        key_kprint	__P((EditLine *, char *,  +					     key_value_t *, int)); +protected char 	       *key__decode_str	__P((char *, char *, char *)); + +#endif /* _h_el_key */ diff --git a/makelist b/makelist new file mode 100644 index 0000000000000..507364887e5cb --- /dev/null +++ b/makelist @@ -0,0 +1,185 @@ +#!/bin/sh - +#	$NetBSD: makelist,v 1.3 1997/01/11 06:48:00 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. +# +#	@(#)makelist	5.3 (Berkeley) 6/4/93 + +# makelist.sh: Automatically generate header files... + +AWK=/usr/bin/awk +USAGE="Usage: $0 -h|-e|-fc|-fh|-bc|-bh <filenames>"  + +if [ "x$1" = "x" ] +then +    echo $USAGE 1>&2 +    exit 1 +fi + +FLAG="$1" +shift + +FILES="$@" + +case $FLAG in +-h) +    set - `echo $FILES | sed -e 's/\\./_/g'` +    hdr="_h_`basename $1`" +    cat $FILES | $AWK ' +	BEGIN { +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#ifndef %s\n#define %s\n", "'$hdr'", "'$hdr'"); +	} +	/\(\):/ { +	    pr = substr($2, 1, 2); +	    if (pr == "vi" || pr == "em" || pr == "ed") { +		name = substr($2, 1, length($2) - 3); +		printf("protected el_action_t\t%-25.25s __P((EditLine *, int));\n", name); +	    } +	} +	END { +	    printf("#endif /* %s */\n", "'$hdr'"); +	}';; +-bc) +    cat $FILES | $AWK ' +	BEGIN { +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#include \"sys.h\"\n#include \"el.h\"\n"); +	    printf("private struct el_bindings_t el_func_help[] = {\n"); +	    low = "abcdefghijklmnopqrstuvwxyz_"; +	    high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; +	    for (i = 1; i <= length(low); i++) +		tr[substr(low, i, 1)] = substr(high, i, 1); +	} +	/\(\):/ { +	    pr = substr($2, 1, 2); +	    if (pr == "vi" || pr == "em" || pr == "ed") { +		name = substr($2, 1, length($2) - 3); +		uname = ""; +		fname = ""; +		for (i = 1; i <= length(name); i++) { +		    s = substr(name, i, 1); +		    uname = uname tr[s]; +		    if (s == "_") +			s = "-"; +		    fname = fname s; +		} +		      +		printf("    { %-30.30s %-30.30s\n","\"" fname "\",", uname ","); +		ok = 1;  +	    } +	} +	/^ \*/ { +	    if (ok) { +		printf("      \""); +		for (i = 2; i < NF; i++) +		    printf("%s ", $i); +		printf("%s\" },\n", $i); +		ok = 0; +	    } +	} +	END { +	    printf("    { NULL, 0, NULL }\n"); +	    printf("};\n"); +	    printf("\nprotected el_bindings_t* help__get()"); +	    printf("{ return el_func_help; }\n"); +	}';; +-bh) +    $AWK ' +	BEGIN {  +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#ifndef _h_help_c\n#define _h_help_c\n"); +	    printf("protected el_bindings_t *help__get\t__P((void));\n"); +	    printf("#endif /* _h_help_c */\n"); +	}' /dev/null;; +-fh) +    cat $FILES | $AWK '/el_action_t/ { print $3 }' | \ +    sort | tr '[a-z]' '[A-Z]' | $AWK ' +	BEGIN {  +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#ifndef _h_fcns_c\n#define _h_fcns_c\n"); +	    count = 0;  +	} +	{  +	    printf("#define\t%-30.30s\t%3d\n", $1, count++); +	} +	END { +	    printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count); + +	    printf("typedef el_action_t (*el_func_t) __P((EditLine *, int));"); +	    printf("\nprotected el_func_t* func__get __P((void));\n"); +	    printf("#endif /* _h_fcns_c */\n"); +	}';; +-fc) +    cat $FILES | $AWK '/el_action_t/ { print $3 }' | sort | $AWK ' +	BEGIN { +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#include \"sys.h\"\n#include \"el.h\"\n"); +	    printf("private el_func_t el_func[] = {"); +	    maxlen = 80; +	    needn = 1; +	    len = 0; +	} +	{ +	    clen = 25 + 2; +	    len += clen; +	    if (len >= maxlen)  +		needn = 1; +	    if (needn) { +		printf("\n    "); +		needn = 0; +		len = 4 + clen; +	    } +	    s = $1 ","; +	    printf("%-26.26s ", s); +	} +	END { +	    printf("\n};\n"); +	    printf("\nprotected el_func_t* func__get() { return el_func; }\n"); +	}';; +-e) +	echo "$FILES" | tr ' ' '\012' | $AWK ' +	BEGIN { +	    printf("/* Automatically generated file, do not edit */\n"); +	    printf("#define protected static\n"); +	    printf("#define SCCSID\n"); +	} +	{ +	    printf("#include \"%s\"\n", $1); +	}';; +*) +    echo $USAGE 1>&2 +    exit 1;; +esac diff --git a/map.c b/map.c new file mode 100644 index 0000000000000..5782dfefccf6a --- /dev/null +++ b/map.c @@ -0,0 +1,1403 @@ +/*	$NetBSD: map.c,v 1.3 1997/01/11 06:48:00 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)map.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: map.c,v 1.3 1997/01/11 06:48:00 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * map.c: Editor function definitions  + */ +#include "sys.h" +#include <stdlib.h> +#include "el.h" + +#define N_KEYS 256 + +private void map_print_key	 __P((EditLine *, el_action_t *, char *)); +private void map_print_some_keys __P((EditLine *, el_action_t *, int, int)); +private void map_print_all_keys	 __P((EditLine *)); +private void map_init_nls 	 __P((EditLine *)); +private void map_init_meta	 __P((EditLine *)); + +/* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */ + +private el_action_t  el_map_emacs[] = { +    /*   0 */	EM_SET_MARK,		/* ^@ */ +    /*   1 */	ED_MOVE_TO_BEG,		/* ^A */ +    /*   2 */	ED_PREV_CHAR,		/* ^B */ +    /*   3 */	ED_TTY_SIGINT,		/* ^C */ +    /*   4 */	EM_DELETE_OR_LIST,	/* ^D */ +    /*   5 */	ED_MOVE_TO_END,		/* ^E */ +    /*   6 */	ED_NEXT_CHAR,		/* ^F */ +    /*   7 */	ED_UNASSIGNED,		/* ^G */ +    /*   8 */	ED_DELETE_PREV_CHAR,	/* ^H */ +    /*   9 */	ED_UNASSIGNED,		/* ^I */ +    /*  10 */	ED_NEWLINE,		/* ^J */ +    /*  11 */	ED_KILL_LINE,		/* ^K */ +    /*  12 */	ED_CLEAR_SCREEN,	/* ^L */ +    /*  13 */	ED_NEWLINE,		/* ^M */ +    /*  14 */	ED_NEXT_HISTORY,	/* ^N */ +    /*  15 */	ED_TTY_FLUSH_OUTPUT,	/* ^O */ +    /*  16 */	ED_PREV_HISTORY,	/* ^P */ +    /*  17 */	ED_TTY_START_OUTPUT,	/* ^Q */ +    /*  18 */	ED_REDISPLAY,		/* ^R */ +    /*  19 */	ED_TTY_STOP_OUTPUT,	/* ^S */ +    /*  20 */	ED_TRANSPOSE_CHARS,	/* ^T */ +    /*  21 */	EM_KILL_LINE,		/* ^U */ +    /*  22 */	ED_QUOTED_INSERT,	/* ^V */ +    /*  23 */	EM_KILL_REGION,		/* ^W */ +    /*  24 */	ED_SEQUENCE_LEAD_IN,	/* ^X */ +    /*  25 */	EM_YANK,		/* ^Y */ +    /*  26 */	ED_TTY_SIGTSTP,		/* ^Z */ +    /*  27 */	EM_META_NEXT,		/* ^[ */ +    /*  28 */	ED_TTY_SIGQUIT,		/* ^\ */ +    /*  29 */	ED_TTY_DSUSP,		/* ^] */ +    /*  30 */	ED_UNASSIGNED,		/* ^^ */ +    /*  31 */	ED_UNASSIGNED,		/* ^_ */ +    /*  32 */	ED_INSERT,		/* SPACE */ +    /*  33 */	ED_INSERT,		/* ! */ +    /*  34 */	ED_INSERT,		/* " */ +    /*  35 */	ED_INSERT,		/* # */ +    /*  36 */	ED_INSERT,		/* $ */ +    /*  37 */	ED_INSERT,		/* % */ +    /*  38 */	ED_INSERT,		/* & */ +    /*  39 */	ED_INSERT,		/* ' */ +    /*  40 */	ED_INSERT,		/* ( */ +    /*  41 */	ED_INSERT,		/* ) */ +    /*  42 */	ED_INSERT,		/* * */ +    /*  43 */	ED_INSERT,		/* + */ +    /*  44 */	ED_INSERT,		/* , */ +    /*  45 */	ED_INSERT,		/* - */ +    /*  46 */	ED_INSERT,		/* . */ +    /*  47 */	ED_INSERT,		/* / */ +    /*  48 */	ED_DIGIT,		/* 0 */ +    /*  49 */	ED_DIGIT,		/* 1 */ +    /*  50 */	ED_DIGIT,		/* 2 */ +    /*  51 */	ED_DIGIT,		/* 3 */ +    /*  52 */	ED_DIGIT,		/* 4 */ +    /*  53 */	ED_DIGIT,		/* 5 */ +    /*  54 */	ED_DIGIT,		/* 6 */ +    /*  55 */	ED_DIGIT,		/* 7 */ +    /*  56 */	ED_DIGIT,		/* 8 */ +    /*  57 */	ED_DIGIT,		/* 9 */ +    /*  58 */	ED_INSERT,		/* : */ +    /*  59 */	ED_INSERT,		/* ; */ +    /*  60 */	ED_INSERT,		/* < */ +    /*  61 */	ED_INSERT,		/* = */ +    /*  62 */	ED_INSERT,		/* > */ +    /*  63 */	ED_INSERT,		/* ? */ +    /*  64 */	ED_INSERT,		/* @ */ +    /*  65 */	ED_INSERT,		/* A */ +    /*  66 */	ED_INSERT,		/* B */ +    /*  67 */	ED_INSERT,		/* C */ +    /*  68 */	ED_INSERT,		/* D */ +    /*  69 */	ED_INSERT,		/* E */ +    /*  70 */	ED_INSERT,		/* F */ +    /*  71 */	ED_INSERT,		/* G */ +    /*  72 */	ED_INSERT,		/* H */ +    /*  73 */	ED_INSERT,		/* I */ +    /*  74 */	ED_INSERT,		/* J */ +    /*  75 */	ED_INSERT,		/* K */ +    /*  76 */	ED_INSERT,		/* L */ +    /*  77 */	ED_INSERT,		/* M */ +    /*  78 */	ED_INSERT,		/* N */ +    /*  79 */	ED_INSERT,		/* O */ +    /*  80 */	ED_INSERT,		/* P */ +    /*  81 */	ED_INSERT,		/* Q */ +    /*  82 */	ED_INSERT,		/* R */ +    /*  83 */	ED_INSERT,		/* S */ +    /*  84 */	ED_INSERT,		/* T */ +    /*  85 */	ED_INSERT,		/* U */ +    /*  86 */	ED_INSERT,		/* V */ +    /*  87 */	ED_INSERT,		/* W */ +    /*  88 */	ED_INSERT,		/* X */ +    /*  89 */	ED_INSERT,		/* Y */ +    /*  90 */	ED_INSERT,		/* Z */ +    /*  91 */	ED_INSERT,		/* [ */ +    /*  92 */	ED_INSERT,		/* \ */ +    /*  93 */	ED_INSERT,		/* ] */ +    /*  94 */	ED_INSERT,		/* ^ */ +    /*  95 */	ED_INSERT,		/* _ */ +    /*  96 */	ED_INSERT,		/* ` */ +    /*  97 */	ED_INSERT,		/* a */ +    /*  98 */	ED_INSERT,		/* b */ +    /*  99 */	ED_INSERT,		/* c */ +    /* 100 */	ED_INSERT,		/* d */ +    /* 101 */	ED_INSERT,		/* e */ +    /* 102 */	ED_INSERT,		/* f */ +    /* 103 */	ED_INSERT,		/* g */ +    /* 104 */	ED_INSERT,		/* h */ +    /* 105 */	ED_INSERT,		/* i */ +    /* 106 */	ED_INSERT,		/* j */ +    /* 107 */	ED_INSERT,		/* k */ +    /* 108 */	ED_INSERT,		/* l */ +    /* 109 */	ED_INSERT,		/* m */ +    /* 110 */	ED_INSERT,		/* n */ +    /* 111 */	ED_INSERT,		/* o */ +    /* 112 */	ED_INSERT,		/* p */ +    /* 113 */	ED_INSERT,		/* q */ +    /* 114 */	ED_INSERT,		/* r */ +    /* 115 */	ED_INSERT,		/* s */ +    /* 116 */	ED_INSERT,		/* t */ +    /* 117 */	ED_INSERT,		/* u */ +    /* 118 */	ED_INSERT,		/* v */ +    /* 119 */	ED_INSERT,		/* w */ +    /* 120 */	ED_INSERT,		/* x */ +    /* 121 */	ED_INSERT,		/* y */ +    /* 122 */	ED_INSERT,		/* z */ +    /* 123 */	ED_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_DELETE_PREV_WORD,	/* M-^H */ +    /* 137 */	ED_UNASSIGNED,		/* M-^I */ +    /* 138 */	ED_UNASSIGNED,		/* M-^J */ +    /* 139 */	ED_UNASSIGNED,		/* M-^K */ +    /* 140 */	ED_CLEAR_SCREEN,		/* 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 */	EM_COPY_PREV_WORD,	/* 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_ARGUMENT_DIGIT,	/* M-0 */ +    /* 177 */	ED_ARGUMENT_DIGIT,	/* M-1 */ +    /* 178 */	ED_ARGUMENT_DIGIT,	/* M-2 */ +    /* 179 */	ED_ARGUMENT_DIGIT,	/* M-3 */ +    /* 180 */	ED_ARGUMENT_DIGIT,	/* M-4 */ +    /* 181 */	ED_ARGUMENT_DIGIT,	/* M-5 */ +    /* 182 */	ED_ARGUMENT_DIGIT,	/* M-6 */ +    /* 183 */	ED_ARGUMENT_DIGIT,	/* M-7 */ +    /* 184 */	ED_ARGUMENT_DIGIT,	/* M-8 */ +    /* 185 */	ED_ARGUMENT_DIGIT,	/* 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_PREV_WORD,		/* M-B */ +    /* 195 */	EM_CAPITOL_CASE,		/* M-C */ +    /* 196 */	EM_DELETE_NEXT_WORD,	/* M-D */ +    /* 197 */	ED_UNASSIGNED,		/* M-E */ +    /* 198 */	EM_NEXT_WORD,		/* 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 */	EM_LOWER_CASE,		/* M-L */ +    /* 205 */	ED_UNASSIGNED,		/* M-M */ +    /* 206 */	ED_SEARCH_NEXT_HISTORY,	/* M-N */ +    /* 207 */	ED_SEQUENCE_LEAD_IN,	/* M-O */ +    /* 208 */	ED_SEARCH_PREV_HISTORY,	/* M-P */ +    /* 209 */	ED_UNASSIGNED,		/* M-Q */ +    /* 210 */	ED_UNASSIGNED,		/* M-R */ +    /* 211 */	ED_UNASSIGNED,		/* M-S */ +    /* 212 */	ED_UNASSIGNED,		/* M-T */ +    /* 213 */	EM_UPPER_CASE,		/* M-U */ +    /* 214 */	ED_UNASSIGNED,		/* M-V */ +    /* 215 */	EM_COPY_REGION,		/* M-W */ +    /* 216 */	ED_COMMAND,		/* M-X */ +    /* 217 */	ED_UNASSIGNED,		/* M-Y */ +    /* 218 */	ED_UNASSIGNED,		/* M-Z */ +    /* 219 */	ED_SEQUENCE_LEAD_IN,	/* M-[ */ +    /* 220 */	ED_UNASSIGNED,		/* M-\ */ +    /* 221 */	ED_UNASSIGNED,		/* M-] */ +    /* 222 */	ED_UNASSIGNED,		/* M-^ */ +    /* 223 */	ED_UNASSIGNED,		/* M-_ */ +    /* 223 */	ED_UNASSIGNED,		/* M-` */ +    /* 224 */	ED_UNASSIGNED,		/* M-a */ +    /* 225 */	ED_PREV_WORD,		/* M-b */ +    /* 226 */	EM_CAPITOL_CASE,	/* M-c */ +    /* 227 */	EM_DELETE_NEXT_WORD,	/* M-d */ +    /* 228 */	ED_UNASSIGNED,		/* M-e */ +    /* 229 */	EM_NEXT_WORD,		/* M-f */ +    /* 230 */	ED_UNASSIGNED,		/* M-g */ +    /* 231 */	ED_UNASSIGNED,		/* M-h */ +    /* 232 */	ED_UNASSIGNED,		/* M-i */ +    /* 233 */	ED_UNASSIGNED,		/* M-j */ +    /* 234 */	ED_UNASSIGNED,		/* M-k */ +    /* 235 */	EM_LOWER_CASE,		/* M-l */ +    /* 236 */	ED_UNASSIGNED,		/* M-m */ +    /* 237 */	ED_SEARCH_NEXT_HISTORY,	/* M-n */ +    /* 238 */	ED_UNASSIGNED,		/* M-o */ +    /* 239 */	ED_SEARCH_PREV_HISTORY,	/* M-p */ +    /* 240 */	ED_UNASSIGNED,		/* M-q */ +    /* 241 */	ED_UNASSIGNED,		/* M-r */ +    /* 242 */	ED_UNASSIGNED,		/* M-s */ +    /* 243 */	ED_UNASSIGNED,		/* M-t */ +    /* 244 */	EM_UPPER_CASE,		/* M-u */ +    /* 245 */	ED_UNASSIGNED,		/* M-v */ +    /* 246 */	EM_COPY_REGION,		/* M-w */ +    /* 247 */	ED_COMMAND,		/* M-x */ +    /* 248 */	ED_UNASSIGNED,		/* M-y */ +    /* 249 */	ED_UNASSIGNED,		/* M-z */ +    /* 250 */	ED_UNASSIGNED,		/* M-{ */ +    /* 251 */	ED_UNASSIGNED,		/* M-| */ +    /* 252 */	ED_UNASSIGNED,		/* M-} */ +    /* 253 */	ED_UNASSIGNED,		/* M-~ */ +    /* 254 */	ED_DELETE_PREV_WORD		/* M-^? */ +    /* 255 */ +}; + +/* + * keymap table for vi.  Each index into above tbl; should be + * N_KEYS entries long.  Vi mode uses a sticky-extend to do command mode: + * insert mode characters are in the normal keymap, and command mode + * in the extended keymap. + */ +private el_action_t  el_map_vi_insert[] = { +#ifdef KSHVI +    /*   0 */	ED_UNASSIGNED,		/* ^@ */ +    /*   1 */	ED_INSERT,		/* ^A */ +    /*   2 */	ED_INSERT,		/* ^B */ +    /*   3 */	ED_INSERT,		/* ^C */ +    /*   4 */	VI_LIST_OR_EOF,		/* ^D */ +    /*   5 */	ED_INSERT,		/* ^E */ +    /*   6 */	ED_INSERT,		/* ^F */ +    /*   7 */	ED_INSERT,		/* ^G */ +    /*   8 */	VI_DELETE_PREV_CHAR,	/* ^H */   /* BackSpace key */ +    /*   9 */	ED_INSERT,		/* ^I */   /* Tab Key  */ +    /*  10 */	ED_NEWLINE,		/* ^J */ +    /*  11 */	ED_INSERT,		/* ^K */ +    /*  12 */	ED_INSERT,		/* ^L */ +    /*  13 */	ED_NEWLINE,		/* ^M */ +    /*  14 */	ED_INSERT,		/* ^N */ +    /*  15 */	ED_INSERT,		/* ^O */ +    /*  16 */	ED_INSERT,		/* ^P */ +    /*  17 */	ED_TTY_START_OUTPUT,	/* ^Q */ +    /*  18 */	ED_INSERT,		/* ^R */ +    /*  19 */	ED_TTY_STOP_OUTPUT,	/* ^S */ +    /*  20 */	ED_INSERT,		/* ^T */ +    /*  21 */	VI_KILL_LINE_PREV,	/* ^U */ +    /*  22 */	ED_QUOTED_INSERT,	/* ^V */ +    /*  23 */	ED_DELETE_PREV_WORD,	/* ^W */  /* Only until strt edit pos */ +    /*  24 */	ED_INSERT,		/* ^X */ +    /*  25 */	ED_INSERT,		/* ^Y */ +    /*  26 */	ED_INSERT,		/* ^Z */ +    /*  27 */	VI_COMMAND_MODE,	/* ^[ */  /* [ Esc ] key */ +    /*  28 */	ED_TTY_SIGQUIT,		/* ^\ */ +    /*  29 */	ED_INSERT,		/* ^] */ +    /*  30 */	ED_INSERT,		/* ^^ */ +    /*  31 */	ED_INSERT,		/* ^_ */ +#else /* !KSHVI */ +    /*   0 */	ED_UNASSIGNED,		/* ^@ */   /* NOTE: These mappings do */ +    /*   1 */	ED_MOVE_TO_BEG,		/* ^A */   /* NOT Correspond well to  */ +    /*   2 */	ED_PREV_CHAR,		/* ^B */   /* the KSH VI editing as-  */ +    /*   3 */	ED_TTY_SIGINT,		/* ^C */   /* signments. On the other */ +    /*   4 */	VI_LIST_OR_EOF,		/* ^D */   /* hand they are convenient*/ +    /*   5 */	ED_MOVE_TO_END,		/* ^E */   /* and many people have    */ +    /*   6 */	ED_NEXT_CHAR,		/* ^F */   /* have gotten used to them*/ +    /*   7 */	ED_UNASSIGNED,		/* ^G */ +    /*   8 */	ED_DELETE_PREV_CHAR,	/* ^H */   /* BackSpace key */ +    /*   9 */	ED_UNASSIGNED,		/* ^I */   /* Tab Key */ +    /*  10 */	ED_NEWLINE,		/* ^J */ +    /*  11 */	ED_KILL_LINE,		/* ^K */ +    /*  12 */	ED_CLEAR_SCREEN,	/* ^L */ +    /*  13 */	ED_NEWLINE,		/* ^M */ +    /*  14 */	ED_NEXT_HISTORY,	/* ^N */ +    /*  15 */	ED_TTY_FLUSH_OUTPUT,	/* ^O */ +    /*  16 */	ED_PREV_HISTORY,	/* ^P */ +    /*  17 */	ED_TTY_START_OUTPUT,	/* ^Q */ +    /*  18 */	ED_REDISPLAY,		/* ^R */ +    /*  19 */	ED_TTY_STOP_OUTPUT,	/* ^S */ +    /*  20 */	ED_TRANSPOSE_CHARS,	/* ^T */ +    /*  21 */	VI_KILL_LINE_PREV,	/* ^U */ +    /*  22 */	ED_QUOTED_INSERT,	/* ^V */ +    /*  23 */	ED_DELETE_PREV_WORD,	/* ^W */ +    /*  24 */	ED_UNASSIGNED,		/* ^X */ +    /*  25 */	ED_TTY_DSUSP,		/* ^Y */ +    /*  26 */	ED_TTY_SIGTSTP,		/* ^Z */ +    /*  27 */	VI_COMMAND_MODE,	/* ^[ */ +    /*  28 */	ED_TTY_SIGQUIT,		/* ^\ */ +    /*  29 */	ED_UNASSIGNED,		/* ^] */ +    /*  30 */	ED_UNASSIGNED,		/* ^^ */ +    /*  31 */	ED_UNASSIGNED,		/* ^_ */ +#endif  /* KSHVI */ +    /*  32 */	ED_INSERT,		/* SPACE */ +    /*  33 */	ED_INSERT,		/* ! */ +    /*  34 */	ED_INSERT,		/* " */ +    /*  35 */	ED_INSERT,		/* # */ +    /*  36 */	ED_INSERT,		/* $ */ +    /*  37 */	ED_INSERT,		/* % */ +    /*  38 */	ED_INSERT,		/* & */ +    /*  39 */	ED_INSERT,		/* ' */ +    /*  40 */	ED_INSERT,		/* ( */ +    /*  41 */	ED_INSERT,		/* ) */ +    /*  42 */	ED_INSERT,		/* * */ +    /*  43 */	ED_INSERT,		/* + */ +    /*  44 */	ED_INSERT,		/* , */ +    /*  45 */	ED_INSERT,		/* - */ +    /*  46 */	ED_INSERT,		/* . */ +    /*  47 */	ED_INSERT,		/* / */ +    /*  48 */	ED_INSERT,		/* 0 */ +    /*  49 */	ED_INSERT,		/* 1 */ +    /*  50 */	ED_INSERT,		/* 2 */ +    /*  51 */	ED_INSERT,		/* 3 */ +    /*  52 */	ED_INSERT,		/* 4 */ +    /*  53 */	ED_INSERT,		/* 5 */ +    /*  54 */	ED_INSERT,		/* 6 */ +    /*  55 */	ED_INSERT,		/* 7 */ +    /*  56 */	ED_INSERT,		/* 8 */ +    /*  57 */	ED_INSERT,		/* 9 */ +    /*  58 */	ED_INSERT,		/* : */ +    /*  59 */	ED_INSERT,		/* ; */ +    /*  60 */	ED_INSERT,		/* < */ +    /*  61 */	ED_INSERT,		/* = */ +    /*  62 */	ED_INSERT,		/* > */ +    /*  63 */	ED_INSERT,		/* ? */ +    /*  64 */	ED_INSERT,		/* @ */ +    /*  65 */	ED_INSERT,		/* A */ +    /*  66 */	ED_INSERT,		/* B */ +    /*  67 */	ED_INSERT,		/* C */ +    /*  68 */	ED_INSERT,		/* D */ +    /*  69 */	ED_INSERT,		/* E */ +    /*  70 */	ED_INSERT,		/* F */ +    /*  71 */	ED_INSERT,		/* G */ +    /*  72 */	ED_INSERT,		/* H */ +    /*  73 */	ED_INSERT,		/* I */ +    /*  74 */	ED_INSERT,		/* J */ +    /*  75 */	ED_INSERT,		/* K */ +    /*  76 */	ED_INSERT,		/* L */ +    /*  77 */	ED_INSERT,		/* M */ +    /*  78 */	ED_INSERT,		/* N */ +    /*  79 */	ED_INSERT,		/* O */ +    /*  80 */	ED_INSERT,		/* P */ +    /*  81 */	ED_INSERT,		/* Q */ +    /*  82 */	ED_INSERT,		/* R */ +    /*  83 */	ED_INSERT,		/* S */ +    /*  84 */	ED_INSERT,		/* T */ +    /*  85 */	ED_INSERT,		/* U */ +    /*  86 */	ED_INSERT,		/* V */ +    /*  87 */	ED_INSERT,		/* W */ +    /*  88 */	ED_INSERT,		/* X */ +    /*  89 */	ED_INSERT,		/* Y */ +    /*  90 */	ED_INSERT,		/* Z */ +    /*  91 */	ED_INSERT,		/* [ */ +    /*  92 */	ED_INSERT,		/* \ */ +    /*  93 */	ED_INSERT,		/* ] */ +    /*  94 */	ED_INSERT,		/* ^ */ +    /*  95 */	ED_INSERT,		/* _ */ +    /*  96 */	ED_INSERT,		/* ` */ +    /*  97 */	ED_INSERT,		/* a */ +    /*  98 */	ED_INSERT,		/* b */ +    /*  99 */	ED_INSERT,		/* c */ +    /* 100 */	ED_INSERT,		/* d */ +    /* 101 */	ED_INSERT,		/* e */ +    /* 102 */	ED_INSERT,		/* f */ +    /* 103 */	ED_INSERT,		/* g */ +    /* 104 */	ED_INSERT,		/* h */ +    /* 105 */	ED_INSERT,		/* i */ +    /* 106 */	ED_INSERT,		/* j */ +    /* 107 */	ED_INSERT,		/* k */ +    /* 108 */	ED_INSERT,		/* l */ +    /* 109 */	ED_INSERT,		/* m */ +    /* 110 */	ED_INSERT,		/* n */ +    /* 111 */	ED_INSERT,		/* o */ +    /* 112 */	ED_INSERT,		/* p */ +    /* 113 */	ED_INSERT,		/* q */ +    /* 114 */	ED_INSERT,		/* r */ +    /* 115 */	ED_INSERT,		/* s */ +    /* 116 */	ED_INSERT,		/* t */ +    /* 117 */	ED_INSERT,		/* u */ +    /* 118 */	ED_INSERT,		/* v */ +    /* 119 */	ED_INSERT,		/* w */ +    /* 120 */	ED_INSERT,		/* x */ +    /* 121 */	ED_INSERT,		/* y */ +    /* 122 */	ED_INSERT,		/* z */ +    /* 123 */	ED_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-^? */ +}; + +private el_action_t  el_map_vi_command[] = { +    /*   0 */	ED_UNASSIGNED,		/* ^@ */ +    /*   1 */	ED_MOVE_TO_BEG,		/* ^A */ +    /*   2 */	ED_UNASSIGNED,		/* ^B */ +    /*   3 */	ED_TTY_SIGINT,		/* ^C */ +    /*   4 */	ED_UNASSIGNED,		/* ^D */ +    /*   5 */	ED_MOVE_TO_END,		/* ^E */ +    /*   6 */	ED_UNASSIGNED,		/* ^F */ +    /*   7 */	ED_UNASSIGNED,		/* ^G */ +    /*   8 */	ED_PREV_CHAR,		/* ^H */ +    /*   9 */	ED_UNASSIGNED,		/* ^I */ +    /*  10 */	ED_NEWLINE,		/* ^J */ +    /*  11 */	ED_KILL_LINE,		/* ^K */ +    /*  12 */	ED_CLEAR_SCREEN,	/* ^L */ +    /*  13 */	ED_NEWLINE,		/* ^M */ +    /*  14 */	ED_NEXT_HISTORY,	/* ^N */ +    /*  15 */	ED_TTY_FLUSH_OUTPUT,	/* ^O */ +    /*  16 */	ED_PREV_HISTORY,	/* ^P */ +    /*  17 */	ED_TTY_START_OUTPUT,	/* ^Q */ +    /*  18 */	ED_REDISPLAY,		/* ^R */ +    /*  19 */	ED_TTY_STOP_OUTPUT,	/* ^S */ +    /*  20 */	ED_UNASSIGNED,		/* ^T */ +    /*  21 */	VI_KILL_LINE_PREV,	/* ^U */ +    /*  22 */	ED_UNASSIGNED,		/* ^V */ +    /*  23 */	ED_DELETE_PREV_WORD,	/* ^W */ +    /*  24 */	ED_UNASSIGNED,		/* ^X */ +    /*  25 */	ED_UNASSIGNED,		/* ^Y */ +    /*  26 */	ED_UNASSIGNED,		/* ^Z */ +    /*  27 */	EM_META_NEXT,		/* ^[ */ +    /*  28 */	ED_TTY_SIGQUIT,		/* ^\ */ +    /*  29 */	ED_UNASSIGNED,		/* ^] */ +    /*  30 */	ED_UNASSIGNED,		/* ^^ */ +    /*  31 */	ED_UNASSIGNED,		/* ^_ */ +    /*  32 */	ED_NEXT_CHAR,		/* SPACE */ +    /*  33 */	ED_UNASSIGNED,		/* ! */ +    /*  34 */	ED_UNASSIGNED,		/* " */ +    /*  35 */	ED_UNASSIGNED,		/* # */ +    /*  36 */	ED_MOVE_TO_END,		/* $ */ +    /*  37 */	ED_UNASSIGNED,		/* % */ +    /*  38 */	ED_UNASSIGNED,		/* & */ +    /*  39 */	ED_UNASSIGNED,		/* ' */ +    /*  40 */	ED_UNASSIGNED,		/* ( */ +    /*  41 */	ED_UNASSIGNED,		/* ) */ +    /*  42 */	ED_UNASSIGNED,		/* * */ +    /*  43 */	ED_NEXT_HISTORY,	/* + */ +    /*  44 */	VI_REPEAT_PREV_CHAR,	/* , */	 +    /*  45 */	ED_PREV_HISTORY,	/* - */	 +    /*  46 */	ED_UNASSIGNED,		/* . */ +    /*  47 */	VI_SEARCH_PREV,		/* / */ +    /*  48 */	VI_ZERO,		/* 0 */ +    /*  49 */	ED_ARGUMENT_DIGIT,	/* 1 */ +    /*  50 */	ED_ARGUMENT_DIGIT,	/* 2 */ +    /*  51 */	ED_ARGUMENT_DIGIT,	/* 3 */ +    /*  52 */	ED_ARGUMENT_DIGIT,	/* 4 */ +    /*  53 */	ED_ARGUMENT_DIGIT,	/* 5 */ +    /*  54 */	ED_ARGUMENT_DIGIT,	/* 6 */ +    /*  55 */	ED_ARGUMENT_DIGIT,	/* 7 */ +    /*  56 */	ED_ARGUMENT_DIGIT,	/* 8 */ +    /*  57 */	ED_ARGUMENT_DIGIT,	/* 9 */ +    /*  58 */	ED_COMMAND,		/* : */ +    /*  59 */	VI_REPEAT_NEXT_CHAR,	/* ; */ +    /*  60 */	ED_UNASSIGNED,		/* < */ +    /*  61 */	ED_UNASSIGNED,		/* = */ +    /*  62 */	ED_UNASSIGNED,		/* > */ +    /*  63 */	VI_SEARCH_NEXT,		/* ? */ +    /*  64 */	ED_UNASSIGNED,		/* @ */ +    /*  65 */	VI_ADD_AT_EOL,		/* A */ +    /*  66 */	VI_PREV_SPACE_WORD,	/* B */ +    /*  67 */	VI_CHANGE_TO_EOL,	/* C */ +    /*  68 */	ED_KILL_LINE,		/* D */ +    /*  69 */	VI_TO_END_WORD,		/* E */ +    /*  70 */	VI_PREV_CHAR,		/* F */ +    /*  71 */	ED_UNASSIGNED,		/* G */ +    /*  72 */	ED_UNASSIGNED,		/* H */ +    /*  73 */	VI_INSERT_AT_BOL,	/* I */ +    /*  74 */	ED_SEARCH_NEXT_HISTORY,	/* J */ +    /*  75 */	ED_SEARCH_PREV_HISTORY,	/* K */ +    /*  76 */	ED_UNASSIGNED,		/* L */ +    /*  77 */	ED_UNASSIGNED,		/* M */ +    /*  78 */	VI_REPEAT_SEARCH_PREV,	/* N */ +    /*  79 */	ED_SEQUENCE_LEAD_IN,	/* O */ +    /*  80 */	VI_PASTE_PREV,		/* P */ +    /*  81 */	ED_UNASSIGNED,		/* Q */ +    /*  82 */	VI_REPLACE_MODE,	/* R */ +    /*  83 */	VI_SUBSTITUTE_LINE,	/* S */ +    /*  84 */	VI_TO_PREV_CHAR,	/* T */ +    /*  85 */	ED_UNASSIGNED,		/* U */ +    /*  86 */	ED_UNASSIGNED,		/* V */ +    /*  87 */	VI_NEXT_SPACE_WORD,	/* W */ +    /*  88 */	ED_DELETE_PREV_CHAR,	/* X */ +    /*  89 */	ED_UNASSIGNED,		/* Y */ +    /*  90 */	ED_UNASSIGNED,		/* Z */ +    /*  91 */	ED_SEQUENCE_LEAD_IN,	/* [ */ +    /*  92 */	ED_UNASSIGNED,		/* \ */ +    /*  93 */	ED_UNASSIGNED,		/* ] */ +    /*  94 */	ED_MOVE_TO_BEG,		/* ^ */ +    /*  95 */	ED_UNASSIGNED,		/* _ */ +    /*  96 */	ED_UNASSIGNED,		/* ` */ +    /*  97 */	VI_ADD,			/* a */ +    /*  98 */	VI_PREV_WORD,		/* b */ +    /*  99 */	VI_CHANGE_META,		/* c */ +    /* 100 */	VI_DELETE_META,		/* d */ +    /* 101 */	VI_END_WORD,		/* e */ +    /* 102 */	VI_NEXT_CHAR,		/* f */ +    /* 103 */	ED_UNASSIGNED,		/* g */ +    /* 104 */	ED_PREV_CHAR,		/* h */ +    /* 105 */	VI_INSERT,		/* i */ +    /* 106 */	ED_NEXT_HISTORY,	/* j */ +    /* 107 */	ED_PREV_HISTORY,	/* k */ +    /* 108 */	ED_NEXT_CHAR,		/* l */ +    /* 109 */	ED_UNASSIGNED,		/* m */ +    /* 110 */	VI_REPEAT_SEARCH_NEXT,	/* n */ +    /* 111 */	ED_UNASSIGNED,		/* o */ +    /* 112 */	VI_PASTE_NEXT,		/* p */ +    /* 113 */	ED_UNASSIGNED,		/* q */ +    /* 114 */	VI_REPLACE_CHAR,	/* r */ +    /* 115 */	VI_SUBSTITUTE_CHAR,	/* s */ +    /* 116 */	VI_TO_NEXT_CHAR,	/* t */ +    /* 117 */	VI_UNDO,		/* u */ +    /* 118 */	ED_UNASSIGNED,		/* v */ +    /* 119 */	VI_NEXT_WORD,		/* w */ +    /* 120 */	ED_DELETE_NEXT_CHAR,	/* x */ +    /* 121 */	ED_UNASSIGNED,		/* y */ +    /* 122 */	ED_UNASSIGNED,		/* z */ +    /* 123 */	ED_UNASSIGNED,		/* { */ +    /* 124 */	ED_UNASSIGNED,		/* | */ +    /* 125 */	ED_UNASSIGNED,		/* } */ +    /* 126 */	VI_CHANGE_CASE,		/* ~ */ +    /* 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_SEQUENCE_LEAD_IN,	/* 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_SEQUENCE_LEAD_IN,	/* 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-^? */ +}; + + +/* map_init(): + *	Initialize and allocate the maps + */ +protected int +map_init(el) +    EditLine *el; +{ +     +    /* +     * Make sure those are correct before starting. +     */ +#ifdef MAP_DEBUG +    if (sizeof(el_map_emacs)      != N_KEYS * sizeof(el_action_t)) +	abort(); +    if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t)) +	abort(); +    if (sizeof(el_map_vi_insert)  != N_KEYS * sizeof(el_action_t)) +	abort(); +#endif + +    el->el_map.alt   = (el_action_t *) el_malloc(sizeof(el_action_t) * N_KEYS); +    el->el_map.key   = (el_action_t *) el_malloc(sizeof(el_action_t) * N_KEYS); +    el->el_map.emacs = el_map_emacs; +    el->el_map.vic   = el_map_vi_command; +    el->el_map.vii   = el_map_vi_insert; +    el->el_map.help  = (el_bindings_t *) el_malloc(sizeof(el_bindings_t) * +						   EL_NUM_FCNS); +    (void) memcpy(el->el_map.help, help__get(),  +		  sizeof(el_bindings_t) * EL_NUM_FCNS); +    el->el_map.func  = (el_func_t *) el_malloc(sizeof(el_func_t) * EL_NUM_FCNS); +    memcpy(el->el_map.func, func__get(), sizeof(el_func_t) * EL_NUM_FCNS); +    el->el_map.nfunc = EL_NUM_FCNS; + +#ifdef VIDEFAULT +    map_init_vi(el); +#else +    map_init_emacs(el); +#endif /* VIDEFAULT */ +    return 0; +} + + +/* map_end(): + *	Free the space taken by the editor maps + */ +protected void +map_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_map.alt); +    el->el_map.alt   = NULL; +    el_free((ptr_t) el->el_map.key); +    el->el_map.key   = NULL; +    el->el_map.emacs = NULL; +    el->el_map.vic   = NULL; +    el->el_map.vii   = NULL; +    el_free((ptr_t) el->el_map.help); +    el->el_map.help  = NULL; +    el_free((ptr_t) el->el_map.func); +    el->el_map.func  = NULL; +} + + +/* map_init_nls(): + *	Find all the printable keys and bind them to self insert + */ +private void +map_init_nls(el) +    EditLine *el; +{ +    int i; +    el_action_t *map = el->el_map.key; + +    for (i = 0200; i <= 0377; i++)  +	if (isprint(i))  +	    map[i] = ED_INSERT; +} + + +/* map_init_meta(): + *	Bind all the meta keys to the appropriate ESC-<key> sequence + */ +private void +map_init_meta(el) +    EditLine *el; +{ +    char    buf[3]; +    register int i; +    el_action_t *map = el->el_map.key; +    el_action_t *alt = el->el_map.alt; + +    for (i = 0; i <= 0377 && map[i] != EM_META_NEXT; i++) +	continue; + +    if (i > 0377) { +	for (i = 0; i <= 0377 && alt[i] != EM_META_NEXT; i++) +	    continue; +	if (i > 0377) { +	    i = 033; +	    if (el->el_map.type == MAP_VI) +		map = alt; +	} +	else  +	    map = alt; +    } +    buf[0] = (char) i; +    buf[2] = 0; +    for (i = 0200; i <= 0377; i++)  +	switch (map[i]) { +	case ED_INSERT: +	case ED_UNASSIGNED: +	case ED_SEQUENCE_LEAD_IN: +	    break; +	default: +	    buf[1] = i & 0177; +	    key_add(el, buf, key_map_cmd(el, (int) map[i]), XK_CMD); +	    break; +	} +    map[buf[0]] = ED_SEQUENCE_LEAD_IN; +} + + +/* map_init_vi(): + *	Initialize the vi bindings + */ +protected void +map_init_vi(el) +    EditLine *el; +{ +    register int i; +    el_action_t *key = el->el_map.key; +    el_action_t *alt = el->el_map.alt; +    el_action_t *vii = el->el_map.vii; +    el_action_t *vic = el->el_map.vic; + +    el->el_map.type = MAP_VI; +    el->el_map.current = el->el_map.key; + +    key_reset(el); + +    for (i = 0; i < N_KEYS; i++) { +	key[i] = vii[i]; +	alt[i] = vic[i]; +    } + +    map_init_meta(el); +#ifdef notyet +    if (0 /* XXX: USER has set LC_CTYPE */) +	map_init_nls(el); +#endif + +    tty_bind_char(el, 1); +    term_bind_arrow(el); +} + + +/* map_init_emacs(): + *	Initialize the emacs bindings + */ +protected void +map_init_emacs(el) +    EditLine *el; +{ +    int i; +    char    buf[3]; +    el_action_t *key   = el->el_map.key; +    el_action_t *alt   = el->el_map.alt; +    el_action_t *emacs = el->el_map.emacs; + +    el->el_map.type = MAP_EMACS; +    el->el_map.current = el->el_map.key; +    key_reset(el); + +    for (i = 0; i < N_KEYS; i++) { +	key[i] = emacs[i]; +	alt[i] = ED_UNASSIGNED; +    } + +    map_init_meta(el); +#ifdef notyet +    if (0 /* XXX: USER has set LC_CTYPE */) +	map_init_nls(el); +#endif +    map_init_nls(el); + +    buf[0] = CONTROL('X'); +    buf[1] = CONTROL('X'); +    buf[2] = 0; +    key_add(el, buf, key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); +     +    tty_bind_char(el, 1); +    term_bind_arrow(el); +} + + +/* map_set_editor(): + *	Set the editor  + */ +protected int +map_set_editor(el, editor) +    EditLine *el; +    char *editor; +{ +    if (strcmp(editor, "emacs") == 0) { +	map_init_emacs(el); +	return 0; +    } +    if (strcmp(editor, "vi") == 0) { +	map_init_vi(el); +	return 0; +    } +    return -1; +} + + +/* map_print_key(): + *	Print the function description for 1 key + */ +private void +map_print_key(el, map, in) +    EditLine *el; +    el_action_t *map; +    char *in; +{ +    char outbuf[EL_BUFSIZ]; +    el_bindings_t *bp; + +    if (in[0] == '\0' || in[1] == '\0') { +	(void) key__decode_str(in, outbuf, ""); +	for (bp = el->el_map.help; bp->name != NULL; bp++) +	    if (bp->func == map[(unsigned char) *in]) { +		(void) fprintf(el->el_outfile,  +			       "%s\t->\t%s\n", outbuf, bp->name); +		return; +	    } +    } +    else  +	key_print(el, in); +} + + +/* map_print_some_keys(): + *	Print keys from first to last + */ +private void +map_print_some_keys(el, map, first, last) +    EditLine *el; +    el_action_t *map; +    int     first, last; +{ +    el_bindings_t *bp; +    char    firstbuf[2], lastbuf[2]; +    char unparsbuf[EL_BUFSIZ], extrabuf[EL_BUFSIZ]; + +    firstbuf[0] = first; +    firstbuf[1] = 0; +    lastbuf[0] = last; +    lastbuf[1] = 0; +    if (map[first] == ED_UNASSIGNED) { +	if (first == last) +	    (void) fprintf(el->el_outfile, "%-15s->  is undefined\n", +		    key__decode_str(firstbuf, unparsbuf, STRQQ)); +	return; +    } + +    for (bp = el->el_map.help; bp->name != NULL; bp++) { +	if (bp->func == map[first]) { +	    if (first == last) { +		(void) fprintf(el->el_outfile, "%-15s->  %s\n", +			       key__decode_str(firstbuf, unparsbuf, STRQQ),  +			       bp->name); +	    } +	    else { +		(void) fprintf(el->el_outfile, "%-4s to %-7s->  %s\n", +			       key__decode_str(firstbuf, unparsbuf, STRQQ), +			       key__decode_str(lastbuf, extrabuf, STRQQ),  +			       bp->name); +	    } +	    return; +	} +    } +#ifdef MAP_DEBUG +    if (map == el->el_map.key) { +	(void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", +		       key__decode_str(firstbuf, unparsbuf, STRQQ)); +	(void) fprintf(el->el_outfile, "el->el_map.key[%d] == %d\n",  +		       first, el->el_map.key[first]); +    } +    else { +	(void) fprintf(el->el_outfile, "BUG!!! %s isn't bound to anything.\n", +		       key__decode_str(firstbuf, unparsbuf, STRQQ)); +	(void) fprintf(el->el_outfile, "el->el_map.alt[%d] == %d\n",  +		       first, el->el_map.alt[first]); +    } +#endif +    abort(); +} + + +/* map_print_all_keys(): + *	Print the function description for all keys. + */ +private void +map_print_all_keys(el) +    EditLine *el; +{ +    int     prev, i; + +    (void) fprintf(el->el_outfile, "Standard key bindings\n"); +    prev = 0; +    for (i = 0; i < N_KEYS; i++) { +	if (el->el_map.key[prev] == el->el_map.key[i]) +	    continue; +	map_print_some_keys(el, el->el_map.key, prev, i - 1); +	prev = i; +    } +    map_print_some_keys(el, el->el_map.key, prev, i - 1); + +    (void) fprintf(el->el_outfile, "Alternative key bindings\n"); +    prev = 0; +    for (i = 0; i < N_KEYS; i++) { +	if (el->el_map.alt[prev] == el->el_map.alt[i]) +	    continue; +	map_print_some_keys(el, el->el_map.alt, prev, i - 1); +	prev = i; +    } +    map_print_some_keys(el, el->el_map.alt, prev, i - 1); + +    (void) fprintf(el->el_outfile, "Multi-character bindings\n"); +    key_print(el, ""); +    (void) fprintf(el->el_outfile, "Arrow key bindings\n"); +    term_print_arrow(el, ""); +} + + +/* map_bind(): + *	Add/remove/change bindings + */ +protected int +map_bind(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    el_action_t *map; +    int     ntype, remove; +    char   *p; +    char    inbuf[EL_BUFSIZ]; +    char    outbuf[EL_BUFSIZ]; +    char   *in = NULL; +    char   *out = NULL; +    el_bindings_t *bp; +    int     cmd; +    int	    key; + +    if (argv == NULL) +	return -1; + +    map = el->el_map.key; +    ntype = XK_CMD; +    key = remove = 0; +    for (argc = 1; (p = argv[argc]) != NULL; argc++) +	if (p[0] == '-') +	    switch (p[1]) { +	    case 'a': +		map = el->el_map.alt; +		break; + +	    case 's': +		ntype = XK_STR; +		break; +#ifdef notyet +	    case 'c': +		ntype = XK_EXE; +		break; +#endif +	    case 'k': +		key = 1; +		break; + +	    case 'r': +		remove = 1; +		break; + +	    case 'v': +		map_init_vi(el); +		return 0; + +	    case 'e': +		map_init_emacs(el); +		return 0; + +	    case 'l': +		for (bp = el->el_map.help; bp->name != NULL; bp++)  +		    (void) fprintf(el->el_outfile, "%s\n\t%s\n",  +				   bp->name, bp->description); +		return 0; +	    default: +		(void) fprintf(el->el_errfile, "%s: Invalid switch `%c'.\n", +			       argv[0], p[1]); +	    } +	else +	    break; + +    if (argv[argc] == NULL) { +	map_print_all_keys(el); +	return 0; +    } + +    if (key) +	in = argv[argc++]; +    else +	if ((in = parse__string(inbuf, argv[argc++])) == NULL) { +	    (void) fprintf(el->el_errfile, "%s: Invalid \\ or ^ in instring.\n", +			   argv[0]); +	    return -1; +	} + +    if (remove) { +	if (key) { +	    (void) term_clear_arrow(el, in); +	    return -1; +	} +	if (in[1])  +	    (void) key_delete(el, in); +	else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN)  +	    (void) key_delete(el, in); +	else  +	    map[(unsigned char) *in] = ED_UNASSIGNED; +	return 0; +    } + +    if (argv[argc] == NULL) { +	if (key) +	    term_print_arrow(el, in); +	else +	    map_print_key(el, map, in); +	return 0; +    } + +#ifdef notyet +    if (argv[argc + 1] != NULL) { +	bindkey_usage(); +	return -1; +    } +#endif + +    switch (ntype) { +    case XK_STR: +    case XK_EXE: +	if ((out = parse__string(outbuf, argv[argc])) == NULL) { +	    (void) fprintf(el->el_errfile,  +			   "%s: Invalid \\ or ^ in outstring.\n", argv[0]); +	    return -1; +	} +	if (key) +	    term_set_arrow(el, in, key_map_str(el, out), ntype); +	else +	    key_add(el, in, key_map_str(el, out), ntype); +	map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; +	break; + +    case XK_CMD: +	if ((cmd = parse_cmd(el, argv[argc])) == -1) { +	    (void) fprintf(el->el_errfile,  +			   "%s: Invalid command `%s'.\n", argv[0], argv[argc]); +	    return -1; +	} +	if (key) +	    term_set_arrow(el, in, key_map_str(el, out), ntype); +	else { +	    if (in[1]) { +		key_add(el, in, key_map_cmd(el, cmd), ntype); +		map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; +	    } +	    else  { +		key_clear(el, map, in); +		map[(unsigned char) *in] = cmd; +	    } +	} +	break; + +    default: +	abort(); +	break; +    } +    return 0; +} + + +/* map_addfunc(): + *	add a user defined function + */ +protected int +map_addfunc(el, name, help, func) +    EditLine *el; +    const char *name; +    const char *help; +    el_func_t func; +{ +    int nf = el->el_map.nfunc + 2; +    if (name == NULL || help == NULL || func == NULL) +	return -1; + +    el->el_map.func = (el_func_t *)  +		el_realloc(el->el_map.func, nf * sizeof(el_func_t)); +    el->el_map.help = (el_bindings_t *) +		el_realloc(el->el_map.help, nf * sizeof(el_bindings_t)); + +    nf = el->el_map.nfunc; +    el->el_map.func[nf] = func; + +    el->el_map.help[nf].name = name; +    el->el_map.help[nf].func = nf; +    el->el_map.help[nf].description = help; +    el->el_map.help[++nf].name = NULL; +    el->el_map.nfunc++; + +    return 0; +} diff --git a/map.h b/map.h new file mode 100644 index 0000000000000..a73181b57e73a --- /dev/null +++ b/map.h @@ -0,0 +1,79 @@ +/*	$NetBSD: map.h,v 1.2 1997/01/11 06:48:01 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. + * + *	@(#)map.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.map.h:	Editor maps + */ +#ifndef _h_el_map +#define _h_el_map + +typedef struct el_bindings_t {	/* for the "bind" shell command */ +    const char   *name;		/* function name for bind command */ +    int     func;		/* function numeric value */ +    const char   *description;	/* description of function */ +} el_bindings_t; + + +typedef struct el_map_t { +    el_action_t   *alt;		/* The current alternate key map	*/ +    el_action_t   *key;		/* The current normal key map		*/ +    el_action_t   *current;	/* The keymap we are using		*/ +    el_action_t   *emacs;	/* The default emacs key map		*/ +    el_action_t   *vic;		/* The vi command mode key map		*/ +    el_action_t   *vii;		/* The vi insert mode key map		*/ +    int		   type;	/* Emacs or vi				*/ +    el_bindings_t *help;	/* The help for the editor functions	*/ +    el_func_t     *func;	/* List of available functions		*/ +    int  	   nfunc;	/* The number of functions/help items	*/ +} el_map_t; + +#define MAP_EMACS	0 +#define MAP_VI		1 + +protected int	map_bind		__P((EditLine *, int, char **)); +protected int	map_init		__P((EditLine *)); +protected void	map_end			__P((EditLine *)); +protected void	map_init_vi		__P((EditLine *)); +protected void	map_init_emacs		__P((EditLine *)); +protected int	map_set_editor		__P((EditLine *, char *)); +protected int	map_addfunc		__P((EditLine *, const char *,  +					     const char *, el_func_t)); + +#endif /* _h_el_map */ diff --git a/parse.c b/parse.c new file mode 100644 index 0000000000000..ee37c14195f5d --- /dev/null +++ b/parse.c @@ -0,0 +1,255 @@ +/*	$NetBSD: parse.c,v 1.5 1997/01/11 09:57:08 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: parse.c,v 1.5 1997/01/11 09:57:08 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * parse.c: parse an editline extended command + * + * commands are: + * + *	bind + *	echotc + *	gettc + *	history + *	settc + *	setty + */ +#include "sys.h" +#include "el.h" +#include "tokenizer.h" + +private struct { +    char *name; +    int (*func) __P((EditLine *, int, char **)); +} cmds[] = { +    {	"bind",		map_bind 	}, +    {	"echotc",	term_echotc 	}, +    {	"history",	hist_list	}, +    {	"telltc",	term_telltc 	}, +    {	"settc",	term_settc	}, +    {	"setty",	tty_stty	}, +    {	NULL,		NULL		} +}; + + +/* parse_line(): + *	Parse a line and dispatch it + */ +protected int +parse_line(el, line) +    EditLine *el; +    const char *line; +{ +    char **argv; +    int argc; +    Tokenizer *tok; + +    tok = tok_init(NULL); +    tok_line(tok, line, &argc, &argv); +    argc = el_parse(el, argc, argv); +    tok_end(tok); +    return argc; +} + +/* el_parse(): + *	Command dispatcher + */ +public int +el_parse(el, argc, argv) +    EditLine *el; +    int argc; +    char *argv[]; +{ +    char *ptr; +    int i; + +    if (argc < 1) +	return -1; +    ptr = strchr(argv[0], ':'); +    if (ptr != NULL) { +	*ptr++ = '\0'; +	if (! el_match(el->el_prog, argv[0])) +	    return 0; +    } +    else +	ptr = argv[0]; + +    for (i = 0; cmds[i].name != NULL; i++) +	if (strcmp(cmds[i].name, ptr) == 0) { +	    i = (*cmds[i].func)(el, argc, argv); +	    return -i; +	} + +    return -1; +} + + +/* parse__escape(): + *	Parse a string of the form ^<char> \<odigit> \<char> and return + *	the appropriate character or -1 if the escape is not valid + */ +protected int +parse__escape(ptr) +    const char  ** const ptr; +{ +    const char   *p; +    int   c; + +    p = *ptr; + +    if (p[1] == 0)  +	return -1; + +    if (*p == '\\') { +	p++; +	switch (*p) { +	case 'a': +	    c = '\007';		/* Bell */ +	    break; +	case 'b': +	    c = '\010';		/* Backspace */ +	    break; +	case 't': +	    c = '\011';		/* Horizontal Tab */ +	    break; +	case 'n': +	    c = '\012';		/* New Line */ +	    break; +	case 'v': +	    c = '\013';		/* Vertical Tab */ +	    break; +	case 'f': +	    c = '\014';		/* Form Feed */ +	    break; +	case 'r': +	    c = '\015';		/* Carriage Return */ +	    break; +	case 'e': +	    c = '\033';		/* Escape */ +	    break; +	case '0': +	case '1': +	case '2': +	case '3': +	case '4': +	case '5': +	case '6': +	case '7': +	    { +		int cnt, ch; + +		for (cnt = 0, c = 0; cnt < 3; cnt++) { +		    ch = *p++; +		    if (ch < '0' || ch > '7') { +			p--; +			break; +		    } +		    c = (c << 3) | (ch - '0'); +		} +		if ((c & 0xffffff00) != 0)  +		    return -1; +		--p; +	    } +	    break; +	default: +	    c = *p; +	    break; +	} +    } +    else if (*p == '^' && isalpha((unsigned char) p[1])) { +	p++; +	c = (*p == '?') ? '\177' : (*p & 0237); +    } +    else +	c = *p; +    *ptr = ++p; +    return c; +} + +/* parse__string(): + *	Parse the escapes from in and put the raw string out + */ +protected char * +parse__string(out, in) +    char *out; +    const char *in; +{ +    char *rv = out; +    int n; +    for (;;) +	switch (*in) { +	case '\0': +	    *out = '\0'; +	    return rv; + +	case '\\': +	case '^': +	    if ((n = parse__escape(&in)) == -1) +		return NULL; +	    *out++ = n; +	    break; + +	default: +	    *out++ = *in++; +	    break; +	} +} + +/* parse_cmd(): + *	Return the command number for the command string given + *	or -1 if one is not found + */ +protected int +parse_cmd(el, cmd) +    EditLine *el; +    const char *cmd; +{ +    el_bindings_t *b; + +    for (b = el->el_map.help; b->name != NULL; b++) +	if (strcmp(b->name, cmd) == 0) +	    return b->func; +    return -1; +} diff --git a/parse.h b/parse.h new file mode 100644 index 0000000000000..76fddf2e06aca --- /dev/null +++ b/parse.h @@ -0,0 +1,52 @@ +/*	$NetBSD: parse.h,v 1.2 1997/01/11 06:48:03 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. + * + *	@(#)parse.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.parse.h: Parser functions + */ +#ifndef _h_el_parse +#define _h_el_parse + +protected int		 parse_line	__P((EditLine *, const char *));  +protected int		 parse__escape	__P((const char ** const)); +protected char *	 parse__string	__P((char *, const char *)); +protected int		 parse_cmd	__P((EditLine *, const char *)); + +#endif /* _h_el_parse */ diff --git a/prompt.c b/prompt.c new file mode 100644 index 0000000000000..8999c141194ba --- /dev/null +++ b/prompt.c @@ -0,0 +1,129 @@ +/*	$NetBSD: prompt.c,v 1.2 1997/01/11 06:48:04 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)prompt.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: prompt.c,v 1.2 1997/01/11 06:48:04 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * prompt.c: Prompt printing functions + */ +#include "sys.h" +#include <stdio.h> +#include "el.h" + +private char *prompt_default	__P((EditLine *)); + +/* prompt_default(): + *	Just a default prompt, in case the user did not provide one + */ +private char * +/*ARGSUSED*/ +prompt_default(el) +    EditLine *el; +{ +    static char a[3] = { '?', ' ', '\0' }; +    return a; +} + + +/* prompt_print(): + *	Print the prompt and update the prompt position. + *	We use an array of integers in case we want to pass + * 	literal escape sequences in the prompt and we want a + *	bit to flag them + */ +protected void +prompt_print(el) +    EditLine *el; +{ +    char *p = (*el->el_prompt.p_func)(el); +    while (*p) +	re_putc(el, *p++); + +    el->el_prompt.p_pos.v = el->el_refresh.r_cursor.v; +    el->el_prompt.p_pos.h = el->el_refresh.r_cursor.h; + +} /* end prompt_print */ + + +/* prompt_init(): + *	Initialize the prompt stuff + */ +protected int  +prompt_init(el) +    EditLine *el; +{ +    el->el_prompt.p_func = prompt_default; +    el->el_prompt.p_pos.v = 0; +    el->el_prompt.p_pos.h = 0; +    return 0; +} /* end prompt_init */ + + +/* prompt_end(): + *	Clean up the prompt stuff + */ +protected void +/*ARGSUSED*/  +prompt_end(el) +    EditLine *el; +{ +} /* end prompt_end */ + + +/* prompt_set(): + *	Install a prompt printing function + */ +protected int  +prompt_set(el, prf) +    EditLine *el; +    el_pfunc_t prf; +{ +    if (prf == NULL) +	el->el_prompt.p_func = prompt_default; +    else +	el->el_prompt.p_func = prf; +    el->el_prompt.p_pos.v = 0; +    el->el_prompt.p_pos.h = 0; +    return 0; +} /* end prompt_set */ diff --git a/prompt.h b/prompt.h new file mode 100644 index 0000000000000..4734ae11b9549 --- /dev/null +++ b/prompt.h @@ -0,0 +1,61 @@ +/*	$NetBSD: prompt.h,v 1.2 1997/01/11 06:48:05 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. + * + *	@(#)prompt.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.prompt.h: Prompt printing stuff + */ +#ifndef _h_el_prompt +#define _h_el_prompt + +#include "histedit.h" + +typedef char * (*el_pfunc_t) __P((EditLine*)); + +typedef struct el_prompt_t { +    el_pfunc_t p_func;		/* Function to return the prompt	*/ +    coord_t    p_pos;		/* position in the line after prompt	*/ +} el_prompt_t; + +protected void prompt_print	__P((EditLine *)); +protected int  prompt_set	__P((EditLine *, el_pfunc_t)); +protected int  prompt_init	__P((EditLine *)); +protected void prompt_end	__P((EditLine *)); + +#endif /* _h_el_prompt */ diff --git a/read.c b/read.c new file mode 100644 index 0000000000000..46d08cc5bf418 --- /dev/null +++ b/read.c @@ -0,0 +1,452 @@ +/*	$NetBSD: read.c,v 1.4 1997/04/11 17:52:47 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)read.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: read.c,v 1.4 1997/04/11 17:52:47 christos Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * read.c: Clean this junk up! This is horrible code. + *	   Terminal read functions + */ +#include "sys.h" +#include <sys/errno.h> +#include <unistd.h> +#include <stdlib.h> +extern int errno; +#include "el.h" + +#define OKCMD -1 + +private int read__fixio		__P((int, int)); +private int read_preread	__P((EditLine *)); +private int read_getcmd		__P((EditLine *, el_action_t *, char *)); + +#ifdef DEBUG_EDIT +private void +read_debug(el) +    EditLine *el; +{ + +    if (el->el_line.cursor > el->el_line.lastchar) +	(void) fprintf(el->el_errfile, "cursor > lastchar\r\n"); +    if (el->el_line.cursor < el->el_line.buffer) +	(void) fprintf(el->el_errfile, "cursor < buffer\r\n"); +    if (el->el_line.cursor > el->el_line.limit) +	(void) fprintf(el->el_errfile, "cursor > limit\r\n"); +    if (el->el_line.lastchar > el->el_line.limit) +	(void) fprintf(el->el_errfile, "lastchar > limit\r\n"); +    if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2]) +	(void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n"); +} +#endif /* DEBUG_EDIT */ + +/* read__fixio(): + *	Try to recover from a read error + */ +private int +read__fixio(fd, e) +    int fd, e; +{ +    switch (e) { +    case -1:	/* Make sure that the code is reachable */ + +#ifdef EWOULDBLOCK +    case EWOULDBLOCK: +# ifndef TRY_AGAIN +#  define TRY_AGAIN +# endif +#endif /* EWOULDBLOCK */ + +#if defined(POSIX) && defined(EAGAIN) +# if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN +    case EAGAIN: +#  ifndef TRY_AGAIN +#   define TRY_AGAIN +#  endif +# endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */ +#endif /* POSIX && EAGAIN */ + +	e = 0; +#ifdef TRY_AGAIN +# if defined(F_SETFL) && defined(O_NDELAY) +	if ((e = fcntl(fd, F_GETFL, 0)) == -1) +	    return -1; + +	if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1) +	    return -1; +	else  +	    e = 1; +# endif /* F_SETFL && O_NDELAY */ + +# ifdef FIONBIO +	if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) +	    return -1; +	else +	    e = 1; +# endif	/* FIONBIO */ + +#endif /* TRY_AGAIN */ +	return e ? 0 : -1; + +    case EINTR: +	return 0; + +    default: +	return -1; +    } +} + + +/* read_preread(): + *	Try to read the stuff in the input queue; + */ +private int +read_preread(el) +    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; + +#ifdef FIONREAD +    (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); +    if (chrs > 0) { +	char    buf[EL_BUFSIZ]; + +	chrs = read(el->el_infd, buf, (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_chared.c_macro.nline); +	} +    } +#endif  /* FIONREAD */ + +    return chrs > 0; +} + + +/* el_push(): + *	Push a macro + */ +public void +el_push(el, str) +    EditLine *el; +    const char   *str; +{ +    c_macro_t *ma = &el->el_chared.c_macro; + +    if (str != NULL && ma->level + 1 < EL_MAXMACRO) { +	ma->level++; +	ma->macro[ma->level] = (char *) str; +    } +    else { +	term_beep(el); +	term__flush(); +    } +} + + +/* read_getcmd(): + *	Return next command from the input stream. + */ +private int +read_getcmd(el, cmdnum, ch) +    EditLine *el; +    el_action_t *cmdnum; +    char *ch; +{ +    el_action_t  cmd = 0; +    int     num; + +    while (cmd == 0 || cmd == ED_SEQUENCE_LEAD_IN) { +	if ((num = el_getc(el, ch)) != 1)	/* if EOF or error */ +	    return num; + +#ifdef	KANJI +	if ((*ch & 0200)) { +	    el->el_state.metanext = 0; +	    cmd = CcViMap[' ']; +	    break; +	} +	else +#endif /* KANJI */ + +	if (el->el_state.metanext) { +	    el->el_state.metanext = 0; +	    *ch |= 0200; +	} +	cmd = el->el_map.current[(unsigned char) *ch]; +	if (cmd == ED_SEQUENCE_LEAD_IN) { +	    key_value_t val; +	    switch (key_get(el, ch, &val)) { +	    case XK_CMD: +		cmd = val.cmd; +		break; +	    case XK_STR: +		el_push(el, val.str); +		break; +#ifdef notyet +	    case XK_EXE: +		/* XXX: In the future to run a user function */ +		RunCommand(val.str); +		break; +#endif +	    default: +		abort(); +		break; +	    } +	} +	if (el->el_map.alt == NULL)  +	    el->el_map.current = el->el_map.key; +    } +    *cmdnum = cmd; +    return OKCMD; +} + + +/* el_getc(): + *	Read a character + */ +public int +el_getc(el, cp) +    EditLine *el; +    char *cp; +{ +    int num_read; +    unsigned char tcp; +    int tried = 0; + +    c_macro_t *ma = &el->el_chared.c_macro; + +    term__flush(); +    for (;;) { +	if (ma->level < 0) { +	    if (!read_preread(el)) +		break; +	} +	if (ma->level < 0)  +	    break; +    +	if (*ma->macro[ma->level] == 0) { +	    ma->level--; +	    continue; +	} +	*cp = *ma->macro[ma->level]++ & 0377; +	if (*ma->macro[ma->level] == 0) {	/* Needed for QuoteMode On */ +	    ma->level--; +	} +	return 1; +    } + +#ifdef DEBUG_READ +    (void) fprintf(el->el_errfile, "Turning raw mode on\n"); +#endif /* DEBUG_READ */ +    if (tty_rawmode(el) < 0)	/* make sure the tty is set up correctly */ +	return 0; + +#ifdef DEBUG_READ +    (void) fprintf(el->el_errfile, "Reading a character\n"); +#endif /* DEBUG_READ */ +    while ((num_read = read(el->el_infd, (char *) &tcp, 1)) == -1) +	if (!tried && read__fixio(el->el_infd, errno) == 0) +	    tried = 1; +	else { +	    *cp = '\0'; +	    return -1; +	} +#ifdef DEBUG_READ +    (void) fprintf(el->el_errfile, "Got it %c\n", tcp); +#endif /* DEBUG_READ */ +    *cp = tcp; +    return num_read; +} + + + +public const char * +el_gets(el, nread) +    EditLine *el; +    int *nread; +{ +    int retval; +    el_action_t  cmdnum = 0; +    int     num;		/* how many chars we have read at NL */ +    char    ch; + +    if (el->el_flags & HANDLE_SIGNALS) +	sig_set(el); + +    re_clear_display(el);		/* reset the display stuff */ +    ch_reset(el); + +#ifdef FIONREAD +    if (el->el_tty.t_mode == EX_IO && ma->level < 0) { +	long    chrs = 0; + +	(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) &chrs); +	if (chrs == 0) { +	    if (tty_rawmode(el) < 0) { +		if (nread) +			*nread = 0; +		return NULL; +	    } +	} +    } +#endif /* FIONREAD */ + +    re_refresh(el);			/* print the prompt */ + +    for (num = OKCMD; num == OKCMD;) {	/* while still editing this line */ +#ifdef DEBUG_EDIT +	read_debug(el); +#endif /* DEBUG_EDIT */ +	/* if EOF or error */ +	if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) { +#ifdef DEBUG_READ +	    (void) fprintf(el->el_errfile, "Returning from el_gets %d\n", num); +#endif /* DEBUG_READ */ +	    break; +	} + +	if (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); +#endif /* DEBUG_EDIT */ +	    continue;		/* try again */ +	} + +	/* now do the real command */ +#ifdef DEBUG_READ +	{ +	    el_bindings_t *b; +	    for (b = el->el_map.help; b->name; b++) +		if (b->func == cmdnum) +		    break; +	    if (b->name) +		(void) fprintf(el->el_errfile, "Executing %s\n", b->name); +	    else +		(void) fprintf(el->el_errfile, "Error command = %d\n", cmdnum); +	} +#endif /* DEBUG_READ */ +	retval = (*el->el_map.func[cmdnum])(el, ch); + +	/* save the last command here */ +	el->el_state.lastcmd = cmdnum; + +	/* use any return value */ +	switch (retval) { +	case CC_CURSOR: +	    el->el_state.argument = 1; +	    el->el_state.doingarg = 0; +	    re_refresh_cursor(el); +	    break; + +	case CC_REDISPLAY: +	    re_clear_lines(el); +	    re_clear_display(el); +		/* FALLTHROUGH */ + +	case CC_REFRESH: +	    el->el_state.argument = 1; +	    el->el_state.doingarg = 0; +	    re_refresh(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 */ +	    /* <rsalz@pineapple.bbn.com> */ +	    break;		/* keep going... */ + +	case CC_EOF:		/* end of file typed */ +	    num = 0; +	    break; + +	case CC_NEWLINE:	/* normal end of line */ +	    num = el->el_line.lastchar - el->el_line.buffer;	 +	    break; + +	case CC_FATAL:		/* fatal error, reset to known state */ +#ifdef DEBUG_READ +	    (void) fprintf(el->el_errfile, "*** editor fatal ERROR ***\r\n\n"); +#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 */ +	    re_refresh(el);		/* print the prompt again */ +	    el->el_state.argument = 1; +	    el->el_state.doingarg = 0; +	    break; + +	case CC_ERROR: +	default:		/* functions we don't know about */ +#ifdef DEBUG_READ +	    (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; +	} +    } + +    (void) tty_cookedmode(el);	/* make sure the tty is set up correctly */ +    term__flush();		/* flush any buffered output */ +    if (el->el_flags & HANDLE_SIGNALS) +	sig_clr(el); +    if (nread) +	    *nread = num; +    return num ? el->el_line.buffer : NULL; +} diff --git a/refresh.c b/refresh.c new file mode 100644 index 0000000000000..304b806e5eddd --- /dev/null +++ b/refresh.c @@ -0,0 +1,1019 @@ +/*	$NetBSD: refresh.c,v 1.2 1997/01/11 06:48:07 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: refresh.c,v 1.2 1997/01/11 06:48:07 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * refresh.c: Lower level screen refreshing functions + */ +#include "sys.h" +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include <string.h> + +#include "el.h" + +private	void	re_addc 		__P((EditLine *, int)); +private	void	re_update_line 		__P((EditLine *, char *, char *, int)); +private	void	re_insert		__P((EditLine *, char *, int, int,  +					     char *, int)); +private	void	re_delete		__P((EditLine *, char *, int, int,  +					     int)); +private	void	re_fastputc		__P((EditLine *, int)); + +private	void	re__strncopy		__P((char *, char *, size_t)); +private	void	re__copy_and_pad	__P((char *, char *, size_t)); + +#ifdef DEBUG_REFRESH +private	void	re_printstr		__P((EditLine *, char *, char *,  +					     char *)); +# define __F el->el_errfile +# define RE_DEBUG(a, b, c)	do 				\ +				    if (a) {			\ +					(void) fprintf b;	\ +					c;			\ +				    }				\ +				while (0) +/* re_printstr(): + *	Print a string on the debugging pty + */ +private void +re_printstr(el, str, f, t) +    EditLine *el; +    char *str; +    char *f, *t; +{ +    RE_DEBUG(1,(__F, "%s:\"", str),); +    while (f < t) +	RE_DEBUG(1,(__F, "%c", *f++ & 0177),); +    RE_DEBUG(1,(__F, "\"\r\n"),); +}  +#else +# define RE_DEBUG(a, b, c) +#endif + + +/* re_addc(): + *	Draw c, expanding tabs, control chars etc. + */ +private void +re_addc(el, c) +    EditLine *el; +    int c; +{ +    if (isprint(c)) { +	re_putc(el, c); +	return; +    } +    if (c == '\n') {			/* expand the newline	 */ +	re_putc(el, '\0');		/* assure end of line	 */ +	el->el_refresh.r_cursor.h = 0;	/* reset cursor pos	 */ +	el->el_refresh.r_cursor.v++; +	return; +    } +    if (c == '\t') {		/* expand the tab 	 */ +	for (;;) { +	    re_putc(el, ' '); +	    if ((el->el_refresh.r_cursor.h & 07) == 0) +		break;		/* go until tab stop	 */ +	} +    } +    else if (iscntrl(c)) { +	re_putc(el, '^'); +	if (c == '\177')  +	    re_putc(el, '?'); +	else  +	    /* uncontrolify it; works only for iso8859-1 like sets */ +	    re_putc(el, (c | 0100)); +    } +    else { +	re_putc(el, '\\'); +	re_putc(el, ((c >> 6) & 07) + '0'); +	re_putc(el, ((c >> 3) & 07) + '0'); +	re_putc(el, (c & 07) + '0'); +    } +} /* end re_addc */ + + +/* re_putc(): + *	Draw the character given + */ +protected void +re_putc(el, c) +    EditLine *el; +    int c; +{ +    RE_DEBUG(1,(__F, "printing %3.3o '%c'\r\n", c, c),); + +    el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c; +    el->el_refresh.r_cursor.h++;				/* advance to next place */ +    if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) { +	el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';	 +						/* assure end of line */ +	el->el_refresh.r_cursor.h = 0;				/* reset it. */ +	el->el_refresh.r_cursor.v++; +	RE_DEBUG(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,  +		 (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", +		  el->el_refresh.r_cursor.v, el->el_term.t_size.v), abort()); +    } +} /* end re_putc */ + + +/* re_refresh(): + *	draws the new virtual screen image from the current input + *  	line, then goes line-by-line changing the real image to the new + *	virtual image. The routine to re-draw a line can be replaced + *	easily in hopes of a smarter one being placed there. + */ +protected void +re_refresh(el) +    EditLine *el; +{ +    int i; +    char *cp; +    coord_t     cur; + +    RE_DEBUG(1,(__F, "el->el_line.buffer = :%s:\r\n", el->el_line.buffer),); + +    /* reset the Drawing cursor */ +    el->el_refresh.r_cursor.h = 0; +    el->el_refresh.r_cursor.v = 0; + +    cur.h = -1;			/* set flag in case I'm not set */ +    cur.v = 0; + +    prompt_print(el); + +    /* draw the current input buffer */ +    for (cp = el->el_line.buffer; cp < el->el_line.lastchar; cp++) { +	if (cp == el->el_line.cursor) { +	    cur.h = el->el_refresh.r_cursor.h;	/* save for later */ +	    cur.v = el->el_refresh.r_cursor.v; +	} +	re_addc(el, *cp); +    } + +    if (cur.h == -1) {		/* if I haven't been set yet, I'm at the end */ +	cur.h = el->el_refresh.r_cursor.h; +	cur.v = el->el_refresh.r_cursor.v; +    } +    /* must be done BEFORE the NUL is written */ +    el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;	 +    re_putc(el, '\0');		/* put NUL on end */ + +    RE_DEBUG(1,(__F,  +	     "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", +	     el->el_term.t_size.h, el->el_refresh.r_cursor.h,  +	     el->el_refresh.r_cursor.v, el->el_vdisplay[0]),); + +    RE_DEBUG(1,(__F, "updating %d lines.\r\n", el->el_refresh.r_newcv),); +    for (i = 0; i <= el->el_refresh.r_newcv; i++) { +	/* NOTE THAT re_update_line MAY CHANGE el_display[i] */ +	re_update_line(el, el->el_display[i], el->el_vdisplay[i], i); + +	/* +	 * Copy the new line to be the current one, and pad out with spaces +	 * to the full width of the terminal so that if we try moving the +	 * cursor by writing the character that is at the end of the +	 * screen line, it won't be a NUL or some old leftover stuff. +	 */ +	re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],  +			el->el_term.t_size.h); +    } +    RE_DEBUG(1,(__F, +	 "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", +	 el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i),); + +    if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)  +	for (; i <= el->el_refresh.r_oldcv; i++) { +	    term_move_to_line(el, i); +	    term_move_to_char(el, 0); +	    term_clear_EOL(el, strlen(el->el_display[i])); +#ifdef DEBUG_REFRESH +	    term_overwrite(el, "C\b", 2); +#endif /* DEBUG_REFRESH */ +	    *el->el_display[i] = '\0'; +	} +     +    el->el_refresh.r_oldcv = el->el_refresh.r_newcv;	/* set for next time */ +    RE_DEBUG(1,(__F,  +		"\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", +		el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,  +		cur.h, cur.v),); +    term_move_to_line(el, cur.v);		/* go to where the cursor is */ +    term_move_to_char(el, cur.h); +} /* end re_refresh */ + + +/* re_goto_bottom(): + *	 used to go to last used screen line  + */ +protected void +re_goto_bottom(el) +    EditLine *el; +{ +    term_move_to_line(el, el->el_refresh.r_oldcv); +    term__putc('\r'); +    term__putc('\n'); +    re_clear_display(el); +    term__flush(); +} /* end re_goto_bottom */ + + +/* re_insert(): + *	insert num characters of s into d (in front of the character) + *	at dat, maximum length of d is dlen  + */ +private void +/*ARGSUSED*/ +re_insert(el, d, dat, dlen, s, num) +    EditLine *el; +    char *d; +    int dat, dlen; +    char *s; +    int num; +{ +    char *a, *b; + +    if (num <= 0) +	return; +    if (num > dlen - dat) +	num = dlen - dat; + +    RE_DEBUG(1,(__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", +	    num, dat, dlen, d),); +    RE_DEBUG(1,(__F, "s == \"%s\"n", s),); + +    /* open up the space for num chars */ +    if (num > 0) { +	b = d + dlen - 1; +	a = b - num; +	while (a >= &d[dat]) +	    *b-- = *a--; +	d[dlen] = '\0';		/* just in case */ +    } +    RE_DEBUG(1,(__F,  +		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n", +		num, dat, dlen, d),); +    RE_DEBUG(1,(__F, "s == \"%s\"n", s),); + +    /* copy the characters */ +    for (a = d + dat; (a < d + dlen) && (num > 0); num--) +	*a++ = *s++; + +    RE_DEBUG(1,(__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", +	     num, dat, dlen, d, s),); +    RE_DEBUG(1,(__F, "s == \"%s\"n", s),); +} /* end re_insert */ + + +/* re_delete(): + *	delete num characters d at dat, maximum length of d is dlen  + */ +private void +/*ARGSUSED*/ +re_delete(el, d, dat, dlen, num) +    EditLine *el; +    char *d; +    int dat, dlen, num; +{ +    char *a, *b; + +    if (num <= 0) +	return; +    if (dat + num >= dlen) { +	d[dat] = '\0'; +	return; +    } + +    RE_DEBUG(1,(__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", +	    num, dat, dlen, d),); + +    /* open up the space for num chars */ +    if (num > 0) { +	b = d + dat; +	a = b + num; +	while (a < &d[dlen]) +	    *b++ = *a++; +	d[dlen] = '\0';		/* just in case */ +    } +    RE_DEBUG(1,(__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", +	    num, dat, dlen, d),); +} /* end re_delete */ + + +/* re__strncopy(): + *	Like strncpy without padding. + */ +private void +re__strncopy(a, b, n) +    char *a, *b; +    size_t n; +{ +    while (n-- && *b) +	*a++ = *b++; +} /* end re__strncopy */ + + +/* **************************************************************** +    re_update_line() is based on finding the middle difference of each line +    on the screen; vis: + +			     /old first difference +	/beginning of line   |              /old last same       /old EOL +	v		     v              v                    v +old:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as +new:	eddie> Oh, my little buggy says to me, as lurgid as +	^		     ^        ^			   ^ +	\beginning of line   |        \new last same	   \new end of line +			     \new first difference + +    all are character pointers for the sake of speed.  Special cases for +    no differences, as well as for end of line additions must be handled. +**************************************************************** */ + +/* Minimum at which doing an insert it "worth it".  This should be about + * half the "cost" of going into insert mode, inserting a character, and + * going back out.  This should really be calculated from the termcap + * data...  For the moment, a good number for ANSI terminals. + */ +#define MIN_END_KEEP	4 + +private void +re_update_line(el, old, new, i) +    EditLine *el; +    char *old, *new; +    int     i; +{ +    char *o, *n, *p, c; +    char   *ofd, *ols, *oe, *nfd, *nls, *ne; +    char   *osb, *ose, *nsb, *nse; +    int     fx, sx; + +    /* +     * find first diff +     */ +    for (o = old, n = new; *o && (*o == *n); o++, n++) +	continue; +    ofd = o; +    nfd = n; + +    /* +     * Find the end of both old and new +     */ +    while (*o) +	o++; +    /*  +     * Remove any trailing blanks off of the end, being careful not to +     * back up past the beginning. +     */ +    while (ofd < o) { +	if (o[-1] != ' ') +	    break; +	o--; +    } +    oe = o; +    *oe = '\0'; +   +    while (*n) +	n++; + +    /* remove blanks from end of new */ +    while (nfd < n) { +	if (n[-1] != ' ') +	    break; +	n--; +    } +    ne = n; +    *ne = '\0'; +   +    /* +     * if no diff, continue to next line of redraw +     */ +    if (*ofd == '\0' && *nfd == '\0') { +	RE_DEBUG(1,(__F, "no difference.\r\n"),); +	return; +    } + +    /* +     * find last same pointer +     */ +    while ((o > ofd) && (n > nfd) && (*--o == *--n)) +	continue; +    ols = ++o; +    nls = ++n; + +    /* +     * find same begining and same end +     */ +    osb = ols; +    nsb = nls; +    ose = ols; +    nse = nls; + +    /* +     * case 1: insert: scan from nfd to nls looking for *ofd +     */ +    if (*ofd) { +	for (c = *ofd, n = nfd; n < nls; n++) { +	    if (c == *n) { +		for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++) +		    continue; +		/* +		 * if the new match is longer and it's worth keeping, then we +		 * take it +		 */ +		if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) { +		    nsb = n; +		    nse = p; +		    osb = ofd; +		    ose = o; +		} +	    } +	} +    } + +    /* +     * case 2: delete: scan from ofd to ols looking for *nfd +     */ +    if (*nfd) { +	for (c = *nfd, o = ofd; o < ols; o++) { +	    if (c == *o) { +		for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++) +		    continue; +		/* +		 * if the new match is longer and it's worth keeping, then we +		 * take it +		 */ +		if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) { +		    nsb = nfd; +		    nse = n; +		    osb = o; +		    ose = p; +		} +	    } +	} +    } + +    /* +     * Pragmatics I: If old trailing whitespace or not enough characters to +     * save to be worth it, then don't save the last same info. +     */ +    if ((oe - ols) < MIN_END_KEEP) { +	ols = oe; +	nls = ne; +    } + +    /* +     * Pragmatics II: if the terminal isn't smart enough, make the data dumber +     * so the smart update doesn't try anything fancy +     */ + +    /* +     * fx is the number of characters we need to insert/delete: in the +     * beginning to bring the two same begins together +     */ +    fx = (nsb - nfd) - (osb - ofd); +    /* +     * sx is the number of characters we need to insert/delete: in the end to +     * bring the two same last parts together +     */ +    sx = (nls - nse) - (ols - ose); + +    if (!EL_CAN_INSERT) { +	if (fx > 0) { +	    osb = ols; +	    ose = ols; +	    nsb = nls; +	    nse = nls; +	} +	if (sx > 0) { +	    ols = oe; +	    nls = ne; +	} +	if ((ols - ofd) < (nls - nfd)) { +	    ols = oe; +	    nls = ne; +	} +    } +    if (!EL_CAN_DELETE) { +	if (fx < 0) { +	    osb = ols; +	    ose = ols; +	    nsb = nls; +	    nse = nls; +	} +	if (sx < 0) { +	    ols = oe; +	    nls = ne; +	} +	if ((ols - ofd) > (nls - nfd)) { +	    ols = oe; +	    nls = ne; +	} +    } + +    /* +     * Pragmatics III: make sure the middle shifted pointers are correct if +     * they don't point to anything (we may have moved ols or nls). +     */ +    /* if the change isn't worth it, don't bother */ +    /* was: if (osb == ose) */ +    if ((ose - osb) < MIN_END_KEEP) { +	osb = ols; +	ose = ols; +	nsb = nls; +	nse = nls; +    } + +    /* +     * Now that we are done with pragmatics we recompute fx, sx +     */ +    fx = (nsb - nfd) - (osb - ofd); +    sx = (nls - nse) - (ols - ose); + +    RE_DEBUG(1,(__F, "\n"),); +    RE_DEBUG(1,(__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n", +	    ofd - old, osb - old, ose - old, ols - old, oe - old),); +    RE_DEBUG(1,(__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n", +	    nfd - new, nsb - new, nse - new, nls - new, ne - new),); +    RE_DEBUG(1,(__F,  +		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"),); +    RE_DEBUG(1,(__F, +		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"),); +#ifdef DEBUG_REFRESH +    re_printstr(el, "old- oe", old, oe); +    re_printstr(el, "new- ne", new, ne); +    re_printstr(el, "old-ofd", old, ofd); +    re_printstr(el, "new-nfd", new, nfd); +    re_printstr(el, "ofd-osb", ofd, osb); +    re_printstr(el, "nfd-nsb", nfd, nsb); +    re_printstr(el, "osb-ose", osb, ose); +    re_printstr(el, "nsb-nse", nsb, nse); +    re_printstr(el, "ose-ols", ose, ols); +    re_printstr(el, "nse-nls", nse, nls); +    re_printstr(el, "ols- oe", ols, oe); +    re_printstr(el, "nls- ne", nls, ne); +#endif /* DEBUG_REFRESH */ + +    /* +     * el_cursor.v to this line i MUST be in this routine so that if we +     * don't have to change the line, we don't move to it. el_cursor.h to first +     * diff char +     */ +    term_move_to_line(el, i); + +    /* +     * at this point we have something like this: +     *  +     * /old                  /ofd    /osb               /ose    /ols     /oe +     * v.....................v       v..................v       v........v +     * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as +     * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as +     * ^.....................^     ^..................^       ^........^  +     * \new                  \nfd  \nsb               \nse     \nls    \ne +     *  +     * fx is the difference in length between the the chars between nfd and +     * nsb, and the chars between ofd and osb, and is thus the number of +     * characters to delete if < 0 (new is shorter than old, as above), +     * or insert (new is longer than short). +     * +     * sx is the same for the second differences. +     */ + +    /* +     * if we have a net insert on the first difference, AND inserting the net +     * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character +     * (which is ne if nls != ne, otherwise is nse) off the edge of the screen +     * (el->el_term.t_size.h) else we do the deletes first so that we keep everything we need +     * to. +     */ + +    /* +     * if the last same is the same like the end, there is no last same part, +     * otherwise we want to keep the last same part set p to the last useful +     * old character +     */ +    p = (ols != oe) ? oe : ose; + +    /* +     * if (There is a diffence in the beginning) && (we need to insert +     * characters) && (the number of characters to insert is less than the term +     * width) We need to do an insert! else if (we need to delete characters) +     * We need to delete characters! else No insert or delete +     */ +    if ((nsb != nfd) && fx > 0 && ((p - old) + fx <= el->el_term.t_size.h)) { +	RE_DEBUG(1,(__F, "first diff insert at %d...\r\n", nfd - new),); +	/* +	 * Move to the first char to insert, where the first diff is. +	 */ +	term_move_to_char(el, nfd - new); +	/* +	 * Check if we have stuff to keep at end +	 */ +	if (nsb != ne) { +	    RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),); +	    /* +	     * insert fx chars of new starting at nfd +	     */ +	    if (fx > 0) { +		RE_DEBUG(!EL_CAN_INSERT, +			 (__F, "ERROR: cannot insert in early first diff\n"),); +		term_insertwrite(el, nfd, fx); +		re_insert(el, old, ofd - old, el->el_term.t_size.h, nfd, fx); +	    } +	    /* +	     * write (nsb-nfd) - fx chars of new starting at (nfd + fx) +	     */ +	    term_overwrite(el, nfd + fx, (nsb - nfd) - fx); +	    re__strncopy(ofd + fx, nfd + fx, (nsb - nfd) - fx); +	} +	else { +	    RE_DEBUG(1,(__F, "without anything to save\r\n"),); +	    term_overwrite(el, nfd, (nsb - nfd)); +	    re__strncopy(ofd, nfd, (nsb - nfd)); +	    /* +	     * Done +	     */ +	    return; +	} +    } +    else if (fx < 0) { +	RE_DEBUG(1,(__F, "first diff delete at %d...\r\n", ofd - old),); +	/* +	 * move to the first char to delete where the first diff is +	 */ +	term_move_to_char(el, ofd - old); +	/* +	 * Check if we have stuff to save +	 */ +	if (osb != oe) { +	    RE_DEBUG(1,(__F, "with stuff to save at end\r\n"),); +	    /* +	     * fx is less than zero *always* here but we check for code +	     * symmetry +	     */ +	    if (fx < 0) { +		RE_DEBUG(!EL_CAN_DELETE, +			 (__F, "ERROR: cannot delete in first diff\n"),); +		term_deletechars(el, -fx); +		re_delete(el, old, ofd - old, el->el_term.t_size.h, -fx); +	    } +	    /* +	     * write (nsb-nfd) chars of new starting at nfd +	     */ +	    term_overwrite(el, nfd, (nsb - nfd)); +	    re__strncopy(ofd, nfd, (nsb - nfd)); + +	} +	else { +	    RE_DEBUG(1,(__F, "but with nothing left to save\r\n"),); +	    /* +	     * write (nsb-nfd) chars of new starting at nfd +	     */ +	    term_overwrite(el, nfd, (nsb - nfd)); +	    RE_DEBUG(1,(__F, "cleareol %d\n", (oe - old) - (ne - new)),); +	    term_clear_EOL(el, (oe - old) - (ne - new)); +	    /* +	     * Done +	     */ +	    return; +	} +    } +    else +	fx = 0; + +    if (sx < 0) { +	RE_DEBUG(1,(__F, "second diff delete at %d...\r\n", (ose - old) + fx),); +	/* +	 * Check if we have stuff to delete +	 */ +	/* +	 * fx is the number of characters inserted (+) or deleted (-) +	 */ + +	term_move_to_char(el, (ose - old) + fx); +	/* +	 * Check if we have stuff to save +	 */ +	if (ols != oe) { +	    RE_DEBUG(1,(__F, "with stuff to save at end\r\n"),); +	    /* +	     * Again a duplicate test. +	     */ +	    if (sx < 0) { +		RE_DEBUG(!EL_CAN_DELETE,  +			 (__F, "ERROR: cannot delete in second diff\n"),); +		term_deletechars(el, -sx); +	    } + +	    /* +	     * write (nls-nse) chars of new starting at nse +	     */ +	    term_overwrite(el, nse, (nls - nse)); +	} +	else { +	    RE_DEBUG(1,(__F, "but with nothing left to save\r\n"),); +	    term_overwrite(el, nse, (nls - nse)); +	    RE_DEBUG(1,(__F, "cleareol %d\n", (oe - old) - (ne - new)),); +	    term_clear_EOL(el, (oe - old) - (ne - new)); +	} +    } + +    /* +     * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... +     */ +    if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { +	RE_DEBUG(1,(__F, "late first diff insert at %d...\r\n", nfd - new),); + +	term_move_to_char(el, nfd - new); +	/* +	 * Check if we have stuff to keep at the end +	 */ +	if (nsb != ne) { +	    RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),); +	    /*  +	     * We have to recalculate fx here because we set it +	     * to zero above as a flag saying that we hadn't done +	     * an early first insert. +	     */ +	    fx = (nsb - nfd) - (osb - ofd); +	    if (fx > 0) { +		/* +		 * insert fx chars of new starting at nfd +		 */ +		RE_DEBUG(!EL_CAN_INSERT, +			 (__F, "ERROR: cannot insert in late first diff\n"),); +		term_insertwrite(el, nfd, fx); +		re_insert(el, old, ofd - old, el->el_term.t_size.h, nfd, fx); +	    } + +	    /* +	     * write (nsb-nfd) - fx chars of new starting at (nfd + fx) +	     */ +	    term_overwrite(el, nfd + fx, (nsb - nfd) - fx); +	    re__strncopy(ofd + fx, nfd + fx, (nsb - nfd) - fx); +	} +	else { +	    RE_DEBUG(1,(__F, "without anything to save\r\n"),); +	    term_overwrite(el, nfd, (nsb - nfd)); +	    re__strncopy(ofd, nfd, (nsb - nfd)); +	} +    } + +    /* +     * line is now NEW up to nse +     */ +    if (sx >= 0) { +	RE_DEBUG(1,(__F, "second diff insert at %d...\r\n", nse - new),); +	term_move_to_char(el, nse - new); +	if (ols != oe) { +	    RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),); +	    if (sx > 0) { +		/* insert sx chars of new starting at nse */ +		RE_DEBUG(!EL_CAN_INSERT, +		         (__F, "ERROR: cannot insert in second diff\n"),); +		term_insertwrite(el, nse, sx); +	    } + +	    /* +	     * write (nls-nse) - sx chars of new starting at (nse + sx) +	     */ +	    term_overwrite(el, nse + sx, (nls - nse) - sx); +	} +	else { +	    RE_DEBUG(1,(__F, "without anything to save\r\n"),); +	    term_overwrite(el, nse, (nls - nse)); + +	    /* +             * No need to do a clear-to-end here because we were doing +	     * a second insert, so we will have over written all of the +	     * old string. +	     */ +	} +    } +    RE_DEBUG(1,(__F, "done.\r\n"),); +} /* re_update_line */ + + +/* re__copy_and_pad(): + *	Copy string and pad with spaces + */ +private void +re__copy_and_pad(dst, src, width) +    char *dst, *src; +    size_t width; +{ +    int i; + +    for (i = 0; i < width; i++) { +	if (*src == '\0') +	    break; +	*dst++ = *src++; +    } + +    while (i < width) { +	*dst++ = ' '; +	i++; +    } +    *dst = '\0'; +} /* end re__copy_and_pad */ + + +/* re_refresh_cursor(): + *	Move to the new cursor position + */ +protected void +re_refresh_cursor(el) +    EditLine *el; +{ +    char *cp, c; +    int h, v, th; + +    /* first we must find where the cursor is... */ +    h  = el->el_prompt.p_pos.h; +    v  = el->el_prompt.p_pos.v; +    th = el->el_term.t_size.h;		/* optimize for speed 		*/ + +    /* do input buffer to el->el_line.cursor */ +    for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {	 +	c = *cp; +	h++;			/* all chars at least this long */ + +	if (c == '\n') {	/* handle newline in data part too */ +	    h = 0; +	    v++; +	} +	else { +	    if (c == '\t') {	/* if a tab, to next tab stop */ +		while (h & 07) { +		    h++; +		} +	    } +	    else if (iscntrl(c)) {	/* if control char */ +		h++; +		if (h > th) {	/* if overflow, compensate */ +		    h = 1; +		    v++; +		} +	    } +	    else if (!isprint(c)) { +		h += 3; +		if (h > th) {	/* if overflow, compensate */ +		    h = h - th; +		    v++; +		} +	    } +	} + +	if (h >= th) {		/* check, extra long tabs picked up here also */ +	    h = 0; +	    v++; +	} +    } + +    /* now go there */ +    term_move_to_line(el, v); +    term_move_to_char(el, h); +    term__flush(); +} /* re_refresh_cursor */ + + +/* re_fastputc(): + *	Add a character fast. + */ +private void +re_fastputc(el, c) +    EditLine *el; +    int    c; +{ +    term__putc(c); +    el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; +    if (el->el_cursor.h >= el->el_term.t_size.h) {	 +	/* if we must overflow */ +	el->el_cursor.h = 0; +	el->el_cursor.v++; +	el->el_refresh.r_oldcv++; +	term__putc('\r'); +	term__putc('\n'); +    } +} /* end re_fastputc */ + + +/* re_fastaddc(): + *	we added just one char, handle it fast. + *	Assumes that screen cursor == real cursor  + */ +protected void +re_fastaddc(el) +    EditLine *el; +{ +    char c; + +    c = el->el_line.cursor[-1]; + +    if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { +	re_refresh(el);		/* too hard to handle */ +	return; +    }				/* else (only do at end of line, no TAB) */ + +    if (iscntrl(c)) {		/* if control char, do caret */ +	char mc = (c == '\177') ? '?' : (c | 0100); +	re_fastputc(el, '^'); +	re_fastputc(el, mc); +    } +    else if (isprint(c)) {	/* normal char */ +	re_fastputc(el, c); +    } +    else { +	re_fastputc(el, '\\'); +	re_fastputc(el, ((c >> 6) & 7) + '0'); +	re_fastputc(el, ((c >> 3) & 7) + '0'); +	re_fastputc(el, (c & 7) + '0'); +    } +    term__flush(); +} /* end re_fastaddc */ + + +/* re_clear_display(): + *	clear the screen buffers so that new new prompt starts fresh.  + */ +protected void +re_clear_display(el) +    EditLine *el; +{ +    int i; + +    el->el_cursor.v = 0; +    el->el_cursor.h = 0; +    for (i = 0; i < el->el_term.t_size.v; i++) +	el->el_display[i][0] = '\0'; +    el->el_refresh.r_oldcv = 0; +} /* end re_clear_display */ + + +/* re_clear_lines(): + *	Make sure all lines are *really* blank  + */ +protected void +re_clear_lines(el) +    EditLine *el; +{ +    if (EL_CAN_CEOL) { +	int i; +	term_move_to_char(el, 0); +	for (i = 0; i <= el->el_refresh.r_oldcv; i++) { +	    /* for each line on the screen */ +	    term_move_to_line(el, i); +	    term_clear_EOL(el, el->el_term.t_size.h); +	} +	term_move_to_line(el, 0); +    } +    else { +	term_move_to_line(el, el->el_refresh.r_oldcv);	/* go to last line */ +	term__putc('\r');				/* go to BOL */ +	term__putc('\n');				/* go to new line */ +    } +} /* end re_clear_lines */ diff --git a/refresh.h b/refresh.h new file mode 100644 index 0000000000000..30533d19dda38 --- /dev/null +++ b/refresh.h @@ -0,0 +1,62 @@ +/*	$NetBSD: refresh.h,v 1.2 1997/01/11 06:48:08 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. + * + *	@(#)refresh.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.refresh.h: Screen refresh functions + */ +#ifndef _h_el_refresh +#define _h_el_refresh + +#include "histedit.h" + +typedef struct { +    coord_t 	 r_cursor;	/* Refresh cursor position	*/ +    int r_oldcv, r_newcv;	/* Vertical locations		*/ +} el_refresh_t; + +protected void	re_putc 		__P((EditLine *, int)); +protected void	re_clear_lines		__P((EditLine *)); +protected void	re_clear_display	__P((EditLine *)); +protected void	re_refresh		__P((EditLine *)); +protected void	re_refresh_cursor	__P((EditLine *)); +protected void	re_fastaddc		__P((EditLine *)); +protected void	re_goto_bottom		__P((EditLine *)); + +#endif /* _h_el_refresh */ diff --git a/search.c b/search.c new file mode 100644 index 0000000000000..1149a58237b8c --- /dev/null +++ b/search.c @@ -0,0 +1,640 @@ +/*	$NetBSD: search.c,v 1.4 1997/01/23 14:02:47 mrg 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)search.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: search.c,v 1.4 1997/01/23 14:02:47 mrg Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * search.c: History and character search functions + */ +#include "sys.h" +#include <stdlib.h> +#if defined(REGEX) +#include <regex.h> +#elif defined(REGEXP) +#include <regexp.h> +#endif +#include "el.h" + +/* + * Adjust cursor in vi mode to include the character under it + */ +#define EL_CURSOR(el) \ +    ((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \ +			    ((el)->el_map.current == (el)->el_map.alt))) + +/* search_init(): + *	Initialize the search stuff + */ +protected int +search_init(el) +    EditLine *el; +{ +    el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ); +    el->el_search.patlen = 0; +    el->el_search.patdir = -1; +    el->el_search.chacha = '\0'; +    el->el_search.chadir = -1; +    return 0; +} + + +/* search_end(): + *	Initialize the search stuff + */ +protected void +search_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_search.patbuf); +    el->el_search.patbuf = NULL; +} + +#ifdef REGEXP +/* regerror(): + *	Handle regular expression errors + */ +public void  +/*ARGSUSED*/ +regerror(msg) +    const char *msg; +{ +} +#endif + +/* el_match(): + *	Return if string matches pattern + */ +protected int +el_match(str, pat) +    const char *str; +    const char *pat; +{ +#if defined (REGEX) +    regex_t re; +    int rv; +#elif defined (REGEXP) +    regexp *rp; +    int rv; +#else  +    extern char *re_comp __P((const char *)); +    extern int re_exec __P((const char *)); +#endif + +    if (strstr(str, pat) != NULL) +	return 1; + +#if defined(REGEX) +    if (regcomp(&re, pat, 0) == 0) { +	rv = regexec(&re, str, 0, NULL, 0) == 0; +	regfree(&re); +    } else { +	rv = 0; +    } +    return rv; +#elif defined(REGEXP) +    if ((re = regcomp(pat)) != NULL) { +	rv = regexec(re, str); +	free((ptr_t) re); +    } else { +	rv = 0; +    } +    return rv; +#else +    if (re_comp(pat) != NULL) +	return 0; +    else +    return re_exec(str) == 1; +#endif +} + + +/* c_hmatch(): + *	 return True if the pattern matches the prefix + */ +protected int +c_hmatch(el, str) +    EditLine *el; +    const char *str; +{ +#ifdef SDEBUG +    (void) fprintf(el->el_errfile, "match `%s' with `%s'\n", +		   el->el_search.patbuf, str); +#endif /* SDEBUG */ +     +    return el_match(str, el->el_search.patbuf); +} + + +/* c_setpat():  + *	Set the history seatch pattern + */ +protected void +c_setpat(el) +    EditLine *el; +{ +    if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&  +	el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) { +	el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer; +	if (el->el_search.patlen >= EL_BUFSIZ)  +	    el->el_search.patlen = EL_BUFSIZ -1; +	if (el->el_search.patlen >= 0)  { +	    (void) strncpy(el->el_search.patbuf, el->el_line.buffer,  +			   el->el_search.patlen); +	    el->el_search.patbuf[el->el_search.patlen] = '\0'; +	} +	else +	    el->el_search.patlen = strlen(el->el_search.patbuf); +    } +#ifdef SDEBUG +    (void) fprintf(el->el_errfile, "\neventno = %d\n", el->el_history.eventno); +    (void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen); +    (void) fprintf(el->el_errfile, "patbuf = \"%s\"\n", el->el_search.patbuf); +    (void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",  +		   EL_CURSOR(el) - el->el_line.buffer,  +		   el->el_line.lastchar - el->el_line.buffer); +#endif +} + + +/* ce_inc_search(): + *	Emacs incremental search + */ +protected el_action_t +ce_inc_search(el, dir) +    EditLine *el; +    int dir; +{ +    static char STRfwd[] = { 'f', 'w', 'd', '\0' }, +		STRbck[] = { 'b', 'c', 'k', '\0' }; +    static char pchar = ':';	/* ':' = normal, '?' = failed */ +    static char endcmd[2] = { '\0', '\0' }; +    char ch, *cp, *ocursor = el->el_line.cursor, oldpchar = pchar; + +    el_action_t ret = CC_NORM; + +    int ohisteventno = el->el_history.eventno, +	oldpatlen = el->el_search.patlen, +	newdir = dir, +        done, redo; + +    if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 +  +	el->el_search.patlen >= el->el_line.limit) +	return CC_ERROR; + +    for (;;) { + +	if (el->el_search.patlen == 0) {	/* first round */ +	    pchar = ':'; +#ifdef ANCHOR +	    el->el_search.patbuf[el->el_search.patlen++] = '.'; +	    el->el_search.patbuf[el->el_search.patlen++] = '*'; +#endif +	} +	done = redo = 0; +	*el->el_line.lastchar++ = '\n'; +	for (cp = newdir == ED_SEARCH_PREV_HISTORY ? STRbck : STRfwd;  +	     *cp; *el->el_line.lastchar++ = *cp++) +	     continue; +	*el->el_line.lastchar++ = pchar; +	for (cp = &el->el_search.patbuf[1];  +	      cp < &el->el_search.patbuf[el->el_search.patlen];  +	      *el->el_line.lastchar++ = *cp++) +	    continue; +	*el->el_line.lastchar = '\0'; +	re_refresh(el); + +	if (el_getc(el, &ch) != 1) +	    return ed_end_of_file(el, 0); + +	switch (el->el_map.current[(unsigned char) ch]) { +	case ED_INSERT: +	case ED_DIGIT: +	    if (el->el_search.patlen > EL_BUFSIZ - 3) +		term_beep(el); +	    else { +		el->el_search.patbuf[el->el_search.patlen++] = ch; +		*el->el_line.lastchar++ = ch; +		*el->el_line.lastchar = '\0'; +		re_refresh(el); +	    } +	    break; + +	case EM_INC_SEARCH_NEXT: +	    newdir = ED_SEARCH_NEXT_HISTORY; +	    redo++; +	    break; + +	case EM_INC_SEARCH_PREV: +	    newdir = ED_SEARCH_PREV_HISTORY; +	    redo++; +	    break; + +	case ED_DELETE_PREV_CHAR: +	    if (el->el_search.patlen > 1) +		done++; +	    else  +		term_beep(el); +	    break; + +	default: +	    switch (ch) { +	    case 0007:		/* ^G: Abort */ +		ret = CC_ERROR; +		done++; +		break; + +	    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]) { +			el->el_line.cursor += el->el_search.patlen - 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) { +				term_beep(el); +				break; +			    } +			    el->el_search.patbuf[el->el_search.patlen++] =  +				*el->el_line.cursor; +			    *el->el_line.lastchar++ = *el->el_line.cursor++; +			} +			el->el_line.cursor = ocursor; +			*el->el_line.lastchar = '\0'; +			re_refresh(el); +			break; +		    } else if (isglob(*cp)) { +			term_beep(el); +			break; +		    } +		break; +	     +	    default:		/* Terminate and execute cmd */ +		endcmd[0] = ch; +		el_push(el, endcmd);  +		/*FALLTHROUGH*/ + +	    case 0033:		/* ESC: Terminate */ +		ret = CC_REFRESH; +		done++; +		break; +	    } +	    break; +	} + +	while (el->el_line.lastchar > el->el_line.buffer &&  +	       *el->el_line.lastchar != '\n') +	    *el->el_line.lastchar-- = '\0'; +	*el->el_line.lastchar = '\0'; + +	if (!done) { + +	    /* Can't search if unmatched '[' */ +	    for (cp = &el->el_search.patbuf[el->el_search.patlen-1], ch = ']';  +		 cp > el->el_search.patbuf; cp--) +		if (*cp == '[' || *cp == ']') { +		    ch = *cp; +		    break; +		} + +	    if (el->el_search.patlen > 1 && ch != '[') { +		if (redo && newdir == dir) { +		    if (pchar == '?') {	/* wrap around */ +			el->el_history.eventno =  +			    newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff; +			if (hist_get(el) == CC_ERROR) +			    /* el->el_history.eventno was fixed by first call */ +			    (void) hist_get(el); +			el->el_line.cursor = newdir == ED_SEARCH_PREV_HISTORY ? +			    el->el_line.lastchar : el->el_line.buffer; +		    } else +			el->el_line.cursor +=  +				newdir == ED_SEARCH_PREV_HISTORY ? -1 : 1; +		} +#ifdef ANCHOR +		el->el_search.patbuf[el->el_search.patlen++] = '.'; +		el->el_search.patbuf[el->el_search.patlen++] = '*'; +#endif +		el->el_search.patbuf[el->el_search.patlen] = '\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) { +		    /* avoid c_setpat */ +		    el->el_state.lastcmd = (el_action_t) newdir;  +		    ret = newdir == ED_SEARCH_PREV_HISTORY ? +			ed_search_prev_history(el, 0) :  +			ed_search_next_history(el, 0); +		    if (ret != CC_ERROR) { +			el->el_line.cursor = newdir == ED_SEARCH_PREV_HISTORY ? +			    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] = '\0'; +		if (ret == CC_ERROR) { +		    term_beep(el); +		    if (el->el_history.eventno != ohisteventno) { +			el->el_history.eventno = ohisteventno; +			if (hist_get(el) == CC_ERROR) +			    return CC_ERROR; +		    } +		    el->el_line.cursor = ocursor; +		    pchar = '?'; +		} else { +		    pchar = ':'; +		} +	    } + +	    ret = ce_inc_search(el, newdir); + +	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')  +		/* break abort of failed search at last non-failed */ +		ret = CC_NORM; + +	} + +	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) { +	    /* restore on normal return or error exit */ +	    pchar = oldpchar; +	    el->el_search.patlen = oldpatlen; +	    if (el->el_history.eventno != ohisteventno) { +		el->el_history.eventno = ohisteventno; +		if (hist_get(el) == CC_ERROR) +		    return CC_ERROR; +	    } +	    el->el_line.cursor = ocursor; +	    if (ret == CC_ERROR) +		re_refresh(el); +	} +	if (done || ret != CC_NORM) +	    return ret; +    } +} + + +/* cv_search(): + *	Vi search. + */ +protected el_action_t +cv_search(el, dir) +    EditLine *el; +    int dir; +{ +    char ch; +    char tmpbuf[EL_BUFSIZ]; +    int tmplen; + +    tmplen = 0; +#ifdef ANCHOR +    tmpbuf[tmplen++] = '.'; +    tmpbuf[tmplen++] = '*'; +#endif + +    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); + +#ifdef ANCHOR +# define LEN 2 +#else +# define LEN 0 +#endif + +    tmplen = c_gets(el, &tmpbuf[LEN]) + LEN; +    ch = tmpbuf[tmplen]; +    tmpbuf[tmplen] = '\0'; + +    if (tmplen == LEN) { +	/* +	 * 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; +	} +#ifdef ANCHOR +	if (el->el_search.patbuf[0] != '.' && el->el_search.patbuf[0] != '*') { +	    (void)strncpy(tmpbuf, el->el_search.patbuf, sizeof(tmpbuf) - 1); +	    el->el_search.patbuf[0] = '.'; +	    el->el_search.patbuf[1] = '*'; +	    (void)strncpy(&el->el_search.patbuf[2], tmpbuf, +		sizeof(el->el_search.patbuf) - 3); +	    el->el_search.patlen++; +	    el->el_search.patbuf[el->el_search.patlen++] = '.'; +	    el->el_search.patbuf[el->el_search.patlen++] = '*'; +	    el->el_search.patbuf[el->el_search.patlen] = '\0'; +	} +#endif +    } +    else { +#ifdef ANCHOR +	tmpbuf[tmplen++] = '.'; +	tmpbuf[tmplen++] = '*'; +#endif +	tmpbuf[tmplen] = '\0'; +	(void)strncpy(el->el_search.patbuf, tmpbuf, +	    sizeof(el->el_search.patbuf) - 1); +	el->el_search.patlen = tmplen; +    } +    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) { +	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; +    } +} + + +/* ce_search_line(): + *	Look for a pattern inside a line + */ +protected el_action_t +ce_search_line(el, pattern, dir) +    EditLine *el; +    char *pattern; +    int dir; +{ +    char *cp; + +    if (dir == ED_SEARCH_PREV_HISTORY) { +	for (cp = el->el_line.cursor; cp >= el->el_line.buffer; cp--) +	    if (el_match(cp, pattern)) { +		el->el_line.cursor = cp; +		return CC_NORM; +	    } +	return CC_ERROR; +    } else { +	for (cp = el->el_line.cursor; *cp != '\0' &&  +	     cp < el->el_line.limit; cp++) +	    if (el_match(cp, pattern)) { +		el->el_line.cursor = cp; +		return CC_NORM; +	    } +	return CC_ERROR; +    } +} + + +/* cv_repeat_srch(): + *	Vi repeat search + */ +protected el_action_t +cv_repeat_srch(el, c) +    EditLine *el; +    int c; +{ +#ifdef SDEBUG +    (void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",  +		   c, el->el_search.patlen, el->el_search.patbuf); +#endif + +    el->el_state.lastcmd = (el_action_t) c;  /* Hack to stop c_setpat */ +    el->el_line.lastchar = el->el_line.buffer; + +    switch (c) { +    case ED_SEARCH_NEXT_HISTORY: +	return ed_search_next_history(el, 0); +    case ED_SEARCH_PREV_HISTORY: +	return ed_search_prev_history(el, 0); +    default: +	return CC_ERROR; +    } +} + + +/* cv_csearch_back(): + *	Vi character search reverse + */ +protected el_action_t +cv_csearch_back(el, ch, count, tflag) +    EditLine *el; +    int ch, count, tflag; +{ +    char *cp; + +    cp = el->el_line.cursor; +    while (count--) { +	if (*cp == ch)  +	    cp--; +	while (cp > el->el_line.buffer && *cp != ch)  +	    cp--; +    } + +    if (cp < el->el_line.buffer || (cp == el->el_line.buffer && *cp != ch)) +	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; +} + + +/* cv_csearch_fwd(): + *	Vi character search forward + */ +protected el_action_t +cv_csearch_fwd(el, ch, count, tflag) +    EditLine *el; +    int ch, count, 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; +} diff --git a/search.h b/search.h new file mode 100644 index 0000000000000..3df54865feefd --- /dev/null +++ b/search.h @@ -0,0 +1,70 @@ +/*	$NetBSD: search.h,v 1.2 1997/01/11 06:48:09 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. + * + *	@(#)search.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.search.h: Line and history searching utilities + */ +#ifndef _h_el_search  +#define _h_el_search  + +#include "histedit.h" + +typedef struct el_search_t { +    char *patbuf;		/* The pattern buffer		*/ +    int  patlen;		/* Length of the pattern buffer	*/ +    int  patdir;		/* Direction of the last search	*/ +    int  chadir;		/* Character search direction	*/ +    char chacha;		/* Character we are looking for	*/ +} el_search_t; + + +protected int 		el_match	__P((const char *, const char *)); +protected int		search_init	__P((EditLine *)); +protected void		search_end	__P((EditLine *)); +protected int		c_hmatch	__P((EditLine *, const char *)); +protected void		c_setpat	__P((EditLine *)); +protected el_action_t	ce_inc_search	__P((EditLine *, int)); +protected el_action_t	cv_search	__P((EditLine *, int)); +protected el_action_t	ce_search_line	__P((EditLine *, char *, int)); +protected el_action_t	cv_repeat_srch	__P((EditLine *, int)); +protected el_action_t	cv_csearch_back	__P((EditLine *, int, int, int)); +protected el_action_t	cv_csearch_fwd	__P((EditLine *, int, int, int)); + +#endif /* _h_el_search */ diff --git a/shlib_version b/shlib_version new file mode 100644 index 0000000000000..97c9f92d6b8fd --- /dev/null +++ b/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/sig.c b/sig.c new file mode 100644 index 0000000000000..75c1b2f6a2bb0 --- /dev/null +++ b/sig.c @@ -0,0 +1,199 @@ +/*	$NetBSD: sig.c,v 1.3 1997/04/11 17:52:48 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)sig.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: sig.c,v 1.3 1997/04/11 17:52:48 christos Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * sig.c: Signal handling stuff. + *	  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 <stdlib.h> + +private EditLine *sel = NULL; + +private int sighdl[] = { +#define _DO(a)	(a), +    ALLSIGS +#undef _DO +    -1 +}; + +private void sig_handler	__P((int)); + +/* sig_handler(): + *	This is the handler called for all signals + *	XXX: we cannot pass any data so we just store the old editline + *	state in a private variable + */ +private void +sig_handler(signo) +    int signo; +{ +    int i; +    sigset_t nset, oset; + +    (void) sigemptyset(&nset); +    (void) sigaddset(&nset, signo); +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    switch (signo) { +    case SIGCONT: +	tty_rawmode(sel); +	if (ed_redisplay(sel, 0) == CC_REFRESH) +	    re_refresh(sel); +	term__flush(); +	break; + +    case SIGWINCH: +	el_resize(sel); +	break; + +    default: +	tty_cookedmode(sel); +	break; +    } + +    for (i = 0; sighdl[i] != -1; i++)  +	if (signo == sighdl[i]) +	    break; + +    (void) signal(signo, sel->el_signal[i]); +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +    (void) kill(0, signo); +} + + +/* sig_init(): + *	Initialize all signal stuff + */ +protected int +sig_init(el) +    EditLine *el; +{ +    int i; +    sigset_t nset, oset; + +    (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, SIGWINCH); +    ALLSIGS +#undef _DO +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(sig_t)) + +    el->el_signal = (sig_t *) el_malloc(SIGSIZE); +    for (i = 0; sighdl[i] != -1; i++)  +	el->el_signal[i] = SIG_ERR; + +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); + +    return 0; +} + + +/* sig_end(): + *	Clear all signal stuff + */ +protected void +sig_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_signal); +    el->el_signal = NULL; +} + + +/* sig_set(): + *	set all the signal handlers + */ +protected void +sig_set(el) +    EditLine *el; +{ +    int i; +    sigset_t nset, oset; + +    (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, SIGWINCH); +    ALLSIGS +#undef _DO +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    for (i = 0; sighdl[i] != -1; i++) { +	sig_t s; +	/* This could happen if we get interrupted */ +	if ((s = signal(sighdl[i], sig_handler)) != sig_handler) +	    el->el_signal[i] = s; +    } +    sel = el; +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +} + + +/* sig_clr(): + *	clear all the signal handlers + */ +protected void +sig_clr(el) +    EditLine *el; +{ +    int i; +    sigset_t nset, oset; + +    (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, SIGWINCH); +    ALLSIGS +#undef _DO +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    for (i = 0; sighdl[i] != -1; i++)  +	if (el->el_signal[i] != SIG_ERR) +	    (void) signal(sighdl[i], el->el_signal[i]); + +    sel = NULL;	/* we are going to die if the handler is called */ +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +} diff --git a/sig.h b/sig.h new file mode 100644 index 0000000000000..bb05def180606 --- /dev/null +++ b/sig.h @@ -0,0 +1,72 @@ +/*	$NetBSD: sig.h,v 1.2 1997/01/11 06:48:11 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. + * + *	@(#)sig.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.sig.h: Signal handling functions + */ +#ifndef _h_el_sig +#define _h_el_sig + +#include <signal.h> + +#include "histedit.h" + +/* + * Define here all the signals we are going to handle + * The _DO macro is used to iterate in the source code + */ +#define ALLSIGS 	\ +    _DO(SIGINT)		\ +    _DO(SIGTSTP)	\ +    _DO(SIGSTOP)	\ +    _DO(SIGQUIT)	\ +    _DO(SIGHUP)		\ +    _DO(SIGTERM)	\ +    _DO(SIGCONT)	\ +    _DO(SIGWINCH) + +typedef sig_t *el_signal_t; + +protected void	sig_end		__P((EditLine*)); +protected int	sig_init	__P((EditLine*)); +protected void	sig_set		__P((EditLine*)); +protected void	sig_clr		__P((EditLine*)); + +#endif /* _h_el_sig */ diff --git a/sys.h b/sys.h new file mode 100644 index 0000000000000..637b6a332d7ac --- /dev/null +++ b/sys.h @@ -0,0 +1,118 @@ +/*	$NetBSD: sys.h,v 1.3 1997/01/11 06:48:12 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. + * + *	@(#)sys.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * sys.h: Put all the stupid compiler and system dependencies here... + */ +#ifndef _h_sys +#define _h_sys + +#ifndef public +# define public		/* Externally visible functions/variables */ +#endif + +#ifndef private +# define private	static	/* Always hidden internals */ +#endif + +#ifndef protected +# define protected	/* Redefined from elsewhere to "static" */ +			/* When we want to hide everything	*/ +#endif + +#include <sys/cdefs.h> + +#ifndef _PTR_T +# define _PTR_T +# if __STDC__ +typedef void* ptr_t; +# else +typedef char* ptr_t; +# endif +#endif + +#ifndef _IOCTL_T +# define _IOCTL_T +# if __STDC__ +typedef void* ioctl_t; +# else +typedef char* ioctl_t; +# endif +#endif + +#include <stdio.h> + +#define	REGEX		/* Use POSIX.2 regular expression functions */ +#undef	REGEXP		/* Use UNIX V8 regular expression functions */ + +#ifdef SUNOS +# undef REGEX +# undef REGEXP +# include <malloc.h> +typedef void (*sig_t)__P((int)); +# ifdef __GNUC__ +/* + * Broken hdrs. + */ +extern char    *getenv		__P((const char *)); +extern int	fprintf		__P((FILE *, const char *, ...)); +extern int	sigsetmask	__P((int)); +extern int	sigblock	__P((int)); +extern int	ioctl		__P((int, int, void *)); +extern int	fputc		__P((int, FILE *)); +extern int	fgetc		__P((FILE *)); +extern int	fflush		__P((FILE *)); +extern int	tolower		__P((int)); +extern int	toupper		__P((int)); +extern int	errno, sys_nerr; +extern char	*sys_errlist[]; +extern void	perror		__P((const char *)); +extern int	read		__P((int, const char*, int)); +#  include <string.h> +#  define strerror(e)	sys_errlist[e] +# endif +# ifdef SABER +extern ptr_t    memcpy		__P((ptr_t, const ptr_t, size_t)); +extern ptr_t    memset		__P((ptr_t, int, size_t)); +# endif +extern char    *fgetline	__P((FILE *, int *)); +#endif + +#endif /* _h_sys */ diff --git a/term.c b/term.c new file mode 100644 index 0000000000000..6e3670d8bfccd --- /dev/null +++ b/term.c @@ -0,0 +1,1465 @@ +/*	$NetBSD: term.c,v 1.9 1997/04/11 22:40:06 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)term.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: term.c,v 1.9 1997/04/11 22:40:06 christos Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * term.c: Editor/termcap-curses interface + *	   We have to declare a static variable here, since the + *	   termcap putchar routine does not take an argument! + */ +#include "sys.h" +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "termcap.h"	/* XXX: should be <termcap.h> */ +#include <sys/types.h> + +#include "el.h" + +/* + * IMPORTANT NOTE: these routines are allowed to look at the current screen + * and the current possition assuming that it is correct.  If this is not + * true, then the update will be WRONG!  This is (should be) a valid + * assumption... + */ + +#define TC_BUFSIZE 2048 + +#define GoodStr(a) (el->el_term.t_str[a] != NULL && \ +		    el->el_term.t_str[a][0] != '\0') +#define Str(a) el->el_term.t_str[a] +#define Val(a) el->el_term.t_val[a] + +#ifdef notdef +private struct { +    char   *b_name; +    int     b_rate; +} baud_rate[] = { +#ifdef B0 +    { "0", B0 }, +#endif +#ifdef B50 +    { "50", B50 }, +#endif +#ifdef B75 +    { "75", B75 }, +#endif +#ifdef B110 +    { "110", B110 }, +#endif +#ifdef B134 +    { "134", B134 }, +#endif +#ifdef B150 +    { "150", B150 }, +#endif +#ifdef B200 +    { "200", B200 }, +#endif +#ifdef B300 +    { "300", B300 }, +#endif +#ifdef B600 +    { "600", B600 }, +#endif +#ifdef B900 +    { "900", B900 }, +#endif +#ifdef B1200 +    { "1200", B1200 }, +#endif +#ifdef B1800 +    { "1800", B1800 }, +#endif +#ifdef B2400 +    { "2400", B2400 }, +#endif +#ifdef B3600 +    { "3600", B3600 }, +#endif +#ifdef B4800 +    { "4800", B4800 }, +#endif +#ifdef B7200 +    { "7200", B7200 }, +#endif +#ifdef B9600 +    { "9600", B9600 }, +#endif +#ifdef EXTA +    { "19200", EXTA }, +#endif +#ifdef B19200 +    { "19200", B19200 }, +#endif +#ifdef EXTB +    { "38400", EXTB }, +#endif +#ifdef B38400 +    { "38400", B38400 }, +#endif +    { NULL, 0 } +}; +#endif + +private struct termcapstr { +    char   *name; +    char   *long_name; +} tstr[] = { + +#define T_al	0 +    {	"al",	"add new blank line"		}, +#define T_bl	1 +    {	"bl",	"audible bell"			}, +#define T_cd	2 +    {	"cd",	"clear to bottom"		}, +#define T_ce	3 +    {	"ce",	"clear to end of line"		}, +#define T_ch	4 +    {	"ch",	"cursor to horiz pos"		}, +#define T_cl	5 +    {	"cl",	"clear screen"			}, +#define	T_dc	6 +    {	"dc",	"delete a character"		}, +#define	T_dl	7 +    {	"dl",	"delete a line"		 	}, +#define	T_dm	8 +    {	"dm",	"start delete mode"		}, +#define	T_ed	9 +    {	"ed",	"end delete mode"		}, +#define	T_ei	10 +    {	"ei",	"end insert mode"		}, +#define	T_fs	11 +    {	"fs",	"cursor from status line"	}, +#define	T_ho	12 +    {	"ho",	"home cursor"			}, +#define	T_ic	13 +    {	"ic",	"insert character"		}, +#define	T_im	14  +    {	"im",	"start insert mode"		}, +#define	T_ip	15 +    {	"ip",	"insert padding"		}, +#define	T_kd	16 +    {	"kd",	"sends cursor down"		}, +#define	T_kl	17 +    {	"kl",	"sends cursor left"		}, +#define T_kr	18 +    {	"kr",	"sends cursor right"		}, +#define T_ku	19 +    {	"ku",	"sends cursor up"		}, +#define T_md	20 +    {	"md",	"begin bold"			}, +#define T_me	21 +    {	"me",	"end attributes"		}, +#define T_nd	22 +    {	"nd",	"non destructive space"	 	}, +#define T_se	23 +    {	"se",	"end standout"			}, +#define T_so	24 +    {	"so",	"begin standout"		}, +#define T_ts	25 +    {	"ts",	"cursor to status line"	 	}, +#define T_up	26 +    {	"up",	"cursor up one"		 	}, +#define T_us	27 +    {	"us",	"begin underline"		}, +#define T_ue	28 +    {	"ue",	"end underline"		 	}, +#define T_vb	29 +    {	"vb",	"visible bell"			}, +#define T_DC	30 +    {	"DC",	"delete multiple chars"	 	}, +#define T_DO	31 +    {	"DO",	"cursor down multiple"		}, +#define T_IC	32 +    {	"IC",	"insert multiple chars"	 	}, +#define T_LE	33 +    {	"LE",	"cursor left multiple"		}, +#define T_RI	34 +    {	"RI",	"cursor right multiple"	 	}, +#define T_UP	35 +    {	"UP",	"cursor up multiple"		}, +#define T_str	36 +    {	NULL,   NULL			 	} +}; + +private struct termcapval { +    char   *name; +    char   *long_name; +} tval[] = { +#define T_pt	0 +    {	"pt",	"has physical tabs"	}, +#define T_li	1 +    {	"li",	"Number of lines"	}, +#define T_co	2 +    {	"co",	"Number of columns"	}, +#define T_km	3 +    {	"km",	"Has meta key"		}, +#define T_xt	4 +    {	"xt",	"Tab chars destructive" }, +#define T_MT	5 +    {	"MT",	"Has meta key"		},	/* XXX? */ +#define T_val	6 +    {	NULL, 	NULL,			} +}; + +/* do two or more of the attributes use me */ + +private	void	term_rebuffer_display	__P((EditLine *)); +private	void	term_free_display	__P((EditLine *)); +private	void	term_alloc_display	__P((EditLine *)); +private	void	term_alloc		__P((EditLine *, +					     struct termcapstr *, char *));  +private void	term_init_arrow		__P((EditLine *)); +private void	term_reset_arrow	__P((EditLine *)); + + +private FILE *term_outfile = NULL;	/* XXX: How do we fix that? */ + + +/* term_setflags(): + *	Set the terminal capability flags + */ +private void +term_setflags(el) +    EditLine *el; +{ +    EL_FLAGS = 0; +    if (el->el_tty.t_tabs)  +	EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; + +    EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; +    EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; +    EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; +    EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? +		 TERM_CAN_INSERT : 0; +    EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP))  ? TERM_CAN_UP : 0; + +    if (GoodStr(T_me) && GoodStr(T_ue)) +	EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? TERM_CAN_ME : 0; +    else +	EL_FLAGS &= ~TERM_CAN_ME; +    if (GoodStr(T_me) && GoodStr(T_se)) +	EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? TERM_CAN_ME : 0; + + +#ifdef DEBUG_SCREEN +    if (!EL_CAN_UP) { +	(void) fprintf(el->el_errfile, "WARNING: Your terminal cannot move up.\n"); +	(void) fprintf(el->el_errfile, "Editing may be odd for long lines.\n"); +    } +    if (!EL_CAN_CEOL) +	(void) fprintf(el->el_errfile, "no clear EOL capability.\n"); +    if (!EL_CAN_DELETE) +	(void) fprintf(el->el_errfile, "no delete char capability.\n"); +    if (!EL_CAN_INSERT) +	(void) fprintf(el->el_errfile, "no insert char capability.\n"); +#endif /* DEBUG_SCREEN */ +} + + +/* term_init(): + *	Initialize the terminal stuff + */ +protected int +term_init(el) +    EditLine *el; +{ +    el->el_term.t_buf = (char *)  el_malloc(TC_BUFSIZE); +    el->el_term.t_cap = (char *)  el_malloc(TC_BUFSIZE); +    el->el_term.t_fkey = (fkey_t *) el_malloc(4 * sizeof(fkey_t)); +    el->el_term.t_loc = 0; +    el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char*)); +    (void) memset(el->el_term.t_str, 0, T_str * sizeof(char*)); +    el->el_term.t_val = (int *)   el_malloc(T_val * sizeof(int)); +    (void) memset(el->el_term.t_val, 0, T_val * sizeof(char*)); +    term_outfile = el->el_outfile; +    (void) term_set(el, NULL); +    term_init_arrow(el); +    return 0; +} + +/* term_end(): + *	Clean up the terminal stuff + */ +protected void +term_end(el) +    EditLine *el; +{ +    el_free((ptr_t) el->el_term.t_buf); +    el->el_term.t_buf = NULL; +    el_free((ptr_t) el->el_term.t_cap); +    el->el_term.t_cap = NULL; +    el->el_term.t_loc = 0; +    el_free((ptr_t) el->el_term.t_str); +    el->el_term.t_str = NULL; +    el_free((ptr_t) el->el_term.t_val); +    el->el_term.t_val = NULL; +    term_free_display(el); +} + + +/* term_alloc(): + *	Maintain a string pool for termcap strings + */ +private void +term_alloc(el, t, cap) +    EditLine *el; +    struct termcapstr *t; +    char   *cap; +{ +    char    termbuf[TC_BUFSIZE]; +    int     tlen, clen; +    char    **tlist = el->el_term.t_str; +    char    **tmp, **str = &tlist[t - tstr]; + +    if (cap == NULL || *cap == '\0') { +	*str = NULL; +	return; +    } +    else +	clen = strlen(cap); + +    tlen  = *str == NULL ? 0 : strlen(*str); + +    /* +     * New string is shorter; no need to allocate space +     */ +    if (clen <= tlen) { +	(void)strcpy(*str, cap);	/* XXX strcpy is safe */ +	return; +    } + +    /* +     * New string is longer; see if we have enough space to append +     */ +    if (el->el_term.t_loc + 3 < TC_BUFSIZE) { +	/* XXX strcpy is safe */ +	(void)strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); +	el->el_term.t_loc += clen + 1;	/* one for \0 */ +	return; +    } + +    /* +     * Compact our buffer; no need to check compaction, cause we know it +     * fits... +     */ +    tlen = 0; +    for (tmp = tlist; tmp < &tlist[T_str]; tmp++) +	if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { +	    char   *ptr; + +	    for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) +		continue; +	    termbuf[tlen++] = '\0'; +	} +    memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); +    el->el_term.t_loc = tlen; +    if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { +	(void) fprintf(el->el_errfile, "Out of termcap string space.\n"); +	return; +    } +    /* XXX strcpy is safe */ +    (void)strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); +    el->el_term.t_loc += clen + 1;		/* one for \0 */ +    return; +} /* end term_alloc */ + + +/* term_rebuffer_display(): + *	Rebuffer the display after the screen changed size + */ +private void +term_rebuffer_display(el) +    EditLine *el; +{ +    coord_t *c = &el->el_term.t_size; + +    term_free_display(el); + +    /* make this public, -1 to avoid wraps */ +    c->h = Val(T_co) - 1; +    c->v = (EL_BUFSIZ * 4) / c->h + 1; + +    term_alloc_display(el); +} /* end term_rebuffer_display */ + + +/* term_alloc_display(): + *	Allocate a new display. + */ +private void +term_alloc_display(el) +    EditLine *el; +{ +    int i; +    char  **b; +    coord_t *c = &el->el_term.t_size; + +    b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); +    for (i = 0; i < c->v; i++) +	b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); +    b[c->v] = NULL; +    el->el_display = b; + +    b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); +    for (i = 0; i < c->v; i++) +	b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); +    b[c->v] = NULL; +    el->el_vdisplay = b; + +} /* end term_alloc_display */ + + +/* term_free_display(): + *	Free the display buffers + */ +private void +term_free_display(el) +    EditLine *el; +{ +    char  **b; +    char  **bufp; + +    b = el->el_display; +    el->el_display = NULL; +    if (b != NULL) { +	for (bufp = b; *bufp != NULL; bufp++) +	    el_free((ptr_t) *bufp); +	el_free((ptr_t) b); +    } +    b = el->el_vdisplay; +    el->el_vdisplay = NULL; +    if (b != NULL) { +	for (bufp = b; *bufp != NULL; bufp++) +	    el_free((ptr_t) * bufp); +	el_free((ptr_t) b); +    } +} /* end term_free_display */ + + +/* term_move_to_line(): + *	move to line <where> (first line == 0) + * 	as efficiently as possible + */ +protected void +term_move_to_line(el, where) +    EditLine *el; +    int     where;		 +{ +    int     del, i; + +    if (where == el->el_cursor.v) +	return; + +    if (where > el->el_term.t_size.v) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_move_to_line: where is ridiculous: %d\r\n", where); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if ((del = where - el->el_cursor.v) > 0) { +	if ((del > 1) && GoodStr(T_DO)) +	    (void) tputs(tgoto(Str(T_DO), del, del), del, term__putc); +	else { +	    for (i = 0; i < del; i++) +		term__putc('\n'); +	    el->el_cursor.h = 0;	/* because the \n will become \r\n */ +	} +    } +    else {			/* del < 0 */ +	if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) +	    (void) tputs(tgoto(Str(T_UP), -del, -del), -del, term__putc); +	else { +	    if (GoodStr(T_up)) +		for (i = 0; i < -del; i++) +		    (void) tputs(Str(T_up), 1, term__putc); +	} +    } +    el->el_cursor.v = where;		/* now where is here */ +} /* end term_move_to_line */ + + +/* term_move_to_char(): + *	Move to the character position specified + */ +protected void +term_move_to_char(el, where) +    EditLine *el; +    int     where; +{ +    int     del, i; + +mc_again: +    if (where == el->el_cursor.h) +	return; + +    if (where > (el->el_term.t_size.h + 1)) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_move_to_char: where is riduculous: %d\r\n", where); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (!where) {		/* if where is first column */ +	term__putc('\r');	/* do a CR */ +	el->el_cursor.h = 0; +	return; +    } + +    del = where - el->el_cursor.h; + +    if ((del < -4 || del > 4) && GoodStr(T_ch)) +	/* go there directly */ +	(void) tputs(tgoto(Str(T_ch), where, where), where, term__putc); +    else { +	if (del > 0) {		/* moving forward */ +	    if ((del > 4) && GoodStr(T_RI)) +		(void) tputs(tgoto(Str(T_RI), del, del), del, term__putc); +	    else { +		if (EL_CAN_TAB) {	/* if I can do tabs, use them */ +		    if ((el->el_cursor.h & 0370) != (where & 0370)) { +			/* if not within tab stop */ +			for (i = (el->el_cursor.h & 0370);  +			     i < (where & 0370); i += 8) +			    term__putc('\t');	/* then tab over */ +			el->el_cursor.h = where & 0370; +		    } +		} +		/* it's usually cheaper to just write the chars, so we do. */ + +		/* NOTE THAT term_overwrite() WILL CHANGE el->el_cursor.h!!! */ +		term_overwrite(el,  +			&el->el_display[el->el_cursor.v][el->el_cursor.h],  +		        where - el->el_cursor.h); + +	    } +	} +	else {			/* del < 0 := moving backward */ +	    if ((-del > 4) && GoodStr(T_LE)) +		(void) tputs(tgoto(Str(T_LE), -del, -del), -del, term__putc); +	    else {		/* can't go directly there */ +		/* if the "cost" is greater than the "cost" from col 0 */ +		if (EL_CAN_TAB ? (-del > ((where >> 3) + (where & 07))) +		    : (-del > where)) { +		    term__putc('\r');	/* do a CR */ +		    el->el_cursor.h = 0; +		    goto mc_again;	/* and try again */ +		} +		for (i = 0; i < -del; i++) +		    term__putc('\b'); +	    } +	} +    } +    el->el_cursor.h = where;		/* now where is here */ +} /* end term_move_to_char */ + + +/* term_overwrite(): + *	Overstrike num characters + */ +protected void +term_overwrite(el, cp, n) +    EditLine *el; +    char *cp; +    int n; +{ +    if (n <= 0) +	return;			/* catch bugs */ + +    if (n > (el->el_term.t_size.h + 1)) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile, "term_overwrite: n is riduculous: %d\r\n", n); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    do { +	term__putc(*cp++); +	el->el_cursor.h++; +    } while (--n); +} /* end term_overwrite */ + + +/* term_deletechars(): + *	Delete num characters + */ +protected void +term_deletechars(el, num) +    EditLine *el; +    int     num; +{ +    if (num <= 0) +	return; + +    if (!EL_CAN_DELETE) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "   ERROR: cannot delete   \n"); +#endif /* DEBUG_EDIT */ +	return; +    } + +    if (num > el->el_term.t_size.h) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile,  +		"term_deletechars: num is riduculous: %d\r\n", num); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (GoodStr(T_DC))		/* if I have multiple delete */ +	if ((num > 1) || !GoodStr(T_dc)) {	/* if dc would be more expen. */ +	    (void) tputs(tgoto(Str(T_DC), num, num), num, term__putc); +	    return; +	} + +    if (GoodStr(T_dm))		/* if I have delete mode */ +	(void) tputs(Str(T_dm), 1, term__putc); + +    if (GoodStr(T_dc))		/* else do one at a time */ +	while (num--) +	    (void) tputs(Str(T_dc), 1, term__putc); + +    if (GoodStr(T_ed))		/* if I have delete mode */ +	(void) tputs(Str(T_ed), 1, term__putc); +} /* end term_deletechars */ + + +/* term_insertwrite(): + *	Puts terminal in insert character mode or inserts num  + *	characters in the line  + */ +protected void +term_insertwrite(el, cp, num)	 +    EditLine *el; +    char *cp; +    int num; +{ +    if (num <= 0) +	return; +    if (!EL_CAN_INSERT) { +#ifdef DEBUG_EDIT +	(void) fprintf(el->el_errfile, "   ERROR: cannot insert   \n"); +#endif /* DEBUG_EDIT */ +	return; +    } + +    if (num > el->el_term.t_size.h) { +#ifdef DEBUG_SCREEN +	(void) fprintf(el->el_errfile, "StartInsert: num is riduculous: %d\r\n", num); +#endif /* DEBUG_SCREEN */ +	return; +    } + +    if (GoodStr(T_IC))		/* if I have multiple insert */ +	if ((num > 1) || !GoodStr(T_ic)) {	/* if ic would be more expen. */ +	    (void) tputs(tgoto(Str(T_IC), num, num), num, term__putc); +	    term_overwrite(el, cp, num);	/* this updates el_cursor.h */ +	    return; +	} + +    if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ +	(void) tputs(Str(T_im), 1, term__putc); + +	el->el_cursor.h += num; +	do  +	    term__putc(*cp++); +	while (--num); + +	if (GoodStr(T_ip))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ip), 1, term__putc); + +	(void) tputs(Str(T_ei), 1, term__putc); +	return; +    } + +    do { +	if (GoodStr(T_ic))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ic), 1, term__putc);	/* insert a char */ + +	term__putc(*cp++); + +	el->el_cursor.h++; + +	if (GoodStr(T_ip))	/* have to make num chars insert */ +	    (void) tputs(Str(T_ip), 1, term__putc);/* pad the inserted char */ + +    } while (--num); +} /* end term_insertwrite */ + + +/* term_clear_EOL(): + *	clear to end of line.  There are num characters to clear  + */ +protected void +term_clear_EOL(el, num)	 +    EditLine *el; +    int     num; +{ +    int i; + +    if (EL_CAN_CEOL && GoodStr(T_ce)) +	(void) tputs(Str(T_ce), 1, term__putc); +    else { +	for (i = 0; i < num; i++) +	    term__putc(' '); +	el->el_cursor.h += num;		/* have written num spaces */ +    } +} /* end term_clear_EOL */ + + +/* term_clear_screen(): + *	Clear the screen  + */ +protected void +term_clear_screen(el) +    EditLine *el; +{				/* clear the whole screen and home */ +    if (GoodStr(T_cl)) +	/* send the clear screen code */ +	(void) tputs(Str(T_cl), Val(T_li), term__putc); +    else if (GoodStr(T_ho) && GoodStr(T_cd)) { +	(void) tputs(Str(T_ho), Val(T_li), term__putc);	/* home */ +	/* clear to bottom of screen */ +	(void) tputs(Str(T_cd), Val(T_li), term__putc); +    } +    else { +	term__putc('\r'); +	term__putc('\n'); +    } +} /* end term_clear_screen */ + + +/* term_beep(): + *	Beep the way the terminal wants us + */ +protected void +term_beep(el) +    EditLine *el; +{ +    if (GoodStr(T_vb)) +	(void) tputs(Str(T_vb), 1, term__putc);	/* visible bell */ +    else if (GoodStr(T_bl)) +	/* what termcap says we should use */ +	(void) tputs(Str(T_bl), 1, term__putc); +    else +	term__putc('\007');	/* an ASCII bell; ^G */ +} /* end term_beep */ + + +#ifdef notdef +/* term_clear_to_bottom(): + *	Clear to the bottom of the screen + */ +protected void +term_clear_to_bottom(el) +    EditLine *el; +{ +    if (GoodStr(T_cd)) +	(void) tputs(Str(T_cd), Val(T_li), term__putc); +    else if (GoodStr(T_ce)) +	(void) tputs(Str(T_ce), Val(T_li), term__putc); +} /* end term_clear_to_bottom */ +#endif + + +/* term_set(): + *	Read in the terminal capabilities from the requested terminal + */ +protected int +term_set(el, term) +    EditLine *el; +    char *term; +{ +    int i; +    char    buf[TC_BUFSIZE]; +    char   *area; +    struct termcapstr *t; +    sigset_t oset, nset; +    int     lins, cols; + +    (void) sigemptyset(&nset); +    (void) sigaddset(&nset, SIGWINCH); +    (void) sigprocmask(SIG_BLOCK, &nset, &oset); + +    area = buf; + + +    if (term == NULL) +	term = getenv("TERM"); + +    if (!term || !term[0]) +	term = "dumb"; + +    memset(el->el_term.t_cap, 0, TC_BUFSIZE); + +    i = tgetent(el->el_term.t_cap, term); + +    if (i <= 0) { +	if (i == -1)  +	    (void) fprintf(el->el_errfile, "Cannot read termcap database;\n"); +	else if (i == 0)  +	    (void) fprintf(el->el_errfile,  +			   "No entry for terminal type \"%s\";\n", term); +	(void) fprintf(el->el_errfile, "using dumb terminal settings.\n"); +	Val(T_co) = 80;		/* do a dumb terminal */ +	Val(T_pt) = Val(T_km) = Val(T_li) = 0; +	Val(T_xt) = Val(T_MT); +	for (t = tstr; t->name != NULL; t++) +	    term_alloc(el, t, NULL); +    } +    else { +	/* Can we tab */ +	Val(T_pt) = tgetflag("pt"); +	Val(T_xt) = tgetflag("xt"); +	/* do we have a meta? */ +	Val(T_km) = tgetflag("km"); +	Val(T_MT) = tgetflag("MT"); +	/* 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)); +    } + +    if (Val(T_co) < 2) +	Val(T_co) = 80;		/* just in case */ +    if (Val(T_li) < 1) +	Val(T_li) = 24; + +    el->el_term.t_size.v = Val(T_co); +    el->el_term.t_size.h = Val(T_li); + +    term_setflags(el); + +    (void) term_get_size(el, &lins, &cols);/* get the correct window size */ +    term_change_size(el, lins, cols); +    (void) sigprocmask(SIG_SETMASK, &oset, NULL); +    term_bind_arrow(el); +    return i <= 0 ? -1 : 0; +} /* end term_set */ + + +/* term_get_size(): + *	Return the new window size in lines and cols, and + *	true if the size was changed.  + */ +protected int +term_get_size(el, lins, cols) +    EditLine *el; +    int    *lins, *cols; +{ + +    *cols = Val(T_co); +    *lins = Val(T_li); + +#ifdef TIOCGWINSZ +    { +	struct winsize ws; +	if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) &ws) != -1) { +	    if (ws.ws_col) +		*cols = ws.ws_col; +	    if (ws.ws_row) +		*lins = ws.ws_row; +	} +    } +#endif +#ifdef TIOCGSIZE +    { +	struct ttysize ts; +	if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) &ts) != -1) { +	    if (ts.ts_cols) +		*cols = ts.ts_cols; +	    if (ts.ts_lines) +		*lins = ts.ts_lines; +	} +    } +#endif +    return (Val(T_co) != *cols || Val(T_li) != *lins); +} /* end term_get_size */ + + +/* term_change_size(): + *	Change the size of the terminal + */ +protected void +term_change_size(el, lins, cols) +    EditLine *el; +    int     lins, cols; +{ +    /* +     * Just in case +     */ +    Val(T_co) = (cols < 2) ? 80 : cols; +    Val(T_li) = (lins < 1) ? 24 : lins; + +    term_rebuffer_display(el);		/* re-make display buffers */ +    re_clear_display(el); +} /* end term_change_size */ + + +/* term_init_arrow(): + *	Initialize the arrow key bindings from termcap + */ +private void +term_init_arrow(el) +    EditLine *el; +{ +    fkey_t *arrow = el->el_term.t_fkey; + +    arrow[A_K_DN].name    = "down"; +    arrow[A_K_DN].key	  = T_kd; +    arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; +    arrow[A_K_DN].type    = XK_CMD; + +    arrow[A_K_UP].name    = "up"; +    arrow[A_K_UP].key	  = T_ku; +    arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; +    arrow[A_K_UP].type    = XK_CMD; + +    arrow[A_K_LT].name    = "left"; +    arrow[A_K_LT].key	  = T_kl; +    arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; +    arrow[A_K_LT].type    = XK_CMD; + +    arrow[A_K_RT].name    = "right"; +    arrow[A_K_RT].key	  = T_kr; +    arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; +    arrow[A_K_RT].type    = XK_CMD; + +} + + +/* term_reset_arrow(): + *	Reset arrow key bindings + */ +private void +term_reset_arrow(el)  +    EditLine *el; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    static char strA[] = {033, '[', 'A', '\0'}; +    static char strB[] = {033, '[', 'B', '\0'}; +    static char strC[] = {033, '[', 'C', '\0'}; +    static char strD[] = {033, '[', 'D', '\0'}; +    static char stOA[] = {033, 'O', 'A', '\0'}; +    static char stOB[] = {033, 'O', 'B', '\0'}; +    static char stOC[] = {033, 'O', 'C', '\0'}; +    static char stOD[] = {033, 'O', 'D', '\0'}; + +    key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); +    key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); +    key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); +    key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); +    key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); +    key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); +    key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); +    key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + +    if (el->el_map.type == MAP_VI) { +	key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); +	key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); +	key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); +	key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); +	key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); +	key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); +	key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); +	key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); +    } +} + + +/* term_set_arrow(): + *	Set an arrow key binding + */ +protected int +term_set_arrow(el, name, fun, type) +    EditLine *el; +    char *name; +    key_value_t *fun; +    int type; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    int i; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (strcmp(name, arrow[i].name) == 0) { +	    arrow[i].fun  = *fun; +	    arrow[i].type = type; +	    return 0; +	} +    return -1; +} + + +/* term_clear_arrow(): + *	Clear an arrow key binding + */ +protected int +term_clear_arrow(el, name) +    EditLine *el; +    char *name; +{ +    fkey_t *arrow = el->el_term.t_fkey; +    int i; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (strcmp(name, arrow[i].name) == 0) { +	    arrow[i].type = XK_NOD; +	    return 0; +	} +    return -1; +} + + +/* term_print_arrow(): + *	Print the arrow key bindings + */ +protected void +term_print_arrow(el, name) +    EditLine *el; +    char *name; +{ +    int i; +    fkey_t *arrow = el->el_term.t_fkey; + +    for (i = 0; i < A_K_NKEYS; i++) +	if (*name == '\0' || strcmp(name, arrow[i].name) == 0) +	    if (arrow[i].type != XK_NOD) +		key_kprint(el, arrow[i].name, &arrow[i].fun, arrow[i].type); +} + + +/* term_bind_arrow(): + *	Bind the arrow keys + */ +protected void +term_bind_arrow(el) +    EditLine *el; +{ +    el_action_t *map, *dmap; +    int     i, j; +    char   *p; +    fkey_t *arrow = el->el_term.t_fkey; + +    /* Check if the components needed are initialized */ +    if (el->el_term.t_buf == NULL || el->el_map.key == NULL) +	return; + +    map  = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; +    dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; + +    term_reset_arrow(el); + +    for (i = 0; i < 4; i++) { +	p = el->el_term.t_str[arrow[i].key]; +	if (p && *p) { +	    j = (unsigned char) *p; +	    /* +	     * Assign the arrow keys only if: +	     * +	     * 1. They are multi-character arrow keys and the user  +	     *    has not re-assigned the leading character, or  +	     *    has re-assigned the leading character to be +	     *	  ED_SEQUENCE_LEAD_IN +	     * 2. They are single arrow keys pointing to an unassigned key. +	     */ +	    if (arrow[i].type == XK_NOD) +		key_clear(el, map, p); +	    else { +		if (p[1] && (dmap[j] == map[j] ||  +			     map[j] == ED_SEQUENCE_LEAD_IN)) { +		    key_add(el, p, &arrow[i].fun, arrow[i].type); +		    map[j] = ED_SEQUENCE_LEAD_IN; +		} +		else if (map[j] == ED_UNASSIGNED) { +		    key_clear(el, map, p); +		    if (arrow[i].type == XK_CMD) +			map[j] = arrow[i].fun.cmd; +		    else +			key_add(el, p, &arrow[i].fun, arrow[i].type); +		} +	    } +	} +    } +} + + +/* term__putc(): + *	Add a character + */ +protected void +term__putc(c) +    int c; +{ +    (void) fputc(c, term_outfile); +} /* end term__putc */ + + +/* term__flush(): + *	Flush output + */ +protected void +term__flush() +{ +    (void) fflush(term_outfile); +} /* end term__flush */ + + +/* term_telltc(): + *	Print the current termcap characteristics + */ +protected int +/*ARGSUSED*/ +term_telltc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    struct termcapstr *t; +    char **ts; +    char upbuf[EL_BUFSIZ]; + +    (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); +    (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); +    (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", +	    Val(T_co), Val(T_li)); +    (void) fprintf(el->el_outfile,  +		   "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); +    (void) fprintf(el->el_outfile,  +		   "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); +#ifdef notyet +    (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n",  +		   (T_Margin&MARGIN_AUTO)? "has": "does not have"); +    if (T_Margin & MARGIN_AUTO) +	(void) fprintf(el->el_outfile, "\tIt %s magic margins\n",  +			(T_Margin&MARGIN_MAGIC)?"has":"does not have"); +#endif + +    for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) +	(void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name,  +		       t->name, *ts && **ts ?  +			key__decode_str(*ts, upbuf, "") : "(empty)"); +    (void) fputc('\n', el->el_outfile); +    return 0; +} + + +/* term_settc(): + *	Change the current terminal characteristics + */ +protected int +/*ARGSUSED*/ +term_settc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    struct termcapstr *ts; +    struct termcapval *tv; +    char   *what, *how; + +    if (argv == NULL || argv[1] == NULL || argv[2] == NULL) +	return -1; + +    what = argv[1]; +    how = argv[2]; + +    /* +     * Do the strings first +     */ +    for (ts = tstr; ts->name != NULL; ts++) +	if (strcmp(ts->name, what) == 0) +	    break; + +    if (ts->name != NULL) { +	term_alloc(el, ts, how); +	term_setflags(el); +	return 0; +    } + +    /* +     * Do the numeric ones second +     */ +    for (tv = tval; tv->name != NULL; tv++) +	if (strcmp(tv->name, what) == 0) +	    break; + +    if (tv->name != NULL) { +	if (tv == &tval[T_pt] || tv == &tval[T_km]  +#ifdef notyet +	    || tv == &tval[T_am] || tv == &tval[T_xn] +#endif +	    ) { +	    if (strcmp(how, "yes") == 0) +		el->el_term.t_val[tv - tval] = 1; +	    else if (strcmp(how, "no") == 0) +		el->el_term.t_val[tv - tval] = 0; +	    else { +		(void) fprintf(el->el_errfile, "settc: Bad value `%s'.\n", how); +		return -1; +	    } +	    term_setflags(el); +	    term_change_size(el, Val(T_li), Val(T_co)); +	    return 0; +	} +	else { +	    el->el_term.t_val[tv - tval] = atoi(how); +	    el->el_term.t_size.v = Val(T_co); +	    el->el_term.t_size.h = Val(T_li); +	    if (tv == &tval[T_co] || tv == &tval[T_li]) +		term_change_size(el, Val(T_li), Val(T_co)); +	    return 0; +	} +    } +    return -1; +} + + +/* term_echotc(): + *	Print the termcap string out with variable substitution + */ +protected int +/*ARGSUSED*/ +term_echotc(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    char   *cap, *scap; +    int     arg_need, arg_cols, arg_rows; +    int     verbose = 0, silent = 0; +    char   *area; +    static char *fmts = "%s\n", *fmtd = "%d\n"; +    struct termcapstr *t; +    char    buf[TC_BUFSIZE]; + +    area = buf; + +    if (argv == NULL || argv[1] == NULL) +	return -1; +    argv++; + +    if (argv[0][0] == '-') { +	switch (argv[0][1]) { +	case 'v': +	    verbose = 1; +	    break; +	case 's': +	    silent = 1; +	    break; +	default: +	    /* stderror(ERR_NAME | ERR_TCUSAGE); */ +	    break; +	} +	argv++; +    } +    if (!*argv || *argv[0] == '\0') +	return 0; +    if (strcmp(*argv, "tabs") == 0) { +	(void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); +	return 0; +    } +    else if (strcmp(*argv, "meta") == 0) { +	(void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); +	return 0; +    } +#ifdef notyet +    else if (strcmp(*argv, "xn") == 0) { +	(void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_MAGIC ?  +			"yes" : "no"); +	return 0; +    } +    else if (strcmp(*argv, "am") == 0) { +	(void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_AUTO ?  +			"yes" : "no"); +	return 0; +    } +#endif +    else if (strcmp(*argv, "baud") == 0) { +#ifdef notdef +	int     i; + +	for (i = 0; baud_rate[i].b_name != NULL; i++) +	    if (el->el_tty.t_speed == baud_rate[i].b_rate) { +		(void) fprintf(el->el_outfile, fmts, baud_rate[i].b_name); +		return 0; +	    } +	(void) fprintf(el->el_outfile, fmtd, 0); +#else +	(void) fprintf(el->el_outfile, fmtd, el->el_tty.t_speed); +#endif +	return 0; +    } +    else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { +	(void) fprintf(el->el_outfile, fmtd, Val(T_li)); +	return 0; +    } +    else if (strcmp(*argv, "cols") == 0) { +	(void) fprintf(el->el_outfile, fmtd, Val(T_co)); +	return 0; +    } + +    /*  +     * Try to use our local definition first +     */ +    scap = NULL; +    for (t = tstr; t->name != NULL; t++) +	if (strcmp(t->name, *argv) == 0) { +	    scap = el->el_term.t_str[t - tstr]; +	    break; +	} +    if (t->name == NULL) +	scap = tgetstr(*argv, &area); +    if (!scap || scap[0] == '\0') { +	if (!silent) +	    (void) fprintf(el->el_errfile,  +		"echotc: Termcap parameter `%s' not found.\n", *argv); +	return -1; +    } + +    /* +     * Count home many values we need for this capability. +     */ +    for (cap = scap, arg_need = 0; *cap; cap++) +	if (*cap == '%') +	    switch (*++cap) { +	    case 'd': +	    case '2': +	    case '3': +	    case '.': +	    case '+': +		arg_need++; +		break; +	    case '%': +	    case '>': +	    case 'i': +	    case 'r': +	    case 'n': +	    case 'B': +	    case 'D': +		break; +	    default: +		/* +		 * hpux has lot's of them... +		 */ +		if (verbose) +		    (void) fprintf(el->el_errfile,  +			"echotc: Warning: unknown termcap %% `%c'.\n", *cap); +		/* This is bad, but I won't complain */ +		break; +	    } + +    switch (arg_need) { +    case 0: +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(scap, 1, term__putc); +	break; +    case 1: +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_cols = 0; +	arg_rows = atoi(*argv); +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc); +	break; +    default: +	/* This is wrong, but I will ignore it... */ +	if (verbose) +	    (void) fprintf(el->el_errfile,  +		"echotc: Warning: Too many required arguments (%d).\n",  +		arg_need); +	/*FALLTHROUGH*/ +    case 2: +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_cols = atoi(*argv); +	argv++; +	if (!*argv || *argv[0] == '\0') { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Missing argument.\n"); +	    return -1; +	} +	arg_rows = atoi(*argv); +	argv++; +	if (*argv && *argv[0]) { +	    if (!silent) +		(void) fprintf(el->el_errfile,  +		    "echotc: Warning: Extra argument `%s'.\n", *argv); +	    return -1; +	} +	(void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, term__putc); +	break; +    } +    return 0; +} diff --git a/term.h b/term.h new file mode 100644 index 0000000000000..73347cff1d2c9 --- /dev/null +++ b/term.h @@ -0,0 +1,120 @@ +/*	$NetBSD: term.h,v 1.4 1997/01/11 06:48:14 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. + * + *	@(#)term.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.term.h: Termcap header + */ +#ifndef _h_el_term +#define _h_el_term + +#include "histedit.h" + +typedef struct {	/* Symbolic function key bindings	*/ +    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 { +    coord_t t_size;			/* # lines and cols	*/ +    bool_t  t_flags; +#define TERM_CAN_INSERT		0x01	/* Has insert cap	*/ +#define TERM_CAN_DELETE		0x02	/* Has delete cap	*/ +#define TERM_CAN_CEOL		0x04	/* Has CEOL cap		*/ +#define TERM_CAN_TAB		0x08	/* Can use tabs		*/ +#define TERM_CAN_ME		0x10	/* Can turn all attrs.	*/ +#define TERM_CAN_UP		0x20	/* Can move up		*/ +#define TERM_HAS_META		0x40	/* Has a meta key	*/ +    char   *t_buf;			/* Termcap buffer	*/ +    int	    t_loc;			/* location used	*/ +    char  **t_str;			/* termcap strings	*/ +    int	   *t_val;			/* termcap values	*/ +    char   *t_cap;			/* Termcap buffer	*/ +    fkey_t *t_fkey;			/* Array of keys	*/ +} el_term_t; + +/* + * fKey indexes + */ +#define A_K_DN		0 +#define A_K_UP		1 +#define A_K_LT		2 +#define A_K_RT		3 +#define A_K_NKEYS	4 + +protected void term_move_to_line	__P((EditLine *, int)); +protected void term_move_to_char	__P((EditLine *, int)); +protected void term_clear_EOL		__P((EditLine *, int)); +protected void term_overwrite		__P((EditLine *, char *, int)); +protected void term_insertwrite		__P((EditLine *, char *, int)); +protected void term_deletechars		__P((EditLine *, int)); +protected void term_clear_screen	__P((EditLine *)); +protected void term_beep		__P((EditLine *)); +protected void term_change_size		__P((EditLine *, int, int)); +protected int  term_get_size		__P((EditLine *, int *, int *)); +protected int  term_init		__P((EditLine *)); +protected void term_bind_arrow		__P((EditLine *)); +protected void term_print_arrow		__P((EditLine *, char *)); +protected int  term_clear_arrow		__P((EditLine *, char *)); +protected int  term_set_arrow		__P((EditLine *, char *,  +					     key_value_t *, int)); +protected void term_end			__P((EditLine *)); +protected int  term_set			__P((EditLine *, char *)); +protected int  term_settc		__P((EditLine *, int, char **)); +protected int  term_telltc		__P((EditLine *, int, char **)); +protected int  term_echotc		__P((EditLine *, int, char **)); + +protected void term__putc		__P((int)); +protected void term__flush		__P((void)); + +/* + * Easy access macros + */ +#define EL_FLAGS	(el)->el_term.t_flags + +#define EL_CAN_INSERT	(EL_FLAGS & TERM_CAN_INSERT) +#define EL_CAN_DELETE	(EL_FLAGS & TERM_CAN_DELETE) +#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_HAS_META	(EL_FLAGS & TERM_HAS_META) + +#endif /* _h_el_term */ diff --git a/termcap.h b/termcap.h new file mode 100644 index 0000000000000..6b6faacfa32ce --- /dev/null +++ b/termcap.h @@ -0,0 +1,54 @@ +/*	$NetBSD: termcap.h,v 1.2 1997/01/11 06:48:14 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. + * + *	@(#)termcap.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * termcap.h: I cannot find those in any include files... + */ +#ifndef _h_termcap +#define _h_termcap + +int   tgetent	__P((char *, char *)); +char *tgetstr	__P((char *, char **)); +int   tgetflag	__P((char *)); +int   tgetnum	__P((char *)); +char *tgoto	__P((char *, int, int)); +char *tputs	__P((char *, int, void (*)(int))); + +#endif /* _h_termcap */ diff --git a/tokenizer.c b/tokenizer.c new file mode 100644 index 0000000000000..49ebf08e61731 --- /dev/null +++ b/tokenizer.c @@ -0,0 +1,391 @@ +/*	$NetBSD: tokenizer.c,v 1.2 1997/01/11 06:48:15 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)tokenizer.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: tokenizer.c,v 1.2 1997/01/11 06:48:15 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * tokenize.c: Bourne shell like tokenizer + */ +#include "sys.h" +#include <string.h> +#include <stdlib.h> +#include "tokenizer.h" + +typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone } quote_t; + +#define IFS "\t \n" + +#define TOK_KEEP	1 +#define TOK_EAT		2 + +#define WINCR 20 +#define AINCR 10 + +#define tok_malloc(a)		malloc(a) +#define tok_free(a)		free(a) +#define tok_realloc(a, b)	realloc(a, b) + + +struct tokenizer { +    char   *ifs;		/* In field separator			*/ +    int     argc, amax;		/* Current and maximum number of args	*/ +    char  **argv;		/* Argument list			*/ +    char   *wptr, *wmax;	/* Space and limit on the word buffer	*/ +    char   *wstart;		/* Beginning of next word		*/ +    char   *wspace;		/* Space of word buffer			*/ +    quote_t quote;		/* Quoting state			*/ +    int	    flags;		/* flags;				*/ +}; + + +private void tok_finish	__P((Tokenizer *)); + + +/* tok_finish(): + *	Finish a word in the tokenizer. + */ +private void +tok_finish(tok) +    Tokenizer *tok; +{ +    *tok->wptr = '\0'; +    if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) { +	tok->argv[tok->argc++] = tok->wstart; +	tok->argv[tok->argc] = NULL; +	tok->wstart = ++tok->wptr; +    } +    tok->flags &= ~TOK_KEEP; +} + + +/* tok_init(): + *	Initialize the tokenizer + */ +public Tokenizer * +tok_init(ifs) +    const char *ifs; +{ +    Tokenizer* tok = (Tokenizer*) tok_malloc(sizeof(Tokenizer)); + +    tok->ifs     = strdup(ifs ? ifs : IFS); +    tok->argc    = 0; +    tok->amax    = AINCR; +    tok->argv    = (char **) tok_malloc(sizeof(char *) * tok->amax); +    tok->argv[0] = NULL; +    tok->wspace  = (char *) tok_malloc(WINCR); +    tok->wmax    = tok->wspace + WINCR; +    tok->wstart  = tok->wspace; +    tok->wptr    = tok->wspace; +    tok->flags   = 0; +    tok->quote   = Q_none; + +    return tok; +} + + +/* tok_reset(): + *	Reset the tokenizer + */ +public void +tok_reset(tok) +    Tokenizer *tok; +{ +    tok->argc  = 0; +    tok->wstart = tok->wspace; +    tok->wptr = tok->wspace; +    tok->flags = 0; +    tok->quote = Q_none; +} + + +/* tok_end(): + *	Clean up + */ +public void +tok_end(tok) +    Tokenizer *tok; +{ +    tok_free((ptr_t) tok->ifs); +    tok_free((ptr_t) tok->wspace); +    tok_free((ptr_t) tok->argv); +    tok_free((ptr_t) tok); +} + + + +/* tok_line(): + *	Bourne shell like tokenizing + *	Return: + *		-1: Internal error + *		 3: Quoted return + *		 2: Unmatched double quote + *		 1: Unmatched single quote + *		 0: Ok  + */ +public int +tok_line(tok, line, argc, argv) +    Tokenizer *tok; +    const char* line; +    int *argc; +    char ***argv; +{ +    const char *ptr; + +    while (1) { +	switch (*(ptr = line++)) { +	case '\'': +	    tok->flags |= TOK_KEEP; +	    tok->flags &= ~TOK_EAT; +	    switch (tok->quote) { +	    case Q_none: +		tok->quote = Q_single;	/* Enter single quote mode */ +		break; + +	    case Q_single:		/* Exit single quote mode */ +		tok->quote = Q_none; +		break; + +	    case Q_one:			/* Quote this ' */ +		tok->quote = Q_none; +		*tok->wptr++ = *ptr; +		break; + +	    case Q_double:		/* Stay in double quote mode */ +		*tok->wptr++ = *ptr; +		break; + +	    case Q_doubleone:		/* Quote this ' */ +		tok->quote = Q_double; +		*tok->wptr++ = *ptr; +		break; + +	    default: +		return(-1); +	    } +	    break; + +	case '"': +	    tok->flags &= ~TOK_EAT; +	    tok->flags |= TOK_KEEP; +	    switch (tok->quote) { +	    case Q_none:		/* Enter double quote mode */ +		tok->quote = Q_double; +		break; + +	    case Q_double: +		tok->quote = Q_none;	/* Exit double quote mode */ +		break; + +	    case Q_one:			/* Quote this " */ +		tok->quote = Q_none; +		*tok->wptr++ = *ptr; +		break; + +	    case Q_single:		/* Stay in single quote mode */ +		*tok->wptr++ = *ptr; +		break; + +	    case Q_doubleone:		/* Quote this " */ +		tok->quote = Q_double; +		*tok->wptr++ = *ptr; +		break; + +	    default:  +		return(-1); +	    } +	    break; + +	case '\\': +	    tok->flags |= TOK_KEEP; +	    tok->flags &= ~TOK_EAT; +	    switch (tok->quote) { +	    case Q_none:		/* Quote next character */ +		tok->quote = Q_one; +		break; + +	    case Q_double: +		tok->quote = Q_doubleone;/* Quote next character */ +		break; + +	    case Q_one:	 +		*tok->wptr++ = *ptr; +		tok->quote = Q_none;	/* Quote this, restore state */ +		break; + +	    case Q_single:		/* Stay in single quote mode */ +		*tok->wptr++ = *ptr; +		break; + +	    case Q_doubleone:		/* Quote this \ */ +		tok->quote = Q_double; +		*tok->wptr++ = *ptr; +		break; + +	    default: +		return(-1); +	    } +	    break; + +	case '\n': +	    tok->flags &= ~TOK_EAT; +	    switch (tok->quote) { +	    case Q_none: +		tok_finish(tok); +		*argv = tok->argv; +		*argc = tok->argc; +		return(0); + +	    case Q_single: +	    case Q_double: +		*tok->wptr++ = *ptr;	/* Add the return		*/ +		break; +	     +	    case Q_doubleone: +		tok->flags |= TOK_EAT; +		tok->quote = Q_double;	/* Back to double, eat the '\n' */ +		break; + +	    case Q_one: +		tok->flags |= TOK_EAT; +		tok->quote = Q_none;	/* No quote, more eat the '\n' */ +		break; + +	    default: +		return(0); +	    } +	    break; + +	case '\0': +	    switch (tok->quote) { +	    case Q_none: +		/* Finish word and return */ +		if (tok->flags & TOK_EAT) { +		    tok->flags &= ~TOK_EAT; +		    return 3; +		} +		tok_finish(tok); +		*argv = tok->argv; +		*argc = tok->argc; +		return(0); + +	    case Q_single: +		return(1); + +	    case Q_double: +		return(2); + +	    case Q_doubleone: +		tok->quote = Q_double; +		*tok->wptr++ = *ptr; +		break; + +	    case Q_one: +		tok->quote = Q_none; +		*tok->wptr++ = *ptr; +		break; + +	    default: +		return(-1); +	    } +	    break; + +	default: +	    tok->flags &= ~TOK_EAT; +	    switch (tok->quote) { +	    case Q_none: +		if (strchr(tok->ifs, *ptr) != NULL) +		    tok_finish(tok); +		else +		    *tok->wptr++ = *ptr; +		break; + +	    case Q_single: +	    case Q_double: +		*tok->wptr++ = *ptr; +		break; + + +	    case Q_doubleone: +		*tok->wptr++ = '\\'; +		tok->quote = Q_double; +		*tok->wptr++ = *ptr; +		break; + +	    case Q_one: +		tok->quote = Q_none; +		*tok->wptr++ = *ptr; +		break; + +	    default: +		return(-1); + +	    } +	    break; +	} + +	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 (offs != 0) { +		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; +		tok->wspace = s; +	    } +	} + +	if (tok->argc >= tok->amax - 4) { +	    tok->amax += AINCR; +	    tok->argv = (char **) tok_realloc(tok->argv,  +					      tok->amax * sizeof(char*)); +	} + +    } +} diff --git a/tokenizer.h b/tokenizer.h new file mode 100644 index 0000000000000..11b49ac4b7086 --- /dev/null +++ b/tokenizer.h @@ -0,0 +1,55 @@ +/*	$NetBSD: tokenizer.h,v 1.2 1997/01/11 06:48:16 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	__P((const char *)); +void		 tok_reset	__P((Tokenizer *)); +void		 tok_end	__P((Tokenizer *)); +int		 tok_line	__P((Tokenizer *, const char *,  +				     int *, char ***)); + +#endif /* _h_tokenizer */ diff --git a/tty.c b/tty.c new file mode 100644 index 0000000000000..8dcb738818bc8 --- /dev/null +++ b/tty.c @@ -0,0 +1,1150 @@ +/*	$NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 christos 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)tty.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: tty.c,v 1.3 1997/04/11 17:52:49 christos Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/*  + * tty.c: tty interface stuff + */ +#include "sys.h" +#include "tty.h" +#include "el.h" + +typedef struct ttymodes_t { +    char *m_name; +    u_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; + + +private ttyperm_t ttyperm = {    +    { +	{ "iflag:", ICRNL, (INLCR|IGNCR) }, +	{ "oflag:", (OPOST|ONLCR), ONLRET }, +	{ "cflag:", 0, 0 }, +	{ "lflag:", (ISIG|ICANON|ECHO|ECHOE|ECHOCTL|IEXTEN), +		    (NOFLSH|ECHONL|EXTPROC|FLUSHO) }, +	{ "chars:", 	0, 0 }, +    }, +    { +	{ "iflag:", (INLCR|ICRNL), IGNCR }, +	{ "oflag:", (OPOST|ONLCR), ONLRET }, +	{ "cflag:", 0, 0 }, +	{ "lflag:", ISIG, +		    (NOFLSH|ICANON|ECHO|ECHOK|ECHONL|EXTPROC|IEXTEN|FLUSHO) }, +	{ "chars:", (C_SH(C_MIN)|C_SH(C_TIME)|C_SH(C_SWTCH)|C_SH(C_DSWTCH)| +		     C_SH(C_SUSP)|C_SH(C_DSUSP)|C_SH(C_EOL)|C_SH(C_DISCARD)| +		     C_SH(C_PGOFF)|C_SH(C_PAGE)|C_SH(C_STATUS)), 0 } +    }, +    { +	{ "iflag:", 0, IXON | IXOFF }, +	{ "oflag:", 0, 0 }, +	{ "cflag:", 0, 0 }, +	{ "lflag:", 0, ISIG | IEXTEN }, +	{ "chars:", 0, 0 }, +    } +}; + +private ttychar_t ttychar = { +    { +	CINTR,		 CQUIT, 	 CERASE, 	   CKILL,	 +	CEOF, 		 CEOL, 		 CEOL2, 	   CSWTCH,  +	CDSWTCH,	 CERASE2,	 CSTART, 	   CSTOP, +	CWERASE, 	 CSUSP, 	 CDSUSP, 	   CREPRINT, +	CDISCARD, 	 CLNEXT,	 CSTATUS,	   CPAGE, +	CPGOFF,		 CKILL2, 	 CBRK, 		   CMIN, +	CTIME +    }, +    { +	CINTR, 		 CQUIT, 	  CERASE, 	   CKILL,  +	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,  +	_POSIX_VDISABLE, CERASE2,	  CSTART, 	   CSTOP, 	    +	_POSIX_VDISABLE, CSUSP,           _POSIX_VDISABLE, _POSIX_VDISABLE,  +	CDISCARD, 	 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,  +	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1, +	0 +    }, +    {	 +	0,		 0,		  0,		   0, +	0,		 0,		  0,		   0, +	0,		 0,		  0,		   0, +	0,		 0,		  0,		   0, +	0,		 0,		  0,		   0, +	0,		 0,		  0,		   0, +	0 +    } +}; + +private ttymap_t tty_map[] = { +#ifdef VERASE +	{ C_ERASE,   VERASE,	 +	    { ED_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 } }, +#endif /* VERASE2 */ +#ifdef VKILL +    	{ C_KILL,    VKILL,	 +	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } }, +#endif /* VKILL */ +#ifdef VKILL2 +    	{ C_KILL2,   VKILL2,	 +	    { EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED } }, +#endif /* VKILL2 */ +#ifdef VEOF +    	{ C_EOF,     VEOF,	 +	    { EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED } }, +#endif /* VEOF */ +#ifdef VWERASE +    	{ C_WERASE,  VWERASE,	 +	    { ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD } }, +#endif /* VWERASE */ +#ifdef VREPRINT +   	{ C_REPRINT, VREPRINT,	 +	    { ED_REDISPLAY, ED_INSERT, ED_REDISPLAY } }, +#endif /* VREPRINT */ +#ifdef VLNEXT +    	{ C_LNEXT,   VLNEXT,	 +	    { ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED } }, +#endif /* VLNEXT */ +	{ -1,	     -1,	 +	    { ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED } } +    }; + +private ttymodes_t ttymodes[] = { +# ifdef	IGNBRK +    { "ignbrk",	IGNBRK,	M_INP }, +# endif /* IGNBRK */ +# ifdef	BRKINT +    { "brkint",	BRKINT,	M_INP }, +# endif /* BRKINT */ +# ifdef	IGNPAR +    { "ignpar",	IGNPAR,	M_INP }, +# endif /* IGNPAR */ +# ifdef	PARMRK +    { "parmrk",	PARMRK,	M_INP }, +# endif /* PARMRK */ +# ifdef	INPCK +    { "inpck",	INPCK,	M_INP }, +# endif /* INPCK */ +# ifdef	ISTRIP +    { "istrip",	ISTRIP,	M_INP }, +# endif /* ISTRIP */ +# ifdef	INLCR +    { "inlcr",	INLCR,	M_INP }, +# endif /* INLCR */ +# ifdef	IGNCR +    { "igncr",	IGNCR,	M_INP }, +# endif /* IGNCR */ +# ifdef	ICRNL +    { "icrnl",	ICRNL,	M_INP }, +# endif /* ICRNL */ +# ifdef	IUCLC +    { "iuclc",	IUCLC,	M_INP }, +# endif /* IUCLC */ +# ifdef	IXON +    { "ixon",	IXON,	M_INP }, +# endif /* IXON */ +# ifdef	IXANY +    { "ixany",	IXANY,	M_INP }, +# endif /* IXANY */ +# ifdef	IXOFF +    { "ixoff",	IXOFF,	M_INP }, +# endif /* IXOFF */ +# ifdef  IMAXBEL +    { "imaxbel",IMAXBEL,M_INP }, +# endif /* IMAXBEL */ + +# ifdef	OPOST +    { "opost",	OPOST,	M_OUT }, +# endif /* OPOST */ +# ifdef	OLCUC +    { "olcuc",	OLCUC,	M_OUT }, +# endif /* OLCUC */ +# ifdef	ONLCR +    { "onlcr",	ONLCR,	M_OUT }, +# endif /* ONLCR */ +# ifdef	OCRNL +    { "ocrnl",	OCRNL,	M_OUT }, +# endif /* OCRNL */ +# ifdef	ONOCR +    { "onocr",	ONOCR,	M_OUT }, +# endif /* ONOCR */ +# ifdef ONOEOT +    { "onoeot",	ONOEOT,	M_OUT }, +# endif /* ONOEOT */ +# ifdef	ONLRET +    { "onlret",	ONLRET,	M_OUT }, +# endif /* ONLRET */ +# ifdef	OFILL +    { "ofill",	OFILL,	M_OUT }, +# endif /* OFILL */ +# ifdef	OFDEL +    { "ofdel",	OFDEL,	M_OUT }, +# endif /* OFDEL */ +# ifdef	NLDLY +    { "nldly",	NLDLY,	M_OUT }, +# endif /* NLDLY */ +# ifdef	CRDLY +    { "crdly",	CRDLY,	M_OUT }, +# endif /* CRDLY */ +# ifdef	TABDLY +    { "tabdly",	TABDLY,	M_OUT }, +# endif /* TABDLY */ +# ifdef	XTABS +    { "xtabs",	XTABS,	M_OUT }, +# endif /* XTABS */ +# ifdef	BSDLY +    { "bsdly",	BSDLY,	M_OUT }, +# endif /* BSDLY */ +# ifdef	VTDLY +    { "vtdly",	VTDLY,	M_OUT }, +# endif /* VTDLY */ +# ifdef	FFDLY +    { "ffdly",	FFDLY,	M_OUT }, +# endif /* FFDLY */ +# ifdef	PAGEOUT +    { "pageout",PAGEOUT,M_OUT }, +# endif /* PAGEOUT */ +# ifdef	WRAP +    { "wrap",	WRAP,	M_OUT }, +# endif /* WRAP */ + +# ifdef	CIGNORE +    { "cignore",CIGNORE,M_CTL }, +# endif /* CBAUD */ +# ifdef	CBAUD +    { "cbaud",	CBAUD,	M_CTL }, +# endif /* CBAUD */ +# ifdef	CSTOPB +    { "cstopb",	CSTOPB,	M_CTL }, +# endif /* CSTOPB */ +# ifdef	CREAD +    { "cread",	CREAD,	M_CTL }, +# endif /* CREAD */ +# ifdef	PARENB +    { "parenb",	PARENB,	M_CTL }, +# endif /* PARENB */ +# ifdef	PARODD +    { "parodd",	PARODD,	M_CTL }, +# endif /* PARODD */ +# ifdef	HUPCL +    { "hupcl",	HUPCL,	M_CTL }, +# endif /* HUPCL */ +# ifdef	CLOCAL +    { "clocal",	CLOCAL,	M_CTL }, +# endif /* CLOCAL */ +# ifdef	LOBLK +    { "loblk",	LOBLK,	M_CTL }, +# endif /* LOBLK */ +# ifdef	CIBAUD +    { "cibaud",	CIBAUD,	M_CTL }, +# endif /* CIBAUD */ +# ifdef CRTSCTS +#  ifdef CCTS_OFLOW +    { "ccts_oflow",CCTS_OFLOW,M_CTL }, +#  else +    { "crtscts",CRTSCTS,M_CTL }, +#  endif /* CCTS_OFLOW */ +# endif /* CRTSCTS */ +# ifdef CRTS_IFLOW +    { "crts_iflow",CRTS_IFLOW,M_CTL }, +# endif /* CRTS_IFLOW */ +# ifdef MDMBUF +    { "mdmbuf",	MDMBUF,	M_CTL }, +# endif /* MDMBUF */ +# ifdef RCV1EN +    { "rcv1en",	RCV1EN,	M_CTL }, +# endif /* RCV1EN */ +# ifdef XMT1EN +    { "xmt1en",	XMT1EN,	M_CTL }, +# endif /* XMT1EN */ + +# ifdef	ISIG +    { "isig",	ISIG,	M_LIN }, +# endif /* ISIG */ +# ifdef	ICANON +    { "icanon",	ICANON,	M_LIN }, +# endif /* ICANON */ +# ifdef	XCASE +    { "xcase",	XCASE,	M_LIN }, +# endif /* XCASE */ +# ifdef	ECHO +    { "echo",	ECHO,	M_LIN }, +# endif /* ECHO */ +# ifdef	ECHOE +    { "echoe",	ECHOE,	M_LIN }, +# endif /* ECHOE */ +# ifdef	ECHOK +    { "echok",	ECHOK,	M_LIN }, +# endif /* ECHOK */ +# ifdef	ECHONL +    { "echonl",	ECHONL,	M_LIN }, +# endif /* ECHONL */ +# ifdef	NOFLSH +    { "noflsh",	NOFLSH,	M_LIN }, +# endif /* NOFLSH */ +# ifdef	TOSTOP +    { "tostop",	TOSTOP,	M_LIN }, +# endif /* TOSTOP */ +# ifdef	ECHOCTL +    { "echoctl",ECHOCTL,M_LIN }, +# endif /* ECHOCTL */ +# ifdef	ECHOPRT +    { "echoprt",ECHOPRT,M_LIN }, +# endif /* ECHOPRT */ +# ifdef	ECHOKE +    { "echoke",	ECHOKE,	M_LIN }, +# endif /* ECHOKE */ +# ifdef	DEFECHO +    { "defecho",DEFECHO,M_LIN }, +# endif /* DEFECHO */ +# ifdef	FLUSHO +    { "flusho",	FLUSHO,	M_LIN }, +# endif /* FLUSHO */ +# ifdef	PENDIN +    { "pendin",	PENDIN,	M_LIN }, +# endif /* PENDIN */ +# ifdef	IEXTEN +    { "iexten",	IEXTEN,	M_LIN }, +# endif /* IEXTEN */ +# ifdef	NOKERNINFO +    { "nokerninfo",NOKERNINFO,M_LIN }, +# endif /* NOKERNINFO */ +# ifdef	ALTWERASE +    { "altwerase",ALTWERASE,M_LIN }, +# endif /* ALTWERASE */ +# ifdef	EXTPROC +    { "extproc",EXTPROC, M_LIN }, +# endif /* EXTPROC */ + +# if defined(VINTR)  +    { "intr",		C_SH(C_INTR), 	M_CHAR }, +# endif /* VINTR */ +# if defined(VQUIT) +    { "quit",		C_SH(C_QUIT), 	M_CHAR }, +# endif /* VQUIT */ +# if defined(VERASE) +    { "erase",		C_SH(C_ERASE), 	M_CHAR }, +# endif /* VERASE */ +# if defined(VKILL) +    { "kill",		C_SH(C_KILL), 	M_CHAR }, +# endif /* VKILL */ +# if defined(VEOF) +    { "eof",		C_SH(C_EOF), 	M_CHAR }, +# endif /* VEOF */ +# if defined(VEOL) +    { "eol",		C_SH(C_EOL), 	M_CHAR }, +# endif /* VEOL */ +# if defined(VEOL2) +    { "eol2",		C_SH(C_EOL2), 	M_CHAR }, +# endif  /* VEOL2 */ +# if defined(VSWTCH) +    { "swtch",		C_SH(C_SWTCH), 	M_CHAR }, +# endif /* VSWTCH */ +# if defined(VDSWTCH) +    { "dswtch",		C_SH(C_DSWTCH),	M_CHAR }, +# endif /* VDSWTCH */ +# if defined(VERASE2) +    { "erase2",		C_SH(C_ERASE2),	M_CHAR }, +# endif /* VERASE2 */ +# if defined(VSTART) +    { "start",		C_SH(C_START), 	M_CHAR }, +# endif /* VSTART */ +# if defined(VSTOP) +    { "stop",		C_SH(C_STOP), 	M_CHAR }, +# endif /* VSTOP */ +# if defined(VWERASE) +    { "werase",		C_SH(C_WERASE),	M_CHAR }, +# endif /* VWERASE */ +# if defined(VSUSP) +    { "susp",		C_SH(C_SUSP), 	M_CHAR }, +# endif /* VSUSP */ +# if defined(VDSUSP) +    { "dsusp",		C_SH(C_DSUSP), 	M_CHAR }, +# endif /* VDSUSP */ +# if defined(VREPRINT) +    { "reprint",	C_SH(C_REPRINT),M_CHAR }, +# endif /* VREPRINT */ +# if defined(VDISCARD) +    { "discard",	C_SH(C_DISCARD),M_CHAR }, +# endif /* VDISCARD */ +# if defined(VLNEXT) +    { "lnext",		C_SH(C_LNEXT), 	M_CHAR }, +# endif /* VLNEXT */ +# if defined(VSTATUS) +    { "status",		C_SH(C_STATUS),	M_CHAR }, +# endif /* VSTATUS */ +# if defined(VPAGE) +    { "page",		C_SH(C_PAGE), 	M_CHAR }, +# endif /* VPAGE */ +# if defined(VPGOFF) +    { "pgoff",		C_SH(C_PGOFF), 	M_CHAR }, +# endif /* VPGOFF */ +# if defined(VKILL2)  +    { "kill2",		C_SH(C_KILL2), 	M_CHAR }, +# endif /* VKILL2 */ +# if defined(VBRK) +    { "brk",		C_SH(C_BRK), 	M_CHAR }, +# endif /* VBRK */ +# if defined(VMIN) +    { "min",		C_SH(C_MIN), 	M_CHAR }, +# endif /* VMIN */ +# if defined(VTIME) +    { "time",		C_SH(C_TIME), 	M_CHAR }, +# endif /* VTIME */ +    { NULL, 0, -1 }, +}; + + + +#define tty_getty(el, td) tcgetattr((el)->el_infd, (td)) +#define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td))  + +#define tty__gettabs(td)     ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1) +#define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) +#define tty__cooked_mode(td) ((td)->c_lflag & ICANON) + +private void    tty__getchar	__P((struct termios *, unsigned char *)); +private void    tty__setchar	__P((struct termios *, unsigned char *)); +private speed_t tty__getspeed	__P((struct termios *)); +private int     tty_setup	__P((EditLine *)); + +#define t_qu t_ts + + +/* tty_setup(): + *	Get the tty parameters and initialize the editing state + */ +private int  +tty_setup(el) +    EditLine *el; +{ +    int rst = 1; +    if (tty_getty(el, &el->el_tty.t_ed) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile,  +		       "tty_setup: tty_getty: %s\n", strerror(errno)); +#endif /* DEBUG_TTY */ +	return(-1); +    } +    el->el_tty.t_ts    = el->el_tty.t_ex = el->el_tty.t_ed; + +    el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex); +    el->el_tty.t_tabs  = tty__gettabs(&el->el_tty.t_ex); +    el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex); + +    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask; +    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask; + +    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask; +    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask; + +    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask; +    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask; + +    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask; +    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask; + +    /* +     * Reset the tty chars to reasonable defaults +     * If they are disabled, then enable them. +     */ +    if (rst) { +        if (tty__cooked_mode(&el->el_tty.t_ts)) { +            tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); +            /* +             * Don't affect CMIN and CTIME for the editor mode +             */ +            for (rst = 0; rst < C_NCC - 2; rst++) +                if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable && +                    el->el_tty.t_c[ED_IO][rst] != el->el_tty.t_vdisable) +                    el->el_tty.t_c[ED_IO][rst]  = el->el_tty.t_c[TS_IO][rst]; +            for (rst = 0; rst < C_NCC; rst++) +                if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable && +                    el->el_tty.t_c[EX_IO][rst] != el->el_tty.t_vdisable) +                    el->el_tty.t_c[EX_IO][rst]  = el->el_tty.t_c[TS_IO][rst]; +        } +        tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); +        if (tty_setty(el, &el->el_tty.t_ex) == -1) { +#ifdef DEBUG_TTY +            (void) fprintf(el->el_errfile, "tty_setup: tty_setty: %s\n",  +			   strerror(errno)); +#endif /* DEBUG_TTY */ +            return(-1); +        } +    } +    else +        tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); + +    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask; +    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask; + +    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask; +    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask; + +    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask; +    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask; + +    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask; +    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask; + +    tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); +    return 0; +} + +protected int +tty_init(el) +    EditLine *el; +{ +    el->el_tty.t_mode     = EX_IO; +    el->el_tty.t_vdisable = _POSIX_VDISABLE; +    (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); +    (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); +    return tty_setup(el); +} /* end tty_init */ + + +/* tty_end(): + *	Restore the tty to its original settings + */ +protected void +/*ARGSUSED*/ +tty_end(el) +    EditLine *el; +{ +    /* XXX: Maybe reset to an initial state? */ +} + + +/* tty__getspeed(): + *	Get the tty speed + */ +private speed_t +tty__getspeed(td) +    struct termios *td; +{ +    speed_t spd; + +    if ((spd = cfgetispeed(td)) == 0) +	spd = cfgetospeed(td); +    return spd; +} /* end tty__getspeed */ + + +/* tty__getchar(): + *	Get the tty characters + */ +private void +tty__getchar(td, s) +    struct termios *td; +    unsigned char *s; +{    +# ifdef VINTR +    s[C_INTR]	= td->c_cc[VINTR]; +# endif /* VINTR */ +# ifdef VQUIT +    s[C_QUIT]	= td->c_cc[VQUIT]; +# endif /* VQUIT */ +# ifdef VERASE +    s[C_ERASE]	= td->c_cc[VERASE]; +# endif /* VERASE */ +# ifdef VKILL +    s[C_KILL]	= td->c_cc[VKILL]; +# endif /* VKILL */ +# ifdef VEOF +    s[C_EOF]	= td->c_cc[VEOF]; +# endif /* VEOF */ +# ifdef VEOL +    s[C_EOL]	= td->c_cc[VEOL]; +# endif /* VEOL */ +# ifdef VEOL2 +    s[C_EOL2]	= td->c_cc[VEOL2]; +# endif  /* VEOL2 */ +# ifdef VSWTCH +    s[C_SWTCH]	= td->c_cc[VSWTCH]; +# endif /* VSWTCH */ +# ifdef VDSWTCH +    s[C_DSWTCH]	= td->c_cc[VDSWTCH]; +# endif /* VDSWTCH */ +# ifdef VERASE2 +    s[C_ERASE2]	= td->c_cc[VERASE2]; +# endif /* VERASE2 */ +# ifdef VSTART +    s[C_START]	= td->c_cc[VSTART]; +# endif /* VSTART */ +# ifdef VSTOP +    s[C_STOP]	= td->c_cc[VSTOP]; +# endif /* VSTOP */ +# ifdef VWERASE +    s[C_WERASE]	= td->c_cc[VWERASE]; +# endif /* VWERASE */ +# ifdef VSUSP +    s[C_SUSP]	= td->c_cc[VSUSP]; +# endif /* VSUSP */ +# ifdef VDSUSP +    s[C_DSUSP]	= td->c_cc[VDSUSP]; +# endif /* VDSUSP */ +# ifdef VREPRINT +    s[C_REPRINT]= td->c_cc[VREPRINT]; +# endif /* VREPRINT */ +# ifdef VDISCARD +    s[C_DISCARD]= td->c_cc[VDISCARD]; +# endif /* VDISCARD */ +# ifdef VLNEXT +    s[C_LNEXT]	= td->c_cc[VLNEXT]; +# endif /* VLNEXT */ +# ifdef VSTATUS +    s[C_STATUS]	= td->c_cc[VSTATUS]; +# endif /* VSTATUS */ +# ifdef VPAGE +    s[C_PAGE]	= td->c_cc[VPAGE]; +# endif /* VPAGE */ +# ifdef VPGOFF +    s[C_PGOFF]	= td->c_cc[VPGOFF]; +# endif /* VPGOFF */ +# ifdef VKILL2 +    s[C_KILL2]	= td->c_cc[VKILL2]; +# endif /* KILL2 */ +# ifdef VMIN +    s[C_MIN]	= td->c_cc[VMIN]; +# endif /* VMIN */ +# ifdef VTIME +    s[C_TIME]	= td->c_cc[VTIME]; +# endif /* VTIME */ +} /* tty__getchar */ + + +/* tty__setchar(): + *	Set the tty characters + */ +private void +tty__setchar(td, s) +    struct termios *td; +    unsigned char *s; +{    +# ifdef VINTR +    td->c_cc[VINTR]	= s[C_INTR]; +# endif /* VINTR */ +# ifdef VQUIT +    td->c_cc[VQUIT]	= s[C_QUIT]; +# endif /* VQUIT */ +# ifdef VERASE +    td->c_cc[VERASE]	= s[C_ERASE]; +# endif /* VERASE */ +# ifdef VKILL +    td->c_cc[VKILL]	= s[C_KILL]; +# endif /* VKILL */ +# ifdef VEOF +    td->c_cc[VEOF]	= s[C_EOF]; +# endif /* VEOF */ +# ifdef VEOL +    td->c_cc[VEOL]	= s[C_EOL]; +# endif /* VEOL */ +# ifdef VEOL2 +    td->c_cc[VEOL2]	= s[C_EOL2]; +# endif  /* VEOL2 */ +# ifdef VSWTCH +    td->c_cc[VSWTCH]	= s[C_SWTCH]; +# endif /* VSWTCH */ +# ifdef VDSWTCH +    td->c_cc[VDSWTCH]	= s[C_DSWTCH]; +# endif /* VDSWTCH */ +# ifdef VERASE2 +    td->c_cc[VERASE2]	= s[C_ERASE2]; +# endif /* VERASE2 */ +# ifdef VSTART +    td->c_cc[VSTART]	= s[C_START]; +# endif /* VSTART */ +# ifdef VSTOP +    td->c_cc[VSTOP]	= s[C_STOP]; +# endif /* VSTOP */ +# ifdef VWERASE +    td->c_cc[VWERASE]	= s[C_WERASE]; +# endif /* VWERASE */ +# ifdef VSUSP +    td->c_cc[VSUSP]	= s[C_SUSP]; +# endif /* VSUSP */ +# ifdef VDSUSP +    td->c_cc[VDSUSP]	= s[C_DSUSP]; +# endif /* VDSUSP */ +# ifdef VREPRINT +    td->c_cc[VREPRINT]	= s[C_REPRINT]; +# endif /* VREPRINT */ +# ifdef VDISCARD +    td->c_cc[VDISCARD]	= s[C_DISCARD]; +# endif /* VDISCARD */ +# ifdef VLNEXT +    td->c_cc[VLNEXT]	= s[C_LNEXT]; +# endif /* VLNEXT */ +# ifdef VSTATUS +    td->c_cc[VSTATUS]	= s[C_STATUS]; +# endif /* VSTATUS */ +# ifdef VPAGE +    td->c_cc[VPAGE]	= s[C_PAGE]; +# endif /* VPAGE */ +# ifdef VPGOFF +    td->c_cc[VPGOFF]	= s[C_PGOFF]; +# endif /* VPGOFF */ +# ifdef VKILL2 +    td->c_cc[VKILL2]	= s[C_KILL2]; +# endif /* VKILL2 */ +# ifdef VMIN +    td->c_cc[VMIN]	= s[C_MIN]; +# endif /* VMIN */ +# ifdef VTIME +    td->c_cc[VTIME]	= s[C_TIME]; +# endif /* VTIME */ +} /* tty__setchar */ + + +/* tty_bind_char(): + *	Rebind the editline functions + */ +protected void +tty_bind_char(el, force) +    EditLine *el; +    int force; +{ +    unsigned char *t_n = el->el_tty.t_c[ED_IO]; +    unsigned char *t_o = el->el_tty.t_ed.c_cc; +    char new[2], old[2]; +    ttymap_t *tp; +    el_action_t  *dmap, *dalt, *map, *alt; +    new[1] = old[1] = '\0'; + + +    map = el->el_map.key; +    alt = el->el_map.alt; +    if (el->el_map.type == MAP_VI) { +	dmap = el->el_map.vii; +	dalt = el->el_map.vic; +    } +    else { +	dmap = el->el_map.emacs; +	dalt = NULL; +    } + +    for (tp = tty_map; tp->nch != -1; tp++) { +	new[0] = t_n[tp->nch]; +	old[0] = t_o[tp->och]; +	if (new[0] == old[0] && !force) +	    continue; +	/* Put the old default binding back, and set the new binding */ +	key_clear(el, map, old); +	map[old[0]] = dmap[old[0]]; +	key_clear(el, map, new); +	/* MAP_VI == 1, MAP_EMACS == 0... */ +	map[new[0]] = tp->bind[el->el_map.type]; +	if (dalt) { +	    key_clear(el, alt, old); +	    alt[old[0]] = dalt[old[0]]; +	    key_clear(el, alt, new); +	    alt[new[0]] = tp->bind[el->el_map.type+1]; +	} +    } +} + +/* tty_rawmode(): + * 	Set terminal into 1 character at a time mode. + */ +protected int +tty_rawmode(el) +    EditLine *el; +{ +    if (el->el_tty.t_mode == ED_IO) +	return (0); + +    if (tty_getty(el, &el->el_tty.t_ts) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno)); +#endif /* DEBUG_TTY */ +	return(-1); +    } + +    /* +     * We always keep up with the eight bit setting and the speed of the +     * tty. But only we only believe changes that are made to cooked mode! +     */ +    el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); +    el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); + +    if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||  +	tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { +	(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); +	(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); +	(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); +	(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); +    } + +    if (tty__cooked_mode(&el->el_tty.t_ts)) { +	if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {  +	    el->el_tty.t_ex.c_cflag  = el->el_tty.t_ts.c_cflag; +	    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask; +	    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask; + +	    el->el_tty.t_ed.c_cflag  = el->el_tty.t_ts.c_cflag; +	    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask; +	    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask; +	} + +	if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) && +	    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) { +	    el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag; +	    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask; +	    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask; + +	    el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag; +	    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask; +	    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask; +	} + +	if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) && +	    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) { +	    el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag; +	    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask; +	    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask; + +	    el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag; +	    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask; +	    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask; +	} + +	if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) && +	    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) { +	    el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag; +	    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask; +	    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask; + +	    el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag; +	    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask; +	    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask; +	} + +	if (tty__gettabs(&el->el_tty.t_ex) == 0)  +	    el->el_tty.t_tabs = 0; +	else  +	    el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; + +	{ +	    int i; + +	    tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); +	    /* +	     * Check if the user made any changes. +	     * If he did, then propagate the changes to the +	     * edit and execute data structures. +	     */ +	    for (i = 0; i < C_NCC; i++) +		if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]) +		    break; +		 +	    if (i != C_NCC) { +		/* +		 * Propagate changes only to the unprotected chars +		 * that have been modified just now. +		 */ +		for (i = 0; i < C_NCC; i++) { +		    if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i))) +		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) +			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i]; +		    if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i)) +			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable; +		} +		tty_bind_char(el, 0); +		tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); + +		for (i = 0; i < C_NCC; i++) { +		    if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i))) +		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) +			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i]; +		    if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i)) +			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable; +		} +		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); +	    } + +	} +    } + +    if (tty_setty(el, &el->el_tty.t_ed) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",  +		       strerror(errno)); +#endif /* DEBUG_TTY */ +	return -1; +    } +    el->el_tty.t_mode = ED_IO; +    return (0); +} /* end tty_rawmode */ + + +/* tty_cookedmode(): + *	Set the tty back to normal mode + */ +protected int +tty_cookedmode(el) +    EditLine *el; +{				/* set tty in normal setup */ +    if (el->el_tty.t_mode == EX_IO) +	return (0); + +    if (tty_setty(el, &el->el_tty.t_ex) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",  +		       strerror(errno)); +#endif /* DEBUG_TTY */ +	return -1; +    } +    el->el_tty.t_mode = EX_IO; +    return (0); +} /* end tty_cookedmode */ + + +/* tty_quotemode(): + *	Turn on quote mode + */ +protected int +tty_quotemode(el) +    EditLine *el; +{ +    if (el->el_tty.t_mode == QU_IO) +	return 0; + +    el->el_tty.t_qu = el->el_tty.t_ed; + +    el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask; +    el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask; + +    el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask; +    el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask; + +    el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask; +    el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask; + +    el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask; +    el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask; + +    if (tty_setty(el, &el->el_tty.t_qu) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",  +		       strerror(errno)); +#endif /* DEBUG_TTY */ +	return -1; +    } +    el->el_tty.t_mode = QU_IO; +    return 0; +} /* end tty_quotemode */ + + +/* tty_noquotemode(): + *	Turn off quote mode + */ +protected int +tty_noquotemode(el) +    EditLine *el; +{ +    if (el->el_tty.t_mode != QU_IO) +	return 0; +    if (tty_setty(el, &el->el_tty.t_ed) == -1) { +#ifdef DEBUG_TTY +	(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",  +		       strerror(errno)); +#endif /* DEBUG_TTY */ +	return -1; +    } +    el->el_tty.t_mode = ED_IO; +    return 0; +} + +/* tty_stty(): + *	Stty builtin + */ +protected int +/*ARGSUSED*/ +tty_stty(el, argc, argv) +    EditLine *el; +    int argc; +    char **argv; +{ +    ttymodes_t *m; +    char x, *d; +    int aflag = 0; +    char *s; +    char *name; +    int z = EX_IO; + +    if (argv == NULL) +	return -1; +    name = *argv++; + +    while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')  +	switch (argv[0][1]) { +	case 'a': +	    aflag++; +	    argv++; +	    break; +	case 'd': +	    argv++; +	    z = ED_IO; +	    break; +	case 'x': +	    argv++; +	    z = EX_IO; +	    break; +	case 'q': +	    argv++; +	    z = QU_IO; +	    break; +	default: +	    (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n", +			   name, argv[0][1]); +	    return -1; +	} + +    if (!argv || !*argv) { +	int i = -1; +	int len = 0, st = 0, cu; +	for (m = ttymodes; m->m_name; m++) { +	    if (m->m_type != i) { +		(void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",  +			el->el_tty.t_t[z][m->m_type].t_name); +		i = m->m_type; +		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name); +	    } + +	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0'; +	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x; + +	    if (x != '\0' || aflag) { + +		cu = strlen(m->m_name) + (x != '\0') + 1; + +		if (len + cu >= el->el_term.t_size.h) { +		    (void) fprintf(el->el_outfile, "\n%*s", st, ""); +		    len = st + cu; +		} +		else  +		    len += cu; + +		if (x != '\0') +		    (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name); +		else +		    (void) fprintf(el->el_outfile, "%s ", m->m_name); +	    } +	} +	(void) fprintf(el->el_outfile, "\n"); +	return 0; +    } + +    while (argv && (s = *argv++)) { +	switch (*s) { +	case '+': +	case '-': +	    x = *s++; +	    break; +	default: +	    x = '\0'; +	    break; +	} +	d = s; +	for (m = ttymodes; m->m_name; m++) +	    if (strcmp(m->m_name, d) == 0) +		break; + +	if (!m->m_name)  { +	    (void) fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n", +			   name, d); +	    return -1; +	} + +	switch (x) { +	case '+': +	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; +	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; +	    break; +	case '-': +	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; +	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; +	    break; +	default: +	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; +	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; +	    break; +	} +    } +    return 0; +} /* end tty_stty */ + + +#ifdef notyet +/* tty_printchar(): + *	DEbugging routine to print the tty characters + */ +private void +tty_printchar(el, s) +    EditLine *el; +    unsigned char *s; +{ +    ttyperm_t *m; +    int i; + +    for (i = 0; i < C_NCC; i++) { +	for (m = el->el_tty.t_t; m->m_name; m++)  +	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value) +		break; +	if (m->m_name) +	    (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1); +	if (i % 5 == 0) +	    (void) fprintf(el->el_errfile, "\n"); +    } +    (void) fprintf(el->el_errfile, "\n");  +} +#endif /* notyet */ diff --git a/tty.h b/tty.h new file mode 100644 index 0000000000000..213048ef4720e --- /dev/null +++ b/tty.h @@ -0,0 +1,483 @@ +/*	$NetBSD: tty.h,v 1.4 1997/04/11 21:38:02 christos 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. + * + *	@(#)tty.h	8.1 (Berkeley) 6/4/93 + */ + +/* + * el.tty.h: Local terminal header + */ +#ifndef _h_el_tty +#define _h_el_tty + +#include "histedit.h" +#include <termios.h> + +/* Define our own since everyone gets it wrong! */ +#define CONTROL(A)	((A) & 037)	 + +/* + * Aix compatible names + */ +# if defined(VWERSE) && !defined(VWERASE) +#  define VWERASE VWERSE +# endif /* VWERSE && !VWERASE */ + +# if defined(VDISCRD) && !defined(VDISCARD) +#  define VDISCARD VDISCRD +# endif /* VDISCRD && !VDISCARD */ + +# if defined(VFLUSHO) && !defined(VDISCARD) +#  define VDISCARD VFLUSHO +# endif  /* VFLUSHO && VDISCARD */ + +# if defined(VSTRT) && !defined(VSTART) +#  define VSTART VSTRT +# endif /* VSTRT && ! VSTART */ + +# if defined(VSTAT) && !defined(VSTATUS) +#  define VSTATUS VSTAT +# endif /* VSTAT && ! VSTATUS */ + +# ifndef ONLRET +#  define ONLRET 0 +# endif /* ONLRET */ + +# ifndef TAB3 +#  ifdef OXTABS +#   define TAB3 OXTABS +#  else +#   define TAB3 0 +#  endif /* OXTABS */ +# endif /* !TAB3 */ + +# if defined(OXTABS) && !defined(XTABS) +#  define XTABS OXTABS +# endif /* OXTABS && !XTABS */ + +# ifndef ONLCR +#  define ONLCR 0 +# endif /* ONLCR */ + +# ifndef IEXTEN +#  define IEXTEN 0 +# endif /* IEXTEN */ + +# ifndef ECHOCTL +#  define ECHOCTL 0 +# endif /* ECHOCTL */ + +# ifndef PARENB +#  define PARENB 0 +# endif /* PARENB */ + +# ifndef EXTPROC +#  define EXTPROC 0 +# endif /* EXTPROC */ + +# ifndef FLUSHO +#  define FLUSHO  0 +# endif /* FLUSHO */ + + +# if defined(VDISABLE) && !defined(_POSIX_VDISABLE) +#  define _POSIX_VDISABLE VDISABLE +# endif /* VDISABLE && ! _POSIX_VDISABLE */ + +/* + * Work around ISC's definition of IEXTEN which is + * XCASE! + */ +# ifdef ISC +#  if defined(IEXTEN) && defined(XCASE) +#   if IEXTEN == XCASE +#    undef IEXTEN +#    define IEXTEN 0 +#   endif /* IEXTEN == XCASE */ +#  endif /* IEXTEN && XCASE */ +#  if defined(IEXTEN) && !defined(XCASE) +#   define XCASE IEXTEN +#   undef IEXTEN +#   define IEXTEN 0 +#  endif /* IEXTEN && !XCASE */ +# endif /* ISC */ + +/* + * Work around convex weirdness where turning off IEXTEN makes us + * lose all postprocessing! + */ +#if defined(convex) || defined(__convex__) +# if defined(IEXTEN) && IEXTEN != 0 +#  undef IEXTEN +#  define IEXTEN 0 +# endif /* IEXTEN != 0 */ +#endif /* convex || __convex__ */ + +/* + * So that we don't lose job control. + */ +#ifdef __SVR4 +# undef CSWTCH +#endif + +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE ((unsigned char) -1) +#endif /* _POSIX_VDISABLE */ + +#if !defined(CREPRINT) && defined(CRPRNT) +# define CREPRINT CRPRNT +#endif /* !CREPRINT && CRPRNT */ +#if !defined(CDISCARD) && defined(CFLUSH) +# define CDISCARD CFLUSH +#endif /* !CDISCARD && CFLUSH */ + +#ifndef CINTR +# define CINTR		CONTROL('c') +#endif /* CINTR */ +#ifndef CQUIT +# define CQUIT		034	/* ^\ */ +#endif /* CQUIT */ +#ifndef CERASE +# define CERASE		0177	/* ^? */ +#endif /* CERASE */ +#ifndef CKILL +# define CKILL		CONTROL('u') +#endif /* CKILL */ +#ifndef CEOF +# define CEOF		CONTROL('d') +#endif /* CEOF */ +#ifndef CEOL +# define CEOL		_POSIX_VDISABLE +#endif /* CEOL */ +#ifndef CEOL2 +# define CEOL2		_POSIX_VDISABLE +#endif /* CEOL2 */ +#ifndef CSWTCH +# define CSWTCH		_POSIX_VDISABLE +#endif /* CSWTCH */ +#ifndef CDSWTCH +# define CDSWTCH	_POSIX_VDISABLE +#endif /* CDSWTCH */ +#ifndef CERASE2 +# define CERASE2	_POSIX_VDISABLE +#endif /* CERASE2 */ +#ifndef CSTART +# define CSTART		CONTROL('q') +#endif /* CSTART */ +#ifndef CSTOP +# define CSTOP		CONTROL('s') +#endif /* CSTOP */ +#ifndef CSUSP +# define CSUSP		CONTROL('z') +#endif /* CSUSP */ +#ifndef CDSUSP +# define CDSUSP		CONTROL('y') +#endif /* CDSUSP */ + +#ifdef hpux + +# ifndef CREPRINT +#  define CREPRINT	_POSIX_VDISABLE +# endif /* CREPRINT */ +# ifndef CDISCARD +#  define CDISCARD	_POSIX_VDISABLE +# endif /* CDISCARD */ +# ifndef CLNEXT +#  define CLNEXT	_POSIX_VDISABLE +# endif /* CLNEXT */ +# ifndef CWERASE +#  define CWERASE	_POSIX_VDISABLE +# endif /* CWERASE */ + +#else /* !hpux */ + +# ifndef CREPRINT +#  define CREPRINT	CONTROL('r') +# endif /* CREPRINT */ +# ifndef CDISCARD +#  define CDISCARD	CONTROL('o') +# endif /* CDISCARD */ +# ifndef CLNEXT +#  define CLNEXT	CONTROL('v') +# endif /* CLNEXT */ +# ifndef CWERASE +#  define CWERASE	CONTROL('w') +# endif /* CWERASE */ + +#endif /* hpux */ + +#ifndef CSTATUS +# define CSTATUS	CONTROL('t') +#endif /* CSTATUS */ +#ifndef CPAGE +# define CPAGE		' ' +#endif /* CPAGE */ +#ifndef CPGOFF +# define CPGOFF		CONTROL('m') +#endif /* CPGOFF */ +#ifndef CKILL2 +# define CKILL2		_POSIX_VDISABLE +#endif /* CKILL2 */ +#ifndef CBRK +# ifndef masscomp +#  define CBRK		0377 +# else +#  define CBRK		'\0' +# endif /* masscomp */ +#endif /* CBRK */ +#ifndef CMIN +# define CMIN		CEOF +#endif /* CMIN */ +#ifndef CTIME +# define CTIME		CEOL +#endif /* CTIME */ + +/* + * Fix for sun inconsistency. On termio VSUSP and the rest of the + * ttychars > NCC are defined. So we undefine them. + */ +#if defined(TERMIO) || defined(POSIX) +# if defined(POSIX) && defined(NCCS) +#  define NUMCC		NCCS +# else +#  ifdef NCC +#   define NUMCC	NCC +#  endif /* NCC */ +# endif /* POSIX && NCCS */ +# ifdef NUMCC +#  ifdef VINTR +#   if NUMCC <= VINTR +#    undef VINTR +#   endif /* NUMCC <= VINTR */ +#  endif /* VINTR */ +#  ifdef VQUIT +#   if NUMCC <= VQUIT +#    undef VQUIT +#   endif /* NUMCC <= VQUIT */ +#  endif /* VQUIT */ +#  ifdef VERASE +#   if NUMCC <= VERASE +#    undef VERASE +#   endif /* NUMCC <= VERASE */ +#  endif /* VERASE */ +#  ifdef VKILL +#   if NUMCC <= VKILL +#    undef VKILL +#   endif /* NUMCC <= VKILL */ +#  endif /* VKILL */ +#  ifdef VEOF +#   if NUMCC <= VEOF +#    undef VEOF +#   endif /* NUMCC <= VEOF */ +#  endif /* VEOF */ +#  ifdef VEOL +#   if NUMCC <= VEOL +#    undef VEOL +#   endif /* NUMCC <= VEOL */ +#  endif /* VEOL */ +#  ifdef VEOL2 +#   if NUMCC <= VEOL2 +#    undef VEOL2 +#   endif /* NUMCC <= VEOL2 */ +#  endif /* VEOL2 */ +#  ifdef VSWTCH +#   if NUMCC <= VSWTCH +#    undef VSWTCH +#   endif /* NUMCC <= VSWTCH */ +#  endif /* VSWTCH */ +#  ifdef VDSWTCH +#   if NUMCC <= VDSWTCH +#    undef VDSWTCH +#   endif /* NUMCC <= VDSWTCH */ +#  endif /* VDSWTCH */ +#  ifdef VERASE2 +#   if NUMCC <= VERASE2 +#    undef VERASE2 +#   endif /* NUMCC <= VERASE2 */ +#  endif /* VERASE2 */ +#  ifdef VSTART +#   if NUMCC <= VSTART +#    undef VSTART +#   endif /* NUMCC <= VSTART */ +#  endif /* VSTART */ +#  ifdef VSTOP +#   if NUMCC <= VSTOP +#    undef VSTOP +#   endif /* NUMCC <= VSTOP */ +#  endif /* VSTOP */ +#  ifdef VWERASE +#   if NUMCC <= VWERASE +#    undef VWERASE +#   endif /* NUMCC <= VWERASE */ +#  endif /* VWERASE */ +#  ifdef VSUSP +#   if NUMCC <= VSUSP +#    undef VSUSP +#   endif /* NUMCC <= VSUSP */ +#  endif /* VSUSP */ +#  ifdef VDSUSP +#   if NUMCC <= VDSUSP +#    undef VDSUSP +#   endif /* NUMCC <= VDSUSP */ +#  endif /* VDSUSP */ +#  ifdef VREPRINT +#   if NUMCC <= VREPRINT +#    undef VREPRINT +#   endif /* NUMCC <= VREPRINT */ +#  endif /* VREPRINT */ +#  ifdef VDISCARD +#   if NUMCC <= VDISCARD +#    undef VDISCARD +#   endif /* NUMCC <= VDISCARD */ +#  endif /* VDISCARD */ +#  ifdef VLNEXT +#   if NUMCC <= VLNEXT +#    undef VLNEXT +#   endif /* NUMCC <= VLNEXT */ +#  endif /* VLNEXT */ +#  ifdef VSTATUS +#   if NUMCC <= VSTATUS +#    undef VSTATUS +#   endif /* NUMCC <= VSTATUS */ +#  endif /* VSTATUS */ +#  ifdef VPAGE +#   if NUMCC <= VPAGE +#    undef VPAGE +#   endif /* NUMCC <= VPAGE */ +#  endif /* VPAGE */ +#  ifdef VPGOFF +#   if NUMCC <= VPGOFF +#    undef VPGOFF +#   endif /* NUMCC <= VPGOFF */ +#  endif /* VPGOFF */ +#  ifdef VKILL2 +#   if NUMCC <= VKILL2 +#    undef VKILL2 +#   endif /* NUMCC <= VKILL2 */ +#  endif /* VKILL2 */ +#  ifdef VBRK +#   if NUMCC <= VBRK +#    undef VBRK +#   endif /* NUMCC <= VBRK */ +#  endif /* VBRK */ +#  ifdef VMIN +#   if NUMCC <= VMIN +#    undef VMIN +#   endif /* NUMCC <= VMIN */ +#  endif /* VMIN */ +#  ifdef VTIME +#   if NUMCC <= VTIME +#    undef VTIME +#   endif /* NUMCC <= VTIME */ +#  endif /* VTIME */ +# endif /* NUMCC */ +#endif /* !POSIX */ + +#define C_INTR		 0 +#define C_QUIT		 1 +#define C_ERASE		 2 +#define C_KILL		 3 +#define C_EOF		 4 +#define C_EOL		 5 +#define C_EOL2		 6 +#define C_SWTCH		 7 +#define C_DSWTCH	 8 +#define C_ERASE2	 9 +#define C_START		10 +#define C_STOP		11 +#define C_WERASE	12 +#define C_SUSP		13 +#define C_DSUSP		14 +#define C_REPRINT	15 +#define C_DISCARD	16 +#define C_LNEXT		17 +#define C_STATUS	18 +#define C_PAGE		19 +#define C_PGOFF		20 +#define C_KILL2		21 +#define C_BRK		22 +#define C_MIN		23 +#define C_TIME		24 +#define C_NCC		25 +#define C_SH(A)		(1 << (A)) + +/* + * Terminal dependend data structures + */ +#define EX_IO	0	/* while we are executing	*/ +#define ED_IO	1	/* while we are editing		*/ +#define TS_IO	2	/* new mode from terminal	*/ +#define QU_IO	2	/* used only for quoted chars	*/ +#define NN_IO	3	/* The number of entries	*/ + +#define M_INP	0 +#define M_OUT	1 +#define M_CTL	2 +#define M_LIN	3 +#define M_CHAR	4 +#define M_NN	5 + +typedef struct {  +    char *t_name; +    u_int t_setmask; +    u_int t_clrmask; +} ttyperm_t[NN_IO][M_NN]; + +typedef unsigned char ttychar_t[NN_IO][C_NCC]; + +protected int	tty_init	__P((EditLine *)); +protected void	tty_end		__P((EditLine *)); +protected int	tty_stty	__P((EditLine *, int, char**)); +protected int	tty_rawmode	__P((EditLine *)); +protected int	tty_cookedmode	__P((EditLine *)); +protected int	tty_quotemode	__P((EditLine *)); +protected int	tty_noquotemode	__P((EditLine *)); +protected void	tty_bind_char	__P((EditLine *, int)); + +typedef struct { +    ttyperm_t t_t; +    ttychar_t t_c; +    struct termios t_ex, t_ed, t_ts; +    int t_tabs; +    int t_eight; +    speed_t t_speed; +    int t_mode; +    unsigned char t_vdisable; +} el_tty_t; + + +#endif /* _h_el_tty */ diff --git a/vi.c b/vi.c new file mode 100644 index 0000000000000..5b5a2f63c4387 --- /dev/null +++ b/vi.c @@ -0,0 +1,992 @@ +/*	$NetBSD: vi.c,v 1.2 1997/01/11 06:48:19 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. + */ + +#if !defined(lint) && !defined(SCCSID) +#if 0 +static char sccsid[] = "@(#)vi.c	8.1 (Berkeley) 6/4/93"; +#else +static char rcsid[] = "$NetBSD: vi.c,v 1.2 1997/01/11 06:48:19 lukem Exp $"; +#endif +#endif /* not lint && not SCCSID */ + +/* + * vi.c: Vi mode commands. + */ +#include "sys.h" +#include "el.h" + +private el_action_t cv_action __P((EditLine *, int)); + +/* cv_action(): + *	Handle vi actions. + */ +private el_action_t +cv_action(el, c) +    EditLine *el; +    int c; +{ +    register char *cp, *kp; + +    if (el->el_chared.c_vcmd.action & DELETE) { +	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) +	    el->el_map.current = el->el_map.key; +	     +	return CC_REFRESH; +    } + +    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 + */ +protected el_action_t +cv_paste(el, c) +    EditLine *el; +    int c; +{ +    char *ptr; +    c_undo_t *un = &el->el_chared.c_undo; +#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) +	return CC_ERROR; + +    if (!c && el->el_line.cursor < el->el_line.lastchar) +	el->el_line.cursor++; +    ptr = el->el_line.cursor; +	 +    c_insert(el, un->isize); +    if (el->el_line.cursor + un->isize > el->el_line.lastchar) +	return CC_ERROR; +    (void) memcpy(ptr, un->buf, un->isize); +    return CC_REFRESH; +} + + +/* vi_paste_next():  + *	Vi paste previous deletion to the right of the cursor + *	[p] + */ +protected el_action_t +/*ARGSUSED*/ +vi_paste_next(el, c) +    EditLine *el; +    int c; +{ +    return cv_paste(el, 0); +} + + +/* vi_paste_prev():  + *	Vi paste previous deletion to the left of the cursor + *	[P] + */ +protected el_action_t +/*ARGSUSED*/ +vi_paste_prev(el, c) +    EditLine *el; +    int c; +{ +    return cv_paste(el, 1); +} + + +/* vi_prev_space_word():  + *	Vi move to the previous space delimited word + *	[B] + */ +protected el_action_t +/*ARGSUSED*/ +vi_prev_space_word(el, c) +    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.buffer,  +			 	      el->el_state.argument,  +				      cv__isword);  + +    if (el->el_chared.c_vcmd.action & DELETE) { +	cv_delfini(el); +	return CC_REFRESH; +    } + +    return CC_CURSOR; +} + + +/* vi_prev_word():  + *	Vi move to the previous word + *	[B] + */ +protected el_action_t +/*ARGSUSED*/ +vi_prev_word(el, c) +    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.buffer,  +			 	      el->el_state.argument,  +				      ce__isword);  + +    if (el->el_chared.c_vcmd.action & DELETE) { +	cv_delfini(el); +	return CC_REFRESH; +    } + +    return CC_CURSOR; +} + + +/* vi_next_space_word():  + *	Vi move to the next space delimited word + *	[W] + */ +protected el_action_t +/*ARGSUSED*/ +vi_next_space_word(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor == el->el_line.lastchar) +	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); + +    if (el->el_map.type == MAP_VI) +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} + +    return CC_CURSOR; +} + +/* vi_next_word():  + *	Vi move to the next word + *	[w] + */ +protected el_action_t +/*ARGSUSED*/ +vi_next_word(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor == el->el_line.lastchar) +	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); + +    if (el->el_map.type == MAP_VI) +	if (el->el_chared.c_vcmd.action & DELETE) { +	    cv_delfini(el); +	    return CC_REFRESH; +	} + +    return CC_CURSOR; +} + + + +/* vi_change_case():  + *	Vi change case of character under the cursor and advance one character + *	[~] + */ +protected el_action_t +vi_change_case(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_line.cursor < el->el_line.lastchar) { +	c = *el->el_line.cursor; +	if (isupper(c)) +	    *el->el_line.cursor++ = tolower(c); +	else if (islower(c)) +	    *el->el_line.cursor++ = toupper(c); +	else +	    el->el_line.cursor++; +	re_fastaddc(el); +	return CC_NORM; +    } +    return CC_ERROR; +} + + +/* vi_change_meta():  + *	Vi change prefix command + *	[c] + */ +protected el_action_t +/*ARGSUSED*/ +vi_change_meta(el, c) +    EditLine *el; +    int c; +{ +    /* +     * Delete with insert == change: first we delete and then we leave in +     * insert mode. +     */ +    return cv_action(el, DELETE|INSERT); +} + + +/* vi_insert_at_bol():  + *	Vi enter insert mode at the beginning of line + *	[I] + */ +protected el_action_t +/*ARGSUSED*/ +vi_insert_at_bol(el, c) +    EditLine *el; +    int c; +{ +    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; + +    el->el_map.current = el->el_map.key; +    return CC_CURSOR; +} + + +/* vi_replace_char():  + *	Vi replace character under the cursor with the next character typed + *	[r] + */ +protected el_action_t +/*ARGSUSED*/ +vi_replace_char(el, c) +    EditLine *el; +    int c; +{ +    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; +} + + +/* vi_replace_mode():  + *	Vi enter replace mode + *	[R] + */ +protected el_action_t +/*ARGSUSED*/ +vi_replace_mode(el, c) +    EditLine *el; +    int c; +{ +    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; +    return CC_NORM; +} + + +/* vi_substitute_char():  + *	Vi replace character under the cursor and enter insert mode + *	[r] + */ +protected el_action_t +/*ARGSUSED*/ +vi_substitute_char(el, c) +    EditLine *el; +    int c; +{ +    c_delafter(el, el->el_state.argument); +    el->el_map.current = el->el_map.key; +    return CC_REFRESH; +} + + +/* vi_substitute_line():  + *	Vi substitute entire line + *	[S] + */ +protected el_action_t +/*ARGSUSED*/ +vi_substitute_line(el, c) +    EditLine *el; +    int c; +{ +    (void) em_kill_line(el, 0); +    el->el_map.current = el->el_map.key; +    return CC_REFRESH; +} + + +/* vi_change_to_eol():  + *	Vi change to end of line + *	[C] + */ +protected el_action_t +/*ARGSUSED*/ +vi_change_to_eol(el, c) +    EditLine *el; +    int c; +{ +    (void) ed_kill_line(el, 0); +    el->el_map.current = el->el_map.key; +    return CC_REFRESH; +} + + +/* vi_insert(): + *	Vi enter insert mode + *	[i] + */ +protected el_action_t +/*ARGSUSED*/ +vi_insert(el, c) +    EditLine *el; +    int c; +{ +    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; + +    return CC_NORM; +} + + +/* vi_add(): + *	Vi enter insert mode after the cursor  + *	[a] + */ +protected el_action_t +/*ARGSUSED*/ +vi_add(el, c) +    EditLine *el; +    int c; +{ +    int ret; +    el->el_map.current = el->el_map.key; +    if (el->el_line.cursor < el->el_line.lastchar) { +	el->el_line.cursor++; +	if (el->el_line.cursor > el->el_line.lastchar) +	    el->el_line.cursor = el->el_line.lastchar; +	ret = CC_CURSOR; +    } +    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; + +    return ret; +} + + +/* vi_add_at_eol(): + *	Vi enter insert mode at end of line + *	[A] + */ +protected el_action_t +/*ARGSUSED*/ +vi_add_at_eol(el, c) +    EditLine *el; +    int c; +{ +    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; +    return CC_CURSOR; +} + + +/* vi_delete_meta(): + *	Vi delete prefix command  + *	[d] + */ +protected el_action_t +/*ARGSUSED*/ +vi_delete_meta(el, c) +    EditLine *el; +    int c; +{ +    return cv_action(el, DELETE); +} + + +/* vi_end_word(): + *	Vi move to the end of the current space delimited word  + *	[E]  + */ +protected el_action_t +/*ARGSUSED*/ +vi_end_word(el, c) +    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); + +    if (el->el_chared.c_vcmd.action & DELETE) { +	el->el_line.cursor++; +	cv_delfini(el); +	return CC_REFRESH; +    } + +    return CC_CURSOR; +} + + +/* vi_to_end_word(): + *	Vi move to the end of the current word + *	[e] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_end_word(el, c) +    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); + +    if (el->el_chared.c_vcmd.action & DELETE) { +	el->el_line.cursor++; +	cv_delfini(el); +	return CC_REFRESH; +    } + +    return CC_CURSOR; +} + + +/* vi_undo(): + *	Vi undo last change + *	[u] + */ +protected el_action_t +/*ARGSUSED*/ +vi_undo(el, c) +    EditLine *el; +    int c; +{ +    char *cp, *kp; +    char temp; +    int	 i, size; +    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; + +	(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, un->isize); +	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; +    } + +    return CC_REFRESH; +} + + +/* vi_command_mode(): + *	Vi enter command mode (use alternative key bindings) + *	[<ESC>] + */ +protected el_action_t +/*ARGSUSED*/ +vi_command_mode(el, c) +    EditLine *el; +    int c; +{ +    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; +#ifdef VI_MOVE +    if (el->el_line.cursor > el->el_line.buffer) +	el->el_line.cursor--; +#endif +    return CC_CURSOR; +} + +/* vi_zero(): + *	Vi move to the beginning of line  + *	[0] + */ +protected el_action_t +vi_zero(el, c) +    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; +    } +} + + +/* vi_delete_prev_char(): + * 	Vi move to previous character (backspace)  + *	[^H] + */  +protected el_action_t +/*ARGSUSED*/ +vi_delete_prev_char(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_chared.c_vcmd.ins == 0)  +	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; + +    return CC_REFRESH; +} /* end v_del_char_prev  */ + + +/* vi_list_or_eof(): + *	Vi list choices for completion or indicate end of file if empty line + *	[^D] + */ +protected el_action_t +/*ARGSUSED*/ +vi_list_or_eof(el, c) +    EditLine *el; +    int c; +{ +#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 +    } +    else { +	re_goto_bottom(el); +	*el->el_line.lastchar = '\0';	/* just in case */ +	return CC_LIST_CHOICES; +    } +#endif +} + + +/* vi_kill_line_prev(): + *	Vi cut from beginning of line to cursor  + *	[^U] + */ +protected el_action_t +/*ARGSUSED*/ +vi_kill_line_prev(el, c) +    EditLine *el; +    int c; +{ +    char *kp, *cp; + +    cp = el->el_line.buffer; +    kp = el->el_chared.c_kill.buf; +    while (cp < el->el_line.cursor) +	*kp++ = *cp++;		/* copy it */ +    el->el_chared.c_kill.last = kp; +    c_delbefore(el, el->el_line.cursor - el->el_line.buffer); +    el->el_line.cursor = el->el_line.buffer;		/* zap! */ +    return CC_REFRESH; +} + + +/* vi_search_prev(): + *	Vi search history previous + *	[?] + */ +protected el_action_t +/*ARGSUSED*/ +vi_search_prev(el, c) +    EditLine *el; +    int c; +{ +    return cv_search(el, ED_SEARCH_PREV_HISTORY); +} + + +/* vi_search_next(): + *	Vi search history next + *	[/] + */ +protected el_action_t +/*ARGSUSED*/ +vi_search_next(el, c) +    EditLine *el; +    int c; +{ +    return cv_search(el, ED_SEARCH_NEXT_HISTORY); +} + + +/* vi_repeat_search_next(): + *	Vi repeat current search in the same search direction + *	[n] + */ +protected el_action_t +/*ARGSUSED*/ +vi_repeat_search_next(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_search.patlen == 0)  +	return CC_ERROR; +    else +	return cv_repeat_srch(el, el->el_search.patdir); +} + + +/* vi_repeat_search_prev(): + *	Vi repeat current search in the opposite search direction + *	[N] + */ +/*ARGSUSED*/ +protected el_action_t +vi_repeat_search_prev(el, c) +    EditLine *el; +    int c; +{ +    if (el->el_search.patlen == 0)  +	return CC_ERROR; +    else +	return cv_repeat_srch(el,  +			      el->el_search.patdir == ED_SEARCH_PREV_HISTORY ? +			      ED_SEARCH_NEXT_HISTORY : ED_SEARCH_PREV_HISTORY); +} + + +/* vi_next_char(): + *	Vi move to the character specified next + *	[f] + */ +protected el_action_t +/*ARGSUSED*/ +vi_next_char(el, c) +    EditLine *el; +    int c; +{ +    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); + +} + + +/* vi_prev_char(): + *	Vi move to the character specified previous + *	[F] + */ +protected el_action_t +/*ARGSUSED*/ +vi_prev_char(el, c) +    EditLine *el; +    int c; +{ +    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); +} + + +/* vi_to_next_char(): + *	Vi move up to the character specified next + *	[t] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_next_char(el, c) +    EditLine *el; +    int c; +{ +    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); + +} + + +/* vi_to_prev_char(): + *	Vi move up to the character specified previous + *	[T] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_prev_char(el, c) +    EditLine *el; +    int c; +{ +    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); +} + + +/* vi_repeat_next_char(): + *	Vi repeat current character search in the same search direction + *	[;] + */ +protected el_action_t +/*ARGSUSED*/ +vi_repeat_next_char(el, c) +    EditLine *el; +    int c; +{ +    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); +} + + +/* vi_repeat_prev_char(): + *	Vi repeat current character search in the opposite search direction + *	[,] + */ +protected el_action_t +/*ARGSUSED*/ +vi_repeat_prev_char(el, c) +    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); +}  | 
