diff options
Diffstat (limited to 'cmd-line-utils')
105 files changed, 44226 insertions, 0 deletions
diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am new file mode 100644 index 00000000000..4c8d055df06 --- /dev/null +++ b/cmd-line-utils/libedit/Makefile.am @@ -0,0 +1,86 @@ +## Process this file with automake to create Makefile.in +# Makefile for the GNU readline library. +# Copyright (C) 1994,1996,1997 Free Software Foundation, Inc. + +ASRC=vi.c emacs.c common.c +AHDR=vi.h emacs.h common.h + +INCLUDES = -I$(top_srcdir)/include -I$(srcdir)/../.. -I.. + +noinst_LIBRARIES = liblibedit.a + +liblibedit_a_SOURCES = chared.c el.c fgetln.c history.c map.c \ + prompt.c readline.c search.c \ + strlcpy.c tokenizer.c vi.c common.c \ + emacs.c hist.c key.c parse.c read.c \ + refresh.c sig.c term.c tty.c help.c \ + fcns.c + +pkginclude_HEADERS = readline/readline.h + +noinst_HEADERS = chared.h el.h histedit.h key.h \ + parse.h refresh.h sig.h sys.h \ + tokenizer.h compat.h fgetln.h \ + hist.h map.h prompt.h search.h \ + strlcpy.h term.h tty.h + +DEFS = -DUNDEF_THREADS_HACK -DHAVE_CONFIG_H -DNO_KILL_INTR + +vi.h: vi.c makelist + sh ./makelist -h ./vi.c > $@.tmp && \ + mv $@.tmp $@ + +emacs.h: emacs.c makelist + sh ./makelist -h ./emacs.c > $@.tmp && \ + mv $@.tmp $@ + +common.h: common.c makelist + sh ./makelist -h ./common.c > $@.tmp && \ + mv $@.tmp $@ + +help.c: ${ASRC} makelist + sh ./makelist -bc ${ASRC} > $@.tmp && \ + mv $@.tmp $@ + +help.h: ${ASRC} makelist + sh ./makelist -bh ${ASRC} > $@.tmp && \ + mv $@.tmp $@ + +fcns.h: ${AHDR} makelist + sh ./makelist -fh ${AHDR} > $@.tmp && \ + mv $@.tmp $@ + +fcns.c: ${AHDR} fcns.h makelist + sh ./makelist -fc ${AHDR} > $@.tmp && \ + mv $@.tmp $@ + +#%.o: vi.h emacs.h common.h help.h fcns.h +#objects := $(patsubst %.c,%.o,$(wildcard *.c)) +#$(objects): vi.h emacs.h + +chared.o: vi.h emacs.h common.h help.h fcns.h +el.o: vi.h emacs.h common.h help.h fcns.h +fgetln.o: vi.h emacs.h common.h help.h fcns.h +history.o: vi.h emacs.h common.h help.h fcns.h +map.o: vi.h emacs.h common.h help.h fcns.h +prompt.o: vi.h emacs.h common.h help.h fcns.h +readline.o: vi.h emacs.h common.h help.h fcns.h +search.o: vi.h emacs.h common.h help.h fcns.h +strlcpy.o: vi.h emacs.h common.h help.h fcns.h +tokenizer.o: vi.h emacs.h common.h help.h fcns.h +vi.o: vi.h emacs.h common.h help.h fcns.h +common.o: vi.h emacs.h common.h help.h fcns.h +emacs.o: vi.h emacs.h common.h help.h fcns.h +hist.o: vi.h emacs.h common.h help.h fcns.h +key.o: vi.h emacs.h common.h help.h fcns.h +parse.o: vi.h emacs.h common.h help.h fcns.h +read.o: vi.h emacs.h common.h help.h fcns.h +refresh.o: vi.h emacs.h common.h help.h fcns.h +sig.o: vi.h emacs.h common.h help.h fcns.h +term.o: vi.h emacs.h common.h help.h fcns.h +tty.o: vi.h emacs.h common.h help.h fcns.h +help.o: vi.h emacs.h common.h help.h fcns.h +fcns.o: vi.h emacs.h common.h help.h fcns.h + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/cmd-line-utils/libedit/TEST/test.c b/cmd-line-utils/libedit/TEST/test.c new file mode 100644 index 00000000000..605341eac62 --- /dev/null +++ b/cmd-line-utils/libedit/TEST/test.c @@ -0,0 +1,269 @@ +/* $NetBSD: test.c,v 1.9 2000/09/04 23:36:41 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. + */ + +#include <sys/cdefs.h> +#include "compat.h" +#ifndef lint +__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 +__RCSID("$NetBSD: test.c,v 1.9 2000/09/04 23:36:41 lukem Exp $"); +#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 u_char complete(EditLine *, int); + int main(int, char **); +static char *prompt(EditLine *); +static void sig(int); + +static char * +prompt(EditLine *el) +{ + static char a[] = "Edit$"; + static char b[] = "Edit>"; + + return (continuation ? b : a); +} + +static void +sig(int i) +{ + + (void) fprintf(stderr, "Got signal %d.\n", i); + el_reset(el); +} + +static unsigned char +complete(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 +main(int argc, char *argv[]) +{ + int num; + const char *buf; + Tokenizer *tok; + int lastevent = 0, ncontinuation; + History *hist; + HistEvent ev; + + (void) signal(SIGINT, sig); + (void) signal(SIGQUIT, sig); + (void) signal(SIGHUP, sig); + (void) signal(SIGTERM, sig); + + hist = history_init(); /* Init the builtin history */ + /* Remember 100 events */ + history(hist, &ev, H_SETSIZE, 100); + + tok = tok_init(NULL); /* Initialize the tokenizer */ + + /* Initialize editline */ + el = el_init(*argv, stdin, stdout, stderr); + + 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); + + /* Bind tab to it */ + el_set(el, EL_BIND, "^I", "ed-complete", NULL); + + /* + * 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) + ncontinuation = 1; + +#if 0 + if (continuation) { + /* + * Append to the right event in case the user + * moved around in history. + */ + if (history(hist, &ev, H_SET, lastevent) == -1) + err(1, "%d: %s\n", lastevent, ev.str); + history(hist, &ev, H_ADD , buf); + } else { + history(hist, &ev, H_ENTER, buf); + lastevent = ev.num; + } +#else + /* Simpler */ + history(hist, &ev, continuation ? H_APPEND : H_ENTER, buf); +#endif + + continuation = ncontinuation; + ncontinuation = 0; + + if (strcmp(av[0], "history") == 0) { + int rv; + + switch (ac) { + case 1: + for (rv = history(hist, &ev, H_LAST); rv != -1; + rv = history(hist, &ev, H_PREV)) + (void) fprintf(stdout, "%4d %s", + ev.num, ev.str); + break; + + case 2: + if (strcmp(av[1], "clear") == 0) + history(hist, &ev, H_CLEAR); + else + goto badhist; + break; + + case 3: + if (strcmp(av[1], "load") == 0) + history(hist, &ev, H_LOAD, av[2]); + else if (strcmp(av[1], "save") == 0) + history(hist, &ev, 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/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c new file mode 100644 index 00000000000..6ac051c3bb0 --- /dev/null +++ b/cmd-line-utils/libedit/chared.c @@ -0,0 +1,690 @@ +/* $NetBSD: chared.c,v 1.14 2001/05/17 01:02:17 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. + */ + +#include "compat.h" + +/* + * chared.c: Character editor utilities + */ +#include "sys.h" + +#include <stdlib.h> +#include "el.h" + +/* value to leave unused in line buffer */ +#define EL_LEAVE 2 + +/* cv_undo(): + * Handle state for the vi undo command + */ +protected void +cv_undo(EditLine *el,int action, size_t 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(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; +} + + +/* c_delafter(): + * Delete num characters after the cursor + */ +protected void +c_delafter(EditLine *el, int num) +{ + + if (el->el_line.cursor + num > el->el_line.lastchar) + num = el->el_line.lastchar - el->el_line.cursor; + + if (num > 0) { + char *cp; + + if (el->el_map.current != el->el_map.emacs) + cv_undo(el, INSERT, (size_t)num, el->el_line.cursor); + + for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) + *cp = cp[num]; + + el->el_line.lastchar -= num; + } +} + + +/* c_delbefore(): + * Delete num characters before the cursor + */ +protected void +c_delbefore(EditLine *el, int num) +{ + + if (el->el_line.cursor - num < el->el_line.buffer) + num = el->el_line.cursor - el->el_line.buffer; + + if (num > 0) { + char *cp; + + if (el->el_map.current != el->el_map.emacs) + cv_undo(el, INSERT, (size_t)num, + el->el_line.cursor - num); + + for (cp = el->el_line.cursor - num; + cp <= el->el_line.lastchar; + cp++) + *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(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(int p) +{ + return (!isspace(p)); +} + + +/* c__prev_word(): + * Find the previous word + */ +protected char * +c__prev_word(char *p, char *low, int n, int (*wtest)(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(char *p, char *high, int n, int (*wtest)(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(EditLine *el, char *p, char *high, int n, int (*wtest)(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(EditLine *el, char *p, char *low, int n, int (*wtest)(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( + char *p, /* character position */ + int *num, /* Return value */ + int dval) /* dval is the number to subtract from like $-3 */ +{ + int i; + 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(EditLine *el) +{ + 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: + EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction)); + break; + } + + + el->el_chared.c_undo.ptr = el->el_line.cursor; + el->el_chared.c_undo.dsize = size; +} + + +#ifdef notdef +/* ce__endword(): + * Go to the end of this word according to emacs + */ +protected char * +ce__endword(char *p, char *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(char *p, char *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(EditLine *el) +{ + el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ); + if (el->el_line.buffer == NULL) + return (-1); + + (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); + if (el->el_chared.c_undo.buf == NULL) + return (-1); + (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ); + el->el_chared.c_undo.action = NOP; + el->el_chared.c_undo.isize = 0; + el->el_chared.c_undo.dsize = 0; + el->el_chared.c_undo.ptr = el->el_line.buffer; + + el->el_chared.c_vcmd.action = NOP; + el->el_chared.c_vcmd.pos = el->el_line.buffer; + el->el_chared.c_vcmd.ins = el->el_line.buffer; + + el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ); + if (el->el_chared.c_kill.buf == NULL) + return (-1); + (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 *)); + if (el->el_chared.c_macro.macro == NULL) + return (-1); + return (0); +} + +/* ch_reset(): + * Reset the character editor + */ +protected void +ch_reset(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_enlargebufs(): + * Enlarge line buffer to be able to hold twice as much characters. + * Returns 1 if successful, 0 if not. + */ +protected int +ch_enlargebufs(el, addlen) + EditLine *el; + size_t addlen; +{ + size_t sz, newsz; + char *newbuffer, *oldbuf, *oldkbuf; + + sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE; + newsz = sz * 2; + /* + * If newly required length is longer than current buffer, we need + * to make the buffer big enough to hold both old and new stuff. + */ + if (addlen > sz) { + while(newsz - sz < addlen) + newsz *= 2; + } + + /* + * Reallocate line buffer. + */ + newbuffer = el_realloc(el->el_line.buffer, newsz); + if (!newbuffer) + return 0; + + /* zero the newly added memory, leave old data in */ + (void) memset(&newbuffer[sz], 0, newsz - sz); + + oldbuf = el->el_line.buffer; + + el->el_line.buffer = newbuffer; + el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf); + el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf); + el->el_line.limit = &newbuffer[newsz - EL_LEAVE]; + + /* + * Reallocate kill buffer. + */ + newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz); + if (!newbuffer) + return 0; + + /* zero the newly added memory, leave old data in */ + (void) memset(&newbuffer[sz], 0, newsz - sz); + + oldkbuf = el->el_chared.c_kill.buf; + + el->el_chared.c_kill.buf = newbuffer; + el->el_chared.c_kill.last = newbuffer + + (el->el_chared.c_kill.last - oldkbuf); + el->el_chared.c_kill.mark = el->el_line.buffer + + (el->el_chared.c_kill.mark - oldbuf); + + /* + * Reallocate undo buffer. + */ + newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz); + if (!newbuffer) + return 0; + + /* zero the newly added memory, leave old data in */ + (void) memset(&newbuffer[sz], 0, newsz - sz); + + el->el_chared.c_undo.ptr = el->el_line.buffer + + (el->el_chared.c_undo.ptr - oldbuf); + el->el_chared.c_undo.buf = newbuffer; + + if (!hist_enlargebuf(el, sz, newsz)) + return 0; + + return 1; +} + +/* ch_end(): + * Free the data structures used by the editor + */ +protected void +ch_end(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(EditLine *el, const char *s) +{ + size_t len; + + if ((len = strlen(s)) == 0) + return (-1); + if (el->el_line.lastchar + len >= el->el_line.limit) { + if (!ch_enlargebufs(el, len)) + return (-1); + } + + c_insert(el, (int)len); + while (*s) + *el->el_line.cursor++ = *s++; + return (0); +} + + +/* el_deletestr(): + * Delete num characters before the cursor + */ +public void +el_deletestr(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(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(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/cmd-line-utils/libedit/chared.h b/cmd-line-utils/libedit/chared.h new file mode 100644 index 00000000000..2eb9ad32886 --- /dev/null +++ b/cmd-line-utils/libedit/chared.h @@ -0,0 +1,159 @@ +/* $NetBSD: chared.h,v 1.6 2001/01/10 07:45:41 jdolecek 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; + size_t isize; + size_t 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(int); +protected void cv_delfini(EditLine *); +protected char *cv__endword(char *, char *, int); +protected int ce__isword(int); +protected void cv_undo(EditLine *, int, size_t, char *); +protected char *cv_next_word(EditLine*, char *, char *, int, int (*)(int)); +protected char *cv_prev_word(EditLine*, char *, char *, int, int (*)(int)); +protected char *c__next_word(char *, char *, int, int (*)(int)); +protected char *c__prev_word(char *, char *, int, int (*)(int)); +protected void c_insert(EditLine *, int); +protected void c_delbefore(EditLine *, int); +protected void c_delafter(EditLine *, int); +protected int c_gets(EditLine *, char *); +protected int c_hpos(EditLine *); + +protected int ch_init(EditLine *); +protected void ch_reset(EditLine *); +protected int ch_enlargebufs __P((EditLine *, size_t)); +protected void ch_end(EditLine *); + +#endif /* _h_el_chared */ diff --git a/cmd-line-utils/libedit/common.c b/cmd-line-utils/libedit/common.c new file mode 100644 index 00000000000..9ac6af9ac1b --- /dev/null +++ b/cmd-line-utils/libedit/common.c @@ -0,0 +1,954 @@ +/* $NetBSD: common.c,v 1.10 2001/01/10 07:45:41 jdolecek 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. + */ + +#include "compat.h" + +/* + * 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(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) { + /* end of buffer space, try to allocate more */ + if (!ch_enlargebufs(el, (size_t) el->el_state.argument)) + return CC_ERROR; /* error allocating more */ + } + + if (el->el_state.argument == 1) { + if (el->el_state.inputmode != MODE_INSERT) { + el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] = + *el->el_line.cursor; + el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] = + '\0'; + c_delafter(el, 1); + } + c_insert(el, 1); + + *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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ +#ifdef notdef /* XXX */ +#define EL el->el_line + (void) fprintf(el->el_errlfile, + "\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) + /* bounds check */ + el->el_line.cursor = el->el_line.lastchar - 1; + return (CC_REFRESH); +} + + +/* ed_kill_line(): + * Cut to the end of line + * [^K] [^K] + */ +protected el_action_t +/*ARGSUSED*/ +ed_kill_line(EditLine *el, int c __attribute__((unused))) +{ + 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; + /* zap! -- delete to end */ + el->el_line.lastchar = el->el_line.cursor; + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_line.cursor = el->el_line.buffer; + + if (el->el_map.type == MAP_VI) { + /* We want FIRST non space character */ + while (isspace((unsigned char) *el->el_line.cursor)) + el->el_line.cursor++; + if (el->el_chared.c_vcmd.action & DELETE) { + 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(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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(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(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) { + if (!ch_enlargebufs(el, 1)) + return (CC_ERROR); + } + + if (el->el_state.inputmode != MODE_INSERT) { + el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] = + *el->el_line.cursor; + el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] = + '\0'; + c_delafter(el, 1); + } + c_insert(el, 1); + *el->el_line.cursor++ = c; + el->el_state.doingarg = 0; + re_fastaddc(el); + } + return (CC_NORM); +} + + +/* ed_argument_digit(): + * Digit that starts argument + * For ESC-n + */ +protected el_action_t +ed_argument_digit(EditLine *el, 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_dsusp(): + * Tty delayed suspend character + * [^Y] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_dsusp(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_flush_output(): + * Tty flush output characters + * [^O] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_flush_output(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_sigquit(): + * Tty quit character + * [^\] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_sigquit(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_sigtstp(): + * Tty suspend character + * [^Z] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_sigtstp(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_stop_output(): + * Tty disallow output characters + * [^S] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_stop_output(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_tty_start_output(): + * Tty allow output characters + * [^Q] + */ +protected el_action_t +/*ARGSUSED*/ +ed_tty_start_output(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_newline(): + * Execute command + * [^J] + */ +protected el_action_t +/*ARGSUSED*/ +ed_newline(EditLine *el, int c __attribute__((unused))) +{ + + re_goto_bottom(el); + *el->el_line.lastchar++ = '\n'; + *el->el_line.lastchar = '\0'; + if (el->el_map.type == MAP_VI) + el->el_chared.c_vcmd.ins = el->el_line.buffer; + return (CC_NEWLINE); +} + + +/* ed_delete_prev_char(): + * Delete the character to the left of the cursor + * [^?] + */ +protected el_action_t +/*ARGSUSED*/ +ed_delete_prev_char(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_REDISPLAY); +} + + +/* ed_start_over(): + * Erase current line and start from scratch + * [^G] + */ +protected el_action_t +/*ARGSUSED*/ +ed_start_over(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el __attribute__((unused)), + int c __attribute__((unused))) +{ + + return (CC_NORM); +} + + +/* ed_prev_history(): + * Move to the previous history line + * [^P] [k] + */ +protected el_action_t +/*ARGSUSED*/ +ed_prev_history(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + const char *hp; + int h; + bool_t found = 0; + + el->el_chared.c_vcmd.action = NOP; + el->el_chared.c_undo.action = NOP; + *el->el_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, (size_t) + (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(EditLine *el, int c __attribute__((unused))) +{ + const char *hp; + int h; + bool_t found = 0; + + el->el_chared.c_vcmd.action = NOP; + el->el_chared.c_undo.action = NOP; + *el->el_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, (size_t) + (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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + char tmpbuf[EL_BUFSIZ]; + int tmplen; + + el->el_line.buffer[0] = '\0'; + el->el_line.lastchar = el->el_line.buffer; + el->el_line.cursor = el->el_line.buffer; + + 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/cmd-line-utils/libedit/compat.h b/cmd-line-utils/libedit/compat.h new file mode 100644 index 00000000000..f432ac45dfc --- /dev/null +++ b/cmd-line-utils/libedit/compat.h @@ -0,0 +1,39 @@ +#ifndef __LIBEDIT_COMPATH_H +#define __LIBEDIT_COMPATH_H + +#define __RCSID(x) +#define __COPYRIGHT(x) + +#include "compat_conf.h" + +#ifndef HAVE_VIS_H +/* string visual representation - may want to reimplement */ +#define strvis(d,s,m) strcpy(d,s) +#define strunvis(d,s) strcpy(d,s) +#endif + +#ifndef HAVE_FGETLN +#include "fgetln.h" +#endif + +#ifndef HAVE_ISSETUGID +#define issetugid() (getuid()!=geteuid() || getegid()!=getgid()) +#endif + +#ifndef HAVE_STRLCPY +#include "strlcpy.h" +#endif + +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +#ifndef __P +#ifdef __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif +#endif + +#endif diff --git a/cmd-line-utils/libedit/compat_conf.h b/cmd-line-utils/libedit/compat_conf.h new file mode 100644 index 00000000000..e2b9557f5b1 --- /dev/null +++ b/cmd-line-utils/libedit/compat_conf.h @@ -0,0 +1,2 @@ + +#include "my_config.h" diff --git a/cmd-line-utils/libedit/editline.3 b/cmd-line-utils/libedit/editline.3 new file mode 100644 index 00000000000..1b812ebcc79 --- /dev/null +++ b/cmd-line-utils/libedit/editline.3 @@ -0,0 +1,619 @@ +.\" $NetBSD: editline.3,v 1.21 2001/04/02 18:29:49 wiz Exp $ +.\" +.\" Copyright (c) 1997-1999 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 FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd November 12, 1999 +.Os +.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 LIBRARY +.Lb libedit +.Sh SYNOPSIS +.Fd #include <histedit.h> +.Ft EditLine * +.Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr" +.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_get "EditLine *e" "int op" "void *result" +.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" "const char *str" +.Ft void +.Fn el_deletestr "EditLine *e" "int count" +.Ft History * +.Fn history_init +.Ft void +.Fn history_end "History *h" +.Ft int +.Fn history "History *h" "HistEvent *ev" "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 , +.Fa fout +and +.Fa ferr +are the input, output, and error 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. +.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_RPROMPT , Fa "char *(*f)(EditLine *)" +Define right side 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_REFRESH_BEEP +Refresh display, and beep. +.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 . +.It Dv EL_EDITMODE , Fa "int flag" +If +.Fa flag +is non-zero, +editing is enabled (the default). +Note that this is only an indication, and does not +affect the operation of +.Nm "" . +At this time, it is the caller's responsibility to +check this +(using +.Fn el_get ) +to determine if editing should be enabled or not. +.El +.It Fn el_get +Get +.Nm +parameters. +.Fa op +determines which parameter to retrieve into +.Fa result . +.Pp +The following values for +.Fa op +are supported, along with actual type of +.Fa result : +.Bl -tag -width 4n +.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)" +Return a pointer to the function that displays the prompt. +.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)" +Return a pointer to the function that displays the rightside prompt. +.It Dv EL_EDITOR , Fa "const char *" +Return the name of the editor, which will be one of +.Dq emacs +or +.Dq vi . +.It Dv EL_SIGNAL , Fa "int *" +Return non-zero if +.Nm +has installed private signal handlers (see +.Fn el_get +above). +.It Dv EL_EDITMODE, Fa "int *" +Return non-zero if editing is enabled. +.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. +.Fa ev +is changed accordingly to operation. +The following values for +.Fa op +are supported, along with the required argument list: +.Bl -tag -width 4n +.It Dv H_SETSIZE , Fa "int size" +Set size of history to +.Fa size +elements. +.It Dv H_GETSIZE +Get number of events currently in history. +.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_sfun_t set" , +.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_SET +Set the cursor to point to the requested element. +.It Dv H_ADD , Fa "const char *str" +Append +.Fa str +to the current element of the history, or create an element with +.It Dv H_APPEND , Fa "const char *str" +Append +.Fa str +to the last new element of the history. +.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 +.Pp +.Fn history +returns 0 if the operation +.Fa op +succeeds. Otherwise, -1 is returned and +.Fa ev +is updated to contain more details about the error. +.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 . +.Dv CC_REDISPLAY +appeared in +.Nx 1.3 . +.Dv CC_REFRESH_BEEP , +.Dv EL_EDITMODE +and the readline emulation appeared in +.Nx 1.4 . +.Dv EL_RPROMPT +appeared in +.Nx 1.5 . +.Sh AUTHORS +The +.Nm +library was written by Christos Zoulas. +Luke Mewburn wrote this manual and implemented +.Dv CC_REDISPLAY , +.Dv CC_REFRESH_BEEP , +.Dv EL_EDITMODE , +and +.Dv EL_RPROMPT . +Jaromir Dolecek implemented the readline emulation. +.Sh BUGS +The tokenization functions are not publically defined in +.Fd <histedit.h>. +.Pp +At this time, it is the responsibility of the caller to +check the result of the +.Dv EL_EDITMODE +operation of +.Fn el_get +(after an +.Fn el_source +or +.Fn el_parse ) +to determine if +.Nm +should be used for further input. +I.e., +.Dv EL_EDITMODE +is purely an indication of the result of the most recent +.Xr editrc 5 +.Ic edit +command. diff --git a/cmd-line-utils/libedit/editrc.5 b/cmd-line-utils/libedit/editrc.5 new file mode 100644 index 00000000000..b1122618939 --- /dev/null +++ b/cmd-line-utils/libedit/editrc.5 @@ -0,0 +1,491 @@ +.\" $NetBSD: editrc.5,v 1.11 2001/06/19 13:42:09 wiz Exp $ +.\" +.\" Copyright (c) 1997-2000 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 FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd November 8, 2000 +.Os +.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: +.Dl [prog:]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. +.Pp +If +.Ar prog +is absent, +.Ar command +is executed for all programs. +.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 command +may be one of the commands documented in +.Sx "EDITOR COMMANDS" +below, or another key. +.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-existent capabilities, rather than +causing an error. +.Fl v +causes messages to be verbose. +.It Ic edit Op Li on | Li off +Enable or disable the +.Nm editline +functionality in a program. +.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 EDITOR COMMANDS +The following editor commands are available for use in key bindings: +.\" Section automatically generated with makelist +.Bl -tag -width 4n +.It Ic vi-paste-next +Vi paste previous deletion to the right of the cursor. +.It Ic vi-paste-prev +Vi paste previous deletion to the left of the cursor. +.It Ic vi-prev-space-word +Vi move to the previous space delimited word. +.It Ic vi-prev-word +Vi move to the previous word. +.It Ic vi-next-space-word +Vi move to the next space delimited word. +.It Ic vi-next-word +Vi move to the next word. +.It Ic vi-change-case +Vi change case of character under the cursor and advance one character. +.It Ic vi-change-meta +Vi change prefix command. +.It Ic vi-insert-at-bol +Vi enter insert mode at the beginning of line. +.It Ic vi-replace-char +Vi replace character under the cursor with the next character typed. +.It Ic vi-replace-mode +Vi enter replace mode. +.It Ic vi-substitute-char +Vi replace character under the cursor and enter insert mode. +.It Ic vi-substitute-line +Vi substitute entire line. +.It Ic vi-change-to-eol +Vi change to end of line. +.It Ic vi-insert +Vi enter insert mode. +.It Ic vi-add +Vi enter insert mode after the cursor. +.It Ic vi-add-at-eol +Vi enter insert mode at end of line. +.It Ic vi-delete-meta +Vi delete prefix command. +.It Ic vi-end-word +Vi move to the end of the current space delimited word. +.It Ic vi-to-end-word +Vi move to the end of the current word. +.It Ic vi-undo +Vi undo last change. +.It Ic vi-command-mode +Vi enter command mode (use alternative key bindings). +.It Ic vi-zero +Vi move to the beginning of line. +.It Ic vi-delete-prev-char +Vi move to previous character (backspace). +.It Ic vi-list-or-eof +Vi list choices for completion or indicate end of file if empty line. +.It Ic vi-kill-line-prev +Vi cut from beginning of line to cursor. +.It Ic vi-search-prev +Vi search history previous. +.It Ic vi-search-next +Vi search history next. +.It Ic vi-repeat-search-next +Vi repeat current search in the same search direction. +.It Ic vi-repeat-search-prev +Vi repeat current search in the opposite search direction. +.It Ic vi-next-char +Vi move to the character specified next. +.It Ic vi-prev-char +Vi move to the character specified previous. +.It Ic vi-to-next-char +Vi move up to the character specified next. +.It Ic vi-to-prev-char +Vi move up to the character specified previous. +.It Ic vi-repeat-next-char +Vi repeat current character search in the same search direction. +.It Ic vi-repeat-prev-char +Vi repeat current character search in the opposite search direction. +.It Ic em-delete-or-list +Delete character under cursor or list completions if at end of line. +.It Ic em-delete-next-word +Cut from cursor to end of current word. +.It Ic em-yank +Paste cut buffer at cursor position. +.It Ic em-kill-line +Cut the entire line and save in cut buffer. +.It Ic em-kill-region +Cut area between mark and cursor and save in cut buffer. +.It Ic em-copy-region +Copy area between mark and cursor to cut buffer. +.It Ic em-gosmacs-traspose +Exchange the two characters before the cursor. +.It Ic em-next-word +Move next to end of current word. +.It Ic em-upper-case +Uppercase the characters from cursor to end of current word. +.It Ic em-capitol-case +Capitalize the characters from cursor to end of current word. +.It Ic em-lower-case +Lowercase the characters from cursor to end of current word. +.It Ic em-set-mark +Set the mark at cursor. +.It Ic em-exchange-mark +Exchange the cursor and mark. +.It Ic em-universal-argument +Universal argument (argument times 4). +.It Ic em-meta-next +Add 8th bit to next character typed. +.It Ic em-toggle-overwrite +Switch from insert to overwrite mode or vice versa. +.It Ic em-copy-prev-word +Copy current word to cursor. +.It Ic em-inc-search-next +Emacs incremental next search. +.It Ic em-inc-search-prev +Emacs incremental reverse search. +.It Ic ed-end-of-file +Indicate end of file. +.It Ic ed-insert +Add character to the line. +.It Ic ed-delete-prev-word +Delete from beginning of current word to cursor. +.It Ic ed-delete-next-char +Delete character under cursor. +.It Ic ed-kill-line +Cut to the end of line. +.It Ic ed-move-to-end +Move cursor to the end of line. +.It Ic ed-move-to-beg +Move cursor to the beginning of line. +.It Ic ed-transpose-chars +Exchange the character to the left of the cursor with the one under it. +.It Ic ed-next-char +Move to the right one character. +.It Ic ed-prev-word +Move to the beginning of the current word. +.It Ic ed-prev-char +Move to the left one character. +.It Ic ed-quoted-insert +Add the next character typed verbatim. +.It Ic ed-digit +Adds to argument or enters a digit. +.It Ic ed-argument-digit +Digit that starts argument. +.It Ic ed-unassigned +Indicates unbound character. +.It Ic ed-tty-sigint +Tty interrupt character. +.It Ic ed-tty-dsusp +Tty delayed suspend character. +.It Ic ed-tty-flush-output +Tty flush output characters. +.It Ic ed-tty-sigquit +Tty quit character. +.It Ic ed-tty-sigtstp +Tty suspend character. +.It Ic ed-tty-stop-output +Tty disallow output characters. +.It Ic ed-tty-start-output +Tty allow output characters. +.It Ic ed-newline +Execute command. +.It Ic ed-delete-prev-char +Delete the character to the left of the cursor. +.It Ic ed-clear-screen +Clear screen leaving current line at the top. +.It Ic ed-redisplay +Redisplay everything. +.It Ic ed-start-over +Erase current line and start from scratch. +.It Ic ed-sequence-lead-in +First character in a bound sequence. +.It Ic ed-prev-history +Move to the previous history line. +.It Ic ed-next-history +Move to the next history line. +.It Ic ed-search-prev-history +Search previous in history for a line matching the current. +.It Ic ed-search-next-history +Search next in history for a line matching the current. +.It Ic ed-prev-line +Move up one line. +.It Ic ed-next-line +Move down one line. +.It Ic ed-command +Editline extended command. +.El +.\" End of section automatically generated with makelist +.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/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c new file mode 100644 index 00000000000..d436d113419 --- /dev/null +++ b/cmd-line-utils/libedit/el.c @@ -0,0 +1,468 @@ +/* $NetBSD: el.c,v 1.21 2001/01/05 22:45:30 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. + */ + +#include "compat.h" + +/* + * el.c: EditLine interface functions + */ +#include "sys.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include "el.h" + +/* el_init(): + * Initialize editline and set default parameters. + */ +public EditLine * +el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) +{ + + EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); +#ifdef DEBUG + char *tty; +#endif + + if (el == NULL) + return (NULL); + + memset(el, 0, sizeof(EditLine)); + + el->el_infd = fileno(fin); + el->el_outfile = fout; + el->el_errfile = ferr; + el->el_prog = strdup(prog); + + /* + * Initialize all the modules. Order is important!!! + */ + el->el_flags = 0; + + (void) term_init(el); + (void) key_init(el); + (void) map_init(el); + if (tty_init(el) == -1) + el->el_flags |= NO_TTY; + (void) ch_init(el); + (void) search_init(el); + (void) hist_init(el); + (void) prompt_init(el); + (void) sig_init(el); + + return (el); +} + + +/* el_end(): + * Clean up. + */ +public void +el_end(EditLine *el) +{ + + if (el == NULL) + return; + + el_reset(el); + + term_end(el); + key_end(el); + map_end(el); + tty_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); +} + + +/* el_reset(): + * Reset the tty and the parser + */ +public void +el_reset(EditLine *el) +{ + + tty_cookedmode(el); + ch_reset(el); /* XXX: Do we want that? */ +} + + +/* el_set(): + * set the editline parameters + */ +public int +el_set(EditLine *el, int op, ...) +{ + va_list va; + int rv; + va_start(va, op); + + if (el == NULL) + return (-1); + switch (op) { + case EL_PROMPT: + case EL_RPROMPT: + rv = prompt_set(el, va_arg(va, el_pfunc_t), op); + 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: + { + const 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; + EL_ABORT((el->el_errfile, "Bad op %d\n", op)); + 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; + } + + case EL_EDITMODE: + if (va_arg(va, int)) + el->el_flags &= ~EDIT_DISABLED; + else + el->el_flags |= EDIT_DISABLED; + rv = 0; + break; + + default: + rv = -1; + } + + va_end(va); + return (rv); +} + + +/* el_get(): + * retrieve the editline parameters + */ +public int +el_get(EditLine *el, int op, void *ret) +{ + int rv; + + if (el == NULL || ret == NULL) + return (-1); + switch (op) { + case EL_PROMPT: + case EL_RPROMPT: + rv = prompt_get(el, (el_pfunc_t *) & ret, op); + break; + + case EL_EDITOR: + rv = map_get_editor(el, (const char **) &ret); + break; + + case EL_SIGNAL: + *((int *) ret) = (el->el_flags & HANDLE_SIGNALS); + rv = 0; + break; + + case EL_EDITMODE: + *((int *) ret) = (!(el->el_flags & EDIT_DISABLED)); + rv = 0; + break; + +#if 0 /* XXX */ + case EL_TERMINAL: + rv = term_get(el, (const char *) &ret); + 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; + EL_ABORT((el->errfile, "Bad op %d\n", op)); + 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; +#endif /* XXX */ + + default: + rv = -1; + } + + return (rv); +} + + +/* el_line(): + * Return editing info + */ +public const LineInfo * +el_line(EditLine *el) +{ + + return (const LineInfo *) (void *) &el->el_line; +} + +static const char elpath[] = "/.editrc"; + +/* el_source(): + * Source a file + */ +public int +el_source(EditLine *el, const char *fname) +{ + FILE *fp; + size_t len; + char *ptr, path[MAXPATHLEN]; + + fp = NULL; + if (fname == NULL) { + if (issetugid()) + return (-1); + if ((ptr = getenv("HOME")) == NULL) + return (-1); + if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) + return (-1); + if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) + return (-1); + fname = path; + } + if (fp == NULL) + fp = fopen(fname, "r"); + if (fp == NULL) + return (-1); + + while ((ptr = fgetln(fp, &len)) != NULL) { + if (len > 0 && 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(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); +} + + +/* el_beep(): + * Called from the program to beep + */ +public void +el_beep(EditLine *el) +{ + + term_beep(el); +} + + +/* el_editmode() + * Set the state of EDIT_DISABLED from the `edit' command. + */ +protected int +/*ARGSUSED*/ +el_editmode(EditLine *el, int argc, const char **argv) +{ + const char *how; + + if (argv == NULL || argc != 2 || argv[1] == NULL) + return (-1); + + how = argv[1]; + if (strcmp(how, "on") == 0) + el->el_flags &= ~EDIT_DISABLED; + else if (strcmp(how, "off") == 0) + el->el_flags |= EDIT_DISABLED; + else { + (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); + return (-1); + } + return (0); +} diff --git a/cmd-line-utils/libedit/el.h b/cmd-line-utils/libedit/el.h new file mode 100644 index 00000000000..484cbab6122 --- /dev/null +++ b/cmd-line-utils/libedit/el.h @@ -0,0 +1,142 @@ +/* $NetBSD: el.h,v 1.8 2001/01/06 14:44:50 jdolecek 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<<0 +#define NO_TTY 1<<1 +#define EDIT_DISABLED 1<<2 + +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; + int v; +} coord_t; + +typedef struct el_line_t { + char *buffer; /* Input line */ + char *cursor; /* Cursor position */ + char *lastchar; /* Last character */ + const char *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 */ + char **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_prompt_t el_rprompt; /* 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 */ +}; + +protected int el_editmode(EditLine *, int, const char **); + +#ifdef DEBUG +#define EL_ABORT(a) (void) (fprintf(el->el_errfile, "%s, %d: ", \ + __FILE__, __LINE__), fprintf a, abort()) +#else +#define EL_ABORT(a) abort() +#endif +#endif /* _h_el */ diff --git a/cmd-line-utils/libedit/emacs.c b/cmd-line-utils/libedit/emacs.c new file mode 100644 index 00000000000..bb5ffb2a9f6 --- /dev/null +++ b/cmd-line-utils/libedit/emacs.c @@ -0,0 +1,482 @@ +/* $NetBSD: emacs.c,v 1.9 2001/01/10 07:45:41 jdolecek 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. + */ + +#include "compat.h" + +/* + * 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + char *kp, *cp; + + if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { + if (!ch_enlargebufs(el, 1)) + return (CC_ERROR); + } + + if (el->el_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(EditLine *el, int c __attribute__((unused))) +{ + 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; + /* zap! -- delete all of it */ + el->el_line.lastchar = el->el_line.buffer; + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + 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((unsigned char) *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(EditLine *el, int c __attribute__((unused))) +{ + 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((unsigned char) *cp)) { + if (islower((unsigned char) *cp)) + *cp = toupper(*cp); + cp++; + break; + } + } + for (; cp < ep; cp++) + if (isupper((unsigned char) *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(EditLine *el, int c __attribute__((unused))) +{ + 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((unsigned char) *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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ /* 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_search.patlen = 0; + return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); +} diff --git a/cmd-line-utils/libedit/fgetln.c b/cmd-line-utils/libedit/fgetln.c new file mode 100644 index 00000000000..9804866147f --- /dev/null +++ b/cmd-line-utils/libedit/fgetln.c @@ -0,0 +1,108 @@ +#include <stdio.h> +#include "compat.h" + +#ifndef HAVE_FGETLN + +#ifdef HAVE_GETLINE + +extern int getline (char **lineptr, size_t *n, FILE *stream); + +#else + +/* The interface here is that of GNU libc's getline */ +static int +getline (char **lineptr, size_t *n, FILE *stream) +{ +#define EXPAND_CHUNK 16 + + int n_read = 0; + char *line = *lineptr; + + if (lineptr == NULL) return -1; + if (n == NULL) return -1; + if (stream == NULL) return -1; + if (*lineptr == NULL || *n == 0) return -1; + +#ifdef HAVE_FLOCKFILE + flockfile (stream); +#endif + + while (1) + { + int c; + +#ifdef HAVE_FLOCKFILE + c = getc_unlocked (stream); +#else + c = getc (stream); +#endif + + if (c == EOF) + { + if (n_read > 0) + line[n_read] = '\0'; + break; + } + + if (n_read + 2 >= *n) + { + size_t new_size; + + if (*n == 0) + new_size = 16; + else + new_size = *n * 2; + + if (*n >= new_size) /* Overflowed size_t */ + line = NULL; + else + line = (char *)*lineptr ? realloc (*lineptr, new_size) : malloc (new_size); + + if (line) + { + *lineptr = line; + *n = new_size; + } + else + { + if (*n > 0) + { + (*lineptr)[*n - 1] = '\0'; + n_read = *n - 2; + } + break; + } + } + + line[n_read] = c; + n_read++; + + if (c == '\n') + { + line[n_read] = '\0'; + break; + } + } + +#ifdef HAVE_FLOCKFILE + funlockfile (stream); +#endif + + return n_read - 1; +} +#endif /* ! HAVE_GETLINE */ + +char *fgetln(FILE *stream, size_t *len) +{ + char *ptr = NULL; + int sz; + size_t length= 0; + + sz = getline(&ptr, &length, stream); + if(len) { + *len = sz; + } + + return sz >= 0 ? ptr : NULL; +} +#endif diff --git a/cmd-line-utils/libedit/fgetln.h b/cmd-line-utils/libedit/fgetln.h new file mode 100644 index 00000000000..b2ddce01da9 --- /dev/null +++ b/cmd-line-utils/libedit/fgetln.h @@ -0,0 +1,3 @@ +#include <stdio.h> + +char *fgetln(FILE *stream, size_t *len); diff --git a/cmd-line-utils/libedit/hist.c b/cmd-line-utils/libedit/hist.c new file mode 100644 index 00000000000..2b20c7d14dc --- /dev/null +++ b/cmd-line-utils/libedit/hist.c @@ -0,0 +1,192 @@ +/* $NetBSD: hist.c,v 1.9 2001/05/17 01:02:17 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. + */ + +#include "compat.h" + +/* + * hist.c: History access functions + */ +#include "sys.h" +#include <stdlib.h> +#include "el.h" + +/* hist_init(): + * Initialization function. + */ +protected int +hist_init(EditLine *el) +{ + + el->el_history.fun = NULL; + el->el_history.ref = NULL; + el->el_history.buf = (char *) el_malloc(EL_BUFSIZ); + el->el_history.sz = EL_BUFSIZ; + if (el->el_history.buf == NULL) + return (-1); + el->el_history.last = el->el_history.buf; + return (0); +} + + +/* hist_end(): + * clean up history; + */ +protected void +hist_end(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(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(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->el_history.sz); + 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, + (size_t)(el->el_line.limit - el->el_line.buffer)); + el->el_line.lastchar = el->el_line.buffer + strlen(el->el_line.buffer); + + if (el->el_line.lastchar > el->el_line.buffer) { + if (el->el_line.lastchar[-1] == '\n') + el->el_line.lastchar--; + if (el->el_line.lastchar[-1] == ' ') + el->el_line.lastchar--; + if (el->el_line.lastchar < el->el_line.buffer) + el->el_line.lastchar = el->el_line.buffer; + } +#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(EditLine *el, int argc __attribute__((unused)), + const char **argv __attribute__((unused))) +{ + 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); +} + +/* hist_enlargebuf() + * Enlarge history buffer to specified value. Called from el_enlargebufs(). + * Return 0 for failure, 1 for success. + */ +protected int +/*ARGSUSED*/ +hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz) +{ + char *newbuf; + + newbuf = realloc(el->el_history.buf, newsz); + if (!newbuf) + return 0; + + (void) memset(&newbuf[oldsz], '\0', newsz - oldsz); + + el->el_history.last = newbuf + + (el->el_history.last - el->el_history.buf); + el->el_history.buf = newbuf; + el->el_history.sz = newsz; + + return 1; +} diff --git a/cmd-line-utils/libedit/hist.h b/cmd-line-utils/libedit/hist.h new file mode 100644 index 00000000000..e650b6a55a9 --- /dev/null +++ b/cmd-line-utils/libedit/hist.h @@ -0,0 +1,80 @@ +/* $NetBSD: hist.h,v 1.6 2001/01/10 07:45:41 jdolecek 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 int (*hist_fun_t)(ptr_t, HistEvent *, int, ...); + +typedef struct el_history_t { + char *buf; /* The history buffer */ + size_t sz; /* Size of 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 */ + HistEvent ev; /* Event cookie */ +} el_history_t; + +#define HIST_FUN(el, fn, arg) \ + ((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \ + fn, arg)) == -1) ? 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(EditLine *); +protected void hist_end(EditLine *); +protected el_action_t hist_get(EditLine *); +protected int hist_set(EditLine *, hist_fun_t, ptr_t); +protected int hist_list(EditLine *, int, const char **); +protected int hist_enlargebuf(EditLine *, size_t, size_t); + +#endif /* _h_el_hist */ diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h new file mode 100644 index 00000000000..0b8d175cef1 --- /dev/null +++ b/cmd-line-utils/libedit/histedit.h @@ -0,0 +1,190 @@ +/* $NetBSD: histedit.h,v 1.16 2000/09/04 22:06:30 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. + * + * @(#)histedit.h 8.2 (Berkeley) 1/3/94 + */ + +/* + * histedit.h: Line editor and history interface. + */ +#ifndef _HISTEDIT_H_ +#define _HISTEDIT_H_ + +#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 +#define CC_REFRESH_BEEP 9 + +/* + * Initialization, cleanup, and resetting + */ +EditLine *el_init(const char *, FILE *, FILE *, FILE *); +void el_reset(EditLine *); +void el_end(EditLine *); + + +/* + * Get a line, a character or push a string back in the input queue + */ +const char *el_gets(EditLine *, int *); +int el_getc(EditLine *, char *); +void el_push(EditLine *, const char *); + +/* + * Beep! + */ +void el_beep(EditLine *); + +/* + * High level function internals control + * Parses argc, argv array and executes builtin editline commands + */ +int el_parse(EditLine *, int, const char **); + +/* + * Low level editline access functions + */ +int el_set(EditLine *, int, ...); +int el_get(EditLine *, int, void *); + +/* + * 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 *); */ +#define EL_EDITMODE 11 /* , int); */ +#define EL_RPROMPT 12 /* , el_pfunc_t); */ + +/* + * Source named file or $PWD/.editrc or $HOME/.editrc + */ +int el_source(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(EditLine *); + + +/* + * User-defined function interface. + */ +const LineInfo *el_line(EditLine *); +int el_insertstr(EditLine *, const char *); +void el_deletestr(EditLine *, int); + +/* + * ==== History ==== + */ + +typedef struct history History; + +typedef struct HistEvent { + int num; + const char *str; +} HistEvent; + +/* + * History access functions. + */ +History * history_init(void); +void history_end(History *); + +int history(History *, HistEvent *, int, ...); + +#define H_FUNC 0 /* , UTSL */ +#define H_SETSIZE 1 /* , const int); */ +#define H_GETSIZE 2 /* , void); */ +#define H_FIRST 3 /* , void); */ +#define H_LAST 4 /* , void); */ +#define H_PREV 5 /* , void); */ +#define H_NEXT 6 /* , void); */ +#define H_CURR 8 /* , const int); */ +#define H_SET 7 /* , void); */ +#define H_ADD 9 /* , const char *); */ +#define H_ENTER 10 /* , const char *); */ +#define H_APPEND 11 /* , const char *); */ +#define H_END 12 /* , void); */ +#define H_NEXT_STR 13 /* , const char *); */ +#define H_PREV_STR 14 /* , const char *); */ +#define H_NEXT_EVENT 15 /* , const int); */ +#define H_PREV_EVENT 16 /* , const int); */ +#define H_LOAD 17 /* , const char *); */ +#define H_SAVE 18 /* , const char *); */ +#define H_CLEAR 19 /* , void); */ + +#endif /* _HISTEDIT_H_ */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c new file mode 100644 index 00000000000..90d94e7fc18 --- /dev/null +++ b/cmd-line-utils/libedit/history.c @@ -0,0 +1,864 @@ +/* $NetBSD: history.c,v 1.17 2001/03/20 00:08:31 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. + */ + +#include "compat.h" + +/* + * hist.c: History access functions + */ +#include "sys.h" + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#ifdef HAVE_VIS_H +#include <vis.h> +#endif +#include <sys/stat.h> + +static const char hist_cookie[] = "_HiStOrY_V2_\n"; + +#include "histedit.h" + +typedef int (*history_gfun_t)(ptr_t, HistEvent *); +typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *); +typedef void (*history_vfun_t)(ptr_t, HistEvent *); +typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int); + +struct history { + ptr_t h_ref; /* Argument for history fcns */ + int h_ent; /* Last entry point for history */ + 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_sfun_t h_set; /* Set 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, ev) (*(h)->h_next)((h)->h_ref, ev) +#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) +#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) +#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) +#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) +#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) +#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) +#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) +#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) + +#define h_malloc(a) malloc(a) +#define h_realloc(a, b) realloc((a), (b)) +#define h_free(a) free(a) + + +private int history_setsize(History *, HistEvent *, int); +private int history_getsize(History *, HistEvent *); +private int history_set_fun(History *, History *); +private int history_load(History *, const char *); +private int history_save(History *, const char *); +private int history_prev_event(History *, HistEvent *, int); +private int history_next_event(History *, HistEvent *, int); +private int history_next_string(History *, HistEvent *, const char *); +private int history_prev_string(History *, HistEvent *, 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 eventid; /* For generation of unique event id */ +} history_t; + +private int history_def_first(ptr_t, HistEvent *); +private int history_def_last(ptr_t, HistEvent *); +private int history_def_next(ptr_t, HistEvent *); +private int history_def_prev(ptr_t, HistEvent *); +private int history_def_curr(ptr_t, HistEvent *); +private int history_def_set(ptr_t, HistEvent *, const int n); +private int history_def_enter(ptr_t, HistEvent *, const char *); +private int history_def_add(ptr_t, HistEvent *, const char *); +private void history_def_init(ptr_t *, HistEvent *, int); +private void history_def_clear(ptr_t, HistEvent *); +private int history_def_insert(history_t *, HistEvent *, const char *); +private void history_def_delete(history_t *, HistEvent *, hentry_t *); + +#define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num)) +#define history_def_getsize(p) (((history_t *) p)->cur) + +#define he_strerror(code) he_errlist[code] +#define he_seterrev(evp, code) {\ + evp->num = code;\ + evp->str = he_strerror(code);\ + } + +/* error messages */ +static const char *const he_errlist[] = { + "OK", + "unknown error", + "malloc() failed", + "first event not found", + "last event not found", + "empty list", + "no next event", + "no previous event", + "current event is invalid", + "event not found", + "can't read history from file", + "can't write history", + "required parameter(s) not supplied", + "history size negative", + "function not allowed with other history-functions-set the default", + "bad parameters" +}; +/* error codes */ +#define _HE_OK 0 +#define _HE_UNKNOWN 1 +#define _HE_MALLOC_FAILED 2 +#define _HE_FIRST_NOTFOUND 3 +#define _HE_LAST_NOTFOUND 4 +#define _HE_EMPTY_LIST 5 +#define _HE_END_REACHED 6 +#define _HE_START_REACHED 7 +#define _HE_CURR_INVALID 8 +#define _HE_NOT_FOUND 9 +#define _HE_HIST_READ 10 +#define _HE_HIST_WRITE 11 +#define _HE_PARAM_MISSING 12 +#define _HE_SIZE_NEGATIVE 13 +#define _HE_NOT_ALLOWED 14 +#define _HE_BAD_PARAM 15 + +/* history_def_first(): + * Default function to return the first event in the history. + */ +private int +history_def_first(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + h->cursor = h->list.next; + if (h->cursor != &h->list) + *ev = h->cursor->ev; + else { + he_seterrev(ev, _HE_FIRST_NOTFOUND); + return (-1); + } + + return (0); +} + + +/* history_def_last(): + * Default function to return the last event in the history. + */ +private int +history_def_last(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + h->cursor = h->list.prev; + if (h->cursor != &h->list) + *ev = h->cursor->ev; + else { + he_seterrev(ev, _HE_LAST_NOTFOUND); + return (-1); + } + + return (0); +} + + +/* history_def_next(): + * Default function to return the next event in the history. + */ +private int +history_def_next(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + h->cursor = h->cursor->next; + else { + he_seterrev(ev, _HE_EMPTY_LIST); + return (-1); + } + + if (h->cursor != &h->list) + *ev = h->cursor->ev; + else { + he_seterrev(ev, _HE_END_REACHED); + return (-1); + } + + return (0); +} + + +/* history_def_prev(): + * Default function to return the previous event in the history. + */ +private int +history_def_prev(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + h->cursor = h->cursor->prev; + else { + he_seterrev(ev, + (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); + return (-1); + } + + if (h->cursor != &h->list) + *ev = h->cursor->ev; + else { + he_seterrev(ev, _HE_START_REACHED); + return (-1); + } + + return (0); +} + + +/* history_def_curr(): + * Default function to return the current event in the history. + */ +private int +history_def_curr(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + if (h->cursor != &h->list) + *ev = h->cursor->ev; + else { + he_seterrev(ev, + (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); + return (-1); + } + + return (0); +} + + +/* history_def_set(): + * Default function to set the current event in the history to the + * given one. + */ +private int +history_def_set(ptr_t p, HistEvent *ev, const int n) +{ + history_t *h = (history_t *) p; + + if (h->cur == 0) { + he_seterrev(ev, _HE_EMPTY_LIST); + return (-1); + } + if (h->cursor == &h->list || h->cursor->ev.num != n) { + for (h->cursor = h->list.next; h->cursor != &h->list; + h->cursor = h->cursor->next) + if (h->cursor->ev.num == n) + break; + } + if (h->cursor == &h->list) { + he_seterrev(ev, _HE_NOT_FOUND); + return (-1); + } + return (0); +} + + +/* history_def_add(): + * Append string to element + */ +private int +history_def_add(ptr_t p, HistEvent *ev, const char *str) +{ + history_t *h = (history_t *) p; + size_t len; + char *s; + + if (h->cursor == &h->list) + return (history_def_enter(p, ev, str)); + len = strlen(h->cursor->ev.str) + strlen(str) + 1; + s = (char *) h_malloc(len); + if (!s) { + he_seterrev(ev, _HE_MALLOC_FAILED); + return (-1); + } + (void) strlcpy(s, h->cursor->ev.str, len); + (void) strlcat(s, str, len); + /* LINTED const cast */ + h_free((ptr_t) h->cursor->ev.str); + h->cursor->ev.str = s; + *ev = h->cursor->ev; + return (0); +} + + +/* history_def_delete(): + * Delete element hp of the h list + */ +/* ARGSUSED */ +private void +history_def_delete(history_t *h, + HistEvent *ev __attribute__((unused)), hentry_t *hp) +{ + + if (hp == &h->list) + abort(); + hp->prev->next = hp->next; + hp->next->prev = hp->prev; + /* LINTED const cast */ + 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 int +history_def_insert(history_t *h, HistEvent *ev, const char *str) +{ + + h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); + if (h->cursor) + h->cursor->ev.str = strdup(str); + if (!h->cursor || !h->cursor->ev.str) { + he_seterrev(ev, _HE_MALLOC_FAILED); + return (-1); + } + h->cursor->ev.num = ++h->eventid; + h->cursor->next = h->list.next; + h->cursor->prev = &h->list; + h->list.next->prev = h->cursor; + h->list.next = h->cursor; + h->cur++; + + *ev = h->cursor->ev; + return (0); +} + + +/* history_def_enter(): + * Default function to enter an item in the history + */ +private int +history_def_enter(ptr_t p, HistEvent *ev, const char *str) +{ + history_t *h = (history_t *) p; + + if (history_def_insert(h, ev, str) == -1) + return (-1); /* error, keep error message */ + + /* + * Always keep at least one entry. + * This way we don't have to check for the empty list. + */ + while (h->cur - 1 > h->max) + history_def_delete(h, ev, h->list.prev); + + return (0); +} + + +/* history_def_init(): + * Default history initialization function + */ +/* ARGSUSED */ +private void +history_def_init(ptr_t *p, HistEvent *ev __attribute__((unused)), int n) +{ + history_t *h = (history_t *) h_malloc(sizeof(history_t)); + + if (n <= 0) + n = 0; + h->eventid = 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(ptr_t p, HistEvent *ev) +{ + history_t *h = (history_t *) p; + + while (h->list.prev != &h->list) + history_def_delete(h, ev, h->list.prev); + h->eventid = 0; + h->cur = 0; +} + + + + +/************************************************************************/ + +/* history_init(): + * Initialization function. + */ +public History * +history_init(void) +{ + History *h = (History *) h_malloc(sizeof(History)); + HistEvent ev; + + history_def_init(&h->h_ref, &ev, 0); + h->h_ent = -1; + 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_set = history_def_set; + 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(History *h) +{ + HistEvent ev; + + if (h->h_next == history_def_next) + history_def_clear(h->h_ref, &ev); +} + + + +/* history_setsize(): + * Set history number of events + */ +private int +history_setsize(History *h, HistEvent *ev, int num) +{ + + if (h->h_next != history_def_next) { + he_seterrev(ev, _HE_NOT_ALLOWED); + return (-1); + } + if (num < 0) { + he_seterrev(ev, _HE_BAD_PARAM); + return (-1); + } + history_def_setsize(h->h_ref, num); + return (0); +} + + +/* history_getsize(): + * Get number of events currently in history + */ +private int +history_getsize(History *h, HistEvent *ev) +{ + int retval = 0; + + if (h->h_next != history_def_next) { + he_seterrev(ev, _HE_NOT_ALLOWED); + return (-1); + } + retval = history_def_getsize(h->h_ref); + if (retval < -1) { + he_seterrev(ev, _HE_SIZE_NEGATIVE); + return (-1); + } + ev->num = retval; + return (0); +} + + +/* history_set_fun(): + * Set history functions + */ +private int +history_set_fun(History *h, History *nh) +{ + HistEvent ev; + + if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || + nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || + nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || + nh->h_ref == NULL) { + if (h->h_next != history_def_next) { + history_def_init(&h->h_ref, &ev, 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_set = history_def_set; + 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, &ev); + + h->h_ent = -1; + 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_set = nh->h_set; + 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(History *h, const char *fname) +{ + FILE *fp; + char *line; + size_t sz, max_size; + char *ptr; + int i = -1; + HistEvent ev; + + 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; + + ptr = h_malloc(max_size = 1024); + for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { + char c = line[sz]; + + if (sz != 0 && line[sz - 1] == '\n') + line[--sz] = '\0'; + else + line[sz] = '\0'; + + if (max_size < sz) { + max_size = (sz + 1023) & ~1023; + ptr = h_realloc(ptr, max_size); + } + (void) strunvis(ptr, line); + line[sz] = c; + HENTER(h, &ev, ptr); + } + h_free(ptr); + +done: + (void) fclose(fp); + return (i); +} + + +/* history_save(): + * History save function + */ +private int +history_save(History *h, const char *fname) +{ + FILE *fp; + HistEvent ev; + int i = 0, retval; + size_t len, max_size; + char *ptr; + + if ((fp = fopen(fname, "w")) == NULL) + return (-1); + + (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR); + (void) fputs(hist_cookie, fp); + ptr = h_malloc(max_size = 1024); + for (retval = HLAST(h, &ev); + retval != -1; + retval = HPREV(h, &ev), i++) { + len = strlen(ev.str) * 4; + if (len >= max_size) { + max_size = (len + 1023) & 1023; + ptr = h_realloc(ptr, max_size); + } + (void) strvis(ptr, ev.str, VIS_WHITE); + (void) fprintf(fp, "%s\n", ev.str); + } + h_free(ptr); + (void) fclose(fp); + return (i); +} + + +/* history_prev_event(): + * Find the previous event, with number given + */ +private int +history_prev_event(History *h, HistEvent *ev, int num) +{ + int retval; + + for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) + if (ev->num == num) + return (0); + + he_seterrev(ev, _HE_NOT_FOUND); + return (-1); +} + + +/* history_next_event(): + * Find the next event, with number given + */ +private int +history_next_event(History *h, HistEvent *ev, int num) +{ + int retval; + + for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) + if (ev->num == num) + return (0); + + he_seterrev(ev, _HE_NOT_FOUND); + return (-1); +} + + +/* history_prev_string(): + * Find the previous event beginning with string + */ +private int +history_prev_string(History *h, HistEvent *ev, const char *str) +{ + size_t len = strlen(str); + int retval; + + for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) + if (strncmp(str, ev->str, len) == 0) + return (0); + + he_seterrev(ev, _HE_NOT_FOUND); + return (-1); +} + + +/* history_next_string(): + * Find the next event beginning with string + */ +private int +history_next_string(History *h, HistEvent *ev, const char *str) +{ + size_t len = strlen(str); + int retval; + + for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) + if (strncmp(str, ev->str, len) == 0) + return (0); + + he_seterrev(ev, _HE_NOT_FOUND); + return (-1); +} + + +/* history(): + * User interface to history functions. + */ +int +history(History *h, HistEvent *ev, int fun, ...) +{ + va_list va; + const char *str; + int retval; + + va_start(va, fun); + + he_seterrev(ev, _HE_OK); + + switch (fun) { + case H_GETSIZE: + retval = history_getsize(h, ev); + break; + + case H_SETSIZE: + retval = history_setsize(h, ev, va_arg(va, int)); + break; + + case H_ADD: + str = va_arg(va, const char *); + retval = HADD(h, ev, str); + break; + + case H_ENTER: + str = va_arg(va, const char *); + if ((retval = HENTER(h, ev, str)) != -1) + h->h_ent = ev->num; + break; + + case H_APPEND: + str = va_arg(va, const char *); + if ((retval = HSET(h, ev, h->h_ent)) != -1) + retval = HADD(h, ev, str); + break; + + case H_FIRST: + retval = HFIRST(h, ev); + break; + + case H_NEXT: + retval = HNEXT(h, ev); + break; + + case H_LAST: + retval = HLAST(h, ev); + break; + + case H_PREV: + retval = HPREV(h, ev); + break; + + case H_CURR: + retval = HCURR(h, ev); + break; + + case H_SET: + retval = HSET(h, ev, va_arg(va, const int)); + break; + + case H_CLEAR: + HCLEAR(h, ev); + retval = 0; + break; + + case H_LOAD: + retval = history_load(h, va_arg(va, const char *)); + if (retval == -1) + he_seterrev(ev, _HE_HIST_READ); + break; + + case H_SAVE: + retval = history_save(h, va_arg(va, const char *)); + if (retval == -1) + he_seterrev(ev, _HE_HIST_WRITE); + break; + + case H_PREV_EVENT: + retval = history_prev_event(h, ev, va_arg(va, int)); + break; + + case H_NEXT_EVENT: + retval = history_next_event(h, ev, va_arg(va, int)); + break; + + case H_PREV_STR: + retval = history_prev_string(h, ev, va_arg(va, const char *)); + break; + + case H_NEXT_STR: + retval = history_next_string(h, ev, va_arg(va, const char *)); + break; + + case H_FUNC: + { + History hf; + + hf.h_ref = va_arg(va, ptr_t); + h->h_ent = -1; + 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_set = va_arg(va, history_sfun_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 ((retval = history_set_fun(h, &hf)) == -1) + he_seterrev(ev, _HE_PARAM_MISSING); + break; + } + + case H_END: + history_end(h); + retval = 0; + break; + + default: + retval = -1; + he_seterrev(ev, _HE_UNKNOWN); + break; + } + va_end(va); + return (retval); +} diff --git a/cmd-line-utils/libedit/key.c b/cmd-line-utils/libedit/key.c new file mode 100644 index 00000000000..629c6aeeb9c --- /dev/null +++ b/cmd-line-utils/libedit/key.c @@ -0,0 +1,681 @@ +/* $NetBSD: key.c,v 1.12 2001/05/17 01:02:17 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. + */ + +#include "compat.h" + +/* + * 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(EditLine *, key_node_t *, char *, + key_value_t *); +private int node__try(EditLine *, key_node_t *, const char *, + key_value_t *, int); +private key_node_t *node__get(int); +private void node__put(EditLine *, key_node_t *); +private int node__delete(EditLine *, key_node_t **, const char *); +private int node_lookup(EditLine *, const char *, + key_node_t *, int); +private int node_enum(EditLine *, key_node_t *, int); +private int key__decode_char(char *, int, int); + +#define KEY_BUFSIZ EL_BUFSIZ + + +/* key_init(): + * Initialize the key maps + */ +protected int +key_init(EditLine *el) +{ + + el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); + if (el->el_key.buf == NULL) + return (-1); + el->el_key.map = NULL; + key_reset(el); + return (0); +} + + +/* key_end(): + * Free the key maps + */ +protected void +key_end(EditLine *el) +{ + + el_free((ptr_t) el->el_key.buf); + el->el_key.buf = NULL; + /* XXX: provide a function to clear the keys */ + el->el_key.map = NULL; +} + + +/* key_map_cmd(): + * Associate cmd with a key value + */ +protected key_value_t * +key_map_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(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(EditLine *el) +{ + + node__put(el, 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(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(EditLine *el, const 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->el_key.map, key, val, ntype); + return; +} + + +/* key_clear(): + * + */ +protected void +key_clear(EditLine *el, el_action_t *map, const 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(EditLine *el, const 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->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(EditLine *el, const 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(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(EditLine *el, key_node_t *ptr, const 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(el, 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: + EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", + ptr->type)); + 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: + EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); + break; + } + } else { + /* still more chars to go */ + if (ptr->next == NULL) + ptr->next = node__get(*str); /* setup new node */ + (void) node__try(el, ptr->next, str, val, ntype); + } + return (0); +} + + +/* node__delete(): + * Delete node that matches str + */ +private int +node__delete(EditLine *el, key_node_t **inptr, const 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(el, ptr); + return (1); + } else if (ptr->next != NULL && + node__delete(el, &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(el, ptr); + return (1); + } else { + return (0); + } +} + + +/* node__put(): + * Puts a tree of nodes onto free list using free(3). + */ +private void +node__put(EditLine *el, key_node_t *ptr) +{ + if (ptr == NULL) + return; + + if (ptr->next != NULL) { + node__put(el, ptr->next); + ptr->next = NULL; + } + node__put(el, 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: + EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); + break; + } + el_free((ptr_t) ptr); +} + + +/* node__get(): + * Returns pointer to an key_node_t for ch. + */ +private key_node_t * +node__get(int ch) +{ + key_node_t *ptr; + + ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t)); + if (ptr == NULL) + return NULL; + 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(EditLine *el, const 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(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(EditLine *el, const char *key, key_value_t *val, int ntype) +{ + el_bindings_t *fp; + char unparsbuf[EL_BUFSIZ]; + static const char fmt[] = "%-15s-> %s\n"; + + if (val != NULL) + switch (ntype) { + case XK_STR: + case XK_EXE: + (void) fprintf(el->el_outfile, 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_outfile, fmt, + key, fp->name); + break; + } +#ifdef DEBUG_KEY + if (fp->name == NULL) + (void) fprintf(el->el_outfile, + "BUG! Command not found.\n"); +#endif + + break; + default: + EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); + break; + } + else + (void) fprintf(el->el_outfile, fmt, key, "no input"); +} + + +/* key__decode_char(): + * Put a printable form of char in buf. + */ +private int +key__decode_char(char *buf, int cnt, int 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++] = (((unsigned int) ch >> 6) & 7) + '0'; + buf[cnt++] = (((unsigned int) 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(const char *str, char *buf, const char *sep) +{ + char *b; + const char *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++ = (((unsigned int) *p >> 6) & 7) + '0'; + *b++ = (((unsigned int) *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/cmd-line-utils/libedit/key.h b/cmd-line-utils/libedit/key.h new file mode 100644 index 00000000000..c3a0889f901 --- /dev/null +++ b/cmd-line-utils/libedit/key.h @@ -0,0 +1,79 @@ +/* $NetBSD: key.h,v 1.5 2001/01/23 15:55:30 jdolecek 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(EditLine *); +protected void key_end(EditLine *); +protected key_value_t *key_map_cmd(EditLine *, int); +protected key_value_t *key_map_str(EditLine *, char *); +protected void key_reset(EditLine *); +protected int key_get(EditLine *, char *, key_value_t *); +protected void key_add(EditLine *, const char *, key_value_t *, int); +protected void key_clear(EditLine *, el_action_t *, const char *); +protected int key_delete(EditLine *, const char *); +protected void key_print(EditLine *, const char *); +protected void key_kprint(EditLine *, const char *, + key_value_t *, int); +protected char *key__decode_str(const char *, char *, const char *); + +#endif /* _h_el_key */ diff --git a/cmd-line-utils/libedit/makelist b/cmd-line-utils/libedit/makelist new file mode 100644 index 00000000000..8e9835309d6 --- /dev/null +++ b/cmd-line-utils/libedit/makelist @@ -0,0 +1,254 @@ +#!/bin/sh - +# $NetBSD: makelist,v 1.7 2001/01/09 19:22:31 jdolecek 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|-m <filenames>" + +if [ "x$1" = "x" ] +then + echo $USAGE 1>&2 + exit 1 +fi + +FLAG="$1" +shift + +FILES="$@" + +case $FLAG in + +# generate foo.h file from foo.c +# +-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); +# +# XXX: need a space between name and prototype so that -fc and -fh +# parsing is much easier +# + printf("protected el_action_t\t%s (EditLine *, int);\n", name); + } + } + END { + printf("#endif /* %s */\n", "'$hdr'"); + }' + ;; + +# generate help.c from various .c files +# +-bc) + cat $FILES | $AWK ' + BEGIN { + printf("/* Automatically generated file, do not edit */\n"); + printf("#include \"sys.h\"\n#include \"el.h\"\n"); + printf("private const 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 const el_bindings_t* help__get()"); + printf("{ return el_func_help; }\n"); + }' + ;; + +# generate help.h from various .c files +# +-bh) + $AWK ' + BEGIN { + printf("/* Automatically generated file, do not edit */\n"); + printf("#ifndef _h_help_c\n#define _h_help_c\n"); + printf("protected const el_bindings_t *help__get(void);\n"); + printf("#endif /* _h_help_c */\n"); + }' /dev/null + ;; + +# generate fcns.h from various .h files +# +-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)(EditLine *, int);"); + printf("\nprotected const el_func_t* func__get(void);\n"); + printf("#endif /* _h_fcns_c */\n"); + }' + ;; + +# generate fcns.c from various .h files +# +-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 const 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 const el_func_t* func__get() { return el_func; }\n"); + }' + ;; + +# generate editline.c from various .c files +# +-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); + }' + ;; + +# generate man page fragment from various .c files +# +-m) + cat $FILES | $AWK ' + BEGIN { + printf(".\\\" Section automatically generated with makelist\n"); + printf(".Bl -tag -width 4n\n"); + } + /\(\):/ { + pr = substr($2, 1, 2); + if (pr == "vi" || pr == "em" || pr == "ed") { + name = substr($2, 1, length($2) - 3); + fname = ""; + for (i = 1; i <= length(name); i++) { + s = substr(name, i, 1); + if (s == "_") + s = "-"; + fname = fname s; + } + + printf(".It Ic %s\n", fname); + ok = 1; + } + } + /^ \*/ { + if (ok) { + for (i = 2; i < NF; i++) + printf("%s ", $i); + printf("%s.\n", $i); + ok = 0; + } + } + END { + printf(".El\n"); + printf(".\\\" End of section automatically generated with makelist\n"); + }' + ;; + +*) + echo $USAGE 1>&2 + exit 1 + ;; + +esac diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c new file mode 100644 index 00000000000..144ccf1ebe0 --- /dev/null +++ b/cmd-line-utils/libedit/map.c @@ -0,0 +1,1412 @@ +/* $NetBSD: map.c,v 1.14 2001/01/09 17:22:09 jdolecek 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. + */ + +#include "compat.h" + +/* + * map.c: Editor function definitions + */ +#include "sys.h" +#include <stdlib.h> +#include "el.h" + +#define N_KEYS 256 + +private void map_print_key(EditLine *, el_action_t *, const char *); +private void map_print_some_keys(EditLine *, el_action_t *, int, int); +private void map_print_all_keys(EditLine *); +private void map_init_nls(EditLine *); +private void map_init_meta(EditLine *); + +/* keymap tables ; should be N_KEYS*sizeof(KEYCMD) bytes long */ + + +private const 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 const 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 */ + /* ED_DELETE_PREV_WORD: 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 */ + /* + * NOTE: These mappings do NOT Correspond well + * to the KSH VI editing assignments. + * On the other and they are convenient and + * many people have have gotten used to them. + */ + /* 0 */ ED_UNASSIGNED, /* ^@ */ + /* 1 */ ED_MOVE_TO_BEG, /* ^A */ + /* 2 */ ED_PREV_CHAR, /* ^B */ + /* 3 */ ED_TTY_SIGINT, /* ^C */ + /* 4 */ VI_LIST_OR_EOF, /* ^D */ + /* 5 */ ED_MOVE_TO_END, /* ^E */ + /* 6 */ ED_NEXT_CHAR, /* ^F */ + /* 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 const 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(EditLine *el) +{ + + /* + * Make sure those are correct before starting. + */ +#ifdef MAP_DEBUG + if (sizeof(el_map_emacs) != N_KEYS * sizeof(el_action_t)) + EL_ABORT((el->errfile, "Emacs map incorrect\n")); + if (sizeof(el_map_vi_command) != N_KEYS * sizeof(el_action_t)) + EL_ABORT((el->errfile, "Vi command map incorrect\n")); + if (sizeof(el_map_vi_insert) != N_KEYS * sizeof(el_action_t)) + EL_ABORT((el->errfile, "Vi insert map incorrect\n")); +#endif + + el->el_map.alt = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS); + if (el->el_map.alt == NULL) + return (-1); + el->el_map.key = (el_action_t *)el_malloc(sizeof(el_action_t) * N_KEYS); + if (el->el_map.key == NULL) + return (-1); + 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); + if (el->el_map.help == NULL) + return (-1); + (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); + if (el->el_map.func == NULL) + return (-1); + 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(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(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(EditLine *el) +{ + char buf[3]; + 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[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; +} + + +/* map_init_vi(): + * Initialize the vi bindings + */ +protected void +map_init_vi(EditLine *el) +{ + int i; + el_action_t *key = el->el_map.key; + el_action_t *alt = el->el_map.alt; + const el_action_t *vii = el->el_map.vii; + const 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); + map_init_nls(el); + + tty_bind_char(el, 1); + term_bind_arrow(el); +} + + +/* map_init_emacs(): + * Initialize the emacs bindings + */ +protected void +map_init_emacs(EditLine *el) +{ + int i; + char buf[3]; + el_action_t *key = el->el_map.key; + el_action_t *alt = el->el_map.alt; + const 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); + 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(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_get_editor(): + * Retrieve the editor + */ +protected int +map_get_editor(EditLine *el, const char **editor) +{ + + if (editor == NULL) + return (-1); + switch (el->el_map.type) { + case MAP_EMACS: + *editor = "emacs"; + return (0); + case MAP_VI: + *editor = "vi"; + return (0); + } + return (-1); +} + + +/* map_print_key(): + * Print the function description for 1 key + */ +private void +map_print_key(EditLine *el, el_action_t *map, const 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(EditLine *el, el_action_t *map, int first, int 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 + EL_ABORT((el->el_errfile, "Error printing keys\n")); +} + + +/* map_print_all_keys(): + * Print the function description for all keys. + */ +private void +map_print_all_keys(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(EditLine *el, int argc, const char **argv) +{ + el_action_t *map; + int ntype, rem; + const char *p; + char inbuf[EL_BUFSIZ]; + char outbuf[EL_BUFSIZ]; + const 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 = rem = 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': + rem = 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 (rem) { + 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: + EL_ABORT((el->el_errfile, "Bad XK_ type\n", ntype)); + break; + } + return (0); +} + + +/* map_addfunc(): + * add a user defined function + */ +protected int +map_addfunc(EditLine *el, const char *name, const char *help, el_func_t func) +{ + void *p; + int nf = el->el_map.nfunc + 2; + + if (name == NULL || help == NULL || func == NULL) + return (-1); + + if ((p = el_realloc(el->el_map.func, nf * sizeof(el_func_t))) == NULL) + return (-1); + el->el_map.func = (el_func_t *) p; + if ((p = el_realloc(el->el_map.help, nf * sizeof(el_bindings_t))) + == NULL) + return (-1); + el->el_map.help = (el_bindings_t *) p; + + 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/cmd-line-utils/libedit/map.h b/cmd-line-utils/libedit/map.h new file mode 100644 index 00000000000..6033eaf1a87 --- /dev/null +++ b/cmd-line-utils/libedit/map.h @@ -0,0 +1,79 @@ +/* $NetBSD: map.h,v 1.6 2001/01/09 17:22:09 jdolecek 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 */ + const el_action_t *emacs; /* The default emacs key map */ + const el_action_t *vic; /* The vi command mode key map */ + const 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(EditLine *, int, const char **); +protected int map_init(EditLine *); +protected void map_end(EditLine *); +protected void map_init_vi(EditLine *); +protected void map_init_emacs(EditLine *); +protected int map_set_editor(EditLine *, char *); +protected int map_get_editor(EditLine *, const char **); +protected int map_addfunc(EditLine *, const char *, const char *, el_func_t); + +#endif /* _h_el_map */ diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c new file mode 100644 index 00000000000..b6d077793af --- /dev/null +++ b/cmd-line-utils/libedit/parse.c @@ -0,0 +1,253 @@ +/* $NetBSD: parse.c,v 1.14 2001/01/23 15:55:30 jdolecek 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. + */ + +#include "compat.h" + +/* + * parse.c: parse an editline extended command + * + * commands are: + * + * bind + * echotc + * edit + * gettc + * history + * settc + * setty + */ +#include "sys.h" +#include "el.h" +#include "tokenizer.h" +#include <stdlib.h> + +private const struct { + const char *name; + int (*func)(EditLine *, int, const char **); +} cmds[] = { + { "bind", map_bind }, + { "echotc", term_echotc }, + { "edit", el_editmode }, + { "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(EditLine *el, const char *line) +{ + const 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(EditLine *el, int argc, const char *argv[]) +{ + const char *ptr; + int i; + + if (argc < 1) + return (-1); + ptr = strchr(argv[0], ':'); + if (ptr != NULL) { + char *tprog; + size_t l; + + if (ptr == argv[0]) + return (0); + l = ptr - argv[0] - 1; + tprog = (char *) el_malloc(l + 1); + if (tprog == NULL) + return (0); + (void) strncpy(tprog, argv[0], l); + tprog[l] = '\0'; + ptr++; + l = el_match(el->el_prog, tprog); + el_free(tprog); + if (!l) + 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(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(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(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/cmd-line-utils/libedit/parse.h b/cmd-line-utils/libedit/parse.h new file mode 100644 index 00000000000..4aaef2f834a --- /dev/null +++ b/cmd-line-utils/libedit/parse.h @@ -0,0 +1,52 @@ +/* $NetBSD: parse.h,v 1.4 2000/09/04 22:06:31 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(EditLine *, const char *); +protected int parse__escape(const char ** const); +protected char *parse__string(char *, const char *); +protected int parse_cmd(EditLine *, const char *); + +#endif /* _h_el_parse */ diff --git a/cmd-line-utils/libedit/prompt.c b/cmd-line-utils/libedit/prompt.c new file mode 100644 index 00000000000..fb7d9d35936 --- /dev/null +++ b/cmd-line-utils/libedit/prompt.c @@ -0,0 +1,168 @@ +/* $NetBSD: prompt.c,v 1.8 2001/01/10 07:45:41 jdolecek 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. + */ + +#include "compat.h" + +/* + * prompt.c: Prompt printing functions + */ +#include "sys.h" +#include <stdio.h> +#include "el.h" + +private char *prompt_default(EditLine *); +private char *prompt_default_r(EditLine *); + +/* prompt_default(): + * Just a default prompt, in case the user did not provide one + */ +private char * +/*ARGSUSED*/ +prompt_default(EditLine *el __attribute__((unused))) +{ + static char a[3] = {'?', ' ', '\0'}; + + return (a); +} + + +/* prompt_default_r(): + * Just a default rprompt, in case the user did not provide one + */ +private char * +/*ARGSUSED*/ +prompt_default_r(EditLine *el __attribute__((unused))) +{ + static char a[1] = {'\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(EditLine *el, int op) +{ + el_prompt_t *elp; + char *p; + + if (op == EL_PROMPT) + elp = &el->el_prompt; + else + elp = &el->el_rprompt; + p = (elp->p_func) (el); + while (*p) + re_putc(el, *p++, 1); + + elp->p_pos.v = el->el_refresh.r_cursor.v; + elp->p_pos.h = el->el_refresh.r_cursor.h; +} + + +/* prompt_init(): + * Initialize the prompt stuff + */ +protected int +prompt_init(EditLine *el) +{ + + el->el_prompt.p_func = prompt_default; + el->el_prompt.p_pos.v = 0; + el->el_prompt.p_pos.h = 0; + el->el_rprompt.p_func = prompt_default_r; + el->el_rprompt.p_pos.v = 0; + el->el_rprompt.p_pos.h = 0; + return (0); +} + + +/* prompt_end(): + * Clean up the prompt stuff + */ +protected void +/*ARGSUSED*/ +prompt_end(EditLine *el __attribute__((unused))) +{ +} + + +/* prompt_set(): + * Install a prompt printing function + */ +protected int +prompt_set(EditLine *el, el_pfunc_t prf, int op) +{ + el_prompt_t *p; + + if (op == EL_PROMPT) + p = &el->el_prompt; + else + p = &el->el_rprompt; + if (prf == NULL) { + if (op == EL_PROMPT) + p->p_func = prompt_default; + else + p->p_func = prompt_default_r; + } else + p->p_func = prf; + p->p_pos.v = 0; + p->p_pos.h = 0; + return (0); +} + + +/* prompt_get(): + * Retrieve the prompt printing function + */ +protected int +prompt_get(EditLine *el, el_pfunc_t *prf, int op) +{ + + if (prf == NULL) + return (-1); + if (op == EL_PROMPT) + *prf = el->el_prompt.p_func; + else + *prf = el->el_rprompt.p_func; + return (0); +} diff --git a/cmd-line-utils/libedit/prompt.h b/cmd-line-utils/libedit/prompt.h new file mode 100644 index 00000000000..08810e22a0c --- /dev/null +++ b/cmd-line-utils/libedit/prompt.h @@ -0,0 +1,62 @@ +/* $NetBSD: prompt.h,v 1.5 2000/09/04 22:06:31 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)(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(EditLine *, int); +protected int prompt_set(EditLine *, el_pfunc_t, int); +protected int prompt_get(EditLine *, el_pfunc_t *, int); +protected int prompt_init(EditLine *); +protected void prompt_end(EditLine *); + +#endif /* _h_el_prompt */ diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c new file mode 100644 index 00000000000..05f9e3da454 --- /dev/null +++ b/cmd-line-utils/libedit/read.c @@ -0,0 +1,514 @@ +/* $NetBSD: read.c,v 1.19 2001/01/10 07:45:41 jdolecek 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. + */ + +#include "compat.h" + +/* + * read.c: Clean this junk up! This is horrible code. + * Terminal read functions + */ +#include "sys.h" +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include "el.h" + +#define OKCMD -1 + +private int read__fixio(int, int); +private int read_preread(EditLine *); +private int read_getcmd(EditLine *, el_action_t *, char *); +private int read_char(EditLine *, char *); + +#ifdef DEBUG_EDIT +private void +read_debug(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 + */ +/* ARGSUSED */ +private int +read__fixio(int fd __attribute__((unused)), int 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 + { + int zero = 0; + + if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -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(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->el_chared.c_macro.nline); + } + } +#endif /* FIONREAD */ + + return (chrs > 0); +} + + +/* el_push(): + * Push a macro + */ +public void +el_push(EditLine *el, const char *str) +{ + c_macro_t *ma = &el->el_chared.c_macro; + + if (str != NULL && ma->level + 1 < EL_MAXMACRO) { + ma->level++; + /* LINTED const cast */ + ma->macro[ma->level] = (char *) str; + } else { + term_beep(el); + term__flush(); + } +} + + +/* read_getcmd(): + * Return next command from the input stream. + */ +private int +read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) +{ + el_action_t cmd = ED_UNASSIGNED; + int num; + + while (cmd == ED_UNASSIGNED || 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: + EL_ABORT((el->el_errfile, "Bad XK_ type \n")); + break; + } + } + if (el->el_map.alt == NULL) + el->el_map.current = el->el_map.key; + } + *cmdnum = cmd; + return (OKCMD); +} + + +/* read_char(): + * Read a character from the tty. + */ +private int +read_char(EditLine *el, char *cp) +{ + int num_read; + int tried = 0; + + while ((num_read = read(el->el_infd, cp, 1)) == -1) + if (!tried && read__fixio(el->el_infd, errno) == 0) + tried = 1; + else { + *cp = '\0'; + return (-1); + } + + return (num_read); +} + + +/* el_getc(): + * Read a character + */ +public int +el_getc(EditLine *el, char *cp) +{ + int num_read; + 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 */ + num_read = read_char(el, cp); +#ifdef DEBUG_READ + (void) fprintf(el->el_errfile, "Got it %c\n", *cp); +#endif /* DEBUG_READ */ + return (num_read); +} + + +public const char * +el_gets(EditLine *el, int *nread) +{ + int retval; + el_action_t cmdnum = 0; + int num; /* how many chars we have read at NL */ + char ch; +#ifdef FIONREAD + c_macro_t *ma = &el->el_chared.c_macro; +#endif /* FIONREAD */ + + if (el->el_flags & HANDLE_SIGNALS) + sig_set(el); + + if (el->el_flags & NO_TTY) { + char *cp = el->el_line.buffer; + size_t idx; + + while (read_char(el, cp) == 1) { + /* make sure there is space for next character */ + if (cp + 1 >= el->el_line.limit) { + idx = (cp - el->el_line.buffer); + if (!ch_enlargebufs(el, 2)) + break; + cp = &el->el_line.buffer[idx]; + } + cp++; + if (cp[-1] == '\r' || cp[-1] == '\n') + break; + } + + el->el_line.cursor = el->el_line.lastchar = cp; + *cp = '\0'; + if (nread) + *nread = el->el_line.cursor - el->el_line.buffer; + return (el->el_line.buffer); + } + re_clear_display(el); /* reset the display stuff */ + ch_reset(el); + +#ifdef FIONREAD + if (el->el_tty.t_mode == EX_IO && ma->level < 0) { + 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 */ + + if (el->el_flags & EDIT_DISABLED) { + char *cp = el->el_line.buffer; + size_t idx; + + term__flush(); + + while (read_char(el, cp) == 1) { + /* make sure there is space next character */ + if (cp + 1 >= el->el_line.limit) { + idx = (cp - el->el_line.buffer); + if (!ch_enlargebufs(el, 2)) + break; + cp = &el->el_line.buffer[idx]; + } + cp++; + if (cp[-1] == '\r' || cp[-1] == '\n') + break; + } + + el->el_line.cursor = el->el_line.lastchar = cp; + *cp = '\0'; + if (nread) + *nread = el->el_line.cursor - el->el_line.buffer; + return (el->el_line.buffer); + } + for (num = OKCMD; num == OKCMD;) { /* while still editing this + * line */ +#ifdef DEBUG_EDIT + 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 ((int) cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ +#ifdef DEBUG_EDIT + (void) fprintf(el->el_errfile, + "ERROR: illegal command from key 0%o\r\n", ch); +#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_REFRESH_BEEP: + el->el_state.argument = 1; + el->el_state.doingarg = 0; + re_refresh(el); + term_beep(el); + break; + + case CC_NORM: /* normal char */ + el->el_state.argument = 1; + el->el_state.doingarg = 0; + break; + + case CC_ARGHACK: /* Suggested by Rich Salz */ + /* <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; + } + } + + /* make sure the tty is set up correctly */ + (void) tty_cookedmode(el); + term__flush(); /* flush any buffered output */ + if (el->el_flags & HANDLE_SIGNALS) + sig_clr(el); + if (nread) + *nread = num; + return (num ? el->el_line.buffer : NULL); +} diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c new file mode 100644 index 00000000000..e9c8409102c --- /dev/null +++ b/cmd-line-utils/libedit/readline.c @@ -0,0 +1,1661 @@ +/* $NetBSD: readline.c,v 1.19 2001/01/10 08:10:45 jdolecek Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "compat.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <pwd.h> +#include <ctype.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "histedit.h" +#include "readline/readline.h" +#include "sys.h" +#include "el.h" +#include "fcns.h" /* for EL_NUM_FCNS */ + +/* for rl_complete() */ +#define TAB '\r' + +/* see comment at the #ifdef for sense of this */ +#define GDB_411_HACK + +/* readline compatibility stuff - look at readline sources/documentation */ +/* to see what these variables mean */ +const char *rl_library_version = "EditLine wrapper"; +const char *rl_readline_name = ""; +FILE *rl_instream = NULL; +FILE *rl_outstream = NULL; +int rl_point = 0; +int rl_end = 0; +char *rl_line_buffer = NULL; + +int history_base = 1; /* probably never subject to change */ +int history_length = 0; +int max_input_history = 0; +char history_expansion_char = '!'; +char history_subst_char = '^'; +const char *history_no_expand_chars = " \t\n=("; +Function *history_inhibit_expansion_function = NULL; + +int rl_inhibit_completion = 0; +int rl_attempted_completion_over = 0; +const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; +char *rl_completer_word_break_characters = NULL; +char *rl_completer_quote_characters = NULL; +CPFunction *rl_completion_entry_function = NULL; +CPPFunction *rl_attempted_completion_function = NULL; + +/* + * This is set to character indicating type of completion being done by + * rl_complete_internal(); this is available for application completion + * functions. + */ +int rl_completion_type = 0; + +/* + * If more than this number of items results from query for possible + * completions, we ask user if they are sure to really display the list. + */ +int rl_completion_query_items = 100; + +/* + * List of characters which are word break characters, but should be left + * in the parsed text when it is passed to the completion function. + * Shell uses this to help determine what kind of completing to do. + */ +char *rl_special_prefixes = (char *)NULL; + +/* + * This is the character appended to the completed words if at the end of + * the line. Default is ' ' (a space). + */ +int rl_completion_append_character = ' '; + +/* stuff below is used internally by libedit for readline emulation */ + +/* if not zero, non-unique completions always show list of possible matches */ +static int _rl_complete_show_all = 0; + +static History *h = NULL; +static EditLine *e = NULL; +static int el_rl_complete_cmdnum = 0; + +/* internal functions */ +static unsigned char _el_rl_complete(EditLine *, int); +static char *_get_prompt(EditLine *); +static HIST_ENTRY *_move_history(int); +static int _history_search_gen(const char *, int, int); +static int _history_expand_command(const char *, size_t, char **); +static char *_rl_compat_sub(const char *, const char *, + const char *, int); +static int rl_complete_internal(int); +static int _rl_qsort_string_compare(const void *, const void *); + +/* + * needed for prompt switching in readline() + */ +static char *el_rl_prompt = NULL; + + +/* ARGSUSED */ +static char * +_get_prompt(EditLine *el __attribute__((unused))) +{ + return (el_rl_prompt); +} + + +/* + * generic function for moving around history + */ +static HIST_ENTRY * +_move_history(int op) +{ + HistEvent ev; + static HIST_ENTRY rl_he; + + if (history(h, &ev, op) != 0) + return (HIST_ENTRY *) NULL; + + rl_he.line = ev.str; + rl_he.data = ""; + + return (&rl_he); +} + + +/* + * READLINE compatibility stuff + */ + +/* + * initialize rl compat stuff + */ +int +rl_initialize(void) +{ + HistEvent ev; + const LineInfo *li; + int i; + int editmode = 1; + struct termios t; + + if (e != NULL) + el_end(e); + if (h != NULL) + history_end(h); + + if (!rl_instream) + rl_instream = stdin; + if (!rl_outstream) + rl_outstream = stdout; + + /* + * See if we don't really want to run the editor + */ + if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) + editmode = 0; + + e = el_init(rl_readline_name, rl_instream, rl_outstream, stderr); + + if (!editmode) + el_set(e, EL_EDITMODE, 0); + + h = history_init(); + if (!e || !h) + return (-1); + + history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ + history_length = 0; + max_input_history = INT_MAX; + el_set(e, EL_HIST, history, h); + + /* for proper prompt printing in readline() */ + el_rl_prompt = strdup(""); + el_set(e, EL_PROMPT, _get_prompt); + el_set(e, EL_SIGNAL, 1); + + /* set default mode to "emacs"-style and read setting afterwards */ + /* so this can be overriden */ + el_set(e, EL_EDITOR, "emacs"); + + /* + * Word completition - this has to go AFTER rebinding keys + * to emacs-style. + */ + el_set(e, EL_ADDFN, "rl_complete", + "ReadLine compatible completition function", + _el_rl_complete); + el_set(e, EL_BIND, "^I", "rl_complete", NULL); + + /* + * Find out where the rl_complete function was added; this is + * used later to detect that lastcmd was also rl_complete. + */ + for(i=EL_NUM_FCNS; i < e->el_map.nfunc; i++) { + if (e->el_map.func[i] == _el_rl_complete) { + el_rl_complete_cmdnum = i; + break; + } + } + + /* read settings from configuration file */ + el_source(e, NULL); + + /* + * Unfortunately, some applications really do use rl_point + * and rl_line_buffer directly. + */ + li = el_line(e); + /* LINTED const cast */ + rl_line_buffer = (char *) li->buffer; + rl_point = rl_end = 0; + + return (0); +} + + +/* + * read one line from input stream and return it, chomping + * trailing newline (if there is any) + */ +char * +readline(const char *prompt) +{ + HistEvent ev; + int count; + const char *ret; + + if (e == NULL || h == NULL) + rl_initialize(); + + /* update prompt accordingly to what has been passed */ + if (!prompt) + prompt = ""; + if (strcmp(el_rl_prompt, prompt) != 0) { + free(el_rl_prompt); + el_rl_prompt = strdup(prompt); + } + /* get one line from input stream */ + ret = el_gets(e, &count); + + if (ret && count > 0) { + char *foo; + int lastidx; + + foo = strdup(ret); + lastidx = count - 1; + if (foo[lastidx] == '\n') + foo[lastidx] = '\0'; + + ret = foo; + } else + ret = NULL; + + history(h, &ev, H_GETSIZE); + history_length = ev.num; + + /* LINTED const cast */ + return (char *) ret; +} + +/* + * history functions + */ + +/* + * is normally called before application starts to use + * history expansion functions + */ +void +using_history(void) +{ + if (h == NULL || e == NULL) + rl_initialize(); +} + + +/* + * substitute ``what'' with ``with'', returning resulting string; if + * globally == 1, substitutes all occurences of what, otherwise only the + * first one + */ +static char * +_rl_compat_sub(const char *str, const char *what, const char *with, + int globally) +{ + char *result; + const char *temp, *new; + unsigned int len, with_len, what_len, add; + size_t size, i; + + result = malloc((size = 16)); + temp = str; + with_len = strlen(with); + what_len = strlen(what); + len = 0; + do { + new = strstr(temp, what); + if (new) { + i = new - temp; + add = i + with_len; + if (i + add + 1 >= size) { + size += add + 1; + result = realloc(result, size); + } + (void) strncpy(&result[len], temp, i); + len += i; + (void) strcpy(&result[len], with); /* safe */ + len += with_len; + temp = new + what_len; + } else { + add = strlen(temp); + if (len + add + 1 >= size) { + size += add + 1; + result = realloc(result, size); + } + (void) strcpy(&result[len], temp); /* safe */ + len += add; + temp = NULL; + } + } while (temp && globally); + result[len] = '\0'; + + return (result); +} + + +/* + * the real function doing history expansion - takes as argument command + * to do and data upon which the command should be executed + * does expansion the way I've understood readline documentation + * word designator ``%'' isn't supported (yet ?) + * + * returns 0 if data was not modified, 1 if it was and 2 if the string + * should be only printed and not executed; in case of error, + * returns -1 and *result points to NULL + * it's callers responsibility to free() string returned in *result + */ +static int +_history_expand_command(const char *command, size_t cmdlen, char **result) +{ + char **arr, *tempcmd, *line, *search = NULL, *cmd; + const char *event_data = NULL; + static char *from = NULL, *to = NULL; + int start = -1, end = -1, max, i, idx; + int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; + int event_num = 0, retval; + size_t cmdsize; + + *result = NULL; + + cmd = alloca(cmdlen + 1); + (void) strncpy(cmd, command, cmdlen); + cmd[cmdlen] = 0; + + idx = 1; + /* find out which event to take */ + if (cmd[idx] == history_expansion_char) { + event_num = history_length; + idx++; + } else { + int off, num; + size_t len; + off = idx; + while (cmd[off] && !strchr(":^$*-%", cmd[off])) + off++; + num = atoi(&cmd[idx]); + if (num != 0) { + event_num = num; + if (num < 0) + event_num += history_length + 1; + } else { + int prefix = 1, curr_num; + HistEvent ev; + + len = off - idx; + if (cmd[idx] == '?') { + idx++, len--; + if (cmd[off - 1] == '?') + len--; + else if (cmd[off] != '\n' && cmd[off] != '\0') + return (-1); + prefix = 0; + } + search = alloca(len + 1); + (void) strncpy(search, &cmd[idx], len); + search[len] = '\0'; + + if (history(h, &ev, H_CURR) != 0) + return (-1); + curr_num = ev.num; + + if (prefix) + retval = history_search_prefix(search, -1); + else + retval = history_search(search, -1); + + if (retval == -1) { + fprintf(rl_outstream, "%s: Event not found\n", + search); + return (-1); + } + if (history(h, &ev, H_CURR) != 0) + return (-1); + event_data = ev.str; + + /* roll back to original position */ + history(h, &ev, H_NEXT_EVENT, curr_num); + } + idx = off; + } + + if (!event_data && event_num >= 0) { + HIST_ENTRY *rl_he; + rl_he = history_get(event_num); + if (!rl_he) + return (0); + event_data = rl_he->line; + } else + return (-1); + + if (cmd[idx] != ':') + return (-1); + cmd += idx + 1; + + /* recognize cmd */ + if (*cmd == '^') + start = end = 1, cmd++; + else if (*cmd == '$') + start = end = -1, cmd++; + else if (*cmd == '*') + start = 1, end = -1, cmd++; + else if (isdigit((unsigned char) *cmd)) { + const char *temp; + int shifted = 0; + + start = atoi(cmd); + temp = cmd; + for (; isdigit((unsigned char) *cmd); cmd++); + if (temp != cmd) + shifted = 1; + if (shifted && *cmd == '-') { + if (!isdigit((unsigned char) *(cmd + 1))) + end = -2; + else { + end = atoi(cmd + 1); + for (; isdigit((unsigned char) *cmd); cmd++); + } + } else if (shifted && *cmd == '*') + end = -1, cmd++; + else if (shifted) + end = start; + } + if (*cmd == ':') + cmd++; + + line = strdup(event_data); + for (; *cmd; cmd++) { + if (*cmd == ':') + continue; + else if (*cmd == 'h') + h_on = 1 | g_on, g_on = 0; + else if (*cmd == 't') + t_on = 1 | g_on, g_on = 0; + else if (*cmd == 'r') + r_on = 1 | g_on, g_on = 0; + else if (*cmd == 'e') + e_on = 1 | g_on, g_on = 0; + else if (*cmd == 'p') + p_on = 1 | g_on, g_on = 0; + else if (*cmd == 'g') + g_on = 2; + else if (*cmd == 's' || *cmd == '&') { + char *what, *with, delim; + size_t len, from_len; + size_t size; + + if (*cmd == '&' && (from == NULL || to == NULL)) + continue; + else if (*cmd == 's') { + delim = *(++cmd), cmd++; + size = 16; + what = realloc(from, size); + len = 0; + for (; *cmd && *cmd != delim; cmd++) { + if (*cmd == '\\' + && *(cmd + 1) == delim) + cmd++; + if (len >= size) + what = realloc(what, + (size <<= 1)); + what[len++] = *cmd; + } + what[len] = '\0'; + from = what; + if (*what == '\0') { + free(what); + if (search) + from = strdup(search); + else { + from = NULL; + return (-1); + } + } + cmd++; /* shift after delim */ + if (!*cmd) + continue; + + size = 16; + with = realloc(to, size); + len = 0; + from_len = strlen(from); + for (; *cmd && *cmd != delim; cmd++) { + if (len + from_len + 1 >= size) { + size += from_len + 1; + with = realloc(with, size); + } + if (*cmd == '&') { + /* safe */ + (void) strcpy(&with[len], from); + len += from_len; + continue; + } + if (*cmd == '\\' + && (*(cmd + 1) == delim + || *(cmd + 1) == '&')) + cmd++; + with[len++] = *cmd; + } + with[len] = '\0'; + to = with; + + tempcmd = _rl_compat_sub(line, from, to, + (g_on) ? 1 : 0); + free(line); + line = tempcmd; + g_on = 0; + } + } + } + + arr = history_tokenize(line); + free(line); /* no more needed */ + if (arr && *arr == NULL) + free(arr), arr = NULL; + if (!arr) + return (-1); + + /* find out max valid idx to array of array */ + max = 0; + for (i = 0; arr[i]; i++) + max++; + max--; + + /* set boundaries to something relevant */ + if (start < 0) + start = 1; + if (end < 0) + end = max - ((end < -1) ? 1 : 0); + + /* check boundaries ... */ + if (start > max || end > max || start > end) + return (-1); + + for (i = 0; i <= max; i++) { + char *temp; + if (h_on && (i == 1 || h_on > 1) && + (temp = strrchr(arr[i], '/'))) + *(temp + 1) = '\0'; + if (t_on && (i == 1 || t_on > 1) && + (temp = strrchr(arr[i], '/'))) + (void) strcpy(arr[i], temp + 1); + if (r_on && (i == 1 || r_on > 1) && + (temp = strrchr(arr[i], '.'))) + *temp = '\0'; + if (e_on && (i == 1 || e_on > 1) && + (temp = strrchr(arr[i], '.'))) + (void) strcpy(arr[i], temp); + } + + cmdsize = 1, cmdlen = 0; + tempcmd = malloc(cmdsize); + for (i = start; start <= i && i <= end; i++) { + int arr_len; + + arr_len = strlen(arr[i]); + if (cmdlen + arr_len + 1 >= cmdsize) { + cmdsize += arr_len + 1; + tempcmd = realloc(tempcmd, cmdsize); + } + (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ + cmdlen += arr_len; + tempcmd[cmdlen++] = ' '; /* add a space */ + } + while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) + cmdlen--; + tempcmd[cmdlen] = '\0'; + + *result = tempcmd; + + for (i = 0; i <= max; i++) + free(arr[i]); + free(arr), arr = (char **) NULL; + return (p_on) ? 2 : 1; +} + + +/* + * csh-style history expansion + */ +int +history_expand(char *str, char **output) +{ + int i, retval = 0, idx; + size_t size; + char *temp, *result; + + if (h == NULL || e == NULL) + rl_initialize(); + + *output = strdup(str); /* do it early */ + + if (str[0] == history_subst_char) { + /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ + temp = alloca(4 + strlen(str) + 1); + temp[0] = temp[1] = history_expansion_char; + temp[2] = ':'; + temp[3] = 's'; + (void) strcpy(temp + 4, str); + str = temp; + } +#define ADD_STRING(what, len) \ + { \ + if (idx + len + 1 > size) \ + result = realloc(result, (size += len + 1)); \ + (void)strncpy(&result[idx], what, len); \ + idx += len; \ + result[idx] = '\0'; \ + } + + result = NULL; + size = idx = 0; + for (i = 0; str[i];) { + int start, j, loop_again; + size_t len; + + loop_again = 1; + start = j = i; +loop: + for (; str[j]; j++) { + if (str[j] == '\\' && + str[j + 1] == history_expansion_char) { + (void) strcpy(&str[j], &str[j + 1]); + continue; + } + if (!loop_again) { + if (str[j] == '?') { + while (str[j] && str[++j] != '?'); + if (str[j] == '?') + j++; + } else if (isspace((unsigned char) str[j])) + break; + } + if (str[j] == history_expansion_char + && !strchr(history_no_expand_chars, str[j + 1]) + && (!history_inhibit_expansion_function || + (*history_inhibit_expansion_function)(str, j) == 0)) + break; + } + + if (str[j] && str[j + 1] != '#' && loop_again) { + i = j; + j++; + if (str[j] == history_expansion_char) + j++; + loop_again = 0; + goto loop; + } + len = i - start; + temp = &str[start]; + ADD_STRING(temp, len); + + if (str[i] == '\0' || str[i] != history_expansion_char + || str[i + 1] == '#') { + len = j - i; + temp = &str[i]; + ADD_STRING(temp, len); + if (start == 0) + retval = 0; + else + retval = 1; + break; + } + retval = _history_expand_command(&str[i], (size_t) (j - i), + &temp); + if (retval != -1) { + len = strlen(temp); + ADD_STRING(temp, len); + } + i = j; + } /* for(i ...) */ + + if (retval == 2) { + add_history(temp); +#ifdef GDB_411_HACK + /* gdb 4.11 has been shipped with readline, where */ + /* history_expand() returned -1 when the line */ + /* should not be executed; in readline 2.1+ */ + /* it should return 2 in such a case */ + retval = -1; +#endif + } + free(*output); + *output = result; + + return (retval); +} + + +/* + * Parse the string into individual tokens, similarily to how shell would do it. + */ +char ** +history_tokenize(const char *str) +{ + int size = 1, result_idx = 0, i, start; + size_t len; + char **result = NULL, *temp, delim = '\0'; + + for (i = 0; str[i]; i++) { + while (isspace((unsigned char) str[i])) + i++; + start = i; + for (; str[i]; i++) { + if (str[i] == '\\') { + if (str[i+1] != '\0') + i++; + } else if (str[i] == delim) + delim = '\0'; + else if (!delim && + (isspace((unsigned char) str[i]) || + strchr("()<>;&|$", str[i]))) + break; + else if (!delim && strchr("'`\"", str[i])) + delim = str[i]; + } + + if (result_idx + 2 >= size) { + size <<= 1; + result = realloc(result, size * sizeof(char *)); + } + len = i - start; + temp = malloc(len + 1); + (void) strncpy(temp, &str[start], len); + temp[len] = '\0'; + result[result_idx++] = temp; + result[result_idx] = NULL; + } + + return (result); +} + + +/* + * limit size of history record to ``max'' events + */ +void +stifle_history(int max) +{ + HistEvent ev; + + if (h == NULL || e == NULL) + rl_initialize(); + + if (history(h, &ev, H_SETSIZE, max) == 0) + max_input_history = max; +} + + +/* + * "unlimit" size of history - set the limit to maximum allowed int value + */ +int +unstifle_history(void) +{ + HistEvent ev; + int omax; + + history(h, &ev, H_SETSIZE, INT_MAX); + omax = max_input_history; + max_input_history = INT_MAX; + return (omax); /* some value _must_ be returned */ +} + + +int +history_is_stifled(void) +{ + + /* cannot return true answer */ + return (max_input_history != INT_MAX); +} + + +/* + * read history from a file given + */ +int +read_history(const char *filename) +{ + HistEvent ev; + + if (h == NULL || e == NULL) + rl_initialize(); + return (history(h, &ev, H_LOAD, filename)); +} + + +/* + * write history to a file given + */ +int +write_history(const char *filename) +{ + HistEvent ev; + + if (h == NULL || e == NULL) + rl_initialize(); + return (history(h, &ev, H_SAVE, filename)); +} + + +/* + * returns history ``num''th event + * + * returned pointer points to static variable + */ +HIST_ENTRY * +history_get(int num) +{ + static HIST_ENTRY she; + HistEvent ev; + int i = 1, curr_num; + + if (h == NULL || e == NULL) + rl_initialize(); + + /* rewind to beginning */ + if (history(h, &ev, H_CURR) != 0) + return (NULL); + curr_num = ev.num; + if (history(h, &ev, H_LAST) != 0) + return (NULL); /* error */ + while (i < num && history(h, &ev, H_PREV) == 0) + i++; + if (i != num) + return (NULL); /* not so many entries */ + + she.line = ev.str; + she.data = NULL; + + /* rewind history to the same event it was before */ + (void) history(h, &ev, H_FIRST); + (void) history(h, &ev, H_NEXT_EVENT, curr_num); + + return (&she); +} + + +/* + * add the line to history table + */ +int +add_history(const char *line) +{ + HistEvent ev; + + if (h == NULL || e == NULL) + rl_initialize(); + + (void) history(h, &ev, H_ENTER, line); + if (history(h, &ev, H_GETSIZE) == 0) + history_length = ev.num; + + return (!(history_length > 0)); /* return 0 if all is okay */ +} + + +/* + * clear the history list - delete all entries + */ +void +clear_history(void) +{ + HistEvent ev; + + history(h, &ev, H_CLEAR); +} + + +/* + * returns offset of the current history event + */ +int +where_history(void) +{ + HistEvent ev; + int curr_num, off; + + if (history(h, &ev, H_CURR) != 0) + return (0); + curr_num = ev.num; + + history(h, &ev, H_FIRST); + off = 1; + while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) + off++; + + return (off); +} + + +/* + * returns current history event or NULL if there is no such event + */ +HIST_ENTRY * +current_history(void) +{ + + return (_move_history(H_CURR)); +} + + +/* + * returns total number of bytes history events' data are using + */ +int +history_total_bytes(void) +{ + HistEvent ev; + int curr_num, size; + + if (history(h, &ev, H_CURR) != 0) + return (-1); + curr_num = ev.num; + + history(h, &ev, H_FIRST); + size = 0; + do + size += strlen(ev.str); + while (history(h, &ev, H_NEXT) == 0); + + /* get to the same position as before */ + history(h, &ev, H_PREV_EVENT, curr_num); + + return (size); +} + + +/* + * sets the position in the history list to ``pos'' + */ +int +history_set_pos(int pos) +{ + HistEvent ev; + int off, curr_num; + + if (pos > history_length || pos < 0) + return (-1); + + history(h, &ev, H_CURR); + curr_num = ev.num; + history(h, &ev, H_FIRST); + off = 0; + while (off < pos && history(h, &ev, H_NEXT) == 0) + off++; + + if (off != pos) { /* do a rollback in case of error */ + history(h, &ev, H_FIRST); + history(h, &ev, H_NEXT_EVENT, curr_num); + return (-1); + } + return (0); +} + + +/* + * returns previous event in history and shifts pointer accordingly + */ +HIST_ENTRY * +previous_history(void) +{ + + return (_move_history(H_PREV)); +} + + +/* + * returns next event in history and shifts pointer accordingly + */ +HIST_ENTRY * +next_history(void) +{ + + return (_move_history(H_NEXT)); +} + + +/* + * generic history search function + */ +static int +_history_search_gen(const char *str, int direction, int pos) +{ + HistEvent ev; + const char *strp; + int curr_num; + + if (history(h, &ev, H_CURR) != 0) + return (-1); + curr_num = ev.num; + + for (;;) { + strp = strstr(ev.str, str); + if (strp && (pos < 0 || &ev.str[pos] == strp)) + return (int) (strp - ev.str); + if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) + break; + } + + history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); + + return (-1); +} + + +/* + * searches for first history event containing the str + */ +int +history_search(const char *str, int direction) +{ + + return (_history_search_gen(str, direction, -1)); +} + + +/* + * searches for first history event beginning with str + */ +int +history_search_prefix(const char *str, int direction) +{ + + return (_history_search_gen(str, direction, 0)); +} + + +/* + * search for event in history containing str, starting at offset + * abs(pos); continue backward, if pos<0, forward otherwise + */ +/* ARGSUSED */ +int +history_search_pos(const char *str, + int direction __attribute__((unused)), int pos) +{ + HistEvent ev; + int curr_num, off; + + off = (pos > 0) ? pos : -pos; + pos = (pos > 0) ? 1 : -1; + + if (history(h, &ev, H_CURR) != 0) + return (-1); + curr_num = ev.num; + + if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) + return (-1); + + + for (;;) { + if (strstr(ev.str, str)) + return (off); + if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) + break; + } + + /* set "current" pointer back to previous state */ + history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); + + return (-1); +} + + +/********************************/ +/* completition functions */ + +/* + * does tilde expansion of strings of type ``~user/foo'' + * if ``user'' isn't valid user name or ``txt'' doesn't start + * w/ '~', returns pointer to strdup()ed copy of ``txt'' + * + * it's callers's responsibility to free() returned string + */ +char * +tilde_expand(char *txt) +{ + struct passwd *pass; + char *temp; + size_t len = 0; + + if (txt[0] != '~') + return (strdup(txt)); + + temp = strchr(txt + 1, '/'); + if (temp == NULL) + temp = strdup(txt + 1); + else { + len = temp - txt + 1; /* text until string after slash */ + temp = malloc(len); + (void) strncpy(temp, txt + 1, len - 2); + temp[len - 2] = '\0'; + } + pass = getpwnam(temp); + free(temp); /* value no more needed */ + if (pass == NULL) + return (strdup(txt)); + + /* update pointer txt to point at string immedially following */ + /* first slash */ + txt += len; + + temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); + + return (temp); +} + + +/* + * return first found file name starting by the ``text'' or NULL if no + * such file can be found + * value of ``state'' is ignored + * + * it's caller's responsibility to free returned string + */ +char * +filename_completion_function(const char *text, int state) +{ + static DIR *dir = NULL; + static char *filename = NULL, *dirname = NULL; + static size_t filename_len = 0; + struct dirent *entry; + char *temp; + size_t len; + + if (state == 0 || dir == NULL) { + if (dir != NULL) { + closedir(dir); + dir = NULL; + } + temp = strrchr(text, '/'); + if (temp) { + temp++; + filename = realloc(filename, strlen(temp) + 1); + (void) strcpy(filename, temp); + len = temp - text; /* including last slash */ + dirname = realloc(dirname, len + 1); + (void) strncpy(dirname, text, len); + dirname[len] = '\0'; + } else { + filename = strdup(text); + dirname = NULL; + } + + /* support for ``~user'' syntax */ + if (dirname && *dirname == '~') { + temp = tilde_expand(dirname); + dirname = realloc(dirname, strlen(temp) + 1); + (void) strcpy(dirname, temp); /* safe */ + free(temp); /* no longer needed */ + } + /* will be used in cycle */ + filename_len = strlen(filename); + if (filename_len == 0) + return (NULL); /* no expansion possible */ + + dir = opendir(dirname ? dirname : "."); + if (!dir) + return (NULL); /* cannot open the directory */ + } + /* find the match */ + while ((entry = readdir(dir)) != NULL) { + /* otherwise, get first entry where first */ + /* filename_len characters are equal */ + if (entry->d_name[0] == filename[0] +#if defined(__SVR4) || defined(__linux__) + && strlen(entry->d_name) >= filename_len +#else + && entry->d_namlen >= filename_len +#endif + && strncmp(entry->d_name, filename, + filename_len) == 0) + break; + } + + if (entry) { /* match found */ + + struct stat stbuf; +#if defined(__SVR4) || defined(__linux__) + len = strlen(entry->d_name) + +#else + len = entry->d_namlen + +#endif + ((dirname) ? strlen(dirname) : 0) + 1 + 1; + temp = malloc(len); + (void) sprintf(temp, "%s%s", + dirname ? dirname : "", entry->d_name); /* safe */ + + /* test, if it's directory */ + if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) + strcat(temp, "/"); /* safe */ + } else + temp = NULL; + + return (temp); +} + + +/* + * a completion generator for usernames; returns _first_ username + * which starts with supplied text + * text contains a partial username preceded by random character + * (usually '~'); state is ignored + * it's callers responsibility to free returned value + */ +char * +username_completion_function(const char *text, int state) +{ + struct passwd *pwd; + + if (text[0] == '\0') + return (NULL); + + if (*text == '~') + text++; + + if (state == 0) + setpwent(); + + while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] + && strcmp(text, pwd->pw_name) == 0); + + if (pwd == NULL) { + endpwent(); + return (NULL); + } + return (strdup(pwd->pw_name)); +} + + +/* + * el-compatible wrapper around rl_complete; needed for key binding + */ +/* ARGSUSED */ +static unsigned char +_el_rl_complete(EditLine *el __attribute__((unused)), int ch) +{ + return (unsigned char) rl_complete(0, ch); +} + + +/* + * returns list of completitions for text given + */ +char ** +completion_matches(const char *text, CPFunction *genfunc) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + unsigned int matches; + + if (h == NULL || e == NULL) + rl_initialize(); + + matches = 0; + match_list_len = 1; + while ((retstr = (*genfunc) (text, matches)) != NULL) { + if (matches + 1 >= match_list_len) { + match_list_len <<= 1; + match_list = realloc(match_list, + match_list_len * sizeof(char *)); + } + match_list[++matches] = retstr; + } + + if (!match_list) + return (char **) NULL; /* nothing found */ + + /* find least denominator and insert it to match_list[0] */ + which = 2; + prevstr = match_list[1]; + max_equal = strlen(prevstr); + for (; which <= matches; which++) { + for (i = 0; i < max_equal && + prevstr[i] == match_list[which][i]; i++) + continue; + max_equal = i; + } + + retstr = malloc(max_equal + 1); + (void) strncpy(retstr, match_list[1], max_equal); + retstr[max_equal] = '\0'; + match_list[0] = retstr; + + /* add NULL as last pointer to the array */ + if (matches + 1 >= match_list_len) + match_list = realloc(match_list, + (match_list_len + 1) * sizeof(char *)); + match_list[matches + 1] = (char *) NULL; + + return (match_list); +} + +/* + * Sort function for qsort(). Just wrapper around strcasecmp(). + */ +static int +_rl_qsort_string_compare(i1, i2) + const void *i1, *i2; +{ + /*LINTED const castaway*/ + const char *s1 = ((const char **)i1)[0]; + /*LINTED const castaway*/ + const char *s2 = ((const char **)i2)[0]; + + return strcasecmp(s1, s2); +} + +/* + * Display list of strings in columnar format on readline's output stream. + * 'matches' is list of strings, 'len' is number of strings in 'matches', + * 'max' is maximum length of string in 'matches'. + */ +void +rl_display_match_list (matches, len, max) + char **matches; + int len, max; +{ + int i, idx, limit, count; + int screenwidth = e->el_term.t_size.h; + + /* + * Find out how many entries can be put on one line, count + * with two spaces between strings. + */ + limit = screenwidth / (max + 2); + if (limit == 0) + limit = 1; + + /* how many lines of output */ + count = len / limit; + if (count * limit < len) + count++; + + /* Sort the items if they are not already sorted. */ + qsort(&matches[1], (size_t)(len - 1), sizeof(char *), + _rl_qsort_string_compare); + + idx = 1; + for(; count > 0; count--) { + for(i=0; i < limit && matches[idx]; i++, idx++) + fprintf(e->el_outfile, "%-*s ", max, matches[idx]); + fprintf(e->el_outfile, "\n"); + } +} + +/* + * Complete the word at or before point, called by rl_complete() + * 'what_to_do' says what to do with the completion. + * `?' means list the possible completions. + * TAB means do standard completion. + * `*' means insert all of the possible completions. + * `!' means to do standard completion, and list all possible completions if + * there is more than one. + * + * Note: '*' support is not implemented + */ +static int +rl_complete_internal(int what_to_do) +{ + CPFunction *complet_func; + const LineInfo *li; + char *temp, **matches; + const char *ctemp; + size_t len; + + rl_completion_type = what_to_do; + + if (h == NULL || e == NULL) + rl_initialize(); + + complet_func = rl_completion_entry_function; + if (!complet_func) + complet_func = filename_completion_function; + + /* We now look backwards for the start of a filename/variable word */ + li = el_line(e); + ctemp = (const char *) li->cursor; + while (ctemp > li->buffer + && !strchr(rl_basic_word_break_characters, ctemp[-1]) + && (!rl_special_prefixes + || !strchr(rl_special_prefixes, ctemp[-1]) ) ) + ctemp--; + + len = li->cursor - ctemp; + temp = alloca(len + 1); + (void) strncpy(temp, ctemp, len); + temp[len] = '\0'; + + /* these can be used by function called in completion_matches() */ + /* or (*rl_attempted_completion_function)() */ + rl_point = li->cursor - li->buffer; + rl_end = li->lastchar - li->buffer; + + if (!rl_attempted_completion_function) + matches = completion_matches(temp, complet_func); + else { + int end = li->cursor - li->buffer; + matches = (*rl_attempted_completion_function) (temp, (int) + (end - len), end); + } + + if (matches) { + int i, retval = CC_REFRESH; + int matches_num, maxlen, match_len, match_display=1; + + /* + * Only replace the completed string with common part of + * possible matches if there is possible completion. + */ + if (matches[0][0] != '\0') { + el_deletestr(e, (int) len); + el_insertstr(e, matches[0]); + } + + if (what_to_do == '?') + goto display_matches; + + if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { + /* + * We found exact match. Add a space after + * it, unless we do filename completition and the + * object is a directory. + */ + size_t alen = strlen(matches[0]); + if ((complet_func != filename_completion_function + || (alen > 0 && (matches[0])[alen - 1] != '/')) + && rl_completion_append_character) { + char buf[2]; + buf[0] = rl_completion_append_character; + buf[1] = '\0'; + el_insertstr(e, buf); + } + } else if (what_to_do == '!') { + display_matches: + /* + * More than one match and requested to list possible + * matches. + */ + + for(i=1, maxlen=0; matches[i]; i++) { + match_len = strlen(matches[i]); + if (match_len > maxlen) + maxlen = match_len; + } + matches_num = i - 1; + + /* newline to get on next line from command line */ + fprintf(e->el_outfile, "\n"); + + /* + * If there are too many items, ask user for display + * confirmation. + */ + if (matches_num > rl_completion_query_items) { + fprintf(e->el_outfile, + "Display all %d possibilities? (y or n) ", + matches_num); + fflush(e->el_outfile); + if (getc(stdin) != 'y') + match_display = 0; + fprintf(e->el_outfile, "\n"); + } + + if (match_display) + rl_display_match_list(matches, matches_num, + maxlen); + retval = CC_REDISPLAY; + } else if (matches[0][0]) { + /* + * There was some common match, but the name was + * not complete enough. Next tab will print possible + * completions. + */ + el_beep(e); + } else { + /* lcd is not a valid object - further specification */ + /* is needed */ + el_beep(e); + retval = CC_NORM; + } + + /* free elements of array and the array itself */ + for (i = 0; matches[i]; i++) + free(matches[i]); + free(matches), matches = NULL; + + return (retval); + } + return (CC_NORM); +} + + +/* + * complete word at current point + */ +int +rl_complete(int ignore, int invoking_key) +{ + if (h == NULL || e == NULL) + rl_initialize(); + + if (rl_inhibit_completion) { + rl_insert(ignore, invoking_key); + return (CC_REFRESH); + } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) + return rl_complete_internal('?'); + else if (_rl_complete_show_all) + return rl_complete_internal('!'); + else + return (rl_complete_internal(TAB)); +} + + +/* + * misc other functions + */ + +/* + * bind key c to readline-type function func + */ +int +rl_bind_key(int c, int func(int, int)) +{ + int retval = -1; + + if (h == NULL || e == NULL) + rl_initialize(); + + if (func == rl_insert) { + /* XXX notice there is no range checking of ``c'' */ + e->el_map.key[c] = ED_INSERT; + retval = 0; + } + return (retval); +} + + +/* + * read one key from input - handles chars pushed back + * to input stream also + */ +int +rl_read_key(void) +{ + char fooarr[2 * sizeof(int)]; + + if (e == NULL || h == NULL) + rl_initialize(); + + return (el_getc(e, fooarr)); +} + + +/* + * reset the terminal + */ +/* ARGSUSED */ +void +rl_reset_terminal(const char *p __attribute__((unused))) +{ + + if (h == NULL || e == NULL) + rl_initialize(); + el_reset(e); +} + + +/* + * insert character ``c'' back into input stream, ``count'' times + */ +int +rl_insert(int count, int c) +{ + char arr[2]; + + if (h == NULL || e == NULL) + rl_initialize(); + + /* XXX - int -> char conversion can lose on multichars */ + arr[0] = c; + arr[1] = '\0'; + + for (; count > 0; count--) + el_push(e, arr); + + return (0); +} diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/readline/readline.h new file mode 100644 index 00000000000..851ade02b53 --- /dev/null +++ b/cmd-line-utils/libedit/readline/readline.h @@ -0,0 +1,127 @@ +/* $NetBSD: readline.h,v 1.1 2001/01/05 21:15:50 jdolecek Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _READLINE_H_ +#define _READLINE_H_ + +#include <sys/types.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#else +#ifndef __BEGIN_DECLS +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif +#endif +#endif + +/* list of readline stuff supported by editline library's readline wrapper */ + +/* typedefs */ +typedef int Function(const char *, int); +typedef void VFunction(void); +typedef char *CPFunction(const char *, int); +typedef char **CPPFunction(const char *, int, int); + +typedef struct _hist_entry { + const char *line; + const char *data; +} HIST_ENTRY; + +/* global variables used by readline enabled applications */ +__BEGIN_DECLS +extern const char *rl_library_version; +extern const char *rl_readline_name; +extern FILE *rl_instream; +extern FILE *rl_outstream; +extern char *rl_line_buffer; +extern int rl_point, rl_end; +extern int history_base, history_length; +extern int max_input_history; +extern const char *rl_basic_word_break_characters; +extern char *rl_completer_word_break_characters; +extern char *rl_completer_quote_characters; +extern CPFunction *rl_completion_entry_function; +extern CPPFunction *rl_attempted_completion_function; +extern int rl_completion_type; +extern int rl_completion_query_items; +extern char *rl_special_prefixes; +extern int rl_completion_append_character; + +/* supported functions */ +char *readline(const char *); +int rl_initialize(void); + +void using_history(void); +int add_history(const char *); +void clear_history(void); +void stifle_history(int); +int unstifle_history(void); +int history_is_stifled(void); +int where_history(void); +HIST_ENTRY *current_history(void); +HIST_ENTRY *history_get(int); +int history_total_bytes(void); +int history_set_pos(int); +HIST_ENTRY *previous_history(void); +HIST_ENTRY *next_history(void); +int history_search(const char *, int); +int history_search_prefix(const char *, int); +int history_search_pos(const char *, int, int); +int read_history(const char *); +int write_history(const char *); +int history_expand(char *, char **); +char **history_tokenize(const char *); + +char *tilde_expand(char *); +char *filename_completion_function(const char *, int); +char *username_completion_function(const char *, int); +int rl_complete(int, int); +int rl_read_key(void); +char **completion_matches(const char *, CPFunction *); +void rl_display_match_list(char **, int, int); + +int rl_insert(int, int); +void rl_reset_terminal(const char *); +int rl_bind_key(int, int (*)(int, int)); +__END_DECLS + +#endif /* _READLINE_H_ */ diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c new file mode 100644 index 00000000000..534e7e12304 --- /dev/null +++ b/cmd-line-utils/libedit/refresh.c @@ -0,0 +1,1100 @@ +/* $NetBSD: refresh.c,v 1.17 2001/04/13 00:53: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. + */ + +#include "compat.h" + +/* + * 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(EditLine *, int); +private void re_update_line(EditLine *, char *, char *, int); +private void re_insert (EditLine *, char *, int, int, char *, int); +private void re_delete(EditLine *, char *, int, int, int); +private void re_fastputc(EditLine *, int); +private void re__strncopy(char *, char *, size_t); +private void re__copy_and_pad(char *, const char *, size_t); + +#ifdef DEBUG_REFRESH +private void re_printstr(EditLine *, char *, char *, char *); +#define __F el->el_errfile +#define ELRE_ASSERT(a, b, c) do \ + if (a) { \ + (void) fprintf b; \ + c; \ + } \ + while (0) +#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) + +/* re_printstr(): + * Print a string on the debugging pty + */ +private void +re_printstr(EditLine *el, char *str, char *f, char *t) +{ + + ELRE_DEBUG(1, (__F, "%s:\"", str)); + while (f < t) + ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); + ELRE_DEBUG(1, (__F, "\"\r\n")); +} +#else +#define ELRE_ASSERT(a, b, c) +#define ELRE_DEBUG(a, b) +#endif + + +/* re_addc(): + * Draw c, expanding tabs, control chars etc. + */ +private void +re_addc(EditLine *el, int c) +{ + + if (isprint(c)) { + re_putc(el, c, 1); + return; + } + if (c == '\n') { /* expand the newline */ + int oldv = el->el_refresh.r_cursor.v; + re_putc(el, '\0', 0); /* assure end of line */ + if (oldv == el->el_refresh.r_cursor.v) { /* XXX */ + 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, ' ', 1); + if ((el->el_refresh.r_cursor.h & 07) == 0) + break; /* go until tab stop */ + } + } else if (iscntrl(c)) { + re_putc(el, '^', 1); + if (c == '\177') + re_putc(el, '?', 1); + else + /* uncontrolify it; works only for iso8859-1 like sets */ + re_putc(el, (c | 0100), 1); + } else { + re_putc(el, '\\', 1); + re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1); + re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1); + re_putc(el, (c & 07) + '0', 1); + } +} + + +/* re_putc(): + * Draw the character given + */ +protected void +re_putc(EditLine *el, int c, int shift) +{ + + ELRE_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; + if (!shift) + return; + + 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. */ + + /* + * If we would overflow (input is longer than terminal size), + * emulate scroll by dropping first line and shuffling the rest. + * We do this via pointer shuffling - it's safe in this case + * and we avoid memcpy(). + */ + if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) { + int i, lins = el->el_term.t_size.v; + char *firstline = el->el_vdisplay[0]; + + for(i=1; i < lins; i++) + el->el_vdisplay[i-1] = el->el_vdisplay[i]; + + firstline[0] = '\0'; /* empty the string */ + el->el_vdisplay[i-1] = firstline; + } else + el->el_refresh.r_cursor.v++; + + ELRE_ASSERT(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()); + } +} + + +/* 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(EditLine *el) +{ + int i, rhdiff; + char *cp, *st; + coord_t cur; +#ifdef notyet + size_t termsz; +#endif + + ELRE_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; + + /* temporarily draw rprompt to calculate its size */ + prompt_print(el, EL_RPROMPT); + + /* 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, EL_PROMPT); + + /* draw the current input buffer */ +#if notyet + termsz = el->el_term.t_size.h * el->el_term.t_size.v; + if (el->el_line.lastchar - el->el_line.buffer > termsz) { + /* + * If line is longer than terminal, process only part + * of line which would influence display. + */ + size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; + + st = el->el_line.lastchar - rem + - (termsz - (((rem / el->el_term.t_size.v) - 1) + * el->el_term.t_size.v)); + } else +#endif + st = el->el_line.buffer; + + for (cp = st; cp < el->el_line.lastchar; cp++) { + if (cp == el->el_line.cursor) { + /* save for later */ + cur.h = el->el_refresh.r_cursor.h; + cur.v = el->el_refresh.r_cursor.v; + } + re_addc(el, (unsigned char) *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; + } + rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h - + el->el_rprompt.p_pos.h; + if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && + !el->el_refresh.r_cursor.v && rhdiff > 1) { + /* + * have a right-hand side prompt that will fit + * on the end of the first line with at least + * one character gap to the input buffer. + */ + while (--rhdiff > 0) /* pad out with spaces */ + re_putc(el, ' ', 1); + prompt_print(el, EL_RPROMPT); + } else { + el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */ + el->el_rprompt.p_pos.v = 0; + } + + re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */ + + el->el_refresh.r_newcv = el->el_refresh.r_cursor.v; + + ELRE_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])); + + ELRE_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], + (size_t) el->el_term.t_size.h); + } + ELRE_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, (int) strlen(el->el_display[i])); +#ifdef DEBUG_REFRESH + term_overwrite(el, "C\b", 2); +#endif /* DEBUG_REFRESH */ + el->el_display[i][0] = '\0'; + } + + el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ + ELRE_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); +} + + +/* re_goto_bottom(): + * used to go to last used screen line + */ +protected void +re_goto_bottom(EditLine *el) +{ + + term_move_to_line(el, el->el_refresh.r_oldcv); + term__putc('\r'); + term__putc('\n'); + re_clear_display(el); + term__flush(); +} + + +/* 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(EditLine *el __attribute__((unused)), + char *d, int dat, int dlen, char *s, int num) +{ + char *a, *b; + + if (num <= 0) + return; + if (num > dlen - dat) + num = dlen - dat; + + ELRE_DEBUG(1, + (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, d)); + ELRE_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 */ + } + ELRE_DEBUG(1, (__F, + "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, d)); + ELRE_DEBUG(1, (__F, "s == \"%s\"n", s)); + + /* copy the characters */ + for (a = d + dat; (a < d + dlen) && (num > 0); num--) + *a++ = *s++; + + ELRE_DEBUG(1, + (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", + num, dat, dlen, d, s)); + ELRE_DEBUG(1, (__F, "s == \"%s\"n", s)); +} + + +/* re_delete(): + * delete num characters d at dat, maximum length of d is dlen + */ +private void +/*ARGSUSED*/ +re_delete(EditLine *el __attribute__((unused)), + char *d, int dat, int dlen, int num) +{ + char *a, *b; + + if (num <= 0) + return; + if (dat + num >= dlen) { + d[dat] = '\0'; + return; + } + ELRE_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 */ + } + ELRE_DEBUG(1, + (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", + num, dat, dlen, d)); +} + + +/* re__strncopy(): + * Like strncpy without padding. + */ +private void +re__strncopy(char *a, char *b, size_t n) +{ + + while (n-- && *b) + *a++ = *b++; +} + + +/***************************************************************** + 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(EditLine *el, char *old, char *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') { + ELRE_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); + + ELRE_DEBUG(1, (__F, "\n")); + ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n", + ofd - old, osb - old, ose - old, ols - old, oe - old)); + ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n", + nfd - new, nsb - new, nse - new, nls - new, ne - new)); + ELRE_DEBUG(1, (__F, + "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n")); + ELRE_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 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)) { + ELRE_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) { + ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); + /* + * insert fx chars of new starting at nfd + */ + if (fx > 0) { + ELRE_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, + (size_t) ((nsb - nfd) - fx)); + } else { + ELRE_DEBUG(1, (__F, "without anything to save\r\n")); + term_overwrite(el, nfd, (nsb - nfd)); + re__strncopy(ofd, nfd, (size_t) (nsb - nfd)); + /* + * Done + */ + return; + } + } else if (fx < 0) { + ELRE_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) { + ELRE_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) { + ELRE_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, (size_t) (nsb - nfd)); + + } else { + ELRE_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)); + ELRE_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 && (ose - old) + fx < el->el_term.t_size.h) { + ELRE_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) { + ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); + /* + * Again a duplicate test. + */ + if (sx < 0) { + ELRE_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 { + ELRE_DEBUG(1, (__F, + "but with nothing left to save\r\n")); + term_overwrite(el, nse, (nls - nse)); + ELRE_DEBUG(1, (__F, + "cleareol %d\n", (oe - old) - (ne - new))); + if ((oe - old) - (ne - new) != 0) + 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)) { + ELRE_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) { + ELRE_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 + */ + ELRE_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, + (size_t) ((nsb - nfd) - fx)); + } else { + ELRE_DEBUG(1, (__F, "without anything to save\r\n")); + term_overwrite(el, nfd, (nsb - nfd)); + re__strncopy(ofd, nfd, (size_t) (nsb - nfd)); + } + } + /* + * line is now NEW up to nse + */ + if (sx >= 0) { + ELRE_DEBUG(1, (__F, + "second diff insert at %d...\r\n", nse - new)); + term_move_to_char(el, nse - new); + if (ols != oe) { + ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); + if (sx > 0) { + /* insert sx chars of new starting at nse */ + ELRE_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 { + ELRE_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. + */ + } + } + ELRE_DEBUG(1, (__F, "done.\r\n")); +} + + +/* re__copy_and_pad(): + * Copy string and pad with spaces + */ +private void +re__copy_and_pad(char *dst, const char *src, size_t width) +{ + unsigned int i; + + for (i = 0; i < width; i++) { + if (*src == '\0') + break; + *dst++ = *src++; + } + + for (; i < width; i++) + *dst++ = ' '; + + *dst = '\0'; +} + + +/* re_refresh_cursor(): + * Move to the new cursor position + */ +protected void +re_refresh_cursor(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((unsigned char) c)) { + /* if control char */ + h++; + if (h > th) { /* if overflow, compensate */ + h = 1; + v++; + } + } else if (!isprint((unsigned char) 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_fastputc(): + * Add a character fast. + */ +private void +re_fastputc(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; + + /* + * If we would overflow (input is longer than terminal size), + * emulate scroll by dropping first line and shuffling the rest. + * We do this via pointer shuffling - it's safe in this case + * and we avoid memcpy(). + */ + if (el->el_cursor.v + 1 >= el->el_term.t_size.v) { + int i, lins = el->el_term.t_size.v; + char *firstline = el->el_display[0]; + + for(i=1; i < lins; i++) + el->el_display[i-1] = el->el_display[i]; + + re__copy_and_pad(firstline, "", 0); + el->el_display[i-1] = firstline; + } else { + el->el_cursor.v++; + el->el_refresh.r_oldcv++; + } + if (EL_HAS_AUTO_MARGINS) { + if (EL_HAS_MAGIC_MARGINS) { + term__putc(' '); + term__putc('\b'); + } + } else { + term__putc('\r'); + term__putc('\n'); + } + } +} + + +/* re_fastaddc(): + * we added just one char, handle it fast. + * Assumes that screen cursor == real cursor + */ +protected void +re_fastaddc(EditLine *el) +{ + char c; + int rhdiff; + + 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; + } + rhdiff = el->el_term.t_size.h - el->el_cursor.h - + el->el_rprompt.p_pos.h; + if (el->el_rprompt.p_pos.h && rhdiff < 3) { + re_refresh(el); /* clear out rprompt if less than 1 char gap */ + return; + } /* else (only do at end of line, no TAB) */ + if (iscntrl((unsigned char) c)) { /* if control char, do caret */ + char mc = (c == '\177') ? '?' : (c | 0100); + re_fastputc(el, '^'); + re_fastputc(el, mc); + } else if (isprint((unsigned char) c)) { /* normal char */ + re_fastputc(el, c); + } else { + re_fastputc(el, '\\'); + re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0')); + re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0')); + re_fastputc(el, (c & 7) + '0'); + } + term__flush(); +} + + +/* re_clear_display(): + * clear the screen buffers so that new new prompt starts fresh. + */ +protected void +re_clear_display(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; +} + + +/* re_clear_lines(): + * Make sure all lines are *really* blank + */ +protected void +re_clear_lines(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 */ + } +} diff --git a/cmd-line-utils/libedit/refresh.h b/cmd-line-utils/libedit/refresh.h new file mode 100644 index 00000000000..33c0887c1b3 --- /dev/null +++ b/cmd-line-utils/libedit/refresh.h @@ -0,0 +1,63 @@ +/* $NetBSD: refresh.h,v 1.4 2001/01/10 07:45:42 jdolecek 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; /* Vertical locations */ + int r_newcv; +} el_refresh_t; + +protected void re_putc(EditLine *, int, int); +protected void re_clear_lines(EditLine *); +protected void re_clear_display(EditLine *); +protected void re_refresh(EditLine *); +protected void re_refresh_cursor(EditLine *); +protected void re_fastaddc(EditLine *); +protected void re_goto_bottom(EditLine *); + +#endif /* _h_el_refresh */ diff --git a/cmd-line-utils/libedit/search.c b/cmd-line-utils/libedit/search.c new file mode 100644 index 00000000000..bdc3a1e8bb9 --- /dev/null +++ b/cmd-line-utils/libedit/search.c @@ -0,0 +1,646 @@ +/* $NetBSD: search.c,v 1.11 2001/01/23 15:55:31 jdolecek 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. + */ + +#include "compat.h" + +/* + * search.c: History and character search functions + */ +#include "sys.h" +#include <stdlib.h> +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#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(EditLine *el) +{ + + el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ); + if (el->el_search.patbuf == NULL) + return (-1); + 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(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(const char *msg) +{ +} +#endif + + +/* el_match(): + * Return if string matches pattern + */ +protected int +el_match(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(const char *); + extern int re_exec(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(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(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(EditLine *el, int dir) +{ + static const char STRfwd[] = {'f', 'w', 'd', '\0'}, + STRbck[] = {'b', 'c', 'k', '\0'}; + static char pchar = ':';/* ':' = normal, '?' = failed */ + static char endcmd[2] = {'\0', '\0'}; + char ch, *ocursor = el->el_line.cursor, oldpchar = pchar; + const char *cp; + + el_action_t ret = CC_NORM; + + int ohisteventno = el->el_history.eventno; + int oldpatlen = el->el_search.patlen; + int newdir = dir; + int 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.event + * no 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(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, + EL_BUFSIZ - 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, EL_BUFSIZ - 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(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(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(EditLine *el, int ch, int count, int tflag) +{ + char *cp; + + cp = el->el_line.cursor; + while (count--) { + if (*cp == ch) + cp--; + while (cp > el->el_line.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(EditLine *el, int ch, int count, int tflag) +{ + char *cp; + + cp = el->el_line.cursor; + while (count--) { + if (*cp == ch) + cp++; + while (cp < el->el_line.lastchar && *cp != ch) + cp++; + } + + if (cp >= el->el_line.lastchar) + return (CC_ERROR); + + if (*cp == ch && tflag) + cp--; + + el->el_line.cursor = cp; + + if (el->el_chared.c_vcmd.action & DELETE) { + el->el_line.cursor++; + cv_delfini(el); + return (CC_REFRESH); + } + re_refresh_cursor(el); + return (CC_NORM); +} diff --git a/cmd-line-utils/libedit/search.h b/cmd-line-utils/libedit/search.h new file mode 100644 index 00000000000..676bbe2e35b --- /dev/null +++ b/cmd-line-utils/libedit/search.h @@ -0,0 +1,70 @@ +/* $NetBSD: search.h,v 1.5 2000/09/04 22:06:32 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 */ + size_t 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(const char *, const char *); +protected int search_init(EditLine *); +protected void search_end(EditLine *); +protected int c_hmatch(EditLine *, const char *); +protected void c_setpat(EditLine *); +protected el_action_t ce_inc_search(EditLine *, int); +protected el_action_t cv_search(EditLine *, int); +protected el_action_t ce_search_line(EditLine *, char *, int); +protected el_action_t cv_repeat_srch(EditLine *, int); +protected el_action_t cv_csearch_back(EditLine *, int, int, int); +protected el_action_t cv_csearch_fwd(EditLine *, int, int, int); + +#endif /* _h_el_search */ diff --git a/cmd-line-utils/libedit/sig.c b/cmd-line-utils/libedit/sig.c new file mode 100644 index 00000000000..19408a0a8f2 --- /dev/null +++ b/cmd-line-utils/libedit/sig.c @@ -0,0 +1,192 @@ +/* $NetBSD: sig.c,v 1.8 2001/01/09 17:31:04 jdolecek 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. + */ + +#include "compat.h" + +/* + * 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 const int sighdl[] = { +#define _DO(a) (a), + ALLSIGS +#undef _DO + - 1 +}; + +private void sig_handler(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(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(EditLine *el) +{ + int i; + sigset_t nset, oset; + + (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, a); + 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); + if (el->el_signal == NULL) + return (-1); + 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(EditLine *el) +{ + + el_free((ptr_t) el->el_signal); + el->el_signal = NULL; +} + + +/* sig_set(): + * set all the signal handlers + */ +protected void +sig_set(EditLine *el) +{ + int i; + sigset_t nset, oset; + + (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, a); + 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(EditLine *el) +{ + int i; + sigset_t nset, oset; + + (void) sigemptyset(&nset); +#define _DO(a) (void) sigaddset(&nset, a); + 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/cmd-line-utils/libedit/sig.h b/cmd-line-utils/libedit/sig.h new file mode 100644 index 00000000000..e7231b65cf4 --- /dev/null +++ b/cmd-line-utils/libedit/sig.h @@ -0,0 +1,72 @@ +/* $NetBSD: sig.h,v 1.3 2000/09/04 22:06:32 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(EditLine*); +protected int sig_init(EditLine*); +protected void sig_set(EditLine*); +protected void sig_clr(EditLine*); + +#endif /* _h_el_sig */ diff --git a/cmd-line-utils/libedit/strlcpy.c b/cmd-line-utils/libedit/strlcpy.c new file mode 100644 index 00000000000..74317d99cd2 --- /dev/null +++ b/cmd-line-utils/libedit/strlcpy.c @@ -0,0 +1,28 @@ +#include <string.h> + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t size) +{ + if(size) { + strncpy(dst, src, size-1); + dst[size-1] = '\0'; + } else { + dst[0] = '\0'; + } + return strlen(src); +} + +size_t strlcat(char *dst, const char *src, size_t size) +{ + int dl = strlen(dst); + int sz = size-dl-1; + + if(sz >= 0) { + strncat(dst, src, sz); + dst[sz] = '\0'; + } + + return dl+strlen(src); +} + +#endif diff --git a/cmd-line-utils/libedit/strlcpy.h b/cmd-line-utils/libedit/strlcpy.h new file mode 100644 index 00000000000..e4d3a7ffa3f --- /dev/null +++ b/cmd-line-utils/libedit/strlcpy.h @@ -0,0 +1,2 @@ +size_t strlcpy(char *dst, const char *src, size_t size); +size_t strlcat(char *dst, const char *src, size_t size); diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h new file mode 100644 index 00000000000..d9007243456 --- /dev/null +++ b/cmd-line-utils/libedit/sys.h @@ -0,0 +1,94 @@ +/* $NetBSD: sys.h,v 1.4 2000/09/04 22:06:32 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 + +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +#ifndef _PTR_T +# define _PTR_T +typedef void *ptr_t; +#endif + +#ifndef _IOCTL_T +# define _IOCTL_T +typedef void *ioctl_t; +#endif + +#include <stdio.h> + +#define REGEX /* Use POSIX.2 regular expression functions */ +#undef REGEXP /* Use UNIX V8 regular expression functions */ + +#if defined(__sun__) && defined(__SVR4) +# undef REGEX +# undef REGEXP +# include <malloc.h> +typedef void (*sig_t)(int); +#endif + +#ifndef __P +#ifdef __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif +#endif + +#endif /* _h_sys */ diff --git a/cmd-line-utils/libedit/term.c b/cmd-line-utils/libedit/term.c new file mode 100644 index 00000000000..df8d1ea67cc --- /dev/null +++ b/cmd-line-utils/libedit/term.c @@ -0,0 +1,1564 @@ +/* $NetBSD: term.c,v 1.32 2001/01/23 15:55:31 jdolecek 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. + */ + +#include "compat.h" + +/* + * 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> +#include <sys/types.h> +#include <sys/ioctl.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 const struct { + const 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 const struct termcapstr { + const char *name; + const 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_kh 36 + { "kh", "send cursor home" }, +#define T_at7 37 + { "@7", "send cursor end" }, +#define T_str 38 + { NULL, NULL } +}; + +private const struct termcapval { + const char *name; + const char *long_name; +} tval[] = { +#define T_am 0 + { "am", "has automatic margins" }, +#define T_pt 1 + { "pt", "has physical tabs" }, +#define T_li 2 + { "li", "Number of lines" }, +#define T_co 3 + { "co", "Number of columns" }, +#define T_km 4 + { "km", "Has meta key" }, +#define T_xt 5 + { "xt", "Tab chars destructive" }, +#define T_xn 6 + { "xn", "newline ignored at right margin" }, +#define T_MT 7 + { "MT", "Has meta key" }, /* XXX? */ +#define T_val 8 + { NULL, NULL, } +}; +/* do two or more of the attributes use me */ + +private void term_setflags(EditLine *); +private int term_rebuffer_display(EditLine *); +private void term_free_display(EditLine *); +private int term_alloc_display(EditLine *); +private void term_alloc(EditLine *, const struct termcapstr *, const char *); +private void term_init_arrow(EditLine *); +private void term_reset_arrow(EditLine *); + + +private FILE *term_outfile = NULL; /* XXX: How do we fix that? */ + + +/* term_setflags(): + * Set the terminal capability flags + */ +private void +term_setflags(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; + EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0; + EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 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(EditLine *el) +{ + + el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE); + if (el->el_term.t_buf == NULL) + return (-1); + el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE); + if (el->el_term.t_cap == NULL) + return (-1); + el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t)); + if (el->el_term.t_fkey == NULL) + return (-1); + el->el_term.t_loc = 0; + el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *)); + if (el->el_term.t_str == NULL) + return (-1); + (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *)); + el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int)); + if (el->el_term.t_val == NULL) + return (-1); + (void) memset(el->el_term.t_val, 0, T_val * sizeof(int)); + term_outfile = el->el_outfile; + if (term_set(el, NULL) == -1) + return (-1); + term_init_arrow(el); + return (0); +} +/* term_end(): + * Clean up the terminal stuff + */ +protected void +term_end(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(EditLine *el, const struct termcapstr *t, const 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; +} + + +/* term_rebuffer_display(): + * Rebuffer the display after the screen changed size + */ +private int +term_rebuffer_display(EditLine *el) +{ + coord_t *c = &el->el_term.t_size; + + term_free_display(el); + + c->h = Val(T_co); + c->v = Val(T_li); + + if (term_alloc_display(el) == -1) + return (-1); + return (0); +} + + +/* term_alloc_display(): + * Allocate a new display. + */ +private int +term_alloc_display(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))); + if (b == NULL) + return (-1); + for (i = 0; i < c->v; i++) { + b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); + if (b[i] == NULL) + return (-1); + } + b[c->v] = NULL; + el->el_display = b; + + b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); + if (b == NULL) + return (-1); + for (i = 0; i < c->v; i++) { + b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); + if (b[i] == NULL) + return (-1); + } + b[c->v] = NULL; + el->el_vdisplay = b; + return (0); +} + + +/* term_free_display(): + * Free the display buffers + */ +private void +term_free_display(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); + } +} + + +/* term_move_to_line(): + * move to line <where> (first line == 0) + * as efficiently as possible + */ +protected void +term_move_to_line(EditLine *el, int where) +{ + int del; + + 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) { + while (del > 0) { + if (EL_HAS_AUTO_MARGINS && + el->el_display[el->el_cursor.v][0] != '\0') { + /* move without newline */ + term_move_to_char(el, el->el_term.t_size.h - 1); + term_overwrite(el, + &el->el_display[el->el_cursor.v][el->el_cursor.h], + 1); + /* updates Cursor */ + del--; + } else { + if ((del > 1) && GoodStr(T_DO)) { + (void) tputs(tgoto(Str(T_DO), del, del), + del, term__putc); + del = 0; + } else { + for (; del > 0; del--) + term__putc('\n'); + /* because the \n will become \r\n */ + el->el_cursor.h = 0; + } + } + } + } 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 (; del < 0; del++) + (void) tputs(Str(T_up), 1, term__putc); + } + } + el->el_cursor.v = where;/* now where is here */ +} + + +/* term_move_to_char(): + * Move to the character position specified + */ +protected void +term_move_to_char(EditLine *el, int where) +{ + int del, i; + +mc_again: + if (where == el->el_cursor.h) + return; + + if (where > el->el_term.t_size.h) { +#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 I can do tabs, use them */ + if (EL_CAN_TAB) { + 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 ? + ((unsigned int)-del > (((unsigned int) 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 */ +} + + +/* term_overwrite(): + * Overstrike num characters + */ +protected void +term_overwrite(EditLine *el, const char *cp, int n) +{ + if (n <= 0) + return; /* catch bugs */ + + if (n > el->el_term.t_size.h) { +#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); + + if (el->el_cursor.h >= el->el_term.t_size.h) { /* wrap? */ + if (EL_HAS_AUTO_MARGINS) { /* yes */ + el->el_cursor.h = 0; + el->el_cursor.v++; + if (EL_HAS_MAGIC_MARGINS) { + /* force the wrap to avoid the "magic" + * situation */ + char c; + if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h]) + != '\0') + term_overwrite(el, &c, 1); + else + term__putc(' '); + el->el_cursor.h = 1; + } + } else /* no wrap, but cursor stays on screen */ + el->el_cursor.h = el->el_term.t_size.h; + } +} + + +/* term_deletechars(): + * Delete num characters + */ +protected void +term_deletechars(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); +} + + +/* term_insertwrite(): + * Puts terminal in insert character mode or inserts num + * characters in the line + */ +protected void +term_insertwrite(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 expensive */ + (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); +} + + +/* term_clear_EOL(): + * clear to end of line. There are num characters to clear + */ +protected void +term_clear_EOL(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 */ + } +} + + +/* term_clear_screen(): + * Clear the screen + */ +protected void +term_clear_screen(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'); + } +} + + +/* term_beep(): + * Beep the way the terminal wants us + */ +protected void +term_beep(EditLine *el) +{ + 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 */ +} + + +#ifdef notdef +/* term_clear_to_bottom(): + * Clear to the bottom of the screen + */ +protected void +term_clear_to_bottom(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); +} +#endif + + +/* term_set(): + * Read in the terminal capabilities from the requested terminal + */ +protected int +term_set(EditLine *el, const char *term) +{ + int i; + char buf[TC_BUFSIZE]; + char *area; + const 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"; + + if (strcmp(term, "emacs") == 0) + el->el_flags |= EDIT_DISABLED; + + 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 { + /* auto/magic margins */ + Val(T_am) = tgetflag("am"); + Val(T_xn) = tgetflag("xn"); + /* 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); + + /* get the correct window size */ + (void) term_get_size(el, &lins, &cols); + if (term_change_size(el, lins, cols) == -1) + return (-1); + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + term_bind_arrow(el); + return (i <= 0 ? -1 : 0); +} + + +/* term_get_size(): + * Return the new window size in lines and cols, and + * true if the size was changed. + */ +protected int +term_get_size(EditLine *el, int *lins, int *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); +} + + +/* term_change_size(): + * Change the size of the terminal + */ +protected int +term_change_size(EditLine *el, int lins, int cols) +{ + /* + * Just in case + */ + Val(T_co) = (cols < 2) ? 80 : cols; + Val(T_li) = (lins < 1) ? 24 : lins; + + /* re-make display buffers */ + if (term_rebuffer_display(el) == -1) + return (-1); + re_clear_display(el); + return (0); +} + + +/* term_init_arrow(): + * Initialize the arrow key bindings from termcap + */ +private void +term_init_arrow(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; + + arrow[A_K_HO].name = "home"; + arrow[A_K_HO].key = T_kh; + arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG; + arrow[A_K_HO].type = XK_CMD; + + arrow[A_K_EN].name = "end"; + arrow[A_K_EN].key = T_at7; + arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END; + arrow[A_K_EN].type = XK_CMD; +} + + +/* term_reset_arrow(): + * Reset arrow key bindings + */ +private void +term_reset_arrow(EditLine *el) +{ + fkey_t *arrow = el->el_term.t_fkey; + static const char strA[] = {033, '[', 'A', '\0'}; + static const char strB[] = {033, '[', 'B', '\0'}; + static const char strC[] = {033, '[', 'C', '\0'}; + static const char strD[] = {033, '[', 'D', '\0'}; + static const char strH[] = {033, '[', 'H', '\0'}; + static const char strF[] = {033, '[', 'F', '\0'}; + static const char stOA[] = {033, 'O', 'A', '\0'}; + static const char stOB[] = {033, 'O', 'B', '\0'}; + static const char stOC[] = {033, 'O', 'C', '\0'}; + static const char stOD[] = {033, 'O', 'D', '\0'}; + static const char stOH[] = {033, 'O', 'H', '\0'}; + static const char stOF[] = {033, 'O', 'F', '\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, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].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); + key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].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, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].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); + key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + } +} + + +/* term_set_arrow(): + * Set an arrow key binding + */ +protected int +term_set_arrow(EditLine *el, const 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(EditLine *el, const 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(EditLine *el, const 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(EditLine *el) +{ + el_action_t *map; + const el_action_t *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 < A_K_NKEYS; 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 int +term__putc(int c) +{ + + return (fputc(c, term_outfile)); +} + + +/* term__flush(): + * Flush output + */ +protected void +term__flush(void) +{ + + (void) fflush(term_outfile); +} + + +/* term_telltc(): + * Print the current termcap characteristics + */ +protected int +/*ARGSUSED*/ +term_telltc(EditLine *el, int + argc __attribute__((unused)), + const char **argv __attribute__((unused))) +{ + const 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 "); + (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n", + EL_HAS_AUTO_MARGINS ? "has" : "does not have"); + if (EL_HAS_AUTO_MARGINS) + (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", + EL_HAS_MAGIC_MARGINS ? "has" : "does not have"); + + 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(EditLine *el, int argc __attribute__((unused)), const char **argv) +{ + const struct termcapstr *ts; + const struct termcapval *tv; + const 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] || + tv == &tval[T_am] || tv == &tval[T_xn]) { + 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); + if (term_change_size(el, Val(T_li), Val(T_co)) == -1) + return (-1); + return (0); + } else { + long i; + char *ep; + + i = strtol(how, &ep, 10); + if (*ep != '\0') { + (void) fprintf(el->el_errfile, + "settc: Bad value `%s'.\n", how); + return (-1); + } + el->el_term.t_val[tv - tval] = (int) i; + 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]) + if (term_change_size(el, Val(T_li), Val(T_co)) + == -1) + return (-1); + return (0); + } + } + return (-1); +} + + +/* term_echotc(): + * Print the termcap string out with variable substitution + */ +protected int +/*ARGSUSED*/ +term_echotc(EditLine *el, int argc __attribute__((unused)), const char **argv) +{ + char *cap, *scap, *ep; + int arg_need, arg_cols, arg_rows; + int verbose = 0, silent = 0; + char *area; + static const char fmts[] = "%s\n", fmtd[] = "%d\n"; + const struct termcapstr *t; + char buf[TC_BUFSIZE]; + long i; + + 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); + } else if (strcmp(*argv, "xn") == 0) { + (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ? + "yes" : "no"); + return (0); + } else if (strcmp(*argv, "am") == 0) { + (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ? + "yes" : "no"); + return (0); + } 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; + i = strtol(*argv, &ep, 10); + if (*ep != '\0' || i < 0) { + if (!silent) + (void) fprintf(el->el_errfile, + "echotc: Bad value `%s' for rows.\n", + *argv); + return (-1); + } + arg_rows = (int) i; + 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); + } + i = strtol(*argv, &ep, 10); + if (*ep != '\0' || i < 0) { + if (!silent) + (void) fprintf(el->el_errfile, + "echotc: Bad value `%s' for cols.\n", + *argv); + return (-1); + } + arg_cols = (int) i; + argv++; + if (!*argv || *argv[0] == '\0') { + if (!silent) + (void) fprintf(el->el_errfile, + "echotc: Warning: Missing argument.\n"); + return (-1); + } + i = strtol(*argv, &ep, 10); + if (*ep != '\0' || i < 0) { + if (!silent) + (void) fprintf(el->el_errfile, + "echotc: Bad value `%s' for rows.\n", + *argv); + return (-1); + } + arg_rows = (int) i; + if (*ep != '\0') { + if (!silent) + (void) fprintf(el->el_errfile, + "echotc: Bad value `%s'.\n", *argv); + return (-1); + } + 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/cmd-line-utils/libedit/term.h b/cmd-line-utils/libedit/term.h new file mode 100644 index 00000000000..9f03c549515 --- /dev/null +++ b/cmd-line-utils/libedit/term.h @@ -0,0 +1,124 @@ +/* $NetBSD: term.h,v 1.12 2001/01/04 15:56:32 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. + * + * @(#)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 */ + const char *name; /* name of the key */ + int key; /* Index in termcap table */ + key_value_t fun; /* Function bound to it */ + int type; /* Type of function */ +} fkey_t; + +typedef struct { + coord_t t_size; /* # lines and cols */ + int t_flags; +#define TERM_CAN_INSERT 0x001 /* Has insert cap */ +#define TERM_CAN_DELETE 0x002 /* Has delete cap */ +#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */ +#define TERM_CAN_TAB 0x008 /* Can use tabs */ +#define TERM_CAN_ME 0x010 /* Can turn all attrs. */ +#define TERM_CAN_UP 0x020 /* Can move up */ +#define TERM_HAS_META 0x040 /* Has a meta key */ +#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ +#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ + 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_HO 4 +#define A_K_EN 5 +#define A_K_NKEYS 6 + +protected void term_move_to_line(EditLine *, int); +protected void term_move_to_char(EditLine *, int); +protected void term_clear_EOL(EditLine *, int); +protected void term_overwrite(EditLine *, const char *, int); +protected void term_insertwrite(EditLine *, char *, int); +protected void term_deletechars(EditLine *, int); +protected void term_clear_screen(EditLine *); +protected void term_beep(EditLine *); +protected int term_change_size(EditLine *, int, int); +protected int term_get_size(EditLine *, int *, int *); +protected int term_init(EditLine *); +protected void term_bind_arrow(EditLine *); +protected void term_print_arrow(EditLine *, const char *); +protected int term_clear_arrow(EditLine *, const char *); +protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); +protected void term_end(EditLine *); +protected int term_set(EditLine *, const char *); +protected int term_settc(EditLine *, int, const char **); +protected int term_telltc(EditLine *, int, const char **); +protected int term_echotc(EditLine *, int, const char **); +protected int term__putc(int); +protected void term__flush(void); + +/* + * 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) +#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) +#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) + +#endif /* _h_el_term */ diff --git a/cmd-line-utils/libedit/tokenizer.c b/cmd-line-utils/libedit/tokenizer.c new file mode 100644 index 00000000000..7a7e5b5ed75 --- /dev/null +++ b/cmd-line-utils/libedit/tokenizer.c @@ -0,0 +1,391 @@ +/* $NetBSD: tokenizer.c,v 1.7 2001/01/04 15:56:32 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. + */ + +#include "compat.h" + +/* + * 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 */ + const 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(Tokenizer *); + + +/* tok_finish(): + * Finish a word in the tokenizer. + */ +private void +tok_finish(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(const char *ifs) +{ + Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer)); + + tok->ifs = strdup(ifs ? ifs : IFS); + tok->argc = 0; + tok->amax = AINCR; + tok->argv = (const char **) tok_malloc(sizeof(char *) * tok->amax); + if (tok->argv == NULL) + return (NULL); + tok->argv[0] = NULL; + tok->wspace = (char *) tok_malloc(WINCR); + if (tok->wspace == NULL) + return (NULL); + 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(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(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(Tokenizer *tok, const char *line, int *argc, const char ***argv) +{ + const char *ptr; + + for (;;) { + 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: /* Exit double quote mode */ + tok->quote = Q_none; + 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: /* Quote next character */ + tok->quote = Q_doubleone; + break; + + case Q_one: /* Quote this, restore state */ + *tok->wptr++ = *ptr; + tok->quote = Q_none; + 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: /* Back to double, eat the '\n' */ + tok->flags |= TOK_EAT; + tok->quote = Q_double; + break; + + case Q_one: /* No quote, more eat the '\n' */ + tok->flags |= TOK_EAT; + tok->quote = Q_none; + 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 (s == NULL) + return (-1); + + 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) { + const char **p; + tok->amax += AINCR; + p = (const char **) tok_realloc(tok->argv, + tok->amax * sizeof(char *)); + if (p == NULL) + return (-1); + tok->argv = p; + } + } +} diff --git a/cmd-line-utils/libedit/tokenizer.h b/cmd-line-utils/libedit/tokenizer.h new file mode 100644 index 00000000000..14919fd3f84 --- /dev/null +++ b/cmd-line-utils/libedit/tokenizer.h @@ -0,0 +1,54 @@ +/* $NetBSD: tokenizer.h,v 1.4 2000/09/04 22:06:33 lukem Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tokenizer.h 8.1 (Berkeley) 6/4/93 + */ + +/* + * tokenizer.h: Header file for tokenizer routines + */ +#ifndef _h_tokenizer +#define _h_tokenizer + +typedef struct tokenizer Tokenizer; + +Tokenizer *tok_init(const char *); +void tok_reset(Tokenizer *); +void tok_end(Tokenizer *); +int tok_line(Tokenizer *, const char *, int *, const char ***); + +#endif /* _h_tokenizer */ diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c new file mode 100644 index 00000000000..2c7b502136d --- /dev/null +++ b/cmd-line-utils/libedit/tty.c @@ -0,0 +1,1177 @@ +/* $NetBSD: tty.c,v 1.15 2001/05/17 01:02:17 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. + */ + +#include "compat.h" + +/* + * tty.c: tty interface stuff + */ +#include "sys.h" +#include "tty.h" +#include "el.h" + +typedef struct ttymodes_t { + const 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 const 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 | INLCR | ICRNL}, + {"oflag:", 0, 0}, + {"cflag:", 0, 0}, + {"lflag:", 0, ISIG | IEXTEN}, + {"chars:", 0, 0}, + } +}; + +private const 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 const 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 const ttymodes_t ttymodes[] = { +#ifdef IGNBRK + {"ignbrk", IGNBRK, MD_INP}, +#endif /* IGNBRK */ +#ifdef BRKINT + {"brkint", BRKINT, MD_INP}, +#endif /* BRKINT */ +#ifdef IGNPAR + {"ignpar", IGNPAR, MD_INP}, +#endif /* IGNPAR */ +#ifdef PARMRK + {"parmrk", PARMRK, MD_INP}, +#endif /* PARMRK */ +#ifdef INPCK + {"inpck", INPCK, MD_INP}, +#endif /* INPCK */ +#ifdef ISTRIP + {"istrip", ISTRIP, MD_INP}, +#endif /* ISTRIP */ +#ifdef INLCR + {"inlcr", INLCR, MD_INP}, +#endif /* INLCR */ +#ifdef IGNCR + {"igncr", IGNCR, MD_INP}, +#endif /* IGNCR */ +#ifdef ICRNL + {"icrnl", ICRNL, MD_INP}, +#endif /* ICRNL */ +#ifdef IUCLC + {"iuclc", IUCLC, MD_INP}, +#endif /* IUCLC */ +#ifdef IXON + {"ixon", IXON, MD_INP}, +#endif /* IXON */ +#ifdef IXANY + {"ixany", IXANY, MD_INP}, +#endif /* IXANY */ +#ifdef IXOFF + {"ixoff", IXOFF, MD_INP}, +#endif /* IXOFF */ +#ifdef IMAXBEL + {"imaxbel", IMAXBEL, MD_INP}, +#endif /* IMAXBEL */ + +#ifdef OPOST + {"opost", OPOST, MD_OUT}, +#endif /* OPOST */ +#ifdef OLCUC + {"olcuc", OLCUC, MD_OUT}, +#endif /* OLCUC */ +#ifdef ONLCR + {"onlcr", ONLCR, MD_OUT}, +#endif /* ONLCR */ +#ifdef OCRNL + {"ocrnl", OCRNL, MD_OUT}, +#endif /* OCRNL */ +#ifdef ONOCR + {"onocr", ONOCR, MD_OUT}, +#endif /* ONOCR */ +#ifdef ONOEOT + {"onoeot", ONOEOT, MD_OUT}, +#endif /* ONOEOT */ +#ifdef ONLRET + {"onlret", ONLRET, MD_OUT}, +#endif /* ONLRET */ +#ifdef OFILL + {"ofill", OFILL, MD_OUT}, +#endif /* OFILL */ +#ifdef OFDEL + {"ofdel", OFDEL, MD_OUT}, +#endif /* OFDEL */ +#ifdef NLDLY + {"nldly", NLDLY, MD_OUT}, +#endif /* NLDLY */ +#ifdef CRDLY + {"crdly", CRDLY, MD_OUT}, +#endif /* CRDLY */ +#ifdef TABDLY + {"tabdly", TABDLY, MD_OUT}, +#endif /* TABDLY */ +#ifdef XTABS + {"xtabs", XTABS, MD_OUT}, +#endif /* XTABS */ +#ifdef BSDLY + {"bsdly", BSDLY, MD_OUT}, +#endif /* BSDLY */ +#ifdef VTDLY + {"vtdly", VTDLY, MD_OUT}, +#endif /* VTDLY */ +#ifdef FFDLY + {"ffdly", FFDLY, MD_OUT}, +#endif /* FFDLY */ +#ifdef PAGEOUT + {"pageout", PAGEOUT, MD_OUT}, +#endif /* PAGEOUT */ +#ifdef WRAP + {"wrap", WRAP, MD_OUT}, +#endif /* WRAP */ + +#ifdef CIGNORE + {"cignore", CIGNORE, MD_CTL}, +#endif /* CBAUD */ +#ifdef CBAUD + {"cbaud", CBAUD, MD_CTL}, +#endif /* CBAUD */ +#ifdef CSTOPB + {"cstopb", CSTOPB, MD_CTL}, +#endif /* CSTOPB */ +#ifdef CREAD + {"cread", CREAD, MD_CTL}, +#endif /* CREAD */ +#ifdef PARENB + {"parenb", PARENB, MD_CTL}, +#endif /* PARENB */ +#ifdef PARODD + {"parodd", PARODD, MD_CTL}, +#endif /* PARODD */ +#ifdef HUPCL + {"hupcl", HUPCL, MD_CTL}, +#endif /* HUPCL */ +#ifdef CLOCAL + {"clocal", CLOCAL, MD_CTL}, +#endif /* CLOCAL */ +#ifdef LOBLK + {"loblk", LOBLK, MD_CTL}, +#endif /* LOBLK */ +#ifdef CIBAUD + {"cibaud", CIBAUD, MD_CTL}, +#endif /* CIBAUD */ +#ifdef CRTSCTS +#ifdef CCTS_OFLOW + {"ccts_oflow", CCTS_OFLOW, MD_CTL}, +#else + {"crtscts", CRTSCTS, MD_CTL}, +#endif /* CCTS_OFLOW */ +#endif /* CRTSCTS */ +#ifdef CRTS_IFLOW + {"crts_iflow", CRTS_IFLOW, MD_CTL}, +#endif /* CRTS_IFLOW */ +#ifdef CDTRCTS + {"cdtrcts", CDTRCTS, MD_CTL}, +#endif /* CDTRCTS */ +#ifdef MDMBUF + {"mdmbuf", MDMBUF, MD_CTL}, +#endif /* MDMBUF */ +#ifdef RCV1EN + {"rcv1en", RCV1EN, MD_CTL}, +#endif /* RCV1EN */ +#ifdef XMT1EN + {"xmt1en", XMT1EN, MD_CTL}, +#endif /* XMT1EN */ + +#ifdef ISIG + {"isig", ISIG, MD_LIN}, +#endif /* ISIG */ +#ifdef ICANON + {"icanon", ICANON, MD_LIN}, +#endif /* ICANON */ +#ifdef XCASE + {"xcase", XCASE, MD_LIN}, +#endif /* XCASE */ +#ifdef ECHO + {"echo", ECHO, MD_LIN}, +#endif /* ECHO */ +#ifdef ECHOE + {"echoe", ECHOE, MD_LIN}, +#endif /* ECHOE */ +#ifdef ECHOK + {"echok", ECHOK, MD_LIN}, +#endif /* ECHOK */ +#ifdef ECHONL + {"echonl", ECHONL, MD_LIN}, +#endif /* ECHONL */ +#ifdef NOFLSH + {"noflsh", NOFLSH, MD_LIN}, +#endif /* NOFLSH */ +#ifdef TOSTOP + {"tostop", TOSTOP, MD_LIN}, +#endif /* TOSTOP */ +#ifdef ECHOCTL + {"echoctl", ECHOCTL, MD_LIN}, +#endif /* ECHOCTL */ +#ifdef ECHOPRT + {"echoprt", ECHOPRT, MD_LIN}, +#endif /* ECHOPRT */ +#ifdef ECHOKE + {"echoke", ECHOKE, MD_LIN}, +#endif /* ECHOKE */ +#ifdef DEFECHO + {"defecho", DEFECHO, MD_LIN}, +#endif /* DEFECHO */ +#ifdef FLUSHO + {"flusho", FLUSHO, MD_LIN}, +#endif /* FLUSHO */ +#ifdef PENDIN + {"pendin", PENDIN, MD_LIN}, +#endif /* PENDIN */ +#ifdef IEXTEN + {"iexten", IEXTEN, MD_LIN}, +#endif /* IEXTEN */ +#ifdef NOKERNINFO + {"nokerninfo", NOKERNINFO, MD_LIN}, +#endif /* NOKERNINFO */ +#ifdef ALTWERASE + {"altwerase", ALTWERASE, MD_LIN}, +#endif /* ALTWERASE */ +#ifdef EXTPROC + {"extproc", EXTPROC, MD_LIN}, +#endif /* EXTPROC */ + +#if defined(VINTR) + {"intr", C_SH(C_INTR), MD_CHAR}, +#endif /* VINTR */ +#if defined(VQUIT) + {"quit", C_SH(C_QUIT), MD_CHAR}, +#endif /* VQUIT */ +#if defined(VERASE) + {"erase", C_SH(C_ERASE), MD_CHAR}, +#endif /* VERASE */ +#if defined(VKILL) + {"kill", C_SH(C_KILL), MD_CHAR}, +#endif /* VKILL */ +#if defined(VEOF) + {"eof", C_SH(C_EOF), MD_CHAR}, +#endif /* VEOF */ +#if defined(VEOL) + {"eol", C_SH(C_EOL), MD_CHAR}, +#endif /* VEOL */ +#if defined(VEOL2) + {"eol2", C_SH(C_EOL2), MD_CHAR}, +#endif /* VEOL2 */ +#if defined(VSWTCH) + {"swtch", C_SH(C_SWTCH), MD_CHAR}, +#endif /* VSWTCH */ +#if defined(VDSWTCH) + {"dswtch", C_SH(C_DSWTCH), MD_CHAR}, +#endif /* VDSWTCH */ +#if defined(VERASE2) + {"erase2", C_SH(C_ERASE2), MD_CHAR}, +#endif /* VERASE2 */ +#if defined(VSTART) + {"start", C_SH(C_START), MD_CHAR}, +#endif /* VSTART */ +#if defined(VSTOP) + {"stop", C_SH(C_STOP), MD_CHAR}, +#endif /* VSTOP */ +#if defined(VWERASE) + {"werase", C_SH(C_WERASE), MD_CHAR}, +#endif /* VWERASE */ +#if defined(VSUSP) + {"susp", C_SH(C_SUSP), MD_CHAR}, +#endif /* VSUSP */ +#if defined(VDSUSP) + {"dsusp", C_SH(C_DSUSP), MD_CHAR}, +#endif /* VDSUSP */ +#if defined(VREPRINT) + {"reprint", C_SH(C_REPRINT), MD_CHAR}, +#endif /* VREPRINT */ +#if defined(VDISCARD) + {"discard", C_SH(C_DISCARD), MD_CHAR}, +#endif /* VDISCARD */ +#if defined(VLNEXT) + {"lnext", C_SH(C_LNEXT), MD_CHAR}, +#endif /* VLNEXT */ +#if defined(VSTATUS) + {"status", C_SH(C_STATUS), MD_CHAR}, +#endif /* VSTATUS */ +#if defined(VPAGE) + {"page", C_SH(C_PAGE), MD_CHAR}, +#endif /* VPAGE */ +#if defined(VPGOFF) + {"pgoff", C_SH(C_PGOFF), MD_CHAR}, +#endif /* VPGOFF */ +#if defined(VKILL2) + {"kill2", C_SH(C_KILL2), MD_CHAR}, +#endif /* VKILL2 */ +#if defined(VBRK) + {"brk", C_SH(C_BRK), MD_CHAR}, +#endif /* VBRK */ +#if defined(VMIN) + {"min", C_SH(C_MIN), MD_CHAR}, +#endif /* VMIN */ +#if defined(VTIME) + {"time", C_SH(C_TIME), MD_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(struct termios *, unsigned char *); +private void tty__setchar(struct termios *, unsigned char *); +private speed_t tty__getspeed(struct termios *); +private int tty_setup(EditLine *); + +#define t_qu t_ts + + +/* tty_setup(): + * Get the tty parameters and initialize the editing state + */ +private int +tty_setup(EditLine *el) +{ + int rst = 1; + + if (el->el_flags & EDIT_DISABLED) + return (0); + + 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][MD_INP].t_clrmask; + el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask; + + el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; + el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; + + el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; + el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; + + el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; + el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_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_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][MD_INP].t_clrmask; + el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask; + + el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; + el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; + + el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; + el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; + + el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; + el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; + + tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); + tty_bind_char(el, 1); + return (0); +} + +protected int +tty_init(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)); +} + + +/* tty_end(): + * Restore the tty to its original settings + */ +protected void +/*ARGSUSED*/ +tty_end(EditLine *el __attribute__((unused))) +{ + + /* XXX: Maybe reset to an initial state? */ +} + + +/* tty__getspeed(): + * Get the tty speed + */ +private speed_t +tty__getspeed(struct termios *td) +{ + speed_t spd; + + if ((spd = cfgetispeed(td)) == 0) + spd = cfgetospeed(td); + return (spd); +} + + +/* tty__getchar(): + * Get the tty characters + */ +private void +tty__getchar(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(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(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; + unsigned char new[2], old[2]; + const ttymap_t *tp; + el_action_t *map, *alt; + const el_action_t *dmap, *dalt; + 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, (char *)old); + map[old[0]] = dmap[old[0]]; + key_clear(el, map, (char *)new); + /* MAP_VI == 1, MAP_EMACS == 0... */ + map[new[0]] = tp->bind[el->el_map.type]; + if (dalt) { + key_clear(el, alt, (char *)old); + alt[old[0]] = dalt[old[0]]; + key_clear(el, alt, (char *)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(EditLine *el) +{ + + if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) + return (0); + + if (el->el_flags & EDIT_DISABLED) + 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][MD_CTL].t_clrmask; + el->el_tty.t_ex.c_cflag |= + el->el_tty.t_t[EX_IO][MD_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][MD_CTL].t_clrmask; + el->el_tty.t_ed.c_cflag |= + el->el_tty.t_t[ED_IO][MD_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][MD_LIN].t_clrmask; + el->el_tty.t_ex.c_lflag |= + el->el_tty.t_t[EX_IO][MD_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][MD_LIN].t_clrmask; + el->el_tty.t_ed.c_lflag |= + el->el_tty.t_t[ED_IO][MD_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][MD_INP].t_clrmask; + el->el_tty.t_ex.c_iflag |= + el->el_tty.t_t[EX_IO][MD_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][MD_INP].t_clrmask; + el->el_tty.t_ed.c_iflag |= + el->el_tty.t_t[ED_IO][MD_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][MD_OUT].t_clrmask; + el->el_tty.t_ex.c_oflag |= + el->el_tty.t_t[EX_IO][MD_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][MD_OUT].t_clrmask; + el->el_tty.t_ed.c_oflag |= + el->el_tty.t_t[ED_IO][MD_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][MD_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][MD_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][MD_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][MD_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); +} + + +/* tty_cookedmode(): + * Set the tty back to normal mode + */ +protected int +tty_cookedmode(EditLine *el) +{ /* set tty in normal setup */ + + if (el->el_tty.t_mode == EX_IO) + return (0); + + if (el->el_flags & EDIT_DISABLED) + 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); +} + + +/* tty_quotemode(): + * Turn on quote mode + */ +protected int +tty_quotemode(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][MD_INP].t_clrmask; + el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask; + + el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask; + el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask; + + el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask; + el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask; + + el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask; + el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_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); +} + + +/* tty_noquotemode(): + * Turn off quote mode + */ +protected int +tty_noquotemode(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(EditLine *el, int argc __attribute__((unused)), const char **argv) +{ + const ttymodes_t *m; + char x; + const char *d; + int aflag = 0; + const char *s; + const 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); +} + + +#ifdef notyet +/* tty_printchar(): + * DEbugging routine to print the tty characters + */ +private void +tty_printchar(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 == MD_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/cmd-line-utils/libedit/tty.h b/cmd-line-utils/libedit/tty.h new file mode 100644 index 00000000000..5fdcfadf0dc --- /dev/null +++ b/cmd-line-utils/libedit/tty.h @@ -0,0 +1,484 @@ +/* $NetBSD: tty.h,v 1.8 2000/09/04 22:06:33 lukem Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)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> +#include <unistd.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 MD_INP 0 +#define MD_OUT 1 +#define MD_CTL 2 +#define MD_LIN 3 +#define MD_CHAR 4 +#define MD_NN 5 + +typedef struct { + const char *t_name; + u_int t_setmask; + u_int t_clrmask; +} ttyperm_t[NN_IO][MD_NN]; + +typedef unsigned char ttychar_t[NN_IO][C_NCC]; + +protected int tty_init(EditLine *); +protected void tty_end(EditLine *); +protected int tty_stty(EditLine *, int, const char**); +protected int tty_rawmode(EditLine *); +protected int tty_cookedmode(EditLine *); +protected int tty_quotemode(EditLine *); +protected int tty_noquotemode(EditLine *); +protected void tty_bind_char(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/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c new file mode 100644 index 00000000000..296e11eb4d9 --- /dev/null +++ b/cmd-line-utils/libedit/vi.c @@ -0,0 +1,935 @@ +/* $NetBSD: vi.c,v 1.8 2000/09/04 22:06:33 lukem Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "compat.h" + +/* + * vi.c: Vi mode commands. + */ +#include "sys.h" +#include "el.h" + +private el_action_t cv_action(EditLine *, int); +private el_action_t cv_paste(EditLine *, int); + +/* cv_action(): + * Handle vi actions. + */ +private el_action_t +cv_action(EditLine *el, int c) +{ + 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 + */ +private el_action_t +cv_paste(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, (int) 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + if (el->el_line.cursor == el->el_line.buffer) + return (CC_ERROR); + + el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, + el->el_line.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(EditLine *el, int c __attribute__((unused))) +{ + + if (el->el_line.cursor == el->el_line.buffer) + return (CC_ERROR); + + el->el_line.cursor = cv_prev_word(el, el->el_line.cursor, + el->el_line.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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(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(EditLine *el, int c __attribute__((unused))) +{ + + /* + * 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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_line.cursor = el->el_line.buffer; + el->el_chared.c_vcmd.ins = el->el_line.cursor; + + el->el_chared.c_undo.ptr = el->el_line.cursor; + el->el_chared.c_undo.action = DELETE; + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_map.current = el->el_map.key; + el->el_state.inputmode = MODE_REPLACE; + el->el_chared.c_undo.action = CHANGE; + el->el_chared.c_undo.ptr = el->el_line.cursor; + el->el_chared.c_undo.isize = 0; + el->el_chared.c_undo.dsize = 0; + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + (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(EditLine *el, int c __attribute__((unused))) +{ + + (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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_map.current = el->el_map.key; + + el->el_chared.c_vcmd.ins = el->el_line.cursor; + el->el_chared.c_undo.ptr = el->el_line.cursor; + el->el_chared.c_undo.action = DELETE; + + return (CC_NORM); +} + + +/* vi_add(): + * Vi enter insert mode after the cursor + * [a] + */ +protected el_action_t +/*ARGSUSED*/ +vi_add(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + + el->el_map.current = el->el_map.key; + el->el_line.cursor = el->el_line.lastchar; + + /* Mark where insertion begins */ + el->el_chared.c_vcmd.ins = el->el_line.lastchar; + el->el_chared.c_undo.ptr = el->el_line.lastchar; + el->el_chared.c_undo.action = DELETE; + return (CC_CURSOR); +} + + +/* vi_delete_meta(): + * Vi delete prefix command + * [d] + */ +protected el_action_t +/*ARGSUSED*/ +vi_delete_meta(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + if (el->el_line.cursor == el->el_line.lastchar) + return (CC_ERROR); + + el->el_line.cursor = cv__endword(el->el_line.cursor, + el->el_line.lastchar, el->el_state.argument); + + 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(EditLine *el, int c __attribute__((unused))) +{ + + if (el->el_line.cursor == el->el_line.lastchar) + return (CC_ERROR); + + el->el_line.cursor = cv__endword(el->el_line.cursor, + el->el_line.lastchar, el->el_state.argument); + + 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(EditLine *el, int c __attribute__((unused))) +{ + 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, (int) un->isize); + (void) memcpy(un->ptr, un->buf, un->isize); + un->action = DELETE; + un->dsize = un->isize; + un->isize = 0; + break; + + case CHANGE: + if (un->isize == 0) + return (CC_NORM); + + el->el_line.cursor = un->ptr; + size = (int) (el->el_line.cursor - el->el_line.lastchar); + if (size < (int)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(EditLine *el, int c __attribute__((unused))) +{ + int size; + + /* [Esc] cancels pending action */ + el->el_chared.c_vcmd.ins = 0; + el->el_chared.c_vcmd.action = NOP; + el->el_chared.c_vcmd.pos = 0; + + el->el_state.doingarg = 0; + size = el->el_chared.c_undo.ptr - el->el_line.cursor; + if (size < 0) + size = -size; + if (el->el_chared.c_undo.action == (INSERT | DELETE) || + el->el_chared.c_undo.action == DELETE) + el->el_chared.c_undo.dsize = size; + else + el->el_chared.c_undo.isize = size; + + el->el_state.inputmode = MODE_INSERT; + el->el_map.current = el->el_map.alt; +#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(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(EditLine *el, int c __attribute__((unused))) +{ + + 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); +} + + +/* 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(EditLine *el, int c __attribute__((unused))) +{ + +#ifdef notyet + if (el->el_line.cursor == el->el_line.lastchar && + el->el_line.cursor == el->el_line.buffer) { +#endif + term_overwrite(el, STReof, 4); /* then do a EOF */ + term__flush(); + return (CC_EOF); +#ifdef notyet + } 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(EditLine *el, int c __attribute__((unused))) +{ + 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(EditLine *el, int c __attribute__((unused))) +{ + + return (cv_search(el, ED_SEARCH_PREV_HISTORY)); +} + + +/* vi_search_next(): + * Vi search history next + * [/] + */ +protected el_action_t +/*ARGSUSED*/ +vi_search_next(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + + 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(EditLine *el, int c __attribute__((unused))) +{ + char ch; + + if (el_getc(el, &ch) != 1) + return (ed_end_of_file(el, 0)); + + el->el_search.chadir = CHAR_FWD; + el->el_search.chacha = ch; + + return (cv_csearch_fwd(el, ch, el->el_state.argument, 0)); + +} + + +/* vi_prev_char(): + * Vi move to the character specified previous + * [F] + */ +protected el_action_t +/*ARGSUSED*/ +vi_prev_char(EditLine *el, int c __attribute__((unused))) +{ + char ch; + + if (el_getc(el, &ch) != 1) + return (ed_end_of_file(el, 0)); + + el->el_search.chadir = CHAR_BACK; + el->el_search.chacha = ch; + + return (cv_csearch_back(el, ch, el->el_state.argument, 0)); +} + + +/* vi_to_next_char(): + * Vi move up to the character specified next + * [t] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_next_char(EditLine *el, int c __attribute__((unused))) +{ + char ch; + + if (el_getc(el, &ch) != 1) + return (ed_end_of_file(el, 0)); + + return (cv_csearch_fwd(el, ch, el->el_state.argument, 1)); + +} + + +/* vi_to_prev_char(): + * Vi move up to the character specified previous + * [T] + */ +protected el_action_t +/*ARGSUSED*/ +vi_to_prev_char(EditLine *el, int c __attribute__((unused))) +{ + char ch; + + if (el_getc(el, &ch) != 1) + return (ed_end_of_file(el, 0)); + + return (cv_csearch_back(el, ch, el->el_state.argument, 1)); +} + + +/* vi_repeat_next_char(): + * Vi repeat current character search in the same search direction + * [;] + */ +protected el_action_t +/*ARGSUSED*/ +vi_repeat_next_char(EditLine *el, int c __attribute__((unused))) +{ + + if (el->el_search.chacha == 0) + return (CC_ERROR); + + return (el->el_search.chadir == CHAR_FWD + ? cv_csearch_fwd(el, el->el_search.chacha, + el->el_state.argument, 0) + : cv_csearch_back(el, el->el_search.chacha, + el->el_state.argument, 0)); +} + + +/* vi_repeat_prev_char(): + * Vi repeat current character search in the opposite search direction + * [,] + */ +protected el_action_t +/*ARGSUSED*/ +vi_repeat_prev_char(EditLine *el, int c __attribute__((unused))) +{ + + 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); +} diff --git a/cmd-line-utils/readline/.cvsignore b/cmd-line-utils/readline/.cvsignore new file mode 100644 index 00000000000..e9955884756 --- /dev/null +++ b/cmd-line-utils/readline/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/cmd-line-utils/readline/COPYING b/cmd-line-utils/readline/COPYING new file mode 100644 index 00000000000..1bf15263878 --- /dev/null +++ b/cmd-line-utils/readline/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/cmd-line-utils/readline/INSTALL b/cmd-line-utils/readline/INSTALL new file mode 100644 index 00000000000..adb27a9f222 --- /dev/null +++ b/cmd-line-utils/readline/INSTALL @@ -0,0 +1,273 @@ +Basic Installation +================== + +These are installation instructions for Readline-4.3. + +The simplest way to compile readline is: + + 1. `cd' to the directory containing the readline source code and type + `./configure' to configure readline for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes some time. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile readline and build the static readline + and history libraries. If supported, the shared readline and history + libraries will be built also. See below for instructions on compiling + the other parts of the distribution. Typing `make everything' will + cause the static and shared libraries (if supported) and the example + programs to be built. + + 3. Type `make install' to install the static readline and history + libraries, the readline include files, the documentation, and, if + supported, the shared readline and history libraries. + + 4. You can remove the created libraries and object files from the + build directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile readline for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the readline developers, and should be used with care. + +The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It +uses those values to create a `Makefile' in the build directory, +and Makefiles in the `doc', `shlib', and `examples' +subdirectories. It also creates a `config.h' file containing +system-dependent definitions. Finally, it creates a shell script +`config.status' that you can run in the future to recreate the +current configuration, a file `config.cache' that saves the +results of its tests to speed up reconfiguring, and a file +`config.log' containing compiler output (useful mainly for +debugging `configure'). + +If you need to do unusual things to compile readline, please try +to figure out how `configure' could check whether to do them, and +mail diffs or instructions to <bug-readline@gnu.org> so they can +be considered for the next release. If at some point +`config.cache' contains results you don't want to keep, you may +remove or edit it. + +The file `configure.in' is used to create `configure' by a +program called `autoconf'. You only need `configure.in' if you +want to change it or regenerate `configure' using a newer version +of `autoconf'. The readline `configure.in' requires autoconf +version 2.50 or newer. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + +You can compile readline for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + +If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile readline for one architecture at a +time in the source code directory. After you have installed +readline for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' will install the readline libraries in +`/usr/local/lib', the include files in +`/usr/local/include/readline', the man pages in `/usr/local/man', +and the info files in `/usr/local/info'. You can specify an +installation prefix other than `/usr/local' by giving `configure' +the option `--prefix=PATH' or by supplying a value for the +DESTDIR variable when running `make install'. + +You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. +If you give `configure' the option `--exec-prefix=PATH', the +readline Makefiles will use PATH as the prefix for installing the +libraries. Documentation and other data files will still use the +regular prefix. + +Specifying the System Type +========================== + +There may be some features `configure' can not figure out +automatically, but need to determine by the type of host readline +will run on. Usually `configure' can figure that out, but if it +prints a message saying it can not guess the host type, give it +the `--host=TYPE' option. TYPE can either be a short name for +the system type, such as `sun4', or a canonical name with three +fields: CPU-COMPANY-SYSTEM (e.g., i386-unknown-freebsd4.2). + +See the file `config.sub' for the possible values of each field. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: the readline `configure' looks for a site script, but not +all `configure' scripts do. + +Operation Controls +================== + +`configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + +Optional Features +================= + +The readline `configure' recognizes a single `--with-PACKAGE' option: + +`--with-curses' + This tells readline that it can find the termcap library functions + (tgetent, et al.) in the curses library, rather than a separate + termcap library. Readline uses the termcap functions, but does not + link with the termcap or curses library itself, allowing applications + which link with readline the to choose an appropriate library. + This option tells readline to link the example programs with the + curses library rather than libtermcap. + +`configure' also recognizes two `--enable-FEATURE' options: + +`--enable-shared' + Build the shared libraries by default on supported platforms. The + default is `yes'. + +`--enable-static' + Build the static libraries by default. The default is `yes'. + +Shared Libraries +================ + +There is support for building shared versions of the readline and +history libraries. The configure script creates a Makefile in +the `shlib' subdirectory, and typing `make shared' will cause +shared versions of the readline and history libraries to be built +on supported platforms. + +If `configure' is given the `--enable-shared' option, it will attempt +to build the shared libraries by default on supported platforms. + +Configure calls the script support/shobj-conf to test whether or +not shared library creation is supported and to generate the values +of variables that are substituted into shlib/Makefile. If you +try to build shared libraries on an unsupported platform, `make' +will display a message asking you to update support/shobj-conf for +your platform. + +If you need to update support/shobj-conf, you will need to create +a `stanza' for your operating system and compiler. The script uses +the value of host_os and ${CC} as determined by configure. For +instance, FreeBSD 4.2 with any version of gcc is identified as +`freebsd4.2-gcc*'. + +In the stanza for your operating system-compiler pair, you will need to +define several variables. They are: + +SHOBJ_CC The C compiler used to compile source files into shareable + object files. This is normally set to the value of ${CC} + by configure, and should not need to be changed. + +SHOBJ_CFLAGS Flags to pass to the C compiler ($SHOBJ_CC) to create + position-independent code. If you are using gcc, this + should probably be set to `-fpic'. + +SHOBJ_LD The link editor to be used to create the shared library from + the object files created by $SHOBJ_CC. If you are using + gcc, a value of `gcc' will probably work. + +SHOBJ_LDFLAGS Flags to pass to SHOBJ_LD to enable shared object creation. + If you are using gcc, `-shared' may be all that is necessary. + These should be the flags needed for generic shared object + creation. + +SHLIB_XLDFLAGS Additional flags to pass to SHOBJ_LD for shared library + creation. Many systems use the -R option to the link + editor to embed a path within the library for run-time + library searches. A reasonable value for such systems would + be `-R$(libdir)'. + +SHLIB_LIBS Any additional libraries that shared libraries should be + linked against when they are created. + +SHLIB_LIBSUFF The suffix to add to `libreadline' and `libhistory' when + generating the filename of the shared library. Many systems + use `so'; HP-UX uses `sl'. + +SHLIB_LIBVERSION The string to append to the filename to indicate the version + of the shared library. It should begin with $(SHLIB_LIBSUFF), + and possibly include version information that allows the + run-time loader to load the version of the shared library + appropriate for a particular program. Systems using shared + libraries similar to SunOS 4.x use major and minor library + version numbers; for those systems a value of + `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' is appropriate. + Systems based on System V Release 4 don't use minor version + numbers; use `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' on those systems. + Other Unix versions use different schemes. + +SHLIB_STATUS Set this to `supported' when you have defined the other + necessary variables. Make uses this to determine whether + or not shared library creation should be attempted. If + shared libraries are not supported, this will be set to + `unsupported'. + +You should look at the existing stanzas in support/shobj-conf for ideas. + +Once you have updated support/shobj-conf, re-run configure and type +`make shared' or `make'. The shared libraries will be created in the +shlib subdirectory. + +If shared libraries are created, `make install' will install them. +You may install only the shared libraries by running `make +install-shared' from the top-level build directory. Running `make +install' in the shlib subdirectory will also work. If you don't want +to install any created shared libraries, run `make install-static'. diff --git a/cmd-line-utils/readline/Makefile.am b/cmd-line-utils/readline/Makefile.am new file mode 100644 index 00000000000..7c4fe8eeb91 --- /dev/null +++ b/cmd-line-utils/readline/Makefile.am @@ -0,0 +1,35 @@ +## Process this file with automake to create Makefile.in +# Makefile for the GNU readline library. +# Copyright (C) 1994,1996,1997 Free Software Foundation, Inc. + +# Last -I$(top_srcdir) needed for RedHat! +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir) + +noinst_LIBRARIES = libreadline.a + +libreadline_a_SOURCES = readline.c funmap.c keymaps.c \ + vi_mode.c parens.c rltty.c \ + complete.c bind.c isearch.c \ + display.c signals.c \ + util.c kill.c \ + undo.c macro.c input.c \ + callback.c terminal.c xmalloc.c \ + history.c histsearch.c histexpand.c \ + histfile.c nls.c search.c \ + shell.c tilde.c misc.c text.c mbutil.c + +pkginclude_HEADERS = readline.h chardefs.h keymaps.h \ + history.h tilde.h rlmbutil.h rltypedefs.h rlprivate.h \ + rlshell.h xmalloc.h + +noinst_HEADERS = rldefs.h histlib.h rlwinsize.h \ + posixstat.h posixdir.h posixjmp.h \ + tilde.h rlconf.h rltty.h ansi_stdlib.h \ + tcap.h rlstdc.h + +EXTRA_DIST= emacs_keymap.c vi_keymap.c + +DEFS = -DUNDEF_THREADS_HACK -DHAVE_CONFIG_H -DNO_KILL_INTR + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/cmd-line-utils/readline/README b/cmd-line-utils/readline/README new file mode 100644 index 00000000000..7aa939452fb --- /dev/null +++ b/cmd-line-utils/readline/README @@ -0,0 +1,172 @@ +Introduction +============ + +This is the Gnu Readline library, version 4.3. + +The Readline library provides a set of functions for use by applications +that allow users to edit command lines as they are typed in. Both +Emacs and vi editing modes are available. The Readline library includes +additional functions to maintain a list of previously-entered command +lines, to recall and perhaps reedit those lines, and perform csh-like +history expansion on previous commands. + +The history facilites are also placed into a separate library, the +History library, as part of the build process. The History library +may be used without Readline in applications which desire its +capabilities. + +The Readline library is free software, distributed under the terms of +the [GNU] General Public License, version 2. For more information, see +the file COPYING. + +To build the library, try typing `./configure', then `make'. The +configuration process is automated, so no further intervention should +be necessary. Readline builds with `gcc' by default if it is +available. If you want to use `cc' instead, type + + CC=cc ./configure + +if you are using a Bourne-style shell. If you are not, the following +may work: + + env CC=cc ./configure + +Read the file INSTALL in this directory for more information about how +to customize and control the build process. + +The file rlconf.h contains C preprocessor defines that enable and disable +certain Readline features. + +The special make target `everything' will build the static and shared +libraries (if the target platform supports them) and the examples. + +Examples +======== + +There are several example programs that use Readline features in the +examples directory. The `rl' program is of particular interest. It +is a command-line interface to Readline, suitable for use in shell +scripts in place of `read'. + +Shared Libraries +================ + +There is skeletal support for building shared versions of the +Readline and History libraries. The configure script creates +a Makefile in the `shlib' subdirectory, and typing `make shared' +will cause shared versions of the Readline and History libraries +to be built on supported platforms. + +If `configure' is given the `--enable-shared' option, it will attempt +to build the shared libraries by default on supported platforms. + +Configure calls the script support/shobj-conf to test whether or +not shared library creation is supported and to generate the values +of variables that are substituted into shlib/Makefile. If you +try to build shared libraries on an unsupported platform, `make' +will display a message asking you to update support/shobj-conf for +your platform. + +If you need to update support/shobj-conf, you will need to create +a `stanza' for your operating system and compiler. The script uses +the value of host_os and ${CC} as determined by configure. For +instance, FreeBSD 4.2 with any version of gcc is identified as +`freebsd4.2-gcc*'. + +In the stanza for your operating system-compiler pair, you will need to +define several variables. They are: + +SHOBJ_CC The C compiler used to compile source files into shareable + object files. This is normally set to the value of ${CC} + by configure, and should not need to be changed. + +SHOBJ_CFLAGS Flags to pass to the C compiler ($SHOBJ_CC) to create + position-independent code. If you are using gcc, this + should probably be set to `-fpic'. + +SHOBJ_LD The link editor to be used to create the shared library from + the object files created by $SHOBJ_CC. If you are using + gcc, a value of `gcc' will probably work. + +SHOBJ_LDFLAGS Flags to pass to SHOBJ_LD to enable shared object creation. + If you are using gcc, `-shared' may be all that is necessary. + These should be the flags needed for generic shared object + creation. + +SHLIB_XLDFLAGS Additional flags to pass to SHOBJ_LD for shared library + creation. Many systems use the -R option to the link + editor to embed a path within the library for run-time + library searches. A reasonable value for such systems would + be `-R$(libdir)'. + +SHLIB_LIBS Any additional libraries that shared libraries should be + linked against when they are created. + +SHLIB_LIBSUFF The suffix to add to `libreadline' and `libhistory' when + generating the filename of the shared library. Many systems + use `so'; HP-UX uses `sl'. + +SHLIB_LIBVERSION The string to append to the filename to indicate the version + of the shared library. It should begin with $(SHLIB_LIBSUFF), + and possibly include version information that allows the + run-time loader to load the version of the shared library + appropriate for a particular program. Systems using shared + libraries similar to SunOS 4.x use major and minor library + version numbers; for those systems a value of + `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' is appropriate. + Systems based on System V Release 4 don't use minor version + numbers; use `$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' on those systems. + Other Unix versions use different schemes. + +SHLIB_STATUS Set this to `supported' when you have defined the other + necessary variables. Make uses this to determine whether + or not shared library creation should be attempted. + +You should look at the existing stanzas in support/shobj-conf for ideas. + +Once you have updated support/shobj-conf, re-run configure and type +`make shared'. The shared libraries will be created in the shlib +subdirectory. + +If shared libraries are created, `make install' will install them. +You may install only the shared libraries by running `make +install-shared' from the top-level build directory. Running `make +install' in the shlib subdirectory will also work. If you don't want +to install any created shared libraries, run `make install-static'. + +Documentation +============= + +The documentation for the Readline and History libraries appears in +the `doc' subdirectory. There are three texinfo files and a +Unix-style manual page describing the facilities available in the +Readline library. The texinfo files include both user and +programmer's manuals. HTML versions of the manuals appear in the +`doc' subdirectory as well. + +Reporting Bugs +============== + +Bug reports for Readline should be sent to: + + bug-readline@gnu.org + +When reporting a bug, please include the following information: + + * the version number and release status of Readline (e.g., 4.2-release) + * the machine and OS that it is running on + * a list of the compilation flags or the contents of `config.h', if + appropriate + * a description of the bug + * a recipe for recreating the bug reliably + * a fix for the bug if you have one! + +If you would like to contact the Readline maintainer directly, send mail +to bash-maintainers@gnu.org. + +Since Readline is developed along with bash, the bug-bash@gnu.org mailing +list (mirrored to the Usenet newsgroup gnu.bash.bug) often contains +Readline bug reports and fixes. + +Chet Ramey +chet@po.cwru.edu diff --git a/cmd-line-utils/readline/ansi_stdlib.h b/cmd-line-utils/readline/ansi_stdlib.h new file mode 100644 index 00000000000..db13cd234bd --- /dev/null +++ b/cmd-line-utils/readline/ansi_stdlib.h @@ -0,0 +1,54 @@ +/* ansi_stdlib.h -- An ANSI Standard stdlib.h. */ +/* A minimal stdlib.h containing extern declarations for those functions + that bash uses. */ + +/* Copyright (C) 1993 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_STDLIB_H_) +#define _STDLIB_H_ 1 + +/* String conversion functions. */ +extern int atoi (); + +extern double atof (); +extern double strtod (); + +/* Memory allocation functions. */ +/* Generic pointer type. */ +#ifndef PTR_T + +#if defined (__STDC__) +# define PTR_T void * +#else +# define PTR_T char * +#endif + +#endif /* PTR_T */ + +extern PTR_T malloc (); +extern PTR_T realloc (); +extern void free (); + +/* Other miscellaneous functions. */ +extern void abort (); +extern void exit (); +extern char *getenv (); +extern void qsort (); + +#endif /* _STDLIB_H */ diff --git a/cmd-line-utils/readline/bind.c b/cmd-line-utils/readline/bind.c new file mode 100644 index 00000000000..7e8ca04e0d6 --- /dev/null +++ b/cmd-line-utils/readline/bind.c @@ -0,0 +1,2151 @@ +/* bind.c -- key binding and startup file support for the readline library. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#if defined (HAVE_SYS_FILE_H) +# include <sys/file.h> +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <errno.h> + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +/* Variables exported by this file. */ +Keymap rl_binding_keymap; + +static char *_rl_read_file PARAMS((char *, size_t *)); +static void _rl_init_file_error PARAMS((const char *)); +static int _rl_read_init_file PARAMS((const char *, int)); +static int glean_key_from_name PARAMS((char *)); +static int substring_member_of_array PARAMS((char *, const char **)); + +static int currently_reading_init_file; + +/* used only in this file */ +static int _rl_prefer_visible_bell = 1; + +/* **************************************************************** */ +/* */ +/* Binding keys */ +/* */ +/* **************************************************************** */ + +/* rl_add_defun (char *name, rl_command_func_t *function, int key) + Add NAME to the list of named functions. Make FUNCTION be the function + that gets called. If KEY is not -1, then bind it. */ +int +rl_add_defun (name, function, key) + const char *name; + rl_command_func_t *function; + int key; +{ + if (key != -1) + rl_bind_key (key, function); + rl_add_funmap_entry (name, function); + return 0; +} + +/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */ +int +rl_bind_key (key, function) + int key; + rl_command_func_t *function; +{ + if (key < 0) + return (key); + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (_rl_keymap[ESC].type == ISKMAP) + { + Keymap escmap; + + escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); + key = UNMETA (key); + escmap[key].type = ISFUNC; + escmap[key].function = function; + return (0); + } + return (key); + } + + _rl_keymap[key].type = ISFUNC; + _rl_keymap[key].function = function; + rl_binding_keymap = _rl_keymap; + return (0); +} + +/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid + KEY. */ +int +rl_bind_key_in_map (key, function, map) + int key; + rl_command_func_t *function; + Keymap map; +{ + int result; + Keymap oldmap; + + oldmap = _rl_keymap; + _rl_keymap = map; + result = rl_bind_key (key, function); + _rl_keymap = oldmap; + return (result); +} + +/* Make KEY do nothing in the currently selected keymap. + Returns non-zero in case of error. */ +int +rl_unbind_key (key) + int key; +{ + return (rl_bind_key (key, (rl_command_func_t *)NULL)); +} + +/* Make KEY do nothing in MAP. + Returns non-zero in case of error. */ +int +rl_unbind_key_in_map (key, map) + int key; + Keymap map; +{ + return (rl_bind_key_in_map (key, (rl_command_func_t *)NULL, map)); +} + +/* Unbind all keys bound to FUNCTION in MAP. */ +int +rl_unbind_function_in_map (func, map) + rl_command_func_t *func; + Keymap map; +{ + register int i, rval; + + for (i = rval = 0; i < KEYMAP_SIZE; i++) + { + if (map[i].type == ISFUNC && map[i].function == func) + { + map[i].function = (rl_command_func_t *)NULL; + rval = 1; + } + } + return rval; +} + +int +rl_unbind_command_in_map (command, map) + const char *command; + Keymap map; +{ + rl_command_func_t *func; + + func = rl_named_function (command); + if (func == 0) + return 0; + return (rl_unbind_function_in_map (func, map)); +} + +/* Bind the key sequence represented by the string KEYSEQ to + FUNCTION. This makes new keymaps as necessary. The initial + place to do bindings is in MAP. */ +int +rl_set_key (keyseq, function, map) + const char *keyseq; + rl_command_func_t *function; + Keymap map; +{ + return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map)); +} + +/* Bind the key sequence represented by the string KEYSEQ to + the string of characters MACRO. This makes new keymaps as + necessary. The initial place to do bindings is in MAP. */ +int +rl_macro_bind (keyseq, macro, map) + const char *keyseq, *macro; + Keymap map; +{ + char *macro_keys; + int macro_keys_len; + + macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); + + if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) + { + free (macro_keys); + return -1; + } + rl_generic_bind (ISMACR, keyseq, macro_keys, map); + return 0; +} + +/* Bind the key sequence represented by the string KEYSEQ to + the arbitrary pointer DATA. TYPE says what kind of data is + pointed to by DATA, right now this can be a function (ISFUNC), + a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps + as necessary. The initial place to do bindings is in MAP. */ +int +rl_generic_bind (type, keyseq, data, map) + int type; + const char *keyseq; + char *data; + Keymap map; +{ + char *keys; + int keys_len; + register int i; + KEYMAP_ENTRY k; + + k.function = 0; + + /* If no keys to bind to, exit right away. */ + if (!keyseq || !*keyseq) + { + if (type == ISMACR) + free (data); + return -1; + } + + keys = (char *)xmalloc (1 + (2 * strlen (keyseq))); + + /* Translate the ASCII representation of KEYSEQ into an array of + characters. Stuff the characters into KEYS, and the length of + KEYS into KEYS_LEN. */ + if (rl_translate_keyseq (keyseq, keys, &keys_len)) + { + free (keys); + return -1; + } + + /* Bind keys, making new keymaps as necessary. */ + for (i = 0; i < keys_len; i++) + { + unsigned char uc = keys[i]; + int ic; + + ic = uc; + if (ic < 0 || ic >= KEYMAP_SIZE) + return -1; + + if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic)) + { + ic = UNMETA (ic); + if (map[ESC].type == ISKMAP) + map = FUNCTION_TO_KEYMAP (map, ESC); + } + + if ((i + 1) < keys_len) + { + if (map[ic].type != ISKMAP) + { + /* We allow subsequences of keys. If a keymap is being + created that will `shadow' an existing function or macro + key binding, we save that keybinding into the ANYOTHERKEY + index in the new map. The dispatch code will look there + to find the function to execute if the subsequence is not + matched. ANYOTHERKEY was chosen to be greater than + UCHAR_MAX. */ + k = map[ic]; + + map[ic].type = ISKMAP; + map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); + } + map = FUNCTION_TO_KEYMAP (map, ic); + /* The dispatch code will return this function if no matching + key sequence is found in the keymap. This (with a little + help from the dispatch code in readline.c) allows `a' to be + mapped to something, `abc' to be mapped to something else, + and the function bound to `a' to be executed when the user + types `abx', leaving `bx' in the input queue. */ + if (k.function /* && k.type == ISFUNC */) + { + map[ANYOTHERKEY] = k; + k.function = 0; + } + } + else + { + if (map[ic].type == ISMACR) + free ((char *)map[ic].function); + else if (map[ic].type == ISKMAP) + { + map = FUNCTION_TO_KEYMAP (map, ic); + ic = ANYOTHERKEY; + } + + map[ic].function = KEYMAP_TO_FUNCTION (data); + map[ic].type = type; + } + + rl_binding_keymap = map; + } + free (keys); + return 0; +} + +/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY, + an array of characters. LEN gets the final length of ARRAY. Return + non-zero if there was an error parsing SEQ. */ +int +rl_translate_keyseq (seq, array, len) + const char *seq; + char *array; + int *len; +{ + register int i, c, l, temp; + + for (i = l = 0; (c = seq[i]); i++) + { + if (c == '\\') + { + c = seq[++i]; + + if (c == 0) + break; + + /* Handle \C- and \M- prefixes. */ + if ((c == 'C' || c == 'M') && seq[i + 1] == '-') + { + /* Handle special case of backwards define. */ + if (strncmp (&seq[i], "C-\\M-", 5) == 0) + { + array[l++] = ESC; /* ESC is meta-prefix */ + i += 5; + array[l++] = CTRL (_rl_to_upper (seq[i])); + if (seq[i] == '\0') + i--; + } + else if (c == 'M') + { + i++; + array[l++] = ESC; /* ESC is meta-prefix */ + } + else if (c == 'C') + { + i += 2; + /* Special hack for C-?... */ + array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); + } + continue; + } + + /* Translate other backslash-escaped characters. These are the + same escape sequences that bash's `echo' and `printf' builtins + handle, with the addition of \d -> RUBOUT. A backslash + preceding a character that is not special is stripped. */ + switch (c) + { + case 'a': + array[l++] = '\007'; + break; + case 'b': + array[l++] = '\b'; + break; + case 'd': + array[l++] = RUBOUT; /* readline-specific */ + break; + case 'e': + array[l++] = ESC; + break; + case 'f': + array[l++] = '\f'; + break; + case 'n': + array[l++] = NEWLINE; + break; + case 'r': + array[l++] = RETURN; + break; + case 't': + array[l++] = TAB; + break; + case 'v': + array[l++] = 0x0B; + break; + case '\\': + array[l++] = '\\'; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + i++; + for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++) + c = (c * 8) + OCTVALUE (seq[i]); + i--; /* auto-increment in for loop */ + array[l++] = c & largest_char; + break; + case 'x': + i++; + for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++) + c = (c * 16) + HEXVALUE (seq[i]); + if (temp == 2) + c = 'x'; + i--; /* auto-increment in for loop */ + array[l++] = c & largest_char; + break; + default: /* backslashes before non-special chars just add the char */ + array[l++] = c; + break; /* the backslash is stripped */ + } + continue; + } + + array[l++] = c; + } + + *len = l; + array[l] = '\0'; + return (0); +} + +char * +rl_untranslate_keyseq (seq) + int seq; +{ + static char kseq[16]; + int i, c; + + i = 0; + c = seq; + if (META_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'M'; + kseq[i++] = '-'; + c = UNMETA (c); + } + else if (CTRL_CHAR (c)) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + else if (c == RUBOUT) + { + kseq[i++] = '\\'; + kseq[i++] = 'C'; + kseq[i++] = '-'; + c = '?'; + } + + if (c == ESC) + { + kseq[i++] = '\\'; + c = 'e'; + } + else if (c == '\\' || c == '"') + { + kseq[i++] = '\\'; + } + + kseq[i++] = (unsigned char) c; + kseq[i] = '\0'; + return kseq; +} + +static char * +_rl_untranslate_macro_value (seq) + char *seq; +{ + char *ret, *r, *s; + int c; + + r = ret = (char *)xmalloc (7 * strlen (seq) + 1); + for (s = seq; *s; s++) + { + c = *s; + if (META_CHAR (c)) + { + *r++ = '\\'; + *r++ = 'M'; + *r++ = '-'; + c = UNMETA (c); + } + else if (CTRL_CHAR (c) && c != ESC) + { + *r++ = '\\'; + *r++ = 'C'; + *r++ = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + else if (c == RUBOUT) + { + *r++ = '\\'; + *r++ = 'C'; + *r++ = '-'; + c = '?'; + } + + if (c == ESC) + { + *r++ = '\\'; + c = 'e'; + } + else if (c == '\\' || c == '"') + *r++ = '\\'; + + *r++ = (unsigned char)c; + } + *r = '\0'; + return ret; +} + +/* Return a pointer to the function that STRING represents. + If STRING doesn't have a matching function, then a NULL pointer + is returned. */ +rl_command_func_t * +rl_named_function (string) + const char *string; +{ + register int i; + + rl_initialize_funmap (); + + for (i = 0; funmap[i]; i++) + if (_rl_stricmp (funmap[i]->name, string) == 0) + return (funmap[i]->function); + return ((rl_command_func_t *)NULL); +} + +/* Return the function (or macro) definition which would be invoked via + KEYSEQ if executed in MAP. If MAP is NULL, then the current keymap is + used. TYPE, if non-NULL, is a pointer to an int which will receive the + type of the object pointed to. One of ISFUNC (function), ISKMAP (keymap), + or ISMACR (macro). */ +rl_command_func_t * +rl_function_of_keyseq (keyseq, map, type) + const char *keyseq; + Keymap map; + int *type; +{ + register int i; + + if (!map) + map = _rl_keymap; + + for (i = 0; keyseq && keyseq[i]; i++) + { + unsigned char ic = keyseq[i]; + + if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type != ISKMAP) + { + if (type) + *type = map[ESC].type; + + return (map[ESC].function); + } + else + { + map = FUNCTION_TO_KEYMAP (map, ESC); + ic = UNMETA (ic); + } + } + + if (map[ic].type == ISKMAP) + { + /* If this is the last key in the key sequence, return the + map. */ + if (!keyseq[i + 1]) + { + if (type) + *type = ISKMAP; + + return (map[ic].function); + } + else + map = FUNCTION_TO_KEYMAP (map, ic); + } + else + { + if (type) + *type = map[ic].type; + + return (map[ic].function); + } + } + return ((rl_command_func_t *) NULL); +} + +/* The last key bindings file read. */ +static char *last_readline_init_file = (char *)NULL; + +/* The file we're currently reading key bindings from. */ +static const char *current_readline_init_file; +static int current_readline_init_include_level; +static int current_readline_init_lineno; + +/* Read FILENAME into a locally-allocated buffer and return the buffer. + The size of the buffer is returned in *SIZEP. Returns NULL if any + errors were encountered. */ +static char * +_rl_read_file (filename, sizep) + char *filename; + size_t *sizep; +{ + struct stat finfo; + size_t file_size; + char *buffer; + int i, file; + + if ((stat (filename, &finfo) < 0) || (file = open (filename, O_RDONLY, 0666)) < 0) + return ((char *)NULL); + + file_size = (size_t)finfo.st_size; + + /* check for overflow on very large files */ + if (file_size != finfo.st_size || file_size + 1 < file_size) + { + if (file >= 0) + close (file); +#if defined (EFBIG) + errno = EFBIG; +#endif + return ((char *)NULL); + } + + /* Read the file into BUFFER. */ + buffer = (char *)xmalloc (file_size + 1); + i = read (file, buffer, file_size); + close (file); + + if (i < 0) + { + free (buffer); + return ((char *)NULL); + } + + buffer[i] = '\0'; + if (sizep) + *sizep = i; + + return (buffer); +} + +/* Re-read the current keybindings file. */ +int +rl_re_read_init_file (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + int r; + r = rl_read_init_file ((const char *)NULL); + rl_set_keymap_from_edit_mode (); + return r; +} + +/* Do key bindings from a file. If FILENAME is NULL it defaults + to the first non-null filename from this list: + 1. the filename used for the previous call + 2. the value of the shell variable `INPUTRC' + 3. ~/.inputrc + If the file existed and could be opened and read, 0 is returned, + otherwise errno is returned. */ +int +rl_read_init_file (filename) + const char *filename; +{ + /* Default the filename. */ + if (filename == 0) + { + filename = last_readline_init_file; + if (filename == 0) + filename = sh_get_env_value ("INPUTRC"); + if (filename == 0) + filename = DEFAULT_INPUTRC; + } + + if (*filename == 0) + filename = DEFAULT_INPUTRC; + +#if defined (__MSDOS__) + if (_rl_read_init_file (filename, 0) == 0) + return 0; + filename = "~/_inputrc"; +#endif + return (_rl_read_init_file (filename, 0)); +} + +static int +_rl_read_init_file (filename, include_level) + const char *filename; + int include_level; +{ + register int i; + char *buffer, *openname, *line, *end; + size_t file_size; + + current_readline_init_file = filename; + current_readline_init_include_level = include_level; + + openname = tilde_expand (filename); + buffer = _rl_read_file (openname, &file_size); + free (openname); + + if (buffer == 0) + return (errno); + + if (include_level == 0 && filename != last_readline_init_file) + { + FREE (last_readline_init_file); + last_readline_init_file = savestring (filename); + } + + currently_reading_init_file = 1; + + /* Loop over the lines in the file. Lines that start with `#' are + comments; all other lines are commands for readline initialization. */ + current_readline_init_lineno = 1; + line = buffer; + end = buffer + file_size; + while (line < end) + { + /* Find the end of this line. */ + for (i = 0; line + i != end && line[i] != '\n'; i++); + +#if defined (__CYGWIN__) + /* ``Be liberal in what you accept.'' */ + if (line[i] == '\n' && line[i-1] == '\r') + line[i - 1] = '\0'; +#endif + + /* Mark end of line. */ + line[i] = '\0'; + + /* Skip leading whitespace. */ + while (*line && whitespace (*line)) + { + line++; + i--; + } + + /* If the line is not a comment, then parse it. */ + if (*line && *line != '#') + rl_parse_and_bind (line); + + /* Move to the next line. */ + line += i + 1; + current_readline_init_lineno++; + } + + free (buffer); + currently_reading_init_file = 0; + return (0); +} + +static void +_rl_init_file_error (msg) + const char *msg; +{ + if (currently_reading_init_file) + fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file, + current_readline_init_lineno, msg); + else + fprintf (stderr, "readline: %s\n", msg); +} + +/* **************************************************************** */ +/* */ +/* Parser Directives */ +/* */ +/* **************************************************************** */ + +typedef int _rl_parser_func_t PARAMS((char *)); + +/* Things that mean `Control'. */ +const char *_rl_possible_control_prefixes[] = { + "Control-", "C-", "CTRL-", (const char *)NULL +}; + +const char *_rl_possible_meta_prefixes[] = { + "Meta", "M-", (const char *)NULL +}; + +/* Conditionals. */ + +/* Calling programs set this to have their argv[0]. */ +const char *rl_readline_name = "other"; + +/* Stack of previous values of parsing_conditionalized_out. */ +static unsigned char *if_stack = (unsigned char *)NULL; +static int if_stack_depth; +static int if_stack_size; + +/* Push _rl_parsing_conditionalized_out, and set parser state based + on ARGS. */ +static int +parser_if (args) + char *args; +{ + register int i; + + /* Push parser state. */ + if (if_stack_depth + 1 >= if_stack_size) + { + if (!if_stack) + if_stack = (unsigned char *)xmalloc (if_stack_size = 20); + else + if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20); + } + if_stack[if_stack_depth++] = _rl_parsing_conditionalized_out; + + /* If parsing is turned off, then nothing can turn it back on except + for finding the matching endif. In that case, return right now. */ + if (_rl_parsing_conditionalized_out) + return 0; + + /* Isolate first argument. */ + for (i = 0; args[i] && !whitespace (args[i]); i++); + + if (args[i]) + args[i++] = '\0'; + + /* Handle "$if term=foo" and "$if mode=emacs" constructs. If this + isn't term=foo, or mode=emacs, then check to see if the first + word in ARGS is the same as the value stored in rl_readline_name. */ + if (rl_terminal_name && _rl_strnicmp (args, "term=", 5) == 0) + { + char *tem, *tname; + + /* Terminals like "aaa-60" are equivalent to "aaa". */ + tname = savestring (rl_terminal_name); + tem = strchr (tname, '-'); + if (tem) + *tem = '\0'; + + /* Test the `long' and `short' forms of the terminal name so that + if someone has a `sun-cmd' and does not want to have bindings + that will be executed if the terminal is a `sun', they can put + `$if term=sun-cmd' into their .inputrc. */ + _rl_parsing_conditionalized_out = _rl_stricmp (args + 5, tname) && + _rl_stricmp (args + 5, rl_terminal_name); + free (tname); + } +#if defined (VI_MODE) + else if (_rl_strnicmp (args, "mode=", 5) == 0) + { + int mode; + + if (_rl_stricmp (args + 5, "emacs") == 0) + mode = emacs_mode; + else if (_rl_stricmp (args + 5, "vi") == 0) + mode = vi_mode; + else + mode = no_mode; + + _rl_parsing_conditionalized_out = mode != rl_editing_mode; + } +#endif /* VI_MODE */ + /* Check to see if the first word in ARGS is the same as the + value stored in rl_readline_name. */ + else if (_rl_stricmp (args, rl_readline_name) == 0) + _rl_parsing_conditionalized_out = 0; + else + _rl_parsing_conditionalized_out = 1; + return 0; +} + +/* Invert the current parser state if there is anything on the stack. */ +static int +parser_else (args) + char *args __attribute__((unused)); +{ + register int i; + + if (if_stack_depth == 0) + { + _rl_init_file_error ("$else found without matching $if"); + return 0; + } + + /* Check the previous (n - 1) levels of the stack to make sure that + we haven't previously turned off parsing. */ + for (i = 0; i < if_stack_depth - 1; i++) + if (if_stack[i] == 1) + return 0; + + /* Invert the state of parsing if at top level. */ + _rl_parsing_conditionalized_out = !_rl_parsing_conditionalized_out; + return 0; +} + +/* Terminate a conditional, popping the value of + _rl_parsing_conditionalized_out from the stack. */ +static int +parser_endif (args) + char *args __attribute__((unused)); +{ + if (if_stack_depth) + _rl_parsing_conditionalized_out = if_stack[--if_stack_depth]; + else + _rl_init_file_error ("$endif without matching $if"); + return 0; +} + +static int +parser_include (args) + char *args; +{ + const char *old_init_file; + char *e; + int old_line_number, old_include_level, r; + + if (_rl_parsing_conditionalized_out) + return (0); + + old_init_file = current_readline_init_file; + old_line_number = current_readline_init_lineno; + old_include_level = current_readline_init_include_level; + + e = strchr (args, '\n'); + if (e) + *e = '\0'; + r = _rl_read_init_file ((const char *)args, old_include_level + 1); + + current_readline_init_file = old_init_file; + current_readline_init_lineno = old_line_number; + current_readline_init_include_level = old_include_level; + + return r; +} + +/* Associate textual names with actual functions. */ +static struct { + const char *name; + _rl_parser_func_t *function; +} parser_directives [] = { + { "if", parser_if }, + { "endif", parser_endif }, + { "else", parser_else }, + { "include", parser_include }, + { (char *)0x0, (_rl_parser_func_t *)0x0 } +}; + +/* Handle a parser directive. STATEMENT is the line of the directive + without any leading `$'. */ +static int +handle_parser_directive (statement) + char *statement; +{ + register int i; + char *directive, *args; + + /* Isolate the actual directive. */ + + /* Skip whitespace. */ + for (i = 0; whitespace (statement[i]); i++); + + directive = &statement[i]; + + for (; statement[i] && !whitespace (statement[i]); i++); + + if (statement[i]) + statement[i++] = '\0'; + + for (; statement[i] && whitespace (statement[i]); i++); + + args = &statement[i]; + + /* Lookup the command, and act on it. */ + for (i = 0; parser_directives[i].name; i++) + if (_rl_stricmp (directive, parser_directives[i].name) == 0) + { + (*parser_directives[i].function) (args); + return (0); + } + + /* display an error message about the unknown parser directive */ + _rl_init_file_error ("unknown parser directive"); + return (1); +} + +/* Read the binding command from STRING and perform it. + A key binding command looks like: Keyname: function-name\0, + a variable binding command looks like: set variable value. + A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */ +int +rl_parse_and_bind (string) + char *string; +{ + char *funname, *kname; + register int c, i; + int key, equivalency; + + while (string && whitespace (*string)) + string++; + + if (!string || !*string || *string == '#') + return 0; + + /* If this is a parser directive, act on it. */ + if (*string == '$') + { + handle_parser_directive (&string[1]); + return 0; + } + + /* If we aren't supposed to be parsing right now, then we're done. */ + if (_rl_parsing_conditionalized_out) + return 0; + + i = 0; + /* If this keyname is a complex key expression surrounded by quotes, + advance to after the matching close quote. This code allows the + backslash to quote characters in the key expression. */ + if (*string == '"') + { + int passc = 0; + + for (i = 1; (c = string[i]); i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc++; + continue; + } + + if (c == '"') + break; + } + /* If we didn't find a closing quote, abort the line. */ + if (string[i] == '\0') + { + _rl_init_file_error ("no closing `\"' in key binding"); + return 1; + } + } + + /* Advance to the colon (:) or whitespace which separates the two objects. */ + for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ ); + + equivalency = (c == ':' && string[i + 1] == '='); + + /* Mark the end of the command (or keyname). */ + if (string[i]) + string[i++] = '\0'; + + /* If doing assignment, skip the '=' sign as well. */ + if (equivalency) + string[i++] = '\0'; + + /* If this is a command to set a variable, then do that. */ + if (_rl_stricmp (string, "set") == 0) + { + char *var = string + i; + char *value; + + /* Make VAR point to start of variable name. */ + while (*var && whitespace (*var)) var++; + + /* Make VALUE point to start of value string. */ + value = var; + while (*value && !whitespace (*value)) value++; + if (*value) + *value++ = '\0'; + while (*value && whitespace (*value)) value++; + + rl_variable_bind (var, value); + return 0; + } + + /* Skip any whitespace between keyname and funname. */ + for (; string[i] && whitespace (string[i]); i++); + funname = &string[i]; + + /* Now isolate funname. + For straight function names just look for whitespace, since + that will signify the end of the string. But this could be a + macro definition. In that case, the string is quoted, so skip + to the matching delimiter. We allow the backslash to quote the + delimiter characters in the macro body. */ + /* This code exists to allow whitespace in macro expansions, which + would otherwise be gobbled up by the next `for' loop.*/ + /* XXX - it may be desirable to allow backslash quoting only if " is + the quoted string delimiter, like the shell. */ + if (*funname == '\'' || *funname == '"') + { + int delimiter = string[i++], passc; + + for (passc = 0; (c = string[i]); i++) + { + if (passc) + { + passc = 0; + continue; + } + + if (c == '\\') + { + passc = 1; + continue; + } + + if (c == delimiter) + break; + } + if (c) + i++; + } + + /* Advance to the end of the string. */ + for (; string[i] && !whitespace (string[i]); i++); + + /* No extra whitespace at the end of the string. */ + string[i] = '\0'; + + /* Handle equivalency bindings here. Make the left-hand side be exactly + whatever the right-hand evaluates to, including keymaps. */ + if (equivalency) + { + return 0; + } + + /* If this is a new-style key-binding, then do the binding with + rl_set_key (). Otherwise, let the older code deal with it. */ + if (*string == '"') + { + char *seq; + register int j, k, passc; + + seq = (char *)xmalloc (1 + strlen (string)); + for (j = 1, k = passc = 0; string[j]; j++) + { + /* Allow backslash to quote characters, but leave them in place. + This allows a string to end with a backslash quoting another + backslash, or with a backslash quoting a double quote. The + backslashes are left in place for rl_translate_keyseq (). */ + if (passc || (string[j] == '\\')) + { + seq[k++] = string[j]; + passc = !passc; + continue; + } + + if (string[j] == '"') + break; + + seq[k++] = string[j]; + } + seq[k] = '\0'; + + /* Binding macro? */ + if (*funname == '\'' || *funname == '"') + { + j = strlen (funname); + + /* Remove the delimiting quotes from each end of FUNNAME. */ + if (j && funname[j - 1] == *funname) + funname[j - 1] = '\0'; + + rl_macro_bind (seq, &funname[1], _rl_keymap); + } + else + rl_set_key (seq, rl_named_function (funname), _rl_keymap); + + free (seq); + return 0; + } + + /* Get the actual character we want to deal with. */ + kname = strrchr (string, '-'); + if (!kname) + kname = string; + else + kname++; + + key = glean_key_from_name (kname); + + /* Add in control and meta bits. */ + if (substring_member_of_array (string, _rl_possible_control_prefixes)) + key = CTRL (_rl_to_upper (key)); + + if (substring_member_of_array (string, _rl_possible_meta_prefixes)) + key = META (key); + + /* Temporary. Handle old-style keyname with macro-binding. */ + if (*funname == '\'' || *funname == '"') + { + char useq[2]; + int fl = strlen (funname); + + useq[0] = key; useq[1] = '\0'; + if (fl && funname[fl - 1] == *funname) + funname[fl - 1] = '\0'; + + rl_macro_bind (useq, &funname[1], _rl_keymap); + } +#if defined (PREFIX_META_HACK) + /* Ugly, but working hack to keep prefix-meta around. */ + else if (_rl_stricmp (funname, "prefix-meta") == 0) + { + char seq[2]; + + seq[0] = key; + seq[1] = '\0'; + rl_generic_bind (ISKMAP, seq, (char *)emacs_meta_keymap, _rl_keymap); + } +#endif /* PREFIX_META_HACK */ + else + rl_bind_key (key, rl_named_function (funname)); + return 0; +} + +/* Simple structure for boolean readline variables (i.e., those that can + have one of two values; either "On" or 1 for truth, or "Off" or 0 for + false. */ + +#define V_SPECIAL 0x1 + +static struct { + const char *name; + int *value; + int flags; +} boolean_varlist [] = { + { "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL }, + { "byte-oriented", &rl_byte_oriented, 0 }, + { "completion-ignore-case", &_rl_completion_case_fold, 0 }, + { "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 }, + { "disable-completion", &rl_inhibit_completion, 0 }, + { "enable-keypad", &_rl_enable_keypad, 0 }, + { "expand-tilde", &rl_complete_with_tilde_expansion, 0 }, + { "history-preserve-point", &_rl_history_preserve_point, 0 }, + { "horizontal-scroll-mode", &_rl_horizontal_scroll_mode, 0 }, + { "input-meta", &_rl_meta_flag, 0 }, + { "mark-directories", &_rl_complete_mark_directories, 0 }, + { "mark-modified-lines", &_rl_mark_modified_lines, 0 }, + { "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 }, + { "match-hidden-files", &_rl_match_hidden_files, 0 }, + { "meta-flag", &_rl_meta_flag, 0 }, + { "output-meta", &_rl_output_meta_chars, 0 }, + { "page-completions", &_rl_page_completions, 0 }, + { "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL }, + { "print-completions-horizontally", &_rl_print_completions_horizontally, 0 }, + { "show-all-if-ambiguous", &_rl_complete_show_all, 0 }, +#if defined (VISIBLE_STATS) + { "visible-stats", &rl_visible_stats, 0 }, +#endif /* VISIBLE_STATS */ + { (char *)NULL, (int *)NULL, 0 } +}; + +static int +find_boolean_var (name) + const char *name; +{ + register int i; + + for (i = 0; boolean_varlist[i].name; i++) + if (_rl_stricmp (name, boolean_varlist[i].name) == 0) + return i; + return -1; +} + +/* Hooks for handling special boolean variables, where a + function needs to be called or another variable needs + to be changed when they're changed. */ +static void +hack_special_boolean_var (i) + int i; +{ + const char *name; + + name = boolean_varlist[i].name; + + if (_rl_stricmp (name, "blink-matching-paren") == 0) + _rl_enable_paren_matching (rl_blink_matching_paren); + else if (_rl_stricmp (name, "prefer-visible-bell") == 0) + { + if (_rl_prefer_visible_bell) + _rl_bell_preference = VISIBLE_BELL; + else + _rl_bell_preference = AUDIBLE_BELL; + } +} + +typedef int _rl_sv_func_t PARAMS((const char *)); + +/* These *must* correspond to the array indices for the appropriate + string variable. (Though they're not used right now.) */ +#define V_BELLSTYLE 0 +#define V_COMBEGIN 1 +#define V_EDITMODE 2 +#define V_ISRCHTERM 3 +#define V_KEYMAP 4 + +#define V_STRING 1 +#define V_INT 2 + +/* Forward declarations */ +static int sv_bell_style PARAMS((const char *)); +static int sv_combegin PARAMS((const char *)); +static int sv_compquery PARAMS((const char *)); +static int sv_editmode PARAMS((const char *)); +static int sv_isrchterm PARAMS((const char *)); +static int sv_keymap PARAMS((const char *)); + +static struct { + const char *name; + int flags; + _rl_sv_func_t *set_func; +} string_varlist[] = { + { "bell-style", V_STRING, sv_bell_style }, + { "comment-begin", V_STRING, sv_combegin }, + { "completion-query-items", V_INT, sv_compquery }, + { "editing-mode", V_STRING, sv_editmode }, + { "isearch-terminators", V_STRING, sv_isrchterm }, + { "keymap", V_STRING, sv_keymap }, + { (char *)NULL, 0, 0 } +}; + +static int +find_string_var (name) + const char *name; +{ + register int i; + + for (i = 0; string_varlist[i].name; i++) + if (_rl_stricmp (name, string_varlist[i].name) == 0) + return i; + return -1; +} + +/* A boolean value that can appear in a `set variable' command is true if + the value is null or empty, `on' (case-insenstive), or "1". Any other + values result in 0 (false). */ +static int +bool_to_int (value) + char *value; +{ + return (value == 0 || *value == '\0' || + (_rl_stricmp (value, "on") == 0) || + (value[0] == '1' && value[1] == '\0')); +} + +int +rl_variable_bind (name, value) + const char *name, *value; +{ + register int i; + int v; + + /* Check for simple variables first. */ + i = find_boolean_var (name); + if (i >= 0) + { + *boolean_varlist[i].value = bool_to_int (value); + if (boolean_varlist[i].flags & V_SPECIAL) + hack_special_boolean_var (i); + return 0; + } + + i = find_string_var (name); + + /* For the time being, unknown variable names or string names without a + handler function are simply ignored. */ + if (i < 0 || string_varlist[i].set_func == 0) + return 0; + + v = (*string_varlist[i].set_func) (value); + return v; +} + +static int +sv_editmode (value) + const char *value; +{ + if (_rl_strnicmp (value, "vi", 2) == 0) + { +#if defined (VI_MODE) + _rl_keymap = vi_insertion_keymap; + rl_editing_mode = vi_mode; +#endif /* VI_MODE */ + return 0; + } + else if (_rl_strnicmp (value, "emacs", 5) == 0) + { + _rl_keymap = emacs_standard_keymap; + rl_editing_mode = emacs_mode; + return 0; + } + return 1; +} + +static int +sv_combegin (value) + const char *value; +{ + if (value && *value) + { + FREE (_rl_comment_begin); + _rl_comment_begin = savestring (value); + return 0; + } + return 1; +} + +static int +sv_compquery (value) + const char *value; +{ + int nval = 100; + + if (value && *value) + { + nval = atoi (value); + if (nval < 0) + nval = 0; + } + rl_completion_query_items = nval; + return 0; +} + +static int +sv_keymap (value) + const char *value; +{ + Keymap kmap; + + kmap = rl_get_keymap_by_name (value); + if (kmap) + { + rl_set_keymap (kmap); + return 0; + } + return 1; +} + +static int +sv_bell_style (value) + const char *value; +{ + if (value == 0 || *value == '\0') + _rl_bell_preference = AUDIBLE_BELL; + else if (_rl_stricmp (value, "none") == 0 || _rl_stricmp (value, "off") == 0) + _rl_bell_preference = NO_BELL; + else if (_rl_stricmp (value, "audible") == 0 || _rl_stricmp (value, "on") == 0) + _rl_bell_preference = AUDIBLE_BELL; + else if (_rl_stricmp (value, "visible") == 0) + _rl_bell_preference = VISIBLE_BELL; + else + return 1; + return 0; +} + +static int +sv_isrchterm (value) + const char *value; +{ + int beg, end, delim; + char *v; + + if (value == 0) + return 1; + + /* Isolate the value and translate it into a character string. */ + v = savestring (value); + FREE (_rl_isearch_terminators); + if (v[0] == '"' || v[0] == '\'') + { + delim = v[0]; + for (beg = end = 1; v[end] && v[end] != delim; end++) + ; + } + else + { + for (beg = end = 0; whitespace (v[end]) == 0; end++) + ; + } + + v[end] = '\0'; + + /* The value starts at v + beg. Translate it into a character string. */ + _rl_isearch_terminators = (char *)xmalloc (2 * strlen (v) + 1); + rl_translate_keyseq (v + beg, _rl_isearch_terminators, &end); + _rl_isearch_terminators[end] = '\0'; + + free (v); + return 0; +} + +/* Return the character which matches NAME. + For example, `Space' returns ' '. */ + +typedef struct { + const char *name; + int value; +} assoc_list; + +static assoc_list name_key_alist[] = { + { "DEL", 0x7f }, + { "ESC", '\033' }, + { "Escape", '\033' }, + { "LFD", '\n' }, + { "Newline", '\n' }, + { "RET", '\r' }, + { "Return", '\r' }, + { "Rubout", 0x7f }, + { "SPC", ' ' }, + { "Space", ' ' }, + { "Tab", 0x09 }, + { (char *)0x0, 0 } +}; + +static int +glean_key_from_name (name) + char *name; +{ + register int i; + + for (i = 0; name_key_alist[i].name; i++) + if (_rl_stricmp (name, name_key_alist[i].name) == 0) + return (name_key_alist[i].value); + + return (*(unsigned char *)name); /* XXX was return (*name) */ +} + +/* Auxiliary functions to manage keymaps. */ +static struct { + const char *name; + Keymap map; +} keymap_names[] = { + { "emacs", emacs_standard_keymap }, + { "emacs-standard", emacs_standard_keymap }, + { "emacs-meta", emacs_meta_keymap }, + { "emacs-ctlx", emacs_ctlx_keymap }, +#if defined (VI_MODE) + { "vi", vi_movement_keymap }, + { "vi-move", vi_movement_keymap }, + { "vi-command", vi_movement_keymap }, + { "vi-insert", vi_insertion_keymap }, +#endif /* VI_MODE */ + { (char *)0x0, (Keymap)0x0 } +}; + +Keymap +rl_get_keymap_by_name (name) + const char *name; +{ + register int i; + + for (i = 0; keymap_names[i].name; i++) + if (_rl_stricmp (name, keymap_names[i].name) == 0) + return (keymap_names[i].map); + return ((Keymap) NULL); +} + +char * +rl_get_keymap_name (map) + Keymap map; +{ + register int i; + for (i = 0; keymap_names[i].name; i++) + if (map == keymap_names[i].map) + return ((char *)keymap_names[i].name); + return ((char *)NULL); +} + +void +rl_set_keymap (map) + Keymap map; +{ + if (map) + _rl_keymap = map; +} + +Keymap +rl_get_keymap () +{ + return (_rl_keymap); +} + +void +rl_set_keymap_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + _rl_keymap = emacs_standard_keymap; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + _rl_keymap = vi_insertion_keymap; +#endif /* VI_MODE */ +} + + +const char * +rl_get_keymap_name_from_edit_mode () +{ + if (rl_editing_mode == emacs_mode) + return "emacs"; +#if defined (VI_MODE) + else if (rl_editing_mode == vi_mode) + return "vi"; +#endif /* VI_MODE */ + else + return "nope"; +} + +/* **************************************************************** */ +/* */ +/* Key Binding and Function Information */ +/* */ +/* **************************************************************** */ + +/* Each of the following functions produces information about the + state of keybindings and functions known to Readline. The info + is always printed to rl_outstream, and in such a way that it can + be read back in (i.e., passed to rl_parse_and_bind (). */ + +/* Print the names of functions known to Readline. */ +void +rl_list_funmap_names () +{ + register int i; + const char **funmap_names; + + funmap_names = rl_funmap_names (); + + if (!funmap_names) + return; + + for (i = 0; funmap_names[i]; i++) + fprintf (rl_outstream, "%s\n", funmap_names[i]); + + free (funmap_names); +} + +static char * +_rl_get_keyname (key) + int key; +{ + char *keyname; + int i, c; + + keyname = (char *)xmalloc (8); + + c = key; + /* Since this is going to be used to write out keysequence-function + pairs for possible inclusion in an inputrc file, we don't want to + do any special meta processing on KEY. */ + +#if 1 + /* XXX - Experimental */ + /* We might want to do this, but the old version of the code did not. */ + + /* If this is an escape character, we don't want to do any more processing. + Just add the special ESC key sequence and return. */ + if (c == ESC) + { + keyname[0] = '\\'; + keyname[1] = 'e'; + keyname[2] = '\0'; + return keyname; + } +#endif + + /* RUBOUT is translated directly into \C-? */ + if (key == RUBOUT) + { + keyname[0] = '\\'; + keyname[1] = 'C'; + keyname[2] = '-'; + keyname[3] = '?'; + keyname[4] = '\0'; + return keyname; + } + + i = 0; + /* Now add special prefixes needed for control characters. This can + potentially change C. */ + if (CTRL_CHAR (c)) + { + keyname[i++] = '\\'; + keyname[i++] = 'C'; + keyname[i++] = '-'; + c = _rl_to_lower (UNCTRL (c)); + } + + /* XXX experimental code. Turn the characters that are not ASCII or + ISO Latin 1 (128 - 159) into octal escape sequences (\200 - \237). + This changes C. */ + if (c >= 128 && c <= 159) + { + keyname[i++] = '\\'; + keyname[i++] = '2'; + c -= 128; + keyname[i++] = (c / 8) + '0'; + c = (c % 8) + '0'; + } + + /* Now, if the character needs to be quoted with a backslash, do that. */ + if (c == '\\' || c == '"') + keyname[i++] = '\\'; + + /* Now add the key, terminate the string, and return it. */ + keyname[i++] = (char) c; + keyname[i] = '\0'; + + return keyname; +} + +/* Return a NULL terminated array of strings which represent the key + sequences that are used to invoke FUNCTION in MAP. */ +char ** +rl_invoking_keyseqs_in_map (function, map) + rl_command_func_t *function; + Keymap map; +{ + register int key; + char **result; + int result_index, result_size; + + result = (char **)NULL; + result_index = result_size = 0; + + for (key = 0; key < KEYMAP_SIZE; key++) + { + switch (map[key].type) + { + case ISMACR: + /* Macros match, if, and only if, the pointers are identical. + Thus, they are treated exactly like functions in here. */ + case ISFUNC: + /* If the function in the keymap is the one we are looking for, + then add the current KEY to the list of invoking keys. */ + if (map[key].function == function) + { + char *keyname; + + keyname = _rl_get_keyname (key); + + if (result_index + 2 > result_size) + { + result_size += 10; + result = (char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index++] = keyname; + result[result_index] = (char *)NULL; + } + break; + + case ISKMAP: + { + char **seqs; + register int i; + + /* Find the list of keyseqs in this map which have FUNCTION as + their target. Add the key sequences found to RESULT. */ + if (map[key].function) + seqs = + rl_invoking_keyseqs_in_map (function, FUNCTION_TO_KEYMAP (map, key)); + else + break; + + if (seqs == 0) + break; + + for (i = 0; seqs[i]; i++) + { + char *keyname = (char *)xmalloc (6 + strlen (seqs[i])); + + if (key == ESC) +#if 0 + sprintf (keyname, "\\e"); +#else + /* XXX - experimental */ + sprintf (keyname, "\\M-"); +#endif + else if (CTRL_CHAR (key)) + sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key))); + else if (key == RUBOUT) + sprintf (keyname, "\\C-?"); + else if (key == '\\' || key == '"') + { + keyname[0] = '\\'; + keyname[1] = (char) key; + keyname[2] = '\0'; + } + else + { + keyname[0] = (char) key; + keyname[1] = '\0'; + } + + strcat (keyname, seqs[i]); + free (seqs[i]); + + if (result_index + 2 > result_size) + { + result_size += 10; + result = (char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index++] = keyname; + result[result_index] = (char *)NULL; + } + + free (seqs); + } + break; + } + } + return (result); +} + +/* Return a NULL terminated array of strings which represent the key + sequences that can be used to invoke FUNCTION using the current keymap. */ +char ** +rl_invoking_keyseqs (function) + rl_command_func_t *function; +{ + return (rl_invoking_keyseqs_in_map (function, _rl_keymap)); +} + +/* Print all of the functions and their bindings to rl_outstream. If + PRINT_READABLY is non-zero, then print the output in such a way + that it can be read back in. */ +void +rl_function_dumper (print_readably) + int print_readably; +{ + register int i; + const char **names; + const char *name; + + names = rl_funmap_names (); + + fprintf (rl_outstream, "\n"); + + for (i = 0; (name = names[i]); i++) + { + rl_command_func_t *function; + char **invokers; + + function = rl_named_function (name); + invokers = rl_invoking_keyseqs_in_map (function, _rl_keymap); + + if (print_readably) + { + if (!invokers) + fprintf (rl_outstream, "# %s (not bound)\n", name); + else + { + register int j; + + for (j = 0; invokers[j]; j++) + { + fprintf (rl_outstream, "\"%s\": %s\n", + invokers[j], name); + free (invokers[j]); + } + + free (invokers); + } + } + else + { + if (!invokers) + fprintf (rl_outstream, "%s is not bound to any keys\n", + name); + else + { + register int j; + + fprintf (rl_outstream, "%s can be found on ", name); + + for (j = 0; invokers[j] && j < 5; j++) + { + fprintf (rl_outstream, "\"%s\"%s", invokers[j], + invokers[j + 1] ? ", " : ".\n"); + } + + if (j == 5 && invokers[j]) + fprintf (rl_outstream, "...\n"); + + for (j = 0; invokers[j]; j++) + free (invokers[j]); + + free (invokers); + } + } + } +} + +/* Print all of the current functions and their bindings to + rl_outstream. If an explicit argument is given, then print + the output in such a way that it can be read back in. */ +int +rl_dump_functions (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_function_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +static void +_rl_macro_dumper_internal (print_readably, map, prefix) + int print_readably; + Keymap map; + char *prefix; +{ + register int key; + char *keyname, *out; + int prefix_len; + + for (key = 0; key < KEYMAP_SIZE; key++) + { + switch (map[key].type) + { + case ISMACR: + keyname = _rl_get_keyname (key); + out = _rl_untranslate_macro_value ((char *)map[key].function); + + if (print_readably) + fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "", + keyname, + out ? out : ""); + else + fprintf (rl_outstream, "%s%s outputs %s\n", prefix ? prefix : "", + keyname, + out ? out : ""); + free (keyname); + free (out); + break; + case ISFUNC: + break; + case ISKMAP: + prefix_len = prefix ? strlen (prefix) : 0; + if (key == ESC) + { + keyname = (char *)xmalloc (3 + prefix_len); + if (prefix) + strcpy (keyname, prefix); + keyname[prefix_len] = '\\'; + keyname[prefix_len + 1] = 'e'; + keyname[prefix_len + 2] = '\0'; + } + else + { + keyname = _rl_get_keyname (key); + if (prefix) + { + out = (char *)xmalloc (strlen (keyname) + prefix_len + 1); + strcpy (out, prefix); + strcpy (out + prefix_len, keyname); + free (keyname); + keyname = out; + } + } + + _rl_macro_dumper_internal (print_readably, FUNCTION_TO_KEYMAP (map, key), keyname); + free (keyname); + break; + } + } +} + +void +rl_macro_dumper (print_readably) + int print_readably; +{ + _rl_macro_dumper_internal (print_readably, _rl_keymap, (char *)NULL); +} + +int +rl_dump_macros (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_macro_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +void +rl_variable_dumper (print_readably) + int print_readably; +{ + int i; + const char *kname; + + for (i = 0; boolean_varlist[i].name; i++) + { + if (print_readably) + fprintf (rl_outstream, "set %s %s\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + else + fprintf (rl_outstream, "%s is set to `%s'\n", boolean_varlist[i].name, + *boolean_varlist[i].value ? "on" : "off"); + } + + /* bell-style */ + switch (_rl_bell_preference) + { + case NO_BELL: + kname = "none"; break; + case VISIBLE_BELL: + kname = "visible"; break; + case AUDIBLE_BELL: + default: + kname = "audible"; break; + } + if (print_readably) + fprintf (rl_outstream, "set bell-style %s\n", kname); + else + fprintf (rl_outstream, "bell-style is set to `%s'\n", kname); + + /* comment-begin */ + if (print_readably) + fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); + else + fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT); + + /* completion-query-items */ + if (print_readably) + fprintf (rl_outstream, "set completion-query-items %d\n", rl_completion_query_items); + else + fprintf (rl_outstream, "completion-query-items is set to `%d'\n", rl_completion_query_items); + + /* editing-mode */ + if (print_readably) + fprintf (rl_outstream, "set editing-mode %s\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); + else + fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi"); + + /* isearch-terminators */ + if (_rl_isearch_terminators) + { + char *disp; + + disp = _rl_untranslate_macro_value (_rl_isearch_terminators); + + if (print_readably) + fprintf (rl_outstream, "set isearch-terminators \"%s\"\n", disp); + else + fprintf (rl_outstream, "isearch-terminators is set to \"%s\"\n", disp); + + free (disp); + } + + /* keymap */ + kname = rl_get_keymap_name (_rl_keymap); + if (kname == 0) + kname = rl_get_keymap_name_from_edit_mode (); + if (print_readably) + fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none"); + else + fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none"); +} + +/* Print all of the current variables and their values to + rl_outstream. If an explicit argument is given, then print + the output in such a way that it can be read back in. */ +int +rl_dump_variables (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (rl_dispatching) + fprintf (rl_outstream, "\r\n"); + rl_variable_dumper (rl_explicit_arg); + rl_on_new_line (); + return (0); +} + +/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right + now, this is always used to attempt to bind the arrow keys, hence the + check for rl_vi_movement_mode. */ +void +_rl_bind_if_unbound (keyseq, default_func) + const char *keyseq; + rl_command_func_t *default_func; +{ + rl_command_func_t *func; + + if (keyseq) + { + func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL); +#if defined (VI_MODE) + if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode) +#else + if (!func || func == rl_do_lowercase_version) +#endif + rl_set_key (keyseq, default_func, _rl_keymap); + } +} + +/* Return non-zero if any members of ARRAY are a substring in STRING. */ +static int +substring_member_of_array (string, array) + char *string; + const char **array; +{ + while (*array) + { + if (_rl_strindex (string, *array)) + return (1); + array++; + } + return (0); +} diff --git a/cmd-line-utils/readline/callback.c b/cmd-line-utils/readline/callback.c new file mode 100644 index 00000000000..a8f4323c929 --- /dev/null +++ b/cmd-line-utils/readline/callback.c @@ -0,0 +1,156 @@ +/* callback.c -- functions to use readline as an X `callback' mechanism. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include "rlconf.h" + +#if defined (READLINE_CALLBACKS) + +#include <sys/types.h> + +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "readline.h" +#include "rlprivate.h" + +/* **************************************************************** */ +/* */ +/* Callback Readline Functions */ +/* */ +/* **************************************************************** */ + +/* Allow using readline in situations where a program may have multiple + things to handle at once, and dispatches them via select(). Call + rl_callback_handler_install() with the prompt and a function to call + whenever a complete line of input is ready. The user must then + call rl_callback_read_char() every time some input is available, and + rl_callback_read_char() will call the user's function with the complete + text read in at each end of line. The terminal is kept prepped and + signals handled all the time, except during calls to the user's function. */ + +rl_vcpfunc_t *rl_linefunc; /* user callback function */ +static int in_handler; /* terminal_prepped and signals set? */ + +/* Make sure the terminal is set up, initialize readline, and prompt. */ +static void +_rl_callback_newline () +{ + rl_initialize (); + + if (in_handler == 0) + { + in_handler = 1; + + (*rl_prep_term_function) (_rl_meta_flag); + +#if defined (HANDLE_SIGNALS) + rl_set_signals (); +#endif + } + + readline_internal_setup (); +} + +/* Install a readline handler, set up the terminal, and issue the prompt. */ +void +rl_callback_handler_install (prompt, linefunc) + const char *prompt; + rl_vcpfunc_t *linefunc; +{ + rl_set_prompt (prompt); + rl_linefunc = linefunc; + _rl_callback_newline (); +} + +/* Read one character, and dispatch to the handler if it ends the line. */ +void +rl_callback_read_char () +{ + char *line; + int eof; + + if (rl_linefunc == NULL) + { + fprintf (stderr, "readline: readline_callback_read_char() called with no handler!\r\n"); + abort (); + } + + eof = readline_internal_char (); + + /* We loop in case some function has pushed input back with rl_execute_next. */ + for (;;) + { + if (rl_done) + { + line = readline_internal_teardown (eof); + + (*rl_deprep_term_function) (); +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + in_handler = 0; + (*rl_linefunc) (line); + + /* If the user did not clear out the line, do it for him. */ + if (rl_line_buffer[0]) + _rl_init_line_state (); + + /* Redisplay the prompt if readline_handler_{install,remove} + not called. */ + if (in_handler == 0 && rl_linefunc) + _rl_callback_newline (); + } + if (rl_pending_input) + eof = readline_internal_char (); + else + break; + } +} + +/* Remove the handler, and make sure the terminal is in its normal state. */ +void +rl_callback_handler_remove () +{ + rl_linefunc = NULL; + if (in_handler) + { + in_handler = 0; + (*rl_deprep_term_function) (); +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + } +} + +#endif diff --git a/cmd-line-utils/readline/chardefs.h b/cmd-line-utils/readline/chardefs.h new file mode 100644 index 00000000000..a537be220b0 --- /dev/null +++ b/cmd-line-utils/readline/chardefs.h @@ -0,0 +1,159 @@ +/* chardefs.h -- Character definitions for readline. */ + +/* Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _CHARDEFS_H_ +#define _CHARDEFS_H_ + +#include <ctype.h> + +#if defined (HAVE_CONFIG_H) +# if defined (HAVE_STRING_H) +# if ! defined (STDC_HEADERS) && defined (HAVE_MEMORY_H) +# include <memory.h> +# endif +# include <string.h> +# endif /* HAVE_STRING_H */ +# if defined (HAVE_STRINGS_H) +# include <strings.h> +# endif /* HAVE_STRINGS_H */ +#else +# include <string.h> +#endif /* !HAVE_CONFIG_H */ + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifdef CTRL +# undef CTRL +#endif +#ifdef UNCTRL +# undef UNCTRL +#endif + +/* Some character stuff. */ +#define control_character_threshold 0x020 /* Smaller than this is control. */ +#define control_character_mask 0x1f /* 0x20 - 1 */ +#define meta_character_threshold 0x07f /* Larger than this is Meta. */ +#define control_character_bit 0x40 /* 0x000000, must be off. */ +#define meta_character_bit 0x080 /* x0000000, must be on. */ +#define largest_char 255 /* Largest character value. */ + +#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0)) +#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char) + +#define CTRL(c) ((c) & control_character_mask) +#define META(c) ((c) | meta_character_bit) + +#define UNMETA(c) ((c) & (~meta_character_bit)) +#define UNCTRL(c) _rl_to_upper(((c)|control_character_bit)) + +#if defined STDC_HEADERS || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#if !defined (isxdigit) && !defined (HAVE_ISXDIGIT) +# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) +#endif + +#define NON_NEGATIVE(c) ((unsigned char)(c) == (c)) + +/* Some systems define these; we want our definitions. */ +#undef ISPRINT + +#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c)) +#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c)) +#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c)) + +#define _rl_lowercase_p(c) (NON_NEGATIVE(c) && ISLOWER(c)) +#define _rl_uppercase_p(c) (NON_NEGATIVE(c) && ISUPPER(c)) +#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') + +#define _rl_pure_alphabetic(c) (NON_NEGATIVE(c) && ISALPHA(c)) +#define ALPHABETIC(c) (NON_NEGATIVE(c) && ISALNUM(c)) + +#ifndef _rl_to_upper +# define _rl_to_upper(c) (_rl_lowercase_p(c) ? toupper((unsigned char)c) : (c)) +# define _rl_to_lower(c) (_rl_uppercase_p(c) ? tolower((unsigned char)c) : (c)) +#endif + +#ifndef _rl_digit_value +# define _rl_digit_value(x) ((x) - '0') +#endif + +#ifndef _rl_isident +# define _rl_isident(c) (ISALNUM(c) || (c) == '_') +#endif + +#ifndef ISOCTAL +# define ISOCTAL(c) ((c) >= '0' && (c) <= '7') +#endif +#define OCTVALUE(c) ((c) - '0') + +#define HEXVALUE(c) \ + (((c) >= 'a' && (c) <= 'f') \ + ? (c)-'a'+10 \ + : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0') + +#ifndef NEWLINE +#define NEWLINE '\n' +#endif + +#ifndef RETURN +#define RETURN CTRL('M') +#endif + +#ifndef RUBOUT +#define RUBOUT 0x7f +#endif + +#ifndef TAB +#define TAB '\t' +#endif + +#ifdef ABORT_CHAR +#undef ABORT_CHAR +#endif +#define ABORT_CHAR CTRL('G') + +#ifdef PAGE +#undef PAGE +#endif +#define PAGE CTRL('L') + +#ifdef SPACE +#undef SPACE +#endif +#define SPACE ' ' /* XXX - was 0x20 */ + +#ifdef ESC +#undef ESC +#endif +#define ESC CTRL('[') + +#endif /* _CHARDEFS_H_ */ diff --git a/cmd-line-utils/readline/complete.c b/cmd-line-utils/readline/complete.c new file mode 100644 index 00000000000..693550c9945 --- /dev/null +++ b/cmd-line-utils/readline/complete.c @@ -0,0 +1,2004 @@ +/* complete.c -- filename completion for readline. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#if defined (HAVE_SYS_FILE_H) +#include <sys/file.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +#include <errno.h> +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include <pwd.h> + +#include "posixdir.h" +#include "posixstat.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "xmalloc.h" +#include "rlprivate.h" + +#ifdef __STDC__ +typedef int QSFUNC (const void *, const void *); +#else +typedef int QSFUNC (); +#endif + +#ifdef HAVE_LSTAT +# define LSTAT lstat +#else +# define LSTAT stat +#endif + +/* Unix version of a hidden file. Could be different on other systems. */ +#define HIDDEN_FILE(fname) ((fname)[0] == '.') + +/* Most systems don't declare getpwent in <pwd.h> if _POSIX_SOURCE is + defined. */ +#if !defined (HAVE_GETPW_DECLS) || defined (_POSIX_SOURCE) +extern struct passwd *getpwent PARAMS((void)); +#endif /* !HAVE_GETPW_DECLS || _POSIX_SOURCE */ + +/* If non-zero, then this is the address of a function to call when + completing a word would normally display the list of possible matches. + This function is called instead of actually doing the display. + It takes three arguments: (char **matches, int num_matches, int max_length) + where MATCHES is the array of strings that matched, NUM_MATCHES is the + number of strings in that array, and MAX_LENGTH is the length of the + longest string in that array. */ +rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)NULL; + +#if defined (VISIBLE_STATS) +# if !defined (X_OK) +# define X_OK 1 +# endif +static int stat_char PARAMS((char *)); +#endif + +static char *rl_quote_filename PARAMS((char *, int, char *)); + +static void set_completion_defaults PARAMS((int)); +static int get_y_or_n PARAMS((int)); +static int _rl_internal_pager PARAMS((int)); +static char *printable_part PARAMS((char *)); +static int print_filename PARAMS((char *, char *)); + +static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int)); + +static char **remove_duplicate_matches PARAMS((char **)); +static void insert_match PARAMS((char *, int, int, char *)); +static int append_to_match PARAMS((char *, int, int, int)); +static void insert_all_matches PARAMS((char **, int, char *)); +static void display_matches PARAMS((char **)); +static int compute_lcd_of_matches PARAMS((char **, int, const char *)); +static int postprocess_matches PARAMS((char ***, int)); + +static char *make_quoted_replacement PARAMS((char *, int, char *)); + +/* **************************************************************** */ +/* */ +/* Completion matching, from readline's point of view. */ +/* */ +/* **************************************************************** */ + +/* Variables known only to the readline library. */ + +/* If non-zero, non-unique completions always show the list of matches. */ +int _rl_complete_show_all = 0; + +/* If non-zero, completed directory names have a slash appended. */ +int _rl_complete_mark_directories = 1; + +/* If non-zero, the symlinked directory completion behavior introduced in + readline-4.2a is disabled, and symlinks that point to directories have + a slash appended (subject to the value of _rl_complete_mark_directories). + This is user-settable via the mark-symlinked-directories variable. */ +int _rl_complete_mark_symlink_dirs = 0; + +/* If non-zero, completions are printed horizontally in alphabetical order, + like `ls -x'. */ +int _rl_print_completions_horizontally; + +/* Non-zero means that case is not significant in filename completion. */ +#if defined (__MSDOS__) && !defined (__DJGPP__) +int _rl_completion_case_fold = 1; +#else +int _rl_completion_case_fold; +#endif + +/* If non-zero, don't match hidden files (filenames beginning with a `.' on + Unix) when doing filename completion. */ +int _rl_match_hidden_files = 1; + +/* Global variables available to applications using readline. */ + +#if defined (VISIBLE_STATS) +/* Non-zero means add an additional character to each filename displayed + during listing completion iff rl_filename_completion_desired which helps + to indicate the type of file being listed. */ +int rl_visible_stats = 0; +#endif /* VISIBLE_STATS */ + +/* If non-zero, then this is the address of a function to call when + completing on a directory name. The function is called with + the address of a string (the current directory name) as an arg. */ +rl_icppfunc_t *rl_directory_completion_hook = (rl_icppfunc_t *)NULL; + +rl_icppfunc_t *rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; + +/* Non-zero means readline completion functions perform tilde expansion. */ +int rl_complete_with_tilde_expansion = 0; + +/* Pointer to the generator function for completion_matches (). + NULL means to use rl_filename_completion_function (), the default filename + completer. */ +rl_compentry_func_t *rl_completion_entry_function = (rl_compentry_func_t *)NULL; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +rl_completion_func_t *rl_attempted_completion_function = (rl_completion_func_t *)NULL; + +/* Non-zero means to suppress normal filename completion after the + user-specified completion function has been called. */ +int rl_attempted_completion_over = 0; + +/* Set to a character indicating the type of completion being performed + by rl_complete_internal, available for use by application completion + functions. */ +int rl_completion_type = 0; + +/* Up to this many items will be displayed in response to a + possible-completions call. After that, we ask the user if + she is sure she wants to see them all. */ +int rl_completion_query_items = 100; + +int _rl_page_completions = 1; + +/* The basic list of characters that signal a break between words for the + completer routine. The contents of this variable is what breaks words + in the shell, i.e. " \t\n\"\\'`@$><=" */ +const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; /* }) */ + +/* List of basic quoting characters. */ +const char *rl_basic_quote_characters = "\"'"; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +const char *rl_completer_word_break_characters = (const char *)NULL; + +/* List of characters which can be used to quote a substring of the line. + Completion occurs on the entire substring, and within the substring + rl_completer_word_break_characters are treated as any other character, + unless they also appear within this list. */ +const char *rl_completer_quote_characters = (const char *)NULL; + +/* List of characters that should be quoted in filenames by the completer. */ +const char *rl_filename_quote_characters = (const char *)NULL; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +const char *rl_special_prefixes = (const char *)NULL; + +/* If non-zero, then disallow duplicates in the matches. */ +int rl_ignore_completion_duplicates = 1; + +/* Non-zero means that the results of the matches are to be treated + as filenames. This is ALWAYS zero on entry, and can only be changed + within a completion entry finder function. */ +int rl_filename_completion_desired = 0; + +/* Non-zero means that the results of the matches are to be quoted using + double quotes (or an application-specific quoting mechanism) if the + filename contains any characters in rl_filename_quote_chars. This is + ALWAYS non-zero on entry, and can only be changed within a completion + entry finder function. */ +int rl_filename_quoting_desired = 1; + +/* This function, if defined, is called by the completer when real + filename completion is done, after all the matching names have been + generated. It is passed a (char**) known as matches in the code below. + It consists of a NULL-terminated array of pointers to potential + matching strings. The 1st element (matches[0]) is the maximal + substring that is common to all matches. This function can re-arrange + the list of matches as required, but all elements of the array must be + free()'d if they are deleted. The main intent of this function is + to implement FIGNORE a la SunOS csh. */ +rl_compignore_func_t *rl_ignore_some_completions_function = (rl_compignore_func_t *)NULL; + +/* Set to a function to quote a filename in an application-specific fashion. + Called with the text to quote, the type of match found (single or multiple) + and a pointer to the quoting character to be used, which the function can + reset if desired. */ +rl_quote_func_t *rl_filename_quoting_function = rl_quote_filename; + +/* Function to call to remove quoting characters from a filename. Called + before completion is attempted, so the embedded quotes do not interfere + with matching names in the file system. Readline doesn't do anything + with this; it's set only by applications. */ +rl_dequote_func_t *rl_filename_dequoting_function = (rl_dequote_func_t *)NULL; + +/* Function to call to decide whether or not a word break character is + quoted. If a character is quoted, it does not break words for the + completer. */ +rl_linebuf_func_t *rl_char_is_quoted_p = (rl_linebuf_func_t *)NULL; + +/* If non-zero, the completion functions don't append anything except a + possible closing quote. This is set to 0 by rl_complete_internal and + may be changed by an application-specific completion function. */ +int rl_completion_suppress_append = 0; + +/* Character appended to completed words when at the end of the line. The + default is a space. */ +int rl_completion_append_character = ' '; + +/* If non-zero, a slash will be appended to completed filenames that are + symbolic links to directory names, subject to the value of the + mark-directories variable (which is user-settable). This exists so + that application completion functions can override the user's preference + (set via the mark-symlinked-directories variable) if appropriate. + It's set to the value of _rl_complete_mark_symlink_dirs in + rl_complete_internal before any application-specific completion + function is called, so without that function doing anything, the user's + preferences are honored. */ +int rl_completion_mark_symlink_dirs; + +/* If non-zero, inhibit completion (temporarily). */ +int rl_inhibit_completion; + +/* Variables local to this file. */ + +/* Local variable states what happened during the last completion attempt. */ +static int completion_changed_buffer; + +/*************************************/ +/* */ +/* Bindable completion functions */ +/* */ +/*************************************/ + +/* Complete the word at or before point. You have supplied the function + that does the initial simple matching selection algorithm (see + rl_completion_matches ()). The default is to do filename completion. */ +int +rl_complete (ignore, invoking_key) + int ignore, invoking_key; +{ + if (rl_inhibit_completion) + return (_rl_insert_char (ignore, invoking_key)); + else if (rl_last_func == rl_complete && !completion_changed_buffer) + return (rl_complete_internal ('?')); + else if (_rl_complete_show_all) + return (rl_complete_internal ('!')); + else + return (rl_complete_internal (TAB)); +} + +/* List the possible completions. See description of rl_complete (). */ +int +rl_possible_completions (ignore, invoking_key) + int ignore __attribute__((unused)), invoking_key __attribute__((unused)); +{ + return (rl_complete_internal ('?')); +} + +int +rl_insert_completions (ignore, invoking_key) + int ignore __attribute__((unused)), invoking_key __attribute__((unused)); +{ + return (rl_complete_internal ('*')); +} + +/* Return the correct value to pass to rl_complete_internal performing + the same tests as rl_complete. This allows consecutive calls to an + application's completion function to list possible completions and for + an application-specific completion function to honor the + show-all-if-ambiguous readline variable. */ +int +rl_completion_mode (cfunc) + rl_command_func_t *cfunc; +{ + if (rl_last_func == cfunc && !completion_changed_buffer) + return '?'; + else if (_rl_complete_show_all) + return '!'; + else + return TAB; +} + +/************************************/ +/* */ +/* Completion utility functions */ +/* */ +/************************************/ + +/* Set default values for readline word completion. These are the variables + that application completion functions can change or inspect. */ +static void +set_completion_defaults (what_to_do) + int what_to_do; +{ + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + rl_completion_type = what_to_do; + rl_completion_suppress_append = 0; + + /* The completion entry function may optionally change this. */ + rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs; +} + +/* The user must press "y" or "n". Non-zero return means "y" pressed. */ +static int +get_y_or_n (for_pager) + int for_pager; +{ + int c; + + for (;;) + { + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c == 'y' || c == 'Y' || c == ' ') + return (1); + if (c == 'n' || c == 'N' || c == RUBOUT) + return (0); + if (c == ABORT_CHAR) + _rl_abort_internal (); + if (for_pager && (c == NEWLINE || c == RETURN)) + return (2); + if (for_pager && (c == 'q' || c == 'Q')) + return (0); + rl_ding (); + } +} + +static int +_rl_internal_pager (lines) + int lines; +{ + int i; + + fprintf (rl_outstream, "--More--"); + fflush (rl_outstream); + i = get_y_or_n (1); + _rl_erase_entire_line (); + if (i == 0) + return -1; + else if (i == 2) + return (lines - 1); + else + return 0; +} + +#if defined (VISIBLE_STATS) +/* Return the character which best describes FILENAME. + `@' for symbolic links + `/' for directories + `*' for executables + `=' for sockets + `|' for FIFOs + `%' for character special devices + `#' for block special devices */ +static int +stat_char (filename) + char *filename; +{ + struct stat finfo; + int character, r; + +#if defined (HAVE_LSTAT) && defined (S_ISLNK) + r = lstat (filename, &finfo); +#else + r = stat (filename, &finfo); +#endif + + if (r == -1) + return (0); + + character = 0; + if (S_ISDIR (finfo.st_mode)) + character = '/'; +#if defined (S_ISCHR) + else if (S_ISCHR (finfo.st_mode)) + character = '%'; +#endif /* S_ISCHR */ +#if defined (S_ISBLK) + else if (S_ISBLK (finfo.st_mode)) + character = '#'; +#endif /* S_ISBLK */ +#if defined (S_ISLNK) + else if (S_ISLNK (finfo.st_mode)) + character = '@'; +#endif /* S_ISLNK */ +#if defined (S_ISSOCK) + else if (S_ISSOCK (finfo.st_mode)) + character = '='; +#endif /* S_ISSOCK */ +#if defined (S_ISFIFO) + else if (S_ISFIFO (finfo.st_mode)) + character = '|'; +#endif + else if (S_ISREG (finfo.st_mode)) + { + if (access (filename, X_OK) == 0) + character = '*'; + } + return (character); +} +#endif /* VISIBLE_STATS */ + +/* Return the portion of PATHNAME that should be output when listing + possible completions. If we are hacking filename completion, we + are only interested in the basename, the portion following the + final slash. Otherwise, we return what we were passed. Since + printing empty strings is not very informative, if we're doing + filename completion, and the basename is the empty string, we look + for the previous slash and return the portion following that. If + there's no previous slash, we just return what we were passed. */ +static char * +printable_part (pathname) + char *pathname; +{ + char *temp, *x; + + if (rl_filename_completion_desired == 0) /* don't need to do anything */ + return (pathname); + + temp = strrchr (pathname, '/'); +#if defined (__MSDOS__) + if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':') + temp = pathname + 1; +#endif + + if (temp == 0 || *temp == '\0') + return (pathname); + /* If the basename is NULL, we might have a pathname like '/usr/src/'. + Look for a previous slash and, if one is found, return the portion + following that slash. If there's no previous slash, just return the + pathname we were passed. */ + else if (temp[1] == '\0') + { + for (x = temp - 1; x > pathname; x--) + if (*x == '/') + break; + return ((*x == '/') ? x + 1 : pathname); + } + else + return ++temp; +} + +/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we + are using it, check for and output a single character for `special' + filenames. Return the number of characters we output. */ + +#define PUTX(c) \ + do { \ + if (CTRL_CHAR (c)) \ + { \ + putc ('^', rl_outstream); \ + putc (UNCTRL (c), rl_outstream); \ + printed_len += 2; \ + } \ + else if (c == RUBOUT) \ + { \ + putc ('^', rl_outstream); \ + putc ('?', rl_outstream); \ + printed_len += 2; \ + } \ + else \ + { \ + putc (c, rl_outstream); \ + printed_len++; \ + } \ + } while (0) + +static int +print_filename (to_print, full_pathname) + char *to_print, *full_pathname; +{ + int printed_len = 0; +#if !defined (VISIBLE_STATS) + char *s; + + for (s = to_print; *s; s++) + { + PUTX (*s); + } +#else + char *s, c, *new_full_pathname; + int extension_char, slen, tlen; + + for (s = to_print; *s; s++) + { + PUTX (*s); + } + + if (rl_filename_completion_desired && rl_visible_stats) + { + /* If to_print != full_pathname, to_print is the basename of the + path passed. In this case, we try to expand the directory + name before checking for the stat character. */ + if (to_print != full_pathname) + { + /* Terminate the directory name. */ + c = to_print[-1]; + to_print[-1] = '\0'; + + /* If setting the last slash in full_pathname to a NUL results in + full_pathname being the empty string, we are trying to complete + files in the root directory. If we pass a null string to the + bash directory completion hook, for example, it will expand it + to the current directory. We just want the `/'. */ + s = tilde_expand (full_pathname && *full_pathname ? full_pathname : "/"); + if (rl_directory_completion_hook) + (*rl_directory_completion_hook) (&s); + + slen = strlen (s); + tlen = strlen (to_print); + new_full_pathname = (char *)xmalloc (slen + tlen + 2); + strcpy (new_full_pathname, s); + new_full_pathname[slen] = '/'; + strcpy (new_full_pathname + slen + 1, to_print); + + extension_char = stat_char (new_full_pathname); + + free (new_full_pathname); + to_print[-1] = c; + } + else + { + s = tilde_expand (full_pathname); + extension_char = stat_char (s); + } + + free (s); + if (extension_char) + { + putc (extension_char, rl_outstream); + printed_len++; + } + } +#endif /* VISIBLE_STATS */ + return printed_len; +} + +static char * +rl_quote_filename (s, rtype, qcp) + char *s; + int rtype __attribute__((unused)); + char *qcp; +{ + char *r; + + r = (char *)xmalloc (strlen (s) + 2); + *r = *rl_completer_quote_characters; + strcpy (r + 1, s); + if (qcp) + *qcp = *rl_completer_quote_characters; + return r; +} + +/* Find the bounds of the current word for completion purposes, and leave + rl_point set to the end of the word. This function skips quoted + substrings (characters between matched pairs of characters in + rl_completer_quote_characters). First we try to find an unclosed + quoted substring on which to do matching. If one is not found, we use + the word break characters to find the boundaries of the current word. + We call an application-specific function to decide whether or not a + particular word break character is quoted; if that function returns a + non-zero result, the character does not break a word. This function + returns the opening quote character if we found an unclosed quoted + substring, '\0' otherwise. FP, if non-null, is set to a value saying + which (shell-like) quote characters we found (single quote, double + quote, or backslash) anywhere in the string. DP, if non-null, is set to + the value of the delimiter character that caused a word break. */ + +char +_rl_find_completion_word (fp, dp) + int *fp, *dp; +{ + int scan, end, found_quote, delimiter, pass_next, isbrk; + char quote_char; + + end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_completer_quote_characters) + { + /* We have a list of characters which can be used in pairs to + quote substrings for the completer. Try to find the start + of an unclosed quoted substring. */ + /* FOUND_QUOTE is set so we know what kind of quotes we found. */ + for (scan = pass_next = 0; scan < end; scan++) + { + if (pass_next) + { + pass_next = 0; + continue; + } + + /* Shell-like semantics for single quotes -- don't allow backslash + to quote anything in single quotes, especially not the closing + quote. If you don't like this, take out the check on the value + of quote_char. */ + if (quote_char != '\'' && rl_line_buffer[scan] == '\\') + { + pass_next = 1; + found_quote |= RL_QF_BACKSLASH; + continue; + } + + if (quote_char != '\0') + { + /* Ignore everything until the matching close quote char. */ + if (rl_line_buffer[scan] == quote_char) + { + /* Found matching close. Abandon this substring. */ + quote_char = '\0'; + rl_point = end; + } + } + else if (strchr (rl_completer_quote_characters, rl_line_buffer[scan])) + { + /* Found start of a quoted substring. */ + quote_char = rl_line_buffer[scan]; + rl_point = scan + 1; + /* Shell-like quoting conventions. */ + if (quote_char == '\'') + found_quote |= RL_QF_SINGLE_QUOTE; + else if (quote_char == '"') + found_quote |= RL_QF_DOUBLE_QUOTE; + else + found_quote |= RL_QF_OTHER_QUOTE; + } + } + } + + if (rl_point == end && quote_char == '\0') + { + /* We didn't find an unclosed quoted substring upon which to do + completion, so use the word break characters to find the + substring on which to complete. */ +#if defined (HANDLE_MULTIBYTE) + while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY)) +#else + while (--rl_point) +#endif + { + scan = rl_line_buffer[rl_point]; + + if (strchr (rl_completer_word_break_characters, scan) == 0) + continue; + + /* Call the application-specific function to tell us whether + this word break character is quoted and should be skipped. */ + if (rl_char_is_quoted_p && found_quote && + (*rl_char_is_quoted_p) (rl_line_buffer, rl_point)) + continue; + + /* Convoluted code, but it avoids an n^2 algorithm with calls + to char_is_quoted. */ + break; + } + } + + /* If we are at an unquoted word break, then advance past it. */ + scan = rl_line_buffer[rl_point]; + + /* If there is an application-specific function to say whether or not + a character is quoted and we found a quote character, let that + function decide whether or not a character is a word break, even + if it is found in rl_completer_word_break_characters. Don't bother + if we're at the end of the line, though. */ + if (scan) + { + if (rl_char_is_quoted_p) + isbrk = (found_quote == 0 || + (*rl_char_is_quoted_p) (rl_line_buffer, rl_point) == 0) && + strchr (rl_completer_word_break_characters, scan) != 0; + else + isbrk = strchr (rl_completer_word_break_characters, scan) != 0; + + if (isbrk) + { + /* If the character that caused the word break was a quoting + character, then remember it as the delimiter. */ + if (rl_basic_quote_characters && + strchr (rl_basic_quote_characters, scan) && + (end - rl_point) > 1) + delimiter = scan; + + /* If the character isn't needed to determine something special + about what kind of completion to perform, then advance past it. */ + if (rl_special_prefixes == 0 || strchr (rl_special_prefixes, scan) == 0) + rl_point++; + } + } + + if (fp) + *fp = found_quote; + if (dp) + *dp = delimiter; + + return (quote_char); +} + +static char ** +gen_completion_matches (text, start, end, our_func, found_quote, quote_char) + char *text; + int start, end; + rl_compentry_func_t *our_func; + int found_quote, quote_char; +{ + char **matches, *temp; + + /* If the user wants to TRY to complete, but then wants to give + up and use the default completion function, they set the + variable rl_attempted_completion_function. */ + if (rl_attempted_completion_function) + { + matches = (*rl_attempted_completion_function) (text, start, end); + + if (matches || rl_attempted_completion_over) + { + rl_attempted_completion_over = 0; + return (matches); + } + } + + /* Beware -- we're stripping the quotes here. Do this only if we know + we are doing filename completion and the application has defined a + filename dequoting function. */ + temp = (char *)NULL; + + if (found_quote && our_func == rl_filename_completion_function && + rl_filename_dequoting_function) + { + /* delete single and double quotes */ + temp = (*rl_filename_dequoting_function) (text, quote_char); + text = temp; /* not freeing text is not a memory leak */ + } + + matches = rl_completion_matches (text, our_func); + FREE (temp); + return matches; +} + +/* Filter out duplicates in MATCHES. This frees up the strings in + MATCHES. */ +static char ** +remove_duplicate_matches (matches) + char **matches; +{ + char *lowest_common; + int i, j, newlen; + char dead_slot; + char **temp_array; + + /* Sort the items. */ + for (i = 0; matches[i]; i++) + ; + + /* Sort the array without matches[0], since we need it to + stay in place no matter what. */ + if (i) + qsort (matches+1, i-1, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); + + /* Remember the lowest common denominator for it may be unique. */ + lowest_common = savestring (matches[0]); + + for (i = newlen = 0; matches[i + 1]; i++) + { + if (strcmp (matches[i], matches[i + 1]) == 0) + { + free (matches[i]); + matches[i] = (char *)&dead_slot; + } + else + newlen++; + } + + /* We have marked all the dead slots with (char *)&dead_slot. + Copy all the non-dead entries into a new array. */ + temp_array = (char **)xmalloc ((3 + newlen) * sizeof (char *)); + for (i = j = 1; matches[i]; i++) + { + if (matches[i] != (char *)&dead_slot) + temp_array[j++] = matches[i]; + } + temp_array[j] = (char *)NULL; + + if (matches[0] != (char *)&dead_slot) + free (matches[0]); + + /* Place the lowest common denominator back in [0]. */ + temp_array[0] = lowest_common; + + /* If there is one string left, and it is identical to the + lowest common denominator, then the LCD is the string to + insert. */ + if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0) + { + free (temp_array[1]); + temp_array[1] = (char *)NULL; + } + return (temp_array); +} + +/* Find the common prefix of the list of matches, and put it into + matches[0]. */ +static int +compute_lcd_of_matches (match_list, matches, text) + char **match_list; + int matches; + const char *text; +{ + register int i, c1, c2, si; + int low; /* Count of max-matched characters. */ +#if defined (HANDLE_MULTIBYTE) + int v; + mbstate_t ps1, ps2; + wchar_t wc1, wc2; +#endif + + /* If only one match, just use that. Otherwise, compare each + member of the list with the next, finding out where they + stop matching. */ + if (matches == 1) + { + match_list[0] = match_list[1]; + match_list[1] = (char *)NULL; + return 1; + } + + for (i = 1, low = 100000; i < matches; i++) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps1, 0, sizeof (mbstate_t)); + memset (&ps2, 0, sizeof (mbstate_t)); + } +#endif + if (_rl_completion_case_fold) + { + for (si = 0; + (c1 = _rl_to_lower(match_list[i][si])) && + (c2 = _rl_to_lower(match_list[i + 1][si])); + si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); + mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); + wc1 = towlower (wc1); + wc2 = towlower (wc2); + if (wc1 != wc2) + break; + else if (v > 1) + si += v - 1; + } + else +#endif + if (c1 != c2) + break; + } + else + { + for (si = 0; + (c1 = match_list[i][si]) && + (c2 = match_list[i + 1][si]); + si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + mbstate_t ps_back = ps1; + if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2)) + break; + else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1) + si += v - 1; + } + else +#endif + if (c1 != c2) + break; + } + + if (low > si) + low = si; + } + + /* If there were multiple matches, but none matched up to even the + first character, and the user typed something, use that as the + value of matches[0]. */ + if (low == 0 && text && *text) + { + match_list[0] = (char *)xmalloc (strlen (text) + 1); + strcpy (match_list[0], text); + } + else + { + match_list[0] = (char *)xmalloc (low + 1); + + /* XXX - this might need changes in the presence of multibyte chars */ + + /* If we are ignoring case, try to preserve the case of the string + the user typed in the face of multiple matches differing in case. */ + if (_rl_completion_case_fold) + { + /* sort the list to get consistent answers. */ + qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare); + + si = strlen (text); + if (si <= low) + { + for (i = 1; i <= matches; i++) + if (strncmp (match_list[i], text, si) == 0) + { + strncpy (match_list[0], match_list[i], low); + break; + } + /* no casematch, use first entry */ + if (i > matches) + strncpy (match_list[0], match_list[1], low); + } + else + /* otherwise, just use the text the user typed. */ + strncpy (match_list[0], text, low); + } + else + strncpy (match_list[0], match_list[1], low); + + match_list[0][low] = '\0'; + } + + return matches; +} + +static int +postprocess_matches (matchesp, matching_filenames) + char ***matchesp; + int matching_filenames; +{ + char *t, **matches, **temp_matches; + int nmatch, i; + + matches = *matchesp; + + if (matches == 0) + return 0; + + /* It seems to me that in all the cases we handle we would like + to ignore duplicate possiblilities. Scan for the text to + insert being identical to the other completions. */ + if (rl_ignore_completion_duplicates) + { + temp_matches = remove_duplicate_matches (matches); + free (matches); + matches = temp_matches; + } + + /* If we are matching filenames, then here is our chance to + do clever processing by re-examining the list. Call the + ignore function with the array as a parameter. It can + munge the array, deleting matches as it desires. */ + if (rl_ignore_some_completions_function && matching_filenames) + { + for (nmatch = 1; matches[nmatch]; nmatch++) + ; + (void)(*rl_ignore_some_completions_function) (matches); + if (matches == 0 || matches[0] == 0) + { + FREE (matches); + *matchesp = (char **)0; + return 0; + } + else + { + /* If we removed some matches, recompute the common prefix. */ + for (i = 1; matches[i]; i++) + ; + if (i > 1 && i < nmatch) + { + t = matches[0]; + compute_lcd_of_matches (matches, i - 1, t); + FREE (t); + } + } + } + + *matchesp = matches; + return (1); +} + +/* A convenience function for displaying a list of strings in + columnar format on readline's output stream. MATCHES is the list + of strings, in argv format, LEN is the number of strings in MATCHES, + and MAX is the length of the longest string in MATCHES. */ +void +rl_display_match_list (matches, len, max) + char **matches; + int len, max; +{ + int count, limit, printed_len, lines; + int i, j, k, l; + char *temp; + + /* How many items of MAX length can we fit in the screen window? */ + max += 2; + limit = _rl_screenwidth / max; + if (limit != 1 && (limit * max == _rl_screenwidth)) + limit--; + + /* Avoid a possible floating exception. If max > _rl_screenwidth, + limit will be 0 and a divide-by-zero fault will result. */ + if (limit == 0) + limit = 1; + + /* How many iterations of the printing loop? */ + count = (len + (limit - 1)) / limit; + + /* Watch out for special case. If LEN is less than LIMIT, then + just do the inner printing loop. + 0 < len <= limit implies count = 1. */ + + /* Sort the items if they are not already sorted. */ + if (rl_ignore_completion_duplicates == 0) + qsort (matches + 1, len, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); + + rl_crlf (); + + lines = 0; + if (_rl_print_completions_horizontally == 0) + { + /* Print the sorted items, up-and-down alphabetically, like ls. */ + for (i = 1; i <= count; i++) + { + for (j = 0, l = i; j < limit; j++) + { + if (l > len || matches[l] == 0) + break; + else + { + temp = printable_part (matches[l]); + printed_len = print_filename (temp, matches[l]); + + if (j + 1 < limit) + for (k = 0; k < max - printed_len; k++) + putc (' ', rl_outstream); + } + l += count; + } + rl_crlf (); + lines++; + if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count) + { + lines = _rl_internal_pager (lines); + if (lines < 0) + return; + } + } + } + else + { + /* Print the sorted items, across alphabetically, like ls -x. */ + for (i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + printed_len = print_filename (temp, matches[i]); + /* Have we reached the end of this line? */ + if (matches[i+1]) + { + if (i && (limit > 1) && (i % limit) == 0) + { + rl_crlf (); + lines++; + if (_rl_page_completions && lines >= _rl_screenheight - 1) + { + lines = _rl_internal_pager (lines); + if (lines < 0) + return; + } + } + else + for (k = 0; k < max - printed_len; k++) + putc (' ', rl_outstream); + } + } + rl_crlf (); + } +} + +/* Display MATCHES, a list of matching filenames in argv format. This + handles the simple case -- a single match -- first. If there is more + than one match, we compute the number of strings in the list and the + length of the longest string, which will be needed by the display + function. If the application wants to handle displaying the list of + matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the + address of a function, and we just call it. If we're handling the + display ourselves, we just call rl_display_match_list. We also check + that the list of matches doesn't exceed the user-settable threshold, + and ask the user if he wants to see the list if there are more matches + than RL_COMPLETION_QUERY_ITEMS. */ +static void +display_matches (matches) + char **matches; +{ + int len, max, i; + char *temp; + + /* Move to the last visible line of a possibly-multiple-line command. */ + _rl_move_vert (_rl_vis_botlin); + + /* Handle simple case first. What if there is only one answer? */ + if (matches[1] == 0) + { + temp = printable_part (matches[0]); + rl_crlf (); + print_filename (temp, matches[0]); + rl_crlf (); + + rl_forced_update_display (); + rl_display_fixed = 1; + + return; + } + + /* There is more than one answer. Find out how many there are, + and find the maximum printed length of a single entry. */ + for (max = 0, i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + len = strlen (temp); + + if (len > max) + max = len; + } + + len = i - 1; + + /* If the caller has defined a display hook, then call that now. */ + if (rl_completion_display_matches_hook) + { + (*rl_completion_display_matches_hook) (matches, len, max); + return; + } + + /* If there are many items, then ask the user if she really wants to + see them all. */ + if (len >= rl_completion_query_items) + { + rl_crlf (); + fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); + fflush (rl_outstream); + if (get_y_or_n (0) == 0) + { + rl_crlf (); + + rl_forced_update_display (); + rl_display_fixed = 1; + + return; + } + } + + rl_display_match_list (matches, len, max); + + rl_forced_update_display (); + rl_display_fixed = 1; +} + +static char * +make_quoted_replacement (match, mtype, qc) + char *match; + int mtype; + char *qc; /* Pointer to quoting character, if any */ +{ + int should_quote, do_replace; + char *replacement; + + /* If we are doing completion on quoted substrings, and any matches + contain any of the completer_word_break_characters, then auto- + matically prepend the substring with a quote character (just pick + the first one from the list of such) if it does not already begin + with a quote string. FIXME: Need to remove any such automatically + inserted quote character when it no longer is necessary, such as + if we change the string we are completing on and the new set of + matches don't require a quoted substring. */ + replacement = match; + + should_quote = match && rl_completer_quote_characters && + rl_filename_completion_desired && + rl_filename_quoting_desired; + + if (should_quote) + should_quote = should_quote && (!qc || !*qc || + (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc))); + + if (should_quote) + { + /* If there is a single match, see if we need to quote it. + This also checks whether the common prefix of several + matches needs to be quoted. */ + should_quote = rl_filename_quote_characters + ? (_rl_strpbrk (match, rl_filename_quote_characters) != 0) + : 0; + + do_replace = should_quote ? mtype : NO_MATCH; + /* Quote the replacement, since we found an embedded + word break character in a potential match. */ + if (do_replace != NO_MATCH && rl_filename_quoting_function) + replacement = (*rl_filename_quoting_function) (match, do_replace, qc); + } + return (replacement); +} + +static void +insert_match (match, start, mtype, qc) + char *match; + int start, mtype; + char *qc; +{ + char *replacement; + char oqc; + + oqc = qc ? *qc : '\0'; + replacement = make_quoted_replacement (match, mtype, qc); + + /* Now insert the match. */ + if (replacement) + { + /* Don't double an opening quote character. */ + if (qc && *qc && start && rl_line_buffer[start - 1] == *qc && + replacement[0] == *qc) + start--; + /* If make_quoted_replacement changed the quoting character, remove + the opening quote and insert the (fully-quoted) replacement. */ + else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc && + replacement[0] != oqc) + start--; + _rl_replace_text (replacement, start, rl_point - 1); + if (replacement != match) + free (replacement); + } +} + +/* Append any necessary closing quote and a separator character to the + just-inserted match. If the user has specified that directories + should be marked by a trailing `/', append one of those instead. The + default trailing character is a space. Returns the number of characters + appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS + has them) and don't add a suffix for a symlink to a directory. A + nontrivial match is one that actually adds to the word being completed. + The variable rl_completion_mark_symlink_dirs controls this behavior + (it's initially set to the what the user has chosen, indicated by the + value of _rl_complete_mark_symlink_dirs, but may be modified by an + application's completion function). */ +static int +append_to_match (text, delimiter, quote_char, nontrivial_match) + char *text; + int delimiter, quote_char, nontrivial_match; +{ + char temp_string[4], *filename; + int temp_string_index, s; + struct stat finfo; + + temp_string_index = 0; + if (quote_char && rl_point && rl_line_buffer[rl_point - 1] != quote_char) + temp_string[temp_string_index++] = quote_char; + + if (delimiter) + temp_string[temp_string_index++] = delimiter; + else if (rl_completion_suppress_append == 0 && rl_completion_append_character) + temp_string[temp_string_index++] = rl_completion_append_character; + + temp_string[temp_string_index++] = '\0'; + + if (rl_filename_completion_desired) + { + filename = tilde_expand (text); + s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0) + ? LSTAT (filename, &finfo) + : stat (filename, &finfo); + if (s == 0 && S_ISDIR (finfo.st_mode)) + { + if (_rl_complete_mark_directories) + { + /* This is clumsy. Avoid putting in a double slash if point + is at the end of the line and the previous character is a + slash. */ + if (rl_point && rl_line_buffer[rl_point] == '\0' && rl_line_buffer[rl_point - 1] == '/') + ; + else if (rl_line_buffer[rl_point] != '/') + rl_insert_text ("/"); + } + } +#ifdef S_ISLNK + /* Don't add anything if the filename is a symlink and resolves to a + directory. */ + else if (s == 0 && S_ISLNK (finfo.st_mode) && + stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)) + ; +#endif + else + { + if (rl_point == rl_end && temp_string_index) + rl_insert_text (temp_string); + } + free (filename); + } + else + { + if (rl_point == rl_end && temp_string_index) + rl_insert_text (temp_string); + } + + return (temp_string_index); +} + +static void +insert_all_matches (matches, point, qc) + char **matches; + int point; + char *qc; +{ + int i; + char *rp; + + rl_begin_undo_group (); + /* remove any opening quote character; make_quoted_replacement will add + it back. */ + if (qc && *qc && point && rl_line_buffer[point - 1] == *qc) + point--; + rl_delete_text (point, rl_point); + rl_point = point; + + if (matches[1]) + { + for (i = 1; matches[i]; i++) + { + rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc); + rl_insert_text (rp); + rl_insert_text (" "); + if (rp != matches[i]) + free (rp); + } + } + else + { + rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc); + rl_insert_text (rp); + rl_insert_text (" "); + if (rp != matches[0]) + free (rp); + } + rl_end_undo_group (); +} + +void +_rl_free_match_list (matches) + char **matches; +{ + register int i; + + if (matches == 0) + return; + + for (i = 0; matches[i]; i++) + free (matches[i]); + free (matches); +} + +/* Complete the word at or before point. + WHAT_TO_DO says what to do with the completion. + `?' means list the possible completions. + TAB means do standard completion. + `*' means insert all of the possible completions. + `!' means to do standard completion, and list all possible completions if + there is more than one. */ +int +rl_complete_internal (what_to_do) + int what_to_do; +{ + char **matches; + rl_compentry_func_t *our_func; + int start, end, delimiter, found_quote, i, nontrivial_lcd; + char *text, *saved_line_buffer; + char quote_char; + + RL_SETSTATE(RL_STATE_COMPLETING); + + set_completion_defaults (what_to_do); + + saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : rl_filename_completion_function; + + /* We now look backwards for the start of a filename/variable word. */ + end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_point) + /* This (possibly) changes rl_point. If it returns a non-zero char, + we know we have an open quote. */ + quote_char = _rl_find_completion_word (&found_quote, &delimiter); + + start = rl_point; + rl_point = end; + + text = rl_copy_text (start, end); + matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char); + /* nontrivial_lcd is set if the common prefix adds something to the word + being completed. */ + nontrivial_lcd = matches && strcmp (text, matches[0]) != 0; + free (text); + + if (matches == 0) + { + rl_ding (); + FREE (saved_line_buffer); + completion_changed_buffer = 0; + RL_UNSETSTATE(RL_STATE_COMPLETING); + return (0); + } + + /* If we are matching filenames, the attempted completion function will + have set rl_filename_completion_desired to a non-zero value. The basic + rl_filename_completion_function does this. */ + i = rl_filename_completion_desired; + + if (postprocess_matches (&matches, i) == 0) + { + rl_ding (); + FREE (saved_line_buffer); + completion_changed_buffer = 0; + RL_UNSETSTATE(RL_STATE_COMPLETING); + return (0); + } + + switch (what_to_do) + { + case TAB: + case '!': + /* Insert the first match with proper quoting. */ + if (*matches[0]) + insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); + + /* If there are more matches, ring the bell to indicate. + If we are in vi mode, Posix.2 says to not ring the bell. + If the `show-all-if-ambiguous' variable is set, display + all the matches immediately. Otherwise, if this was the + only match, and we are hacking files, check the file to + see if it was a directory. If so, and the `mark-directories' + variable is set, add a '/' to the name. If not, and we + are at the end of the line, then add a space. */ + if (matches[1]) + { + if (what_to_do == '!') + { + display_matches (matches); + break; + } + else if (rl_editing_mode != vi_mode) + rl_ding (); /* There are other matches remaining. */ + } + else + append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); + + break; + + case '*': + insert_all_matches (matches, start, "e_char); + break; + + case '?': + display_matches (matches); + break; + + default: + fprintf (stderr, "\r\nreadline: bad value %d for what_to_do in rl_complete\n", what_to_do); + rl_ding (); + FREE (saved_line_buffer); + RL_UNSETSTATE(RL_STATE_COMPLETING); + return 1; + } + + _rl_free_match_list (matches); + + /* Check to see if the line has changed through all of this manipulation. */ + if (saved_line_buffer) + { + completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0; + free (saved_line_buffer); + } + + RL_UNSETSTATE(RL_STATE_COMPLETING); + return 0; +} + +/***************************************************************/ +/* */ +/* Application-callable completion match generator functions */ +/* */ +/***************************************************************/ + +/* Return an array of (char *) which is a list of completions for TEXT. + If there are no completions, return a NULL pointer. + The first entry in the returned array is the substitution for TEXT. + The remaining entries are the possible completions. + The array is terminated with a NULL pointer. + + ENTRY_FUNCTION is a function of two args, and returns a (char *). + The first argument is TEXT. + The second is a state argument; it should be zero on the first call, and + non-zero on subsequent calls. It returns a NULL pointer to the caller + when there are no more matches. + */ +char ** +rl_completion_matches (text, entry_function) + const char *text; + rl_compentry_func_t *entry_function; +{ + /* Number of slots in match_list. */ + int match_list_size; + + /* The list of matches. */ + char **match_list; + + /* Number of matches actually found. */ + int matches; + + /* Temporary string binder. */ + char *string; + + matches = 0; + match_list_size = 10; + match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); + match_list[1] = (char *)NULL; + + while ((string = (*entry_function) (text, matches))) + { + if (matches + 1 == match_list_size) + match_list = (char **)xrealloc + (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + + match_list[++matches] = string; + match_list[matches + 1] = (char *)NULL; + } + + /* If there were any matches, then look through them finding out the + lowest common denominator. That then becomes match_list[0]. */ + if (matches) + compute_lcd_of_matches (match_list, matches, text); + else /* There were no matches. */ + { + free (match_list); + match_list = (char **)NULL; + } + return (match_list); +} + +/* A completion function for usernames. + TEXT contains a partial username preceded by a random + character (usually `~'). */ +char * +rl_username_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) + return (char *)NULL; +#else /* !__WIN32__ && !__OPENNT) */ + static char *username = (char *)NULL; + static struct passwd *entry; + static int namelen, first_char, first_char_loc; + char *value; + + if (state == 0) + { + FREE (username); + + first_char = *text; + first_char_loc = first_char == '~'; + + username = savestring (&text[first_char_loc]); + namelen = strlen (username); + setpwent (); + } + + while ((entry = getpwent ())) + { + /* Null usernames should result in all users as possible completions. */ + if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) + break; + } + + if (entry == 0) + { + endpwent (); + return ((char *)NULL); + } + else + { + value = (char *)xmalloc (2 + strlen (entry->pw_name)); + + *value = *text; + + strcpy (value + first_char_loc, entry->pw_name); + + if (first_char == '~') + rl_filename_completion_desired = 1; + + return (value); + } +#endif /* !__WIN32__ && !__OPENNT */ +} + +/* Okay, now we write the entry_function for filename completion. In the + general case. Note that completion in the shell is a little different + because of all the pathnames that must be followed when looking up the + completion for a command. */ +char * +rl_filename_completion_function (text, state) + const char *text; + int state; +{ + static DIR *directory = (DIR *)NULL; + static char *filename = (char *)NULL; + static char *dirname = (char *)NULL; + static char *users_dirname = (char *)NULL; + static int filename_len; + char *temp; + int dirlen; + struct dirent *entry; + + /* If we don't have any state, then do some initialization. */ + if (state == 0) + { + /* If we were interrupted before closing the directory or reading + all of its contents, close it. */ + if (directory) + { + closedir (directory); + directory = (DIR *)NULL; + } + FREE (dirname); + FREE (filename); + FREE (users_dirname); + + filename = savestring (text); + if (*text == 0) + text = "."; + dirname = savestring (text); + + temp = strrchr (dirname, '/'); + +#if defined (__MSDOS__) + /* special hack for //X/... */ + if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/') + temp = strrchr (dirname + 3, '/'); +#endif + + if (temp) + { + strcpy (filename, ++temp); + *temp = '\0'; + } +#if defined (__MSDOS__) + /* searches from current directory on the drive */ + else if (ISALPHA ((unsigned char)dirname[0]) && dirname[1] == ':') + { + strcpy (filename, dirname + 2); + dirname[2] = '\0'; + } +#endif + else + { + dirname[0] = '.'; + dirname[1] = '\0'; + } + + /* We aren't done yet. We also support the "~user" syntax. */ + + /* Save the version of the directory that the user typed. */ + users_dirname = savestring (dirname); + + if (*dirname == '~') + { + temp = tilde_expand (dirname); + free (dirname); + dirname = temp; + } + + if (rl_directory_rewrite_hook) + (*rl_directory_rewrite_hook) (&dirname); + + if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) + { + free (users_dirname); + users_dirname = savestring (dirname); + } + + directory = opendir (dirname); + filename_len = strlen (filename); + + rl_filename_completion_desired = 1; + } + + /* At this point we should entertain the possibility of hacking wildcarded + filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name + contains globbing characters, then build an array of directories, and + then map over that list while completing. */ + /* *** UNIMPLEMENTED *** */ + + /* Now that we have some state, we can read the directory. */ + + entry = (struct dirent *)NULL; + while (directory && (entry = readdir (directory))) + { + /* Special case for no filename. If the user has disabled the + `match-hidden-files' variable, skip filenames beginning with `.'. + All other entries except "." and ".." match. */ + if (filename_len == 0) + { + if (_rl_match_hidden_files == 0 && HIDDEN_FILE (entry->d_name)) + continue; + + if (entry->d_name[0] != '.' || + (entry->d_name[1] && + (entry->d_name[1] != '.' || entry->d_name[2]))) + break; + } + else + { + /* Otherwise, if these match up to the length of filename, then + it is a match. */ + if (_rl_completion_case_fold) + { + if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) && + (((int)D_NAMLEN (entry)) >= filename_len) && + (_rl_strnicmp (filename, entry->d_name, filename_len) == 0)) + break; + } + else + { + if ((entry->d_name[0] == filename[0]) && + (((int)D_NAMLEN (entry)) >= filename_len) && + (strncmp (filename, entry->d_name, filename_len) == 0)) + break; + } + } + } + + if (entry == 0) + { + if (directory) + { + closedir (directory); + directory = (DIR *)NULL; + } + if (dirname) + { + free (dirname); + dirname = (char *)NULL; + } + if (filename) + { + free (filename); + filename = (char *)NULL; + } + if (users_dirname) + { + free (users_dirname); + users_dirname = (char *)NULL; + } + + return (char *)NULL; + } + else + { + /* dirname && (strcmp (dirname, ".") != 0) */ + if (dirname && (dirname[0] != '.' || dirname[1])) + { + if (rl_complete_with_tilde_expansion && *users_dirname == '~') + { + dirlen = strlen (dirname); + temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); + strcpy (temp, dirname); + /* Canonicalization cuts off any final slash present. We + may need to add it back. */ + if (dirname[dirlen - 1] != '/') + { + temp[dirlen++] = '/'; + temp[dirlen] = '\0'; + } + } + else + { + dirlen = strlen (users_dirname); + temp = (char *)xmalloc (2 + dirlen + D_NAMLEN (entry)); + strcpy (temp, users_dirname); + /* Make sure that temp has a trailing slash here. */ + if (users_dirname[dirlen - 1] != '/') + temp[dirlen++] = '/'; + } + + strcpy (temp + dirlen, entry->d_name); + } + else + temp = savestring (entry->d_name); + + return (temp); + } +} + +/* An initial implementation of a menu completion function a la tcsh. The + first time (if the last readline command was not rl_menu_complete), we + generate the list of matches. This code is very similar to the code in + rl_complete_internal -- there should be a way to combine the two. Then, + for each item in the list of matches, we insert the match in an undoable + fashion, with the appropriate character appended (this happens on the + second and subsequent consecutive calls to rl_menu_complete). When we + hit the end of the match list, we restore the original unmatched text, + ring the bell, and reset the counter to zero. */ +int +rl_menu_complete (count, ignore) + int count, ignore __attribute__((unused)); +{ + rl_compentry_func_t *our_func; + int matching_filenames, found_quote; + + static char *orig_text; + static char **matches = (char **)0; + static int match_list_index = 0; + static int match_list_size = 0; + static int orig_start, orig_end; + static char quote_char; + static int delimiter; + + /* The first time through, we generate the list of matches and set things + up to insert them. */ + if (rl_last_func != rl_menu_complete) + { + /* Clean up from previous call, if any. */ + FREE (orig_text); + if (matches) + _rl_free_match_list (matches); + + match_list_index = match_list_size = 0; + matches = (char **)NULL; + + /* Only the completion entry function can change these. */ + set_completion_defaults ('%'); + + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : rl_filename_completion_function; + + /* We now look backwards for the start of a filename/variable word. */ + orig_end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_point) + /* This (possibly) changes rl_point. If it returns a non-zero char, + we know we have an open quote. */ + quote_char = _rl_find_completion_word (&found_quote, &delimiter); + + orig_start = rl_point; + rl_point = orig_end; + + orig_text = rl_copy_text (orig_start, orig_end); + matches = gen_completion_matches (orig_text, orig_start, orig_end, + our_func, found_quote, quote_char); + + /* If we are matching filenames, the attempted completion function will + have set rl_filename_completion_desired to a non-zero value. The basic + rl_filename_completion_function does this. */ + matching_filenames = rl_filename_completion_desired; + + if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) + { + rl_ding (); + FREE (matches); + matches = (char **)0; + FREE (orig_text); + orig_text = (char *)0; + completion_changed_buffer = 0; + return (0); + } + + for (match_list_size = 0; matches[match_list_size]; match_list_size++) + ; + /* matches[0] is lcd if match_list_size > 1, but the circular buffer + code below should take care of it. */ + } + + /* Now we have the list of matches. Replace the text between + rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with + matches[match_list_index], and add any necessary closing char. */ + + if (matches == 0 || match_list_size == 0) + { + rl_ding (); + FREE (matches); + matches = (char **)0; + completion_changed_buffer = 0; + return (0); + } + + match_list_index = (match_list_index + count) % match_list_size; + if (match_list_index < 0) + match_list_index += match_list_size; + + if (match_list_index == 0 && match_list_size > 1) + { + rl_ding (); + insert_match (orig_text, orig_start, MULT_MATCH, "e_char); + } + else + { + insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char); + append_to_match (matches[match_list_index], delimiter, quote_char, + strcmp (orig_text, matches[match_list_index])); + } + + completion_changed_buffer = 1; + return (0); +} diff --git a/cmd-line-utils/readline/configure.in b/cmd-line-utils/readline/configure.in new file mode 100644 index 00000000000..bc78f8a0f60 --- /dev/null +++ b/cmd-line-utils/readline/configure.in @@ -0,0 +1,206 @@ +dnl +dnl Configure script for readline library +dnl +dnl report bugs to chet@po.cwru.edu +dnl +dnl Process this file with autoconf to produce a configure script. +AC_REVISION([for Readline 4.3, version 2.45, from autoconf version] AC_ACVERSION) + +AC_INIT(readline, 4.3, bug-readline@gnu.org) + +dnl make sure we are using a recent autoconf version +AC_PREREQ(2.50) + +AC_CONFIG_SRCDIR(readline.h) +AC_CONFIG_AUX_DIR(./support) +AC_CONFIG_HEADERS(config.h) + +dnl update the value of RL_READLINE_VERSION in readline.h when this changes +LIBVERSION=4.3 + +AC_CANONICAL_HOST + +dnl configure defaults +opt_curses=no + +dnl arguments to configure +AC_ARG_WITH(curses, AC_HELP_STRING([--with-curses], [use the curses library instead of the termcap library]), opt_curses=$withval) + +if test "$opt_curses" = "yes"; then + prefer_curses=yes +fi + +dnl option parsing for optional features +opt_static_libs=yes +opt_shared_libs=yes + +AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build shared libraries [[default=YES]]]), opt_shared_libs=$enableval) +AC_ARG_ENABLE(static, AC_HELP_STRING([--enable-static], [build static libraries [[default=YES]]]), opt_static_libs=$enableval) + +echo "" +echo "Beginning configuration for readline-$LIBVERSION for ${host_cpu}-${host_vendor}-${host_os}" +echo "" + +# We want these before the checks, so the checks can modify their values. +test -z "$CFLAGS" && CFLAGS=-g auto_cflags=1 + +AC_PROG_MAKE_SET +AC_PROG_CC +dnl AC_AIX +AC_MINIX + +# If we're using gcc and the user hasn't specified CFLAGS, add -O to CFLAGS. +test -n "$GCC" && test -n "$auto_cflags" && CFLAGS="$CFLAGS -O" + +AC_PROG_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_CHECK_PROG(AR, ar, , ar) +dnl Set default for ARFLAGS, since autoconf does not have a macro for it. +dnl This allows people to set it when running configure or make +test -n "$ARFLAGS" || ARFLAGS="cr" +AC_PROG_RANLIB + +MAKE_SHELL=/bin/sh +AC_SUBST(MAKE_SHELL) + +AC_C_CONST +AC_C_PROTOTYPES +AC_C_CHAR_UNSIGNED + +AC_TYPE_SIGNAL + +AC_TYPE_SIZE_T +AC_CHECK_TYPE(ssize_t, int) + +AC_HEADER_STAT +AC_HEADER_DIRENT + +AC_CHECK_FUNCS(lstat memmove putenv select setenv setlocale \ + strcasecmp strpbrk tcgetattr vsnprintf isascii isxdigit) + +AC_FUNC_STRCOLL + +AC_CHECK_HEADERS(unistd.h stdlib.h varargs.h stdarg.h string.h strings.h \ + limits.h sys/ptem.h sys/pte.h sys/stream.h sys/select.h \ + termcap.h termios.h termio.h sys/file.h locale.h memory.h ) + +BASH_SYS_SIGNAL_VINTAGE +BASH_SYS_REINSTALL_SIGHANDLERS + +BASH_FUNC_POSIX_SETJMP +BASH_FUNC_LSTAT +BASH_FUNC_STRCOLL + +BASH_CHECK_GETPW_FUNCS + +AC_HEADER_TIOCGWINSZ + +BASH_TYPE_SIGHANDLER +BASH_HAVE_TIOCSTAT +BASH_HAVE_FIONREAD +BASH_CHECK_SPEED_T +BASH_STRUCT_WINSIZE +BASH_STRUCT_DIRENT_D_INO +BASH_STRUCT_DIRENT_D_FILENO + +dnl yuck +case "$host_os" in +aix*) prefer_curses=yes ;; +esac +BASH_CHECK_LIB_TERMCAP +if test "$TERMCAP_LIB" = "./lib/termcap/libtermcap.a"; then + if test "$prefer_curses" = yes; then + TERMCAP_LIB=-lcurses + else + TERMCAP_LIB=-ltermcap #default + fi +fi + +BASH_CHECK_MULTIBYTE + +case "$host_cpu" in +*cray*) LOCAL_CFLAGS=-DCRAY ;; +*s390*) LOCAL_CFLAGS=-fsigned-char ;; +esac + +case "$host_os" in +isc*) LOCAL_CFLAGS=-Disc386 ;; +esac + +# shared library configuration section +# +# Shared object configuration section. These values are generated by +# ${srcdir}/support/shobj-conf +# +if test -f ${srcdir}/support/shobj-conf; then + AC_MSG_CHECKING(configuration for building shared libraries) + eval `${CONFIG_SHELL-/bin/sh} ${srcdir}/support/shobj-conf -C "${CC}" -c ${host_cpu} -o ${host_os} -v ${host_vendor}` + AC_SUBST(SHOBJ_CC) + AC_SUBST(SHOBJ_CFLAGS) + AC_SUBST(SHOBJ_LD) + AC_SUBST(SHOBJ_LDFLAGS) + AC_SUBST(SHOBJ_XLDFLAGS) + AC_SUBST(SHOBJ_LIBS) + AC_SUBST(SHOBJ_STATUS) + AC_SUBST(SHLIB_STATUS) + AC_SUBST(SHLIB_XLDFLAGS) + AC_SUBST(SHLIB_LIBSUFF) + AC_SUBST(SHLIB_LIBVERSION) + AC_SUBST(SHLIB_LIBS) + AC_MSG_RESULT($SHLIB_STATUS) + + # SHLIB_STATUS is either `supported' or `unsupported'. If it's + # `unsupported', turn off any default shared library building + if test "$SHLIB_STATUS" = 'unsupported'; then + opt_shared_libs=no + fi + + # shared library versioning + # quoted for m4 so I can use character classes + SHLIB_MAJOR=[`expr "$LIBVERSION" : '\([0-9]\)\..*'`] + SHLIB_MINOR=[`expr "$LIBVERSION" : '[0-9]\.\([0-9]\).*'`] + AC_SUBST(SHLIB_MAJOR) + AC_SUBST(SHLIB_MINOR) +fi + +if test "$opt_static_libs" = "yes"; then + STATIC_TARGET=static + STATIC_INSTALL_TARGET=install-static +fi +if test "$opt_shared_libs" = "yes"; then + SHARED_TARGET=shared + SHARED_INSTALL_TARGET=install-shared +fi + +AC_SUBST(STATIC_TARGET) +AC_SUBST(SHARED_TARGET) +AC_SUBST(STATIC_INSTALL_TARGET) +AC_SUBST(SHARED_INSTALL_TARGET) + +case "$host_os" in +msdosdjgpp*) BUILD_DIR=`pwd.exe` ;; # to prevent //d/path/file +*) BUILD_DIR=`pwd` ;; +esac + +AC_SUBST(BUILD_DIR) + +AC_SUBST(CFLAGS) +AC_SUBST(LOCAL_CFLAGS) +AC_SUBST(LOCAL_LDFLAGS) +AC_SUBST(LOCAL_DEFS) + +AC_SUBST(AR) +AC_SUBST(ARFLAGS) + +AC_SUBST(host_cpu) +AC_SUBST(host_os) + +AC_SUBST(LIBVERSION) + +AC_SUBST(TERMCAP_LIB) + +AC_OUTPUT([Makefile doc/Makefile examples/Makefile shlib/Makefile], +[ +# Makefile uses this timestamp file to record whether config.h is up to date. +echo > stamp-h +]) diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c new file mode 100644 index 00000000000..f393e7e8516 --- /dev/null +++ b/cmd-line-utils/readline/display.c @@ -0,0 +1,2198 @@ +/* display.c -- readline redisplay facility. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include "posixstat.h" + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Termcap library stuff. */ +#include "tcap.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#if defined (HACK_TERMCAP_MOTION) +extern char *_rl_term_forward_char; +#endif + +static void update_line PARAMS((char *, char *, int, int, int, int)); +static void space_to_eol PARAMS((int)); +static void delete_chars PARAMS((int)); +static void insert_some_chars PARAMS((char *, int, int)); +static void cr PARAMS((void)); + +#if defined (HANDLE_MULTIBYTE) +static int _rl_col_width PARAMS((const char *, int, int)); +static int *_rl_wrapped_line; +#else +# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s)) +#endif + +static int *inv_lbreaks, *vis_lbreaks; +static int inv_lbsize, vis_lbsize; + +/* Heuristic used to decide whether it is faster to move from CUR to NEW + by backing up or outputting a carriage return and moving forward. */ +#define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new))) + +/* **************************************************************** */ +/* */ +/* Display stuff */ +/* */ +/* **************************************************************** */ + +/* This is the stuff that is hard for me. I never seem to write good + display routines in C. Let's see how I do this time. */ + +/* (PWP) Well... Good for a simple line updater, but totally ignores + the problems of input lines longer than the screen width. + + update_line and the code that calls it makes a multiple line, + automatically wrapping line update. Careful attention needs + to be paid to the vertical position variables. */ + +/* Keep two buffers; one which reflects the current contents of the + screen, and the other to draw what we think the new contents should + be. Then compare the buffers, and make whatever changes to the + screen itself that we should. Finally, make the buffer that we + just drew into be the one which reflects the current contents of the + screen, and place the cursor where it belongs. + + Commands that want to can fix the display themselves, and then let + this function know that the display has been fixed by setting the + RL_DISPLAY_FIXED variable. This is good for efficiency. */ + +/* Application-specific redisplay function. */ +rl_voidfunc_t *rl_redisplay_function = rl_redisplay; + +/* Global variables declared here. */ +/* What YOU turn on when you have handled all redisplay yourself. */ +int rl_display_fixed = 0; + +int _rl_suppress_redisplay = 0; + +/* The stuff that gets printed out before the actual text of the line. + This is usually pointing to rl_prompt. */ +const char *rl_display_prompt = (char *)NULL; + +/* Pseudo-global variables declared here. */ +/* The visible cursor position. If you print some text, adjust this. */ +int _rl_last_c_pos = 0; +int _rl_last_v_pos = 0; + +/* Number of lines currently on screen minus 1. */ +int _rl_vis_botlin = 0; + +/* Variables used only in this file. */ +/* The last left edge of text that was displayed. This is used when + doing horizontal scrolling. It shifts in thirds of a screenwidth. */ +static int last_lmargin; + +/* The line display buffers. One is the line currently displayed on + the screen. The other is the line about to be displayed. */ +static char *visible_line = (char *)NULL; +static char *invisible_line = (char *)NULL; + +/* A buffer for `modeline' messages. */ +static char msg_buf[128]; + +/* Non-zero forces the redisplay even if we thought it was unnecessary. */ +static int forced_display; + +/* Default and initial buffer size. Can grow. */ +static int line_size = 1024; + +/* Variables to keep track of the expanded prompt string, which may + include invisible characters. */ + +static char *local_prompt, *local_prompt_prefix; +static int prompt_visible_length, prompt_prefix_length; + +/* The number of invisible characters in the line currently being + displayed on the screen. */ +static int visible_wrap_offset; + +/* The number of invisible characters in the prompt string. Static so it + can be shared between rl_redisplay and update_line */ +static int wrap_offset; + +/* The index of the last invisible character in the prompt string. */ +static int prompt_last_invisible; + +/* The length (buffer offset) of the first line of the last (possibly + multi-line) buffer displayed on the screen. */ +static int visible_first_line_len; + +/* Number of invisible characters on the first physical line of the prompt. + Only valid when the number of physical characters in the prompt exceeds + (or is equal to) _rl_screenwidth. */ +static int prompt_invis_chars_first_line; + +static int prompt_last_screen_line; + +/* Expand the prompt string S and return the number of visible + characters in *LP, if LP is not null. This is currently more-or-less + a placeholder for expansion. LIP, if non-null is a place to store the + index of the last invisible character in the returned string. NIFLP, + if non-zero, is a place to store the number of invisible characters in + the first prompt line. */ + +/* Current implementation: + \001 (^A) start non-visible characters + \002 (^B) end non-visible characters + all characters except \001 and \002 (following a \001) are copied to + the returned string; all characters except those between \001 and + \002 are assumed to be `visible'. */ + +static char * +expand_prompt (pmt, lp, lip, niflp) + char *pmt; + int *lp, *lip, *niflp; +{ + char *r, *ret, *p; + int l, rl, last, ignoring, ninvis, invfl; + + /* Short-circuit if we can. */ + if (strchr (pmt, RL_PROMPT_START_IGNORE) == 0) + { + r = savestring (pmt); + if (lp) + *lp = strlen (r); + return r; + } + + l = strlen (pmt); + r = ret = (char *)xmalloc (l + 1); + + invfl = 0; /* invisible chars in first line of prompt */ + + for (rl = ignoring = last = ninvis = 0, p = pmt; p && *p; p++) + { + /* This code strips the invisible character string markers + RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */ + if (*p == RL_PROMPT_START_IGNORE) + { + ignoring++; + continue; + } + else if (ignoring && *p == RL_PROMPT_END_IGNORE) + { + ignoring = 0; + last = r - ret - 1; + continue; + } + else + { + *r++ = *p; + if (!ignoring) + rl++; + else + ninvis++; + if (rl == _rl_screenwidth) + invfl = ninvis; + } + } + + if (rl < _rl_screenwidth) + invfl = ninvis; + + *r = '\0'; + if (lp) + *lp = rl; + if (lip) + *lip = last; + if (niflp) + *niflp = invfl; + return ret; +} + +/* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from + PMT and return the rest of PMT. */ +char * +_rl_strip_prompt (pmt) + char *pmt; +{ + char *ret; + + ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL); + return ret; +} + +/* + * Expand the prompt string into the various display components, if + * necessary. + * + * local_prompt = expanded last line of string in rl_display_prompt + * (portion after the final newline) + * local_prompt_prefix = portion before last newline of rl_display_prompt, + * expanded via expand_prompt + * prompt_visible_length = number of visible characters in local_prompt + * prompt_prefix_length = number of visible characters in local_prompt_prefix + * + * This function is called once per call to readline(). It may also be + * called arbitrarily to expand the primary prompt. + * + * The return value is the number of visible characters on the last line + * of the (possibly multi-line) prompt. + */ +int +rl_expand_prompt (prompt) + char *prompt; +{ + char *p, *t; + int c; + + /* Clear out any saved values. */ + FREE (local_prompt); + FREE (local_prompt_prefix); + + local_prompt = local_prompt_prefix = (char *)0; + prompt_last_invisible = prompt_visible_length = 0; + + if (prompt == 0 || *prompt == 0) + return (0); + + p = strrchr (prompt, '\n'); + if (!p) + { + /* The prompt is only one logical line, though it might wrap. */ + local_prompt = expand_prompt (prompt, &prompt_visible_length, + &prompt_last_invisible, + &prompt_invis_chars_first_line); + local_prompt_prefix = (char *)0; + return (prompt_visible_length); + } + else + { + /* The prompt spans multiple lines. */ + t = ++p; + local_prompt = expand_prompt (p, &prompt_visible_length, + &prompt_last_invisible, + &prompt_invis_chars_first_line); + c = *t; *t = '\0'; + /* The portion of the prompt string up to and including the + final newline is now null-terminated. */ + local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length, + (int *)NULL, + &prompt_invis_chars_first_line); + *t = c; + return (prompt_prefix_length); + } +} + +/* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated + arrays of line break markers. MINSIZE is the minimum size of VISIBLE_LINE + and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is + increased. If the lines have already been allocated, this ensures that + they can hold at least MINSIZE characters. */ +static void +init_line_structures (minsize) + int minsize; +{ + register int n; + + if (invisible_line == 0) /* initialize it */ + { + if (line_size < minsize) + line_size = minsize; + visible_line = (char *)xmalloc (line_size); + invisible_line = (char *)xmalloc (line_size); + } + else if (line_size < minsize) /* ensure it can hold MINSIZE chars */ + { + line_size *= 2; + if (line_size < minsize) + line_size = minsize; + visible_line = (char *)xrealloc (visible_line, line_size); + invisible_line = (char *)xrealloc (invisible_line, line_size); + } + + for (n = minsize; n < line_size; n++) + { + visible_line[n] = 0; + invisible_line[n] = 1; + } + + if (vis_lbreaks == 0) + { + /* should be enough. */ + inv_lbsize = vis_lbsize = 256; + inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int)); + vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int)); +#if defined (HANDLE_MULTIBYTE) + _rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int)); +#endif + inv_lbreaks[0] = vis_lbreaks[0] = 0; + } +} + +/* Basic redisplay algorithm. */ +void +rl_redisplay () +{ + register int in, out, c, linenum, cursor_linenum; + register char *line; + int c_pos, inv_botlin, lb_botlin, lb_linenum; + int newlines, lpos, temp; + const char *prompt_this_line; +#if defined (HANDLE_MULTIBYTE) + wchar_t wc; + size_t wc_bytes; + int wc_width; + mbstate_t ps; + int _rl_wrapped_multicolumn = 0; +#endif + + if (!readline_echoing_p) + return; + + if (!rl_display_prompt) + rl_display_prompt = ""; + + if (invisible_line == 0) + { + init_line_structures (0); + rl_on_new_line (); + } + + /* Draw the line into the buffer. */ + c_pos = -1; + + line = invisible_line; + out = inv_botlin = 0; + + /* Mark the line as modified or not. We only do this for history + lines. */ + if (_rl_mark_modified_lines && current_history () && rl_undo_list) + { + line[out++] = '*'; + line[out] = '\0'; + } + + /* If someone thought that the redisplay was handled, but the currently + visible line has a different modification state than the one about + to become visible, then correct the caller's misconception. */ + if (visible_line[0] != invisible_line[0]) + rl_display_fixed = 0; + + /* If the prompt to be displayed is the `primary' readline prompt (the + one passed to readline()), use the values we have already expanded. + If not, use what's already in rl_display_prompt. WRAP_OFFSET is the + number of non-visible characters in the prompt string. */ + if (rl_display_prompt == rl_prompt || local_prompt) + { + int local_len = local_prompt ? strlen (local_prompt) : 0; + if (local_prompt_prefix && forced_display) + _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix)); + + if (local_len > 0) + { + temp = local_len + out + 2; + if (temp >= line_size) + { + line_size = (temp + 1024) - (temp % 1024); + visible_line = (char *)xrealloc (visible_line, line_size); + line = invisible_line = (char *)xrealloc (invisible_line, line_size); + } + strncpy (line + out, local_prompt, local_len); + out += local_len; + } + line[out] = '\0'; + wrap_offset = local_len - prompt_visible_length; + } + else + { + int pmtlen; + prompt_this_line = strrchr (rl_display_prompt, '\n'); + if (!prompt_this_line) + prompt_this_line = rl_display_prompt; + else + { + prompt_this_line++; + pmtlen = prompt_this_line - rl_display_prompt; /* temp var */ + if (forced_display) + { + _rl_output_some_chars (rl_display_prompt, pmtlen); + /* Make sure we are at column zero even after a newline, + regardless of the state of terminal output processing. */ + if (pmtlen < 2 || prompt_this_line[-2] != '\r') + cr (); + } + } + + pmtlen = strlen (prompt_this_line); + temp = pmtlen + out + 2; + if (temp >= line_size) + { + line_size = (temp + 1024) - (temp % 1024); + visible_line = (char *)xrealloc (visible_line, line_size); + line = invisible_line = (char *)xrealloc (invisible_line, line_size); + } + strncpy (line + out, prompt_this_line, pmtlen); + out += pmtlen; + line[out] = '\0'; + wrap_offset = prompt_invis_chars_first_line = 0; + } + +#define CHECK_INV_LBREAKS() \ + do { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + } \ + } while (0) + +#if defined (HANDLE_MULTIBYTE) +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= _rl_screenwidth) \ + { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + _rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ + _rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \ + lpos = 0; \ + } \ + } while (0) +#else +#define CHECK_LPOS() \ + do { \ + lpos++; \ + if (lpos >= _rl_screenwidth) \ + { \ + if (newlines >= (inv_lbsize - 2)) \ + { \ + inv_lbsize *= 2; \ + inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \ + } \ + inv_lbreaks[++newlines] = out; \ + lpos = 0; \ + } \ + } while (0) +#endif + + /* inv_lbreaks[i] is where line i starts in the buffer. */ + inv_lbreaks[newlines = 0] = 0; + lpos = out - wrap_offset; +#if defined (HANDLE_MULTIBYTE) + memset (_rl_wrapped_line, 0, vis_lbsize); +#endif + + /* prompt_invis_chars_first_line is the number of invisible characters in + the first physical line of the prompt. + wrap_offset - prompt_invis_chars_first_line is the number of invis + chars on the second line. */ + + /* what if lpos is already >= _rl_screenwidth before we start drawing the + contents of the command line? */ + while (lpos >= _rl_screenwidth) + { + /* fix from Darin Johnson <darin@acuson.com> for prompt string with + invisible characters that is longer than the screen width. The + prompt_invis_chars_first_line variable could be made into an array + saying how many invisible characters there are per line, but that's + probably too much work for the benefit gained. How many people have + prompts that exceed two physical lines? */ + temp = ((newlines + 1) * _rl_screenwidth) + +#if 0 + ((newlines == 0) ? prompt_invis_chars_first_line : 0) + +#else + ((newlines == 0 && local_prompt_prefix == 0) ? prompt_invis_chars_first_line : 0) + +#endif + ((newlines == 1) ? wrap_offset : 0); + + inv_lbreaks[++newlines] = temp; + lpos -= _rl_screenwidth; + } + + prompt_last_screen_line = newlines; + + /* Draw the rest of the line (after the prompt) into invisible_line, keeping + track of where the cursor is (c_pos), the number of the line containing + the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin). + It maintains an array of line breaks for display (inv_lbreaks). + This handles expanding tabs for display and displaying meta characters. */ + lb_linenum = 0; +#if defined (HANDLE_MULTIBYTE) + in = 0; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps, 0, sizeof (mbstate_t)); + wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps); + } + else + wc_bytes = 1; + while (in < rl_end) +#else + for (in = 0; in < rl_end; in++) +#endif + { + c = (unsigned char)rl_line_buffer[in]; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + if (wc_bytes == (size_t)-1 || wc_bytes == (size_t)-2) + { + /* Byte sequence is invalid or shortened. Assume that the + first byte represents a character. */ + wc_bytes = 1; + /* Assume that a character occupies a single column. */ + wc_width = 1; + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (wc_bytes == (size_t)0) + break; /* Found '\0' */ + else + { + temp = wcwidth (wc); + wc_width = (temp < 0) ? 1 : temp; + } + } +#endif + + if (out + 8 >= line_size) /* XXX - 8 for \t */ + { + line_size *= 2; + visible_line = (char *)xrealloc (visible_line, line_size); + invisible_line = (char *)xrealloc (invisible_line, line_size); + line = invisible_line; + } + + if (in == rl_point) + { + c_pos = out; + lb_linenum = newlines; + } + +#if defined (HANDLE_MULTIBYTE) + if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */ +#else + if (META_CHAR (c)) +#endif + { + if (_rl_output_meta_chars == 0) + { + sprintf (line + out, "\\%o", c); + + if (lpos + 4 >= _rl_screenwidth) + { + temp = _rl_screenwidth - lpos; + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out + temp; + lpos = 4 - temp; + } + else + lpos += 4; + + out += 4; + } + else + { + line[out++] = c; + CHECK_LPOS(); + } + } +#if defined (DISPLAY_TABS) + else if (c == '\t') + { + register int newout; + +#if 0 + newout = (out | (int)7) + 1; +#else + newout = out + 8 - lpos % 8; +#endif + temp = newout - out; + if (lpos + temp >= _rl_screenwidth) + { + register int temp2; + temp2 = _rl_screenwidth - lpos; + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out + temp2; + lpos = temp - temp2; + while (out < newout) + line[out++] = ' '; + } + else + { + while (out < newout) + line[out++] = ' '; + lpos += temp; + } + } +#endif + else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up) + { + line[out++] = '\0'; /* XXX - sentinel */ + CHECK_INV_LBREAKS (); + inv_lbreaks[++newlines] = out; + lpos = 0; + } + else if (CTRL_CHAR (c) || c == RUBOUT) + { + line[out++] = '^'; + CHECK_LPOS(); + line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + CHECK_LPOS(); + } + else + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + register int i; + + _rl_wrapped_multicolumn = 0; + + if (_rl_screenwidth < lpos + wc_width) + for (i = lpos; i < _rl_screenwidth; i++) + { + /* The space will be removed in update_line() */ + line[out++] = ' '; + _rl_wrapped_multicolumn++; + CHECK_LPOS(); + } + if (in == rl_point) + { + c_pos = out; + lb_linenum = newlines; + } + for (i = in; i < in+wc_bytes; i++) + line[out++] = rl_line_buffer[i]; + for (i = 0; i < wc_width; i++) + CHECK_LPOS(); + } + else + { + line[out++] = c; + CHECK_LPOS(); + } +#else + line[out++] = c; + CHECK_LPOS(); +#endif + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + in += wc_bytes; + wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps); + } + else + in++; +#endif + + } + line[out] = '\0'; + if (c_pos < 0) + { + c_pos = out; + lb_linenum = newlines; + } + + inv_botlin = lb_botlin = newlines; + CHECK_INV_LBREAKS (); + inv_lbreaks[newlines+1] = out; + cursor_linenum = lb_linenum; + + /* C_POS == position in buffer where cursor should be placed. + CURSOR_LINENUM == line number where the cursor should be placed. */ + + /* PWP: now is when things get a bit hairy. The visible and invisible + line buffers are really multiple lines, which would wrap every + (screenwidth - 1) characters. Go through each in turn, finding + the changed region and updating it. The line order is top to bottom. */ + + /* If we can move the cursor up and down, then use multiple lines, + otherwise, let long lines display in a single terminal line, and + horizontally scroll it. */ + + if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up) + { + int nleft, pos, changed_screen_line; + + if (!rl_display_fixed || forced_display) + { + forced_display = 0; + + /* If we have more than a screenful of material to display, then + only display a screenful. We should display the last screen, + not the first. */ + if (out >= _rl_screenchars) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY); + else + out = _rl_screenchars - 1; + } + + /* The first line is at character position 0 in the buffer. The + second and subsequent lines start at inv_lbreaks[N], offset by + OFFSET (which has already been calculated above). */ + +#define W_OFFSET(line, offset) ((line) == 0 ? offset : 0) +#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l])) +#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l]) +#define VIS_CHARS(line) (visible_line + vis_lbreaks[line]) +#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? (char*)"" : VIS_CHARS(line) +#define INV_LINE(line) (invisible_line + inv_lbreaks[line]) + + /* For each line in the buffer, do the updating display. */ + for (linenum = 0; linenum <= inv_botlin; linenum++) + { + update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum, + VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin); + + /* If this is the line with the prompt, we might need to + compensate for invisible characters in the new line. Do + this only if there is not more than one new line (which + implies that we completely overwrite the old visible line) + and the new line is shorter than the old. Make sure we are + at the end of the new line before clearing. */ + if (linenum == 0 && + inv_botlin == 0 && _rl_last_c_pos == out && + (wrap_offset > visible_wrap_offset) && + (_rl_last_c_pos < visible_first_line_len)) + { + nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos; + if (nleft) + _rl_clear_to_eol (nleft); + } + + /* Since the new first line is now visible, save its length. */ + if (linenum == 0) + visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset; + } + + /* We may have deleted some lines. If so, clear the left over + blank ones at the bottom out. */ + if (_rl_vis_botlin > inv_botlin) + { + char *tt; + for (; linenum <= _rl_vis_botlin; linenum++) + { + tt = VIS_CHARS (linenum); + _rl_move_vert (linenum); + _rl_move_cursor_relative (0, tt); + _rl_clear_to_eol + ((linenum == _rl_vis_botlin) ? (int)strlen (tt) : _rl_screenwidth); + } + } + _rl_vis_botlin = inv_botlin; + + /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a + different screen line during this redisplay. */ + changed_screen_line = _rl_last_v_pos != cursor_linenum; + if (changed_screen_line) + { + _rl_move_vert (cursor_linenum); + /* If we moved up to the line with the prompt using _rl_term_up, + the physical cursor position on the screen stays the same, + but the buffer position needs to be adjusted to account + for invisible characters. */ + if (cursor_linenum == 0 && wrap_offset) + _rl_last_c_pos += wrap_offset; + } + + /* We have to reprint the prompt if it contains invisible + characters, since it's not generally OK to just reprint + the characters from the current cursor position. But we + only need to reprint it if the cursor is before the last + invisible character in the prompt string. */ + nleft = prompt_visible_length + wrap_offset; + if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 && + _rl_last_c_pos <= prompt_last_invisible && local_prompt) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + if (_rl_term_cr) + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_output_some_chars (local_prompt, nleft); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width(local_prompt, 0, nleft); + else + _rl_last_c_pos = nleft; + } + + /* Where on that line? And where does that line start + in the buffer? */ + pos = inv_lbreaks[cursor_linenum]; + /* nleft == number of characters in the line buffer between the + start of the line and the cursor position. */ + nleft = c_pos - pos; + + /* Since _rl_backspace() doesn't know about invisible characters in the + prompt, and there's no good way to tell it, we compensate for + those characters here and call _rl_backspace() directly. */ + if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos) + { + _rl_backspace (_rl_last_c_pos - nleft); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (&visible_line[pos], 0, nleft); + else + _rl_last_c_pos = nleft; + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + else if (nleft != _rl_last_c_pos) + _rl_move_cursor_relative (nleft, &invisible_line[pos]); + } + } + else /* Do horizontal scrolling. */ + { +#define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0) + int lmargin, ndisp, nleft, phys_c_pos, t; + + /* Always at top line. */ + _rl_last_v_pos = 0; + + /* Compute where in the buffer the displayed line should start. This + will be LMARGIN. */ + + /* The number of characters that will be displayed before the cursor. */ + ndisp = c_pos - wrap_offset; + nleft = prompt_visible_length + wrap_offset; + /* Where the new cursor position will be on the screen. This can be + longer than SCREENWIDTH; if it is, lmargin will be adjusted. */ + phys_c_pos = c_pos - (last_lmargin ? last_lmargin : wrap_offset); + t = _rl_screenwidth / 3; + + /* If the number of characters had already exceeded the screenwidth, + last_lmargin will be > 0. */ + + /* If the number of characters to be displayed is more than the screen + width, compute the starting offset so that the cursor is about + two-thirds of the way across the screen. */ + if (phys_c_pos > _rl_screenwidth - 2) + { + lmargin = c_pos - (2 * t); + if (lmargin < 0) + lmargin = 0; + /* If the left margin would be in the middle of a prompt with + invisible characters, don't display the prompt at all. */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else if (ndisp < _rl_screenwidth - 2) /* XXX - was -1 */ + lmargin = 0; + else if (phys_c_pos < 1) + { + /* If we are moving back towards the beginning of the line and + the last margin is no longer correct, compute a new one. */ + lmargin = ((c_pos - 1) / t) * t; /* XXX */ + if (wrap_offset && lmargin > 0 && lmargin < nleft) + lmargin = nleft; + } + else + lmargin = last_lmargin; + + /* If the first character on the screen isn't the first character + in the display line, indicate this with a special character. */ + if (lmargin > 0) + line[lmargin] = '<'; + + /* If SCREENWIDTH characters starting at LMARGIN do not encompass + the whole line, indicate that with a special character at the + right edge of the screen. If LMARGIN is 0, we need to take the + wrap offset into account. */ + t = lmargin + M_OFFSET (lmargin, wrap_offset) + _rl_screenwidth; + if (t < out) + line[t - 1] = '>'; + + if (!rl_display_fixed || forced_display || lmargin != last_lmargin) + { + forced_display = 0; + update_line (&visible_line[last_lmargin], + &invisible_line[lmargin], + 0, + _rl_screenwidth + visible_wrap_offset, + _rl_screenwidth + (lmargin ? 0 : wrap_offset), + 0); + + /* If the visible new line is shorter than the old, but the number + of invisible characters is greater, and we are at the end of + the new line, we need to clear to eol. */ + t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset); + if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) && + (_rl_last_c_pos == out) && + t < visible_first_line_len) + { + nleft = _rl_screenwidth - t; + _rl_clear_to_eol (nleft); + } + visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset); + if (visible_first_line_len > _rl_screenwidth) + visible_first_line_len = _rl_screenwidth; + + _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]); + last_lmargin = lmargin; + } + } + fflush (rl_outstream); + + /* Swap visible and non-visible lines. */ + { + char *vtemp = visible_line; + int *itemp = vis_lbreaks, ntemp = vis_lbsize; + + visible_line = invisible_line; + invisible_line = vtemp; + + vis_lbreaks = inv_lbreaks; + inv_lbreaks = itemp; + + vis_lbsize = inv_lbsize; + inv_lbsize = ntemp; + + rl_display_fixed = 0; + /* If we are displaying on a single line, and last_lmargin is > 0, we + are not displaying any invisible characters, so set visible_wrap_offset + to 0. */ + if (_rl_horizontal_scroll_mode && last_lmargin) + visible_wrap_offset = 0; + else + visible_wrap_offset = wrap_offset; + } +} + +/* PWP: 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. + + Could be made even smarter, but this works well enough */ +static void +update_line (old, new, current_line, omax, nmax, inv_botlin) + register char *old, *new; + int current_line, omax, nmax, inv_botlin; +{ + register char *ofd, *ols, *oe, *nfd, *nls, *ne; + int temp, lendiff, wsatend, od, nd; + int current_invis_chars; + int col_lendiff, col_temp; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps_new, ps_old; + int new_offset, old_offset, tmp; +#endif + + /* If we're at the right edge of a terminal that supports xn, we're + ready to wrap around, so do so. This fixes problems with knowing + the exact cursor position and cut-and-paste with certain terminal + emulators. In this calculation, TEMP is the physical screen + position of the cursor. */ + temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); + if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode + && _rl_last_v_pos == current_line - 1) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + wchar_t wc; + mbstate_t ps; + int tempwidth, bytes; + size_t ret; + + /* This fixes only double-column characters, but if the wrapped + character comsumes more than three columns, spaces will be + inserted in the string buffer. */ + if (_rl_wrapped_line[current_line] > 0) + _rl_clear_to_eol (_rl_wrapped_line[current_line]); + + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps); + if (ret == (size_t)-1 || ret == (size_t)-2) + { + tempwidth = 1; + ret = 1; + } + else if (ret == 0) + tempwidth = 0; + else + tempwidth = wcwidth (wc); + + if (tempwidth > 0) + { + int count; + bytes = ret; + for (count = 0; count < bytes; count++) + putc (new[count], rl_outstream); + _rl_last_c_pos = tempwidth; + _rl_last_v_pos++; + memset (&ps, 0, sizeof (mbstate_t)); + ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps); + if (ret != 0 && bytes != 0) + { + if (ret == (size_t)-1 || ret == (size_t)-2) + memmove (old+bytes, old+1, strlen (old+1)); + else + memmove (old+bytes, old+ret, strlen (old+ret)); + memcpy (old, new, bytes); + } + } + else + { + putc (' ', rl_outstream); + _rl_last_c_pos = 1; + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + } + else +#endif + { + if (new[0]) + putc (new[0], rl_outstream); + else + putc (' ', rl_outstream); + _rl_last_c_pos = 1; /* XXX */ + _rl_last_v_pos++; + if (old[0] && new[0]) + old[0] = new[0]; + } + } + + + /* Find first difference. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + memset (&ps_new, 0, sizeof(mbstate_t)); + memset (&ps_old, 0, sizeof(mbstate_t)); + + new_offset = old_offset = 0; + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && + _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); ) + { + old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY); + new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY); + ofd = old + old_offset; + nfd = new + new_offset; + } + } + else +#endif + for (ofd = old, nfd = new; + (ofd - old < omax) && *ofd && (*ofd == *nfd); + ofd++, nfd++) + ; + + /* Move to the end of the screen line. ND and OD are used to keep track + of the distance between ne and new and oe and old, respectively, to + move a subtraction out of each loop. */ + for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++); + for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++); + + /* If no difference, continue to next line. */ + if (ofd == oe && nfd == ne) + return; + + wsatend = 1; /* flag for trailing whitespace */ + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY); + while ((ols > ofd) && (nls > nfd)) + { + memset (&ps_old, 0, sizeof (mbstate_t)); + memset (&ps_new, 0, sizeof (mbstate_t)); + + _rl_adjust_point (old, ols - old, &ps_old); + _rl_adjust_point (new, nls - new, &ps_new); + + if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0) + break; + + if (*ols == ' ') + wsatend = 0; + + ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY); + nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY); + } + } + else + { +#endif /* HANDLE_MULTIBYTE */ + ols = oe - 1; /* find last same */ + nls = ne - 1; + while ((ols > ofd) && (nls > nfd) && (*ols == *nls)) + { + if (*ols != ' ') + wsatend = 0; + ols--; + nls--; + } +#if defined (HANDLE_MULTIBYTE) + } +#endif + + if (wsatend) + { + ols = oe; + nls = ne; + } +#if defined (HANDLE_MULTIBYTE) + /* This may not work for stateful encoding, but who cares? To handle + stateful encoding properly, we have to scan each string from the + beginning and compare. */ + else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0) +#else + else if (*ols != *nls) +#endif + { + if (*ols) /* don't step past the NUL */ + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY); + else + ols++; + } + if (*nls) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY); + else + nls++; + } + } + + /* count of invisible characters in the current invisible line. */ + current_invis_chars = W_OFFSET (current_line, wrap_offset); + if (_rl_last_v_pos != current_line) + { + _rl_move_vert (current_line); + if (current_line == 0 && visible_wrap_offset) + _rl_last_c_pos += visible_wrap_offset; + } + + /* If this is the first line and there are invisible characters in the + prompt string, and the prompt string has not changed, and the current + cursor position is before the last invisible character in the prompt, + and the index of the character to move to is past the end of the prompt + string, then redraw the entire prompt string. We can only do this + reliably if the terminal supports a `cr' capability. + + This is not an efficiency hack -- there is a problem with redrawing + portions of the prompt string if they contain terminal escape + sequences (like drawing the `unbold' sequence without a corresponding + `bold') that manifests itself on certain terminals. */ + + lendiff = local_prompt ? strlen (local_prompt) : 0; + od = ofd - old; /* index of first difference in visible line */ + if (current_line == 0 && !_rl_horizontal_scroll_mode && + _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 && + od >= lendiff && _rl_last_c_pos <= prompt_last_invisible) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_output_some_chars (local_prompt, lendiff); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff); + else + _rl_last_c_pos = lendiff; + } + + _rl_move_cursor_relative (od, old); + + /* if (len (new) > len (old)) + lendiff == difference in buffer + col_lendiff == difference on screen + When not using multibyte characters, these are equal */ + lendiff = (nls - nfd) - (ols - ofd); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old); + else + col_lendiff = lendiff; + + /* If we are changing the number of invisible characters in a line, and + the spot of first difference is before the end of the invisible chars, + lendiff needs to be adjusted. */ + if (current_line == 0 && !_rl_horizontal_scroll_mode && + current_invis_chars != visible_wrap_offset) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff += visible_wrap_offset - current_invis_chars; + } + else + { + lendiff += visible_wrap_offset - current_invis_chars; + col_lendiff = lendiff; + } + } + + /* Insert (diff (len (old), len (new)) ch. */ + temp = ne - nfd; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_temp = _rl_col_width (new, nfd - new, ne - new); + else + col_temp = temp; + + if (col_lendiff > 0) /* XXX - was lendiff */ + { + /* Non-zero if we're increasing the number of lines. */ + int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin; + /* Sometimes it is cheaper to print the characters rather than + use the terminal's capabilities. If we're growing the number + of lines, make sure we actually cause the new line to wrap + around on auto-wrapping terminals. */ + if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl)) + { + /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and + _rl_horizontal_scroll_mode == 1, inserting the characters with + _rl_term_IC or _rl_term_ic will screw up the screen because of the + invisible characters. We need to just draw them. */ + if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 || + lendiff <= prompt_visible_length || !current_invis_chars)) + { + insert_some_chars (nfd, lendiff, col_lendiff); + _rl_last_c_pos += col_lendiff; + } + else if (*ols == 0) + { + /* At the end of a line the characters do not have to + be "inserted". They can just be placed on the screen. */ + /* However, this screws up the rest of this block, which + assumes you've done the insert because you can. */ + _rl_output_some_chars (nfd, lendiff); + _rl_last_c_pos += col_lendiff; + } + else + { + /* We have horizontal scrolling and we are not inserting at + the end. We have invisible characters in this line. This + is a dumb update. */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + return; + } + /* Copy (new) chars to screen from first diff to last match. */ + temp = nls - nfd; + if ((temp - lendiff) > 0) + { + _rl_output_some_chars (nfd + lendiff, temp - lendiff); +#if 0 + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff) - col_lendiff; +#else + _rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff); +#endif + } + } + else + { + /* cannot insert chars, write to EOL */ + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + } + } + else /* Delete characters from line. */ + { + /* If possible and inexpensive to use terminal deletion, then do so. */ + if (_rl_term_dc && (2 * col_temp) >= -col_lendiff) + { + /* If all we're doing is erasing the invisible characters in the + prompt string, don't bother. It screws up the assumptions + about what's on the screen. */ + if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 && + -lendiff == visible_wrap_offset) + col_lendiff = 0; + + if (col_lendiff) + delete_chars (-col_lendiff); /* delete (diff) characters */ + + /* Copy (new) chars to screen from first diff to last match */ + temp = nls - nfd; + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += _rl_col_width (nfd, 0, temp);; + } + } + /* Otherwise, print over the existing material. */ + else + { + if (temp > 0) + { + _rl_output_some_chars (nfd, temp); + _rl_last_c_pos += col_temp; + } + lendiff = (oe - old) - (ne - new); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new); + else + col_lendiff = lendiff; + + if (col_lendiff) + { + if (_rl_term_autowrap && current_line < inv_botlin) + space_to_eol (col_lendiff); + else + _rl_clear_to_eol (col_lendiff); + } + } + } +} + +/* Tell the update routines that we have moved onto a new (empty) line. */ +int +rl_on_new_line () +{ + if (visible_line) + visible_line[0] = '\0'; + + _rl_last_c_pos = _rl_last_v_pos = 0; + _rl_vis_botlin = last_lmargin = 0; + if (vis_lbreaks) + vis_lbreaks[0] = vis_lbreaks[1] = 0; + visible_wrap_offset = 0; + return 0; +} + +/* Tell the update routines that we have moved onto a new line with the + prompt already displayed. Code originally from the version of readline + distributed with CLISP. */ +int +rl_on_new_line_with_prompt () +{ + int prompt_size, i, l, real_screenwidth, newlines; + char *prompt_last_line; + + /* Initialize visible_line and invisible_line to ensure that they can hold + the already-displayed prompt. */ + prompt_size = strlen (rl_prompt) + 1; + init_line_structures (prompt_size); + + /* Make sure the line structures hold the already-displayed prompt for + redisplay. */ + strcpy (visible_line, rl_prompt); + strcpy (invisible_line, rl_prompt); + + /* If the prompt contains newlines, take the last tail. */ + prompt_last_line = strrchr (rl_prompt, '\n'); + if (!prompt_last_line) + prompt_last_line = rl_prompt; + + l = strlen (prompt_last_line); + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l); + else + _rl_last_c_pos = l; + + /* Dissect prompt_last_line into screen lines. Note that here we have + to use the real screenwidth. Readline's notion of screenwidth might be + one less, see terminal.c. */ + real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1); + _rl_last_v_pos = l / real_screenwidth; + /* If the prompt length is a multiple of real_screenwidth, we don't know + whether the cursor is at the end of the last line, or already at the + beginning of the next line. Output a newline just to be safe. */ + if (l > 0 && (l % real_screenwidth) == 0) + _rl_output_some_chars ("\n", 1); + last_lmargin = 0; + + newlines = 0; i = 0; + while (i <= l) + { + _rl_vis_botlin = newlines; + vis_lbreaks[newlines++] = i; + i += real_screenwidth; + } + vis_lbreaks[newlines] = l; + visible_wrap_offset = 0; + + return 0; +} + +/* Actually update the display, period. */ +int +rl_forced_update_display () +{ + if (visible_line) + { + register char *temp = visible_line; + + while (*temp) + *temp++ = '\0'; + } + rl_on_new_line (); + forced_display++; + (*rl_redisplay_function) (); + return 0; +} + +/* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices. + DATA is the contents of the screen line of interest; i.e., where + the movement is being done. */ +void +_rl_move_cursor_relative (new, data) + int new; + const char *data; +{ + register int i; + + /* If we don't have to do anything, then return. */ +#if defined (HANDLE_MULTIBYTE) + /* If we have multibyte characters, NEW is indexed by the buffer point in + a multibyte string, but _rl_last_c_pos is the display position. In + this case, NEW's display position is not obvious. */ + if ((MB_CUR_MAX == 1 || rl_byte_oriented ) && _rl_last_c_pos == new) return; +#else + if (_rl_last_c_pos == new) return; +#endif + + /* It may be faster to output a CR, and then move forwards instead + of moving backwards. */ + /* i == current physical cursor position. */ + i = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset); + if (new == 0 || CR_FASTER (new, _rl_last_c_pos) || + (_rl_term_autowrap && i == _rl_screenwidth)) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif /* !__MSDOS__ */ + _rl_last_c_pos = 0; + } + + if (_rl_last_c_pos < new) + { + /* Move the cursor forward. We do it by printing the command + to move the cursor forward if there is one, else print that + portion of the output buffer again. Which is cheaper? */ + + /* The above comment is left here for posterity. It is faster + to print one character (non-control) than to print a control + sequence telling the terminal to move forward one character. + That kind of control is for people who don't know what the + data is underneath the cursor. */ +#if defined (HACK_TERMCAP_MOTION) + if (_rl_term_forward_char) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int width; + width = _rl_col_width (data, _rl_last_c_pos, new); + for (i = 0; i < width; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + else + { + for (i = _rl_last_c_pos; i < new; i++) + tputs (_rl_term_forward_char, 1, _rl_output_character_function); + } + } + else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); + +#else /* !HACK_TERMCAP_MOTION */ + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + for (i = _rl_last_c_pos; i < new; i++) + putc (data[i], rl_outstream); + +#endif /* !HACK_TERMCAP_MOTION */ + + } +#if defined (HANDLE_MULTIBYTE) + /* NEW points to the buffer point, but _rl_last_c_pos is the display point. + The byte length of the string is probably bigger than the column width + of the string, which means that if NEW == _rl_last_c_pos, then NEW's + display point is less than _rl_last_c_pos. */ + else if (_rl_last_c_pos >= new) +#else + else if (_rl_last_c_pos > new) +#endif + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + tputs (_rl_term_cr, 1, _rl_output_character_function); + for (i = 0; i < new; i++) + putc (data[i], rl_outstream); + } + else + _rl_backspace (_rl_last_c_pos - new); + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + _rl_last_c_pos = _rl_col_width (data, 0, new); + else + _rl_last_c_pos = new; +} + +/* PWP: move the cursor up or down. */ +void +_rl_move_vert (to) + int to; +{ + register int delta, i; + + if (_rl_last_v_pos == to || to > _rl_screenheight) + return; + + if ((delta = to - _rl_last_v_pos) > 0) + { + for (i = 0; i < delta; i++) + putc ('\n', rl_outstream); +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; + } + else + { /* delta < 0 */ + if (_rl_term_up && *_rl_term_up) + for (i = 0; i < -delta; i++) + tputs (_rl_term_up, 1, _rl_output_character_function); + } + + _rl_last_v_pos = to; /* Now TO is here */ +} + +/* Physically print C on rl_outstream. This is for functions which know + how to optimize the display. Return the number of characters output. */ +int +rl_show_char (c) + int c; +{ + int n = 1; + if (META_CHAR (c) && (_rl_output_meta_chars == 0)) + { + fprintf (rl_outstream, "M-"); + n += 2; + c = UNMETA (c); + } + +#if defined (DISPLAY_TABS) + if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT) +#else + if (CTRL_CHAR (c) || c == RUBOUT) +#endif /* !DISPLAY_TABS */ + { + fprintf (rl_outstream, "C-"); + n += 2; + c = CTRL_CHAR (c) ? UNCTRL (c) : '?'; + } + + putc (c, rl_outstream); + fflush (rl_outstream); + return n; +} + +int +rl_character_len (c, pos) + register int c, pos; +{ + unsigned char uc; + + uc = (unsigned char)c; + + if (META_CHAR (uc)) + return ((_rl_output_meta_chars == 0) ? 4 : 1); + + if (uc == '\t') + { +#if defined (DISPLAY_TABS) + return (((pos | 7) + 1) - pos); +#else + return (2); +#endif /* !DISPLAY_TABS */ + } + + if (CTRL_CHAR (c) || c == RUBOUT) + return (2); + + return ((ISPRINT (uc)) ? 1 : 2); +} + +/* How to print things in the "echo-area". The prompt is treated as a + mini-modeline. */ + +#if defined (USE_VARARGS) +int +#if defined (PREFER_STDARG) +rl_message (const char *format, ...) +#else +rl_message (va_alist) + va_dcl +#endif +{ + va_list args; +#if defined (PREFER_VARARGS) + char *format; +#endif + +#if defined (PREFER_STDARG) + va_start (args, format); +#else + va_start (args); + format = va_arg (args, char *); +#endif + +#if defined (HAVE_VSNPRINTF) + vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args); +#else + vsprintf (msg_buf, format, args); + msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ +#endif + va_end (args); + + rl_display_prompt = msg_buf; + (*rl_redisplay_function) (); + return 0; +} +#else /* !USE_VARARGS */ +int +rl_message (format, arg1, arg2) + char *format; + int arg1, arg2; +{ + sprintf (msg_buf, format, arg1, arg2); + msg_buf[sizeof(msg_buf) - 1] = '\0'; /* overflow? */ + rl_display_prompt = msg_buf; + (*rl_redisplay_function) (); + return 0; +} +#endif /* !USE_VARARGS */ + +/* How to clear things from the "echo-area". */ +int +rl_clear_message () +{ + rl_display_prompt = rl_prompt; + (*rl_redisplay_function) (); + return 0; +} + +int +rl_reset_line_state () +{ + rl_on_new_line (); + + rl_display_prompt = rl_prompt ? rl_prompt : ""; + forced_display = 1; + return 0; +} + +static char *saved_local_prompt; +static char *saved_local_prefix; +static int saved_last_invisible; +static int saved_visible_length; + +void +rl_save_prompt () +{ + saved_local_prompt = local_prompt; + saved_local_prefix = local_prompt_prefix; + saved_last_invisible = prompt_last_invisible; + saved_visible_length = prompt_visible_length; + + local_prompt = local_prompt_prefix = (char *)0; + prompt_last_invisible = prompt_visible_length = 0; +} + +void +rl_restore_prompt () +{ + FREE (local_prompt); + FREE (local_prompt_prefix); + + local_prompt = saved_local_prompt; + local_prompt_prefix = saved_local_prefix; + prompt_last_invisible = saved_last_invisible; + prompt_visible_length = saved_visible_length; +} + +char * +_rl_make_prompt_for_search (pchar) + int pchar; +{ + int len; + char *pmt; + + rl_save_prompt (); + + if (saved_local_prompt == 0) + { + len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0; + pmt = (char *)xmalloc (len + 2); + if (len) + strcpy (pmt, rl_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + } + else + { + len = *saved_local_prompt ? strlen (saved_local_prompt) : 0; + pmt = (char *)xmalloc (len + 2); + if (len) + strcpy (pmt, saved_local_prompt); + pmt[len] = pchar; + pmt[len+1] = '\0'; + local_prompt = savestring (pmt); + prompt_last_invisible = saved_last_invisible; + prompt_visible_length = saved_visible_length + 1; + } + return pmt; +} + +/* Quick redisplay hack when erasing characters at the end of the line. */ +void +_rl_erase_at_end_of_line (l) + int l; +{ + register int i; + + _rl_backspace (l); + for (i = 0; i < l; i++) + putc (' ', rl_outstream); + _rl_backspace (l); + for (i = 0; i < l; i++) + visible_line[--_rl_last_c_pos] = '\0'; + rl_display_fixed++; +} + +/* Clear to the end of the line. COUNT is the minimum + number of character spaces to clear, */ +void +_rl_clear_to_eol (count) + int count; +{ + if (_rl_term_clreol) + tputs (_rl_term_clreol, 1, _rl_output_character_function); + else if (count) + space_to_eol (count); +} + +/* Clear to the end of the line using spaces. COUNT is the minimum + number of character spaces to clear, */ +static void +space_to_eol (count) + int count; +{ + register int i; + + for (i = 0; i < count; i++) + putc (' ', rl_outstream); + + _rl_last_c_pos += count; +} + +void +_rl_clear_screen () +{ + if (_rl_term_clrpag) + tputs (_rl_term_clrpag, 1, _rl_output_character_function); + else + rl_crlf (); +} + +/* Insert COUNT characters from STRING to the output stream at column COL. */ +static void +insert_some_chars (string, count, col) + char *string; + int count, col; +{ + /* DEBUGGING */ + if (MB_CUR_MAX == 1 || rl_byte_oriented) + if (count != col) + fprintf(stderr, "readline: debug: insert_some_chars: count (%d) != col (%d)\n", count, col); + + /* If IC is defined, then we do not have to "enter" insert mode. */ + if (_rl_term_IC) + { + char *buffer; + + buffer = tgoto (_rl_term_IC, 0, col); + tputs (buffer, 1, _rl_output_character_function); + _rl_output_some_chars (string, count); + } + else + { + register int i; + + /* If we have to turn on insert-mode, then do so. */ + if (_rl_term_im && *_rl_term_im) + tputs (_rl_term_im, 1, _rl_output_character_function); + + /* If there is a special command for inserting characters, then + use that first to open up the space. */ + if (_rl_term_ic && *_rl_term_ic) + { + for (i = col; i--; ) + tputs (_rl_term_ic, 1, _rl_output_character_function); + } + + /* Print the text. */ + _rl_output_some_chars (string, count); + + /* If there is a string to turn off insert mode, we had best use + it now. */ + if (_rl_term_ei && *_rl_term_ei) + tputs (_rl_term_ei, 1, _rl_output_character_function); + } +} + +/* Delete COUNT characters from the display line. */ +static void +delete_chars (count) + int count; +{ + if (count > _rl_screenwidth) /* XXX */ + return; + + if (_rl_term_DC && *_rl_term_DC) + { + char *buffer; + buffer = tgoto (_rl_term_DC, count, count); + tputs (buffer, count, _rl_output_character_function); + } + else + { + if (_rl_term_dc && *_rl_term_dc) + while (count--) + tputs (_rl_term_dc, 1, _rl_output_character_function); + } +} + +void +_rl_update_final () +{ + int full_lines; + + full_lines = 0; + /* If the cursor is the only thing on an otherwise-blank last line, + compensate so we don't print an extra CRLF. */ + if (_rl_vis_botlin && _rl_last_c_pos == 0 && + visible_line[vis_lbreaks[_rl_vis_botlin]] == 0) + { + _rl_vis_botlin--; + full_lines = 1; + } + _rl_move_vert (_rl_vis_botlin); + /* If we've wrapped lines, remove the final xterm line-wrap flag. */ + if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth)) + { + char *last_line; + + last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]]; + _rl_move_cursor_relative (_rl_screenwidth - 1, last_line); + _rl_clear_to_eol (0); + putc (last_line[_rl_screenwidth - 1], rl_outstream); + } + _rl_vis_botlin = 0; + rl_crlf (); + fflush (rl_outstream); + rl_display_fixed++; +} + +/* Move to the start of the current line. */ +static void +cr () +{ + if (_rl_term_cr) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; + } +} + +/* Redraw the last line of a multi-line prompt that may possibly contain + terminal escape sequences. Called with the cursor at column 0 of the + line to draw the prompt on. */ +static void +redraw_prompt (t) + char *t; +{ + const char *oldp; + char *oldl, *oldlprefix; + int oldlen, oldlast, oldplen, oldninvis; + + /* Geez, I should make this a struct. */ + oldp = rl_display_prompt; + oldl = local_prompt; + oldlprefix = local_prompt_prefix; + oldlen = prompt_visible_length; + oldplen = prompt_prefix_length; + oldlast = prompt_last_invisible; + oldninvis = prompt_invis_chars_first_line; + + rl_display_prompt = t; + local_prompt = expand_prompt (t, &prompt_visible_length, + &prompt_last_invisible, + &prompt_invis_chars_first_line); + local_prompt_prefix = (char *)NULL; + rl_forced_update_display (); + + rl_display_prompt = oldp; + local_prompt = oldl; + local_prompt_prefix = oldlprefix; + prompt_visible_length = oldlen; + prompt_prefix_length = oldplen; + prompt_last_invisible = oldlast; + prompt_invis_chars_first_line = oldninvis; +} + +/* Redisplay the current line after a SIGWINCH is received. */ +void +_rl_redisplay_after_sigwinch () +{ + char *t; + + /* Clear the current line and put the cursor at column 0. Make sure + the right thing happens if we have wrapped to a new screen line. */ + if (_rl_term_cr) + { +#if defined (__MSDOS__) + putc ('\r', rl_outstream); +#else + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif + _rl_last_c_pos = 0; +#if defined (__MSDOS__) + space_to_eol (_rl_screenwidth); + putc ('\r', rl_outstream); +#else + if (_rl_term_clreol) + tputs (_rl_term_clreol, 1, _rl_output_character_function); + else + { + space_to_eol (_rl_screenwidth); + tputs (_rl_term_cr, 1, _rl_output_character_function); + } +#endif + if (_rl_last_v_pos > 0) + _rl_move_vert (0); + } + else + rl_crlf (); + + /* Redraw only the last line of a multi-line prompt. */ + t = strrchr (rl_display_prompt, '\n'); + if (t) + redraw_prompt (++t); + else + rl_forced_update_display (); +} + +void +_rl_clean_up_for_exit () +{ + if (readline_echoing_p) + { + _rl_move_vert (_rl_vis_botlin); + _rl_vis_botlin = 0; + fflush (rl_outstream); + rl_restart_output (1, 0); + } +} + +void +_rl_erase_entire_line () +{ + cr (); + _rl_clear_to_eol (0); + cr (); + fflush (rl_outstream); +} + +/* return the `current display line' of the cursor -- the number of lines to + move up to get to the first screen line of the current readline line. */ +int +_rl_current_display_line () +{ + int ret, nleft; + + /* Find out whether or not there might be invisible characters in the + editing buffer. */ + if (rl_display_prompt == rl_prompt) + nleft = _rl_last_c_pos - _rl_screenwidth - rl_visible_prompt_length; + else + nleft = _rl_last_c_pos - _rl_screenwidth; + + if (nleft > 0) + ret = 1 + nleft / _rl_screenwidth; + else + ret = 0; + + return ret; +} + +#if defined (HANDLE_MULTIBYTE) +/* Calculate the number of screen columns occupied by STR from START to END. + In the case of multibyte characters with stateful encoding, we have to + scan from the beginning of the string to take the state into account. */ +static int +_rl_col_width (str, start, end) + const char *str; + int start, end; +{ + wchar_t wc; + mbstate_t ps = {0}; + int tmp, point, width, max; + + if (end <= start) + return 0; + + point = 0; + max = end; + + while (point < start) + { + tmp = mbrlen (str + point, max, &ps); + if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + } + } + + /* If START is not a byte that starts a character, then POINT will be + greater than START. In this case, assume that (POINT - START) gives + a byte count that is the number of columns of difference. */ + width = point - start; + + while (point < end) + { + tmp = mbrtowc (&wc, str + point, max, &ps); + if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2) + { + /* In this case, the bytes are invalid or too short to compose a + multibyte character, so we assume that the first byte represents + a single character. */ + point++; + max--; + + /* and assume that the byte occupies a single column. */ + width++; + + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' */ + else + { + point += tmp; + max -= tmp; + tmp = wcwidth(wc); + width += (tmp >= 0) ? tmp : 1; + } + } + + width += point - end; + + return width; +} +#endif /* HANDLE_MULTIBYTE */ + diff --git a/cmd-line-utils/readline/emacs_keymap.c b/cmd-line-utils/readline/emacs_keymap.c new file mode 100644 index 00000000000..ca9d1343b65 --- /dev/null +++ b/cmd-line-utils/readline/emacs_keymap.c @@ -0,0 +1,873 @@ +/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* !BUFSIZ */ + +#include "readline.h" + +/* An array of function pointers, one for each possible key. + If the type byte is ISKMAP, then the pointer is the address of + a keymap. */ + +KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { + + /* Control keys. */ + { ISFUNC, rl_set_mark }, /* Control-@ */ + { ISFUNC, rl_beg_of_line }, /* Control-a */ + { ISFUNC, rl_backward_char }, /* Control-b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ + { ISFUNC, rl_delete }, /* Control-d */ + { ISFUNC, rl_end_of_line }, /* Control-e */ + { ISFUNC, rl_forward_char }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_rubout }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISKMAP, (rl_command_func_t *)emacs_ctlx_keymap }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ + { ISKMAP, (rl_command_func_t *)emacs_meta_keymap }, /* Control-[ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ + { ISFUNC, rl_char_search }, /* Control-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ + { ISFUNC, rl_insert }, /* ) */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ + { ISFUNC, rl_insert }, /* ] */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ + { ISFUNC, rl_insert }, /* } */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Pure 8-bit characters (128 - 159). + These might be used in some + character sets. */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + + /* ISO Latin-1 characters (160 - 255) */ + { ISFUNC, rl_insert }, /* No-break space */ + { ISFUNC, rl_insert }, /* Inverted exclamation mark */ + { ISFUNC, rl_insert }, /* Cent sign */ + { ISFUNC, rl_insert }, /* Pound sign */ + { ISFUNC, rl_insert }, /* Currency sign */ + { ISFUNC, rl_insert }, /* Yen sign */ + { ISFUNC, rl_insert }, /* Broken bar */ + { ISFUNC, rl_insert }, /* Section sign */ + { ISFUNC, rl_insert }, /* Diaeresis */ + { ISFUNC, rl_insert }, /* Copyright sign */ + { ISFUNC, rl_insert }, /* Feminine ordinal indicator */ + { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Not sign */ + { ISFUNC, rl_insert }, /* Soft hyphen */ + { ISFUNC, rl_insert }, /* Registered sign */ + { ISFUNC, rl_insert }, /* Macron */ + { ISFUNC, rl_insert }, /* Degree sign */ + { ISFUNC, rl_insert }, /* Plus-minus sign */ + { ISFUNC, rl_insert }, /* Superscript two */ + { ISFUNC, rl_insert }, /* Superscript three */ + { ISFUNC, rl_insert }, /* Acute accent */ + { ISFUNC, rl_insert }, /* Micro sign */ + { ISFUNC, rl_insert }, /* Pilcrow sign */ + { ISFUNC, rl_insert }, /* Middle dot */ + { ISFUNC, rl_insert }, /* Cedilla */ + { ISFUNC, rl_insert }, /* Superscript one */ + { ISFUNC, rl_insert }, /* Masculine ordinal indicator */ + { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */ + { ISFUNC, rl_insert }, /* Vulgar fraction one half */ + { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */ + { ISFUNC, rl_insert }, /* Inverted questionk mark */ + { ISFUNC, rl_insert }, /* Latin capital letter a with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter a with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin capital letter ae */ + { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin capital letter e with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter e with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter i with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter i with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter o with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Multiplication sign */ + { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin capital letter u with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter u with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */ + { ISFUNC, rl_insert }, /* Latin small letter a with grave */ + { ISFUNC, rl_insert }, /* Latin small letter a with acute */ + { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin small letter ae */ + { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin small letter e with grave */ + { ISFUNC, rl_insert }, /* Latin small letter e with acute */ + { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter i with grave */ + { ISFUNC, rl_insert }, /* Latin small letter i with acute */ + { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with grave */ + { ISFUNC, rl_insert }, /* Latin small letter o with acute */ + { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Division sign */ + { ISFUNC, rl_insert }, /* Latin small letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin small letter u with grave */ + { ISFUNC, rl_insert }, /* Latin small letter u with acute */ + { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter y with acute */ + { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */ + { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */ +#endif /* KEYMAP_SIZE > 128 */ +}; + +KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { + + /* Meta keys. Just like above, but the high bit is set. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-@ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-c */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-d */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-f */ + { ISFUNC, rl_abort }, /* Meta-Control-g */ + { ISFUNC, rl_backward_kill_word }, /* Meta-Control-h */ + { ISFUNC, rl_tab_insert }, /* Meta-Control-i */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-k */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-l */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-o */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-q */ + { ISFUNC, rl_revert_line }, /* Meta-Control-r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-s */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-t */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-x */ + { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-z */ + + { ISFUNC, rl_complete }, /* Meta-Control-[ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-\ */ + { ISFUNC, rl_backward_char_search }, /* Meta-Control-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-^ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_set_mark }, /* Meta-SPACE */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-! */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-" */ + { ISFUNC, rl_insert_comment }, /* Meta-# */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-$ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-% */ + { ISFUNC, rl_tilde_expand }, /* Meta-& */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-' */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-( */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-) */ + { ISFUNC, rl_insert_completions }, /* Meta-* */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-+ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-, */ + { ISFUNC, rl_digit_argument }, /* Meta-- */ + { ISFUNC, rl_yank_last_arg}, /* Meta-. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-/ */ + + /* Regular digits. */ + { ISFUNC, rl_digit_argument }, /* Meta-0 */ + { ISFUNC, rl_digit_argument }, /* Meta-1 */ + { ISFUNC, rl_digit_argument }, /* Meta-2 */ + { ISFUNC, rl_digit_argument }, /* Meta-3 */ + { ISFUNC, rl_digit_argument }, /* Meta-4 */ + { ISFUNC, rl_digit_argument }, /* Meta-5 */ + { ISFUNC, rl_digit_argument }, /* Meta-6 */ + { ISFUNC, rl_digit_argument }, /* Meta-7 */ + { ISFUNC, rl_digit_argument }, /* Meta-8 */ + { ISFUNC, rl_digit_argument }, /* Meta-9 */ + + /* A little more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-: */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-; */ + { ISFUNC, rl_beginning_of_history }, /* Meta-< */ + { ISFUNC, rl_possible_completions }, /* Meta-= */ + { ISFUNC, rl_end_of_history }, /* Meta-> */ + { ISFUNC, rl_possible_completions }, /* Meta-? */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-@ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-A */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-B */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-C */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-D */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-E */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-F */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-G */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-H */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-I */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-J */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-K */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-L */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-M */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-N */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-O */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-P */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-R */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-S */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-T */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-U */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-V */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-W */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-X */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ + + /* Some more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-[ */ /* was rl_arrow_keys */ + { ISFUNC, rl_delete_horizontal_space }, /* Meta-\ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-^ */ + { ISFUNC, rl_yank_last_arg }, /* Meta-_ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-` */ + + /* Lowercase alphabet. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-a */ + { ISFUNC, rl_backward_word }, /* Meta-b */ + { ISFUNC, rl_capitalize_word }, /* Meta-c */ + { ISFUNC, rl_kill_word }, /* Meta-d */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-e */ + { ISFUNC, rl_forward_word }, /* Meta-f */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-g */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-h */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-i */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-j */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-k */ + { ISFUNC, rl_downcase_word }, /* Meta-l */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-m */ + { ISFUNC, rl_noninc_forward_search }, /* Meta-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-o */ /* was rl_arrow_keys */ + { ISFUNC, rl_noninc_reverse_search }, /* Meta-p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-q */ + { ISFUNC, rl_revert_line }, /* Meta-r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-s */ + { ISFUNC, rl_transpose_words }, /* Meta-t */ + { ISFUNC, rl_upcase_word }, /* Meta-u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-x */ + { ISFUNC, rl_yank_pop }, /* Meta-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-z */ + + /* Final punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-{ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-| */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Meta-} */ + { ISFUNC, rl_tilde_expand }, /* Meta-~ */ + { ISFUNC, rl_backward_kill_word }, /* Meta-rubout */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; + +KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = { + + /* Control keys. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-d */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-h */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-i */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-j */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-k */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-l */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-m */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-q */ + { ISFUNC, rl_re_read_init_file }, /* Control-r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-s */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-t */ + { ISFUNC, rl_undo_command }, /* Control-u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-w */ + { ISFUNC, rl_exchange_point_and_mark }, /* Control-x */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-[ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* SPACE */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* # */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* $ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* % */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* & */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ' */ + { ISFUNC, rl_start_kbd_macro }, /* ( */ + { ISFUNC, rl_end_kbd_macro }, /* ) */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* * */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* + */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* , */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* - */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* . */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 0 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 1 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 2 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 3 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 4 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 5 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 6 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 7 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 8 */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* : */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ; */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* < */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* = */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* > */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ? */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* [ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* \ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ^ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* _ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* c */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* d */ + { ISFUNC, rl_call_last_kbd_macro }, /* e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* f */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* h */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* i */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* j */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* k */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* l */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* m */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* o */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* q */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* s */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* t */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* x */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* { */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* | */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* } */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_line }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; diff --git a/cmd-line-utils/readline/funmap.c b/cmd-line-utils/readline/funmap.c new file mode 100644 index 00000000000..fe9a1da43d7 --- /dev/null +++ b/cmd-line-utils/readline/funmap.c @@ -0,0 +1,253 @@ +/* funmap.c -- attach names to functions. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* BUFSIZ */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "rlconf.h" +#include "readline.h" + +#include "xmalloc.h" + +#ifdef __STDC__ +typedef int QSFUNC (const void *, const void *); +#else +typedef int QSFUNC (); +#endif + +extern int _rl_qsort_string_compare PARAMS((char **, char **)); + +FUNMAP **funmap; +static int funmap_size; +static int funmap_entry; + +/* After initializing the function map, this is the index of the first + program specific function. */ +int funmap_program_specific_entry_start; + +static FUNMAP default_funmap[] = { + { "abort", rl_abort }, + { "accept-line", rl_newline }, + { "arrow-key-prefix", rl_arrow_keys }, + { "backward-byte", rl_backward_byte }, + { "backward-char", rl_backward_char }, + { "backward-delete-char", rl_rubout }, + { "backward-kill-line", rl_backward_kill_line }, + { "backward-kill-word", rl_backward_kill_word }, + { "backward-word", rl_backward_word }, + { "beginning-of-history", rl_beginning_of_history }, + { "beginning-of-line", rl_beg_of_line }, + { "call-last-kbd-macro", rl_call_last_kbd_macro }, + { "capitalize-word", rl_capitalize_word }, + { "character-search", rl_char_search }, + { "character-search-backward", rl_backward_char_search }, + { "clear-screen", rl_clear_screen }, + { "complete", rl_complete }, + { "copy-backward-word", rl_copy_backward_word }, + { "copy-forward-word", rl_copy_forward_word }, + { "copy-region-as-kill", rl_copy_region_to_kill }, + { "delete-char", rl_delete }, + { "delete-char-or-list", rl_delete_or_show_completions }, + { "delete-horizontal-space", rl_delete_horizontal_space }, + { "digit-argument", rl_digit_argument }, + { "do-lowercase-version", rl_do_lowercase_version }, + { "downcase-word", rl_downcase_word }, + { "dump-functions", rl_dump_functions }, + { "dump-macros", rl_dump_macros }, + { "dump-variables", rl_dump_variables }, + { "emacs-editing-mode", rl_emacs_editing_mode }, + { "end-kbd-macro", rl_end_kbd_macro }, + { "end-of-history", rl_end_of_history }, + { "end-of-line", rl_end_of_line }, + { "exchange-point-and-mark", rl_exchange_point_and_mark }, + { "forward-backward-delete-char", rl_rubout_or_delete }, + { "forward-byte", rl_forward_byte }, + { "forward-char", rl_forward_char }, + { "forward-search-history", rl_forward_search_history }, + { "forward-word", rl_forward_word }, + { "history-search-backward", rl_history_search_backward }, + { "history-search-forward", rl_history_search_forward }, + { "insert-comment", rl_insert_comment }, + { "insert-completions", rl_insert_completions }, + { "kill-whole-line", rl_kill_full_line }, + { "kill-line", rl_kill_line }, + { "kill-region", rl_kill_region }, + { "kill-word", rl_kill_word }, + { "menu-complete", rl_menu_complete }, + { "next-history", rl_get_next_history }, + { "non-incremental-forward-search-history", rl_noninc_forward_search }, + { "non-incremental-reverse-search-history", rl_noninc_reverse_search }, + { "non-incremental-forward-search-history-again", rl_noninc_forward_search_again }, + { "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again }, + { "overwrite-mode", rl_overwrite_mode }, +#ifdef __CYGWIN__ + { "paste-from-clipboard", rl_paste_from_clipboard }, +#endif + { "possible-completions", rl_possible_completions }, + { "previous-history", rl_get_previous_history }, + { "quoted-insert", rl_quoted_insert }, + { "re-read-init-file", rl_re_read_init_file }, + { "redraw-current-line", rl_refresh_line}, + { "reverse-search-history", rl_reverse_search_history }, + { "revert-line", rl_revert_line }, + { "self-insert", rl_insert }, + { "set-mark", rl_set_mark }, + { "start-kbd-macro", rl_start_kbd_macro }, + { "tab-insert", rl_tab_insert }, + { "tilde-expand", rl_tilde_expand }, + { "transpose-chars", rl_transpose_chars }, + { "transpose-words", rl_transpose_words }, + { "tty-status", rl_tty_status }, + { "undo", rl_undo_command }, + { "universal-argument", rl_universal_argument }, + { "unix-line-discard", rl_unix_line_discard }, + { "unix-word-rubout", rl_unix_word_rubout }, + { "upcase-word", rl_upcase_word }, + { "yank", rl_yank }, + { "yank-last-arg", rl_yank_last_arg }, + { "yank-nth-arg", rl_yank_nth_arg }, + { "yank-pop", rl_yank_pop }, + +#if defined (VI_MODE) + { "vi-append-eol", rl_vi_append_eol }, + { "vi-append-mode", rl_vi_append_mode }, + { "vi-arg-digit", rl_vi_arg_digit }, + { "vi-back-to-indent", rl_vi_back_to_indent }, + { "vi-bWord", rl_vi_bWord }, + { "vi-bword", rl_vi_bword }, + { "vi-change-case", rl_vi_change_case }, + { "vi-change-char", rl_vi_change_char }, + { "vi-change-to", rl_vi_change_to }, + { "vi-char-search", rl_vi_char_search }, + { "vi-column", rl_vi_column }, + { "vi-complete", rl_vi_complete }, + { "vi-delete", rl_vi_delete }, + { "vi-delete-to", rl_vi_delete_to }, + { "vi-eWord", rl_vi_eWord }, + { "vi-editing-mode", rl_vi_editing_mode }, + { "vi-end-word", rl_vi_end_word }, + { "vi-eof-maybe", rl_vi_eof_maybe }, + { "vi-eword", rl_vi_eword }, + { "vi-fWord", rl_vi_fWord }, + { "vi-fetch-history", rl_vi_fetch_history }, + { "vi-first-print", rl_vi_first_print }, + { "vi-fword", rl_vi_fword }, + { "vi-goto-mark", rl_vi_goto_mark }, + { "vi-insert-beg", rl_vi_insert_beg }, + { "vi-insertion-mode", rl_vi_insertion_mode }, + { "vi-match", rl_vi_match }, + { "vi-movement-mode", rl_vi_movement_mode }, + { "vi-next-word", rl_vi_next_word }, + { "vi-overstrike", rl_vi_overstrike }, + { "vi-overstrike-delete", rl_vi_overstrike_delete }, + { "vi-prev-word", rl_vi_prev_word }, + { "vi-put", rl_vi_put }, + { "vi-redo", rl_vi_redo }, + { "vi-replace", rl_vi_replace }, + { "vi-search", rl_vi_search }, + { "vi-search-again", rl_vi_search_again }, + { "vi-set-mark", rl_vi_set_mark }, + { "vi-subst", rl_vi_subst }, + { "vi-tilde-expand", rl_vi_tilde_expand }, + { "vi-yank-arg", rl_vi_yank_arg }, + { "vi-yank-to", rl_vi_yank_to }, +#endif /* VI_MODE */ + + {(char *)NULL, (rl_command_func_t *)NULL } +}; + +int +rl_add_funmap_entry (name, function) + const char *name; + rl_command_func_t *function; +{ + if (funmap_entry + 2 >= funmap_size) + { + funmap_size += 64; + funmap = (FUNMAP **)xrealloc (funmap, funmap_size * sizeof (FUNMAP *)); + } + + funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP)); + funmap[funmap_entry]->name = name; + funmap[funmap_entry]->function = function; + + funmap[++funmap_entry] = (FUNMAP *)NULL; + return funmap_entry; +} + +static int funmap_initialized; + +/* Make the funmap contain all of the default entries. */ +void +rl_initialize_funmap () +{ + register int i; + + if (funmap_initialized) + return; + + for (i = 0; default_funmap[i].name; i++) + rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function); + + funmap_initialized = 1; + funmap_program_specific_entry_start = i; +} + +/* Produce a NULL terminated array of known function names. The array + is sorted. The array itself is allocated, but not the strings inside. + You should free () the array when you done, but not the pointrs. */ +const char ** +rl_funmap_names () +{ + const char **result; + int result_size, result_index; + + /* Make sure that the function map has been initialized. */ + rl_initialize_funmap (); + + for (result_index = result_size = 0, result = (const char **)NULL; funmap[result_index]; result_index++) + { + if (result_index + 2 > result_size) + { + result_size += 20; + result = (const char **)xrealloc (result, result_size * sizeof (char *)); + } + + result[result_index] = funmap[result_index]->name; + result[result_index + 1] = (char *)NULL; + } + + qsort (result, result_index, sizeof (char *), (QSFUNC *)_rl_qsort_string_compare); + return (result); +} diff --git a/cmd-line-utils/readline/histexpand.c b/cmd-line-utils/readline/histexpand.c new file mode 100644 index 00000000000..f01d54c5b1d --- /dev/null +++ b/cmd-line-utils/readline/histexpand.c @@ -0,0 +1,1491 @@ +/* histexpand.c -- history expansion. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# ifndef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "rlmbutil.h" + +#include "history.h" +#include "histlib.h" + +#include "rlshell.h" +#include "xmalloc.h" + +#define HISTORY_WORD_DELIMITERS " \t\n;&()|<>" +#define HISTORY_QUOTE_CHARACTERS "\"'`" + +typedef int _hist_search_func_t PARAMS((const char *, int)); + +extern int rl_byte_oriented; /* declared in mbutil.c */ + +static char error_pointer; + +static char *subst_lhs; +static char *subst_rhs; +static int subst_lhs_len; +static int subst_rhs_len; + +static char *get_history_word_specifier PARAMS((char *, char *, int *)); +static char *history_find_word PARAMS((char *, int)); + +static char *quote_breaks PARAMS((char *)); + +/* Variables exported by this file. */ +/* The character that represents the start of a history expansion + request. This is usually `!'. */ +char history_expansion_char = '!'; + +/* The character that invokes word substitution if found at the start of + a line. This is usually `^'. */ +char history_subst_char = '^'; + +/* During tokenization, if this character is seen as the first character + of a word, then it, and all subsequent characters upto a newline are + ignored. For a Bourne shell, this should be '#'. Bash special cases + the interactive comment character to not be a comment delimiter. */ +char history_comment_char = '\0'; + +/* The list of characters which inhibit the expansion of text if found + immediately following history_expansion_char. */ +const char *history_no_expand_chars = " \t\n\r="; + +/* If set to a non-zero value, single quotes inhibit history expansion. + The default is 0. */ +int history_quotes_inhibit_expansion = 0; + +/* Used to split words by history_tokenize_internal. */ +const char *history_word_delimiters = HISTORY_WORD_DELIMITERS; + +/* If set, this points to a function that is called to verify that a + particular history expansion should be performed. */ +rl_linebuf_func_t *history_inhibit_expansion_function; + +/* **************************************************************** */ +/* */ +/* History Expansion */ +/* */ +/* **************************************************************** */ + +/* Hairy history expansion on text, not tokens. This is of general + use, and thus belongs in this library. */ + +/* The last string searched for by a !?string? search. */ +static char *search_string; + +/* The last string matched by a !?string? search. */ +static char *search_match; + +/* Return the event specified at TEXT + OFFSET modifying OFFSET to + point to after the event specifier. Just a pointer to the history + line is returned; NULL is returned in the event of a bad specifier. + You pass STRING with *INDEX equal to the history_expansion_char that + begins this specification. + DELIMITING_QUOTE is a character that is allowed to end the string + specification for what to search for in addition to the normal + characters `:', ` ', `\t', `\n', and sometimes `?'. + So you might call this function like: + line = get_history_event ("!echo:p", &index, 0); */ +char * +get_history_event (string, caller_index, delimiting_quote) + const char *string; + int *caller_index; + int delimiting_quote; +{ + register int i; + register char c; + HIST_ENTRY *entry; + int which, sign, local_index, substring_okay; + _hist_search_func_t *search_func; + char *temp; + + /* The event can be specified in a number of ways. + + !! the previous command + !n command line N + !-n current command-line minus N + !str the most recent command starting with STR + !?str[?] + the most recent command containing STR + + All values N are determined via HISTORY_BASE. */ + + i = *caller_index; + + if (string[i] != history_expansion_char) + return ((char *)NULL); + + /* Move on to the specification. */ + i++; + + sign = 1; + substring_okay = 0; + +#define RETURN_ENTRY(e, w) \ + return ((e = history_get (w)) ? e->line : (char *)NULL) + + /* Handle !! case. */ + if (string[i] == history_expansion_char) + { + i++; + which = history_base + (history_length - 1); + *caller_index = i; + RETURN_ENTRY (entry, which); + } + + /* Hack case of numeric line specification. */ + if (string[i] == '-') + { + sign = -1; + i++; + } + + if (_rl_digit_p (string[i])) + { + /* Get the extent of the digits and compute the value. */ + for (which = 0; _rl_digit_p (string[i]); i++) + which = (which * 10) + _rl_digit_value (string[i]); + + *caller_index = i; + + if (sign < 0) + which = (history_length + history_base) - which; + + RETURN_ENTRY (entry, which); + } + + /* This must be something to search for. If the spec begins with + a '?', then the string may be anywhere on the line. Otherwise, + the string must be found at the start of a line. */ + if (string[i] == '?') + { + substring_okay++; + i++; + } + + /* Only a closing `?' or a newline delimit a substring search string. */ + for (local_index = i; (c = string[i]); i++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + /* These produce warnings because we're passing a const string to a + function that takes a non-const string. */ + _rl_adjust_point (string, i, &ps); + if ((v = _rl_get_char_len (string + i, &ps)) > 1) + { + i += v - 1; + continue; + } + } + else +#endif /* HANDLE_MULTIBYTE */ + if ((!substring_okay && (whitespace (c) || c == ':' || + (history_search_delimiter_chars && member (c, history_search_delimiter_chars)) || + string[i] == delimiting_quote)) || + string[i] == '\n' || + (substring_okay && string[i] == '?')) + break; + + which = i - local_index; + temp = (char *)xmalloc (1 + which); + if (which) + strncpy (temp, string + local_index, which); + temp[which] = '\0'; + + if (substring_okay && string[i] == '?') + i++; + + *caller_index = i; + +#define FAIL_SEARCH() \ + do { \ + history_offset = history_length; free (temp) ; return (char *)NULL; \ + } while (0) + + /* If there is no search string, try to use the previous search string, + if one exists. If not, fail immediately. */ + if (*temp == '\0' && substring_okay) + { + if (search_string) + { + free (temp); + temp = savestring (search_string); + } + else + FAIL_SEARCH (); + } + + search_func = substring_okay ? history_search : history_search_prefix; + while (1) + { + local_index = (*search_func) (temp, -1); + + if (local_index < 0) + FAIL_SEARCH (); + + if (local_index == 0 || substring_okay) + { + entry = current_history (); + history_offset = history_length; + + /* If this was a substring search, then remember the + string that we matched for word substitution. */ + if (substring_okay) + { + FREE (search_string); + search_string = temp; + + FREE (search_match); + search_match = history_find_word (entry->line, local_index); + } + else + free (temp); + + return (entry->line); + } + + if (history_offset) + history_offset--; + else + FAIL_SEARCH (); + } +#undef FAIL_SEARCH +#undef RETURN_ENTRY +} + +/* Function for extracting single-quoted strings. Used for inhibiting + history expansion within single quotes. */ + +/* Extract the contents of STRING as if it is enclosed in single quotes. + SINDEX, when passed in, is the offset of the character immediately + following the opening single quote; on exit, SINDEX is left pointing + to the closing single quote. */ +static void +hist_string_extract_single_quoted (string, sindex) + char *string; + int *sindex; +{ + register int i; + + for (i = *sindex; string[i] && string[i] != '\''; i++) + ; + + *sindex = i; +} + +static char * +quote_breaks (s) + char *s; +{ + register char *p, *r; + char *ret; + int len = 3; + + for (p = s; p && *p; p++, len++) + { + if (*p == '\'') + len += 3; + else if (whitespace (*p) || *p == '\n') + len += 2; + } + + r = ret = (char *)xmalloc (len); + *r++ = '\''; + for (p = s; p && *p; ) + { + if (*p == '\'') + { + *r++ = '\''; + *r++ = '\\'; + *r++ = '\''; + *r++ = '\''; + p++; + } + else if (whitespace (*p) || *p == '\n') + { + *r++ = '\''; + *r++ = *p++; + *r++ = '\''; + } + else + *r++ = *p++; + } + *r++ = '\''; + *r = '\0'; + return ret; +} + +static char * +hist_error(s, start, current, errtype) + char *s; + int start, current, errtype; +{ + char *temp; + const char *emsg; + int ll, elen; + + ll = current - start; + + switch (errtype) + { + case EVENT_NOT_FOUND: + emsg = "event not found"; + elen = 15; + break; + case BAD_WORD_SPEC: + emsg = "bad word specifier"; + elen = 18; + break; + case SUBST_FAILED: + emsg = "substitution failed"; + elen = 19; + break; + case BAD_MODIFIER: + emsg = "unrecognized history modifier"; + elen = 29; + break; + case NO_PREV_SUBST: + emsg = "no previous substitution"; + elen = 24; + break; + default: + emsg = "unknown expansion error"; + elen = 23; + break; + } + + temp = (char *)xmalloc (ll + elen + 3); + strncpy (temp, s + start, ll); + temp[ll] = ':'; + temp[ll + 1] = ' '; + strcpy (temp + ll + 2, emsg); + return (temp); +} + +/* Get a history substitution string from STR starting at *IPTR + and return it. The length is returned in LENPTR. + + A backslash can quote the delimiter. If the string is the + empty string, the previous pattern is used. If there is + no previous pattern for the lhs, the last history search + string is used. + + If IS_RHS is 1, we ignore empty strings and set the pattern + to "" anyway. subst_lhs is not changed if the lhs is empty; + subst_rhs is allowed to be set to the empty string. */ + +static char * +get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr) + char *str; + int *iptr, delimiter, is_rhs, *lenptr; +{ + register int si, i, j, k; + char *s; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; +#endif + + s = (char *)NULL; + i = *iptr; + +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); + _rl_adjust_point (str, i, &ps); +#endif + + for (si = i; str[si] && str[si] != delimiter; si++) +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + if ((v = _rl_get_char_len (str + si, &ps)) > 1) + si += v - 1; + else if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (str[si] == '\\' && str[si + 1] == delimiter) + si++; + + if (si > i || is_rhs) + { + s = (char *)xmalloc (si - i + 1); + for (j = 0, k = i; k < si; j++, k++) + { + /* Remove a backslash quoting the search string delimiter. */ + if (str[k] == '\\' && str[k + 1] == delimiter) + k++; + s[j] = str[k]; + } + s[j] = '\0'; + if (lenptr) + *lenptr = j; + } + + i = si; + if (str[i]) + i++; + *iptr = i; + + return s; +} + +static void +postproc_subst_rhs () +{ + char *new; + int i, j, new_size; + + new = (char *)xmalloc (new_size = subst_rhs_len + subst_lhs_len); + for (i = j = 0; i < subst_rhs_len; i++) + { + if (subst_rhs[i] == '&') + { + if (j + subst_lhs_len >= new_size) + new = (char *)xrealloc (new, (new_size = new_size * 2 + subst_lhs_len)); + strcpy (new + j, subst_lhs); + j += subst_lhs_len; + } + else + { + /* a single backslash protects the `&' from lhs interpolation */ + if (subst_rhs[i] == '\\' && subst_rhs[i + 1] == '&') + i++; + if (j >= new_size) + new = (char *)xrealloc (new, new_size *= 2); + new[j++] = subst_rhs[i]; + } + } + new[j] = '\0'; + free (subst_rhs); + subst_rhs = new; + subst_rhs_len = j; +} + +/* Expand the bulk of a history specifier starting at STRING[START]. + Returns 0 if everything is OK, -1 if an error occurred, and 1 + if the `p' modifier was supplied and the caller should just print + the returned string. Returns the new index into string in + *END_INDEX_PTR, and the expanded specifier in *RET_STRING. */ +static int +history_expand_internal (string, start, end_index_ptr, ret_string, current_line) + char *string; + int start, *end_index_ptr; + char **ret_string; + char *current_line; /* for !# */ +{ + int i, n, starting_index; + int substitute_globally, want_quotes, print_only; + char *event, *temp, *result, *tstr, *t, c, *word_spec; + int result_len; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + result = (char *)xmalloc (result_len = 128); + + i = start; + + /* If it is followed by something that starts a word specifier, + then !! is implied as the event specifier. */ + + if (member (string[i + 1], ":$*%^")) + { + char fake_s[3]; + int fake_i = 0; + i++; + fake_s[0] = fake_s[1] = history_expansion_char; + fake_s[2] = '\0'; + event = get_history_event (fake_s, &fake_i, 0); + } + else if (string[i + 1] == '#') + { + i += 2; + event = current_line; + } + else + { + int quoted_search_delimiter = 0; + + /* If the character before this `!' is a double or single + quote, then this expansion takes place inside of the + quoted string. If we have to search for some text ("!foo"), + allow the delimiter to end the search string. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int c, l; + l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY); + c = string[l]; + /* XXX - original patch had i - 1 ??? If i == 0 it would fail. */ + if (i && (c == '\'' || c == '"')) + quoted_search_delimiter = c; + } + else +#endif /* HANDLE_MULTIBYTE */ + if (i && (string[i - 1] == '\'' || string[i - 1] == '"')) + quoted_search_delimiter = string[i - 1]; + + event = get_history_event (string, &i, quoted_search_delimiter); + } + + if (event == 0) + { + *ret_string = hist_error (string, start, i, EVENT_NOT_FOUND); + free (result); + return (-1); + } + + /* If a word specifier is found, then do what that requires. */ + starting_index = i; + word_spec = get_history_word_specifier (string, event, &i); + + /* There is no such thing as a `malformed word specifier'. However, + it is possible for a specifier that has no match. In that case, + we complain. */ + if (word_spec == (char *)&error_pointer) + { + *ret_string = hist_error (string, starting_index, i, BAD_WORD_SPEC); + free (result); + return (-1); + } + + /* If no word specifier, than the thing of interest was the event. */ + temp = word_spec ? savestring (word_spec) : savestring (event); + FREE (word_spec); + + /* Perhaps there are other modifiers involved. Do what they say. */ + want_quotes = substitute_globally = print_only = 0; + starting_index = i; + + while (string[i] == ':') + { + c = string[i + 1]; + + if (c == 'g') + { + substitute_globally = 1; + i++; + c = string[i + 1]; + } + + switch (c) + { + default: + *ret_string = hist_error (string, i+1, i+2, BAD_MODIFIER); + free (result); + free (temp); + return -1; + + case 'q': + want_quotes = 'q'; + break; + + case 'x': + want_quotes = 'x'; + break; + + /* :p means make this the last executed line. So we + return an error state after adding this line to the + history. */ + case 'p': + print_only++; + break; + + /* :t discards all but the last part of the pathname. */ + case 't': + tstr = strrchr (temp, '/'); + if (tstr) + { + tstr++; + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :h discards the last part of a pathname. */ + case 'h': + tstr = strrchr (temp, '/'); + if (tstr) + *tstr = '\0'; + break; + + /* :r discards the suffix. */ + case 'r': + tstr = strrchr (temp, '.'); + if (tstr) + *tstr = '\0'; + break; + + /* :e discards everything but the suffix. */ + case 'e': + tstr = strrchr (temp, '.'); + if (tstr) + { + t = savestring (tstr); + free (temp); + temp = t; + } + break; + + /* :s/this/that substitutes `that' for the first + occurrence of `this'. :gs/this/that substitutes `that' + for each occurrence of `this'. :& repeats the last + substitution. :g& repeats the last substitution + globally. */ + + case '&': + case 's': + { + char *new_event; + int delimiter, failed, si, l_temp; + + if (c == 's') + { + if (i + 2 < (int)strlen (string)) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + _rl_adjust_point (string, i + 2, &ps); + if (_rl_get_char_len (string + i + 2, &ps) > 1) + delimiter = 0; + else + delimiter = string[i + 2]; + } + else +#endif /* HANDLE_MULTIBYTE */ + delimiter = string[i + 2]; + } + else + break; /* no search delimiter */ + + i += 3; + + t = get_subst_pattern (string, &i, delimiter, 0, &subst_lhs_len); + /* An empty substitution lhs with no previous substitution + uses the last search string as the lhs. */ + if (t) + { + FREE (subst_lhs); + subst_lhs = t; + } + else if (!subst_lhs) + { + if (search_string && *search_string) + { + subst_lhs = savestring (search_string); + subst_lhs_len = strlen (subst_lhs); + } + else + { + subst_lhs = (char *) NULL; + subst_lhs_len = 0; + } + } + + FREE (subst_rhs); + subst_rhs = get_subst_pattern (string, &i, delimiter, 1, &subst_rhs_len); + + /* If `&' appears in the rhs, it's supposed to be replaced + with the lhs. */ + if (member ('&', subst_rhs)) + postproc_subst_rhs (); + } + else + i += 2; + + /* If there is no lhs, the substitution can't succeed. */ + if (subst_lhs_len == 0) + { + *ret_string = hist_error (string, starting_index, i, NO_PREV_SUBST); + free (result); + free (temp); + return -1; + } + + l_temp = strlen (temp); + /* Ignore impossible cases. */ + if (subst_lhs_len > l_temp) + { + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + + /* Find the first occurrence of THIS in TEMP. */ + si = 0; + for (failed = 1; (si + subst_lhs_len) <= l_temp; si++) + if (STREQN (temp+si, subst_lhs, subst_lhs_len)) + { + int len = subst_rhs_len - subst_lhs_len + l_temp; + new_event = (char *)xmalloc (1 + len); + strncpy (new_event, temp, si); + strncpy (new_event + si, subst_rhs, subst_rhs_len); + strncpy (new_event + si + subst_rhs_len, + temp + si + subst_lhs_len, + l_temp - (si + subst_lhs_len)); + new_event[len] = '\0'; + free (temp); + temp = new_event; + + failed = 0; + + if (substitute_globally) + { + si += subst_rhs_len; + l_temp = strlen (temp); + substitute_globally++; + continue; + } + else + break; + } + + if (substitute_globally > 1) + { + substitute_globally = 0; + continue; /* don't want to increment i */ + } + + if (failed == 0) + continue; /* don't want to increment i */ + + *ret_string = hist_error (string, starting_index, i, SUBST_FAILED); + free (result); + free (temp); + return (-1); + } + } + i += 2; + } + /* Done with modfiers. */ + /* Believe it or not, we have to back the pointer up by one. */ + --i; + + if (want_quotes) + { + char *x; + + if (want_quotes == 'q') + x = sh_single_quote (temp); + else if (want_quotes == 'x') + x = quote_breaks (temp); + else + x = savestring (temp); + + free (temp); + temp = x; + } + + n = strlen (temp); + if (n >= result_len) + result = (char *)xrealloc (result, n + 2); + strcpy (result, temp); + free (temp); + + *end_index_ptr = i; + *ret_string = result; + return (print_only); +} + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. Returns: + + -1) If there was an error in expansion. + 0) If no expansions took place (or, if the only change in + the text was the de-slashifying of the history expansion + character) + 1) If expansions did take place + 2) If the `p' modifier was given and the caller should print the result + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ + +#define ADD_STRING(s) \ + do \ + { \ + int sl = strlen (s); \ + j += sl; \ + if (j >= result_len) \ + { \ + while (j >= result_len) \ + result_len += 128; \ + result = (char *)xrealloc (result, result_len); \ + } \ + strcpy (result + j - sl, s); \ + } \ + while (0) + +#define ADD_CHAR(c) \ + do \ + { \ + if (j >= result_len - 1) \ + result = (char *)xrealloc (result, result_len += 64); \ + result[j++] = c; \ + result[j] = '\0'; \ + } \ + while (0) + +int +history_expand (hstring, output) + char *hstring; + char **output; +{ + register int j; + int i, r, l, passc, cc, modified, eindex, only_printing; + char *string; + + /* The output string, and its length. */ + int result_len; + char *result; + +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; + mbstate_t ps; +#endif + + /* Used when adding the string. */ + char *temp; + + if (output == 0) + return 0; + + /* Setting the history expansion character to 0 inhibits all + history expansion. */ + if (history_expansion_char == 0) + { + *output = savestring (hstring); + return (0); + } + + /* Prepare the buffer for printing error messages. */ + result = (char *)xmalloc (result_len = 256); + result[0] = '\0'; + + only_printing = modified = 0; + l = strlen (hstring); + + /* Grovel the string. Only backslash and single quotes can quote the + history escape character. We also handle arg specifiers. */ + + /* Before we grovel forever, see if the history_expansion_char appears + anywhere within the text. */ + + /* The quick substitution character is a history expansion all right. That + is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact, + that is the substitution that we do. */ + if (hstring[0] == history_subst_char) + { + string = (char *)xmalloc (l + 5); + + string[0] = string[1] = history_expansion_char; + string[2] = ':'; + string[3] = 's'; + strcpy (string + 4, hstring); + l += 4; + } + else + { +#if defined (HANDLE_MULTIBYTE) + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + string = hstring; + /* If not quick substitution, still maybe have to do expansion. */ + + /* `!' followed by one of the characters in history_no_expand_chars + is NOT an expansion. */ + for (i = 0; string[i]; i++) + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int v; + v = _rl_get_char_len (string + i, &ps); + if (v > 1) + { + i += v - 1; + continue; + } + } +#endif /* HANDLE_MULTIBYTE */ + + cc = string[i + 1]; + /* The history_comment_char, if set, appearing at the beginning + of a word signifies that the rest of the line should not have + history expansion performed on it. + Skip the rest of the line and break out of the loop. */ + if (history_comment_char && string[i] == history_comment_char && + (i == 0 || member (string[i - 1], history_word_delimiters))) + { + while (string[i]) + i++; + break; + } + else if (string[i] == history_expansion_char) + { + if (!cc || member (cc, history_no_expand_chars)) + continue; + /* If the calling application has set + history_inhibit_expansion_function to a function that checks + for special cases that should not be history expanded, + call the function and skip the expansion if it returns a + non-zero value. */ + else if (history_inhibit_expansion_function && + (*history_inhibit_expansion_function) (string, i)) + continue; + else + break; + } + /* XXX - at some point, might want to extend this to handle + double quotes as well. */ + else if (history_quotes_inhibit_expansion && string[i] == '\'') + { + /* If this is bash, single quotes inhibit history expansion. */ + i++; + hist_string_extract_single_quoted (string, &i); + } + else if (history_quotes_inhibit_expansion && string[i] == '\\') + { + /* If this is bash, allow backslashes to quote single + quotes and the history expansion character. */ + if (cc == '\'' || cc == history_expansion_char) + i++; + } + } + + if (string[i] != history_expansion_char) + { + free (result); + *output = savestring (string); + return (0); + } + } + + /* Extract and perform the substitution. */ + for (passc = i = j = 0; i < l; i++) + { + int tchar = string[i]; + + if (passc) + { + passc = 0; + ADD_CHAR (tchar); + continue; + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int k, c; + + c = tchar; + memset (mb, 0, sizeof (mb)); + for (k = 0; k < MB_LEN_MAX; k++) + { + mb[k] = (char)c; + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_get_char_len (mb, &ps) == -2) + c = string[++i]; + else + break; + } + if (strlen (mb) > 1) + { + ADD_STRING (mb); + break; + } + } +#endif /* HANDLE_MULTIBYTE */ + + if (tchar == history_expansion_char) + tchar = -3; + else if (tchar == history_comment_char) + tchar = -2; + + switch (tchar) + { + default: + ADD_CHAR (string[i]); + break; + + case '\\': + passc++; + ADD_CHAR (tchar); + break; + + case '\'': + { + /* If history_quotes_inhibit_expansion is set, single quotes + inhibit history expansion. */ + if (history_quotes_inhibit_expansion) + { + int quote, slen; + + quote = i++; + hist_string_extract_single_quoted (string, &i); + + slen = i - quote + 2; + temp = (char *)xmalloc (slen); + strncpy (temp, string + quote, slen); + temp[slen - 1] = '\0'; + ADD_STRING (temp); + free (temp); + } + else + ADD_CHAR (string[i]); + break; + } + + case -2: /* history_comment_char */ + if (i == 0 || member (string[i - 1], history_word_delimiters)) + { + temp = (char *)xmalloc (l - i + 1); + strcpy (temp, string + i); + ADD_STRING (temp); + free (temp); + i = l; + } + else + ADD_CHAR (string[i]); + break; + + case -3: /* history_expansion_char */ + cc = string[i + 1]; + + /* If the history_expansion_char is followed by one of the + characters in history_no_expand_chars, then it is not a + candidate for expansion of any kind. */ + if (member (cc, history_no_expand_chars)) + { + ADD_CHAR (string[i]); + break; + } + +#if defined (NO_BANG_HASH_MODIFIERS) + /* There is something that is listed as a `word specifier' in csh + documentation which means `the expanded text to this point'. + That is not a word specifier, it is an event specifier. If we + don't want to allow modifiers with `!#', just stick the current + output line in again. */ + if (cc == '#') + { + if (result) + { + temp = (char *)xmalloc (1 + strlen (result)); + strcpy (temp, result); + ADD_STRING (temp); + free (temp); + } + i++; + break; + } +#endif + + r = history_expand_internal (string, i, &eindex, &temp, result); + if (r < 0) + { + *output = temp; + free (result); + if (string != hstring) + free (string); + return -1; + } + else + { + if (temp) + { + modified++; + if (*temp) + ADD_STRING (temp); + free (temp); + } + only_printing = r == 1; + i = eindex; + } + break; + } + } + + *output = result; + if (string != hstring) + free (string); + + if (only_printing) + { + add_history (result); + return (2); + } + + return (modified != 0); +} + +/* Return a consed string which is the word specified in SPEC, and found + in FROM. NULL is returned if there is no spec. The address of + ERROR_POINTER is returned if the word specified cannot be found. + CALLER_INDEX is the offset in SPEC to start looking; it is updated + to point to just after the last character parsed. */ +static char * +get_history_word_specifier (spec, from, caller_index) + char *spec, *from; + int *caller_index; +{ + register int i = *caller_index; + int first, last; + int expecting_word_spec = 0; + char *result; + + /* The range of words to return doesn't exist yet. */ + first = last = 0; + result = (char *)NULL; + + /* If we found a colon, then this *must* be a word specification. If + it isn't, then it is an error. */ + if (spec[i] == ':') + { + i++; + expecting_word_spec++; + } + + /* Handle special cases first. */ + + /* `%' is the word last searched for. */ + if (spec[i] == '%') + { + *caller_index = i + 1; + return (search_match ? savestring (search_match) : savestring ("")); + } + + /* `*' matches all of the arguments, but not the command. */ + if (spec[i] == '*') + { + *caller_index = i + 1; + result = history_arg_extract (1, '$', from); + return (result ? result : savestring ("")); + } + + /* `$' is last arg. */ + if (spec[i] == '$') + { + *caller_index = i + 1; + return (history_arg_extract ('$', '$', from)); + } + + /* Try to get FIRST and LAST figured out. */ + + if (spec[i] == '-') + first = 0; + else if (spec[i] == '^') + first = 1; + else if (_rl_digit_p (spec[i]) && expecting_word_spec) + { + for (first = 0; _rl_digit_p (spec[i]); i++) + first = (first * 10) + _rl_digit_value (spec[i]); + } + else + return ((char *)NULL); /* no valid `first' for word specifier */ + + if (spec[i] == '^' || spec[i] == '*') + { + last = (spec[i] == '^') ? 1 : '$'; /* x* abbreviates x-$ */ + i++; + } + else if (spec[i] != '-') + last = first; + else + { + i++; + + if (_rl_digit_p (spec[i])) + { + for (last = 0; _rl_digit_p (spec[i]); i++) + last = (last * 10) + _rl_digit_value (spec[i]); + } + else if (spec[i] == '$') + { + i++; + last = '$'; + } +#if 0 + else if (!spec[i] || spec[i] == ':') + /* check against `:' because there could be a modifier separator */ +#else + else + /* csh seems to allow anything to terminate the word spec here, + leaving it as an abbreviation. */ +#endif + last = -1; /* x- abbreviates x-$ omitting word `$' */ + } + + *caller_index = i; + + if (last >= first || last == '$' || last < 0) + result = history_arg_extract (first, last, from); + + return (result ? result : (char *)&error_pointer); +} + +/* Extract the args specified, starting at FIRST, and ending at LAST. + The args are taken from STRING. If either FIRST or LAST is < 0, + then make that arg count from the right (subtract from the number of + tokens, so that FIRST = -1 means the next to last token on the line). + If LAST is `$' the last arg from STRING is used. */ +char * +history_arg_extract (first, last, string) + int first, last; + const char *string; +{ + register int i, len; + char *result; + int size, offset; + char **list; + + /* XXX - think about making history_tokenize return a struct array, + each struct in array being a string and a length to avoid the + calls to strlen below. */ + if ((list = history_tokenize (string)) == NULL) + return ((char *)NULL); + + for (len = 0; list[len]; len++) + ; + + if (last < 0) + last = len + last - 1; + + if (first < 0) + first = len + first - 1; + + if (last == '$') + last = len - 1; + + if (first == '$') + first = len - 1; + + last++; + + if (first >= len || last > len || first < 0 || last < 0 || first > last) + result = ((char *)NULL); + else + { + for (size = 0, i = first; i < last; i++) + size += strlen (list[i]) + 1; + result = (char *)xmalloc (size + 1); + result[0] = '\0'; + + for (i = first, offset = 0; i < last; i++) + { + strcpy (result + offset, list[i]); + offset += strlen (list[i]); + if (i + 1 < last) + { + result[offset++] = ' '; + result[offset] = 0; + } + } + } + + for (i = 0; i < len; i++) + free (list[i]); + free (list); + + return (result); +} + +#define slashify_in_quotes "\\`\"$" + +/* Parse STRING into tokens and return an array of strings. If WIND is + not -1 and INDP is not null, we also want the word surrounding index + WIND. The position in the returned array of strings is returned in + *INDP. */ +static char ** +history_tokenize_internal (string, wind, indp) + const char *string; + int wind, *indp; +{ + char **result; + register int i, start, result_index, size; + int len, delimiter; + + /* If we're searching for a string that's not part of a word (e.g., " "), + make sure we set *INDP to a reasonable value. */ + if (indp && wind != -1) + *indp = -1; + + /* Get a token, and stuff it into RESULT. The tokens are split + exactly where the shell would split them. */ + for (i = result_index = size = 0, result = (char **)NULL; string[i]; ) + { + delimiter = 0; + + /* Skip leading whitespace. */ + for (; string[i] && whitespace (string[i]); i++) + ; + if (string[i] == 0 || string[i] == history_comment_char) + return (result); + + start = i; + + if (member (string[i], "()\n")) + { + i++; + goto got_token; + } + + if (member (string[i], "<>;&|$")) + { + int peek = string[i + 1]; + + if (peek == string[i] && peek != '$') + { + if (peek == '<' && string[i + 2] == '-') + i++; + i += 2; + goto got_token; + } + else + { + if ((peek == '&' && (string[i] == '>' || string[i] == '<')) || + ((peek == '>') && (string[i] == '&')) || + ((peek == '(') && (string[i] == '$'))) + { + i += 2; + goto got_token; + } + } + if (string[i] != '$') + { + i++; + goto got_token; + } + } + + /* Get word from string + i; */ + + if (member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i++]; + + for (; string[i]; i++) + { + if (string[i] == '\\' && string[i + 1] == '\n') + { + i++; + continue; + } + + if (string[i] == '\\' && delimiter != '\'' && + (delimiter != '"' || member (string[i], slashify_in_quotes))) + { + i++; + continue; + } + + if (delimiter && string[i] == delimiter) + { + delimiter = 0; + continue; + } + + if (!delimiter && (member (string[i], history_word_delimiters))) + break; + + if (!delimiter && member (string[i], HISTORY_QUOTE_CHARACTERS)) + delimiter = string[i]; + } + + got_token: + + /* If we are looking for the word in which the character at a + particular index falls, remember it. */ + if (indp && wind != -1 && wind >= start && wind < i) + *indp = result_index; + + len = i - start; + if (result_index + 2 >= size) + result = (char **)xrealloc (result, ((size += 10) * sizeof (char *))); + result[result_index] = (char *)xmalloc (1 + len); + strncpy (result[result_index], string + start, len); + result[result_index][len] = '\0'; + result[++result_index] = (char *)NULL; + } + + return (result); +} + +/* Return an array of tokens, much as the shell might. The tokens are + parsed out of STRING. */ +char ** +history_tokenize (string) + const char *string; +{ + return (history_tokenize_internal (string, -1, (int *)NULL)); +} + +/* Find and return the word which contains the character at index IND + in the history line LINE. Used to save the word matched by the + last history !?string? search. */ +static char * +history_find_word (line, ind) + char *line; + int ind; +{ + char **words, *s; + int i, wind; + + words = history_tokenize_internal (line, ind, &wind); + if (wind == -1 || words == 0) + return ((char *)NULL); + s = words[wind]; + for (i = 0; i < wind; i++) + free (words[i]); + for (i = wind + 1; words[i]; i++) + free (words[i]); + free (words); + return s; +} diff --git a/cmd-line-utils/readline/histfile.c b/cmd-line-utils/readline/histfile.c new file mode 100644 index 00000000000..60a91251b7a --- /dev/null +++ b/cmd-line-utils/readline/histfile.c @@ -0,0 +1,479 @@ +/* histfile.c - functions to manipulate the history file. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* The goal is to make the implementation transparent, so that you + don't have to know what data types are used, just what functions + you can call. I think I have done that. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> + +#include <sys/types.h> +#ifndef _MINIX +# include <sys/file.h> +#endif +#include "posixstat.h" +#include <fcntl.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (__EMX__) || defined (__CYGWIN__) +# undef HAVE_MMAP +#endif + +#ifdef HAVE_MMAP +# include <sys/mman.h> + +# ifdef MAP_FILE +# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) +# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) +# else +# define MAP_RFLAGS MAP_PRIVATE +# define MAP_WFLAGS MAP_SHARED +# endif + +# ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +# endif + +#endif /* HAVE_MMAP */ + +/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment + on win 95/98/nt), we want to open files with O_BINARY mode so that there + is no \n -> \r\n conversion performed. On other systems, we don't want to + mess around with O_BINARY at all, so we ensure that it's defined to 0. */ +#if defined (__EMX__) || defined (__CYGWIN__) +# ifndef O_BINARY +# define O_BINARY 0 +# endif +#else /* !__EMX__ && !__CYGWIN__ */ +# undef O_BINARY +# define O_BINARY 0 +#endif /* !__EMX__ && !__CYGWIN__ */ + +#include <errno.h> +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#include "history.h" +#include "histlib.h" + +#include "rlshell.h" +#include "xmalloc.h" + +/* Return the string that should be used in the place of this + filename. This only matters when you don't specify the + filename to read_history (), or write_history (). */ +static char * +history_filename (filename) + const char *filename; +{ + char *return_val; + const char *home; + int home_len; + + return_val = filename ? savestring (filename) : (char *)NULL; + + if (return_val) + return (return_val); + + home = sh_get_env_value ("HOME"); + + if (home == 0) + { + home = "."; + home_len = 1; + } + else + home_len = strlen (home); + + return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ + strcpy (return_val, home); + return_val[home_len] = '/'; +#if defined (__MSDOS__) + strcpy (return_val + home_len + 1, "_history"); +#else + strcpy (return_val + home_len + 1, ".history"); +#endif + + return (return_val); +} + +/* Add the contents of FILENAME to the history list, a line at a time. + If FILENAME is NULL, then read from ~/.history. Returns 0 if + successful, or errno if not. */ +int +read_history (filename) + const char *filename; +{ + return (read_history_range (filename, 0, -1)); +} + +/* Read a range of lines from FILENAME, adding them to the history list. + Start reading at the FROM'th line and end at the TO'th. If FROM + is zero, start at the beginning. If TO is less than FROM, read + until the end of the file. If FILENAME is NULL, then read from + ~/.history. Returns 0 if successful, or errno if not. */ +int +read_history_range (filename, from, to) + const char *filename; + int from, to; +{ + register char *line_start, *line_end; + char *input, *buffer, *bufend; + int file, current_line, chars_read; + struct stat finfo; + size_t file_size; + + buffer = (char *)NULL; + input = history_filename (filename); + file = open (input, O_RDONLY|O_BINARY, 0666); + + if ((file < 0) || (fstat (file, &finfo) == -1)) + goto error_and_exit; + + file_size = (size_t)finfo.st_size; + + /* check for overflow on very large files */ + if (file_size != finfo.st_size || file_size + 1 < file_size) + { +#if defined (EFBIG) + errno = EFBIG; +#elif defined (EOVERFLOW) + errno = EOVERFLOW; +#endif + goto error_and_exit; + } + +#ifdef HAVE_MMAP + /* We map read/write and private so we can change newlines to NULs without + affecting the underlying object. */ + buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); + if ((void *)buffer == MAP_FAILED) + goto error_and_exit; + chars_read = file_size; +#else + buffer = (char *)malloc (file_size + 1); + if (buffer == 0) + goto error_and_exit; + + chars_read = read (file, buffer, file_size); +#endif + if (chars_read < 0) + { + error_and_exit: + chars_read = errno; + if (file >= 0) + close (file); + + FREE (input); +#ifndef HAVE_MMAP + FREE (buffer); +#endif + + return (chars_read); + } + + close (file); + + /* Set TO to larger than end of file if negative. */ + if (to < 0) + to = chars_read; + + /* Start at beginning of file, work to end. */ + bufend = buffer + chars_read; + current_line = 0; + + /* Skip lines until we are at FROM. */ + for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) + if (*line_end == '\n') + { + current_line++; + line_start = line_end + 1; + } + + /* If there are lines left to gobble, then gobble them now. */ + for (line_end = line_start; line_end < bufend; line_end++) + if (*line_end == '\n') + { + *line_end = '\0'; + + if (*line_start) + add_history (line_start); + + current_line++; + + if (current_line >= to) + break; + + line_start = line_end + 1; + } + + FREE (input); +#ifndef HAVE_MMAP + FREE (buffer); +#else + munmap (buffer, file_size); +#endif + + return (0); +} + +/* Truncate the history file FNAME, leaving only LINES trailing lines. + If FNAME is NULL, then use ~/.history. Returns 0 on success, errno + on failure. */ +int +history_truncate_file (fname, lines) + const char *fname; + int lines; +{ + char *buffer, *filename, *bp; + int file, chars_read, rv; + struct stat finfo; + size_t file_size; + + buffer = (char *)NULL; + filename = history_filename (fname); + file = open (filename, O_RDONLY|O_BINARY, 0666); + rv = 0; + + /* Don't try to truncate non-regular files. */ + if (file == -1 || fstat (file, &finfo) == -1) + { + rv = errno; + if (file != -1) + close (file); + goto truncate_exit; + } + + if (S_ISREG (finfo.st_mode) == 0) + { + close (file); +#ifdef EFTYPE + rv = EFTYPE; +#else + rv = EINVAL; +#endif + goto truncate_exit; + } + + file_size = (size_t)finfo.st_size; + + /* check for overflow on very large files */ + if (file_size != finfo.st_size || file_size + 1 < file_size) + { + close (file); +#if defined (EFBIG) + rv = errno = EFBIG; +#elif defined (EOVERFLOW) + rv = errno = EOVERFLOW; +#else + rv = errno = EINVAL; +#endif + goto truncate_exit; + } + + buffer = (char *)malloc (file_size + 1); + if (buffer == 0) + { + close (file); + goto truncate_exit; + } + + chars_read = read (file, buffer, file_size); + close (file); + + if (chars_read <= 0) + { + rv = (chars_read < 0) ? errno : 0; + goto truncate_exit; + } + + /* Count backwards from the end of buffer until we have passed + LINES lines. */ + for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) + { + if (*bp == '\n') + lines--; + } + + /* If this is the first line, then the file contains exactly the + number of lines we want to truncate to, so we don't need to do + anything. It's the first line if we don't find a newline between + the current value of i and 0. Otherwise, write from the start of + this line until the end of the buffer. */ + for ( ; bp > buffer; bp--) + if (*bp == '\n') + { + bp++; + break; + } + + /* Write only if there are more lines in the file than we want to + truncate to. */ + if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) + { + write (file, bp, chars_read - (bp - buffer)); + +#if defined (__BEOS__) + /* BeOS ignores O_TRUNC. */ + ftruncate (file, chars_read - (bp - buffer)); +#endif + + close (file); + } + + truncate_exit: + + FREE (buffer); + + free (filename); + return rv; +} + +/* Workhorse function for writing history. Writes NELEMENT entries + from the history list to FILENAME. OVERWRITE is non-zero if you + wish to replace FILENAME with the entries. */ +static int +history_do_write (filename, nelements, overwrite) + const char *filename; + int nelements, overwrite; +{ + register int i; + char *output; + int file, mode, rv; + size_t cursize; + +#ifdef HAVE_MMAP + mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; +#else + mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; +#endif + output = history_filename (filename); + rv = 0; + + if ((file = open (output, mode, 0600)) == -1) + { + FREE (output); + return (errno); + } + +#ifdef HAVE_MMAP + cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); +#endif + + if (nelements > history_length) + nelements = history_length; + + /* Build a buffer of all the lines to write, and write them in one syscall. + Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ + { + HIST_ENTRY **the_history; /* local */ + register int j; + int buffer_size; + char *buffer; + + the_history = history_list (); + /* Calculate the total number of bytes to write. */ + for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) + buffer_size += 1 + strlen (the_history[i]->line); + + /* Allocate the buffer, and fill it. */ +#ifdef HAVE_MMAP + if (ftruncate (file, buffer_size+cursize) == -1) + goto mmap_error; + buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); + if ((void *)buffer == MAP_FAILED) + { +mmap_error: + rv = errno; + FREE (output); + close (file); + return rv; + } +#else + buffer = (char *)malloc (buffer_size); + if (buffer == 0) + { + rv = errno; + FREE (output); + close (file); + return rv; + } +#endif + + for (j = 0, i = history_length - nelements; i < history_length; i++) + { + strcpy (buffer + j, the_history[i]->line); + j += strlen (the_history[i]->line); + buffer[j++] = '\n'; + } + +#ifdef HAVE_MMAP + if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) + rv = errno; +#else + if (write (file, buffer, buffer_size) < 0) + rv = errno; + free (buffer); +#endif + } + + close (file); + + FREE (output); + + return (rv); +} + +/* Append NELEMENT entries to FILENAME. The entries appended are from + the end of the list minus NELEMENTs up to the end of the list. */ +int +append_history (nelements, filename) + int nelements; + const char *filename; +{ + return (history_do_write (filename, nelements, HISTORY_APPEND)); +} + +/* Overwrite FILENAME with the current history. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history ().*/ +int +write_history (filename) + const char *filename; +{ + return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); +} diff --git a/cmd-line-utils/readline/histlib.h b/cmd-line-utils/readline/histlib.h new file mode 100644 index 00000000000..c39af71814c --- /dev/null +++ b/cmd-line-utils/readline/histlib.h @@ -0,0 +1,82 @@ +/* histlib.h -- internal definitions for the history library. */ +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_HISTLIB_H_) +#define _HISTLIB_H_ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if !defined (STREQ) +#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) +#define STREQN(a, b, n) (((n) == 0) ? (1) \ + : ((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) +#endif + +#ifndef savestring +#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef _rl_digit_p +#define _rl_digit_p(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef _rl_digit_value +#define _rl_digit_value(c) ((c) - '0') +#endif + +#ifndef member +# ifndef strchr +extern char *strchr (); +# endif +#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) +#endif + +#ifndef FREE +# define FREE(x) if (x) free (x) +#endif + +/* Possible history errors passed to hist_error. */ +#define EVENT_NOT_FOUND 0 +#define BAD_WORD_SPEC 1 +#define SUBST_FAILED 2 +#define BAD_MODIFIER 3 +#define NO_PREV_SUBST 4 + +/* Possible definitions for history starting point specification. */ +#define ANCHORED_SEARCH 1 +#define NON_ANCHORED_SEARCH 0 + +/* Possible definitions for what style of writing the history file we want. */ +#define HISTORY_APPEND 0 +#define HISTORY_OVERWRITE 1 + +/* Some variable definitions shared across history source files. */ +extern int history_offset; + +#endif /* !_HISTLIB_H_ */ diff --git a/cmd-line-utils/readline/history.c b/cmd-line-utils/readline/history.c new file mode 100644 index 00000000000..4242f33efe1 --- /dev/null +++ b/cmd-line-utils/readline/history.c @@ -0,0 +1,381 @@ +/* History.c -- standalone history library */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* The goal is to make the implementation transparent, so that you + don't have to know what data types are used, just what functions + you can call. I think I have done that. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "history.h" +#include "histlib.h" + +#include "xmalloc.h" + +/* The number of slots to increase the_history by. */ +#define DEFAULT_HISTORY_GROW_SIZE 50 + +/* **************************************************************** */ +/* */ +/* History Functions */ +/* */ +/* **************************************************************** */ + +/* An array of HIST_ENTRY. This is where we store the history. */ +static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; + +/* Non-zero means that we have enforced a limit on the amount of + history that we save. */ +static int history_stifled; + +/* The current number of slots allocated to the input_history. */ +static int history_size; + +/* If HISTORY_STIFLED is non-zero, then this is the maximum number of + entries to remember. */ +int history_max_entries; +int max_input_history; /* backwards compatibility */ + +/* The current location of the interactive history pointer. Just makes + life easier for outside callers. */ +int history_offset; + +/* The number of strings currently stored in the history list. */ +int history_length; + +/* The logical `base' of the history array. It defaults to 1. */ +int history_base = 1; + +/* Return the current HISTORY_STATE of the history. */ +HISTORY_STATE * +history_get_history_state () +{ + HISTORY_STATE *state; + + state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE)); + state->entries = the_history; + state->offset = history_offset; + state->length = history_length; + state->size = history_size; + state->flags = 0; + if (history_stifled) + state->flags |= HS_STIFLED; + + return (state); +} + +/* Set the state of the current history array to STATE. */ +void +history_set_history_state (state) + HISTORY_STATE *state; +{ + the_history = state->entries; + history_offset = state->offset; + history_length = state->length; + history_size = state->size; + if (state->flags & HS_STIFLED) + history_stifled = 1; +} + +/* Begin a session in which the history functions might be used. This + initializes interactive variables. */ +void +using_history () +{ + history_offset = history_length; +} + +/* Return the number of bytes that the primary history entries are using. + This just adds up the lengths of the_history->lines. */ +int +history_total_bytes () +{ + register int i, result; + + for (i = result = 0; the_history && the_history[i]; i++) + result += strlen (the_history[i]->line); + + return (result); +} + +/* Returns the magic number which says what history element we are + looking at now. In this implementation, it returns history_offset. */ +int +where_history () +{ + return (history_offset); +} + +/* Make the current history item be the one at POS, an absolute index. + Returns zero if POS is out of range, else non-zero. */ +int +history_set_pos (pos) + int pos; +{ + if (pos > history_length || pos < 0 || !the_history) + return (0); + history_offset = pos; + return (1); +} + +/* Return the current history array. The caller has to be carefull, since this + is the actual array of data, and could be bashed or made corrupt easily. + The array is terminated with a NULL pointer. */ +HIST_ENTRY ** +history_list () +{ + return (the_history); +} + +/* Return the history entry at the current position, as determined by + history_offset. If there is no entry there, return a NULL pointer. */ +HIST_ENTRY * +current_history () +{ + return ((history_offset == history_length) || the_history == 0) + ? (HIST_ENTRY *)NULL + : the_history[history_offset]; +} + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry then return + a NULL pointer. */ +HIST_ENTRY * +previous_history () +{ + return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL; +} + +/* Move history_offset forward to the next history entry, and return + a pointer to that entry. If there is no next entry then return a + NULL pointer. */ +HIST_ENTRY * +next_history () +{ + return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset]; +} + +/* Return the history entry which is logically at OFFSET in the history array. + OFFSET is relative to history_base. */ +HIST_ENTRY * +history_get (offset) + int offset; +{ + int local_index; + + local_index = offset - history_base; + return (local_index >= history_length || local_index < 0 || !the_history) + ? (HIST_ENTRY *)NULL + : the_history[local_index]; +} + +/* Place STRING at the end of the history list. The data field + is set to NULL. */ +void +add_history (string) + const char *string; +{ + HIST_ENTRY *temp; + + if (history_stifled && (history_length == history_max_entries)) + { + register int i; + + /* If the history is stifled, and history_length is zero, + and it equals history_max_entries, we don't save items. */ + if (history_length == 0) + return; + + /* If there is something in the slot, then remove it. */ + if (the_history[0]) + { + free (the_history[0]->line); + free (the_history[0]); + } + + /* Copy the rest of the entries, moving down one slot. */ + for (i = 0; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_base++; + } + else + { + if (history_size == 0) + { + history_size = DEFAULT_HISTORY_GROW_SIZE; + the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *)); + history_length = 1; + } + else + { + if (history_length == (history_size - 1)) + { + history_size += DEFAULT_HISTORY_GROW_SIZE; + the_history = (HIST_ENTRY **) + xrealloc (the_history, history_size * sizeof (HIST_ENTRY *)); + } + history_length++; + } + } + + temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + temp->line = savestring (string); + temp->data = (char *)NULL; + + the_history[history_length] = (HIST_ENTRY *)NULL; + the_history[history_length - 1] = temp; +} + +/* Make the history entry at WHICH have LINE and DATA. This returns + the old entry so you can dispose of the data. In the case of an + invalid WHICH, a NULL pointer is returned. */ +HIST_ENTRY * +replace_history_entry (which, line, data) + int which; + const char *line; + histdata_t data; +{ + HIST_ENTRY *temp, *old_value; + + if (which >= history_length) + return ((HIST_ENTRY *)NULL); + + temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + old_value = the_history[which]; + + temp->line = savestring (line); + temp->data = data; + the_history[which] = temp; + + return (old_value); +} + +/* Remove history element WHICH from the history. The removed + element is returned to you so you can free the line, data, + and containing structure. */ +HIST_ENTRY * +remove_history (which) + int which; +{ + HIST_ENTRY *return_value; + register int i; + + if (which >= history_length || !history_length) + return_value = (HIST_ENTRY *)NULL; + else + { + return_value = the_history[which]; + + for (i = which; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_length--; + } + + return (return_value); +} + +/* Stifle the history list, remembering only MAX number of lines. */ +void +stifle_history (max) + int max; +{ + register int i, j; + + if (max < 0) + max = 0; + + if (history_length > max) + { + /* This loses because we cannot free the data. */ + for (i = 0, j = history_length - max; i < j; i++) + { + free (the_history[i]->line); + free (the_history[i]); + } + + history_base = i; + for (j = 0, i = history_length - max; j < max; i++, j++) + the_history[j] = the_history[i]; + the_history[j] = (HIST_ENTRY *)NULL; + history_length = j; + } + + history_stifled = 1; + max_input_history = history_max_entries = max; +} + +/* Stop stifling the history. This returns the previous maximum + number of history entries. The value is positive if the history + was stifled, negative if it wasn't. */ +int +unstifle_history () +{ + if (history_stifled) + { + history_stifled = 0; + return (history_max_entries); + } + else + return (-history_max_entries); +} + +int +history_is_stifled () +{ + return (history_stifled); +} + +void +clear_history () +{ + register int i; + + /* This loses because we cannot free the data. */ + for (i = 0; i < history_length; i++) + { + free (the_history[i]->line); + free (the_history[i]); + the_history[i] = (HIST_ENTRY *)NULL; + } + + history_offset = history_length = 0; +} diff --git a/cmd-line-utils/readline/history.h b/cmd-line-utils/readline/history.h new file mode 100644 index 00000000000..afd85104554 --- /dev/null +++ b/cmd-line-utils/readline/history.h @@ -0,0 +1,246 @@ +/* History.h -- the names of functions that you can call in history. */ +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _HISTORY_H_ +#define _HISTORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined READLINE_LIBRARY +# include "rlstdc.h" +# include "rltypedefs.h" +#else +# include <readline/rlstdc.h> +# include <readline/rltypedefs.h> +#endif + +#ifdef __STDC__ +typedef void *histdata_t; +#else +typedef char *histdata_t; +#endif + +/* The structure used to store a history entry. */ +typedef struct _hist_entry { + char *line; + histdata_t data; +} HIST_ENTRY; + +/* A structure used to pass the current state of the history stuff around. */ +typedef struct _hist_state { + HIST_ENTRY **entries; /* Pointer to the entries themselves. */ + int offset; /* The location pointer within this array. */ + int length; /* Number of elements within this array. */ + int size; /* Number of slots allocated to this array. */ + int flags; +} HISTORY_STATE; + +/* Flag values for the `flags' member of HISTORY_STATE. */ +#define HS_STIFLED 0x01 + +/* Initialization and state management. */ + +/* Begin a session in which the history functions might be used. This + just initializes the interactive variables. */ +extern void using_history PARAMS((void)); + +/* Return the current HISTORY_STATE of the history. */ +extern HISTORY_STATE *history_get_history_state PARAMS((void)); + +/* Set the state of the current history array to STATE. */ +extern void history_set_history_state PARAMS((HISTORY_STATE *)); + +/* Manage the history list. */ + +/* Place STRING at the end of the history list. + The associated data field (if any) is set to NULL. */ +extern void add_history PARAMS((const char *)); + +/* A reasonably useless function, only here for completeness. WHICH + is the magic number that tells us which element to delete. The + elements are numbered from 0. */ +extern HIST_ENTRY *remove_history PARAMS((int)); + +/* Make the history entry at WHICH have LINE and DATA. This returns + the old entry so you can dispose of the data. In the case of an + invalid WHICH, a NULL pointer is returned. */ +extern HIST_ENTRY *replace_history_entry PARAMS((int, const char *, histdata_t)); + +/* Clear the history list and start over. */ +extern void clear_history PARAMS((void)); + +/* Stifle the history list, remembering only MAX number of entries. */ +extern void stifle_history PARAMS((int)); + +/* Stop stifling the history. This returns the previous amount the + history was stifled by. The value is positive if the history was + stifled, negative if it wasn't. */ +extern int unstifle_history PARAMS((void)); + +/* Return 1 if the history is stifled, 0 if it is not. */ +extern int history_is_stifled PARAMS((void)); + +/* Information about the history list. */ + +/* Return a NULL terminated array of HIST_ENTRY which is the current input + history. Element 0 of this list is the beginning of time. If there + is no history, return NULL. */ +extern HIST_ENTRY **history_list PARAMS((void)); + +/* Returns the number which says what history element we are now + looking at. */ +extern int where_history PARAMS((void)); + +/* Return the history entry at the current position, as determined by + history_offset. If there is no entry there, return a NULL pointer. */ +extern HIST_ENTRY *current_history PARAMS((void)); + +/* Return the history entry which is logically at OFFSET in the history + array. OFFSET is relative to history_base. */ +extern HIST_ENTRY *history_get PARAMS((int)); + +/* Return the number of bytes that the primary history entries are using. + This just adds up the lengths of the_history->lines. */ +extern int history_total_bytes PARAMS((void)); + +/* Moving around the history list. */ + +/* Set the position in the history list to POS. */ +extern int history_set_pos PARAMS((int)); + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry, return + a NULL pointer. */ +extern HIST_ENTRY *previous_history PARAMS((void)); + +/* Move history_offset forward to the next item in the input_history, + and return the a pointer to that entry. If there is no next entry, + return a NULL pointer. */ +extern HIST_ENTRY *next_history PARAMS((void)); + +/* Searching the history list. */ + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, + else through subsequent. If the string is found, then + current_history () is the history entry, and the value of this function + is the offset in the line of that history entry that the string was + found in. Otherwise, nothing is changed, and a -1 is returned. */ +extern int history_search PARAMS((const char *, int)); + +/* Search the history for STRING, starting at history_offset. + The search is anchored: matching lines must begin with string. + DIRECTION is as in history_search(). */ +extern int history_search_prefix PARAMS((const char *, int)); + +/* Search for STRING in the history list, starting at POS, an + absolute index into the list. DIR, if negative, says to search + backwards from POS, else forwards. + Returns the absolute index of the history element where STRING + was found, or -1 otherwise. */ +extern int history_search_pos PARAMS((const char *, int, int)); + +/* Managing the history file. */ + +/* Add the contents of FILENAME to the history list, a line at a time. + If FILENAME is NULL, then read from ~/.history. Returns 0 if + successful, or errno if not. */ +extern int read_history PARAMS((const char *)); + +/* Read a range of lines from FILENAME, adding them to the history list. + Start reading at the FROM'th line and end at the TO'th. If FROM + is zero, start at the beginning. If TO is less than FROM, read + until the end of the file. If FILENAME is NULL, then read from + ~/.history. Returns 0 if successful, or errno if not. */ +extern int read_history_range PARAMS((const char *, int, int)); + +/* Write the current history to FILENAME. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history (). */ +extern int write_history PARAMS((const char *)); + +/* Append NELEMENT entries to FILENAME. The entries appended are from + the end of the list minus NELEMENTs up to the end of the list. */ +extern int append_history PARAMS((int, const char *)); + +/* Truncate the history file, leaving only the last NLINES lines. */ +extern int history_truncate_file PARAMS((const char *, int)); + +/* History expansion. */ + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. Returns: + + 0) If no expansions took place (or, if the only change in + the text was the de-slashifying of the history expansion + character) + 1) If expansions did take place + -1) If there was an error in expansion. + 2) If the returned line should just be printed. + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ +extern int history_expand PARAMS((char *, char **)); + +/* Extract a string segment consisting of the FIRST through LAST + arguments present in STRING. Arguments are broken up as in + the shell. */ +extern char *history_arg_extract PARAMS((int, int, const char *)); + +/* Return the text of the history event beginning at the current + offset into STRING. Pass STRING with *INDEX equal to the + history_expansion_char that begins this specification. + DELIMITING_QUOTE is a character that is allowed to end the string + specification for what to search for in addition to the normal + characters `:', ` ', `\t', `\n', and sometimes `?'. */ +extern char *get_history_event PARAMS((const char *, int *, int)); + +/* Return an array of tokens, much as the shell might. The tokens are + parsed out of STRING. */ +extern char **history_tokenize PARAMS((const char *)); + +/* Exported history variables. */ +extern int history_base; +extern int history_length; +extern int history_max_entries; +extern char history_expansion_char; +extern char history_subst_char; +extern const char *history_word_delimiters; +extern char history_comment_char; +extern const char *history_no_expand_chars; +extern char *history_search_delimiter_chars; +extern int history_quotes_inhibit_expansion; + +/* Backwards compatibility */ +extern int max_input_history; + +/* If set, this function is called to decide whether or not a particular + history expansion should be treated as a special case for the calling + application and not expanded. */ +extern rl_linebuf_func_t *history_inhibit_expansion_function; + +#ifdef __cplusplus +} +#endif + +#endif /* !_HISTORY_H_ */ diff --git a/cmd-line-utils/readline/histsearch.c b/cmd-line-utils/readline/histsearch.c new file mode 100644 index 00000000000..d94fd6cd9c6 --- /dev/null +++ b/cmd-line-utils/readline/histsearch.c @@ -0,0 +1,195 @@ +/* histsearch.c -- searching the history list. */ + +/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#include "history.h" +#include "histlib.h" + +/* The list of alternate characters that can delimit a history search + string. */ +char *history_search_delimiter_chars = (char *)NULL; + +static int history_search_internal PARAMS((const char *, int, int)); + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, else + through subsequent. If ANCHORED is non-zero, the string must + appear at the beginning of a history line, otherwise, the string + may appear anywhere in the line. If the string is found, then + current_history () is the history entry, and the value of this + function is the offset in the line of that history entry that the + string was found in. Otherwise, nothing is changed, and a -1 is + returned. */ + +static int +history_search_internal (string, direction, anchored) + const char *string; + int direction, anchored; +{ + register int i, reverse; + register char *line; + register int line_index; + int string_len; + HIST_ENTRY **the_history; /* local */ + + i = history_offset; + reverse = (direction < 0); + + /* Take care of trivial cases first. */ + if (string == 0 || *string == '\0') + return (-1); + + if (!history_length || ((i == history_length) && !reverse)) + return (-1); + + if (reverse && (i == history_length)) + i--; + +#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0) + + the_history = history_list (); + string_len = strlen (string); + while (1) + { + /* Search each line in the history list for STRING. */ + + /* At limit for direction? */ + if ((reverse && i < 0) || (!reverse && i == history_length)) + return (-1); + + line = the_history[i]->line; + line_index = strlen (line); + + /* If STRING is longer than line, no match. */ + if (string_len > line_index) + { + NEXT_LINE (); + continue; + } + + /* Handle anchored searches first. */ + if (anchored == ANCHORED_SEARCH) + { + if (STREQN (string, line, string_len)) + { + history_offset = i; + return (0); + } + + NEXT_LINE (); + continue; + } + + /* Do substring search. */ + if (reverse) + { + line_index -= string_len; + + while (line_index >= 0) + { + if (STREQN (string, line + line_index, string_len)) + { + history_offset = i; + return (line_index); + } + line_index--; + } + } + else + { + register int limit; + + limit = line_index - string_len + 1; + line_index = 0; + + while (line_index < limit) + { + if (STREQN (string, line + line_index, string_len)) + { + history_offset = i; + return (line_index); + } + line_index++; + } + } + NEXT_LINE (); + } +} + +/* Do a non-anchored search for STRING through the history in DIRECTION. */ +int +history_search (string, direction) + const char *string; + int direction; +{ + return (history_search_internal (string, direction, NON_ANCHORED_SEARCH)); +} + +/* Do an anchored search for string through the history in DIRECTION. */ +int +history_search_prefix (string, direction) + const char *string; + int direction; +{ + return (history_search_internal (string, direction, ANCHORED_SEARCH)); +} + +/* Search for STRING in the history list. DIR is < 0 for searching + backwards. POS is an absolute index into the history list at + which point to begin searching. */ +int +history_search_pos (string, dir, pos) + const char *string; + int dir, pos; +{ + int ret, old; + + old = where_history (); + history_set_pos (pos); + if (history_search (string, dir) == -1) + { + history_set_pos (old); + return (-1); + } + ret = where_history (); + history_set_pos (old); + return ret; +} diff --git a/cmd-line-utils/readline/input.c b/cmd-line-utils/readline/input.c new file mode 100644 index 00000000000..1442c5ef155 --- /dev/null +++ b/cmd-line-utils/readline/input.c @@ -0,0 +1,540 @@ +/* input.c -- character input functions for readline. */ + +/* Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#if defined (HAVE_SYS_FILE_H) +# include <sys/file.h> +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_SELECT) +# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX) +# include <sys/time.h> +# endif +#endif /* HAVE_SELECT */ +#if defined (HAVE_SYS_SELECT_H) +# include <sys/select.h> +#endif + +#if defined (FIONREAD_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif + +#include <stdio.h> +#include <errno.h> + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Some standard library routines. */ +#include "readline.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +/* What kind of non-blocking I/O do we have? */ +#if !defined (O_NDELAY) && defined (O_NONBLOCK) +# define O_NDELAY O_NONBLOCK /* Posix style */ +#endif + +/* Non-null means it is a pointer to a function to run while waiting for + character input. */ +rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL; + +rl_getc_func_t *rl_getc_function = rl_getc; + +static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */ + +static int ibuffer_space PARAMS((void)); +static int rl_get_char PARAMS((int *)); +static int rl_gather_tyi PARAMS((void)); + +/* **************************************************************** */ +/* */ +/* Character Input Buffering */ +/* */ +/* **************************************************************** */ + +static int pop_index, push_index; +static unsigned char ibuffer[512]; +static int ibuffer_len = sizeof (ibuffer) - 1; + +#define any_typein (push_index != pop_index) + +int +_rl_any_typein () +{ + return any_typein; +} + +/* Return the amount of space available in the buffer for stuffing + characters. */ +static int +ibuffer_space () +{ + if (pop_index > push_index) + return (pop_index - push_index - 1); + else + return (ibuffer_len - (push_index - pop_index)); +} + +/* Get a key from the buffer of characters to be read. + Return the key in KEY. + Result is KEY if there was a key, or 0 if there wasn't. */ +static int +rl_get_char (key) + int *key; +{ + if (push_index == pop_index) + return (0); + + *key = ibuffer[pop_index++]; + + if (pop_index >= ibuffer_len) + pop_index = 0; + + return (1); +} + +/* Stuff KEY into the *front* of the input buffer. + Returns non-zero if successful, zero if there is + no space left in the buffer. */ +int +_rl_unget_char (key) + int key; +{ + if (ibuffer_space ()) + { + pop_index--; + if (pop_index < 0) + pop_index = ibuffer_len - 1; + ibuffer[pop_index] = key; + return (1); + } + return (0); +} + +/* If a character is available to be read, then read it and stuff it into + IBUFFER. Otherwise, just return. Returns number of characters read + (0 if none available) and -1 on error (EIO). */ +static int +rl_gather_tyi () +{ + int tty; + register int tem, result; + int chars_avail; + char input; +#if defined(HAVE_SELECT) + fd_set readfds, exceptfds; + struct timeval timeout; +#endif + + tty = fileno (rl_instream); + +#if defined (HAVE_SELECT) + FD_ZERO (&readfds); + FD_ZERO (&exceptfds); + FD_SET (tty, &readfds); + FD_SET (tty, &exceptfds); + timeout.tv_sec = 0; + timeout.tv_usec = _keyboard_input_timeout; + result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout); + if (result <= 0) + return 0; /* Nothing to read. */ +#endif + + result = -1; +#if defined (FIONREAD) + errno = 0; + result = ioctl (tty, FIONREAD, &chars_avail); + if (result == -1 && errno == EIO) + return -1; +#endif + +#if defined (O_NDELAY) + if (result == -1) + { + tem = fcntl (tty, F_GETFL, 0); + + fcntl (tty, F_SETFL, (tem | O_NDELAY)); + chars_avail = read (tty, &input, 1); + + fcntl (tty, F_SETFL, tem); + if (chars_avail == -1 && errno == EAGAIN) + return 0; + } +#endif /* O_NDELAY */ + + /* If there's nothing available, don't waste time trying to read + something. */ + if (chars_avail <= 0) + return 0; + + tem = ibuffer_space (); + + if (chars_avail > tem) + chars_avail = tem; + + /* One cannot read all of the available input. I can only read a single + character at a time, or else programs which require input can be + thwarted. If the buffer is larger than one character, I lose. + Damn! */ + if (tem < ibuffer_len) + chars_avail = 0; + + if (result != -1) + { + while (chars_avail--) + rl_stuff_char ((*rl_getc_function) (rl_instream)); + } + else + { + if (chars_avail) + rl_stuff_char (input); + } + + return 1; +} + +int +rl_set_keyboard_input_timeout (u) + int u; +{ + int o; + + o = _keyboard_input_timeout; + if (u > 0) + _keyboard_input_timeout = u; + return (o); +} + +/* Is there input available to be read on the readline input file + descriptor? Only works if the system has select(2) or FIONREAD. + Uses the value of _keyboard_input_timeout as the timeout; if another + readline function wants to specify a timeout and not leave it up to + the user, it should use _rl_input_queued(timeout_value_in_microseconds) + instead. */ +int +_rl_input_available () +{ +#if defined(HAVE_SELECT) + fd_set readfds, exceptfds; + struct timeval timeout; +#endif +#if !defined (HAVE_SELECT) && defined(FIONREAD) + int chars_avail; +#endif + int tty; + + tty = fileno (rl_instream); + +#if defined (HAVE_SELECT) + FD_ZERO (&readfds); + FD_ZERO (&exceptfds); + FD_SET (tty, &readfds); + FD_SET (tty, &exceptfds); + timeout.tv_sec = 0; + timeout.tv_usec = _keyboard_input_timeout; + return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0); +#else + +#if defined (FIONREAD) + if (ioctl (tty, FIONREAD, &chars_avail) == 0) + return (chars_avail); +#endif + +#endif + + return 0; +} + +int +_rl_input_queued (t) + int t; +{ + int old_timeout, r; + + old_timeout = rl_set_keyboard_input_timeout (t); + r = _rl_input_available (); + rl_set_keyboard_input_timeout (old_timeout); + return r; +} + +void +_rl_insert_typein (c) + int c; +{ + int key, t, i; + char *string; + + i = key = 0; + string = (char *)xmalloc (ibuffer_len + 1); + string[i++] = (char) c; + + while ((t = rl_get_char (&key)) && + _rl_keymap[key].type == ISFUNC && + _rl_keymap[key].function == rl_insert) + string[i++] = key; + + if (t) + _rl_unget_char (key); + + string[i] = '\0'; + rl_insert_text (string); + free (string); +} + +/* Add KEY to the buffer of characters to be read. Returns 1 if the + character was stuffed correctly; 0 otherwise. */ +int +rl_stuff_char (key) + int key; +{ + if (ibuffer_space () == 0) + return 0; + + if (key == EOF) + { + key = NEWLINE; + rl_pending_input = EOF; + RL_SETSTATE (RL_STATE_INPUTPENDING); + } + ibuffer[push_index++] = key; + if (push_index >= ibuffer_len) + push_index = 0; + + return 1; +} + +/* Make C be the next command to be executed. */ +int +rl_execute_next (c) + int c; +{ + rl_pending_input = c; + RL_SETSTATE (RL_STATE_INPUTPENDING); + return 0; +} + +/* Clear any pending input pushed with rl_execute_next() */ +int +rl_clear_pending_input () +{ + rl_pending_input = 0; + RL_UNSETSTATE (RL_STATE_INPUTPENDING); + return 0; +} + +/* **************************************************************** */ +/* */ +/* Character Input */ +/* */ +/* **************************************************************** */ + +/* Read a key, including pending input. */ +int +rl_read_key () +{ + int c; + + rl_key_sequence_length++; + + if (rl_pending_input) + { + c = rl_pending_input; + rl_clear_pending_input (); + } + else + { + /* If input is coming from a macro, then use that. */ + if ((c = _rl_next_macro_key ())) + return (c); + + /* If the user has an event function, then call it periodically. */ + if (rl_event_hook) + { + while (rl_event_hook && rl_get_char (&c) == 0) + { + (*rl_event_hook) (); + if (rl_done) /* XXX - experimental */ + return ('\n'); + if (rl_gather_tyi () < 0) /* XXX - EIO */ + { + rl_done = 1; + return ('\n'); + } + } + } + else + { + if (rl_get_char (&c) == 0) + c = (*rl_getc_function) (rl_instream); + } + } + + return (c); +} + +int +rl_getc (stream) + FILE *stream; +{ + int result; + unsigned char c; + + while (1) + { + result = read (fileno (stream), &c, sizeof (unsigned char)); + + if (result == sizeof (unsigned char)) + return (c); + + /* If zero characters are returned, then the file that we are + reading from is empty! Return EOF in that case. */ + if (result == 0) + return (EOF); + +#if defined (__BEOS__) + if (errno == EINTR) + continue; +#endif + +#if defined (EWOULDBLOCK) +# define X_EWOULDBLOCK EWOULDBLOCK +#else +# define X_EWOULDBLOCK -99 +#endif + +#if defined (EAGAIN) +# define X_EAGAIN EAGAIN +#else +# define X_EAGAIN -99 +#endif + + if (errno == X_EWOULDBLOCK || errno == X_EAGAIN) + { + if (sh_unset_nodelay_mode (fileno (stream)) < 0) + return (EOF); + continue; + } + +#undef X_EWOULDBLOCK +#undef X_EAGAIN + + /* If the error that we received was SIGINT, then try again, + this is simply an interrupted system call to read (). + Otherwise, some error ocurred, also signifying EOF. */ + if (errno != EINTR) + return (EOF); + } +} + +#if defined (HANDLE_MULTIBYTE) +/* read multibyte char */ +int +_rl_read_mbchar (mbchar, size) + char *mbchar; + int size; +{ + int mb_len = 0; + size_t mbchar_bytes_length; + wchar_t wc; + mbstate_t ps, ps_back; + + memset(&ps, 0, sizeof (mbstate_t)); + memset(&ps_back, 0, sizeof (mbstate_t)); + + while (mb_len < size) + { + RL_SETSTATE(RL_STATE_MOREINPUT); + mbchar[mb_len++] = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps); + if (mbchar_bytes_length == (size_t)(-1)) + break; /* invalid byte sequence for the current locale */ + else if (mbchar_bytes_length == (size_t)(-2)) + { + /* shorted bytes */ + ps = ps_back; + continue; + } + else if (mbchar_bytes_length > (size_t)(0)) + break; + } + + return mb_len; +} + +/* Read a multibyte-character string whose first character is FIRST into + the buffer MB of length MBLEN. Returns the last character read, which + may be FIRST. Used by the search functions, among others. Very similar + to _rl_read_mbchar. */ +int +_rl_read_mbstring (first, mb, mblen) + int first; + char *mb; + int mblen; +{ + int i, c; + mbstate_t ps; + + c = first; + memset (mb, 0, mblen); + for (i = 0; i < mblen; i++) + { + mb[i] = (char)c; + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_get_char_len (mb, &ps) == -2) + { + /* Read more for multibyte character */ + RL_SETSTATE (RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE (RL_STATE_MOREINPUT); + } + else + break; + } + return c; +} +#endif /* HANDLE_MULTIBYTE */ diff --git a/cmd-line-utils/readline/isearch.c b/cmd-line-utils/readline/isearch.c new file mode 100644 index 00000000000..137842a841f --- /dev/null +++ b/cmd-line-utils/readline/isearch.c @@ -0,0 +1,560 @@ +/* **************************************************************** */ +/* */ +/* I-Search and Searching */ +/* */ +/* **************************************************************** */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif + +#include "rldefs.h" +#include "rlmbutil.h" + +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* Variables exported to other files in the readline library. */ +char *_rl_isearch_terminators = (char *)NULL; + +/* Variables imported from other files in the readline library. */ +extern HIST_ENTRY *_rl_saved_line_for_history; + +/* Forward declarations */ +static int rl_search_history PARAMS((int, int)); + +/* Last line found by the current incremental search, so we don't `find' + identical lines many times in a row. */ +static char *prev_line_found; + +/* Last search string and its length. */ +static char *last_isearch_string; +static int last_isearch_string_len; + +static const char *default_isearch_terminators = "\033\012"; + +/* Search backwards through the history looking for a string which is typed + interactively. Start with the current line. */ +int +rl_reverse_search_history (sign, key) + int sign, key; +{ + return (rl_search_history (-sign, key)); +} + +/* Search forwards through the history looking for a string which is typed + interactively. Start with the current line. */ +int +rl_forward_search_history (sign, key) + int sign, key; +{ + return (rl_search_history (sign, key)); +} + +/* Display the current state of the search in the echo-area. + SEARCH_STRING contains the string that is being searched for, + DIRECTION is zero for forward, or 1 for reverse, + WHERE is the history list number of the current line. If it is + -1, then this line is the starting one. */ +static void +rl_display_search (search_string, reverse_p, where) + char *search_string; + int reverse_p, where __attribute__((unused)); +{ + char *message; + int msglen, searchlen; + + searchlen = (search_string && *search_string) ? strlen (search_string) : 0; + + message = (char *)xmalloc (searchlen + 33); + msglen = 0; + +#if defined (NOTDEF) + if (where != -1) + { + sprintf (message, "[%d]", where + history_base); + msglen = strlen (message); + } +#endif /* NOTDEF */ + + message[msglen++] = '('; + + if (reverse_p) + { + strcpy (message + msglen, "reverse-"); + msglen += 8; + } + + strcpy (message + msglen, "i-search)`"); + msglen += 10; + + if (search_string) + { + strcpy (message + msglen, search_string); + msglen += searchlen; + } + + strcpy (message + msglen, "': "); + + rl_message ("%s", message); + free (message); + (*rl_redisplay_function) (); +} + +/* Search through the history looking for an interactively typed string. + This is analogous to i-search. We start the search in the current line. + DIRECTION is which direction to search; >= 0 means forward, < 0 means + backwards. */ +static int +rl_search_history (direction, invoking_key) + int direction, invoking_key __attribute__((unused)); +{ + /* The string that the user types in to search for. */ + char *search_string; + + /* The current length of SEARCH_STRING. */ + int search_string_index; + + /* The amount of space that SEARCH_STRING has allocated to it. */ + int search_string_size; + + /* The list of lines to search through. */ + char **lines, *allocated_line; + + /* The length of LINES. */ + int hlen; + + /* Where we get LINES from. */ + HIST_ENTRY **hlist; + + register int i; + int orig_point, orig_mark, orig_line, last_found_line; + int c, found, failed, sline_len; + int n, wstart, wlen; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; +#endif + + /* The line currently being searched. */ + char *sline; + + /* Offset in that line. */ + int line_index; + + /* Non-zero if we are doing a reverse search. */ + int reverse; + + /* The list of characters which terminate the search, but are not + subsequently executed. If the variable isearch-terminators has + been set, we use that value, otherwise we use ESC and C-J. */ + const char *isearch_terminators; + + RL_SETSTATE(RL_STATE_ISEARCH); + orig_point = rl_point; + orig_mark = rl_mark; + last_found_line = orig_line = where_history (); + reverse = direction < 0; + hlist = history_list (); + allocated_line = (char *)NULL; + + isearch_terminators = _rl_isearch_terminators ? _rl_isearch_terminators + : default_isearch_terminators; + + /* Create an arrary of pointers to the lines that we want to search. */ + rl_maybe_replace_line (); + i = 0; + if (hlist) + for (i = 0; hlist[i]; i++); + + /* Allocate space for this many lines, +1 for the current input line, + and remember those lines. */ + lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *)); + for (i = 0; i < hlen; i++) + lines[i] = hlist[i]->line; + + if (_rl_saved_line_for_history) + lines[i] = _rl_saved_line_for_history->line; + else + { + /* Keep track of this so we can free it. */ + allocated_line = (char *)xmalloc (1 + strlen (rl_line_buffer)); + strcpy (allocated_line, &rl_line_buffer[0]); + lines[i] = allocated_line; + } + + hlen++; + + /* The line where we start the search. */ + i = orig_line; + + rl_save_prompt (); + + /* Initialize search parameters. */ + search_string = (char *)xmalloc (search_string_size = 128); + *search_string = '\0'; + search_string_index = 0; + prev_line_found = (char *)0; /* XXX */ + + /* Normalize DIRECTION into 1 or -1. */ + direction = (direction >= 0) ? 1 : -1; + + rl_display_search (search_string, reverse, -1); + + sline = rl_line_buffer; + sline_len = strlen (sline); + line_index = rl_point; + + found = failed = 0; + for (;;) + { + rl_command_func_t *f = (rl_command_func_t *)NULL; + + /* Read a key and decide how to proceed. */ + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, MB_LEN_MAX); +#endif + + /* Translate the keys we do something with to opcodes. */ + if (c >= 0 && _rl_keymap[c].type == ISFUNC) + { + f = _rl_keymap[c].function; + + if (f == rl_reverse_search_history) + c = reverse ? -1 : -2; + else if (f == rl_forward_search_history) + c = !reverse ? -1 : -2; + else if (f == rl_rubout) + c = -3; + else if (c == CTRL ('G')) + c = -4; + else if (c == CTRL ('W')) /* XXX */ + c = -5; + else if (c == CTRL ('Y')) /* XXX */ + c = -6; + } + + /* The characters in isearch_terminators (set from the user-settable + variable isearch-terminators) are used to terminate the search but + not subsequently execute the character as a command. The default + value is "\033\012" (ESC and C-J). */ + if (strchr (isearch_terminators, c)) + { + /* ESC still terminates the search, but if there is pending + input or if input arrives within 0.1 seconds (on systems + with select(2)) it is used as a prefix character + with rl_execute_next. WATCH OUT FOR THIS! This is intended + to allow the arrow keys to be used like ^F and ^B are used + to terminate the search and execute the movement command. + XXX - since _rl_input_available depends on the application- + settable keyboard timeout value, this could alternatively + use _rl_input_queued(100000) */ + if (c == ESC && _rl_input_available ()) + rl_execute_next (ESC); + break; + } + +#define ENDSRCH_CHAR(c) \ + ((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G'))) + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c)) + { + /* This sets rl_pending_input to c; it will be picked up the next + time rl_read_key is called. */ + rl_execute_next (c); + break; + } + } + else +#endif + if (c >= 0 && ENDSRCH_CHAR (c)) + { + /* This sets rl_pending_input to c; it will be picked up the next + time rl_read_key is called. */ + rl_execute_next (c); + break; + } + + switch (c) + { + case -1: + if (search_string_index == 0) + { + if (last_isearch_string) + { + search_string_size = 64 + last_isearch_string_len; + search_string = (char *)xrealloc (search_string, search_string_size); + strcpy (search_string, last_isearch_string); + search_string_index = last_isearch_string_len; + rl_display_search (search_string, reverse, -1); + break; + } + continue; + } + else if (reverse) + --line_index; + else if (line_index != sline_len) + ++line_index; + else + rl_ding (); + break; + + /* switch directions */ + case -2: + direction = -direction; + reverse = direction < 0; + break; + + /* delete character from search string. */ + case -3: /* C-H, DEL */ + /* This is tricky. To do this right, we need to keep a + stack of search positions for the current search, with + sentinels marking the beginning and end. But this will + do until we have a real isearch-undo. */ + if (search_string_index == 0) + rl_ding (); + else + search_string[--search_string_index] = '\0'; + + break; + + case -4: /* C-G */ + rl_replace_line (lines[orig_line], 0); + rl_point = orig_point; + rl_mark = orig_mark; + rl_restore_prompt(); + rl_clear_message (); + if (allocated_line) + free (allocated_line); + free (lines); + RL_UNSETSTATE(RL_STATE_ISEARCH); + return 0; + + case -5: /* C-W */ + /* skip over portion of line we already matched */ + wstart = rl_point + search_string_index; + if (wstart >= rl_end) + { + rl_ding (); + break; + } + + /* if not in a word, move to one. */ + if (rl_alphabetic(rl_line_buffer[wstart]) == 0) + { + rl_ding (); + break; + } + n = wstart; + while (n < rl_end && rl_alphabetic(rl_line_buffer[n])) + n++; + wlen = n - wstart + 1; + if (search_string_index + wlen + 1 >= search_string_size) + { + search_string_size += wlen + 1; + search_string = (char *)xrealloc (search_string, search_string_size); + } + for (; wstart < n; wstart++) + search_string[search_string_index++] = rl_line_buffer[wstart]; + search_string[search_string_index] = '\0'; + break; + + case -6: /* C-Y */ + /* skip over portion of line we already matched */ + wstart = rl_point + search_string_index; + if (wstart >= rl_end) + { + rl_ding (); + break; + } + n = rl_end - wstart + 1; + if (search_string_index + n + 1 >= search_string_size) + { + search_string_size += n + 1; + search_string = (char *)xrealloc (search_string, search_string_size); + } + for (n = wstart; n < rl_end; n++) + search_string[search_string_index++] = rl_line_buffer[n]; + search_string[search_string_index] = '\0'; + break; + + default: + /* Add character to search string and continue search. */ + if (search_string_index + 2 >= search_string_size) + { + search_string_size += 128; + search_string = (char *)xrealloc (search_string, search_string_size); + } +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + int j, l; + for (j = 0, l = strlen (mb); j < l; ) + search_string[search_string_index++] = mb[j++]; + } + else +#endif + search_string[search_string_index++] = c; + search_string[search_string_index] = '\0'; + break; + } + + for (found = failed = 0;;) + { + int limit = sline_len - search_string_index + 1; + + /* Search the current line. */ + while (reverse ? (line_index >= 0) : (line_index < limit)) + { + if (STREQN (search_string, sline + line_index, search_string_index)) + { + found++; + break; + } + else + line_index += direction; + } + if (found) + break; + + /* Move to the next line, but skip new copies of the line + we just found and lines shorter than the string we're + searching for. */ + do + { + /* Move to the next line. */ + i += direction; + + /* At limit for direction? */ + if (reverse ? (i < 0) : (i == hlen)) + { + failed++; + break; + } + + /* We will need these later. */ + sline = lines[i]; + sline_len = strlen (sline); + } + while ((prev_line_found && STREQ (prev_line_found, lines[i])) || + (search_string_index > sline_len)); + + if (failed) + break; + + /* Now set up the line for searching... */ + line_index = reverse ? sline_len - search_string_index : 0; + } + + if (failed) + { + /* We cannot find the search string. Ding the bell. */ + rl_ding (); + i = last_found_line; + continue; /* XXX - was break */ + } + + /* We have found the search string. Just display it. But don't + actually move there in the history list until the user accepts + the location. */ + if (found) + { + prev_line_found = lines[i]; + rl_replace_line (lines[i], 0); + rl_point = line_index; + last_found_line = i; + rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i); + } + } + + /* The searching is over. The user may have found the string that she + was looking for, or else she may have exited a failing search. If + LINE_INDEX is -1, then that shows that the string searched for was + not found. We use this to determine where to place rl_point. */ + + /* First put back the original state. */ + strcpy (rl_line_buffer, lines[orig_line]); + + rl_restore_prompt (); + + /* Save the search string for possible later use. */ + FREE (last_isearch_string); + last_isearch_string = search_string; + last_isearch_string_len = search_string_index; + + if (last_found_line < orig_line) + rl_get_previous_history (orig_line - last_found_line, 0); + else + rl_get_next_history (last_found_line - orig_line, 0); + + /* If the string was not found, put point at the end of the last matching + line. If last_found_line == orig_line, we didn't find any matching + history lines at all, so put point back in its original position. */ + if (line_index < 0) + { + if (last_found_line == orig_line) + line_index = orig_point; + else + line_index = strlen (rl_line_buffer); + rl_mark = orig_mark; + } + + rl_point = line_index; + /* Don't worry about where to put the mark here; rl_get_previous_history + and rl_get_next_history take care of it. */ + + rl_clear_message (); + + FREE (allocated_line); + free (lines); + + RL_UNSETSTATE(RL_STATE_ISEARCH); + + return 0; +} diff --git a/cmd-line-utils/readline/keymaps.c b/cmd-line-utils/readline/keymaps.c new file mode 100644 index 00000000000..12506d3aab2 --- /dev/null +++ b/cmd-line-utils/readline/keymaps.c @@ -0,0 +1,150 @@ +/* keymaps.c -- Functions and keymaps for the GNU Readline library. */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> /* for FILE * definition for readline.h */ + +#include "readline.h" +#include "rlconf.h" + +#include "emacs_keymap.c" + +#if defined (VI_MODE) +#include "vi_keymap.c" +#endif + +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Functions for manipulating Keymaps. */ +/* */ +/* **************************************************************** */ + + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap +rl_make_bare_keymap () +{ + register int i; + Keymap keymap = (Keymap)xmalloc (KEYMAP_SIZE * sizeof (KEYMAP_ENTRY)); + + for (i = 0; i < KEYMAP_SIZE; i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = (rl_command_func_t *)NULL; + } + + for (i = 'A'; i < ('Z' + 1); i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = rl_do_lowercase_version; + } + + return (keymap); +} + +/* Return a new keymap which is a copy of MAP. */ +Keymap +rl_copy_keymap (map) + Keymap map; +{ + register int i; + Keymap temp = rl_make_bare_keymap (); + + for (i = 0; i < KEYMAP_SIZE; i++) + { + temp[i].type = map[i].type; + temp[i].function = map[i].function; + } + return (temp); +} + +/* Return a new keymap with the printing characters bound to rl_insert, + the uppercase Meta characters bound to run their lowercase equivalents, + and the Meta digits bound to produce numeric arguments. */ +Keymap +rl_make_keymap () +{ + register int i; + Keymap newmap; + + newmap = rl_make_bare_keymap (); + + /* All ASCII printing characters are self-inserting. */ + for (i = ' '; i < 127; i++) + newmap[i].function = rl_insert; + + newmap[TAB].function = rl_insert; + newmap[RUBOUT].function = rl_rubout; /* RUBOUT == 127 */ + newmap[CTRL('H')].function = rl_rubout; + +#if KEYMAP_SIZE > 128 + /* Printing characters in some 8-bit character sets. */ + for (i = 128; i < 160; i++) + newmap[i].function = rl_insert; + + /* ISO Latin-1 printing characters should self-insert. */ + for (i = 160; i < 256; i++) + newmap[i].function = rl_insert; +#endif /* KEYMAP_SIZE > 128 */ + + return (newmap); +} + +/* Free the storage associated with MAP. */ +void +rl_discard_keymap (map) + Keymap map; +{ + int i; + + if (!map) + return; + + for (i = 0; i < KEYMAP_SIZE; i++) + { + switch (map[i].type) + { + case ISFUNC: + break; + + case ISKMAP: + rl_discard_keymap ((Keymap)map[i].function); + break; + + case ISMACR: + free ((char *)map[i].function); + break; + } + } +} diff --git a/cmd-line-utils/readline/keymaps.h b/cmd-line-utils/readline/keymaps.h new file mode 100644 index 00000000000..66fa2a5ec14 --- /dev/null +++ b/cmd-line-utils/readline/keymaps.h @@ -0,0 +1,103 @@ +/* keymaps.h -- Manipulation of readline keymaps. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _KEYMAPS_H_ +#define _KEYMAPS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (READLINE_LIBRARY) +# include "rlstdc.h" +# include "chardefs.h" +# include "rltypedefs.h" +#else +# include <readline/rlstdc.h> +# include <readline/chardefs.h> +# include <readline/rltypedefs.h> +#endif + +/* A keymap contains one entry for each key in the ASCII set. + Each entry consists of a type and a pointer. + FUNCTION is the address of a function to run, or the + address of a keymap to indirect through. + TYPE says which kind of thing FUNCTION is. */ +typedef struct _keymap_entry { + char type; + rl_command_func_t *function; +} KEYMAP_ENTRY; + +/* This must be large enough to hold bindings for all of the characters + in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x, + and so on) plus one for subsequence matching. */ +#define KEYMAP_SIZE 257 +#define ANYOTHERKEY KEYMAP_SIZE-1 + +/* I wanted to make the above structure contain a union of: + union { rl_command_func_t *function; struct _keymap_entry *keymap; } value; + but this made it impossible for me to create a static array. + Maybe I need C lessons. */ + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; +typedef KEYMAP_ENTRY *Keymap; + +/* The values that TYPE can have in a keymap entry. */ +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; +extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +extern Keymap rl_make_bare_keymap PARAMS((void)); + +/* Return a new keymap which is a copy of MAP. */ +extern Keymap rl_copy_keymap PARAMS((Keymap)); + +/* Return a new keymap with the printing characters bound to rl_insert, + the lowercase Meta characters bound to run their equivalents, and + the Meta digits bound to produce numeric arguments. */ +extern Keymap rl_make_keymap PARAMS((void)); + +/* Free the storage associated with a keymap. */ +extern void rl_discard_keymap PARAMS((Keymap)); + +/* These functions actually appear in bind.c */ + +/* Return the keymap corresponding to a given name. Names look like + `emacs' or `emacs-meta' or `vi-insert'. */ +extern Keymap rl_get_keymap_by_name PARAMS((const char *)); + +/* Return the current keymap. */ +extern Keymap rl_get_keymap PARAMS((void)); + +/* Set the current keymap to MAP. */ +extern void rl_set_keymap PARAMS((Keymap)); + +#ifdef __cplusplus +} +#endif + +#endif /* _KEYMAPS_H_ */ diff --git a/cmd-line-utils/readline/kill.c b/cmd-line-utils/readline/kill.c new file mode 100644 index 00000000000..f8c6961bbd3 --- /dev/null +++ b/cmd-line-utils/readline/kill.c @@ -0,0 +1,652 @@ +/* kill.c -- kill ring management. */ + +/* Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Killing Mechanism */ +/* */ +/* **************************************************************** */ + +/* What we assume for a max number of kills. */ +#define DEFAULT_MAX_KILLS 10 + +/* The real variable to look at to find out when to flush kills. */ +static int rl_max_kills = DEFAULT_MAX_KILLS; + +/* Where to store killed text. */ +static char **rl_kill_ring = (char **)NULL; + +/* Where we are in the kill ring. */ +static int rl_kill_index; + +/* How many slots we have in the kill ring. */ +static int rl_kill_ring_length; + +static int _rl_copy_to_kill_ring PARAMS((char *, int)); +static int region_kill_internal PARAMS((int)); +static int _rl_copy_word_as_kill PARAMS((int, int)); +static int rl_yank_nth_arg_internal PARAMS((int, int, int)); + +/* How to say that you only want to save a certain amount + of kill material. */ +int +rl_set_retained_kills (num) + int num __attribute__((unused)); +{ + return 0; +} + +/* Add TEXT to the kill ring, allocating a new kill ring slot as necessary. + This uses TEXT directly, so the caller must not free it. If APPEND is + non-zero, and the last command was a kill, the text is appended to the + current kill ring slot, otherwise prepended. */ +static int +_rl_copy_to_kill_ring (text, append) + char *text; + int append; +{ + char *old, *new; + int slot; + + /* First, find the slot to work with. */ + if (_rl_last_command_was_kill == 0) + { + /* Get a new slot. */ + if (rl_kill_ring == 0) + { + /* If we don't have any defined, then make one. */ + rl_kill_ring = (char **) + xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *)); + rl_kill_ring[slot = 0] = (char *)NULL; + } + else + { + /* We have to add a new slot on the end, unless we have + exceeded the max limit for remembering kills. */ + slot = rl_kill_ring_length; + if (slot == rl_max_kills) + { + register int i; + free (rl_kill_ring[0]); + for (i = 0; i < slot; i++) + rl_kill_ring[i] = rl_kill_ring[i + 1]; + } + else + { + slot = rl_kill_ring_length += 1; + rl_kill_ring = (char **)xrealloc (rl_kill_ring, slot * sizeof (char *)); + } + rl_kill_ring[--slot] = (char *)NULL; + } + } + else + slot = rl_kill_ring_length - 1; + + /* If the last command was a kill, prepend or append. */ + if (_rl_last_command_was_kill && rl_editing_mode != vi_mode) + { + old = rl_kill_ring[slot]; + new = (char *)xmalloc (1 + strlen (old) + strlen (text)); + + if (append) + { + strcpy (new, old); + strcat (new, text); + } + else + { + strcpy (new, text); + strcat (new, old); + } + free (old); + free (text); + rl_kill_ring[slot] = new; + } + else + rl_kill_ring[slot] = text; + + rl_kill_index = slot; + return 0; +} + +/* The way to kill something. This appends or prepends to the last + kill, if the last command was a kill command. if FROM is less + than TO, then the text is appended, otherwise prepended. If the + last command was not a kill command, then a new slot is made for + this kill. */ +int +rl_kill_text (from, to) + int from, to; +{ + char *text; + + /* Is there anything to kill? */ + if (from == to) + { + _rl_last_command_was_kill++; + return 0; + } + + text = rl_copy_text (from, to); + + /* Delete the copied text from the line. */ + rl_delete_text (from, to); + + _rl_copy_to_kill_ring (text, from < to); + + _rl_last_command_was_kill++; + return 0; +} + +/* Now REMEMBER! In order to do prepending or appending correctly, kill + commands always make rl_point's original position be the FROM argument, + and rl_point's extent be the TO argument. */ + +/* **************************************************************** */ +/* */ +/* Killing Commands */ +/* */ +/* **************************************************************** */ + +/* Delete the word at point, saving the text in the kill ring. */ +int +rl_kill_word (count, key) + int count, key; +{ + int orig_point; + + if (count < 0) + return (rl_backward_kill_word (-count, key)); + else + { + orig_point = rl_point; + rl_forward_word (count, key); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + + rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Rubout the word before point, placing it on the kill ring. */ +int +rl_backward_kill_word (count, ignore) + int count, ignore; +{ + int orig_point; + + if (count < 0) + return (rl_kill_word (-count, ignore)); + else + { + orig_point = rl_point; + rl_backward_word (count, ignore); + + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Kill from here to the end of the line. If DIRECTION is negative, kill + back to the line start instead. */ +int +rl_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point; + + if (direction < 0) + return (rl_backward_kill_line (1, ignore)); + else + { + orig_point = rl_point; + rl_end_of_line (1, ignore); + if (orig_point != rl_point) + rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Kill backwards to the start of the line. If DIRECTION is negative, kill + forwards to the line end instead. */ +int +rl_backward_kill_line (direction, ignore) + int direction, ignore; +{ + int orig_point; + + if (direction < 0) + return (rl_kill_line (1, ignore)); + else + { + if (!rl_point) + rl_ding (); + else + { + orig_point = rl_point; + rl_beg_of_line (1, ignore); + if (rl_point != orig_point) + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + } + return 0; +} + +/* Kill the whole line, no matter where point is. */ +int +rl_kill_full_line (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + rl_begin_undo_group (); + rl_point = 0; + rl_kill_text (rl_point, rl_end); + rl_mark = 0; + rl_end_undo_group (); + return 0; +} + +/* The next two functions mimic unix line editing behaviour, except they + save the deleted text on the kill ring. This is safer than not saving + it, and since we have a ring, nobody should get screwed. */ + +/* This does what C-w does in Unix. We can't prevent people from + using behaviour that they expect. */ +int +rl_unix_word_rubout (count, key) + int count, key __attribute__((unused)); +{ + int orig_point; + + if (rl_point == 0) + rl_ding (); + else + { + orig_point = rl_point; + if (count <= 0) + count = 1; + + while (count--) + { + while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point && (whitespace (rl_line_buffer[rl_point - 1]) == 0)) + rl_point--; + } + + rl_kill_text (orig_point, rl_point); + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Here is C-u doing what Unix does. You don't *have* to use these + key-bindings. We have a choice of killing the entire line, or + killing from where we are to the start of the line. We choose the + latter, because if you are a Unix weenie, then you haven't backspaced + into the line at all, and if you aren't, then you know what you are + doing. */ +int +rl_unix_line_discard (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (rl_point == 0) + rl_ding (); + else + { + rl_kill_text (rl_point, 0); + rl_point = 0; + if (rl_editing_mode == emacs_mode) + rl_mark = rl_point; + } + return 0; +} + +/* Copy the text in the `region' to the kill ring. If DELETE is non-zero, + delete the text from the line as well. */ +static int +region_kill_internal (delete) + int delete; +{ + char *text; + + if (rl_mark != rl_point) + { + text = rl_copy_text (rl_point, rl_mark); + if (delete) + rl_delete_text (rl_point, rl_mark); + _rl_copy_to_kill_ring (text, rl_point < rl_mark); + } + + _rl_last_command_was_kill++; + return 0; +} + +/* Copy the text in the region to the kill ring. */ +int +rl_copy_region_to_kill (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + return (region_kill_internal (0)); +} + +/* Kill the text between the point and mark. */ +int +rl_kill_region (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + int r, npoint; + + npoint = (rl_point < rl_mark) ? rl_point : rl_mark; + r = region_kill_internal (1); + _rl_fix_point (1); + rl_point = npoint; + return r; +} + +/* Copy COUNT words to the kill ring. DIR says which direction we look + to find the words. */ +static int +_rl_copy_word_as_kill (count, dir) + int count, dir; +{ + int om, op, r; + + om = rl_mark; + op = rl_point; + + if (dir > 0) + rl_forward_word (count, 0); + else + rl_backward_word (count, 0); + + rl_mark = rl_point; + + if (dir > 0) + rl_backward_word (count, 0); + else + rl_forward_word (count, 0); + + r = region_kill_internal (0); + + rl_mark = om; + rl_point = op; + + return r; +} + +int +rl_copy_forward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_backward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, 1)); +} + +int +rl_copy_backward_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_copy_forward_word (-count, key)); + + return (_rl_copy_word_as_kill (count, -1)); +} + +/* Yank back the last killed text. This ignores arguments. */ +int +rl_yank (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + if (rl_kill_ring == 0) + { + _rl_abort_internal (); + return -1; + } + + _rl_set_mark_at_pos (rl_point); + rl_insert_text (rl_kill_ring[rl_kill_index]); + return 0; +} + +/* If the last command was yank, or yank_pop, and the text just + before point is identical to the current kill item, then + delete that text from the line, rotate the index down, and + yank back some other text. */ +int +rl_yank_pop (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int l, n; + + if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) || + !rl_kill_ring) + { + _rl_abort_internal (); + return -1; + } + + l = strlen (rl_kill_ring[rl_kill_index]); + n = rl_point - l; + if (n >= 0 && STREQN (rl_line_buffer + n, rl_kill_ring[rl_kill_index], l)) + { + rl_delete_text (n, rl_point); + rl_point = n; + rl_kill_index--; + if (rl_kill_index < 0) + rl_kill_index = rl_kill_ring_length - 1; + rl_yank (1, 0); + return 0; + } + else + { + _rl_abort_internal (); + return -1; + } +} + +/* Yank the COUNTh argument from the previous history line, skipping + HISTORY_SKIP lines before looking for the `previous line'. */ +static int +rl_yank_nth_arg_internal (count, ignore, history_skip) + int count, ignore, history_skip; +{ + register HIST_ENTRY *entry; + char *arg; + int i, pos; + + pos = where_history (); + + if (history_skip) + { + for (i = 0; i < history_skip; i++) + entry = previous_history (); + } + + entry = previous_history (); + + history_set_pos (pos); + + if (entry == 0) + { + rl_ding (); + return -1; + } + + arg = history_arg_extract (count, count, entry->line); + if (!arg || !*arg) + { + rl_ding (); + return -1; + } + + rl_begin_undo_group (); + + _rl_set_mark_at_pos (rl_point); + +#if defined (VI_MODE) + /* Vi mode always inserts a space before yanking the argument, and it + inserts it right *after* rl_point. */ + if (rl_editing_mode == vi_mode) + { + rl_vi_append_mode (1, ignore); + rl_insert_text (" "); + } +#endif /* VI_MODE */ + + rl_insert_text (arg); + free (arg); + + rl_end_undo_group (); + return 0; +} + +/* Yank the COUNTth argument from the previous history line. */ +int +rl_yank_nth_arg (count, ignore) + int count, ignore; +{ + return (rl_yank_nth_arg_internal (count, ignore, 0)); +} + +/* Yank the last argument from the previous history line. This `knows' + how rl_yank_nth_arg treats a count of `$'. With an argument, this + behaves the same as rl_yank_nth_arg. */ +int +rl_yank_last_arg (count, key) + int count, key; +{ + static int history_skip = 0; + static int explicit_arg_p = 0; + static int count_passed = 1; + static int direction = 1; + static int undo_needed = 0; + int retval; + + if (rl_last_func != rl_yank_last_arg) + { + history_skip = 0; + explicit_arg_p = rl_explicit_arg; + count_passed = count; + direction = 1; + } + else + { + if (undo_needed) + rl_do_undo (); + if (count < 1) + direction = -direction; + history_skip += direction; + if (history_skip < 0) + history_skip = 0; + } + + if (explicit_arg_p) + retval = rl_yank_nth_arg_internal (count_passed, key, history_skip); + else + retval = rl_yank_nth_arg_internal ('$', key, history_skip); + + undo_needed = retval == 0; + return retval; +} + +/* A special paste command for users of Cygnus's cygwin32. */ +#if defined (__CYGWIN__) +#include <windows.h> + +int +rl_paste_from_clipboard (count, key) + int count, key; +{ + char *data, *ptr; + int len; + + if (OpenClipboard (NULL) == 0) + return (0); + + data = (char *)GetClipboardData (CF_TEXT); + if (data) + { + ptr = strchr (data, '\r'); + if (ptr) + { + len = ptr - data; + ptr = (char *)xmalloc (len + 1); + ptr[len] = '\0'; + strncpy (ptr, data, len); + } + else + ptr = data; + _rl_set_mark_at_pos (rl_point); + rl_insert_text (ptr); + if (ptr != data) + free (ptr); + CloseClipboard (); + } + return (0); +} +#endif /* __CYGWIN__ */ diff --git a/cmd-line-utils/readline/macro.c b/cmd-line-utils/readline/macro.c new file mode 100644 index 00000000000..7ab4b6ca657 --- /dev/null +++ b/cmd-line-utils/readline/macro.c @@ -0,0 +1,262 @@ +/* macro.c -- keyboard macros for readline. */ + +/* Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Hacking Keyboard Macros */ +/* */ +/* **************************************************************** */ + +/* The currently executing macro string. If this is non-zero, + then it is a malloc ()'ed string where input is coming from. */ +char *rl_executing_macro = (char *)NULL; + +/* The offset in the above string to the next character to be read. */ +static int executing_macro_index; + +/* The current macro string being built. Characters get stuffed + in here by add_macro_char (). */ +static char *current_macro = (char *)NULL; + +/* The size of the buffer allocated to current_macro. */ +static int current_macro_size; + +/* The index at which characters are being added to current_macro. */ +static int current_macro_index; + +/* A structure used to save nested macro strings. + It is a linked list of string/index for each saved macro. */ +struct saved_macro { + struct saved_macro *next; + char *string; + int sindex; +}; + +/* The list of saved macros. */ +static struct saved_macro *macro_list = (struct saved_macro *)NULL; + +/* Set up to read subsequent input from STRING. + STRING is free ()'ed when we are done with it. */ +void +_rl_with_macro_input (string) + char *string; +{ + _rl_push_executing_macro (); + rl_executing_macro = string; + executing_macro_index = 0; + RL_SETSTATE(RL_STATE_MACROINPUT); +} + +/* Return the next character available from a macro, or 0 if + there are no macro characters. */ +int +_rl_next_macro_key () +{ + if (rl_executing_macro == 0) + return (0); + + if (rl_executing_macro[executing_macro_index] == 0) + { + _rl_pop_executing_macro (); + return (_rl_next_macro_key ()); + } + + return (rl_executing_macro[executing_macro_index++]); +} + +/* Save the currently executing macro on a stack of saved macros. */ +void +_rl_push_executing_macro () +{ + struct saved_macro *saver; + + saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro)); + saver->next = macro_list; + saver->sindex = executing_macro_index; + saver->string = rl_executing_macro; + + macro_list = saver; +} + +/* Discard the current macro, replacing it with the one + on the top of the stack of saved macros. */ +void +_rl_pop_executing_macro () +{ + struct saved_macro *macro; + + FREE (rl_executing_macro); + rl_executing_macro = (char *)NULL; + executing_macro_index = 0; + + if (macro_list) + { + macro = macro_list; + rl_executing_macro = macro_list->string; + executing_macro_index = macro_list->sindex; + macro_list = macro_list->next; + free (macro); + } + + if (rl_executing_macro == 0) + RL_UNSETSTATE(RL_STATE_MACROINPUT); +} + +/* Add a character to the macro being built. */ +void +_rl_add_macro_char (c) + int c; +{ + if (current_macro_index + 1 >= current_macro_size) + { + if (current_macro == 0) + current_macro = (char *)xmalloc (current_macro_size = 25); + else + current_macro = (char *)xrealloc (current_macro, current_macro_size += 25); + } + + current_macro[current_macro_index++] = c; + current_macro[current_macro_index] = '\0'; +} + +void +_rl_kill_kbd_macro () +{ + if (current_macro) + { + free (current_macro); + current_macro = (char *) NULL; + } + current_macro_size = current_macro_index = 0; + + FREE (rl_executing_macro); + rl_executing_macro = (char *) NULL; + executing_macro_index = 0; + + RL_UNSETSTATE(RL_STATE_MACRODEF); +} + +/* Begin defining a keyboard macro. + Keystrokes are recorded as they are executed. + End the definition with rl_end_kbd_macro (). + If a numeric argument was explicitly typed, then append this + definition to the end of the existing macro, and start by + re-executing the existing macro. */ +int +rl_start_kbd_macro (ignore1, ignore2) + int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); +{ + if (RL_ISSTATE (RL_STATE_MACRODEF)) + { + _rl_abort_internal (); + return -1; + } + + if (rl_explicit_arg) + { + if (current_macro) + _rl_with_macro_input (savestring (current_macro)); + } + else + current_macro_index = 0; + + RL_SETSTATE(RL_STATE_MACRODEF); + return 0; +} + +/* Stop defining a keyboard macro. + A numeric argument says to execute the macro right now, + that many times, counting the definition as the first time. */ +int +rl_end_kbd_macro (count, ignore) + int count, ignore __attribute__((unused)); +{ + if (RL_ISSTATE (RL_STATE_MACRODEF) == 0) + { + _rl_abort_internal (); + return -1; + } + + current_macro_index -= rl_key_sequence_length - 1; + current_macro[current_macro_index] = '\0'; + + RL_UNSETSTATE(RL_STATE_MACRODEF); + + return (rl_call_last_kbd_macro (--count, 0)); +} + +/* Execute the most recently defined keyboard macro. + COUNT says how many times to execute it. */ +int +rl_call_last_kbd_macro (count, ignore) + int count, ignore __attribute__((unused)); +{ + if (current_macro == 0) + _rl_abort_internal (); + + if (RL_ISSTATE (RL_STATE_MACRODEF)) + { + rl_ding (); /* no recursive macros */ + current_macro[--current_macro_index] = '\0'; /* erase this char */ + return 0; + } + + while (count--) + _rl_with_macro_input (savestring (current_macro)); + return 0; +} + +void +rl_push_macro_input (macro) + char *macro; +{ + _rl_with_macro_input (macro); +} diff --git a/cmd-line-utils/readline/mbutil.c b/cmd-line-utils/readline/mbutil.c new file mode 100644 index 00000000000..debad6320ce --- /dev/null +++ b/cmd-line-utils/readline/mbutil.c @@ -0,0 +1,337 @@ +/* mbutil.c -- readline multibyte character utility functions */ + +/* Copyright (C) 2001 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include "posixjmp.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> +#include <ctype.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (TIOCSTAT_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* TIOCSTAT_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* Declared here so it can be shared between the readline and history + libraries. */ +#if defined (HANDLE_MULTIBYTE) +int rl_byte_oriented = 0; +#else +int rl_byte_oriented = 1; +#endif + +/* **************************************************************** */ +/* */ +/* Multibyte Character Utility Functions */ +/* */ +/* **************************************************************** */ + +#if defined(HANDLE_MULTIBYTE) + +static int +_rl_find_next_mbchar_internal (string, seed, count, find_non_zero) + char *string; + int seed, count, find_non_zero; +{ + size_t tmp = 0; + mbstate_t ps; + int point = 0; + wchar_t wc; + + memset(&ps, 0, sizeof (mbstate_t)); + if (seed < 0) + seed = 0; + if (count <= 0) + return seed; + + point = seed + _rl_adjust_point(string, seed, &ps); + /* if this is true, means that seed was not pointed character + started byte. So correct the point and consume count */ + if (seed < point) + count --; + + while (count > 0) + { + tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps); + if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* invalid bytes. asume a byte represents a character */ + point++; + count--; + /* reset states. */ + memset(&ps, 0, sizeof(mbstate_t)); + } + else if (tmp == (size_t)0) + /* found '\0' char */ + break; + else + { + /* valid bytes */ + point += tmp; + if (find_non_zero) + { + if (wcwidth (wc) == 0) + continue; + else + count--; + } + else + count--; + } + } + + if (find_non_zero) + { + tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); + while (wcwidth (wc) == 0) + { + point += tmp; + tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps); + if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2)) + break; + } + } + return point; +} + +static int +_rl_find_prev_mbchar_internal (string, seed, find_non_zero) + char *string; + int seed, find_non_zero; +{ + mbstate_t ps; + int prev, non_zero_prev, point, length; + size_t tmp; + wchar_t wc; + + memset(&ps, 0, sizeof(mbstate_t)); + length = strlen(string); + + if (seed < 0) + return 0; + else if (length < seed) + return length; + + prev = non_zero_prev = point = 0; + while (point < seed) + { + tmp = mbrtowc (&wc, string + point, length - point, &ps); + if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* in this case, bytes are invalid or shorted to compose + multibyte char, so assume that the first byte represents + a single character anyway. */ + tmp = 1; + /* clear the state of the byte sequence, because + in this case effect of mbstate is undefined */ + memset(&ps, 0, sizeof (mbstate_t)); + } + else if (tmp == 0) + break; /* Found '\0' char. Can this happen? */ + else + { + if (find_non_zero) + { + if (wcwidth (wc) != 0) + prev = point; + } + else + prev = point; + } + + point += tmp; + } + + return prev; +} + +/* return the number of bytes parsed from the multibyte sequence starting + at src, if a non-L'\0' wide character was recognized. It returns 0, + if a L'\0' wide character was recognized. It returns (size_t)(-1), + if an invalid multibyte sequence was encountered. It returns (size_t)(-2) + if it couldn't parse a complete multibyte character. */ +int +_rl_get_char_len (src, ps) + const char *src; + mbstate_t *ps; +{ + size_t tmp; + + tmp = mbrlen((const char *)src, (size_t)strlen (src), ps); + if (tmp == (size_t)(-2)) + { + /* shorted to compose multibyte char */ + memset (ps, 0, sizeof(mbstate_t)); + return -2; + } + else if (tmp == (size_t)(-1)) + { + /* invalid to compose multibyte char */ + /* initialize the conversion state */ + memset (ps, 0, sizeof(mbstate_t)); + return -1; + } + else if (tmp == (size_t)0) + return 0; + else + return (int)tmp; +} + +/* compare the specified two characters. If the characters matched, + return 1. Otherwise return 0. */ +int +_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2) + char *buf1, *buf2; + mbstate_t *ps1, *ps2; + int pos1, pos2; +{ + int i, w1, w2; + + if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 || + (w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 || + (w1 != w2) || + (buf1[pos1] != buf2[pos2])) + return 0; + + for (i = 1; i < w1; i++) + if (buf1[pos1+i] != buf2[pos2+i]) + return 0; + + return 1; +} + +/* adjust pointed byte and find mbstate of the point of string. + adjusted point will be point <= adjusted_point, and returns + differences of the byte(adjusted_point - point). + if point is invalied (point < 0 || more than string length), + it returns -1 */ +int +_rl_adjust_point(string, point, ps) + const char *string; + int point; + mbstate_t *ps; +{ + size_t tmp = 0; + int length; + int pos = 0; + + length = strlen(string); + if (point < 0) + return -1; + if (length < point) + return -1; + + while (pos < point) + { + tmp = mbrlen (string + pos, length - pos, ps); + if((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2) + { + /* in this case, bytes are invalid or shorted to compose + multibyte char, so assume that the first byte represents + a single character anyway. */ + pos++; + /* clear the state of the byte sequence, because + in this case effect of mbstate is undefined */ + memset (ps, 0, sizeof (mbstate_t)); + } + else + pos += tmp; + } + + return (pos - point); +} + +int +_rl_is_mbchar_matched (string, seed, end, mbchar, length) + char *string; + int seed, end; + char *mbchar; + int length; +{ + int i; + + if ((end - seed) < length) + return 0; + + for (i = 0; i < length; i++) + if (string[seed + i] != mbchar[i]) + return 0; + return 1; +} +#endif /* HANDLE_MULTIBYTE */ + +/* Find next `count' characters started byte point of the specified seed. + If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte + characters. */ +#undef _rl_find_next_mbchar +int +_rl_find_next_mbchar (string, seed, count, flags) + char *string __attribute__((unused)); + int seed, count, flags __attribute__((unused)); +{ +#if defined (HANDLE_MULTIBYTE) + return _rl_find_next_mbchar_internal (string, seed, count, flags); +#else + return (seed + count); +#endif +} + +/* Find previous character started byte point of the specified seed. + Returned point will be point <= seed. If flags is MB_FIND_NONZERO, + we look for non-zero-width multibyte characters. */ +#undef _rl_find_prev_mbchar +int +_rl_find_prev_mbchar (string, seed, flags) + char *string __attribute__((unused)); + int seed, flags __attribute__((unused)); +{ +#if defined (HANDLE_MULTIBYTE) + return _rl_find_prev_mbchar_internal (string, seed, flags); +#else + return ((seed == 0) ? seed : seed - 1); +#endif +} diff --git a/cmd-line-utils/readline/misc.c b/cmd-line-utils/readline/misc.c new file mode 100644 index 00000000000..94ad433473b --- /dev/null +++ b/cmd-line-utils/readline/misc.c @@ -0,0 +1,496 @@ +/* misc.c -- miscellaneous bindable readline functions. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +static int rl_digit_loop PARAMS((void)); +static void _rl_history_set_point PARAMS((void)); + +/* Forward declarations used in this file */ +void _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +/* If non-zero, rl_get_previous_history and rl_get_next_history attempt + to preserve the value of rl_point from line to line. */ +int _rl_history_preserve_point = 0; + +/* Saved target point for when _rl_history_preserve_point is set. Special + value of -1 means that point is at the end of the line. */ +int _rl_history_saved_point = -1; + +/* **************************************************************** */ +/* */ +/* Numeric Arguments */ +/* */ +/* **************************************************************** */ + +/* Handle C-u style numeric args, as well as M--, and M-digits. */ +static int +rl_digit_loop () +{ + int key, c, sawminus, sawdigits; + + rl_save_prompt (); + + RL_SETSTATE(RL_STATE_NUMERICARG); + sawminus = sawdigits = 0; + while (1) + { + if (rl_numeric_arg > 1000000) + { + sawdigits = rl_explicit_arg = rl_numeric_arg = 0; + rl_ding (); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return 1; + } + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); + RL_SETSTATE(RL_STATE_MOREINPUT); + key = c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c < 0) + { + _rl_abort_internal (); + return -1; + } + + /* If we see a key bound to `universal-argument' after seeing digits, + it ends the argument but is otherwise ignored. */ + if (_rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + if (sawdigits == 0) + { + rl_numeric_arg *= 4; + continue; + } + else + { + RL_SETSTATE(RL_STATE_MOREINPUT); + key = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + c = UNMETA (c); + + if (_rl_digit_p (c)) + { + rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0'; + sawdigits = rl_explicit_arg = 1; + } + else if (c == '-' && rl_explicit_arg == 0) + { + rl_numeric_arg = sawminus = 1; + rl_arg_sign = -1; + } + else + { + /* Make M-- command equivalent to M--1 command. */ + if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0) + rl_explicit_arg = 1; + rl_restore_prompt (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (_rl_dispatch (key, _rl_keymap)); + } + } + + /*NOTREACHED*/ +} + +/* Add the current digit to the argument in progress. */ +int +rl_digit_argument (ignore, key) + int ignore __attribute__((unused)), key; +{ + rl_execute_next (key); + return (rl_digit_loop ()); +} + +/* What to do when you abort reading an argument. */ +int +rl_discard_argument () +{ + rl_ding (); + rl_clear_message (); + _rl_init_argument (); + return 0; +} + +/* Create a default argument. */ +int +_rl_init_argument () +{ + rl_numeric_arg = rl_arg_sign = 1; + rl_explicit_arg = 0; + return 0; +} + +/* C-u, universal argument. Multiply the current argument by 4. + Read a key. If the key has nothing to do with arguments, then + dispatch on it. If the key is the abort character then abort. */ +int +rl_universal_argument (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_numeric_arg *= 4; + return (rl_digit_loop ()); +} + +/* **************************************************************** */ +/* */ +/* History Utilities */ +/* */ +/* **************************************************************** */ + +/* We already have a history library, and that is what we use to control + the history features of readline. This is our local interface to + the history mechanism. */ + +/* While we are editing the history, this is the saved + version of the original line. */ +HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL; + +/* Set the history pointer back to the last entry in the history. */ +void +_rl_start_using_history () +{ + using_history (); + if (_rl_saved_line_for_history) + _rl_free_history_entry (_rl_saved_line_for_history); + + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; +} + +/* Free the contents (and containing structure) of a HIST_ENTRY. */ +void +_rl_free_history_entry (entry) + HIST_ENTRY *entry; +{ + if (entry == 0) + return; + if (entry->line) + free (entry->line); + free (entry); +} + +/* Perhaps put back the current line if it has changed. */ +int +rl_maybe_replace_line () +{ + HIST_ENTRY *temp; + + temp = current_history (); + /* If the current line has changed, save the changes. */ + if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) + { + temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list); + free (temp->line); + free (temp); + } + return 0; +} + +/* Restore the _rl_saved_line_for_history if there is one. */ +int +rl_maybe_unsave_line () +{ + if (_rl_saved_line_for_history) + { + rl_replace_line (_rl_saved_line_for_history->line, 0); + rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data; + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + rl_point = rl_end; /* rl_replace_line sets rl_end */ + } + else + rl_ding (); + return 0; +} + +/* Save the current line in _rl_saved_line_for_history. */ +int +rl_maybe_save_line () +{ + if (_rl_saved_line_for_history == 0) + { + _rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + _rl_saved_line_for_history->line = savestring (rl_line_buffer); + _rl_saved_line_for_history->data = (char *)rl_undo_list; + } + return 0; +} + +int +_rl_free_saved_history_line () +{ + if (_rl_saved_line_for_history) + { + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + } + return 0; +} + +static void +_rl_history_set_point () +{ + rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1) + ? _rl_history_saved_point + : rl_end; + if (rl_point > rl_end) + rl_point = rl_end; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_point = 0; +#endif /* VI_MODE */ + + if (rl_editing_mode == emacs_mode) + rl_mark = (rl_point == rl_end ? 0 : rl_end); +} + +void +rl_replace_from_history (entry, flags) + HIST_ENTRY *entry; + int flags __attribute__((unused)); /* currently unused */ +{ + rl_replace_line (entry->line, 0); + rl_undo_list = (UNDO_LIST *)entry->data; + rl_point = rl_end; + rl_mark = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + { + rl_point = 0; + rl_mark = rl_end; + } +#endif +} + +/* **************************************************************** */ +/* */ +/* History Commands */ +/* */ +/* **************************************************************** */ + +/* Meta-< goes to the start of the history. */ +int +rl_beginning_of_history (count, key) + int count __attribute__((unused)), key; +{ + return (rl_get_previous_history (1 + where_history (), key)); +} + +/* Meta-> goes to the end of the history. (The current line). */ +int +rl_end_of_history (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_maybe_replace_line (); + using_history (); + rl_maybe_unsave_line (); + return 0; +} + +/* Move down to the next history line. */ +int +rl_get_next_history (count, key) + int count, key; +{ + HIST_ENTRY *temp; + + if (count < 0) + return (rl_get_previous_history (-count, key)); + + if (count == 0) + return 0; + + rl_maybe_replace_line (); + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = next_history (); + if (!temp) + break; + --count; + } + + if (temp == 0) + rl_maybe_unsave_line (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* Get the previous item out of our interactive history, making it the current + line. If there is no previous history, just ding. */ +int +rl_get_previous_history (count, key) + int count, key; +{ + HIST_ENTRY *old_temp, *temp; + + if (count < 0) + return (rl_get_next_history (-count, key)); + + if (count == 0) + return 0; + + /* either not saved by rl_newline or at end of line, so set appropriately. */ + if (_rl_history_saved_point == -1 && (rl_point || rl_end)) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + /* If we don't have a line saved, then save this one. */ + rl_maybe_save_line (); + + /* If the current line has changed, save the changes. */ + rl_maybe_replace_line (); + + temp = old_temp = (HIST_ENTRY *)NULL; + while (count) + { + temp = previous_history (); + if (temp == 0) + break; + + old_temp = temp; + --count; + } + + /* If there was a large argument, and we moved back to the start of the + history, that is not an error. So use the last value found. */ + if (!temp && old_temp) + temp = old_temp; + + if (temp == 0) + rl_ding (); + else + { + rl_replace_from_history (temp, 0); + _rl_history_set_point (); + } + return 0; +} + +/* **************************************************************** */ +/* */ +/* Editing Modes */ +/* */ +/* **************************************************************** */ +/* How to toggle back and forth between editing modes. */ +int +rl_vi_editing_mode (count, key) + int count __attribute__((unused)), key; +{ +#if defined (VI_MODE) + _rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */ + rl_editing_mode = vi_mode; + rl_vi_insertion_mode (1, key); +#endif /* VI_MODE */ + + return 0; +} + +int +rl_emacs_editing_mode (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_editing_mode = emacs_mode; + _rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */ + _rl_keymap = emacs_standard_keymap; + return 0; +} + +/* Function for the rest of the library to use to set insert/overwrite mode. */ +void +_rl_set_insert_mode (im, force) + int im, force __attribute__((unused)); +{ +#ifdef CURSOR_MODE + _rl_set_cursor (im, force); +#endif + + rl_insert_mode = im; +} + +/* Toggle overwrite mode. A positive explicit argument selects overwrite + mode. A negative or zero explicit argument selects insert mode. */ +int +rl_overwrite_mode (count, key) + int count, key __attribute__((unused)); +{ + if (rl_explicit_arg == 0) + _rl_set_insert_mode (rl_insert_mode ^ 1, 0); + else if (count > 0) + _rl_set_insert_mode (RL_IM_OVERWRITE, 0); + else + _rl_set_insert_mode (RL_IM_INSERT, 0); + + return 0; +} diff --git a/cmd-line-utils/readline/nls.c b/cmd-line-utils/readline/nls.c new file mode 100644 index 00000000000..706c8195c10 --- /dev/null +++ b/cmd-line-utils/readline/nls.c @@ -0,0 +1,225 @@ +/* nls.c -- skeletal internationalization code. */ + +/* Copyright (C) 1996 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <ctype.h> + +#include "rldefs.h" +#include "readline.h" +#include "rlshell.h" +#include "rlprivate.h" + +#if !defined (HAVE_SETLOCALE) +/* A list of legal values for the LANG or LC_CTYPE environment variables. + If a locale name in this list is the value for the LC_ALL, LC_CTYPE, + or LANG environment variable (using the first of those with a value), + readline eight-bit mode is enabled. */ +static char *legal_lang_values[] = +{ + "iso88591", + "iso88592", + "iso88593", + "iso88594", + "iso88595", + "iso88596", + "iso88597", + "iso88598", + "iso88599", + "iso885910", + "koi8r", + 0 +}; + +static char *normalize_codeset PARAMS((char *)); +static char *find_codeset PARAMS((char *, size_t *)); +#endif /* !HAVE_SETLOCALE */ + +/* Check for LC_ALL, LC_CTYPE, and LANG and use the first with a value + to decide the defaults for 8-bit character input and output. Returns + 1 if we set eight-bit mode. */ +int +_rl_init_eightbit () +{ +/* If we have setlocale(3), just check the current LC_CTYPE category + value, and go into eight-bit mode if it's not C or POSIX. */ +#if defined (HAVE_SETLOCALE) + char *t; + + /* Set the LC_CTYPE locale category from environment variables. */ + t = setlocale (LC_CTYPE, ""); + if (t && *t && (t[0] != 'C' || t[1]) && (STREQ (t, "POSIX") == 0)) + { + _rl_meta_flag = 1; + _rl_convert_meta_chars_to_ascii = 0; + _rl_output_meta_chars = 1; + return (1); + } + else + return (0); + +#else /* !HAVE_SETLOCALE */ + char *lspec, *t; + int i; + + /* We don't have setlocale. Finesse it. Check the environment for the + appropriate variables and set eight-bit mode if they have the right + values. */ + lspec = sh_get_env_value ("LC_ALL"); + if (lspec == 0) lspec = sh_get_env_value ("LC_CTYPE"); + if (lspec == 0) lspec = sh_get_env_value ("LANG"); + if (lspec == 0 || (t = normalize_codeset (lspec)) == 0) + return (0); + for (i = 0; t && legal_lang_values[i]; i++) + if (STREQ (t, legal_lang_values[i])) + { + _rl_meta_flag = 1; + _rl_convert_meta_chars_to_ascii = 0; + _rl_output_meta_chars = 1; + break; + } + free (t); + return (legal_lang_values[i] ? 1 : 0); + +#endif /* !HAVE_SETLOCALE */ +} + +#if !defined (HAVE_SETLOCALE) +static char * +normalize_codeset (codeset) + char *codeset; +{ + size_t namelen, i; + int len, all_digits; + char *wp, *retval; + + codeset = find_codeset (codeset, &namelen); + + if (codeset == 0) + return (codeset); + + all_digits = 1; + for (len = 0, i = 0; i < namelen; i++) + { + if (ISALNUM ((unsigned char)codeset[i])) + { + len++; + all_digits &= _rl_digit_p (codeset[i]); + } + } + + retval = (char *)malloc ((all_digits ? 3 : 0) + len + 1); + if (retval == 0) + return ((char *)0); + + wp = retval; + /* Add `iso' to beginning of an all-digit codeset */ + if (all_digits) + { + *wp++ = 'i'; + *wp++ = 's'; + *wp++ = 'o'; + } + + for (i = 0; i < namelen; i++) + if (ISALPHA ((unsigned char)codeset[i])) + *wp++ = _rl_to_lower (codeset[i]); + else if (_rl_digit_p (codeset[i])) + *wp++ = codeset[i]; + *wp = '\0'; + + return retval; +} + +/* Isolate codeset portion of locale specification. */ +static char * +find_codeset (name, lenp) + char *name; + size_t *lenp; +{ + char *cp, *language, *result; + + cp = language = name; + result = (char *)0; + + while (*cp && *cp != '_' && *cp != '@' && *cp != '+' && *cp != ',') + cp++; + + /* This does not make sense: language has to be specified. As + an exception we allow the variable to contain only the codeset + name. Perhaps there are funny codeset names. */ + if (language == cp) + { + *lenp = strlen (language); + result = language; + } + else + { + /* Next is the territory. */ + if (*cp == '_') + do + ++cp; + while (*cp && *cp != '.' && *cp != '@' && *cp != '+' && *cp != ',' && *cp != '_'); + + /* Now, finally, is the codeset. */ + result = cp; + if (*cp == '.') + do + ++cp; + while (*cp && *cp != '@'); + + if (cp - result > 2) + { + result++; + *lenp = cp - result; + } + else + { + *lenp = strlen (language); + result = language; + } + } + + return result; +} +#endif /* !HAVE_SETLOCALE */ diff --git a/cmd-line-utils/readline/parens.c b/cmd-line-utils/readline/parens.c new file mode 100644 index 00000000000..54ef1f3695f --- /dev/null +++ b/cmd-line-utils/readline/parens.c @@ -0,0 +1,179 @@ +/* parens.c -- Implementation of matching parentheses feature. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#include "rlconf.h" + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (FD_SET) && !defined (HAVE_SELECT) +# define HAVE_SELECT +#endif + +#if defined (HAVE_SELECT) +# include <sys/time.h> +#endif /* HAVE_SELECT */ +#if defined (HAVE_SYS_SELECT_H) +# include <sys/select.h> +#endif + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#include "readline.h" +#include "rlprivate.h" + +static int find_matching_open PARAMS((char *, int, int)); + +/* Non-zero means try to blink the matching open parenthesis when the + close parenthesis is inserted. */ +#if defined (HAVE_SELECT) +int rl_blink_matching_paren = 1; +#else /* !HAVE_SELECT */ +int rl_blink_matching_paren = 0; +#endif /* !HAVE_SELECT */ + +static int _paren_blink_usec = 500000; + +/* Change emacs_standard_keymap to have bindings for paren matching when + ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */ +void +_rl_enable_paren_matching (on_or_off) + int on_or_off; +{ + if (on_or_off) + { /* ([{ */ + rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap); + rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap); + rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap); + } + else + { /* ([{ */ + rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap); + rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap); + rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap); + } +} + +int +rl_set_paren_blink_timeout (u) + int u; +{ + int o; + + o = _paren_blink_usec; + if (u > 0) + _paren_blink_usec = u; + return (o); +} + +int +rl_insert_close (count, invoking_key) + int count, invoking_key; +{ + if (rl_explicit_arg || !rl_blink_matching_paren) + _rl_insert_char (count, invoking_key); + else + { +#if defined (HAVE_SELECT) + int orig_point, match_point, ready; + struct timeval timer; + fd_set readfds; + + _rl_insert_char (1, invoking_key); + (*rl_redisplay_function) (); + match_point = + find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); + + /* Emacs might message or ring the bell here, but I don't. */ + if (match_point < 0) + return -1; + + FD_ZERO (&readfds); + FD_SET (fileno (rl_instream), &readfds); + timer.tv_sec = 0; + timer.tv_usec = _paren_blink_usec; + + orig_point = rl_point; + rl_point = match_point; + (*rl_redisplay_function) (); + ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); + rl_point = orig_point; +#else /* !HAVE_SELECT */ + _rl_insert_char (count, invoking_key); +#endif /* !HAVE_SELECT */ + } + return 0; +} + +static int +find_matching_open (string, from, closer) + char *string; + int from, closer; +{ + register int i; + int opener, level, delimiter; + + switch (closer) + { + case ']': opener = '['; break; + case '}': opener = '{'; break; + case ')': opener = '('; break; + default: + return (-1); + } + + level = 1; /* The closer passed in counts as 1. */ + delimiter = 0; /* Delimited state unknown. */ + + for (i = from; i > -1; i--) + { + if (delimiter && (string[i] == delimiter)) + delimiter = 0; + else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i])) + delimiter = string[i]; + else if (!delimiter && (string[i] == closer)) + level++; + else if (!delimiter && (string[i] == opener)) + level--; + + if (!level) + break; + } + return (i); +} diff --git a/cmd-line-utils/readline/posixdir.h b/cmd-line-utils/readline/posixdir.h new file mode 100644 index 00000000000..505e27954f1 --- /dev/null +++ b/cmd-line-utils/readline/posixdir.h @@ -0,0 +1,57 @@ +/* posixdir.h -- Posix directory reading includes and defines. */ + +/* Copyright (C) 1987,1991 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with Bash; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* This file should be included instead of <dirent.h> or <sys/dir.h>. */ + +#if !defined (_POSIXDIR_H_) +#define _POSIXDIR_H_ + +#if defined (HAVE_DIRENT_H) +# include <dirent.h> +# define D_NAMLEN(d) (strlen ((d)->d_name)) +#else +# if defined (HAVE_SYS_NDIR_H) +# include <sys/ndir.h> +# endif +# if defined (HAVE_SYS_DIR_H) +# include <sys/dir.h> +# endif +# if defined (HAVE_NDIR_H) +# include <ndir.h> +# endif +# if !defined (dirent) +# define dirent direct +# endif /* !dirent */ +# define D_NAMLEN(d) ((d)->d_namlen) +#endif /* !HAVE_DIRENT_H */ + +#if defined (STRUCT_DIRENT_HAS_D_INO) && !defined (STRUCT_DIRENT_HAS_D_FILENO) +# define d_fileno d_ino +#endif + +#if defined (_POSIX_SOURCE) && (!defined (STRUCT_DIRENT_HAS_D_INO) || defined (BROKEN_DIRENT_D_INO)) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* _POSIX_SOURCE */ + +#endif /* !_POSIXDIR_H_ */ diff --git a/cmd-line-utils/readline/posixjmp.h b/cmd-line-utils/readline/posixjmp.h new file mode 100644 index 00000000000..b52aa00332b --- /dev/null +++ b/cmd-line-utils/readline/posixjmp.h @@ -0,0 +1,40 @@ +/* posixjmp.h -- wrapper for setjmp.h with changes for POSIX systems. */ + +/* Copyright (C) 1987,1991 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with Bash; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _POSIXJMP_H_ +#define _POSIXJMP_H_ + +#include <setjmp.h> + +/* This *must* be included *after* config.h */ + +#if defined (HAVE_POSIX_SIGSETJMP) +# define procenv_t sigjmp_buf +# if !defined (__OPENNT) +# undef setjmp +# define setjmp(x) sigsetjmp((x), 1) +# undef longjmp +# define longjmp(x, n) siglongjmp((x), (n)) +# endif /* !__OPENNT */ +#else +# define procenv_t jmp_buf +#endif + +#endif /* _POSIXJMP_H_ */ diff --git a/cmd-line-utils/readline/posixstat.h b/cmd-line-utils/readline/posixstat.h new file mode 100644 index 00000000000..c93b52887e9 --- /dev/null +++ b/cmd-line-utils/readline/posixstat.h @@ -0,0 +1,142 @@ +/* posixstat.h -- Posix stat(2) definitions for systems that + don't have them. */ + +/* Copyright (C) 1987,1991 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with Bash; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +/* This file should be included instead of <sys/stat.h>. + It relies on the local sys/stat.h to work though. */ +#if !defined (_POSIXSTAT_H_) +#define _POSIXSTAT_H_ + +#include <sys/stat.h> + +#if defined (STAT_MACROS_BROKEN) +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISREG +# undef S_ISLNK +#endif /* STAT_MACROS_BROKEN */ + +/* These are guaranteed to work only on isc386 */ +#if !defined (S_IFDIR) && !defined (S_ISDIR) +# define S_IFDIR 0040000 +#endif /* !S_IFDIR && !S_ISDIR */ +#if !defined (S_IFMT) +# define S_IFMT 0170000 +#endif /* !S_IFMT */ + +/* Posix 1003.1 5.6.1.1 <sys/stat.h> file types */ + +/* Some Posix-wannabe systems define _S_IF* macros instead of S_IF*, but + do not provide the S_IS* macros that Posix requires. */ + +#if defined (_S_IFMT) && !defined (S_IFMT) +#define S_IFMT _S_IFMT +#endif +#if defined (_S_IFIFO) && !defined (S_IFIFO) +#define S_IFIFO _S_IFIFO +#endif +#if defined (_S_IFCHR) && !defined (S_IFCHR) +#define S_IFCHR _S_IFCHR +#endif +#if defined (_S_IFDIR) && !defined (S_IFDIR) +#define S_IFDIR _S_IFDIR +#endif +#if defined (_S_IFBLK) && !defined (S_IFBLK) +#define S_IFBLK _S_IFBLK +#endif +#if defined (_S_IFREG) && !defined (S_IFREG) +#define S_IFREG _S_IFREG +#endif +#if defined (_S_IFLNK) && !defined (S_IFLNK) +#define S_IFLNK _S_IFLNK +#endif +#if defined (_S_IFSOCK) && !defined (S_IFSOCK) +#define S_IFSOCK _S_IFSOCK +#endif + +/* Test for each symbol individually and define the ones necessary (some + systems claiming Posix compatibility define some but not all). */ + +#if defined (S_IFBLK) && !defined (S_ISBLK) +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */ +#endif + +#if defined (S_IFCHR) && !defined (S_ISCHR) +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */ +#endif + +#if defined (S_IFDIR) && !defined (S_ISDIR) +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */ +#endif + +#if defined (S_IFREG) && !defined (S_ISREG) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */ +#endif + +#if defined (S_IFIFO) && !defined (S_ISFIFO) +#define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */ +#endif + +#if defined (S_IFLNK) && !defined (S_ISLNK) +#define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */ +#endif + +#if defined (S_IFSOCK) && !defined (S_ISSOCK) +#define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */ +#endif + +/* + * POSIX 1003.1 5.6.1.2 <sys/stat.h> File Modes + */ + +#if !defined (S_IRWXU) +# if !defined (S_IREAD) +# define S_IREAD 00400 +# define S_IWRITE 00200 +# define S_IEXEC 00100 +# endif /* S_IREAD */ + +# if !defined (S_IRUSR) +# define S_IRUSR S_IREAD /* read, owner */ +# define S_IWUSR S_IWRITE /* write, owner */ +# define S_IXUSR S_IEXEC /* execute, owner */ + +# define S_IRGRP (S_IREAD >> 3) /* read, group */ +# define S_IWGRP (S_IWRITE >> 3) /* write, group */ +# define S_IXGRP (S_IEXEC >> 3) /* execute, group */ + +# define S_IROTH (S_IREAD >> 6) /* read, other */ +# define S_IWOTH (S_IWRITE >> 6) /* write, other */ +# define S_IXOTH (S_IEXEC >> 6) /* execute, other */ +# endif /* !S_IRUSR */ + +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif /* !S_IRWXU */ + +/* These are non-standard, but are used in builtins.c$symbolic_umask() */ +#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) +#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) + +#endif /* _POSIXSTAT_H_ */ diff --git a/cmd-line-utils/readline/readline.c b/cmd-line-utils/readline/readline.c new file mode 100644 index 00000000000..28801f19dfc --- /dev/null +++ b/cmd-line-utils/readline/readline.c @@ -0,0 +1,973 @@ +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include "posixstat.h" +#include <fcntl.h> +#if defined (HAVE_SYS_FILE_H) +# include <sys/file.h> +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> +#include "posixjmp.h" + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (__EMX__) +# define INCL_DOSPROCESS +# include <os2.h> +#endif /* __EMX__ */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +#ifndef RL_LIBRARY_VERSION +# define RL_LIBRARY_VERSION "4.3" +#endif + +#ifndef RL_READLINE_VERSION +# define RL_READLINE_VERSION 0x0403 +#endif + +extern void _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +/* Forward declarations used in this file. */ +static char *readline_internal PARAMS((void)); +static void readline_initialize_everything PARAMS((void)); + +static void bind_arrow_keys_internal PARAMS((Keymap)); +static void bind_arrow_keys PARAMS((void)); + +static void readline_default_bindings PARAMS((void)); + +/* **************************************************************** */ +/* */ +/* Line editing input utility */ +/* */ +/* **************************************************************** */ + +const char *rl_library_version = RL_LIBRARY_VERSION; + +int rl_readline_version = RL_READLINE_VERSION; + +/* True if this is `real' readline as opposed to some stub substitute. */ +int rl_gnu_readline_p = 1; + +/* A pointer to the keymap that is currently in use. + By default, it is the standard emacs keymap. */ +Keymap _rl_keymap = emacs_standard_keymap; + +/* The current style of editing. */ +int rl_editing_mode = emacs_mode; + +/* The current insert mode: input (the default) or overwrite */ +int rl_insert_mode = RL_IM_DEFAULT; + +/* Non-zero if we called this function from _rl_dispatch(). It's present + so functions can find out whether they were called from a key binding + or directly from an application. */ +int rl_dispatching; + +/* Non-zero if the previous command was a kill command. */ +int _rl_last_command_was_kill = 0; + +/* The current value of the numeric argument specified by the user. */ +int rl_numeric_arg = 1; + +/* Non-zero if an argument was typed. */ +int rl_explicit_arg = 0; + +/* Temporary value used while generating the argument. */ +int rl_arg_sign = 1; + +/* Non-zero means we have been called at least once before. */ +static int rl_initialized; + +#if 0 +/* If non-zero, this program is running in an EMACS buffer. */ +static int running_in_emacs; +#endif + +/* Flags word encapsulating the current readline state. */ +int rl_readline_state = RL_STATE_NONE; + +/* The current offset in the current input line. */ +int rl_point; + +/* Mark in the current input line. */ +int rl_mark; + +/* Length of the current input line. */ +int rl_end; + +/* Make this non-zero to return the current input_line. */ +int rl_done; + +/* The last function executed by readline. */ +rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; + +/* Top level environment for readline_internal (). */ +procenv_t readline_top_level; + +/* The streams we interact with. */ +FILE *_rl_in_stream, *_rl_out_stream; + +/* The names of the streams that we do input and output to. */ +FILE *rl_instream = (FILE *)NULL; +FILE *rl_outstream = (FILE *)NULL; + +/* Non-zero means echo characters as they are read. Defaults to no echo; + set to 1 if there is a controlling terminal, we can get its attributes, + and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings + for the code that sets it. */ +int readline_echoing_p = 0; + +/* Current prompt. */ +char *rl_prompt = (char *)NULL; +int rl_visible_prompt_length = 0; + +/* Set to non-zero by calling application if it has already printed rl_prompt + and does not want readline to do it the first time. */ +int rl_already_prompted = 0; + +/* The number of characters read in order to type this complete command. */ +int rl_key_sequence_length = 0; + +/* If non-zero, then this is the address of a function to call just + before readline_internal_setup () prints the first prompt. */ +rl_hook_func_t *rl_startup_hook = (rl_hook_func_t *)NULL; + +/* If non-zero, this is the address of a function to call just before + readline_internal_setup () returns and readline_internal starts + reading input characters. */ +rl_hook_func_t *rl_pre_input_hook = (rl_hook_func_t *)NULL; + +/* What we use internally. You should always refer to RL_LINE_BUFFER. */ +static char *the_line; + +/* The character that can generate an EOF. Really read from + the terminal driver... just defaulted here. */ +int _rl_eof_char = CTRL ('D'); + +/* Non-zero makes this the next keystroke to read. */ +int rl_pending_input = 0; + +/* Pointer to a useful terminal name. */ +const char *rl_terminal_name = (const char *)NULL; + +/* Non-zero means to always use horizontal scrolling in line display. */ +int _rl_horizontal_scroll_mode = 0; + +/* Non-zero means to display an asterisk at the starts of history lines + which have been modified. */ +int _rl_mark_modified_lines = 0; + +/* The style of `bell' notification preferred. This can be set to NO_BELL, + AUDIBLE_BELL, or VISIBLE_BELL. */ +int _rl_bell_preference = AUDIBLE_BELL; + +/* String inserted into the line by rl_insert_comment (). */ +char *_rl_comment_begin; + +/* Keymap holding the function currently being executed. */ +Keymap rl_executing_keymap; + +/* Non-zero means to erase entire line, including prompt, on empty input lines. */ +int rl_erase_empty_line = 0; + +/* Non-zero means to read only this many characters rather than up to a + character bound to accept-line. */ +int rl_num_chars_to_read; + +/* Line buffer and maintenence. */ +char *rl_line_buffer = (char *)NULL; +int rl_line_buffer_len = 0; + +/* Forward declarations used by the display, termcap, and history code. */ + +/* **************************************************************** */ +/* */ +/* `Forward' declarations */ +/* */ +/* **************************************************************** */ + +/* Non-zero means do not parse any lines other than comments and + parser directives. */ +unsigned char _rl_parsing_conditionalized_out = 0; + +/* Non-zero means to convert characters with the meta bit set to + escape-prefixed characters so we can indirect through + emacs_meta_keymap or vi_escape_keymap. */ +int _rl_convert_meta_chars_to_ascii = 1; + +/* Non-zero means to output characters with the meta bit set directly + rather than as a meta-prefixed escape sequence. */ +int _rl_output_meta_chars = 0; + +/* **************************************************************** */ +/* */ +/* Top Level Functions */ +/* */ +/* **************************************************************** */ + +/* Non-zero means treat 0200 bit in terminal input as Meta bit. */ +int _rl_meta_flag = 0; /* Forward declaration */ + +/* Set up the prompt and expand it. Called from readline() and + rl_callback_handler_install (). */ +int +rl_set_prompt (prompt) + const char *prompt; +{ + FREE (rl_prompt); + rl_prompt = prompt ? savestring (prompt) : (char *)NULL; + + rl_visible_prompt_length = rl_expand_prompt (rl_prompt); + return 0; +} + +/* Read a line of input. Prompt with PROMPT. An empty PROMPT means + none. A return value of NULL means that EOF was encountered. */ +char * +readline (prompt) + const char *prompt; +{ + char *value; + + /* If we are at EOF return a NULL string. */ + if (rl_pending_input == EOF) + { + rl_clear_pending_input (); + return ((char *)NULL); + } + + rl_set_prompt (prompt); + + rl_initialize (); + (*rl_prep_term_function) (_rl_meta_flag); + +#if defined (HANDLE_SIGNALS) + rl_set_signals (); +#endif + + value = readline_internal (); + (*rl_deprep_term_function) (); + +#if defined (HANDLE_SIGNALS) + rl_clear_signals (); +#endif + + return (value); +} + +#if defined (READLINE_CALLBACKS) +# define STATIC_CALLBACK +#else +# define STATIC_CALLBACK static +#endif + +STATIC_CALLBACK void +readline_internal_setup () +{ + char *nprompt; + + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; + + if (rl_startup_hook) + (*rl_startup_hook) (); + + /* If we're not echoing, we still want to at least print a prompt, because + rl_redisplay will not do it for us. If the calling application has a + custom redisplay function, though, let that function handle it. */ + if (readline_echoing_p == 0 && rl_redisplay_function == rl_redisplay) + { + if (rl_prompt && rl_already_prompted == 0) + { + nprompt = _rl_strip_prompt (rl_prompt); + fprintf (_rl_out_stream, "%s", nprompt); + fflush (_rl_out_stream); + free (nprompt); + } + } + else + { + if (rl_prompt && rl_already_prompted) + rl_on_new_line_with_prompt (); + else + rl_on_new_line (); + (*rl_redisplay_function) (); + } + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + rl_vi_insertion_mode (1, 0); +#endif /* VI_MODE */ + + if (rl_pre_input_hook) + (*rl_pre_input_hook) (); +} + +STATIC_CALLBACK char * +readline_internal_teardown (eof) + int eof; +{ + char *temp; + HIST_ENTRY *entry; + + /* Restore the original of this history line, iff the line that we + are editing was originally in the history, AND the line has changed. */ + entry = current_history (); + + if (entry && rl_undo_list) + { + temp = savestring (the_line); + rl_revert_line (1, 0); + entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL); + _rl_free_history_entry (entry); + + strcpy (the_line, temp); + free (temp); + } + + /* At any rate, it is highly likely that this line has an undo list. Get + rid of it now. */ + if (rl_undo_list) + rl_free_undo_list (); + + /* Restore normal cursor, if available. */ + _rl_set_insert_mode (RL_IM_INSERT, 0); + + return (eof ? (char *)NULL : savestring (the_line)); +} + +STATIC_CALLBACK int +#if defined (READLINE_CALLBACKS) +readline_internal_char () +#else +readline_internal_charloop () +#endif +{ + static int lastc, eof_found; + int c, code, lk; + + lastc = -1; + eof_found = 0; + +#if !defined (READLINE_CALLBACKS) + while (rl_done == 0) + { +#endif + lk = _rl_last_command_was_kill; + + code = setjmp (readline_top_level); + + if (code) + (*rl_redisplay_function) (); + + if (rl_pending_input == 0) + { + /* Then initialize the argument and number of keys read. */ + _rl_init_argument (); + rl_key_sequence_length = 0; + } + + RL_SETSTATE(RL_STATE_READCMD); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_READCMD); + + /* EOF typed to a non-blank line is a <NL>. */ + if (c == EOF && rl_end) + c = NEWLINE; + + /* The character _rl_eof_char typed to blank line, and not as the + previous character is interpreted as EOF. */ + if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end) + { +#if defined (READLINE_CALLBACKS) + RL_SETSTATE(RL_STATE_DONE); + return (rl_done = 1); +#else + eof_found = 1; + break; +#endif + } + + lastc = c; + _rl_dispatch ((unsigned char)c, _rl_keymap); + + /* If there was no change in _rl_last_command_was_kill, then no kill + has taken place. Note that if input is pending we are reading + a prefix command, so nothing has changed yet. */ + if (rl_pending_input == 0 && lk == _rl_last_command_was_kill) + _rl_last_command_was_kill = 0; + +#if defined (VI_MODE) + /* In vi mode, when you exit insert mode, the cursor moves back + over the previous character. We explicitly check for that here. */ + if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap) + rl_vi_check (); +#endif /* VI_MODE */ + + if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read) + { + (*rl_redisplay_function) (); + rl_newline (1, '\n'); + } + + if (rl_done == 0) + (*rl_redisplay_function) (); + + /* If the application writer has told us to erase the entire line if + the only character typed was something bound to rl_newline, do so. */ + if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline && + rl_point == 0 && rl_end == 0) + _rl_erase_entire_line (); + +#if defined (READLINE_CALLBACKS) + return 0; +#else + } + + return (eof_found); +#endif +} + +#if defined (READLINE_CALLBACKS) +static int +readline_internal_charloop () +{ + int eof = 1; + + while (rl_done == 0) + eof = readline_internal_char (); + return (eof); +} +#endif /* READLINE_CALLBACKS */ + +/* Read a line of input from the global rl_instream, doing output on + the global rl_outstream. + If rl_prompt is non-null, then that is our prompt. */ +static char * +readline_internal () +{ + int eof; + + readline_internal_setup (); + eof = readline_internal_charloop (); + return (readline_internal_teardown (eof)); +} + +void +_rl_init_line_state () +{ + rl_point = rl_end = rl_mark = 0; + the_line = rl_line_buffer; + the_line[0] = 0; +} + +void +_rl_set_the_line () +{ + the_line = rl_line_buffer; +} + +/* Do the command associated with KEY in MAP. + If the associated command is really a keymap, then read + another key, and dispatch into that map. */ +int +_rl_dispatch (key, map) + register int key; + Keymap map; +{ + return _rl_dispatch_subseq (key, map, 0); +} + +int +_rl_dispatch_subseq (key, map, got_subseq) + register int key; + Keymap map; + int got_subseq; +{ + int r, newkey; + char *macro; + rl_command_func_t *func; + + if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) + { + if (map[ESC].type == ISKMAP) + { + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (ESC); + map = FUNCTION_TO_KEYMAP (map, ESC); + key = UNMETA (key); + rl_key_sequence_length += 2; + return (_rl_dispatch (key, map)); + } + else + rl_ding (); + return 0; + } + + if (RL_ISSTATE (RL_STATE_MACRODEF)) + _rl_add_macro_char (key); + + r = 0; + switch (map[key].type) + { + case ISFUNC: + func = map[key].function; + if (func) + { + /* Special case rl_do_lowercase_version (). */ + if (func == rl_do_lowercase_version) + return (_rl_dispatch (_rl_to_lower (key), map)); + + rl_executing_keymap = map; + +#if 0 + _rl_suppress_redisplay = (map[key].function == rl_insert) && _rl_input_available (); +#endif + + rl_dispatching = 1; + RL_SETSTATE(RL_STATE_DISPATCHING); + r = (*map[key].function)(rl_numeric_arg * rl_arg_sign, key); + RL_UNSETSTATE(RL_STATE_DISPATCHING); + rl_dispatching = 0; + + /* If we have input pending, then the last command was a prefix + command. Don't change the state of rl_last_func. Otherwise, + remember the last command executed in this variable. */ + if (rl_pending_input == 0 && map[key].function != rl_digit_argument) + rl_last_func = map[key].function; + } + else if (map[ANYOTHERKEY].function) + { + /* OK, there's no function bound in this map, but there is a + shadow function that was overridden when the current keymap + was created. Return -2 to note that. */ + _rl_unget_char (key); + return -2; + } + else if (got_subseq) + { + /* Return -1 to note that we're in a subsequence, but we don't + have a matching key, nor was one overridden. This means + we need to back up the recursion chain and find the last + subsequence that is bound to a function. */ + _rl_unget_char (key); + return -1; + } + else + { + _rl_abort_internal (); + return -1; + } + break; + + case ISKMAP: + if (map[key].function != 0) + { +#if defined (VI_MODE) + /* The only way this test will be true is if a subsequence has been + bound starting with ESC, generally the arrow keys. What we do is + check whether there's input in the queue, which there generally + will be if an arrow key has been pressed, and, if there's not, + just dispatch to (what we assume is) rl_vi_movement_mode right + away. This is essentially an input test with a zero timeout. */ + if (rl_editing_mode == vi_mode && key == ESC && map == vi_insertion_keymap + && _rl_input_queued (0) == 0) + return (_rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key))); +#endif + + rl_key_sequence_length++; + + if (key == ESC) + RL_SETSTATE(RL_STATE_METANEXT); + RL_SETSTATE(RL_STATE_MOREINPUT); + newkey = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + if (key == ESC) + RL_UNSETSTATE(RL_STATE_METANEXT); + + if (newkey < 0) + { + _rl_abort_internal (); + return -1; + } + + r = _rl_dispatch_subseq (newkey, FUNCTION_TO_KEYMAP (map, key), got_subseq || map[ANYOTHERKEY].function); + + if (r == -2) + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ + r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); + else if (r && map[ANYOTHERKEY].function) + { + /* We didn't match (r is probably -1), so return something to + tell the caller that it should try ANYOTHERKEY for an + overridden function. */ + _rl_unget_char (key); + return -2; + } + else if (r && got_subseq) + { + /* OK, back up the chain. */ + _rl_unget_char (key); + return -1; + } + } + else + { + _rl_abort_internal (); + return -1; + } + break; + + case ISMACR: + if (map[key].function != 0) + { + macro = savestring ((char *)map[key].function); + _rl_with_macro_input (macro); + return 0; + } + break; + } +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap && + _rl_vi_textmod_command (key)) + _rl_vi_set_last (key, rl_numeric_arg, rl_arg_sign); +#endif + return (r); +} + +/* **************************************************************** */ +/* */ +/* Initializations */ +/* */ +/* **************************************************************** */ + +/* Initialize readline (and terminal if not already). */ +int +rl_initialize () +{ + /* If we have never been called before, initialize the + terminal and data structures. */ + if (!rl_initialized) + { + RL_SETSTATE(RL_STATE_INITIALIZING); + readline_initialize_everything (); + RL_UNSETSTATE(RL_STATE_INITIALIZING); + rl_initialized++; + RL_SETSTATE(RL_STATE_INITIALIZED); + } + + /* Initalize the current line information. */ + _rl_init_line_state (); + + /* We aren't done yet. We haven't even gotten started yet! */ + rl_done = 0; + RL_UNSETSTATE(RL_STATE_DONE); + + /* Tell the history routines what is going on. */ + _rl_start_using_history (); + + /* Make the display buffer match the state of the line. */ + rl_reset_line_state (); + + /* No such function typed yet. */ + rl_last_func = (rl_command_func_t *)NULL; + + /* Parsing of key-bindings begins in an enabled state. */ + _rl_parsing_conditionalized_out = 0; + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + _rl_vi_initialize_line (); +#endif + + /* Each line starts in insert mode (the default). */ + _rl_set_insert_mode (RL_IM_DEFAULT, 1); + + return 0; +} + +#if 0 +#if defined (__EMX__) +static void +_emx_build_environ () +{ + TIB *tibp; + PIB *pibp; + char *t, **tp; + int c; + + DosGetInfoBlocks (&tibp, &pibp); + t = pibp->pib_pchenv; + for (c = 1; *t; c++) + t += strlen (t) + 1; + tp = environ = (char **)xmalloc ((c + 1) * sizeof (char *)); + t = pibp->pib_pchenv; + while (*t) + { + *tp++ = t; + t += strlen (t) + 1; + } + *tp = 0; +} +#endif /* __EMX__ */ +#endif + +/* Initialize the entire state of the world. */ +static void +readline_initialize_everything () +{ +#if 0 +#if defined (__EMX__) + if (environ == 0) + _emx_build_environ (); +#endif +#endif + +#if 0 + /* Find out if we are running in Emacs -- UNUSED. */ + running_in_emacs = sh_get_env_value ("EMACS") != (char *)0; +#endif + + /* Set up input and output if they are not already set up. */ + if (!rl_instream) + rl_instream = stdin; + + if (!rl_outstream) + rl_outstream = stdout; + + /* Bind _rl_in_stream and _rl_out_stream immediately. These values + may change, but they may also be used before readline_internal () + is called. */ + _rl_in_stream = rl_instream; + _rl_out_stream = rl_outstream; + + /* Allocate data structures. */ + if (rl_line_buffer == 0) + rl_line_buffer = (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE); + + /* Initialize the terminal interface. */ + if (rl_terminal_name == 0) + rl_terminal_name = sh_get_env_value ("TERM"); + _rl_init_terminal_io (rl_terminal_name); + + /* Bind tty characters to readline functions. */ + readline_default_bindings (); + + /* Initialize the function names. */ + rl_initialize_funmap (); + + /* Decide whether we should automatically go into eight-bit mode. */ + _rl_init_eightbit (); + + /* Read in the init file. */ + rl_read_init_file ((char *)NULL); + + /* XXX */ + if (_rl_horizontal_scroll_mode && _rl_term_autowrap) + { + _rl_screenwidth--; + _rl_screenchars -= _rl_screenheight; + } + + /* Override the effect of any `set keymap' assignments in the + inputrc file. */ + rl_set_keymap_from_edit_mode (); + + /* Try to bind a common arrow key prefix, if not already bound. */ + bind_arrow_keys (); + + /* Enable the meta key, if this terminal has one. */ + if (_rl_enable_meta) + _rl_enable_meta_key (); + + /* If the completion parser's default word break characters haven't + been set yet, then do so now. */ + if (rl_completer_word_break_characters == (char *)NULL) + rl_completer_word_break_characters = rl_basic_word_break_characters; +} + +/* If this system allows us to look at the values of the regular + input editing characters, then bind them to their readline + equivalents, iff the characters are not bound to keymaps. */ +static void +readline_default_bindings () +{ + rl_tty_set_default_bindings (_rl_keymap); +} + +/* Bind some common arrow key sequences in MAP. */ +static void +bind_arrow_keys_internal (map) + Keymap map; +{ + Keymap xkeymap; + + xkeymap = _rl_keymap; + _rl_keymap = map; + +#if defined (__MSDOS__) + _rl_bind_if_unbound ("\033[0A", rl_get_previous_history); + _rl_bind_if_unbound ("\033[0B", rl_backward_char); + _rl_bind_if_unbound ("\033[0C", rl_forward_char); + _rl_bind_if_unbound ("\033[0D", rl_get_next_history); +#endif + + _rl_bind_if_unbound ("\033[A", rl_get_previous_history); + _rl_bind_if_unbound ("\033[B", rl_get_next_history); + _rl_bind_if_unbound ("\033[C", rl_forward_char); + _rl_bind_if_unbound ("\033[D", rl_backward_char); + _rl_bind_if_unbound ("\033[H", rl_beg_of_line); + _rl_bind_if_unbound ("\033[F", rl_end_of_line); + + _rl_bind_if_unbound ("\033OA", rl_get_previous_history); + _rl_bind_if_unbound ("\033OB", rl_get_next_history); + _rl_bind_if_unbound ("\033OC", rl_forward_char); + _rl_bind_if_unbound ("\033OD", rl_backward_char); + _rl_bind_if_unbound ("\033OH", rl_beg_of_line); + _rl_bind_if_unbound ("\033OF", rl_end_of_line); + + _rl_keymap = xkeymap; +} + +/* Try and bind the common arrow key prefixes after giving termcap and + the inputrc file a chance to bind them and create `real' keymaps + for the arrow key prefix. */ +static void +bind_arrow_keys () +{ + bind_arrow_keys_internal (emacs_standard_keymap); + +#if defined (VI_MODE) + bind_arrow_keys_internal (vi_movement_keymap); + bind_arrow_keys_internal (vi_insertion_keymap); +#endif +} + +/* **************************************************************** */ +/* */ +/* Saving and Restoring Readline's state */ +/* */ +/* **************************************************************** */ + +int +rl_save_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + sp->point = rl_point; + sp->end = rl_end; + sp->mark = rl_mark; + sp->buffer = rl_line_buffer; + sp->buflen = rl_line_buffer_len; + sp->ul = rl_undo_list; + sp->prompt = rl_prompt; + + sp->rlstate = rl_readline_state; + sp->done = rl_done; + sp->kmap = _rl_keymap; + + sp->lastfunc = rl_last_func; + sp->insmode = rl_insert_mode; + sp->edmode = rl_editing_mode; + sp->kseqlen = rl_key_sequence_length; + sp->inf = rl_instream; + sp->outf = rl_outstream; + sp->pendingin = rl_pending_input; + sp->macro = rl_executing_macro; + + sp->catchsigs = rl_catch_signals; + sp->catchsigwinch = rl_catch_sigwinch; + + return (0); +} + +int +rl_restore_state (sp) + struct readline_state *sp; +{ + if (sp == 0) + return -1; + + rl_point = sp->point; + rl_end = sp->end; + rl_mark = sp->mark; + the_line = rl_line_buffer = sp->buffer; + rl_line_buffer_len = sp->buflen; + rl_undo_list = sp->ul; + rl_prompt = sp->prompt; + + rl_readline_state = sp->rlstate; + rl_done = sp->done; + _rl_keymap = sp->kmap; + + rl_last_func = sp->lastfunc; + rl_insert_mode = sp->insmode; + rl_editing_mode = sp->edmode; + rl_key_sequence_length = sp->kseqlen; + rl_instream = sp->inf; + rl_outstream = sp->outf; + rl_pending_input = sp->pendingin; + rl_executing_macro = sp->macro; + + rl_catch_signals = sp->catchsigs; + rl_catch_sigwinch = sp->catchsigwinch; + + return (0); +} diff --git a/cmd-line-utils/readline/readline.h b/cmd-line-utils/readline/readline.h new file mode 100644 index 00000000000..9425de50aef --- /dev/null +++ b/cmd-line-utils/readline/readline.h @@ -0,0 +1,799 @@ +/* Readline.h -- the names of functions callable from within readline. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_READLINE_H_) +#define _READLINE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (READLINE_LIBRARY) +# include "rlstdc.h" +# include "rltypedefs.h" +# include "keymaps.h" +# include "tilde.h" +#else +# include <readline/rlstdc.h> +# include <readline/rltypedefs.h> +# include <readline/keymaps.h> +# include <readline/tilde.h> +#endif + +/* Hex-encoded Readline version number. */ +#define RL_READLINE_VERSION 0x0403 /* Readline 4.3 */ +#define RL_VERSION_MAJOR 4 +#define RL_VERSION_MINOR 3 + +/* Readline data structures. */ + +/* Maintaining the state of undo. We remember individual deletes and inserts + on a chain of things to do. */ + +/* The actions that undo knows how to undo. Notice that UNDO_DELETE means + to insert some text, and UNDO_INSERT means to delete some text. I.e., + the code tells undo what to undo, not how to undo it. */ +enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; + +/* What an element of THE_UNDO_LIST looks like. */ +typedef struct undo_list { + struct undo_list *next; + int start, end; /* Where the change took place. */ + char *text; /* The text to insert, if undoing a delete. */ + enum undo_code what; /* Delete, Insert, Begin, End. */ +} UNDO_LIST; + +/* The current undo list for RL_LINE_BUFFER. */ +extern UNDO_LIST *rl_undo_list; + +/* The data structure for mapping textual names to code addresses. */ +typedef struct _funmap { + const char *name; + rl_command_func_t *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* **************************************************************** */ +/* */ +/* Functions available to bind to key sequences */ +/* */ +/* **************************************************************** */ + +/* Bindable commands for numeric arguments. */ +extern int rl_digit_argument PARAMS((int, int)); +extern int rl_universal_argument PARAMS((int, int)); + +/* Bindable commands for moving the cursor. */ +extern int rl_forward_byte PARAMS((int, int)); +extern int rl_forward_char PARAMS((int, int)); +extern int rl_forward PARAMS((int, int)); +extern int rl_backward_byte PARAMS((int, int)); +extern int rl_backward_char PARAMS((int, int)); +extern int rl_backward PARAMS((int, int)); +extern int rl_beg_of_line PARAMS((int, int)); +extern int rl_end_of_line PARAMS((int, int)); +extern int rl_forward_word PARAMS((int, int)); +extern int rl_backward_word PARAMS((int, int)); +extern int rl_refresh_line PARAMS((int, int)); +extern int rl_clear_screen PARAMS((int, int)); +extern int rl_arrow_keys PARAMS((int, int)); + +/* Bindable commands for inserting and deleting text. */ +extern int rl_insert PARAMS((int, int)); +extern int rl_quoted_insert PARAMS((int, int)); +extern int rl_tab_insert PARAMS((int, int)); +extern int rl_newline PARAMS((int, int)); +extern int rl_do_lowercase_version PARAMS((int, int)); +extern int rl_rubout PARAMS((int, int)); +extern int rl_delete PARAMS((int, int)); +extern int rl_rubout_or_delete PARAMS((int, int)); +extern int rl_delete_horizontal_space PARAMS((int, int)); +extern int rl_delete_or_show_completions PARAMS((int, int)); +extern int rl_insert_comment PARAMS((int, int)); + +/* Bindable commands for changing case. */ +extern int rl_upcase_word PARAMS((int, int)); +extern int rl_downcase_word PARAMS((int, int)); +extern int rl_capitalize_word PARAMS((int, int)); + +/* Bindable commands for transposing characters and words. */ +extern int rl_transpose_words PARAMS((int, int)); +extern int rl_transpose_chars PARAMS((int, int)); + +/* Bindable commands for searching within a line. */ +extern int rl_char_search PARAMS((int, int)); +extern int rl_backward_char_search PARAMS((int, int)); + +/* Bindable commands for readline's interface to the command history. */ +extern int rl_beginning_of_history PARAMS((int, int)); +extern int rl_end_of_history PARAMS((int, int)); +extern int rl_get_next_history PARAMS((int, int)); +extern int rl_get_previous_history PARAMS((int, int)); + +/* Bindable commands for managing the mark and region. */ +extern int rl_set_mark PARAMS((int, int)); +extern int rl_exchange_point_and_mark PARAMS((int, int)); + +/* Bindable commands to set the editing mode (emacs or vi). */ +extern int rl_vi_editing_mode PARAMS((int, int)); +extern int rl_emacs_editing_mode PARAMS((int, int)); + +/* Bindable commands to change the insert mode (insert or overwrite) */ +extern int rl_overwrite_mode PARAMS((int, int)); + +/* Bindable commands for managing key bindings. */ +extern int rl_re_read_init_file PARAMS((int, int)); +extern int rl_dump_functions PARAMS((int, int)); +extern int rl_dump_macros PARAMS((int, int)); +extern int rl_dump_variables PARAMS((int, int)); + +/* Bindable commands for word completion. */ +extern int rl_complete PARAMS((int, int)); +extern int rl_possible_completions PARAMS((int, int)); +extern int rl_insert_completions PARAMS((int, int)); +extern int rl_menu_complete PARAMS((int, int)); + +/* Bindable commands for killing and yanking text, and managing the kill ring. */ +extern int rl_kill_word PARAMS((int, int)); +extern int rl_backward_kill_word PARAMS((int, int)); +extern int rl_kill_line PARAMS((int, int)); +extern int rl_backward_kill_line PARAMS((int, int)); +extern int rl_kill_full_line PARAMS((int, int)); +extern int rl_unix_word_rubout PARAMS((int, int)); +extern int rl_unix_line_discard PARAMS((int, int)); +extern int rl_copy_region_to_kill PARAMS((int, int)); +extern int rl_kill_region PARAMS((int, int)); +extern int rl_copy_forward_word PARAMS((int, int)); +extern int rl_copy_backward_word PARAMS((int, int)); +extern int rl_yank PARAMS((int, int)); +extern int rl_yank_pop PARAMS((int, int)); +extern int rl_yank_nth_arg PARAMS((int, int)); +extern int rl_yank_last_arg PARAMS((int, int)); +/* Not available unless __CYGWIN__ is defined. */ +#ifdef __CYGWIN__ +extern int rl_paste_from_clipboard PARAMS((int, int)); +#endif + +/* Bindable commands for incremental searching. */ +extern int rl_reverse_search_history PARAMS((int, int)); +extern int rl_forward_search_history PARAMS((int, int)); + +/* Bindable keyboard macro commands. */ +extern int rl_start_kbd_macro PARAMS((int, int)); +extern int rl_end_kbd_macro PARAMS((int, int)); +extern int rl_call_last_kbd_macro PARAMS((int, int)); + +/* Bindable undo commands. */ +extern int rl_revert_line PARAMS((int, int)); +extern int rl_undo_command PARAMS((int, int)); + +/* Bindable tilde expansion commands. */ +extern int rl_tilde_expand PARAMS((int, int)); + +/* Bindable terminal control commands. */ +extern int rl_restart_output PARAMS((int, int)); +extern int rl_stop_output PARAMS((int, int)); + +/* Miscellaneous bindable commands. */ +extern int rl_abort PARAMS((int, int)); +extern int rl_tty_status PARAMS((int, int)); + +/* Bindable commands for incremental and non-incremental history searching. */ +extern int rl_history_search_forward PARAMS((int, int)); +extern int rl_history_search_backward PARAMS((int, int)); +extern int rl_noninc_forward_search PARAMS((int, int)); +extern int rl_noninc_reverse_search PARAMS((int, int)); +extern int rl_noninc_forward_search_again PARAMS((int, int)); +extern int rl_noninc_reverse_search_again PARAMS((int, int)); + +/* Bindable command used when inserting a matching close character. */ +extern int rl_insert_close PARAMS((int, int)); + +/* Not available unless READLINE_CALLBACKS is defined. */ +extern void rl_callback_handler_install PARAMS((const char *, rl_vcpfunc_t *)); +extern void rl_callback_read_char PARAMS((void)); +extern void rl_callback_handler_remove PARAMS((void)); + +/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */ +/* VI-mode bindable commands. */ +extern int rl_vi_redo PARAMS((int, int)); +extern int rl_vi_undo PARAMS((int, int)); +extern int rl_vi_yank_arg PARAMS((int, int)); +extern int rl_vi_fetch_history PARAMS((int, int)); +extern int rl_vi_search_again PARAMS((int, int)); +extern int rl_vi_search PARAMS((int, int)); +extern int rl_vi_complete PARAMS((int, int)); +extern int rl_vi_tilde_expand PARAMS((int, int)); +extern int rl_vi_prev_word PARAMS((int, int)); +extern int rl_vi_next_word PARAMS((int, int)); +extern int rl_vi_end_word PARAMS((int, int)); +extern int rl_vi_insert_beg PARAMS((int, int)); +extern int rl_vi_append_mode PARAMS((int, int)); +extern int rl_vi_append_eol PARAMS((int, int)); +extern int rl_vi_eof_maybe PARAMS((int, int)); +extern int rl_vi_insertion_mode PARAMS((int, int)); +extern int rl_vi_movement_mode PARAMS((int, int)); +extern int rl_vi_arg_digit PARAMS((int, int)); +extern int rl_vi_change_case PARAMS((int, int)); +extern int rl_vi_put PARAMS((int, int)); +extern int rl_vi_column PARAMS((int, int)); +extern int rl_vi_delete_to PARAMS((int, int)); +extern int rl_vi_change_to PARAMS((int, int)); +extern int rl_vi_yank_to PARAMS((int, int)); +extern int rl_vi_delete PARAMS((int, int)); +extern int rl_vi_back_to_indent PARAMS((int, int)); +extern int rl_vi_first_print PARAMS((int, int)); +extern int rl_vi_char_search PARAMS((int, int)); +extern int rl_vi_match PARAMS((int, int)); +extern int rl_vi_change_char PARAMS((int, int)); +extern int rl_vi_subst PARAMS((int, int)); +extern int rl_vi_overstrike PARAMS((int, int)); +extern int rl_vi_overstrike_delete PARAMS((int, int)); +extern int rl_vi_replace PARAMS((int, int)); +extern int rl_vi_set_mark PARAMS((int, int)); +extern int rl_vi_goto_mark PARAMS((int, int)); + +/* VI-mode utility functions. */ +extern int rl_vi_check PARAMS((void)); +extern int rl_vi_domove PARAMS((int, int *)); +extern int rl_vi_bracktype PARAMS((int)); + +/* VI-mode pseudo-bindable commands, used as utility functions. */ +extern int rl_vi_fWord PARAMS((int, int)); +extern int rl_vi_bWord PARAMS((int, int)); +extern int rl_vi_eWord PARAMS((int, int)); +extern int rl_vi_fword PARAMS((int, int)); +extern int rl_vi_bword PARAMS((int, int)); +extern int rl_vi_eword PARAMS((int, int)); + +/* **************************************************************** */ +/* */ +/* Well Published Functions */ +/* */ +/* **************************************************************** */ + +/* Readline functions. */ +/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ +extern char *readline PARAMS((const char *)); + +extern int rl_set_prompt PARAMS((const char *)); +extern int rl_expand_prompt PARAMS((char *)); + +extern int rl_initialize PARAMS((void)); + +/* Undocumented; unused by readline */ +extern int rl_discard_argument PARAMS((void)); + +/* Utility functions to bind keys to readline commands. */ +extern int rl_add_defun PARAMS((const char *, rl_command_func_t *, int)); +extern int rl_bind_key PARAMS((int, rl_command_func_t *)); +extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap)); +extern int rl_unbind_key PARAMS((int)); +extern int rl_unbind_key_in_map PARAMS((int, Keymap)); +extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap)); +extern int rl_unbind_command_in_map PARAMS((const char *, Keymap)); +extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap)); +extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap)); +extern int rl_variable_bind PARAMS((const char *, const char *)); + +/* Backwards compatibility, use rl_generic_bind instead. */ +extern int rl_macro_bind PARAMS((const char *, const char *, Keymap)); + +/* Undocumented in the texinfo manual; not really useful to programs. */ +extern int rl_translate_keyseq PARAMS((const char *, char *, int *)); +extern char *rl_untranslate_keyseq PARAMS((int)); + +extern rl_command_func_t *rl_named_function PARAMS((const char *)); +extern rl_command_func_t *rl_function_of_keyseq PARAMS((const char *, Keymap, int *)); + +extern void rl_list_funmap_names PARAMS((void)); +extern char **rl_invoking_keyseqs_in_map PARAMS((rl_command_func_t *, Keymap)); +extern char **rl_invoking_keyseqs PARAMS((rl_command_func_t *)); + +extern void rl_function_dumper PARAMS((int)); +extern void rl_macro_dumper PARAMS((int)); +extern void rl_variable_dumper PARAMS((int)); + +extern int rl_read_init_file PARAMS((const char *)); +extern int rl_parse_and_bind PARAMS((char *)); + +/* Functions for manipulating keymaps. */ +extern Keymap rl_make_bare_keymap PARAMS((void)); +extern Keymap rl_copy_keymap PARAMS((Keymap)); +extern Keymap rl_make_keymap PARAMS((void)); +extern void rl_discard_keymap PARAMS((Keymap)); + +extern Keymap rl_get_keymap_by_name PARAMS((const char *)); +extern char *rl_get_keymap_name PARAMS((Keymap)); +extern void rl_set_keymap PARAMS((Keymap)); +extern Keymap rl_get_keymap PARAMS((void)); +/* Undocumented; used internally only. */ +extern void rl_set_keymap_from_edit_mode PARAMS((void)); +extern const char *rl_get_keymap_name_from_edit_mode PARAMS((void)); + +/* Functions for manipulating the funmap, which maps command names to functions. */ +extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *)); +extern const char **rl_funmap_names PARAMS((void)); +/* Undocumented, only used internally -- there is only one funmap, and this + function may be called only once. */ +extern void rl_initialize_funmap PARAMS((void)); + +/* Utility functions for managing keyboard macros. */ +extern void rl_push_macro_input PARAMS((char *)); + +/* Functions for undoing, from undo.c */ +extern void rl_add_undo PARAMS((enum undo_code, int, int, char *)); +extern void rl_free_undo_list PARAMS((void)); +extern int rl_do_undo PARAMS((void)); +extern int rl_begin_undo_group PARAMS((void)); +extern int rl_end_undo_group PARAMS((void)); +extern int rl_modifying PARAMS((int, int)); + +/* Functions for redisplay. */ +extern void rl_redisplay PARAMS((void)); +extern int rl_on_new_line PARAMS((void)); +extern int rl_on_new_line_with_prompt PARAMS((void)); +extern int rl_forced_update_display PARAMS((void)); +extern int rl_clear_message PARAMS((void)); +extern int rl_reset_line_state PARAMS((void)); +extern int rl_crlf PARAMS((void)); + +#if (defined (__STDC__) || defined (__cplusplus)) && defined (USE_VARARGS) && defined (PREFER_STDARG) +extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); +#else +extern int rl_message (); +#endif + +extern int rl_show_char PARAMS((int)); + +/* Undocumented in texinfo manual. */ +extern int rl_character_len PARAMS((int, int)); + +/* Save and restore internal prompt redisplay information. */ +extern void rl_save_prompt PARAMS((void)); +extern void rl_restore_prompt PARAMS((void)); + +/* Modifying text. */ +extern void rl_replace_line PARAMS((const char *, int)); +extern int rl_insert_text PARAMS((const char *)); +extern int rl_delete_text PARAMS((int, int)); +extern int rl_kill_text PARAMS((int, int)); +extern char *rl_copy_text PARAMS((int, int)); + +/* Terminal and tty mode management. */ +extern void rl_prep_terminal PARAMS((int)); +extern void rl_deprep_terminal PARAMS((void)); +extern void rl_tty_set_default_bindings PARAMS((Keymap)); + +extern int rl_reset_terminal PARAMS((const char *)); +extern void rl_resize_terminal PARAMS((void)); +extern void rl_set_screen_size PARAMS((int, int)); +extern void rl_get_screen_size PARAMS((int *, int *)); + +extern const char *rl_get_termcap PARAMS((const char *)); + +/* Functions for character input. */ +extern int rl_stuff_char PARAMS((int)); +extern int rl_execute_next PARAMS((int)); +extern int rl_clear_pending_input PARAMS((void)); +extern int rl_read_key PARAMS((void)); +extern int rl_getc PARAMS((FILE *)); +extern int rl_set_keyboard_input_timeout PARAMS((int)); + +/* `Public' utility functions . */ +extern void rl_extend_line_buffer PARAMS((int)); +extern int rl_ding PARAMS((void)); +extern int rl_alphabetic PARAMS((int)); + +/* Readline signal handling, from signals.c */ +extern int rl_set_signals PARAMS((void)); +extern int rl_clear_signals PARAMS((void)); +extern void rl_cleanup_after_signal PARAMS((void)); +extern void rl_reset_after_signal PARAMS((void)); +extern void rl_free_line_state PARAMS((void)); + +extern int rl_set_paren_blink_timeout PARAMS((int)); + +/* Undocumented. */ +extern int rl_maybe_save_line PARAMS((void)); +extern int rl_maybe_unsave_line PARAMS((void)); +extern int rl_maybe_replace_line PARAMS((void)); + +/* Completion functions. */ +extern int rl_complete_internal PARAMS((int)); +extern void rl_display_match_list PARAMS((char **, int, int)); + +extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *)); +extern char *rl_username_completion_function PARAMS((const char *, int)); +extern char *rl_filename_completion_function PARAMS((const char *, int)); + +extern int rl_completion_mode PARAMS((rl_command_func_t *)); + +#if 0 +/* Backwards compatibility (compat.c). These will go away sometime. */ +extern void free_undo_list PARAMS((void)); +extern int maybe_save_line PARAMS((void)); +extern int maybe_unsave_line PARAMS((void)); +extern int maybe_replace_line PARAMS((void)); + +extern int ding PARAMS((void)); +extern int alphabetic PARAMS((int)); +extern int crlf PARAMS((void)); + +extern char **completion_matches PARAMS((char *, rl_compentry_func_t *)); +extern char *username_completion_function PARAMS((const char *, int)); +extern char *filename_completion_function PARAMS((const char *, int)); +#endif + +/* **************************************************************** */ +/* */ +/* Well Published Variables */ +/* */ +/* **************************************************************** */ + +/* The version of this incarnation of the readline library. */ +extern const char *rl_library_version; /* e.g., "4.2" */ +extern int rl_readline_version; /* e.g., 0x0402 */ + +/* True if this is real GNU readline. */ +extern int rl_gnu_readline_p; + +/* Flags word encapsulating the current readline state. */ +extern int rl_readline_state; + +/* Says which editing mode readline is currently using. 1 means emacs mode; + 0 means vi mode. */ +extern int rl_editing_mode; + +/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means + overwrite mode. Reset to insert mode on each input line. */ +extern int rl_insert_mode; + +/* The name of the calling program. You should initialize this to + whatever was in argv[0]. It is used when parsing conditionals. */ +extern const char *rl_readline_name; + +/* The prompt readline uses. This is set from the argument to + readline (), and should not be assigned to directly. */ +extern char *rl_prompt; + +/* The line buffer that is in use. */ +extern char *rl_line_buffer; + +/* The location of point, and end. */ +extern int rl_point; +extern int rl_end; + +/* The mark, or saved cursor position. */ +extern int rl_mark; + +/* Flag to indicate that readline has finished with the current input + line and should return it. */ +extern int rl_done; + +/* If set to a character value, that will be the next keystroke read. */ +extern int rl_pending_input; + +/* Non-zero if we called this function from _rl_dispatch(). It's present + so functions can find out whether they were called from a key binding + or directly from an application. */ +extern int rl_dispatching; + +/* Non-zero if the user typed a numeric argument before executing the + current function. */ +extern int rl_explicit_arg; + +/* The current value of the numeric argument specified by the user. */ +extern int rl_numeric_arg; + +/* The address of the last command function Readline executed. */ +extern rl_command_func_t *rl_last_func; + +/* The name of the terminal to use. */ +extern const char *rl_terminal_name; + +/* The input and output streams. */ +extern FILE *rl_instream; +extern FILE *rl_outstream; + +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +extern rl_hook_func_t *rl_startup_hook; + +/* If non-zero, this is the address of a function to call just before + readline_internal_setup () returns and readline_internal starts + reading input characters. */ +extern rl_hook_func_t *rl_pre_input_hook; + +/* The address of a function to call periodically while Readline is + awaiting character input, or NULL, for no event handling. */ +extern rl_hook_func_t *rl_event_hook; + +/* The address of the function to call to fetch a character from the current + Readline input stream */ +extern rl_getc_func_t *rl_getc_function; + +extern rl_voidfunc_t *rl_redisplay_function; + +extern rl_vintfunc_t *rl_prep_term_function; +extern rl_voidfunc_t *rl_deprep_term_function; + +/* Dispatch variables. */ +extern Keymap rl_executing_keymap; +extern Keymap rl_binding_keymap; + +/* Display variables. */ +/* If non-zero, readline will erase the entire line, including any prompt, + if the only thing typed on an otherwise-blank line is something bound to + rl_newline. */ +extern int rl_erase_empty_line; + +/* If non-zero, the application has already printed the prompt (rl_prompt) + before calling readline, so readline should not output it the first time + redisplay is done. */ +extern int rl_already_prompted; + +/* A non-zero value means to read only this many characters rather than + up to a character bound to accept-line. */ +extern int rl_num_chars_to_read; + +/* The text of a currently-executing keyboard macro. */ +extern char *rl_executing_macro; + +/* Variables to control readline signal handling. */ +/* If non-zero, readline will install its own signal handlers for + SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ +extern int rl_catch_signals; + +/* If non-zero, readline will install a signal handler for SIGWINCH + that also attempts to call any calling application's SIGWINCH signal + handler. Note that the terminal is not cleaned up before the + application's signal handler is called; use rl_cleanup_after_signal() + to do that. */ +extern int rl_catch_sigwinch; + +/* Completion variables. */ +/* Pointer to the generator function for completion_matches (). + NULL means to use rl_filename_completion_function (), the default + filename completer. */ +extern rl_compentry_func_t *rl_completion_entry_function; + +/* If rl_ignore_some_completions_function is non-NULL it is the address + of a function to call after all of the possible matches have been + generated, but before the actual completion is done to the input line. + The function is called with one argument; a NULL terminated array + of (char *). If your function removes any of the elements, they + must be free()'ed. */ +extern rl_compignore_func_t *rl_ignore_some_completions_function; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +extern rl_completion_func_t *rl_attempted_completion_function; + +/* The basic list of characters that signal a break between words for the + completer routine. The initial contents of this variable is what + breaks words in the shell, i.e. "n\"\\'`@$>". */ +extern const char *rl_basic_word_break_characters; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +extern const char *rl_completer_word_break_characters; + +/* List of characters which can be used to quote a substring of the line. + Completion occurs on the entire substring, and within the substring + rl_completer_word_break_characters are treated as any other character, + unless they also appear within this list. */ +extern const char *rl_completer_quote_characters; + +/* List of quote characters which cause a word break. */ +extern const char *rl_basic_quote_characters; + +/* List of characters that need to be quoted in filenames by the completer. */ +extern const char *rl_filename_quote_characters; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +extern const char *rl_special_prefixes; + +/* If non-zero, then this is the address of a function to call when + completing on a directory name. The function is called with + the address of a string (the current directory name) as an arg. It + changes what is displayed when the possible completions are printed + or inserted. */ +extern rl_icppfunc_t *rl_directory_completion_hook; + +/* If non-zero, this is the address of a function to call when completing + a directory name. This function takes the address of the directory name + to be modified as an argument. Unlike rl_directory_completion_hook, it + only modifies the directory name used in opendir(2), not what is displayed + when the possible completions are printed or inserted. It is called + before rl_directory_completion_hook. I'm not happy with how this works + yet, so it's undocumented. */ +extern rl_icppfunc_t *rl_directory_rewrite_hook; + +/* Backwards compatibility with previous versions of readline. */ +#define rl_symbolic_link_hook rl_directory_completion_hook + +/* If non-zero, then this is the address of a function to call when + completing a word would normally display the list of possible matches. + This function is called instead of actually doing the display. + It takes three arguments: (char **matches, int num_matches, int max_length) + where MATCHES is the array of strings that matched, NUM_MATCHES is the + number of strings in that array, and MAX_LENGTH is the length of the + longest string in that array. */ +extern rl_compdisp_func_t *rl_completion_display_matches_hook; + +/* Non-zero means that the results of the matches are to be treated + as filenames. This is ALWAYS zero on entry, and can only be changed + within a completion entry finder function. */ +extern int rl_filename_completion_desired; + +/* Non-zero means that the results of the matches are to be quoted using + double quotes (or an application-specific quoting mechanism) if the + filename contains any characters in rl_word_break_chars. This is + ALWAYS non-zero on entry, and can only be changed within a completion + entry finder function. */ +extern int rl_filename_quoting_desired; + +/* Set to a function to quote a filename in an application-specific fashion. + Called with the text to quote, the type of match found (single or multiple) + and a pointer to the quoting character to be used, which the function can + reset if desired. */ +extern rl_quote_func_t *rl_filename_quoting_function; + +/* Function to call to remove quoting characters from a filename. Called + before completion is attempted, so the embedded quotes do not interfere + with matching names in the file system. */ +extern rl_dequote_func_t *rl_filename_dequoting_function; + +/* Function to call to decide whether or not a word break character is + quoted. If a character is quoted, it does not break words for the + completer. */ +extern rl_linebuf_func_t *rl_char_is_quoted_p; + +/* Non-zero means to suppress normal filename completion after the + user-specified completion function has been called. */ +extern int rl_attempted_completion_over; + +/* Set to a character describing the type of completion being attempted by + rl_complete_internal; available for use by application completion + functions. */ +extern int rl_completion_type; + +/* Character appended to completed words when at the end of the line. The + default is a space. Nothing is added if this is '\0'. */ +extern int rl_completion_append_character; + +/* If set to non-zero by an application completion function, + rl_completion_append_character will not be appended. */ +extern int rl_completion_suppress_append; + +/* Up to this many items will be displayed in response to a + possible-completions call. After that, we ask the user if she + is sure she wants to see them all. The default value is 100. */ +extern int rl_completion_query_items; + +/* If non-zero, a slash will be appended to completed filenames that are + symbolic links to directory names, subject to the value of the + mark-directories variable (which is user-settable). This exists so + that application completion functions can override the user's preference + (set via the mark-symlinked-directories variable) if appropriate. + It's set to the value of _rl_complete_mark_symlink_dirs in + rl_complete_internal before any application-specific completion + function is called, so without that function doing anything, the user's + preferences are honored. */ +extern int rl_completion_mark_symlink_dirs; + +/* If non-zero, then disallow duplicates in the matches. */ +extern int rl_ignore_completion_duplicates; + +/* If this is non-zero, completion is (temporarily) inhibited, and the + completion character will be inserted as any other. */ +extern int rl_inhibit_completion; + +/* Definitions available for use by readline clients. */ +#define RL_PROMPT_START_IGNORE '\001' +#define RL_PROMPT_END_IGNORE '\002' + +/* Possible values for do_replace argument to rl_filename_quoting_function, + called by rl_complete_internal. */ +#define NO_MATCH 0 +#define SINGLE_MATCH 1 +#define MULT_MATCH 2 + +/* Possible state values for rl_readline_state */ +#define RL_STATE_NONE 0x00000 /* no state; before first call */ + +#define RL_STATE_INITIALIZING 0x00001 /* initializing */ +#define RL_STATE_INITIALIZED 0x00002 /* initialization done */ +#define RL_STATE_TERMPREPPED 0x00004 /* terminal is prepped */ +#define RL_STATE_READCMD 0x00008 /* reading a command key */ +#define RL_STATE_METANEXT 0x00010 /* reading input after ESC */ +#define RL_STATE_DISPATCHING 0x00020 /* dispatching to a command */ +#define RL_STATE_MOREINPUT 0x00040 /* reading more input in a command function */ +#define RL_STATE_ISEARCH 0x00080 /* doing incremental search */ +#define RL_STATE_NSEARCH 0x00100 /* doing non-inc search */ +#define RL_STATE_SEARCH 0x00200 /* doing a history search */ +#define RL_STATE_NUMERICARG 0x00400 /* reading numeric argument */ +#define RL_STATE_MACROINPUT 0x00800 /* getting input from a macro */ +#define RL_STATE_MACRODEF 0x01000 /* defining keyboard macro */ +#define RL_STATE_OVERWRITE 0x02000 /* overwrite mode */ +#define RL_STATE_COMPLETING 0x04000 /* doing completion */ +#define RL_STATE_SIGHANDLER 0x08000 /* in readline sighandler */ +#define RL_STATE_UNDOING 0x10000 /* doing an undo */ +#define RL_STATE_INPUTPENDING 0x20000 /* rl_execute_next called */ + +#define RL_STATE_DONE 0x80000 /* done; accepted line */ + +#define RL_SETSTATE(x) (rl_readline_state |= (x)) +#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) +#define RL_ISSTATE(x) (rl_readline_state & (x)) + +struct readline_state { + /* line state */ + int point; + int end; + int mark; + char *buffer; + int buflen; + UNDO_LIST *ul; + char *prompt; + + /* global state */ + int rlstate; + int done; + Keymap kmap; + + /* input state */ + rl_command_func_t *lastfunc; + int insmode; + int edmode; + int kseqlen; + FILE *inf; + FILE *outf; + int pendingin; + char *macro; + + /* signal state */ + int catchsigs; + int catchsigwinch; + + /* reserved for future expansion, so the struct size doesn't change */ + char reserved[64]; +}; + +extern int rl_save_state PARAMS((struct readline_state *)); +extern int rl_restore_state PARAMS((struct readline_state *)); + +#ifdef __cplusplus +} +#endif + +#endif /* _READLINE_H_ */ diff --git a/cmd-line-utils/readline/rlconf.h b/cmd-line-utils/readline/rlconf.h new file mode 100644 index 00000000000..c651fd8b41f --- /dev/null +++ b/cmd-line-utils/readline/rlconf.h @@ -0,0 +1,60 @@ +/* rlconf.h -- readline configuration definitions */ + +/* Copyright (C) 1994 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RLCONF_H_) +#define _RLCONF_H_ + +/* Define this if you want the vi-mode editing available. */ +#define VI_MODE + +/* Define this to get an indication of file type when listing completions. */ +#define VISIBLE_STATS + +/* This definition is needed by readline.c, rltty.c, and signals.c. */ +/* If on, then readline handles signals in a way that doesn't screw. */ +#define HANDLE_SIGNALS + +/* Ugly but working hack for binding prefix meta. */ +#define PREFIX_META_HACK + +/* The final, last-ditch effort file name for an init file. */ +#define DEFAULT_INPUTRC "~/.inputrc" + +/* If defined, expand tabs to spaces. */ +#define DISPLAY_TABS + +/* If defined, use the terminal escape sequence to move the cursor forward + over a character when updating the line rather than rewriting it. */ +/* #define HACK_TERMCAP_MOTION */ + +/* The string inserted by the `insert comment' command. */ +#define RL_COMMENT_BEGIN_DEFAULT "#" + +/* Define this if you want code that allows readline to be used in an + X `callback' style. */ +#define READLINE_CALLBACKS + +/* Define this if you want the cursor to indicate insert or overwrite mode. */ +/* #define CURSOR_MODE */ + +#endif /* _RLCONF_H_ */ diff --git a/cmd-line-utils/readline/rldefs.h b/cmd-line-utils/readline/rldefs.h new file mode 100644 index 00000000000..5cba9a5ac32 --- /dev/null +++ b/cmd-line-utils/readline/rldefs.h @@ -0,0 +1,160 @@ +/* rldefs.h -- an attempt to isolate some of the system-specific defines + for readline. This should be included after any files that define + system-specific constants like _POSIX_VERSION or USG. */ + +/* Copyright (C) 1987,1989 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RLDEFS_H_) +#define _RLDEFS_H_ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include "rlstdc.h" + +#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ <8) +#define __attribute__(A) +#endif + +#if defined (_POSIX_VERSION) && !defined (TERMIOS_MISSING) +# define TERMIOS_TTY_DRIVER +#else +# if defined (HAVE_TERMIO_H) +# define TERMIO_TTY_DRIVER +# else +# define NEW_TTY_DRIVER +# endif +#endif + +/* Posix macro to check file in statbuf for directory-ness. + This requires that <sys/stat.h> be included before this test. */ +#if defined (S_IFDIR) && !defined (S_ISDIR) +# define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#endif + +/* Decide which flavor of the header file describing the C library + string functions to include and include it. */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if !defined (strchr) && !defined (__STDC__) +extern char *strchr (), *strrchr (); +#endif /* !strchr && !__STDC__ */ + +#if defined (PREFER_STDARG) +# include <stdarg.h> +#else +# if defined (PREFER_VARARGS) +# include <varargs.h> +# endif +#endif + +#if defined (HAVE_STRCASECMP) +#define _rl_stricmp strcasecmp +#define _rl_strnicmp strncasecmp +#else +extern int _rl_stricmp PARAMS((char *, char *)); +extern int _rl_strnicmp PARAMS((char *, char *, int)); +#endif + +#if defined (HAVE_STRPBRK) +# define _rl_strpbrk(a,b) strpbrk((a),(b)) +#else +extern char *_rl_strpbrk PARAMS((const char *, const char *)); +#endif + +#if !defined (emacs_mode) +# define no_mode -1 +# define vi_mode 0 +# define emacs_mode 1 +#endif + +#if !defined (RL_IM_INSERT) +# define RL_IM_INSERT 1 +# define RL_IM_OVERWRITE 0 +# +# define RL_IM_DEFAULT RL_IM_INSERT +#endif + +/* If you cast map[key].function to type (Keymap) on a Cray, + the compiler takes the value of map[key].function and + divides it by 4 to convert between pointer types (pointers + to functions and pointers to structs are different sizes). + This is not what is wanted. */ +#if defined (CRAY) +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)((int)map[key].function) +# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)((int)(data)) +#else +# define FUNCTION_TO_KEYMAP(map, key) (Keymap)(map[key].function) +# define KEYMAP_TO_FUNCTION(data) (rl_command_func_t *)(data) +#endif + +#ifndef savestring +#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x)) +#endif + +/* Possible values for _rl_bell_preference. */ +#define NO_BELL 0 +#define AUDIBLE_BELL 1 +#define VISIBLE_BELL 2 + +/* Definitions used when searching the line for characters. */ +/* NOTE: it is necessary that opposite directions are inverses */ +#define FTO 1 /* forward to */ +#define BTO -1 /* backward to */ +#define FFIND 2 /* forward find */ +#define BFIND -2 /* backward find */ + +/* Possible values for the found_quote flags word used by the completion + functions. It says what kind of (shell-like) quoting we found anywhere + in the line. */ +#define RL_QF_SINGLE_QUOTE 0x01 +#define RL_QF_DOUBLE_QUOTE 0x02 +#define RL_QF_BACKSLASH 0x04 +#define RL_QF_OTHER_QUOTE 0x08 + +/* Default readline line buffer length. */ +#define DEFAULT_BUFFER_SIZE 256 + +#if !defined (STREQ) +#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0)) +#define STREQN(a, b, n) (((n) == 0) ? (1) \ + : ((a)[0] == (b)[0]) && (strncmp ((a), (b), (n)) == 0)) +#endif + +#if !defined (FREE) +# define FREE(x) if (x) free (x) +#endif + +#if !defined (SWAP) +# define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0) +#endif + +/* CONFIGURATION SECTION */ +#include "rlconf.h" + +#endif /* !_RLDEFS_H_ */ diff --git a/cmd-line-utils/readline/rlmbutil.h b/cmd-line-utils/readline/rlmbutil.h new file mode 100644 index 00000000000..4660a72fce5 --- /dev/null +++ b/cmd-line-utils/readline/rlmbutil.h @@ -0,0 +1,108 @@ +/* rlmbutil.h -- utility functions for multibyte characters. */ + +/* Copyright (C) 2001 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_MBUTIL_H_) +#define _RL_MBUTIL_H_ + +#include "rlstdc.h" + +/************************************************/ +/* check multibyte capability for I18N code */ +/************************************************/ + +/* For platforms which support the ISO C amendement 1 functionality we + support user defined character classes. */ + /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ +#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H) +# include <wchar.h> +# include <wctype.h> +# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */ +# define HANDLE_MULTIBYTE 1 +# endif +#endif + +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ +#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T) +# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0) +# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0) +# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0) +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +# define mbrlen(s, n, ps) (mbrlen) (s, n, 0) +# define mbstate_t int +#endif + +/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to + handle multibyte chars (some systems define MB_LEN_MAX as 1) */ +#ifdef HANDLE_MULTIBYTE +# include <limits.h> +# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16) +# undef MB_LEN_MAX +# endif +# if !defined (MB_LEN_MAX) +# define MB_LEN_MAX 16 +# endif +#endif + +/************************************************/ +/* end of multibyte capability checks for I18N */ +/************************************************/ + +/* + * Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar: + * + * MB_FIND_ANY find any multibyte character + * MB_FIND_NONZERO find a non-zero-width multibyte character + */ + +#define MB_FIND_ANY 0x00 +#define MB_FIND_NONZERO 0x01 + +extern int _rl_find_prev_mbchar PARAMS((char *, int, int)); +extern int _rl_find_next_mbchar PARAMS((char *, int, int, int)); + +#ifdef HANDLE_MULTIBYTE + +extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *)); +extern int _rl_get_char_len PARAMS((const char *, mbstate_t *)); +extern int _rl_adjust_point PARAMS((const char *, int, mbstate_t *)); + +extern int _rl_read_mbchar PARAMS((char *, int)); +extern int _rl_read_mbstring PARAMS((int, char *, int)); + +extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int)); + +#else /* !HANDLE_MULTIBYTE */ + +#undef MB_LEN_MAX +#undef MB_CUR_MAX + +#define MB_LEN_MAX 1 +#define MB_CUR_MAX 1 + +#define _rl_find_prev_mbchar(b, i, f) (((i) == 0) ? (i) : ((i) - 1)) +#define _rl_find_next_mbchar(b, i1, i2, f) ((i1) + (i2)) + +#endif /* !HANDLE_MULTIBYTE */ + +extern int rl_byte_oriented; + +#endif /* _RL_MBUTIL_H_ */ diff --git a/cmd-line-utils/readline/rlprivate.h b/cmd-line-utils/readline/rlprivate.h new file mode 100644 index 00000000000..36645fb4a65 --- /dev/null +++ b/cmd-line-utils/readline/rlprivate.h @@ -0,0 +1,284 @@ +/* rlprivate.h -- functions and variables global to the readline library, + but not intended for use by applications. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_PRIVATE_H_) +#define _RL_PRIVATE_H_ + +#include "rlconf.h" /* for VISIBLE_STATS */ +#include "rlstdc.h" +#include "posixjmp.h" /* defines procenv_t */ + +/************************************************************************* + * * + * Global functions undocumented in texinfo manual and not in readline.h * + * * + *************************************************************************/ + +/************************************************************************* + * * + * Global variables undocumented in texinfo manual and not in readline.h * + * * + *************************************************************************/ + +/* complete.c */ +extern int rl_complete_with_tilde_expansion; +#if defined (VISIBLE_STATS) +extern int rl_visible_stats; +#endif /* VISIBLE_STATS */ + +/* readline.c */ +extern int rl_line_buffer_len; +extern int rl_arg_sign; +extern int rl_visible_prompt_length; +extern int readline_echoing_p; +extern int rl_key_sequence_length; +extern int rl_byte_oriented; + +/* display.c */ +extern int rl_display_fixed; + +/* parens.c */ +extern int rl_blink_matching_paren; + +/************************************************************************* + * * + * Global functions and variables unsed and undocumented * + * * + *************************************************************************/ + +/* kill.c */ +extern int rl_set_retained_kills PARAMS((int)); + +/* terminal.c */ +extern void _rl_set_screen_size PARAMS((int, int)); + +/* undo.c */ +extern int _rl_fix_last_undo_of_type PARAMS((unsigned int, int, int)); + +/* util.c */ +extern char *_rl_savestring PARAMS((const char *)); + +/************************************************************************* + * * + * Functions and variables private to the readline library * + * * + *************************************************************************/ + +/* NOTE: Functions and variables prefixed with `_rl_' are + pseudo-global: they are global so they can be shared + between files in the readline library, but are not intended + to be visible to readline callers. */ + +/************************************************************************* + * Undocumented private functions * + *************************************************************************/ + +#if defined(READLINE_CALLBACKS) + +/* readline.c */ +extern void readline_internal_setup PARAMS((void)); +extern char *readline_internal_teardown PARAMS((int)); +extern int readline_internal_char PARAMS((void)); + +#endif /* READLINE_CALLBACKS */ + +/* bind.c */ +extern void _rl_bind_if_unbound PARAMS((const char *, rl_command_func_t *)); + +/* complete.c */ +extern char _rl_find_completion_word PARAMS((int *, int *)); +extern void _rl_free_match_list PARAMS((char **)); + +/* display.c */ +extern char *_rl_strip_prompt PARAMS((char *)); +extern void _rl_move_cursor_relative PARAMS((int, const char *)); +extern void _rl_move_vert PARAMS((int)); +extern void _rl_save_prompt PARAMS((void)); +extern void _rl_restore_prompt PARAMS((void)); +extern char *_rl_make_prompt_for_search PARAMS((int)); +extern void _rl_erase_at_end_of_line PARAMS((int)); +extern void _rl_clear_to_eol PARAMS((int)); +extern void _rl_clear_screen PARAMS((void)); +extern void _rl_update_final PARAMS((void)); +extern void _rl_redisplay_after_sigwinch PARAMS((void)); +extern void _rl_clean_up_for_exit PARAMS((void)); +extern void _rl_erase_entire_line PARAMS((void)); +extern int _rl_current_display_line PARAMS((void)); + +/* input.c */ +extern int _rl_any_typein PARAMS((void)); +extern int _rl_input_available PARAMS((void)); +extern int _rl_input_queued PARAMS((int)); +extern void _rl_insert_typein PARAMS((int)); +extern int _rl_unget_char PARAMS((int)); + +/* macro.c */ +extern void _rl_with_macro_input PARAMS((char *)); +extern int _rl_next_macro_key PARAMS((void)); +extern void _rl_push_executing_macro PARAMS((void)); +extern void _rl_pop_executing_macro PARAMS((void)); +extern void _rl_add_macro_char PARAMS((int)); +extern void _rl_kill_kbd_macro PARAMS((void)); + +/* misc.c */ +extern int _rl_init_argument PARAMS((void)); +extern void _rl_start_using_history PARAMS((void)); +extern int _rl_free_saved_history_line PARAMS((void)); +extern void _rl_set_insert_mode PARAMS((int, int)); + +/* nls.c */ +extern int _rl_init_eightbit PARAMS((void)); + +/* parens.c */ +extern void _rl_enable_paren_matching PARAMS((int)); + +/* readline.c */ +extern void _rl_init_line_state PARAMS((void)); +extern void _rl_set_the_line PARAMS((void)); +extern int _rl_dispatch PARAMS((int, Keymap)); +extern int _rl_dispatch_subseq PARAMS((int, Keymap, int)); + +/* rltty.c */ +extern int _rl_disable_tty_signals PARAMS((void)); +extern int _rl_restore_tty_signals PARAMS((void)); + +/* terminal.c */ +extern void _rl_get_screen_size PARAMS((int, int)); +extern int _rl_init_terminal_io PARAMS((const char *)); +#ifdef _MINIX +extern void _rl_output_character_function PARAMS((int)); +#else +extern int _rl_output_character_function PARAMS((int)); +#endif +extern void _rl_output_some_chars PARAMS((const char *, int)); +extern int _rl_backspace PARAMS((int)); +extern void _rl_enable_meta_key PARAMS((void)); +extern void _rl_control_keypad PARAMS((int)); +extern void _rl_set_cursor PARAMS((int, int)); + +/* text.c */ +extern void _rl_fix_point PARAMS((int)); +extern int _rl_replace_text PARAMS((const char *, int, int)); +extern int _rl_insert_char PARAMS((int, int)); +extern int _rl_overwrite_char PARAMS((int, int)); +extern int _rl_overwrite_rubout PARAMS((int, int)); +extern int _rl_rubout_char PARAMS((int, int)); +#if defined (HANDLE_MULTIBYTE) +extern int _rl_char_search_internal PARAMS((int, int, char *, int)); +#else +extern int _rl_char_search_internal PARAMS((int, int, int)); +#endif +extern int _rl_set_mark_at_pos PARAMS((int)); + +/* util.c */ +extern int _rl_abort_internal PARAMS((void)); +extern char *_rl_strindex PARAMS((const char *, const char *)); +extern int _rl_qsort_string_compare PARAMS((char **, char **)); +extern int (_rl_uppercase_p) PARAMS((int)); +extern int (_rl_lowercase_p) PARAMS((int)); +extern int (_rl_pure_alphabetic) PARAMS((int)); +extern int (_rl_digit_p) PARAMS((int)); +extern int (_rl_to_lower) PARAMS((int)); +extern int (_rl_to_upper) PARAMS((int)); +extern int (_rl_digit_value) PARAMS((int)); + +/* vi_mode.c */ +extern void _rl_vi_initialize_line PARAMS((void)); +extern void _rl_vi_reset_last PARAMS((void)); +extern void _rl_vi_set_last PARAMS((int, int, int)); +extern int _rl_vi_textmod_command PARAMS((int)); +extern void _rl_vi_done_inserting PARAMS((void)); + +/************************************************************************* + * Undocumented private variables * + *************************************************************************/ + +/* bind.c */ +extern const char *_rl_possible_control_prefixes[]; +extern const char *_rl_possible_meta_prefixes[]; + +/* complete.c */ +extern int _rl_complete_show_all; +extern int _rl_complete_mark_directories; +extern int _rl_complete_mark_symlink_dirs; +extern int _rl_print_completions_horizontally; +extern int _rl_completion_case_fold; +extern int _rl_match_hidden_files; +extern int _rl_page_completions; + +/* display.c */ +extern int _rl_vis_botlin; +extern int _rl_last_c_pos; +extern int _rl_suppress_redisplay; +extern const char *rl_display_prompt; + +/* isearch.c */ +extern char *_rl_isearch_terminators; + +/* macro.c */ +extern char *_rl_executing_macro; + +/* misc.c */ +extern int _rl_history_preserve_point; +extern int _rl_history_saved_point; + +/* readline.c */ +extern int _rl_horizontal_scroll_mode; +extern int _rl_mark_modified_lines; +extern int _rl_bell_preference; +extern int _rl_meta_flag; +extern int _rl_convert_meta_chars_to_ascii; +extern int _rl_output_meta_chars; +extern char *_rl_comment_begin; +extern unsigned char _rl_parsing_conditionalized_out; +extern Keymap _rl_keymap; +extern FILE *_rl_in_stream; +extern FILE *_rl_out_stream; +extern int _rl_last_command_was_kill; +extern int _rl_eof_char; +extern procenv_t readline_top_level; + +/* terminal.c */ +extern int _rl_enable_keypad; +extern int _rl_enable_meta; +extern const char *_rl_term_clreol; +extern const char *_rl_term_clrpag; +extern const char *_rl_term_im; +extern const char *_rl_term_ic; +extern const char *_rl_term_ei; +extern const char *_rl_term_DC; +extern const char *_rl_term_up; +extern const char *_rl_term_dc; +extern const char *_rl_term_cr; +extern const char *_rl_term_IC; +extern int _rl_screenheight; +extern int _rl_screenwidth; +extern int _rl_screenchars; +extern int _rl_terminal_can_insert; +extern int _rl_term_autowrap; + +/* undo.c */ +extern int _rl_doing_an_undo; +extern int _rl_undo_group_level; + +#endif /* _RL_PRIVATE_H_ */ diff --git a/cmd-line-utils/readline/rlshell.h b/cmd-line-utils/readline/rlshell.h new file mode 100644 index 00000000000..3c03fbad576 --- /dev/null +++ b/cmd-line-utils/readline/rlshell.h @@ -0,0 +1,34 @@ +/* rlshell.h -- utility functions normally provided by bash. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_SHELL_H_) +#define _RL_SHELL_H_ + +#include "rlstdc.h" + +extern char *sh_single_quote PARAMS((char *)); +extern void sh_set_lines_and_columns PARAMS((int, int)); +extern char *sh_get_env_value PARAMS((const char *)); +extern char *sh_get_home_dir PARAMS((void)); +extern int sh_unset_nodelay_mode PARAMS((int)); + +#endif /* _RL_SHELL_H_ */ diff --git a/cmd-line-utils/readline/rlstdc.h b/cmd-line-utils/readline/rlstdc.h new file mode 100644 index 00000000000..d6a22b3742c --- /dev/null +++ b/cmd-line-utils/readline/rlstdc.h @@ -0,0 +1,45 @@ +/* stdc.h -- macros to make source compile on both ANSI C and K&R C + compilers. */ + +/* Copyright (C) 1993 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + Bash is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with Bash; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_STDC_H_) +#define _RL_STDC_H_ + +/* Adapted from BSD /usr/include/sys/cdefs.h. */ + +/* A function can be defined using prototypes and compile on both ANSI C + and traditional C compilers with something like this: + extern char *func PARAMS((char *, char *, int)); */ + +#if !defined (PARAMS) +# if defined (__STDC__) || defined (__GNUC__) || defined (__cplusplus) +# define PARAMS(protos) protos +# else +# define PARAMS(protos) () +# endif +#endif + +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#endif /* !_RL_STDC_H_ */ diff --git a/cmd-line-utils/readline/rltty.c b/cmd-line-utils/readline/rltty.c new file mode 100644 index 00000000000..09702e9e755 --- /dev/null +++ b/cmd-line-utils/readline/rltty.c @@ -0,0 +1,911 @@ +/* rltty.c -- functions to prepare and restore the terminal for readline's + use. */ + +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <signal.h> +#include <errno.h> +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL */ + +#include "rltty.h" +#include "readline.h" +#include "rlprivate.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; +rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; + +static void block_sigint PARAMS((void)); +static void release_sigint PARAMS((void)); + +static void set_winsize PARAMS((int)); + +/* **************************************************************** */ +/* */ +/* Signal Management */ +/* */ +/* **************************************************************** */ + +#if defined (HAVE_POSIX_SIGNALS) +static sigset_t sigint_set, sigint_oset; +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) +static int sigint_oldmask; +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + +static int sigint_blocked; + +/* Cause SIGINT to not be delivered until the corresponding call to + release_sigint(). */ +static void +block_sigint () +{ + if (sigint_blocked) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigemptyset (&sigint_set); + sigemptyset (&sigint_oset); + sigaddset (&sigint_set, SIGINT); + sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + sigint_oldmask = sigblock (sigmask (SIGINT)); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sighold (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + sigint_blocked = 1; +} + +/* Allow SIGINT to be delivered. */ +static void +release_sigint () +{ + if (sigint_blocked == 0) + return; + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL); +#else +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (sigint_oldmask); +# else /* !HAVE_BSD_SIGNALS */ +# if defined (HAVE_USG_SIGHOLD) + sigrelse (SIGINT); +# endif /* HAVE_USG_SIGHOLD */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + sigint_blocked = 0; +} + +/* **************************************************************** */ +/* */ +/* Saving and Restoring the TTY */ +/* */ +/* **************************************************************** */ + +/* Non-zero means that the terminal is in a prepped state. */ +static int terminal_prepped; + +static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars; + +/* If non-zero, means that this process has called tcflow(fd, TCOOFF) + and output is suspended. */ +#if defined (__ksr1__) +static int ksrflow; +#endif + +/* Dummy call to force a backgrounded readline to stop before it tries + to get the tty settings. */ +static void +set_winsize (tty) + int tty; +{ +#if defined (TIOCGWINSZ) + struct winsize w; + + if (ioctl (tty, TIOCGWINSZ, &w) == 0) + (void) ioctl (tty, TIOCSWINSZ, &w); +#endif /* TIOCGWINSZ */ +} + +#if defined (NEW_TTY_DRIVER) + +/* Values for the `flags' field of a struct bsdtty. This tells which + elements of the struct bsdtty have been fetched from the system and + are valid. */ +#define SGTTY_SET 0x01 +#define LFLAG_SET 0x02 +#define TCHARS_SET 0x04 +#define LTCHARS_SET 0x08 + +struct bsdtty { + struct sgttyb sgttyb; /* Basic BSD tty driver information. */ + int lflag; /* Local mode flags, like LPASS8. */ +#if defined (TIOCGETC) + struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ +#endif +#if defined (TIOCGLTC) + struct ltchars ltchars; /* 4.2 BSD editing characters */ +#endif + int flags; /* Bitmap saying which parts of the struct are valid. */ +}; + +#define TIOTYPE struct bsdtty + +static TIOTYPE otio; + +static void save_tty_chars PARAMS((TIOTYPE *)); +static int _get_tty_settings PARAMS((int, TIOTYPE *)); +static int get_tty_settings PARAMS((int, TIOTYPE *)); +static int _set_tty_settings PARAMS((int, TIOTYPE *)); +static int set_tty_settings PARAMS((int, TIOTYPE *)); + +static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); + +static void +save_tty_chars (tiop) + TIOTYPE *tiop; +{ + _rl_last_tty_chars = _rl_tty_chars; + + if (tiop->flags & SGTTY_SET) + { + _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase; + _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill; + } + + if (tiop->flags & TCHARS_SET) + { + _rl_tty_chars.t_intr = tiop->tchars.t_intrc; + _rl_tty_chars.t_quit = tiop->tchars.t_quitc; + _rl_tty_chars.t_start = tiop->tchars.t_startc; + _rl_tty_chars.t_stop = tiop->tchars.t_stopc; + _rl_tty_chars.t_eof = tiop->tchars.t_eofc; + _rl_tty_chars.t_eol = '\n'; + _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc; + } + + if (tiop->flags & LTCHARS_SET) + { + _rl_tty_chars.t_susp = tiop->ltchars.t_suspc; + _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc; + _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc; + _rl_tty_chars.t_flush = tiop->ltchars.t_flushc; + _rl_tty_chars.t_werase = tiop->ltchars.t_werasc; + _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc; + } + + _rl_tty_chars.t_status = -1; +} + +static int +get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + set_winsize (tty); + + tiop->flags = tiop->lflag = 0; + + if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0) + return -1; + tiop->flags |= SGTTY_SET; + +#if defined (TIOCLGET) + if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0) + tiop->flags |= LFLAG_SET; +#endif + +#if defined (TIOCGETC) + if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0) + tiop->flags |= TCHARS_SET; +#endif + +#if defined (TIOCGLTC) + if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0) + tiop->flags |= LTCHARS_SET; +#endif + + return 0; +} + +static int +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + if (tiop->flags & SGTTY_SET) + { + ioctl (tty, TIOCSETN, &(tiop->sgttyb)); + tiop->flags &= ~SGTTY_SET; + } + readline_echoing_p = 1; + +#if defined (TIOCLSET) + if (tiop->flags & LFLAG_SET) + { + ioctl (tty, TIOCLSET, &(tiop->lflag)); + tiop->flags &= ~LFLAG_SET; + } +#endif + +#if defined (TIOCSETC) + if (tiop->flags & TCHARS_SET) + { + ioctl (tty, TIOCSETC, &(tiop->tchars)); + tiop->flags &= ~TCHARS_SET; + } +#endif + +#if defined (TIOCSLTC) + if (tiop->flags & LTCHARS_SET) + { + ioctl (tty, TIOCSLTC, &(tiop->ltchars)); + tiop->flags &= ~LTCHARS_SET; + } +#endif + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, oldtio, tiop) + int meta_flag; + TIOTYPE oldtio, *tiop; +{ + readline_echoing_p = (oldtio.sgttyb.sg_flags & ECHO); + + /* Copy the original settings to the structure we're going to use for + our settings. */ + tiop->sgttyb = oldtio.sgttyb; + tiop->lflag = oldtio.lflag; +#if defined (TIOCGETC) + tiop->tchars = oldtio.tchars; +#endif +#if defined (TIOCGLTC) + tiop->ltchars = oldtio.ltchars; +#endif + tiop->flags = oldtio.flags; + + /* First, the basic settings to put us into character-at-a-time, no-echo + input mode. */ + tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); + tiop->sgttyb.sg_flags |= CBREAK; + + /* If this terminal doesn't care how the 8th bit is used, then we can + use it for the meta-key. If only one of even or odd parity is + specified, then the terminal is using parity, and we cannot. */ +#if !defined (ANYP) +# define ANYP (EVENP | ODDP) +#endif + if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) || + ((oldtio.sgttyb.sg_flags & ANYP) == 0)) + { + tiop->sgttyb.sg_flags |= ANYP; + + /* Hack on local mode flags if we can. */ +#if defined (TIOCLGET) +# if defined (LPASS8) + tiop->lflag |= LPASS8; +# endif /* LPASS8 */ +#endif /* TIOCLGET */ + } + +#if defined (TIOCGETC) +# if defined (USE_XON_XOFF) + /* Get rid of terminal output start and stop characters. */ + tiop->tchars.t_stopc = -1; /* C-s */ + tiop->tchars.t_startc = -1; /* C-q */ + + /* If there is an XON character, bind it to restart the output. */ + if (oldtio.tchars.t_startc != -1) + rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); +# endif /* USE_XON_XOFF */ + + /* If there is an EOF char, bind _rl_eof_char to it. */ + if (oldtio.tchars.t_eofc != -1) + _rl_eof_char = oldtio.tchars.t_eofc; + +# if defined (NO_KILL_INTR) + /* Get rid of terminal-generated SIGQUIT and SIGINT. */ + tiop->tchars.t_quitc = -1; /* C-\ */ + tiop->tchars.t_intrc = -1; /* C-c */ +# endif /* NO_KILL_INTR */ +#endif /* TIOCGETC */ + +#if defined (TIOCGLTC) + /* Make the interrupt keys go away. Just enough to make people happy. */ + tiop->ltchars.t_dsuspc = -1; /* C-y */ + tiop->ltchars.t_lnextc = -1; /* C-v */ +#endif /* TIOCGLTC */ +} + +#else /* !defined (NEW_TTY_DRIVER) */ + +#if !defined (VMIN) +# define VMIN VEOF +#endif + +#if !defined (VTIME) +# define VTIME VEOL +#endif + +#if defined (TERMIOS_TTY_DRIVER) +# define TIOTYPE struct termios +# define DRAIN_OUTPUT(fd) tcdrain (fd) +# define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) +# ifdef M_UNIX +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) +# else +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) +# endif /* !M_UNIX */ +#else +# define TIOTYPE struct termio +# define DRAIN_OUTPUT(fd) +# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) +# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop)) +#endif /* !TERMIOS_TTY_DRIVER */ + +static TIOTYPE otio; + +static void save_tty_chars PARAMS((TIOTYPE *)); +static int _get_tty_settings PARAMS((int, TIOTYPE *)); +static int get_tty_settings PARAMS((int, TIOTYPE *)); +static int _set_tty_settings PARAMS((int, TIOTYPE *)); +static int set_tty_settings PARAMS((int, TIOTYPE *)); + +static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); + +#if defined (FLUSHO) +# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) +#else +# define OUTPUT_BEING_FLUSHED(tp) 0 +#endif + +static void +save_tty_chars (tiop) + TIOTYPE *tiop; +{ + _rl_last_tty_chars = _rl_tty_chars; + + _rl_tty_chars.t_eof = tiop->c_cc[VEOF]; + _rl_tty_chars.t_eol = tiop->c_cc[VEOL]; +#ifdef VEOL2 + _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2]; +#endif + _rl_tty_chars.t_erase = tiop->c_cc[VERASE]; +#ifdef VWERASE + _rl_tty_chars.t_werase = tiop->c_cc[VWERASE]; +#endif + _rl_tty_chars.t_kill = tiop->c_cc[VKILL]; +#ifdef VREPRINT + _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT]; +#endif + _rl_tty_chars.t_intr = tiop->c_cc[VINTR]; + _rl_tty_chars.t_quit = tiop->c_cc[VQUIT]; +#ifdef VSUSP + _rl_tty_chars.t_susp = tiop->c_cc[VSUSP]; +#endif +#ifdef VDSUSP + _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP]; +#endif +#ifdef VSTART + _rl_tty_chars.t_start = tiop->c_cc[VSTART]; +#endif +#ifdef VSTOP + _rl_tty_chars.t_stop = tiop->c_cc[VSTOP]; +#endif +#ifdef VLNEXT + _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT]; +#endif +#ifdef VDISCARD + _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD]; +#endif +#ifdef VSTATUS + _rl_tty_chars.t_status = tiop->c_cc[VSTATUS]; +#endif +} + +#if defined (_AIX) || defined (_AIX41) +/* Currently this is only used on AIX */ +static void +rltty_warning (msg) + char *msg; +{ + fprintf (stderr, "readline: warning: %s\n", msg); +} +#endif + +#if defined (_AIX) +void +setopost(tp) +TIOTYPE *tp; +{ + if ((tp->c_oflag & OPOST) == 0) + { + rltty_warning ("turning on OPOST for terminal\r"); + tp->c_oflag |= OPOST|ONLCR; + } +} +#endif + +static int +_get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + int ioctl_ret; + + while (1) + { + ioctl_ret = GETATTR (tty, tiop); + if (ioctl_ret < 0) + { + if (errno != EINTR) + return -1; + else + continue; + } + if (OUTPUT_BEING_FLUSHED (tiop)) + { +#if defined (FLUSHO) && defined (_AIX41) + rltty_warning ("turning off output flushing"); + tiop->c_lflag &= ~FLUSHO; + break; +#else + continue; +#endif + } + break; + } + + return 0; +} + +static int +get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + set_winsize (tty); + + if (_get_tty_settings (tty, tiop) < 0) + return -1; + +#if defined (_AIX) + setopost(tiop); +#endif + + return 0; +} + +static int +_set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + while (SETATTR (tty, tiop) < 0) + { + if (errno != EINTR) + return -1; + errno = 0; + } + return 0; +} + +static int +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + if (_set_tty_settings (tty, tiop) < 0) + return -1; + +#if 0 + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (tty, TCOON); + } +# else /* !ksr1 */ + tcflow (tty, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +#else + ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ +#endif /* !TERMIOS_TTY_DRIVER */ + +#endif /* 0 */ + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, oldtio, tiop) + int meta_flag; + TIOTYPE oldtio, *tiop; +{ + readline_echoing_p = (oldtio.c_lflag & ECHO); + + tiop->c_lflag &= ~(ICANON | ECHO); + + if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) + _rl_eof_char = oldtio.c_cc[VEOF]; + +#if defined (USE_XON_XOFF) +#if defined (IXANY) + tiop->c_iflag &= ~(IXON | IXOFF | IXANY); +#else + /* `strict' Posix systems do not define IXANY. */ + tiop->c_iflag &= ~(IXON | IXOFF); +#endif /* IXANY */ +#endif /* USE_XON_XOFF */ + + /* Only turn this off if we are using all 8 bits. */ + if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) + tiop->c_iflag &= ~(ISTRIP | INPCK); + + /* Make sure we differentiate between CR and NL on input. */ + tiop->c_iflag &= ~(ICRNL | INLCR); + +#if !defined (HANDLE_SIGNALS) + tiop->c_lflag &= ~ISIG; +#else + tiop->c_lflag |= ISIG; +#endif + + tiop->c_cc[VMIN] = 1; + tiop->c_cc[VTIME] = 0; + +#if defined (FLUSHO) + if (OUTPUT_BEING_FLUSHED (tiop)) + { + tiop->c_lflag &= ~FLUSHO; + oldtio.c_lflag &= ~FLUSHO; + } +#endif + + /* Turn off characters that we need on Posix systems with job control, + just to be sure. This includes ^Y and ^V. This should not really + be necessary. */ +#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) + +#if defined (VLNEXT) + tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; +#endif + +#if defined (VDSUSP) + tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif + +#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ +} +#endif /* NEW_TTY_DRIVER */ + +/* Put the terminal in CBREAK mode so that we can detect key presses. */ +void +rl_prep_terminal (meta_flag) + int meta_flag; +{ + int tty; + TIOTYPE tio; + + if (terminal_prepped) + return; + + /* Try to keep this function from being INTerrupted. */ + block_sigint (); + + tty = fileno (rl_instream); + + if (get_tty_settings (tty, &tio) < 0) + { + release_sigint (); + return; + } + + otio = tio; + + save_tty_chars (&otio); + + prepare_terminal_settings (meta_flag, otio, &tio); + + if (set_tty_settings (tty, &tio) < 0) + { + release_sigint (); + return; + } + + if (_rl_enable_keypad) + _rl_control_keypad (1); + + fflush (rl_outstream); + terminal_prepped = 1; + RL_SETSTATE(RL_STATE_TERMPREPPED); + + release_sigint (); +} + +/* Restore the terminal's normal settings and modes. */ +void +rl_deprep_terminal () +{ + int tty; + + if (!terminal_prepped) + return; + + /* Try to keep this function from being interrupted. */ + block_sigint (); + + tty = fileno (rl_instream); + + if (_rl_enable_keypad) + _rl_control_keypad (0); + + fflush (rl_outstream); + + if (set_tty_settings (tty, &otio) < 0) + { + release_sigint (); + return; + } + + terminal_prepped = 0; + RL_UNSETSTATE(RL_STATE_TERMPREPPED); + + release_sigint (); +} + +/* **************************************************************** */ +/* */ +/* Bogus Flow Control */ +/* */ +/* **************************************************************** */ + +int +rl_restart_output (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int fildes = fileno (rl_outstream); +#if defined (TIOCSTART) +#if defined (apollo) + ioctl (&fildes, TIOCSTART, 0); +#else + ioctl (fildes, TIOCSTART, 0); +#endif /* apollo */ + +#else /* !TIOCSTART */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (fildes, TCOON); + } +# else /* !ksr1 */ + tcflow (fildes, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +# else /* !TERMIOS_TTY_DRIVER */ +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTART */ + + return 0; +} + +int +rl_stop_output (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int fildes = fileno (rl_instream); + +#if defined (TIOCSTOP) +# if defined (apollo) + ioctl (&fildes, TIOCSTOP, 0); +# else + ioctl (fildes, TIOCSTOP, 0); +# endif /* apollo */ +#else /* !TIOCSTOP */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + ksrflow = 1; +# endif /* ksr1 */ + tcflow (fildes, TCOOFF); +# else +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTOP */ + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Default Key Bindings */ +/* */ +/* **************************************************************** */ + +/* Set the system's default editing characters to their readline equivalents + in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ +void +rltty_set_default_bindings (kmap) + Keymap kmap; +{ + TIOTYPE ttybuff; + int tty = fileno (rl_instream); + +#if defined (NEW_TTY_DRIVER) + +#define SET_SPECIAL(sc, func) \ + do \ + { \ + int ic; \ + ic = sc; \ + if (ic != -1 && kmap[(unsigned char)ic].type == ISFUNC) \ + kmap[(unsigned char)ic].function = func; \ + } \ + while (0) + + if (get_tty_settings (tty, &ttybuff) == 0) + { + if (ttybuff.flags & SGTTY_SET) + { + SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); + SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); + } + +# if defined (TIOCGLTC) + if (ttybuff.flags & LTCHARS_SET) + { + SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); + SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); + } +# endif /* TIOCGLTC */ + } + +#else /* !NEW_TTY_DRIVER */ + +#define SET_SPECIAL(sc, func) \ + do \ + { \ + unsigned char uc; \ + uc = ttybuff.c_cc[sc]; \ + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ + kmap[uc].function = func; \ + } \ + while (0) + + if (get_tty_settings (tty, &ttybuff) == 0) + { + SET_SPECIAL (VERASE, rl_rubout); + SET_SPECIAL (VKILL, rl_unix_line_discard); + +# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VLNEXT, rl_quoted_insert); +# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ + +# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VWERASE, rl_unix_word_rubout); +# endif /* VWERASE && TERMIOS_TTY_DRIVER */ + } +#endif /* !NEW_TTY_DRIVER */ +} + +/* New public way to set the system default editing chars to their readline + equivalents. */ +void +rl_tty_set_default_bindings (kmap) + Keymap kmap; +{ + rltty_set_default_bindings (kmap); +} + +#if defined (HANDLE_SIGNALS) + +#if defined (NEW_TTY_DRIVER) +int +_rl_disable_tty_signals () +{ + return 0; +} + +int +_rl_restore_tty_signals () +{ + return 0; +} +#else + +static TIOTYPE sigstty, nosigstty; +static int tty_sigs_disabled = 0; + +int +_rl_disable_tty_signals () +{ + if (tty_sigs_disabled) + return 0; + + if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0) + return -1; + + nosigstty = sigstty; + + nosigstty.c_lflag &= ~ISIG; + nosigstty.c_iflag &= ~IXON; + + if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0) + return (_set_tty_settings (fileno (rl_instream), &sigstty)); + + tty_sigs_disabled = 1; + return 0; +} + +int +_rl_restore_tty_signals () +{ + int r; + + if (tty_sigs_disabled == 0) + return 0; + + r = _set_tty_settings (fileno (rl_instream), &sigstty); + + if (r == 0) + tty_sigs_disabled = 0; + + return r; +} +#endif /* !NEW_TTY_DRIVER */ + +#endif /* HANDLE_SIGNALS */ diff --git a/cmd-line-utils/readline/rltty.h b/cmd-line-utils/readline/rltty.h new file mode 100644 index 00000000000..029a3fbc0e1 --- /dev/null +++ b/cmd-line-utils/readline/rltty.h @@ -0,0 +1,82 @@ +/* rltty.h - tty driver-related definitions used by some library files. */ + +/* Copyright (C) 1995 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RLTTY_H_) +#define _RLTTY_H_ + +/* Posix systems use termios and the Posix signal functions. */ +#if defined (TERMIOS_TTY_DRIVER) +# include <termios.h> +#endif /* TERMIOS_TTY_DRIVER */ + +/* System V machines use termio. */ +#if defined (TERMIO_TTY_DRIVER) +# include <termio.h> +# if !defined (TCOON) +# define TCOON 1 +# endif +#endif /* TERMIO_TTY_DRIVER */ + +/* Other (BSD) machines use sgtty. */ +#if defined (NEW_TTY_DRIVER) +# include <sgtty.h> +#endif + +#include "rlwinsize.h" + +/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and + it is not already defined. It is used both to determine if a + special character is disabled and to disable certain special + characters. Posix systems should set to 0, USG systems to -1. */ +#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) +# if defined (_SVR4_VDISABLE) +# define _POSIX_VDISABLE _SVR4_VDISABLE +# else +# if defined (_POSIX_VERSION) +# define _POSIX_VDISABLE 0 +# else /* !_POSIX_VERSION */ +# define _POSIX_VDISABLE -1 +# endif /* !_POSIX_VERSION */ +# endif /* !_SVR4_DISABLE */ +#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */ + +typedef struct _rl_tty_chars { + char t_eof; + char t_eol; + char t_eol2; + char t_erase; + char t_werase; + char t_kill; + char t_reprint; + char t_intr; + char t_quit; + char t_susp; + char t_dsusp; + char t_start; + char t_stop; + char t_lnext; + char t_flush; + char t_status; +} _RL_TTY_CHARS; + +#endif /* _RLTTY_H_ */ diff --git a/cmd-line-utils/readline/rltypedefs.h b/cmd-line-utils/readline/rltypedefs.h new file mode 100644 index 00000000000..f3280e9fce0 --- /dev/null +++ b/cmd-line-utils/readline/rltypedefs.h @@ -0,0 +1,88 @@ +/* rltypedefs.h -- Type declarations for readline functions. */ + +/* Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#ifndef _RL_TYPEDEFS_H_ +#define _RL_TYPEDEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Old-style */ + +#if !defined (_FUNCTION_DEF) +# define _FUNCTION_DEF + +typedef int Function (); +typedef void VFunction (); +typedef char *CPFunction (); +typedef char **CPPFunction (); + +#endif /* _FUNCTION_DEF */ + +/* New style. */ + +#if !defined (_RL_FUNCTION_TYPEDEF) +# define _RL_FUNCTION_TYPEDEF + +/* Bindable functions */ +typedef int rl_command_func_t PARAMS((int, int)); + +/* Typedefs for the completion system */ +typedef char *rl_compentry_func_t PARAMS((const char *, int)); +typedef char **rl_completion_func_t PARAMS((const char *, int, int)); + +typedef char *rl_quote_func_t PARAMS((char *, int, char *)); +typedef char *rl_dequote_func_t PARAMS((char *, int)); + +typedef int rl_compignore_func_t PARAMS((char **)); + +typedef void rl_compdisp_func_t PARAMS((char **, int, int)); + +/* Type for input and pre-read hook functions like rl_event_hook */ +typedef int rl_hook_func_t PARAMS((void)); + +/* Input function type */ +typedef int rl_getc_func_t PARAMS((FILE *)); + +/* Generic function that takes a character buffer (which could be the readline + line buffer) and an index into it (which could be rl_point) and returns + an int. */ +typedef int rl_linebuf_func_t PARAMS((char *, int)); + +/* `Generic' function pointer typedefs */ +typedef int rl_intfunc_t PARAMS((int)); +#define rl_ivoidfunc_t rl_hook_func_t +typedef int rl_icpfunc_t PARAMS((char *)); +typedef int rl_icppfunc_t PARAMS((char **)); + +typedef void rl_voidfunc_t PARAMS((void)); +typedef void rl_vintfunc_t PARAMS((int)); +typedef void rl_vcpfunc_t PARAMS((char *)); +typedef void rl_vcppfunc_t PARAMS((char **)); +#endif /* _RL_FUNCTION_TYPEDEF */ + +#ifdef __cplusplus +} +#endif + +#endif /* _RL_TYPEDEFS_H_ */ diff --git a/cmd-line-utils/readline/rlwinsize.h b/cmd-line-utils/readline/rlwinsize.h new file mode 100644 index 00000000000..7838154d023 --- /dev/null +++ b/cmd-line-utils/readline/rlwinsize.h @@ -0,0 +1,57 @@ +/* rlwinsize.h -- an attempt to isolate some of the system-specific defines + for `struct winsize' and TIOCGWINSZ. */ + +/* Copyright (C) 1997 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RLWINSIZE_H_) +#define _RLWINSIZE_H_ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +/* Try to find the definitions of `struct winsize' and TIOGCWINSZ */ + +#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ + +#if defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) +# include <termios.h> +#endif /* STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */ + +/* Not in either of the standard places, look around. */ +#if !defined (STRUCT_WINSIZE_IN_TERMIOS) && !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) +# if defined (HAVE_SYS_STREAM_H) +# include <sys/stream.h> +# endif /* HAVE_SYS_STREAM_H */ +# if defined (HAVE_SYS_PTEM_H) /* SVR4.2, at least, has it here */ +# include <sys/ptem.h> +# define _IO_PTEM_H /* work around SVR4.2 1.1.4 bug */ +# endif /* HAVE_SYS_PTEM_H */ +# if defined (HAVE_SYS_PTE_H) /* ??? */ +# include <sys/pte.h> +# endif /* HAVE_SYS_PTE_H */ +#endif /* !STRUCT_WINSIZE_IN_TERMIOS && !STRUCT_WINSIZE_IN_SYS_IOCTL */ + +#endif /* _RL_WINSIZE_H */ + diff --git a/cmd-line-utils/readline/search.c b/cmd-line-utils/readline/search.c new file mode 100644 index 00000000000..ac47596a3f8 --- /dev/null +++ b/cmd-line-utils/readline/search.c @@ -0,0 +1,465 @@ +/* search.c - code for non-incremental searching in emacs and vi modes. */ + +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file is part of the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <stdio.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif + +#include "rldefs.h" +#include "rlmbutil.h" + +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +#ifdef abs +# undef abs +#endif +#define abs(x) (((x) >= 0) ? (x) : -(x)) + +extern HIST_ENTRY *_rl_saved_line_for_history; + +/* Functions imported from the rest of the library. */ +extern int _rl_free_history_entry PARAMS((HIST_ENTRY *)); + +static char *noninc_search_string = (char *) NULL; +static int noninc_history_pos; + +static char *prev_line_found = (char *) NULL; + +static int rl_history_search_len; +static int rl_history_search_pos; +static char *history_search_string; +static int history_string_size; + +static void make_history_line_current PARAMS((HIST_ENTRY *)); +static int noninc_search_from_pos PARAMS((char *, int, int)); +static void noninc_dosearch PARAMS((char *, int)); +static void noninc_search PARAMS((int, int)); +static int rl_history_search_internal PARAMS((int, int)); +static void rl_history_search_reinit PARAMS((void)); + +/* Make the data from the history entry ENTRY be the contents of the + current line. This doesn't do anything with rl_point; the caller + must set it. */ +static void +make_history_line_current (entry) + HIST_ENTRY *entry; +{ + rl_replace_line (entry->line, 0); + rl_undo_list = (UNDO_LIST *)entry->data; + + if (_rl_saved_line_for_history) + _rl_free_history_entry (_rl_saved_line_for_history); + _rl_saved_line_for_history = (HIST_ENTRY *)NULL; +} + +/* Search the history list for STRING starting at absolute history position + POS. If STRING begins with `^', the search must match STRING at the + beginning of a history line, otherwise a full substring match is performed + for STRING. DIR < 0 means to search backwards through the history list, + DIR >= 0 means to search forward. */ +static int +noninc_search_from_pos (string, pos, dir) + char *string; + int pos, dir; +{ + int ret, old; + + if (pos < 0) + return -1; + + old = where_history (); + if (history_set_pos (pos) == 0) + return -1; + + RL_SETSTATE(RL_STATE_SEARCH); + if (*string == '^') + ret = history_search_prefix (string + 1, dir); + else + ret = history_search (string, dir); + RL_UNSETSTATE(RL_STATE_SEARCH); + + if (ret != -1) + ret = where_history (); + + history_set_pos (old); + return (ret); +} + +/* Search for a line in the history containing STRING. If DIR is < 0, the + search is backwards through previous entries, else through subsequent + entries. */ +static void +noninc_dosearch (string, dir) + char *string; + int dir; +{ + int oldpos, pos; + HIST_ENTRY *entry; + + if (string == 0 || *string == '\0' || noninc_history_pos < 0) + { + rl_ding (); + return; + } + + pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir); + if (pos == -1) + { + /* Search failed, current history position unchanged. */ + rl_maybe_unsave_line (); + rl_clear_message (); + rl_point = 0; + rl_ding (); + return; + } + + noninc_history_pos = pos; + + oldpos = where_history (); + history_set_pos (noninc_history_pos); + entry = current_history (); +#if defined (VI_MODE) + if (rl_editing_mode != vi_mode) +#endif + history_set_pos (oldpos); + + make_history_line_current (entry); + + rl_point = 0; + rl_mark = rl_end; + + rl_clear_message (); +} + +/* Search non-interactively through the history list. DIR < 0 means to + search backwards through the history of previous commands; otherwise + the search is for commands subsequent to the current position in the + history list. PCHAR is the character to use for prompting when reading + the search string; if not specified (0), it defaults to `:'. */ +static void +noninc_search (dir, pchar) + int dir; + int pchar; +{ + int saved_point, saved_mark, c; + char *p; +#if defined (HANDLE_MULTIBYTE) + char mb[MB_LEN_MAX]; +#endif + + rl_maybe_save_line (); + saved_point = rl_point; + saved_mark = rl_mark; + + /* Use the line buffer to read the search string. */ + rl_line_buffer[0] = 0; + rl_end = rl_point = 0; + + p = _rl_make_prompt_for_search (pchar ? pchar : ':'); + rl_message (p, 0, 0); + free (p); + +#define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return + + RL_SETSTATE(RL_STATE_NSEARCH); + /* Read the search string. */ + while (1) + { + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + c = _rl_read_mbstring (c, mb, MB_LEN_MAX); +#endif + + if (c == 0) + break; + + switch (c) + { + case CTRL('H'): + case RUBOUT: + if (rl_point == 0) + { + rl_maybe_unsave_line (); + rl_clear_message (); + rl_point = saved_point; + rl_mark = saved_mark; + SEARCH_RETURN; + } + _rl_rubout_char (1, c); + break; + + case CTRL('W'): + rl_unix_word_rubout (1, c); + break; + + case CTRL('U'): + rl_unix_line_discard (1, c); + break; + + case RETURN: + case NEWLINE: + goto dosearch; + /* NOTREACHED */ + break; + + case CTRL('C'): + case CTRL('G'): + rl_maybe_unsave_line (); + rl_clear_message (); + rl_point = saved_point; + rl_mark = saved_mark; + rl_ding (); + SEARCH_RETURN; + + default: +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mb); + else +#endif + _rl_insert_char (1, c); + break; + } + (*rl_redisplay_function) (); + } + + dosearch: + rl_mark = saved_mark; + + /* If rl_point == 0, we want to re-use the previous search string and + start from the saved history position. If there's no previous search + string, punt. */ + if (rl_point == 0) + { + if (!noninc_search_string) + { + rl_ding (); + SEARCH_RETURN; + } + } + else + { + /* We want to start the search from the current history position. */ + noninc_history_pos = where_history (); + FREE (noninc_search_string); + noninc_search_string = savestring (rl_line_buffer); + } + + rl_restore_prompt (); + noninc_dosearch (noninc_search_string, dir); + RL_UNSETSTATE(RL_STATE_NSEARCH); +} + +/* Search forward through the history list for a string. If the vi-mode + code calls this, KEY will be `?'. */ +int +rl_noninc_forward_search (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + noninc_search (1, (key == '?') ? '?' : 0); + return 0; +} + +/* Reverse search the history list for a string. If the vi-mode code + calls this, KEY will be `/'. */ +int +rl_noninc_reverse_search (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + noninc_search (-1, (key == '/') ? '/' : 0); + return 0; +} + +/* Search forward through the history list for the last string searched + for. If there is no saved search string, abort. */ +int +rl_noninc_forward_search_again (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (!noninc_search_string) + { + rl_ding (); + return (-1); + } + noninc_dosearch (noninc_search_string, 1); + return 0; +} + +/* Reverse search in the history list for the last string searched + for. If there is no saved search string, abort. */ +int +rl_noninc_reverse_search_again (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (!noninc_search_string) + { + rl_ding (); + return (-1); + } + noninc_dosearch (noninc_search_string, -1); + return 0; +} + +static int +rl_history_search_internal (count, dir) + int count, dir; +{ + HIST_ENTRY *temp; + int ret, oldpos; + + rl_maybe_save_line (); + temp = (HIST_ENTRY *)NULL; + + /* Search COUNT times through the history for a line whose prefix + matches history_search_string. When this loop finishes, TEMP, + if non-null, is the history line to copy into the line buffer. */ + while (count) + { + ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir); + if (ret == -1) + break; + + /* Get the history entry we found. */ + rl_history_search_pos = ret; + oldpos = where_history (); + history_set_pos (rl_history_search_pos); + temp = current_history (); + history_set_pos (oldpos); + + /* Don't find multiple instances of the same line. */ + if (prev_line_found && STREQ (prev_line_found, temp->line)) + continue; + prev_line_found = temp->line; + count--; + } + + /* If we didn't find anything at all, return. */ + if (temp == 0) + { + rl_maybe_unsave_line (); + rl_ding (); + /* If you don't want the saved history line (last match) to show up + in the line buffer after the search fails, change the #if 0 to + #if 1 */ +#if 0 + if (rl_point > rl_history_search_len) + { + rl_point = rl_end = rl_history_search_len; + rl_line_buffer[rl_end] = '\0'; + rl_mark = 0; + } +#else + rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ + rl_mark = rl_end; +#endif + return 1; + } + + /* Copy the line we found into the current line buffer. */ + make_history_line_current (temp); + + rl_point = rl_history_search_len; + rl_mark = rl_end; + + return 0; +} + +static void +rl_history_search_reinit () +{ + rl_history_search_pos = where_history (); + rl_history_search_len = rl_point; + prev_line_found = (char *)NULL; + if (rl_point) + { + if (rl_history_search_len >= history_string_size - 2) + { + history_string_size = rl_history_search_len + 2; + history_search_string = (char *)xrealloc (history_search_string, history_string_size); + } + history_search_string[0] = '^'; + strncpy (history_search_string + 1, rl_line_buffer, rl_point); + history_search_string[rl_point + 1] = '\0'; + } + _rl_free_saved_history_line (); +} + +/* Search forward in the history for the string of characters + from the start of the line to rl_point. This is a non-incremental + search. */ +int +rl_history_search_forward (count, ignore) + int count, ignore; +{ + if (count == 0) + return (0); + + if (rl_last_func != rl_history_search_forward && + rl_last_func != rl_history_search_backward) + rl_history_search_reinit (); + + if (rl_history_search_len == 0) + return (rl_get_next_history (count, ignore)); + return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); +} + +/* Search backward through the history for the string of characters + from the start of the line to rl_point. This is a non-incremental + search. */ +int +rl_history_search_backward (count, ignore) + int count, ignore; +{ + if (count == 0) + return (0); + + if (rl_last_func != rl_history_search_forward && + rl_last_func != rl_history_search_backward) + rl_history_search_reinit (); + + if (rl_history_search_len == 0) + return (rl_get_previous_history (count, ignore)); + return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); +} diff --git a/cmd-line-utils/readline/shell.c b/cmd-line-utils/readline/shell.c new file mode 100644 index 00000000000..ad27cc14884 --- /dev/null +++ b/cmd-line-utils/readline/shell.c @@ -0,0 +1,196 @@ +/* shell.c -- readline utility functions that are normally provided by + bash when readline is linked as part of the shell. */ + +/* Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_STRING_H) +# include <string.h> +#else +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_LIMITS_H) +# include <limits.h> +#endif + +#include <fcntl.h> +#include <pwd.h> + +#include <stdio.h> + +#include "rlstdc.h" +#include "rlshell.h" +#include "xmalloc.h" + +#if !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwuid PARAMS((uid_t)); +#endif /* !HAVE_GETPW_DECLS */ + +#ifndef NULL +# define NULL 0 +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* Nonzero if the integer type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* Bound on length of the string representing an integer value of type T. + Subtract one for the sign bit if T is signed; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if t is signed. */ +#define INT_STRLEN_BOUND(t) \ + ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \ + + 1 + TYPE_SIGNED (t)) + +/* All of these functions are resolved from bash if we are linking readline + as part of bash. */ + +/* Does shell-like quoting using single quotes. */ +char * +sh_single_quote (string) + char *string; +{ + register int c; + char *result, *r, *s; + + result = (char *)xmalloc (3 + (4 * strlen (string))); + r = result; + *r++ = '\''; + + for (s = string; s && (c = *s); s++) + { + *r++ = c; + + if (c == '\'') + { + *r++ = '\\'; /* insert escaped single quote */ + *r++ = '\''; + *r++ = '\''; /* start new quoted string */ + } + } + + *r++ = '\''; + *r = '\0'; + + return (result); +} + +/* Set the environment variables LINES and COLUMNS to lines and cols, + respectively. */ +void +sh_set_lines_and_columns (lines, cols) + int lines, cols; +{ + char *b; + +#if defined (HAVE_PUTENV) + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + sizeof ("LINES=") + 1); + sprintf (b, "LINES=%d", lines); + putenv (b); + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + sizeof ("COLUMNS=") + 1); + sprintf (b, "COLUMNS=%d", cols); + putenv (b); +#else /* !HAVE_PUTENV */ +# if defined (HAVE_SETENV) + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + 1); + sprintf (b, "%d", lines); + setenv ("LINES", b, 1); + b = (char *)xmalloc (INT_STRLEN_BOUND (int) + 1); + sprintf (b, "%d", cols); + setenv ("COLUMNS", b, 1); +# endif /* HAVE_SETENV */ +#endif /* !HAVE_PUTENV */ +} + +char * +sh_get_env_value (varname) + const char *varname; +{ + return ((char *)getenv (varname)); +} + +char * +sh_get_home_dir () +{ + char *home_dir; + struct passwd *entry; + + home_dir = (char *)NULL; + entry = getpwuid (getuid ()); + if (entry) + home_dir = entry->pw_dir; + return (home_dir); +} + +#if !defined (O_NDELAY) +# if defined (FNDELAY) +# define O_NDELAY FNDELAY +# endif +#endif + +int +sh_unset_nodelay_mode (fd) + int fd; +{ + int flags, bflags; + + if ((flags = fcntl (fd, F_GETFL, 0)) < 0) + return -1; + + bflags = 0; + +#ifdef O_NONBLOCK + bflags |= O_NONBLOCK; +#endif + +#ifdef O_NDELAY + bflags |= O_NDELAY; +#endif + + if (flags & bflags) + { + flags &= ~bflags; + return (fcntl (fd, F_SETFL, flags)); + } + + return 0; +} diff --git a/cmd-line-utils/readline/signals.c b/cmd-line-utils/readline/signals.c new file mode 100644 index 00000000000..0a1468b6b2a --- /dev/null +++ b/cmd-line-utils/readline/signals.c @@ -0,0 +1,398 @@ +/* signals.c -- signal handling support for readline. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> /* Just for NULL. Yuck. */ +#include <sys/types.h> +#include <signal.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL */ + +#if defined (HANDLE_SIGNALS) +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" + +#if !defined (RETSIGTYPE) +# if defined (VOID_SIGHANDLER) +# define RETSIGTYPE void +# else +# define RETSIGTYPE int +# endif /* !VOID_SIGHANDLER */ +#endif /* !RETSIGTYPE */ + +#if defined (VOID_SIGHANDLER) +# define SIGHANDLER_RETURN return +#else +# define SIGHANDLER_RETURN return (0) +#endif + +/* This typedef is equivalent to the one for Function; it allows us + to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ +typedef RETSIGTYPE SigHandler (); + +#if defined (HAVE_POSIX_SIGNALS) +typedef struct sigaction sighandler_cxt; +# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh) +#else +typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt; +# define sigemptyset(m) +#endif /* !HAVE_POSIX_SIGNALS */ + +static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); +static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *)); + +/* Exported variables for use by applications. */ + +/* If non-zero, readline will install its own signal handlers for + SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */ +int rl_catch_signals = 1; + +/* If non-zero, readline will install a signal handler for SIGWINCH. */ +#ifdef SIGWINCH +int rl_catch_sigwinch = 1; +#endif + +static int signals_set_flag; +static int sigwinch_set_flag; + +/* **************************************************************** */ +/* */ +/* Signal Handling */ +/* */ +/* **************************************************************** */ + +static sighandler_cxt old_int, old_term, old_alrm, old_quit; +#if defined (SIGTSTP) +static sighandler_cxt old_tstp, old_ttou, old_ttin; +#endif +#if defined (SIGWINCH) +static sighandler_cxt old_winch; +#endif + +/* Readline signal handler functions. */ + +static RETSIGTYPE +rl_signal_handler (sig) + int sig; +{ +#if defined (HAVE_POSIX_SIGNALS) + sigset_t set; +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + long omask; +# else /* !HAVE_BSD_SIGNALS */ + sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */ +# endif /* !HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + RL_SETSTATE(RL_STATE_SIGHANDLER); + +#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS) + /* Since the signal will not be blocked while we are in the signal + handler, ignore it until rl_clear_signals resets the catcher. */ + if (sig == SIGINT || sig == SIGALRM) + rl_set_sighandler (sig, SIG_IGN, &dummy_cxt); +#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */ + + switch (sig) + { + case SIGINT: + rl_free_line_state (); + /* FALLTHROUGH */ + +#if defined (SIGTSTP) + case SIGTSTP: + case SIGTTOU: + case SIGTTIN: +#endif /* SIGTSTP */ + case SIGALRM: + case SIGTERM: + case SIGQUIT: + rl_cleanup_after_signal (); + +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set); + sigdelset (&set, sig); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + omask = sigblock (0); +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + +#if defined (__EMX__) + signal (sig, SIG_ACK); +#endif + + kill (getpid (), sig); + + /* Let the signal that we just sent through. */ +#if defined (HAVE_POSIX_SIGNALS) + sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); +#else /* !HAVE_POSIX_SIGNALS */ +# if defined (HAVE_BSD_SIGNALS) + sigsetmask (omask & ~(sigmask (sig))); +# endif /* HAVE_BSD_SIGNALS */ +#endif /* !HAVE_POSIX_SIGNALS */ + + rl_reset_after_signal (); + } + + RL_UNSETSTATE(RL_STATE_SIGHANDLER); + SIGHANDLER_RETURN; +} + +#if defined (SIGWINCH) +static RETSIGTYPE +rl_sigwinch_handler (sig) + int sig; +{ + SigHandler *oh; + +#if defined (MUST_REINSTALL_SIGHANDLERS) + sighandler_cxt dummy_winch; + + /* We don't want to change old_winch -- it holds the state of SIGWINCH + disposition set by the calling application. We need this state + because we call the application's SIGWINCH handler after updating + our own idea of the screen size. */ + rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch); +#endif + + RL_SETSTATE(RL_STATE_SIGHANDLER); + rl_resize_terminal (); + + /* If another sigwinch handler has been installed, call it. */ + oh = (SigHandler *)old_winch.sa_handler; + if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL) + (*oh) (sig); + + RL_UNSETSTATE(RL_STATE_SIGHANDLER); + SIGHANDLER_RETURN; +} +#endif /* SIGWINCH */ + +/* Functions to manage signal handling. */ + +#if !defined (HAVE_POSIX_SIGNALS) +static int +rl_sigaction (sig, nh, oh) + int sig; + sighandler_cxt *nh, *oh; +{ + oh->sa_handler = signal (sig, nh->sa_handler); + return 0; +} +#endif /* !HAVE_POSIX_SIGNALS */ + +/* Set up a readline-specific signal handler, saving the old signal + information in OHANDLER. Return the old signal handler, like + signal(). */ +static SigHandler * +rl_set_sighandler (sig, handler, ohandler) + int sig; + SigHandler *handler; + sighandler_cxt *ohandler; +{ + sighandler_cxt old_handler; +#if defined (HAVE_POSIX_SIGNALS) + struct sigaction act; + + act.sa_handler = handler; + act.sa_flags = 0; /* XXX - should we set SA_RESTART for SIGWINCH? */ + sigemptyset (&act.sa_mask); + sigemptyset (&ohandler->sa_mask); + sigaction (sig, &act, &old_handler); +#else + old_handler.sa_handler = (SigHandler *)signal (sig, handler); +#endif /* !HAVE_POSIX_SIGNALS */ + + /* XXX -- assume we have memcpy */ + /* If rl_set_signals is called twice in a row, don't set the old handler to + rl_signal_handler, because that would cause infinite recursion. */ + if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler) + memcpy (ohandler, &old_handler, sizeof (sighandler_cxt)); + + return (ohandler->sa_handler); +} + +static void +rl_maybe_set_sighandler (sig, handler, ohandler) + int sig; + SigHandler *handler; + sighandler_cxt *ohandler; +{ + sighandler_cxt dummy; + SigHandler *oh; + + sigemptyset (&dummy.sa_mask); + oh = rl_set_sighandler (sig, handler, ohandler); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (sig, ohandler, &dummy); +} + +int +rl_set_signals () +{ + sighandler_cxt dummy; + SigHandler *oh; + + if (rl_catch_signals && signals_set_flag == 0) + { + rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int); + rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term); + rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit); + + oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm); + if (oh == (SigHandler *)SIG_IGN) + rl_sigaction (SIGALRM, &old_alrm, &dummy); +#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART) + /* If the application using readline has already installed a signal + handler with SA_RESTART, SIGALRM will cause reads to be restarted + automatically, so readline should just get out of the way. Since + we tested for SIG_IGN above, we can just test for SIG_DFL here. */ + if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART)) + rl_sigaction (SIGALRM, &old_alrm, &dummy); +#endif /* HAVE_POSIX_SIGNALS */ + +#if defined (SIGTSTP) + rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp); +#endif /* SIGTSTP */ + +#if defined (SIGTTOU) + rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou); +#endif /* SIGTTOU */ + +#if defined (SIGTTIN) + rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin); +#endif /* SIGTTIN */ + + signals_set_flag = 1; + } + +#if defined (SIGWINCH) + if (rl_catch_sigwinch && sigwinch_set_flag == 0) + { + rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch); + sigwinch_set_flag = 1; + } +#endif /* SIGWINCH */ + + return 0; +} + +int +rl_clear_signals () +{ + sighandler_cxt dummy; + + if (rl_catch_signals && signals_set_flag == 1) + { + sigemptyset (&dummy.sa_mask); + + rl_sigaction (SIGINT, &old_int, &dummy); + rl_sigaction (SIGTERM, &old_term, &dummy); + rl_sigaction (SIGQUIT, &old_quit, &dummy); + rl_sigaction (SIGALRM, &old_alrm, &dummy); + +#if defined (SIGTSTP) + rl_sigaction (SIGTSTP, &old_tstp, &dummy); +#endif /* SIGTSTP */ + +#if defined (SIGTTOU) + rl_sigaction (SIGTTOU, &old_ttou, &dummy); +#endif /* SIGTTOU */ + +#if defined (SIGTTIN) + rl_sigaction (SIGTTIN, &old_ttin, &dummy); +#endif /* SIGTTIN */ + + signals_set_flag = 0; + } + +#if defined (SIGWINCH) + if (rl_catch_sigwinch && sigwinch_set_flag == 1) + { + sigemptyset (&dummy.sa_mask); + rl_sigaction (SIGWINCH, &old_winch, &dummy); + sigwinch_set_flag = 0; + } +#endif + + return 0; +} + +/* Clean up the terminal and readline state after catching a signal, before + resending it to the calling application. */ +void +rl_cleanup_after_signal () +{ + _rl_clean_up_for_exit (); + (*rl_deprep_term_function) (); + rl_clear_signals (); + rl_clear_pending_input (); +} + +/* Reset the terminal and readline state after a signal handler returns. */ +void +rl_reset_after_signal () +{ + (*rl_prep_term_function) (_rl_meta_flag); + rl_set_signals (); +} + +/* Free up the readline variable line state for the current line (undo list, + any partial history entry, any keyboard macros in progress, and any + numeric arguments in process) after catching a signal, before calling + rl_cleanup_after_signal(). */ +void +rl_free_line_state () +{ + register HIST_ENTRY *entry; + + rl_free_undo_list (); + + entry = current_history (); + if (entry) + entry->data = (char *)NULL; + + _rl_kill_kbd_macro (); + rl_clear_message (); + _rl_init_argument (); +} + +#endif /* HANDLE_SIGNALS */ diff --git a/cmd-line-utils/readline/tcap.h b/cmd-line-utils/readline/tcap.h new file mode 100644 index 00000000000..58ab894d93e --- /dev/null +++ b/cmd-line-utils/readline/tcap.h @@ -0,0 +1,60 @@ +/* tcap.h -- termcap library functions and variables. */ + +/* Copyright (C) 1996 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RLTCAP_H_) +#define _RLTCAP_H_ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#if defined (HAVE_TERMCAP_H) +# if defined (__linux__) && !defined (SPEED_T_IN_SYS_TYPES) +# include "rltty.h" +# endif +# include <termcap.h> +#else + +/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC. + Unfortunately, PC is a global variable used by the termcap library. */ +#ifdef PC +# undef PC +#endif + +extern char PC; +extern char *UP, *BC; + +extern short ospeed; + +extern int tgetent (); +extern int tgetflag (); +extern int tgetnum (); +extern char *tgetstr (); + +extern int tputs (); + +extern char *tgoto (); + +#endif /* HAVE_TERMCAP_H */ + +#endif /* !_RLTCAP_H_ */ diff --git a/cmd-line-utils/readline/terminal.c b/cmd-line-utils/readline/terminal.c new file mode 100644 index 00000000000..397b10a1d46 --- /dev/null +++ b/cmd-line-utils/readline/terminal.c @@ -0,0 +1,663 @@ +/* terminal.c -- controlling the terminal with termcap. */ + +/* Copyright (C) 1996 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include "posixstat.h" +#include <fcntl.h> +#if defined (HAVE_SYS_FILE_H) +# include <sys/file.h> +#endif /* HAVE_SYS_FILE_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) +# include <sys/ioctl.h> +#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ + +#include "rltty.h" +#include "tcap.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) +#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) + +/* **************************************************************** */ +/* */ +/* Terminal and Termcap */ +/* */ +/* **************************************************************** */ + +static char *term_buffer = (char *)NULL; +static char *term_string_buffer = (char *)NULL; + +static int tcap_initialized; + +#if !defined (__linux__) +# if defined (__EMX__) || defined (NEED_EXTERN_PC) +extern +# endif /* __EMX__ || NEED_EXTERN_PC */ +char PC; +char *BC, *UP; +#endif /* __linux__ */ + +/* Some strings to control terminal actions. These are output by tputs (). */ +const char *_rl_term_clreol; +const char *_rl_term_clrpag; +const char *_rl_term_cr; +const char *_rl_term_backspace; +const char *_rl_term_goto; +const char *_rl_term_pc; + +/* Non-zero if we determine that the terminal can do character insertion. */ +int _rl_terminal_can_insert = 0; + +/* How to insert characters. */ +const char *_rl_term_im; +const char *_rl_term_ei; +const char *_rl_term_ic; +const char *_rl_term_ip; +const char *_rl_term_IC; + +/* How to delete characters. */ +const char *_rl_term_dc; +const char *_rl_term_DC; + +#if defined (HACK_TERMCAP_MOTION) +char *_rl_term_forward_char; +#endif /* HACK_TERMCAP_MOTION */ + +/* How to go up a line. */ +const char *_rl_term_up; + +/* A visible bell; char if the terminal can be made to flash the screen. */ +static const char *_rl_visible_bell; + +/* Non-zero means the terminal can auto-wrap lines. */ +int _rl_term_autowrap; + +/* Non-zero means that this terminal has a meta key. */ +static int term_has_meta; + +/* The sequences to write to turn on and off the meta key, if this + terminal has one. */ +static const char *_rl_term_mm; +static const char *_rl_term_mo; + +/* The key sequences output by the arrow keys, if this terminal has any. */ +static const char *_rl_term_ku; +static const char *_rl_term_kd; +static const char *_rl_term_kr; +static const char *_rl_term_kl; + +/* How to initialize and reset the arrow keys, if this terminal has any. */ +static const char *_rl_term_ks; +static const char *_rl_term_ke; + +/* The key sequences sent by the Home and End keys, if any. */ +static const char *_rl_term_kh; +static const char *_rl_term_kH; +static const char *_rl_term_at7; /* @7 */ + +/* Insert key */ +static const char *_rl_term_kI; + +/* Cursor control */ +static const char *_rl_term_vs; /* very visible */ +static const char *_rl_term_ve; /* normal */ + +static void bind_termcap_arrow_keys PARAMS((Keymap)); + +/* Variables that hold the screen dimensions, used by the display code. */ +int _rl_screenwidth, _rl_screenheight, _rl_screenchars; + +/* Non-zero means the user wants to enable the keypad. */ +int _rl_enable_keypad; + +/* Non-zero means the user wants to enable a meta key. */ +int _rl_enable_meta = 1; + +#if defined (__EMX__) +static void +_emx_get_screensize (swp, shp) + int *swp, *shp; +{ + int sz[2]; + + _scrsize (sz); + + if (swp) + *swp = sz[0]; + if (shp) + *shp = sz[1]; +} +#endif + +/* Get readline's idea of the screen size. TTY is a file descriptor open + to the terminal. If IGNORE_ENV is true, we do not pay attention to the + values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being + non-null serve to check whether or not we have initialized termcap. */ +void +_rl_get_screen_size (tty, ignore_env) + int tty, ignore_env; +{ + char *ss; +#if defined (TIOCGWINSZ) + struct winsize window_size; +#endif /* TIOCGWINSZ */ + +#if defined (TIOCGWINSZ) + if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) + { + _rl_screenwidth = (int) window_size.ws_col; + _rl_screenheight = (int) window_size.ws_row; + } +#endif /* TIOCGWINSZ */ + +#if defined (__EMX__) + _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); +#endif + + /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV + is unset. */ + if (_rl_screenwidth <= 0) + { + if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS"))) + _rl_screenwidth = atoi (ss); + +#if !defined (__DJGPP__) + if (_rl_screenwidth <= 0 && term_string_buffer) + _rl_screenwidth = tgetnum ("co"); +#endif + } + + /* Environment variable LINES overrides setting of "li" if IGNORE_ENV + is unset. */ + if (_rl_screenheight <= 0) + { + if (ignore_env == 0 && (ss = sh_get_env_value ("LINES"))) + _rl_screenheight = atoi (ss); + +#if !defined (__DJGPP__) + if (_rl_screenheight <= 0 && term_string_buffer) + _rl_screenheight = tgetnum ("li"); +#endif + } + + /* If all else fails, default to 80x24 terminal. */ + if (_rl_screenwidth <= 1) + _rl_screenwidth = 80; + + if (_rl_screenheight <= 0) + _rl_screenheight = 24; + + /* If we're being compiled as part of bash, set the environment + variables $LINES and $COLUMNS to new values. Otherwise, just + do a pair of putenv () or setenv () calls. */ + sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth); + + if (_rl_term_autowrap == 0) + _rl_screenwidth--; + + _rl_screenchars = _rl_screenwidth * _rl_screenheight; +} + +void +_rl_set_screen_size (rows, cols) + int rows, cols; +{ + if (rows == 0 || cols == 0) + return; + + _rl_screenheight = rows; + _rl_screenwidth = cols; + + if (_rl_term_autowrap == 0) + _rl_screenwidth--; + + _rl_screenchars = _rl_screenwidth * _rl_screenheight; +} + +void +rl_set_screen_size (rows, cols) + int rows, cols; +{ + _rl_set_screen_size (rows, cols); +} + +void +rl_get_screen_size (rows, cols) + int *rows, *cols; +{ + if (rows) + *rows = _rl_screenheight; + if (cols) + *cols = _rl_screenwidth; +} + +void +rl_resize_terminal () +{ + if (readline_echoing_p) + { + _rl_get_screen_size (fileno (rl_instream), 1); + if (CUSTOM_REDISPLAY_FUNC ()) + rl_forced_update_display (); + else + _rl_redisplay_after_sigwinch (); + } +} + +struct _tc_string { + const char *tc_var; + const char **tc_value; +}; + +/* This should be kept sorted, just in case we decide to change the + search algorithm to something smarter. */ +static struct _tc_string tc_strings[] = +{ + { "@7", &_rl_term_at7 }, + { "DC", &_rl_term_DC }, + { "IC", &_rl_term_IC }, + { "ce", &_rl_term_clreol }, + { "cl", &_rl_term_clrpag }, + { "cr", &_rl_term_cr }, + { "dc", &_rl_term_dc }, + { "ei", &_rl_term_ei }, + { "ic", &_rl_term_ic }, + { "im", &_rl_term_im }, + { "kH", &_rl_term_kH }, /* home down ?? */ + { "kI", &_rl_term_kI }, /* insert */ + { "kd", &_rl_term_kd }, + { "ke", &_rl_term_ke }, /* end keypad mode */ + { "kh", &_rl_term_kh }, /* home */ + { "kl", &_rl_term_kl }, + { "kr", &_rl_term_kr }, + { "ks", &_rl_term_ks }, /* start keypad mode */ + { "ku", &_rl_term_ku }, + { "le", &_rl_term_backspace }, + { "mm", &_rl_term_mm }, + { "mo", &_rl_term_mo }, +#if defined (HACK_TERMCAP_MOTION) + { "nd", &_rl_term_forward_char }, +#endif + { "pc", &_rl_term_pc }, + { "up", &_rl_term_up }, + { "vb", &_rl_visible_bell }, + { "vs", &_rl_term_vs }, + { "ve", &_rl_term_ve }, +}; + +#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) + +/* Read the desired terminal capability strings into BP. The capabilities + are described in the TC_STRINGS table. */ +static void +get_term_capabilities (bp) + char **bp; +{ +#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ + register unsigned int i; + + for (i = 0; i < NUM_TC_STRINGS; i++) +# ifdef __LCC__ + *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp); +# else + *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); +# endif +#endif + tcap_initialized = 1; +} + +int +_rl_init_terminal_io (terminal_name) + const char *terminal_name; +{ + const char *term; + char *buffer; + int tty, tgetent_ret; + + term = terminal_name ? terminal_name : sh_get_env_value ("TERM"); + _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL; + tty = rl_instream ? fileno (rl_instream) : 0; + _rl_screenwidth = _rl_screenheight = 0; + + if (term == 0) + term = "dumb"; + + /* I've separated this out for later work on not calling tgetent at all + if the calling application has supplied a custom redisplay function, + (and possibly if the application has supplied a custom input function). */ + if (CUSTOM_REDISPLAY_FUNC()) + { + tgetent_ret = -1; + } + else + { + if (term_string_buffer == 0) + term_string_buffer = (char *)xmalloc(2032); + + if (term_buffer == 0) + term_buffer = (char *)xmalloc(4080); + + buffer = term_string_buffer; + + tgetent_ret = tgetent (term_buffer, term); + } + + if (tgetent_ret <= 0) + { + FREE (term_string_buffer); + FREE (term_buffer); + buffer = term_buffer = term_string_buffer = (char *)NULL; + + _rl_term_autowrap = 0; /* used by _rl_get_screen_size */ + +#if defined (__EMX__) + _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); + _rl_screenwidth--; +#else /* !__EMX__ */ + _rl_get_screen_size (tty, 0); +#endif /* !__EMX__ */ + + /* Defaults. */ + if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) + { + _rl_screenwidth = 79; + _rl_screenheight = 24; + } + + /* Everything below here is used by the redisplay code (tputs). */ + _rl_screenchars = _rl_screenwidth * _rl_screenheight; + _rl_term_cr = "\r"; + _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL; + _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL; + _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL; + _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL; + _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL; + _rl_term_mm = _rl_term_mo = (char *)NULL; + _rl_term_ve = _rl_term_vs = (char *)NULL; +#if defined (HACK_TERMCAP_MOTION) + term_forward_char = (char *)NULL; +#endif + _rl_terminal_can_insert = term_has_meta = 0; + + /* Reasonable defaults for tgoto(). Readline currently only uses + tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we + change that later... */ + PC = '\0'; + BC = (char*)(_rl_term_backspace = "\b"); + UP = (char*)_rl_term_up; + + return 0; + } + + get_term_capabilities (&buffer); + + /* Set up the variables that the termcap library expects the application + to provide. */ + PC = _rl_term_pc ? *_rl_term_pc : 0; + BC = (char*)_rl_term_backspace; + UP = (char*)_rl_term_up; + + if (!_rl_term_cr) + _rl_term_cr = "\r"; + + _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); + + _rl_get_screen_size (tty, 0); + + /* "An application program can assume that the terminal can do + character insertion if *any one of* the capabilities `IC', + `im', `ic' or `ip' is provided." But we can't do anything if + only `ip' is provided, so... */ + _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic); + + /* Check to see if this terminal has a meta key and clear the capability + variables if there is none. */ + term_has_meta = (tgetflag ("km") || tgetflag ("MT")); + if (!term_has_meta) + _rl_term_mm = _rl_term_mo = (char *)NULL; + + /* Attempt to find and bind the arrow keys. Do not override already + bound keys in an overzealous attempt, however. */ + + bind_termcap_arrow_keys (emacs_standard_keymap); + +#if defined (VI_MODE) + bind_termcap_arrow_keys (vi_movement_keymap); + bind_termcap_arrow_keys (vi_insertion_keymap); +#endif /* VI_MODE */ + + return 0; +} + +/* Bind the arrow key sequences from the termcap description in MAP. */ +static void +bind_termcap_arrow_keys (map) + Keymap map; +{ + Keymap xkeymap; + + xkeymap = _rl_keymap; + _rl_keymap = map; + + _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history); + _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history); + _rl_bind_if_unbound (_rl_term_kr, rl_forward); + _rl_bind_if_unbound (_rl_term_kl, rl_backward); + + _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ + _rl_bind_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ + + _rl_keymap = xkeymap; +} + +const char * +rl_get_termcap (cap) + const char *cap; +{ + register unsigned int i; + + if (tcap_initialized == 0) + return ((char *)NULL); + for (i = 0; i < NUM_TC_STRINGS; i++) + { + if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) + return *(tc_strings[i].tc_value); + } + return ((char *)NULL); +} + +/* Re-initialize the terminal considering that the TERM/TERMCAP variable + has changed. */ +int +rl_reset_terminal (terminal_name) + const char *terminal_name; +{ + _rl_init_terminal_io (terminal_name); + return 0; +} + +/* A function for the use of tputs () */ +#ifdef _MINIX +void +_rl_output_character_function (c) + int c; +{ + putc (c, _rl_out_stream); +} +#else /* !_MINIX */ +int +_rl_output_character_function (c) + int c; +{ + return putc (c, _rl_out_stream); +} +#endif /* !_MINIX */ + +/* Write COUNT characters from STRING to the output stream. */ +void +_rl_output_some_chars (string, count) + const char *string; + int count; +{ + fwrite (string, 1, count, _rl_out_stream); +} + +/* Move the cursor back. */ +int +_rl_backspace (count) + int count; +{ + register int i; + + if (_rl_term_backspace) + for (i = 0; i < count; i++) + tputs (_rl_term_backspace, 1, _rl_output_character_function); + else + for (i = 0; i < count; i++) + putc ('\b', _rl_out_stream); + return 0; +} + +/* Move to the start of the next line. */ +int +rl_crlf () +{ +#if defined (NEW_TTY_DRIVER) + if (_rl_term_cr) + tputs (_rl_term_cr, 1, _rl_output_character_function); +#endif /* NEW_TTY_DRIVER */ + putc ('\n', _rl_out_stream); + return 0; +} + +/* Ring the terminal bell. */ +int +rl_ding () +{ + if (readline_echoing_p) + { + switch (_rl_bell_preference) + { + case NO_BELL: + default: + break; + case VISIBLE_BELL: + if (_rl_visible_bell) + { + tputs (_rl_visible_bell, 1, _rl_output_character_function); + break; + } + /* FALLTHROUGH */ + case AUDIBLE_BELL: + fprintf (stderr, "\007"); + fflush (stderr); + break; + } + return (0); + } + return (-1); +} + +/* **************************************************************** */ +/* */ +/* Controlling the Meta Key and Keypad */ +/* */ +/* **************************************************************** */ + +void +_rl_enable_meta_key () +{ +#if !defined (__DJGPP__) + if (term_has_meta && _rl_term_mm) + tputs (_rl_term_mm, 1, _rl_output_character_function); +#endif +} + +void +_rl_control_keypad (on) + int on; +{ +#if !defined (__DJGPP__) + if (on && _rl_term_ks) + tputs (_rl_term_ks, 1, _rl_output_character_function); + else if (!on && _rl_term_ke) + tputs (_rl_term_ke, 1, _rl_output_character_function); +#endif +} + +/* **************************************************************** */ +/* */ +/* Controlling the Cursor */ +/* */ +/* **************************************************************** */ + +/* Set the cursor appropriately depending on IM, which is one of the + insert modes (insert or overwrite). Insert mode gets the normal + cursor. Overwrite mode gets a very visible cursor. Only does + anything if we have both capabilities. */ +void +_rl_set_cursor (im, force) + int im, force; +{ + if (_rl_term_ve && _rl_term_vs) + { + if (force || im != rl_insert_mode) + { + if (im == RL_IM_OVERWRITE) + tputs (_rl_term_vs, 1, _rl_output_character_function); + else + tputs (_rl_term_ve, 1, _rl_output_character_function); + } + } +} diff --git a/cmd-line-utils/readline/text.c b/cmd-line-utils/readline/text.c new file mode 100644 index 00000000000..81a468fdbda --- /dev/null +++ b/cmd-line-utils/readline/text.c @@ -0,0 +1,1540 @@ +/* text.c -- text handling commands for readline. */ + +/* Copyright (C) 1987-2002 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_LOCALE_H) +# include <locale.h> +#endif + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#if defined (__EMX__) +# define INCL_DOSPROCESS +# include <os2.h> +#endif /* __EMX__ */ + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "rlshell.h" +#include "xmalloc.h" + +/* Forward declarations. */ +static int rl_change_case PARAMS((int, int)); +static int _rl_char_search PARAMS((int, int, int)); + +/* **************************************************************** */ +/* */ +/* Insert and Delete */ +/* */ +/* **************************************************************** */ + +/* Insert a string of text into the line at point. This is the only + way that you should do insertion. _rl_insert_char () calls this + function. Returns the number of characters inserted. */ +int +rl_insert_text (string) + const char *string; +{ + register int i, l; + + l = (string && *string) ? strlen (string) : 0; + if (l == 0) + return 0; + + if (rl_end + l >= rl_line_buffer_len) + rl_extend_line_buffer (rl_end + l); + + for (i = rl_end; i >= rl_point; i--) + rl_line_buffer[i + l] = rl_line_buffer[i]; + strncpy (rl_line_buffer + rl_point, string, l); + + /* Remember how to undo this if we aren't undoing something. */ + if (_rl_doing_an_undo == 0) + { + /* If possible and desirable, concatenate the undos. */ + if ((l == 1) && + rl_undo_list && + (rl_undo_list->what == UNDO_INSERT) && + (rl_undo_list->end == rl_point) && + (rl_undo_list->end - rl_undo_list->start < 20)) + rl_undo_list->end++; + else + rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL); + } + rl_point += l; + rl_end += l; + rl_line_buffer[rl_end] = '\0'; + return l; +} + +/* Delete the string between FROM and TO. FROM is inclusive, TO is not. + Returns the number of characters deleted. */ +int +rl_delete_text (from, to) + int from, to; +{ + register char *text; + register int diff, i; + + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + /* fix boundaries */ + if (to > rl_end) + { + to = rl_end; + if (from > to) + from = to; + } + if (from < 0) + from = 0; + + text = rl_copy_text (from, to); + + /* Some versions of strncpy() can't handle overlapping arguments. */ + diff = to - from; + for (i = from; i < rl_end - diff; i++) + rl_line_buffer[i] = rl_line_buffer[i + diff]; + + /* Remember how to undo this delete. */ + if (_rl_doing_an_undo == 0) + rl_add_undo (UNDO_DELETE, from, to, text); + else + free (text); + + rl_end -= diff; + rl_line_buffer[rl_end] = '\0'; + return (diff); +} + +/* Fix up point so that it is within the line boundaries after killing + text. If FIX_MARK_TOO is non-zero, the mark is forced within line + boundaries also. */ + +#define _RL_FIX_POINT(x) \ + do { \ + if (x > rl_end) \ + x = rl_end; \ + else if (x < 0) \ + x = 0; \ + } while (0) + +void +_rl_fix_point (fix_mark_too) + int fix_mark_too; +{ + _RL_FIX_POINT (rl_point); + if (fix_mark_too) + _RL_FIX_POINT (rl_mark); +} +#undef _RL_FIX_POINT + +int +_rl_replace_text (text, start, end) + const char *text; + int start, end; +{ + int n; + + rl_begin_undo_group (); + rl_delete_text (start, end + 1); + rl_point = start; + n = rl_insert_text (text); + rl_end_undo_group (); + + return n; +} + +/* Replace the current line buffer contents with TEXT. If CLEAR_UNDO is + non-zero, we free the current undo list. */ +void +rl_replace_line (text, clear_undo) + const char *text; + int clear_undo; +{ + int len; + + len = strlen (text); + if (len >= rl_line_buffer_len) + rl_extend_line_buffer (len); + strcpy (rl_line_buffer, text); + rl_end = len; + + if (clear_undo) + rl_free_undo_list (); + + _rl_fix_point (1); +} + +/* **************************************************************** */ +/* */ +/* Readline character functions */ +/* */ +/* **************************************************************** */ + +/* This is not a gap editor, just a stupid line input routine. No hair + is involved in writing any of the functions, and none should be. */ + +/* Note that: + + rl_end is the place in the string that we would place '\0'; + i.e., it is always safe to place '\0' there. + + rl_point is the place in the string where the cursor is. Sometimes + this is the same as rl_end. + + Any command that is called interactively receives two arguments. + The first is a count: the numeric arg pased to this command. + The second is the key which invoked this command. +*/ + +/* **************************************************************** */ +/* */ +/* Movement Commands */ +/* */ +/* **************************************************************** */ + +/* Note that if you `optimize' the display for these functions, you cannot + use said functions in other functions which do not do optimizing display. + I.e., you will have to update the data base for rl_redisplay, and you + might as well let rl_redisplay do that job. */ + +/* Move forward COUNT bytes. */ +int +rl_forward_byte (count, key) + int count, key; +{ + if (count < 0) + return (rl_backward_byte (-count, key)); + + if (count > 0) + { + int end = rl_point + count; +#if defined (VI_MODE) + int lend = rl_end > 0 ? rl_end - (rl_editing_mode == vi_mode) : rl_end; +#else + int lend = rl_end; +#endif + + if (end > lend) + { + rl_point = lend; + rl_ding (); + } + else + rl_point = end; + } + + if (rl_end < 0) + rl_end = 0; + + return 0; +} + +#if defined (HANDLE_MULTIBYTE) +/* Move forward COUNT characters. */ +int +rl_forward_char (count, key) + int count, key; +{ + int point; + + if (MB_CUR_MAX == 1 || rl_byte_oriented) + return (rl_forward_byte (count, key)); + + if (count < 0) + return (rl_backward_char (-count, key)); + + if (count > 0) + { + point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + +#if defined (VI_MODE) + if (rl_end <= point && rl_editing_mode == vi_mode) + point = _rl_find_prev_mbchar (rl_line_buffer, rl_end, MB_FIND_NONZERO); +#endif + + if (rl_point == point) + rl_ding (); + + rl_point = point; + + if (rl_end < 0) + rl_end = 0; + } + + return 0; +} +#else /* !HANDLE_MULTIBYTE */ +int +rl_forward_char (count, key) + int count, key; +{ + return (rl_forward_byte (count, key)); +} +#endif /* !HANDLE_MULTIBYTE */ + +/* Backwards compatibility. */ +int +rl_forward (count, key) + int count, key; +{ + return (rl_forward_char (count, key)); +} + +/* Move backward COUNT bytes. */ +int +rl_backward_byte (count, key) + int count, key; +{ + if (count < 0) + return (rl_forward_byte (-count, key)); + + if (count > 0) + { + if (rl_point < count) + { + rl_point = 0; + rl_ding (); + } + else + rl_point -= count; + } + + if (rl_point < 0) + rl_point = 0; + + return 0; +} + +#if defined (HANDLE_MULTIBYTE) +/* Move backward COUNT characters. */ +int +rl_backward_char (count, key) + int count, key; +{ + int point; + + if (MB_CUR_MAX == 1 || rl_byte_oriented) + return (rl_backward_byte (count, key)); + + if (count < 0) + return (rl_forward_char (-count, key)); + + if (count > 0) + { + point = rl_point; + + while (count > 0 && point > 0) + { + point = _rl_find_prev_mbchar (rl_line_buffer, point, MB_FIND_NONZERO); + count--; + } + if (count > 0) + { + rl_point = 0; + rl_ding (); + } + else + rl_point = point; + } + + return 0; +} +#else +int +rl_backward_char (count, key) + int count, key; +{ + return (rl_backward_byte (count, key)); +} +#endif + +/* Backwards compatibility. */ +int +rl_backward (count, key) + int count, key; +{ + return (rl_backward_char (count, key)); +} + +/* Move to the beginning of the line. */ +int +rl_beg_of_line (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_point = 0; + return 0; +} + +/* Move to the end of the line. */ +int +rl_end_of_line (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_point = rl_end; + return 0; +} + +/* XXX - these might need changes for multibyte characters */ +/* Move forward a word. We do what Emacs does. */ +int +rl_forward_word (count, key) + int count, key; +{ + int c; + + if (count < 0) + return (rl_backward_word (-count, key)); + + while (count) + { + if (rl_point == rl_end) + return 0; + + /* If we are not in a word, move forward until we are in one. + Then, move forward until we hit a non-alphabetic character. */ + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c) == 0) + { + while (++rl_point < rl_end) + { + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c)) + break; + } + } + + if (rl_point == rl_end) + return 0; + + while (++rl_point < rl_end) + { + c = rl_line_buffer[rl_point]; + if (rl_alphabetic (c) == 0) + break; + } + --count; + } + + return 0; +} + +/* Move backward a word. We do what Emacs does. */ +int +rl_backward_word (count, key) + int count, key; +{ + int c; + + if (count < 0) + return (rl_forward_word (-count, key)); + + while (count) + { + if (!rl_point) + return 0; + + /* Like rl_forward_word (), except that we look at the characters + just before point. */ + + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c) == 0) + { + while (--rl_point) + { + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c)) + break; + } + } + + while (rl_point) + { + c = rl_line_buffer[rl_point - 1]; + if (rl_alphabetic (c) == 0) + break; + else + --rl_point; + } + + --count; + } + + return 0; +} + +/* Clear the current line. Numeric argument to C-l does this. */ +int +rl_refresh_line (ignore1, ignore2) + int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); +{ + int curr_line; + + curr_line = _rl_current_display_line (); + + _rl_move_vert (curr_line); + _rl_move_cursor_relative (0, rl_line_buffer); /* XXX is this right */ + + _rl_clear_to_eol (0); /* arg of 0 means to not use spaces */ + + rl_forced_update_display (); + rl_display_fixed = 1; + + return 0; +} + +/* C-l typed to a line without quoting clears the screen, and then reprints + the prompt and the current input line. Given a numeric arg, redraw only + the current line. */ +int +rl_clear_screen (count, key) + int count, key; +{ + if (rl_explicit_arg) + { + rl_refresh_line (count, key); + return 0; + } + + _rl_clear_screen (); /* calls termcap function to clear screen */ + rl_forced_update_display (); + rl_display_fixed = 1; + + return 0; +} + +int +rl_arrow_keys (count, c) + int count, c __attribute__((unused)); +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + switch (_rl_to_upper (ch)) + { + case 'A': + rl_get_previous_history (count, ch); + break; + + case 'B': + rl_get_next_history (count, ch); + break; + + case 'C': + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_forward_char (count, ch); + else + rl_forward_byte (count, ch); + break; + + case 'D': + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, ch); + else + rl_backward_byte (count, ch); + break; + + default: + rl_ding (); + } + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Text commands */ +/* */ +/* **************************************************************** */ + +#ifdef HANDLE_MULTIBYTE +static char pending_bytes[MB_LEN_MAX]; +static int pending_bytes_length = 0; +static mbstate_t ps = {0}; +#endif + +/* Insert the character C at the current location, moving point forward. + If C introduces a multibyte sequence, we read the whole sequence and + then insert the multibyte char into the line buffer. */ +int +_rl_insert_char (count, c) + int count, c; +{ + register int i; + char *string; +#ifdef HANDLE_MULTIBYTE + int string_size; + char incoming[MB_LEN_MAX + 1]; + int incoming_length = 0; + mbstate_t ps_back; + static int stored_count = 0; +#endif + + if (count <= 0) + return 0; + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { + incoming[0] = c; + incoming[1] = '\0'; + incoming_length = 1; + } + else + { + wchar_t wc; + size_t ret; + + if (stored_count <= 0) + stored_count = count; + else + count = stored_count; + + ps_back = ps; + pending_bytes[pending_bytes_length++] = c; + ret = mbrtowc (&wc, pending_bytes, pending_bytes_length, &ps); + + if (ret == (size_t)-2) + { + /* Bytes too short to compose character, try to wait for next byte. + Restore the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + ps = ps_back; + return 1; + } + else if (ret == (size_t)-1) + { + /* Invalid byte sequence for the current locale. Treat first byte + as a single character. */ + incoming[0] = pending_bytes[0]; + incoming[1] = '\0'; + incoming_length = 1; + pending_bytes_length--; + memmove (pending_bytes, pending_bytes + 1, pending_bytes_length); + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else if (ret == (size_t)0) + { + incoming[0] = '\0'; + incoming_length = 0; + pending_bytes_length--; + /* Clear the state of the byte sequence, because in this case the + effect of mbstate is undefined. */ + memset (&ps, 0, sizeof (mbstate_t)); + } + else + { + /* We successfully read a single multibyte character. */ + memcpy (incoming, pending_bytes, pending_bytes_length); + incoming[pending_bytes_length] = '\0'; + incoming_length = pending_bytes_length; + pending_bytes_length = 0; + } + } +#endif /* HANDLE_MULTIBYTE */ + + /* If we can optimize, then do it. But don't let people crash + readline because of extra large arguments. */ + if (count > 1 && count <= 1024) + { +#if defined (HANDLE_MULTIBYTE) + string_size = count * incoming_length; + string = (char *)xmalloc (1 + string_size); + + i = 0; + while (i < string_size) + { + strncpy (string + i, incoming, incoming_length); + i += incoming_length; + } + incoming_length = 0; + stored_count = 0; +#else /* !HANDLE_MULTIBYTE */ + string = (char *)xmalloc (1 + count); + + for (i = 0; i < count; i++) + string[i] = c; +#endif /* !HANDLE_MULTIBYTE */ + + string[i] = '\0'; + rl_insert_text (string); + free (string); + + return 0; + } + + if (count > 1024) + { + int decreaser; +#if defined (HANDLE_MULTIBYTE) + string_size = incoming_length * 1024; + string = (char *)xmalloc (1 + string_size); + + i = 0; + while (i < string_size) + { + strncpy (string + i, incoming, incoming_length); + i += incoming_length; + } + + while (count) + { + decreaser = (count > 1024) ? 1024 : count; + string[decreaser*incoming_length] = '\0'; + rl_insert_text (string); + count -= decreaser; + } + + free (string); + incoming_length = 0; + stored_count = 0; +#else /* !HANDLE_MULTIBYTE */ + char str[1024+1]; + + for (i = 0; i < 1024; i++) + str[i] = c; + + while (count) + { + decreaser = (count > 1024 ? 1024 : count); + str[decreaser] = '\0'; + rl_insert_text (str); + count -= decreaser; + } +#endif /* !HANDLE_MULTIBYTE */ + + return 0; + } + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { +#endif + /* We are inserting a single character. + If there is pending input, then make a string of all of the + pending characters that are bound to rl_insert, and insert + them all. */ + if (_rl_any_typein ()) + _rl_insert_typein (c); + else + { + /* Inserting a single character. */ + char str[2]; + + str[1] = '\0'; + str[0] = c; + rl_insert_text (str); + } +#if defined (HANDLE_MULTIBYTE) + } + else + { + rl_insert_text (incoming); + stored_count = 0; + } +#endif + + return 0; +} + +/* Overwrite the character at point (or next COUNT characters) with C. + If C introduces a multibyte character sequence, read the entire sequence + before starting the overwrite loop. */ +int +_rl_overwrite_char (count, c) + int count, c; +{ + int i; +#if defined (HANDLE_MULTIBYTE) + char mbkey[MB_LEN_MAX]; + int k; + + /* Read an entire multibyte character sequence to insert COUNT times. */ + if (count > 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0) + k = _rl_read_mbstring (c, mbkey, MB_LEN_MAX); +#endif + + for (i = 0; i < count; i++) + { + rl_begin_undo_group (); + + if (rl_point < rl_end) + rl_delete (1, c); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_insert_text (mbkey); + else +#endif + _rl_insert_char (1, c); + + rl_end_undo_group (); + } + + return 0; +} + +int +rl_insert (count, c) + int count, c; +{ + return (rl_insert_mode == RL_IM_INSERT ? _rl_insert_char (count, c) + : _rl_overwrite_char (count, c)); +} + +/* Insert the next typed character verbatim. */ +int +rl_quoted_insert (count, key) + int count, key __attribute__((unused)); +{ + int c; + +#if defined (HANDLE_SIGNALS) + _rl_disable_tty_signals (); +#endif + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + +#if defined (HANDLE_SIGNALS) + _rl_restore_tty_signals (); +#endif + + return (_rl_insert_char (count, c)); +} + +/* Insert a tab character. */ +int +rl_tab_insert (count, key) + int count, key __attribute__((unused)); +{ + return (_rl_insert_char (count, '\t')); +} + +/* What to do when a NEWLINE is pressed. We accept the whole line. + KEY is the key that invoked this command. I guess it could have + meaning in the future. */ +int +rl_newline (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + rl_done = 1; + + if (_rl_history_preserve_point) + _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; + + RL_SETSTATE(RL_STATE_DONE); + +#if defined (VI_MODE) + if (rl_editing_mode == vi_mode) + { + _rl_vi_done_inserting (); + _rl_vi_reset_last (); + } +#endif /* VI_MODE */ + + /* If we've been asked to erase empty lines, suppress the final update, + since _rl_update_final calls rl_crlf(). */ + if (rl_erase_empty_line && rl_point == 0 && rl_end == 0) + return 0; + + if (readline_echoing_p) + _rl_update_final (); + return 0; +} + +/* What to do for some uppercase characters, like meta characters, + and some characters appearing in emacs_ctlx_keymap. This function + is just a stub, you bind keys to it and the code in _rl_dispatch () + is special cased. */ +int +rl_do_lowercase_version (ignore1, ignore2) + int ignore1 __attribute__((unused)), ignore2 __attribute__((unused)); +{ + return 0; +} + +/* This is different from what vi does, so the code's not shared. Emacs + rubout in overwrite mode has one oddity: it replaces a control + character that's displayed as two characters (^X) with two spaces. */ +int +_rl_overwrite_rubout (count, key) + int count, key; +{ + int opoint; + int i, l; + + if (rl_point == 0) + { + rl_ding (); + return 1; + } + + opoint = rl_point; + + /* L == number of spaces to insert */ + for (i = l = 0; i < count; i++) + { + rl_backward_char (1, key); + l += rl_character_len (rl_line_buffer[rl_point], rl_point); /* not exactly right */ + } + + rl_begin_undo_group (); + + if (count > 1 || rl_explicit_arg) + rl_kill_text (opoint, rl_point); + else + rl_delete_text (opoint, rl_point); + + /* Emacs puts point at the beginning of the sequence of spaces. */ + opoint = rl_point; + _rl_insert_char (l, ' '); + rl_point = opoint; + + rl_end_undo_group (); + + return 0; +} + +/* Rubout the character behind point. */ +int +rl_rubout (count, key) + int count, key; +{ + if (count < 0) + return (rl_delete (-count, key)); + + if (!rl_point) + { + rl_ding (); + return -1; + } + + if (rl_insert_mode == RL_IM_OVERWRITE) + return (_rl_overwrite_rubout (count, key)); + + return (_rl_rubout_char (count, key)); +} + +int +_rl_rubout_char (count, key) + int count, key; +{ + int orig_point; + unsigned char c; + + /* Duplicated code because this is called from other parts of the library. */ + if (count < 0) + return (rl_delete (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return -1; + } + + if (count > 1 || rl_explicit_arg) + { + orig_point = rl_point; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_backward_char (count, key); + else +#endif + rl_backward_byte (count, key); + rl_kill_text (orig_point, rl_point); + } + else + { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) + { +#endif + c = rl_line_buffer[--rl_point]; + rl_delete_text (rl_point, rl_point + 1); +#if defined (HANDLE_MULTIBYTE) + } + else + { + int orig_point; + + orig_point = rl_point; + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + c = rl_line_buffer[rl_point]; + rl_delete_text (rl_point, orig_point); + } +#endif /* HANDLE_MULTIBYTE */ + + /* I don't think that the hack for end of line is needed for + multibyte chars. */ +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX == 1 || rl_byte_oriented) +#endif + if (rl_point == rl_end && ISPRINT (c) && _rl_last_c_pos) + { + int l; + l = rl_character_len (c, rl_point); + _rl_erase_at_end_of_line (l); + } + } + + return 0; +} + +/* Delete the character under the cursor. Given a numeric argument, + kill that many characters instead. */ +int +rl_delete (count, key) + int count, key; +{ + int r; + + if (count < 0) + return (_rl_rubout_char (-count, key)); + + if (rl_point == rl_end) + { + rl_ding (); + return -1; + } + + if (count > 1 || rl_explicit_arg) + { + int orig_point = rl_point; +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_forward_char (count, key); + else +#endif + rl_forward_byte (count, key); + + r = rl_kill_text (orig_point, rl_point); + rl_point = orig_point; + return r; + } + else + { + int new_point; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + new_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); + else + new_point = rl_point + 1; + + return (rl_delete_text (rl_point, new_point)); + } +} + +/* Delete the character under the cursor, unless the insertion + point is at the end of the line, in which case the character + behind the cursor is deleted. COUNT is obeyed and may be used + to delete forward or backward that many characters. */ +int +rl_rubout_or_delete (count, key) + int count, key; +{ + if (rl_end != 0 && rl_point == rl_end) + return (_rl_rubout_char (count, key)); + else + return (rl_delete (count, key)); +} + +/* Delete all spaces and tabs around point. */ +int +rl_delete_horizontal_space (count, ignore) + int count __attribute__((unused)), ignore __attribute__((unused)); +{ + int start = rl_point; + + while (rl_point && whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + start = rl_point; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (start != rl_point) + { + rl_delete_text (start, rl_point); + rl_point = start; + } + return 0; +} + +/* Like the tcsh editing function delete-char-or-list. The eof character + is caught before this is invoked, so this really does the same thing as + delete-char-or-list-or-eof, as long as it's bound to the eof character. */ +int +rl_delete_or_show_completions (count, key) + int count, key; +{ + if (rl_end != 0 && rl_point == rl_end) + return (rl_possible_completions (count, key)); + else + return (rl_delete (count, key)); +} + +#ifndef RL_COMMENT_BEGIN_DEFAULT +#define RL_COMMENT_BEGIN_DEFAULT "#" +#endif + +/* Turn the current line into a comment in shell history. + A K*rn shell style function. */ +int +rl_insert_comment (count, key) + int count __attribute__((unused)), key; +{ + const char *rl_comment_text; + int rl_comment_len; + + rl_beg_of_line (1, key); + rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT; + + if (rl_explicit_arg == 0) + rl_insert_text (rl_comment_text); + else + { + rl_comment_len = strlen (rl_comment_text); + if (STREQN (rl_comment_text, rl_line_buffer, rl_comment_len)) + rl_delete_text (rl_point, rl_point + rl_comment_len); + else + rl_insert_text (rl_comment_text); + } + + (*rl_redisplay_function) (); + rl_newline (1, '\n'); + + return (0); +} + +/* **************************************************************** */ +/* */ +/* Changing Case */ +/* */ +/* **************************************************************** */ + +/* The three kinds of things that we know how to do. */ +#define UpCase 1 +#define DownCase 2 +#define CapCase 3 + +/* Uppercase the word at point. */ +int +rl_upcase_word (count, key) + int count, key __attribute__((unused)); +{ + return (rl_change_case (count, UpCase)); +} + +/* Lowercase the word at point. */ +int +rl_downcase_word (count, key) + int count, key __attribute__((unused)); +{ + return (rl_change_case (count, DownCase)); +} + +/* Upcase the first letter, downcase the rest. */ +int +rl_capitalize_word (count, key) + int count, key __attribute__((unused)); +{ + return (rl_change_case (count, CapCase)); +} + +/* The meaty function. + Change the case of COUNT words, performing OP on them. + OP is one of UpCase, DownCase, or CapCase. + If a negative argument is given, leave point where it started, + otherwise, leave it where it moves to. */ +static int +rl_change_case (count, op) + int count, op; +{ + register int start, end; + int inword, c; + + start = rl_point; + rl_forward_word (count, 0); + end = rl_point; + + if (count < 0) + SWAP (start, end); + + /* We are going to modify some text, so let's prepare to undo it. */ + rl_modifying (start, end); + + for (inword = 0; start < end; start++) + { + c = rl_line_buffer[start]; + switch (op) + { + case UpCase: + rl_line_buffer[start] = _rl_to_upper (c); + break; + + case DownCase: + rl_line_buffer[start] = _rl_to_lower (c); + break; + + case CapCase: + rl_line_buffer[start] = (inword == 0) ? _rl_to_upper (c) : _rl_to_lower (c); + inword = rl_alphabetic (rl_line_buffer[start]); + break; + + default: + rl_ding (); + return -1; + } + } + rl_point = end; + return 0; +} + +/* **************************************************************** */ +/* */ +/* Transposition */ +/* */ +/* **************************************************************** */ + +/* Transpose the words at point. If point is at the end of the line, + transpose the two words before point. */ +int +rl_transpose_words (count, key) + int count, key; +{ + char *word1, *word2; + int w1_beg, w1_end, w2_beg, w2_end; + int orig_point = rl_point; + + if (!count) + return 0; + + /* Find the two words. */ + rl_forward_word (count, key); + w2_end = rl_point; + rl_backward_word (1, key); + w2_beg = rl_point; + rl_backward_word (count, key); + w1_beg = rl_point; + rl_forward_word (1, key); + w1_end = rl_point; + + /* Do some check to make sure that there really are two words. */ + if ((w1_beg == w2_beg) || (w2_beg < w1_end)) + { + rl_ding (); + rl_point = orig_point; + return -1; + } + + /* Get the text of the words. */ + word1 = rl_copy_text (w1_beg, w1_end); + word2 = rl_copy_text (w2_beg, w2_end); + + /* We are about to do many insertions and deletions. Remember them + as one operation. */ + rl_begin_undo_group (); + + /* Do the stuff at word2 first, so that we don't have to worry + about word1 moving. */ + rl_point = w2_beg; + rl_delete_text (w2_beg, w2_end); + rl_insert_text (word1); + + rl_point = w1_beg; + rl_delete_text (w1_beg, w1_end); + rl_insert_text (word2); + + /* This is exactly correct since the text before this point has not + changed in length. */ + rl_point = w2_end; + + /* I think that does it. */ + rl_end_undo_group (); + free (word1); + free (word2); + + return 0; +} + +/* Transpose the characters at point. If point is at the end of the line, + then transpose the characters before point. */ +int +rl_transpose_chars (count, key) + int count, key __attribute__((unused)); +{ +#if defined (HANDLE_MULTIBYTE) + char *dummy; + int i, prev_point; +#else + char dummy[2]; +#endif + int char_length; + + if (count == 0) + return 0; + + if (!rl_point || rl_end < 2) + { + rl_ding (); + return -1; + } + + rl_begin_undo_group (); + + if (rl_point == rl_end) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + --rl_point; + count = 1; + } + +#if defined (HANDLE_MULTIBYTE) + prev_point = rl_point; + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else +#endif + rl_point--; + +#if defined (HANDLE_MULTIBYTE) + char_length = prev_point - rl_point; + dummy = (char *)xmalloc (char_length + 1); + for (i = 0; i < char_length; i++) + dummy[i] = rl_line_buffer[rl_point + i]; + dummy[i] = '\0'; +#else + dummy[0] = rl_line_buffer[rl_point]; + dummy[char_length = 1] = '\0'; +#endif + + rl_delete_text (rl_point, rl_point + char_length); + + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + + _rl_fix_point (0); + rl_insert_text (dummy); + rl_end_undo_group (); + +#if defined (HANDLE_MULTIBYTE) + free (dummy); +#endif + + return 0; +} + +/* **************************************************************** */ +/* */ +/* Character Searching */ +/* */ +/* **************************************************************** */ + +int +#if defined (HANDLE_MULTIBYTE) +_rl_char_search_internal (count, dir, smbchar, len) + int count, dir; + char *smbchar; + int len; +#else +_rl_char_search_internal (count, dir, schar) + int count, dir, schar; +#endif +{ + int pos, inc; +#if defined (HANDLE_MULTIBYTE) + int prepos; +#endif + + pos = rl_point; + inc = (dir < 0) ? -1 : 1; + while (count) + { + if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= rl_end)) + { + rl_ding (); + return -1; + } + +#if defined (HANDLE_MULTIBYTE) + pos = (inc > 0) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) + : _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); +#else + pos += inc; +#endif + do + { +#if defined (HANDLE_MULTIBYTE) + if (_rl_is_mbchar_matched (rl_line_buffer, pos, rl_end, smbchar, len)) +#else + if (rl_line_buffer[pos] == schar) +#endif + { + count--; + if (dir < 0) + rl_point = (dir == BTO) ? _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY) + : pos; + else + rl_point = (dir == FTO) ? _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY) + : pos; + break; + } +#if defined (HANDLE_MULTIBYTE) + prepos = pos; +#endif + } +#if defined (HANDLE_MULTIBYTE) + while ((dir < 0) ? (pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY)) != prepos + : (pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos); +#else + while ((dir < 0) ? pos-- : ++pos < rl_end); +#endif + } + return (0); +} + +/* Search COUNT times for a character read from the current input stream. + FDIR is the direction to search if COUNT is non-negative; otherwise + the search goes in BDIR. So much is dependent on HANDLE_MULTIBYTE + that there are two separate versions of this function. */ +#if defined (HANDLE_MULTIBYTE) +static int +_rl_char_search (count, fdir, bdir) + int count, fdir, bdir; +{ + char mbchar[MB_LEN_MAX]; + int mb_len; + + mb_len = _rl_read_mbchar (mbchar, MB_LEN_MAX); + + if (count < 0) + return (_rl_char_search_internal (-count, bdir, mbchar, mb_len)); + else + return (_rl_char_search_internal (count, fdir, mbchar, mb_len)); +} +#else /* !HANDLE_MULTIBYTE */ +static int +_rl_char_search (count, fdir, bdir) + int count, fdir, bdir; +{ + int c; + + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (count < 0) + return (_rl_char_search_internal (-count, bdir, c)); + else + return (_rl_char_search_internal (count, fdir, c)); +} +#endif /* !HANDLE_MULTIBYTE */ + +int +rl_char_search (count, key) + int count, key __attribute__((unused)); +{ + return (_rl_char_search (count, FFIND, BFIND)); +} + +int +rl_backward_char_search (count, key) + int count, key __attribute__((unused)); +{ + return (_rl_char_search (count, BFIND, FFIND)); +} + +/* **************************************************************** */ +/* */ +/* The Mark and the Region. */ +/* */ +/* **************************************************************** */ + +/* Set the mark at POSITION. */ +int +_rl_set_mark_at_pos (position) + int position; +{ + if (position > rl_end) + return -1; + + rl_mark = position; + return 0; +} + +/* A bindable command to set the mark. */ +int +rl_set_mark (count, key) + int count, key __attribute__((unused)); +{ + return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point)); +} + +/* Exchange the position of mark and point. */ +int +rl_exchange_point_and_mark (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (rl_mark > rl_end) + rl_mark = -1; + + if (rl_mark == -1) + { + rl_ding (); + return -1; + } + else + SWAP (rl_point, rl_mark); + + return 0; +} diff --git a/cmd-line-utils/readline/tilde.c b/cmd-line-utils/readline/tilde.c new file mode 100644 index 00000000000..fab4aab65ad --- /dev/null +++ b/cmd-line-utils/readline/tilde.c @@ -0,0 +1,458 @@ +/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include <sys/types.h> +# endif +# include <unistd.h> +#endif + +#if defined (HAVE_STRING_H) +# include <string.h> +#else /* !HAVE_STRING_H */ +# include <strings.h> +#endif /* !HAVE_STRING_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <sys/types.h> +#include <pwd.h> + +#include "tilde.h" + +#if defined (TEST) || defined (STATIC_MALLOC) +static void *xmalloc (), *xrealloc (); +#else +# include "xmalloc.h" +#endif /* TEST || STATIC_MALLOC */ + +#if !defined (HAVE_GETPW_DECLS) +extern struct passwd *getpwuid PARAMS((uid_t)); +extern struct passwd *getpwnam PARAMS((const char *)); +#endif /* !HAVE_GETPW_DECLS */ + +#if !defined (savestring) +#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x)) +#endif /* !savestring */ + +#if !defined (NULL) +# if defined (__STDC__) +# define NULL ((void *) 0) +# else +# define NULL 0x0 +# endif /* !__STDC__ */ +#endif /* !NULL */ + +/* If being compiled as part of bash, these will be satisfied from + variables.o. If being compiled as part of readline, they will + be satisfied from shell.o. */ +extern char *sh_get_home_dir PARAMS((void)); +extern char *sh_get_env_value PARAMS((const char *)); + +/* The default value of tilde_additional_prefixes. This is set to + whitespace preceding a tilde so that simple programs which do not + perform any word separation get desired behaviour. */ +static const char *default_prefixes[] = + { " ~", "\t~", (const char *)NULL }; + +/* The default value of tilde_additional_suffixes. This is set to + whitespace or newline so that simple programs which do not + perform any word separation get desired behaviour. */ +static const char *default_suffixes[] = + { " ", "\n", (const char *)NULL }; + +/* If non-null, this contains the address of a function that the application + wants called before trying the standard tilde expansions. The function + is called with the text sans tilde, and returns a malloc()'ed string + which is the expansion, or a NULL pointer if the expansion fails. */ +tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +char **tilde_additional_prefixes = (char **)default_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +char **tilde_additional_suffixes = (char **)default_suffixes; + +static int tilde_find_prefix PARAMS((const char *, int *)); +static int tilde_find_suffix PARAMS((const char *)); +static char *isolate_tilde_prefix PARAMS((const char *, int *)); +static char *glue_prefix_and_suffix PARAMS((char *, const char *, int)); + +/* Find the start of a tilde expansion in STRING, and return the index of + the tilde which starts the expansion. Place the length of the text + which identified this tilde starter in LEN, excluding the tilde itself. */ +static int +tilde_find_prefix (string, len) + const char *string; + int *len; +{ + register int i, j, string_len; + register char **prefixes; + + prefixes = tilde_additional_prefixes; + + string_len = strlen (string); + *len = 0; + + if (*string == '\0' || *string == '~') + return (0); + + if (prefixes) + { + for (i = 0; i < string_len; i++) + { + for (j = 0; prefixes[j]; j++) + { + if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0) + { + *len = strlen (prefixes[j]) - 1; + return (i + *len); + } + } + } + } + return (string_len); +} + +/* Find the end of a tilde expansion in STRING, and return the index of + the character which ends the tilde definition. */ +static int +tilde_find_suffix (string) + const char *string; +{ + register int i, j, string_len; + register char **suffixes; + + suffixes = tilde_additional_suffixes; + string_len = strlen (string); + + for (i = 0; i < string_len; i++) + { +#if defined (__MSDOS__) + if (string[i] == '/' || string[i] == '\\' /* || !string[i] */) +#else + if (string[i] == '/' /* || !string[i] */) +#endif + break; + + for (j = 0; suffixes && suffixes[j]; j++) + { + if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0) + return (i); + } + } + return (i); +} + +/* Return a new string which is the result of tilde expanding STRING. */ +char * +tilde_expand (string) + const char *string; +{ + char *result; + int result_size, result_index; + + result_index = result_size = 0; + if ((result = strchr(string, '~'))) + result = (char *)xmalloc (result_size = (strlen (string) + 16)); + else + result = (char *)xmalloc (result_size = (strlen (string) + 1)); + + /* Scan through STRING expanding tildes as we come to them. */ + while (1) + { + register int start, end; + char *tilde_word, *expansion; + int len; + + /* Make START point to the tilde which starts the expansion. */ + start = tilde_find_prefix (string, &len); + + /* Copy the skipped text into the result. */ + if ((result_index + start + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (start + 20))); + + strncpy (result + result_index, string, start); + result_index += start; + + /* Advance STRING to the starting tilde. */ + string += start; + + /* Make END be the index of one after the last character of the + username. */ + end = tilde_find_suffix (string); + + /* If both START and END are zero, we are all done. */ + if (!start && !end) + break; + + /* Expand the entire tilde word, and copy it into RESULT. */ + tilde_word = (char *)xmalloc (1 + end); + strncpy (tilde_word, string, end); + tilde_word[end] = '\0'; + string += end; + + expansion = tilde_expand_word (tilde_word); + free (tilde_word); + + len = strlen (expansion); +#ifdef __CYGWIN__ + /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when + $HOME for `user' is /. On cygwin, // denotes a network drive. */ + if (len > 1 || *expansion != '/' || *string != '/') +#endif + { + if ((result_index + len + 1) > result_size) + result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); + + strcpy (result + result_index, expansion); + result_index += len; + } + free (expansion); + } + + result[result_index] = '\0'; + + return (result); +} + +/* Take FNAME and return the tilde prefix we want expanded. If LENP is + non-null, the index of the end of the prefix into FNAME is returned in + the location it points to. */ +static char * +isolate_tilde_prefix (fname, lenp) + const char *fname; + int *lenp; +{ + char *ret; + int i; + + ret = (char *)xmalloc (strlen (fname)); +#if defined (__MSDOS__) + for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++) +#else + for (i = 1; fname[i] && fname[i] != '/'; i++) +#endif + ret[i - 1] = fname[i]; + ret[i - 1] = '\0'; + if (lenp) + *lenp = i; + return ret; +} + +/* Return a string that is PREFIX concatenated with SUFFIX starting at + SUFFIND. */ +static char * +glue_prefix_and_suffix (prefix, suffix, suffind) + char *prefix; + const char *suffix; + int suffind; +{ + char *ret; + int plen, slen; + + plen = (prefix && *prefix) ? strlen (prefix) : 0; + slen = strlen (suffix + suffind); + ret = (char *)xmalloc (plen + slen + 1); + if (plen) + strcpy (ret, prefix); + strcpy (ret + plen, suffix + suffind); + return ret; +} + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. + This always returns a newly-allocated string, never static storage. */ +char * +tilde_expand_word (filename) + const char *filename; +{ + char *dirname, *expansion, *username; + int user_len; + struct passwd *user_entry; + + if (filename == 0) + return ((char *)NULL); + + if (*filename != '~') + return (savestring (filename)); + + /* A leading `~/' or a bare `~' is *always* translated to the value of + $HOME or the home directory of the current user, regardless of any + preexpansion hook. */ + if (filename[1] == '\0' || filename[1] == '/') + { + /* Prefix $HOME to the rest of the string. */ + expansion = sh_get_env_value ("HOME"); + + /* If there is no HOME variable, look up the directory in + the password database. */ + if (expansion == 0) + expansion = sh_get_home_dir (); + + return (glue_prefix_and_suffix (expansion, filename, 1)); + } + + username = isolate_tilde_prefix (filename, &user_len); + + if (tilde_expansion_preexpansion_hook) + { + expansion = (*tilde_expansion_preexpansion_hook) (username); + if (expansion) + { + dirname = glue_prefix_and_suffix (expansion, filename, user_len); + free (username); + free (expansion); + return (dirname); + } + } + + /* No preexpansion hook, or the preexpansion hook failed. Look in the + password database. */ + dirname = (char *)NULL; + user_entry = getpwnam (username); + if (user_entry == 0) + { + /* If the calling program has a special syntax for expanding tildes, + and we couldn't find a standard expansion, then let them try. */ + if (tilde_expansion_failure_hook) + { + expansion = (*tilde_expansion_failure_hook) (username); + if (expansion) + { + dirname = glue_prefix_and_suffix (expansion, filename, user_len); + free (expansion); + } + } + free (username); + /* If we don't have a failure hook, or if the failure hook did not + expand the tilde, return a copy of what we were passed. */ + if (dirname == 0) + dirname = savestring (filename); + } + else + { + free (username); + dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len); + } + + endpwent (); + return (dirname); +} + + +#if defined (TEST) +#undef NULL +#include <stdio.h> + +main (argc, argv) + int argc; + char **argv; +{ + char *result, line[512]; + int done = 0; + + while (!done) + { + printf ("~expand: "); + fflush (stdout); + + if (!gets (line)) + strcpy (line, "done"); + + if ((strcmp (line, "done") == 0) || + (strcmp (line, "quit") == 0) || + (strcmp (line, "exit") == 0)) + { + done = 1; + break; + } + + result = tilde_expand (line); + printf (" --> %s\n", result); + free (result); + } + exit (0); +} + +static void memory_error_and_abort (); + +static void * +xmalloc (bytes) + size_t bytes; +{ + void *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static void * +xrealloc (pointer, bytes) + void *pointer; + int bytes; +{ + void *temp; + + if (!pointer) + temp = malloc (bytes); + else + temp = realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + + return (temp); +} + +static void +memory_error_and_abort () +{ + fprintf (stderr, "readline: out of virtual memory\n"); + abort (); +} + +/* + * Local variables: + * compile-command: "gcc -g -DTEST -o tilde tilde.c" + * end: + */ +#endif /* TEST */ diff --git a/cmd-line-utils/readline/tilde.h b/cmd-line-utils/readline/tilde.h new file mode 100644 index 00000000000..f8182c999d9 --- /dev/null +++ b/cmd-line-utils/readline/tilde.h @@ -0,0 +1,78 @@ +/* tilde.h: Externally available variables and function in libtilde.a. */ + +/* Copyright (C) 1992 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_TILDE_H_) +# define _TILDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* A function can be defined using prototypes and compile on both ANSI C + and traditional C compilers with something like this: + extern char *func PARAMS((char *, char *, int)); */ + +#if !defined (PARAMS) +# if defined (__STDC__) || defined (__GNUC__) || defined (__cplusplus) +# define PARAMS(protos) protos +# else +# define PARAMS(protos) () +# endif +#endif + +typedef char *tilde_hook_func_t PARAMS((char *)); + +/* If non-null, this contains the address of a function that the application + wants called before trying the standard tilde expansions. The function + is called with the text sans tilde, and returns a malloc()'ed string + which is the expansion, or a NULL pointer if the expansion fails. */ +extern tilde_hook_func_t *tilde_expansion_preexpansion_hook; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern tilde_hook_func_t *tilde_expansion_failure_hook; + +/* When non-null, this is a NULL terminated array of strings which + are duplicates for a tilde prefix. Bash uses this to expand + `=~' and `:~'. */ +extern char **tilde_additional_prefixes; + +/* When non-null, this is a NULL terminated array of strings which match + the end of a username, instead of just "/". Bash sets this to + `:' and `=~'. */ +extern char **tilde_additional_suffixes; + +/* Return a new string which is the result of tilde expanding STRING. */ +extern char *tilde_expand PARAMS((const char *)); + +/* Do the work of tilde expansion on FILENAME. FILENAME starts with a + tilde. If there is no expansion, call tilde_expansion_failure_hook. */ +extern char *tilde_expand_word PARAMS((const char *)); + +#ifdef __cplusplus +} +#endif + +#endif /* _TILDE_H_ */ diff --git a/cmd-line-utils/readline/undo.c b/cmd-line-utils/readline/undo.c new file mode 100644 index 00000000000..df913195fad --- /dev/null +++ b/cmd-line-utils/readline/undo.c @@ -0,0 +1,264 @@ +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +/* Some standard library routines. */ +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* Non-zero tells rl_delete_text and rl_insert_text to not add to + the undo list. */ +int _rl_doing_an_undo = 0; + +/* How many unclosed undo groups we currently have. */ +int _rl_undo_group_level = 0; + +/* The current undo list for THE_LINE. */ +UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL; + +/* **************************************************************** */ +/* */ +/* Undo, and Undoing */ +/* */ +/* **************************************************************** */ + +/* Remember how to undo something. Concatenate some undos if that + seems right. */ +void +rl_add_undo (what, start, end, text) + enum undo_code what; + int start, end; + char *text; +{ + UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST)); + temp->what = what; + temp->start = start; + temp->end = end; + temp->text = text; + temp->next = rl_undo_list; + rl_undo_list = temp; +} + +/* Free the existing undo list. */ +void +rl_free_undo_list () +{ + while (rl_undo_list) + { + UNDO_LIST *release = rl_undo_list; + rl_undo_list = rl_undo_list->next; + + if (release->what == UNDO_DELETE) + free (release->text); + + free (release); + } + rl_undo_list = (UNDO_LIST *)NULL; +} + +/* Undo the next thing in the list. Return 0 if there + is nothing to undo, or non-zero if there was. */ +int +rl_do_undo () +{ + UNDO_LIST *release; + int waiting_for_begin, start, end; + +#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i))) + + start = end = waiting_for_begin = 0; + do + { + if (!rl_undo_list) + return (0); + + _rl_doing_an_undo = 1; + RL_SETSTATE(RL_STATE_UNDOING); + + /* To better support vi-mode, a start or end value of -1 means + rl_point, and a value of -2 means rl_end. */ + if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT) + { + start = TRANS (rl_undo_list->start); + end = TRANS (rl_undo_list->end); + } + + switch (rl_undo_list->what) + { + /* Undoing deletes means inserting some text. */ + case UNDO_DELETE: + rl_point = start; + rl_insert_text (rl_undo_list->text); + free (rl_undo_list->text); + break; + + /* Undoing inserts means deleting some text. */ + case UNDO_INSERT: + rl_delete_text (start, end); + rl_point = start; + break; + + /* Undoing an END means undoing everything 'til we get to a BEGIN. */ + case UNDO_END: + waiting_for_begin++; + break; + + /* Undoing a BEGIN means that we are done with this group. */ + case UNDO_BEGIN: + if (waiting_for_begin) + waiting_for_begin--; + else + rl_ding (); + break; + } + + _rl_doing_an_undo = 0; + RL_UNSETSTATE(RL_STATE_UNDOING); + + release = rl_undo_list; + rl_undo_list = rl_undo_list->next; + free (release); + } + while (waiting_for_begin); + + return (1); +} +#undef TRANS + +int +_rl_fix_last_undo_of_type (type, start, end) + unsigned int type; + int start, end; +{ + UNDO_LIST *rl; + + for (rl = rl_undo_list; rl; rl = rl->next) + { + if (rl->what == type) + { + rl->start = start; + rl->end = end; + return 0; + } + } + return 1; +} + +/* Begin a group. Subsequent undos are undone as an atomic operation. */ +int +rl_begin_undo_group () +{ + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + _rl_undo_group_level++; + return 0; +} + +/* End an undo group started with rl_begin_undo_group (). */ +int +rl_end_undo_group () +{ + rl_add_undo (UNDO_END, 0, 0, 0); + _rl_undo_group_level--; + return 0; +} + +/* Save an undo entry for the text from START to END. */ +int +rl_modifying (start, end) + int start, end; +{ + if (start > end) + { + SWAP (start, end); + } + + if (start != end) + { + char *temp = rl_copy_text (start, end); + rl_begin_undo_group (); + rl_add_undo (UNDO_DELETE, start, end, temp); + rl_add_undo (UNDO_INSERT, start, end, (char *)NULL); + rl_end_undo_group (); + } + return 0; +} + +/* Revert the current line to its previous state. */ +int +rl_revert_line (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + if (!rl_undo_list) + rl_ding (); + else + { + while (rl_undo_list) + rl_do_undo (); + } + return 0; +} + +/* Do some undoing of things that were done. */ +int +rl_undo_command (count, key) + int count, key __attribute__((unused)); +{ + if (count < 0) + return 0; /* Nothing to do. */ + + while (count) + { + if (rl_do_undo ()) + count--; + else + { + rl_ding (); + break; + } + } + return 0; +} diff --git a/cmd-line-utils/readline/util.c b/cmd-line-utils/readline/util.c new file mode 100644 index 00000000000..2a6e4e3398a --- /dev/null +++ b/cmd-line-utils/readline/util.c @@ -0,0 +1,338 @@ +/* util.c -- readline utility functions */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include "posixjmp.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> /* for _POSIX_VERSION */ +#endif /* HAVE_UNISTD_H */ + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include <stdio.h> +#include <ctype.h> + +/* System-specific feature definitions and include files. */ +#include "rldefs.h" + +#if defined (TIOCSTAT_IN_SYS_IOCTL) +# include <sys/ioctl.h> +#endif /* TIOCSTAT_IN_SYS_IOCTL */ + +/* Some standard library routines. */ +#include "readline.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Return 0 if C is not a member of the class of characters that belong + in words, or 1 if it is. */ + +int _rl_allow_pathname_alphabetic_chars = 0; +static const char *pathname_alphabetic_chars = "/-_=~.#$"; + +int +rl_alphabetic (c) + int c; +{ + if (ALPHABETIC (c)) + return (1); + + return (_rl_allow_pathname_alphabetic_chars && + strchr (pathname_alphabetic_chars, c) != NULL); +} + +/* How to abort things. */ +int +_rl_abort_internal () +{ + rl_ding (); + rl_clear_message (); + _rl_init_argument (); + rl_clear_pending_input (); + + RL_UNSETSTATE (RL_STATE_MACRODEF); + while (rl_executing_macro) + _rl_pop_executing_macro (); + + rl_last_func = (rl_command_func_t *)NULL; + longjmp (readline_top_level, 1); + return (0); +} + +int +rl_abort (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + return (_rl_abort_internal ()); +} + +int +rl_tty_status (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ +#if defined (TIOCSTAT) + ioctl (1, TIOCSTAT, (char *)0); + rl_refresh_line (count, key); +#else + rl_ding (); +#endif + return 0; +} + +/* Return a copy of the string between FROM and TO. + FROM is inclusive, TO is not. */ +char * +rl_copy_text (from, to) + int from, to; +{ + register int length; + char *copy; + + /* Fix it if the caller is confused. */ + if (from > to) + SWAP (from, to); + + length = to - from; + copy = (char *)xmalloc (1 + length); + strncpy (copy, rl_line_buffer + from, length); + copy[length] = '\0'; + return (copy); +} + +/* Increase the size of RL_LINE_BUFFER until it has enough space to hold + LEN characters. */ +void +rl_extend_line_buffer (len) + int len; +{ + while (len >= rl_line_buffer_len) + { + rl_line_buffer_len += DEFAULT_BUFFER_SIZE; + rl_line_buffer = (char *)xrealloc (rl_line_buffer, rl_line_buffer_len); + } + + _rl_set_the_line (); +} + + +/* A function for simple tilde expansion. */ +int +rl_tilde_expand (ignore, key) + int ignore __attribute__((unused)), key __attribute__((unused)); +{ + register int start, end; + char *homedir, *temp; + int len; + + end = rl_point; + start = end - 1; + + if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') + { + homedir = tilde_expand ("~"); + _rl_replace_text (homedir, start, end); + return (0); + } + else if (rl_line_buffer[start] != '~') + { + for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) + ; + start++; + } + + end = start; + do + end++; + while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); + + if (whitespace (rl_line_buffer[end]) || end >= rl_end) + end--; + + /* If the first character of the current word is a tilde, perform + tilde expansion and insert the result. If not a tilde, do + nothing. */ + if (rl_line_buffer[start] == '~') + { + len = end - start + 1; + temp = (char *)xmalloc (len + 1); + strncpy (temp, rl_line_buffer + start, len); + temp[len] = '\0'; + homedir = tilde_expand (temp); + free (temp); + + _rl_replace_text (homedir, start, end); + } + + return (0); +} + +/* **************************************************************** */ +/* */ +/* String Utility Functions */ +/* */ +/* **************************************************************** */ + +/* Determine if s2 occurs in s1. If so, return a pointer to the + match in s1. The compare is case insensitive. */ +char * +_rl_strindex (s1, s2) + register const char *s1, *s2; +{ + register int i, l, len; + + for (i = 0, l = strlen (s2), len = strlen (s1); (len - i) >= l; i++) + if (_rl_strnicmp (s1 + i, s2, l) == 0) + return ((char *) (s1 + i)); + return ((char *)NULL); +} + +#ifndef HAVE_STRPBRK +/* Find the first occurrence in STRING1 of any character from STRING2. + Return a pointer to the character in STRING1. */ +char * +_rl_strpbrk (string1, string2) + const char *string1, *string2; +{ + register const char *scan; +#if defined (HANDLE_MULTIBYTE) + mbstate_t ps; + register int i, v; + + memset (&ps, 0, sizeof (mbstate_t)); +#endif + + for (; *string1; string1++) + { + for (scan = string2; *scan; scan++) + { + if (*string1 == *scan) + return ((char *)string1); + } +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + v = _rl_get_char_len (string1, &ps); + if (v > 1) + string += v - 1; /* -1 to account for auto-increment in loop */ + } +#endif + } + return ((char *)NULL); +} +#endif + +#if !defined (HAVE_STRCASECMP) +/* Compare at most COUNT characters from string1 to string2. Case + doesn't matter. */ +int +_rl_strnicmp (string1, string2, count) + char *string1, *string2; + int count; +{ + register char ch1, ch2; + + while (count) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) == _rl_to_upper(ch2)) + count--; + else + break; + } + return (count); +} + +/* strcmp (), but caseless. */ +int +_rl_stricmp (string1, string2) + char *string1, *string2; +{ + register char ch1, ch2; + + while (*string1 && *string2) + { + ch1 = *string1++; + ch2 = *string2++; + if (_rl_to_upper(ch1) != _rl_to_upper(ch2)) + return (1); + } + return (*string1 - *string2); +} +#endif /* !HAVE_STRCASECMP */ + +/* Stupid comparison routine for qsort () ing strings. */ +int +_rl_qsort_string_compare (s1, s2) + char **s1, **s2; +{ +#if defined (HAVE_STRCOLL) + return (strcoll (*s1, *s2)); +#else + int result; + + result = **s1 - **s2; + if (result == 0) + result = strcmp (*s1, *s2); + + return result; +#endif +} + +/* Function equivalents for the macros defined in chardefs.h. */ +#define FUNCTION_FOR_MACRO(f) int (f) (c) int c; { return f (c); } + +FUNCTION_FOR_MACRO (_rl_digit_p) +FUNCTION_FOR_MACRO (_rl_digit_value) +FUNCTION_FOR_MACRO (_rl_lowercase_p) +FUNCTION_FOR_MACRO (_rl_pure_alphabetic) +FUNCTION_FOR_MACRO (_rl_to_lower) +FUNCTION_FOR_MACRO (_rl_to_upper) +FUNCTION_FOR_MACRO (_rl_uppercase_p) + +/* Backwards compatibility, now that savestring has been removed from + all `public' readline header files. */ +#undef _rl_savestring +char * +_rl_savestring (s) + const char *s; +{ + return (strcpy ((char *)xmalloc (1 + (int)strlen (s)), (s))); +} diff --git a/cmd-line-utils/readline/vi_keymap.c b/cmd-line-utils/readline/vi_keymap.c new file mode 100644 index 00000000000..53a67c674ce --- /dev/null +++ b/cmd-line-utils/readline/vi_keymap.c @@ -0,0 +1,877 @@ +/* vi_keymap.c -- the keymap for vi_mode in readline (). */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (BUFSIZ) +#include <stdio.h> +#endif /* !BUFSIZ */ + +#include "readline.h" + +#if 0 +extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; +#endif + +/* The keymap arrays for handling vi mode. */ +KEYMAP_ENTRY_ARRAY vi_movement_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_backward_char }, /* Control-h */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ + + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-[ */ /* vi_escape_keymap */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_forward_char }, /* SPACE */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ + { ISFUNC, rl_insert_comment }, /* # */ + { ISFUNC, rl_end_of_line }, /* $ */ + { ISFUNC, rl_vi_match }, /* % */ + { ISFUNC, rl_vi_tilde_expand }, /* & */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ' */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ( */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ) */ + { ISFUNC, rl_vi_complete }, /* * */ + { ISFUNC, rl_get_next_history}, /* + */ + { ISFUNC, rl_vi_char_search }, /* , */ + { ISFUNC, rl_get_previous_history }, /* - */ + { ISFUNC, rl_vi_redo }, /* . */ + { ISFUNC, rl_vi_search }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_beg_of_line }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* : */ + { ISFUNC, rl_vi_char_search }, /* ; */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* < */ + { ISFUNC, rl_vi_complete }, /* = */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* > */ + { ISFUNC, rl_vi_search }, /* ? */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_vi_append_eol }, /* A */ + { ISFUNC, rl_vi_prev_word}, /* B */ + { ISFUNC, rl_vi_change_to }, /* C */ + { ISFUNC, rl_vi_delete_to }, /* D */ + { ISFUNC, rl_vi_end_word }, /* E */ + { ISFUNC, rl_vi_char_search }, /* F */ + { ISFUNC, rl_vi_fetch_history }, /* G */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* H */ + { ISFUNC, rl_vi_insert_beg }, /* I */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* J */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* K */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* L */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* M */ + { ISFUNC, rl_vi_search_again }, /* N */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* O */ + { ISFUNC, rl_vi_put }, /* P */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Q */ + { ISFUNC, rl_vi_replace }, /* R */ + { ISFUNC, rl_vi_subst }, /* S */ + { ISFUNC, rl_vi_char_search }, /* T */ + { ISFUNC, rl_revert_line }, /* U */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* V */ + { ISFUNC, rl_vi_next_word }, /* W */ + { ISFUNC, rl_rubout }, /* X */ + { ISFUNC, rl_vi_yank_to }, /* Y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* [ */ + { ISFUNC, rl_vi_complete }, /* \ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ] */ + { ISFUNC, rl_vi_first_print }, /* ^ */ + { ISFUNC, rl_vi_yank_arg }, /* _ */ + { ISFUNC, rl_vi_goto_mark }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_vi_append_mode }, /* a */ + { ISFUNC, rl_vi_prev_word }, /* b */ + { ISFUNC, rl_vi_change_to }, /* c */ + { ISFUNC, rl_vi_delete_to }, /* d */ + { ISFUNC, rl_vi_end_word }, /* e */ + { ISFUNC, rl_vi_char_search }, /* f */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ + { ISFUNC, rl_backward_char }, /* h */ + { ISFUNC, rl_vi_insertion_mode }, /* i */ + { ISFUNC, rl_get_next_history }, /* j */ + { ISFUNC, rl_get_previous_history }, /* k */ + { ISFUNC, rl_forward_char }, /* l */ + { ISFUNC, rl_vi_set_mark }, /* m */ + { ISFUNC, rl_vi_search_again }, /* n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* o */ + { ISFUNC, rl_vi_put }, /* p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* q */ + { ISFUNC, rl_vi_change_char }, /* r */ + { ISFUNC, rl_vi_subst }, /* s */ + { ISFUNC, rl_vi_char_search }, /* t */ + { ISFUNC, rl_vi_undo }, /* u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* v */ + { ISFUNC, rl_vi_next_word }, /* w */ + { ISFUNC, rl_vi_delete }, /* x */ + { ISFUNC, rl_vi_yank_to }, /* y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* { */ + { ISFUNC, rl_vi_column }, /* | */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* } */ + { ISFUNC, rl_vi_change_case }, /* ~ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; + + +KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ + { ISFUNC, rl_insert }, /* Control-a */ + { ISFUNC, rl_insert }, /* Control-b */ + { ISFUNC, rl_insert }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_insert }, /* Control-e */ + { ISFUNC, rl_insert }, /* Control-f */ + { ISFUNC, rl_insert }, /* Control-g */ + { ISFUNC, rl_rubout }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_insert }, /* Control-k */ + { ISFUNC, rl_insert }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_insert }, /* Control-n */ + { ISFUNC, rl_insert }, /* Control-o */ + { ISFUNC, rl_insert }, /* Control-p */ + { ISFUNC, rl_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, rl_insert }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, rl_insert }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, rl_insert }, /* Control-\ */ + { ISFUNC, rl_insert }, /* Control-] */ + { ISFUNC, rl_insert }, /* Control-^ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ + { ISFUNC, rl_insert }, /* ) */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ + { ISFUNC, rl_insert }, /* ] */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ + { ISFUNC, rl_insert }, /* } */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Pure 8-bit characters (128 - 159). + These might be used in some + character sets. */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* ? */ + + /* ISO Latin-1 characters (160 - 255) */ + { ISFUNC, rl_insert }, /* No-break space */ + { ISFUNC, rl_insert }, /* Inverted exclamation mark */ + { ISFUNC, rl_insert }, /* Cent sign */ + { ISFUNC, rl_insert }, /* Pound sign */ + { ISFUNC, rl_insert }, /* Currency sign */ + { ISFUNC, rl_insert }, /* Yen sign */ + { ISFUNC, rl_insert }, /* Broken bar */ + { ISFUNC, rl_insert }, /* Section sign */ + { ISFUNC, rl_insert }, /* Diaeresis */ + { ISFUNC, rl_insert }, /* Copyright sign */ + { ISFUNC, rl_insert }, /* Feminine ordinal indicator */ + { ISFUNC, rl_insert }, /* Left pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Not sign */ + { ISFUNC, rl_insert }, /* Soft hyphen */ + { ISFUNC, rl_insert }, /* Registered sign */ + { ISFUNC, rl_insert }, /* Macron */ + { ISFUNC, rl_insert }, /* Degree sign */ + { ISFUNC, rl_insert }, /* Plus-minus sign */ + { ISFUNC, rl_insert }, /* Superscript two */ + { ISFUNC, rl_insert }, /* Superscript three */ + { ISFUNC, rl_insert }, /* Acute accent */ + { ISFUNC, rl_insert }, /* Micro sign */ + { ISFUNC, rl_insert }, /* Pilcrow sign */ + { ISFUNC, rl_insert }, /* Middle dot */ + { ISFUNC, rl_insert }, /* Cedilla */ + { ISFUNC, rl_insert }, /* Superscript one */ + { ISFUNC, rl_insert }, /* Masculine ordinal indicator */ + { ISFUNC, rl_insert }, /* Right pointing double angle quotation mark */ + { ISFUNC, rl_insert }, /* Vulgar fraction one quarter */ + { ISFUNC, rl_insert }, /* Vulgar fraction one half */ + { ISFUNC, rl_insert }, /* Vulgar fraction three quarters */ + { ISFUNC, rl_insert }, /* Inverted questionk mark */ + { ISFUNC, rl_insert }, /* Latin capital letter a with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter a with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin capital letter ae */ + { ISFUNC, rl_insert }, /* Latin capital letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin capital letter e with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter e with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter i with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter i with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin capital letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter o with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin capital letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Multiplication sign */ + { ISFUNC, rl_insert }, /* Latin capital letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin capital letter u with grave */ + { ISFUNC, rl_insert }, /* Latin capital letter u with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin capital letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin capital letter Y with acute */ + { ISFUNC, rl_insert }, /* Latin capital letter thorn (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter sharp s (German) */ + { ISFUNC, rl_insert }, /* Latin small letter a with grave */ + { ISFUNC, rl_insert }, /* Latin small letter a with acute */ + { ISFUNC, rl_insert }, /* Latin small letter a with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter a with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter a with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter a with ring above */ + { ISFUNC, rl_insert }, /* Latin small letter ae */ + { ISFUNC, rl_insert }, /* Latin small letter c with cedilla */ + { ISFUNC, rl_insert }, /* Latin small letter e with grave */ + { ISFUNC, rl_insert }, /* Latin small letter e with acute */ + { ISFUNC, rl_insert }, /* Latin small letter e with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter e with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter i with grave */ + { ISFUNC, rl_insert }, /* Latin small letter i with acute */ + { ISFUNC, rl_insert }, /* Latin small letter i with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter i with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter eth (Icelandic) */ + { ISFUNC, rl_insert }, /* Latin small letter n with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with grave */ + { ISFUNC, rl_insert }, /* Latin small letter o with acute */ + { ISFUNC, rl_insert }, /* Latin small letter o with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter o with tilde */ + { ISFUNC, rl_insert }, /* Latin small letter o with diaeresis */ + { ISFUNC, rl_insert }, /* Division sign */ + { ISFUNC, rl_insert }, /* Latin small letter o with stroke */ + { ISFUNC, rl_insert }, /* Latin small letter u with grave */ + { ISFUNC, rl_insert }, /* Latin small letter u with acute */ + { ISFUNC, rl_insert }, /* Latin small letter u with circumflex */ + { ISFUNC, rl_insert }, /* Latin small letter u with diaeresis */ + { ISFUNC, rl_insert }, /* Latin small letter y with acute */ + { ISFUNC, rl_insert }, /* Latin small letter thorn (Icelandic) */ + { ISFUNC, rl_insert } /* Latin small letter y with diaeresis */ +#endif /* KEYMAP_SIZE > 128 */ +}; + +/* Unused for the time being. */ +#if 0 +KEYMAP_ENTRY_ARRAY vi_escape_keymap = { + /* The regular control keys come first. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-@ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-d */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-g */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-h */ + { ISFUNC, rl_tab_insert}, /* Control-i */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-l */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-m */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-n */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-o */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-q */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-s */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-t */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-x */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-\ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* Control-^ */ + { ISFUNC, rl_vi_undo }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* SPACE */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ! */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* " */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* # */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* $ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* % */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* & */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ' */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ( */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ) */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* * */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* + */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* , */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* - */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* . */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_vi_arg_digit }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* : */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ; */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* < */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* = */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* > */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ? */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_arrow_keys }, /* [ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* \ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ] */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ^ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* _ */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* a */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* b */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* c */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* d */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* e */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* f */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* g */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* h */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* i */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* j */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* k */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* l */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* m */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* n */ + { ISFUNC, rl_arrow_keys }, /* o */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* p */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* q */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* r */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* s */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* t */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* u */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* v */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* w */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* x */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* y */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* { */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* | */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* } */ + { ISFUNC, (rl_command_func_t *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_word }, /* RUBOUT */ + +#if KEYMAP_SIZE > 128 + /* Undefined keys. */ + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 }, + { ISFUNC, (rl_command_func_t *)0x0 } +#endif /* KEYMAP_SIZE > 128 */ +}; +#endif diff --git a/cmd-line-utils/readline/vi_mode.c b/cmd-line-utils/readline/vi_mode.c new file mode 100644 index 00000000000..01df589f625 --- /dev/null +++ b/cmd-line-utils/readline/vi_mode.c @@ -0,0 +1,1485 @@ +/* vi_mode.c -- A vi emulation mode for Bash. + Derived from code written by Jeff Sparkes (jsparkes@bnr.ca). */ + +/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +/* **************************************************************** */ +/* */ +/* VI Emulation Mode */ +/* */ +/* **************************************************************** */ +#include "rlconf.h" + +#if defined (VI_MODE) + +#if defined (HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <sys/types.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include <stdio.h> + +/* Some standard library routines. */ +#include "rldefs.h" +#include "rlmbutil.h" + +#include "readline.h" +#include "history.h" + +#include "rlprivate.h" +#include "xmalloc.h" + +#ifndef member +#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0) +#endif + +/* Non-zero means enter insertion mode. */ +static int _rl_vi_doing_insert; + +/* Command keys which do movement for xxx_to commands. */ +static const char *vi_motion = " hl^$0ftFT;,%wbeWBE|"; + +/* Keymap used for vi replace characters. Created dynamically since + rarely used. */ +static Keymap vi_replace_map; + +/* The number of characters inserted in the last replace operation. */ +static int vi_replace_count; + +/* If non-zero, we have text inserted after a c[motion] command that put + us implicitly into insert mode. Some people want this text to be + attached to the command so that it is `redoable' with `.'. */ +static int vi_continued_command; +static char *vi_insert_buffer; +static int vi_insert_buffer_size; + +static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */ +static int _rl_vi_last_repeat = 1; +static int _rl_vi_last_arg_sign = 1; +static int _rl_vi_last_motion; +#if defined (HANDLE_MULTIBYTE) +static char _rl_vi_last_search_mbchar[MB_LEN_MAX]; +#else +static int _rl_vi_last_search_char; +#endif +static int _rl_vi_last_replacement; + +static int _rl_vi_last_key_before_insert; + +static int vi_redoing; + +/* Text modification commands. These are the `redoable' commands. */ +static const char *vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"; + +/* Arrays for the saved marks. */ +static int vi_mark_chars['z' - 'a' + 1]; + +static void _rl_vi_stuff_insert PARAMS((int)); +static void _rl_vi_save_insert PARAMS((UNDO_LIST *)); +static int rl_digit_loop1 PARAMS((void)); + +void +_rl_vi_initialize_line () +{ + register unsigned int i; + + for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++) + vi_mark_chars[i] = -1; +} + +void +_rl_vi_reset_last () +{ + _rl_vi_last_command = 'i'; + _rl_vi_last_repeat = 1; + _rl_vi_last_arg_sign = 1; + _rl_vi_last_motion = 0; +} + +void +_rl_vi_set_last (key, repeat, sign) + int key, repeat, sign; +{ + _rl_vi_last_command = key; + _rl_vi_last_repeat = repeat; + _rl_vi_last_arg_sign = sign; +} + +/* Is the command C a VI mode text modification command? */ +int +_rl_vi_textmod_command (c) + int c; +{ + return (member (c, vi_textmod)); +} + +static void +_rl_vi_stuff_insert (count) + int count; +{ + rl_begin_undo_group (); + while (count--) + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); +} + +/* Bound to `.'. Called from command mode, so we know that we have to + redo a text modification command. The default for _rl_vi_last_command + puts you back into insert mode. */ +int +rl_vi_redo (count, c) + int count, c __attribute__((unused)); +{ + int r; + + if (!rl_explicit_arg) + { + rl_numeric_arg = _rl_vi_last_repeat; + rl_arg_sign = _rl_vi_last_arg_sign; + } + + r = 0; + vi_redoing = 1; + /* If we're redoing an insert with `i', stuff in the inserted text + and do not go into insertion mode. */ + if (_rl_vi_last_command == 'i' && vi_insert_buffer && *vi_insert_buffer) + { + _rl_vi_stuff_insert (count); + /* And back up point over the last character inserted. */ + if (rl_point > 0) + rl_point--; + } + else + r = _rl_dispatch (_rl_vi_last_command, _rl_keymap); + vi_redoing = 0; + + return (r); +} + +/* A placeholder for further expansion. */ +int +rl_vi_undo (count, key) + int count, key; +{ + return (rl_undo_command (count, key)); +} + +/* Yank the nth arg from the previous line into this line at point. */ +int +rl_vi_yank_arg (count, key) + int count, key __attribute__((unused)); +{ + /* Readline thinks that the first word on a line is the 0th, while vi + thinks the first word on a line is the 1st. Compensate. */ + if (rl_explicit_arg) + rl_yank_nth_arg (count - 1, 0); + else + rl_yank_nth_arg ('$', 0); + + return (0); +} + +/* With an argument, move back that many history lines, else move to the + beginning of history. */ +int +rl_vi_fetch_history (count, c) + int count, c; +{ + int wanted; + + /* Giving an argument of n means we want the nth command in the history + file. The command number is interpreted the same way that the bash + `history' command does it -- that is, giving an argument count of 450 + to this command would get the command listed as number 450 in the + output of `history'. */ + if (rl_explicit_arg) + { + wanted = history_base + where_history () - count; + if (wanted <= 0) + rl_beginning_of_history (0, 0); + else + rl_get_previous_history (wanted, c); + } + else + rl_beginning_of_history (count, 0); + return (0); +} + +/* Search again for the last thing searched for. */ +int +rl_vi_search_again (count, key) + int count, key; +{ + switch (key) + { + case 'n': + rl_noninc_reverse_search_again (count, key); + break; + + case 'N': + rl_noninc_forward_search_again (count, key); + break; + } + return (0); +} + +/* Do a vi style search. */ +int +rl_vi_search (count, key) + int count, key; +{ + switch (key) + { + case '?': + rl_noninc_forward_search (count, key); + break; + + case '/': + rl_noninc_reverse_search (count, key); + break; + + default: + rl_ding (); + break; + } + return (0); +} + +/* Completion, from vi's point of view. */ +int +rl_vi_complete (ignore, key) + int ignore __attribute__((unused)), key; +{ + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) + { + if (!whitespace (rl_line_buffer[rl_point + 1])) + rl_vi_end_word (1, 'E'); + rl_point++; + } + + if (key == '*') + rl_complete_internal ('*'); /* Expansion and replacement. */ + else if (key == '=') + rl_complete_internal ('?'); /* List possible completions. */ + else if (key == '\\') + rl_complete_internal (TAB); /* Standard Readline completion. */ + else + rl_complete (0, key); + + if (key == '*' || key == '\\') + { + _rl_vi_set_last (key, 1, rl_arg_sign); + rl_vi_insertion_mode (1, key); + } + return (0); +} + +/* Tilde expansion for vi mode. */ +int +rl_vi_tilde_expand (ignore, key) + int ignore __attribute__((unused)), key; +{ + rl_tilde_expand (0, key); + _rl_vi_set_last (key, 1, rl_arg_sign); /* XXX */ + rl_vi_insertion_mode (1, key); + return (0); +} + +/* Previous word in vi mode. */ +int +rl_vi_prev_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_next_word (-count, key)); + + if (rl_point == 0) + { + rl_ding (); + return (0); + } + + if (_rl_uppercase_p (key)) + rl_vi_bWord (count, key); + else + rl_vi_bword (count, key); + + return (0); +} + +/* Next word in vi mode. */ +int +rl_vi_next_word (count, key) + int count, key; +{ + if (count < 0) + return (rl_vi_prev_word (-count, key)); + + if (rl_point >= (rl_end - 1)) + { + rl_ding (); + return (0); + } + + if (_rl_uppercase_p (key)) + rl_vi_fWord (count, key); + else + rl_vi_fword (count, key); + return (0); +} + +/* Move to the end of the ?next? word. */ +int +rl_vi_end_word (count, key) + int count, key; +{ + if (count < 0) + { + rl_ding (); + return -1; + } + + if (_rl_uppercase_p (key)) + rl_vi_eWord (count, key); + else + rl_vi_eword (count, key); + return (0); +} + +/* Move forward a word the way that 'W' does. */ +int +rl_vi_fWord (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Skip until whitespace. */ + while (!whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + + /* Now skip whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +int +rl_vi_bWord (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point > 0) + { + /* If we are at the start of a word, move back to whitespace so + we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + while (--rl_point >= 0 && !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +int +rl_vi_eWord (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point < (rl_end - 1)) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move to the next non-whitespace character (to the start of the + next word). */ + while (++rl_point < rl_end && whitespace (rl_line_buffer[rl_point])); + + if (rl_point && rl_point < rl_end) + { + /* Skip whitespace. */ + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Skip until whitespace. */ + while (rl_point < rl_end && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + + /* Move back to the last character of the word. */ + rl_point--; + } + } + return (0); +} + +int +rl_vi_fword (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point < (rl_end - 1)) + { + /* Move to white space (really non-identifer). */ + if (_rl_isident (rl_line_buffer[rl_point])) + { + while (_rl_isident (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + else /* if (!whitespace (rl_line_buffer[rl_point])) */ + { + while (!_rl_isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + + /* Move past whitespace. */ + while (whitespace (rl_line_buffer[rl_point]) && rl_point < rl_end) + rl_point++; + } + return (0); +} + +int +rl_vi_bword (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point > 0) + { + int last_is_ident; + + /* If we are at the start of a word, move back to whitespace + so we will go back to the start of the previous word. */ + if (!whitespace (rl_line_buffer[rl_point]) && + whitespace (rl_line_buffer[rl_point - 1])) + rl_point--; + + /* If this character and the previous character are `opposite', move + back so we don't get messed up by the rl_point++ down there in + the while loop. Without this code, words like `l;' screw up the + function. */ + last_is_ident = _rl_isident (rl_line_buffer[rl_point - 1]); + if ((_rl_isident (rl_line_buffer[rl_point]) && !last_is_ident) || + (!_rl_isident (rl_line_buffer[rl_point]) && last_is_ident)) + rl_point--; + + while (rl_point > 0 && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + if (rl_point > 0) + { + if (_rl_isident (rl_line_buffer[rl_point])) + while (--rl_point >= 0 && _rl_isident (rl_line_buffer[rl_point])); + else + while (--rl_point >= 0 && !_rl_isident (rl_line_buffer[rl_point]) && + !whitespace (rl_line_buffer[rl_point])); + rl_point++; + } + } + return (0); +} + +int +rl_vi_eword (count, ignore) + int count, ignore __attribute__((unused)); +{ + while (count-- && rl_point < rl_end - 1) + { + if (!whitespace (rl_line_buffer[rl_point])) + rl_point++; + + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + + if (rl_point < rl_end) + { + if (_rl_isident (rl_line_buffer[rl_point])) + while (++rl_point < rl_end && _rl_isident (rl_line_buffer[rl_point])); + else + while (++rl_point < rl_end && !_rl_isident (rl_line_buffer[rl_point]) + && !whitespace (rl_line_buffer[rl_point])); + } + rl_point--; + } + return (0); +} + +int +rl_vi_insert_beg (count, key) + int count __attribute__((unused)), key; +{ + rl_beg_of_line (1, key); + rl_vi_insertion_mode (1, key); + return (0); +} + +int +rl_vi_append_mode (count, key) + int count __attribute__((unused)), key; +{ + if (rl_point < rl_end) + { + if (MB_CUR_MAX == 1 || rl_byte_oriented) + rl_point++; + else + { + int point = rl_point; + rl_forward_char (1, key); + if (point == rl_point) + rl_point = rl_end; + } + } + rl_vi_insertion_mode (1, key); + return (0); +} + +int +rl_vi_append_eol (count, key) + int count __attribute__((unused)), key; +{ + rl_end_of_line (1, key); + rl_vi_append_mode (1, key); + return (0); +} + +/* What to do in the case of C-d. */ +int +rl_vi_eof_maybe (count, c) + int count __attribute__((unused)), c __attribute__((unused)); +{ + return (rl_newline (1, '\n')); +} + +/* Insertion mode stuff. */ + +/* Switching from one mode to the other really just involves + switching keymaps. */ +int +rl_vi_insertion_mode (count, key) + int count __attribute__((unused)), key; +{ + _rl_keymap = vi_insertion_keymap; + _rl_vi_last_key_before_insert = key; + return (0); +} + +static void +_rl_vi_save_insert (up) + UNDO_LIST *up; +{ + int len, start, end; + + if (up == 0) + { + if (vi_insert_buffer_size >= 1) + vi_insert_buffer[0] = '\0'; + return; + } + + start = up->start; + end = up->end; + len = end - start + 1; + if (len >= vi_insert_buffer_size) + { + vi_insert_buffer_size += (len + 32) - (len % 32); + vi_insert_buffer = (char *)xrealloc (vi_insert_buffer, vi_insert_buffer_size); + } + strncpy (vi_insert_buffer, rl_line_buffer + start, len - 1); + vi_insert_buffer[len-1] = '\0'; +} + +void +_rl_vi_done_inserting () +{ + if (_rl_vi_doing_insert) + { + /* The `C', `s', and `S' commands set this. */ + rl_end_undo_group (); + /* Now, the text between rl_undo_list->next->start and + rl_undo_list->next->end is what was inserted while in insert + mode. It gets copied to VI_INSERT_BUFFER because it depends + on absolute indices into the line which may change (though they + probably will not). */ + _rl_vi_doing_insert = 0; + _rl_vi_save_insert (rl_undo_list->next); + vi_continued_command = 1; + } + else + { + if (_rl_vi_last_key_before_insert == 'i' && rl_undo_list) + _rl_vi_save_insert (rl_undo_list); + /* XXX - Other keys probably need to be checked. */ + else if (_rl_vi_last_key_before_insert == 'C') + rl_end_undo_group (); + while (_rl_undo_group_level > 0) + rl_end_undo_group (); + vi_continued_command = 0; + } +} + +int +rl_vi_movement_mode (count, key) + int count __attribute__((unused)), key; +{ + if (rl_point > 0) + rl_backward_char (1, key); + + _rl_keymap = vi_movement_keymap; + _rl_vi_done_inserting (); + return (0); +} + +int +rl_vi_arg_digit (count, c) + int count, c; +{ + if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg) + return (rl_beg_of_line (1, c)); + else + return (rl_digit_argument (count, c)); +} + +/* Change the case of the next COUNT characters. */ +#if defined (HANDLE_MULTIBYTE) +static int +_rl_vi_change_mbchar_case (count) + int count; +{ + wchar_t wc; + char mb[MB_LEN_MAX]; + mbstate_t ps; + + memset (&ps, 0, sizeof (mbstate_t)); + if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0) + count--; + while (count-- && rl_point < rl_end) + { + mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps); + if (iswupper (wc)) + wc = towlower (wc); + else if (iswlower (wc)) + wc = towupper (wc); + else + { + /* Just skip over chars neither upper nor lower case */ + rl_forward_char (1, 0); + continue; + } + + /* Vi is kind of strange here. */ + if (wc) + { + wctomb (mb, wc); + rl_begin_undo_group (); + rl_delete (1, 0); + rl_insert_text (mb); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward_char (1, 0); + } + + return 0; +} +#endif + +int +rl_vi_change_case (count, ignore) + int count, ignore __attribute__((unused)); +{ + char c = 0; + + /* Don't try this on an empty line. */ + if (rl_point >= rl_end) + return (0); + +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + return (_rl_vi_change_mbchar_case (count)); +#endif + + while (count-- && rl_point < rl_end) + { + if (_rl_uppercase_p (rl_line_buffer[rl_point])) + c = _rl_to_lower (rl_line_buffer[rl_point]); + else if (_rl_lowercase_p (rl_line_buffer[rl_point])) + c = _rl_to_upper (rl_line_buffer[rl_point]); + else + { + /* Just skip over characters neither upper nor lower case. */ + rl_forward_char (1, c); + continue; + } + + /* Vi is kind of strange here. */ + if (c) + { + rl_begin_undo_group (); + rl_delete (1, c); + _rl_insert_char (1, c); + rl_end_undo_group (); + rl_vi_check (); + } + else + rl_forward_char (1, c); + } + return (0); +} + +int +rl_vi_put (count, key) + int count __attribute__((unused)), key; +{ + if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end)) + rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO); + + rl_yank (1, key); + rl_backward_char (1, key); + return (0); +} + +int +rl_vi_check () +{ + if (rl_point && rl_point == rl_end) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO); + else + rl_point--; + } + return (0); +} + +int +rl_vi_column (count, key) + int count, key; +{ + if (count > rl_end) + rl_end_of_line (1, key); + else + rl_point = count - 1; + return (0); +} + +int +rl_vi_domove (key, nextkey) + int key, *nextkey; +{ + int c, save; + int old_end; + + rl_mark = rl_point; + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + *nextkey = c; + + if (!member (c, vi_motion)) + { + if (_rl_digit_p (c)) + { + save = rl_numeric_arg; + rl_numeric_arg = _rl_digit_value (c); + rl_digit_loop1 (); + rl_numeric_arg *= save; + RL_SETSTATE(RL_STATE_MOREINPUT); + c = rl_read_key (); /* real command */ + RL_UNSETSTATE(RL_STATE_MOREINPUT); + *nextkey = c; + } + else if (key == c && (key == 'd' || key == 'y' || key == 'c')) + { + rl_mark = rl_end; + rl_beg_of_line (1, c); + _rl_vi_last_motion = c; + return (0); + } + else + return (-1); + } + + _rl_vi_last_motion = c; + + /* Append a blank character temporarily so that the motion routines + work right at the end of the line. */ + old_end = rl_end; + rl_line_buffer[rl_end++] = ' '; + rl_line_buffer[rl_end] = '\0'; + + _rl_dispatch (c, _rl_keymap); + + /* Remove the blank that we added. */ + rl_end = old_end; + rl_line_buffer[rl_end] = '\0'; + if (rl_point > rl_end) + rl_point = rl_end; + + /* No change in position means the command failed. */ + if (rl_mark == rl_point) + return (-1); + + /* rl_vi_f[wW]ord () leaves the cursor on the first character of the next + word. If we are not at the end of the line, and we are on a + non-whitespace character, move back one (presumably to whitespace). */ + if ((_rl_to_upper (c) == 'W') && rl_point < rl_end && rl_point > rl_mark && + !whitespace (rl_line_buffer[rl_point])) + rl_point--; + + /* If cw or cW, back up to the end of a word, so the behaviour of ce + or cE is the actual result. Brute-force, no subtlety. */ + if (key == 'c' && rl_point >= rl_mark && (_rl_to_upper (c) == 'W')) + { + /* Don't move farther back than where we started. */ + while (rl_point > rl_mark && whitespace (rl_line_buffer[rl_point])) + rl_point--; + + /* Posix.2 says that if cw or cW moves the cursor towards the end of + the line, the character under the cursor should be deleted. */ + if (rl_point == rl_mark) + rl_point++; + else + { + /* Move past the end of the word so that the kill doesn't + remove the last letter of the previous word. Only do this + if we are not at the end of the line. */ + if (rl_point >= 0 && rl_point < (rl_end - 1) && !whitespace (rl_line_buffer[rl_point])) + rl_point++; + } + } + + if (rl_mark < rl_point) + SWAP (rl_point, rl_mark); + + return (0); +} + +/* A simplified loop for vi. Don't dispatch key at end. + Don't recognize minus sign? + Should this do rl_save_prompt/rl_restore_prompt? */ +static int +rl_digit_loop1 () +{ + int key, c; + + RL_SETSTATE(RL_STATE_NUMERICARG); + while (1) + { + if (rl_numeric_arg > 1000000) + { + rl_explicit_arg = rl_numeric_arg = 0; + rl_ding (); + rl_clear_message (); + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return 1; + } + rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg); + RL_SETSTATE(RL_STATE_MOREINPUT); + key = c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (c >= 0 && _rl_keymap[c].type == ISFUNC && + _rl_keymap[c].function == rl_universal_argument) + { + rl_numeric_arg *= 4; + continue; + } + + c = UNMETA (c); + if (_rl_digit_p (c)) + { + if (rl_explicit_arg) + rl_numeric_arg = (rl_numeric_arg * 10) + _rl_digit_value (c); + else + rl_numeric_arg = _rl_digit_value (c); + rl_explicit_arg = 1; + } + else + { + rl_clear_message (); + rl_stuff_char (key); + break; + } + } + + RL_UNSETSTATE(RL_STATE_NUMERICARG); + return (0); +} + +int +rl_vi_delete_to (count, key) + int count __attribute__((unused)), key; +{ + int c; + + if (_rl_uppercase_p (key)) + rl_stuff_char ('$'); + else if (vi_redoing) + rl_stuff_char (_rl_vi_last_motion); + + if (rl_vi_domove (key, &c)) + { + rl_ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. */ + if ((strchr (" l|h^0bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + rl_kill_text (rl_point, rl_mark); + return (0); +} + +int +rl_vi_change_to (count, key) + int count, key; +{ + int c, start_pos; + + if (_rl_uppercase_p (key)) + rl_stuff_char ('$'); + else if (vi_redoing) + rl_stuff_char (_rl_vi_last_motion); + + start_pos = rl_point; + + if (rl_vi_domove (key, &c)) + { + rl_ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. c[wW] are handled by special-case code in rl_vi_domove(), + and already leave the mark at the correct location. */ + if ((strchr (" l|hwW^0bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + /* The cursor never moves with c[wW]. */ + if ((_rl_to_upper (c) == 'W') && rl_point < start_pos) + rl_point = start_pos; + + if (vi_redoing) + { + if (vi_insert_buffer && *vi_insert_buffer) + rl_begin_undo_group (); + rl_delete_text (rl_point, rl_mark); + if (vi_insert_buffer && *vi_insert_buffer) + { + rl_insert_text (vi_insert_buffer); + rl_end_undo_group (); + } + } + else + { + rl_begin_undo_group (); /* to make the `u' command work */ + rl_kill_text (rl_point, rl_mark); + /* `C' does not save the text inserted for undoing or redoing. */ + if (_rl_uppercase_p (key) == 0) + _rl_vi_doing_insert = 1; + _rl_vi_set_last (key, count, rl_arg_sign); + rl_vi_insertion_mode (1, key); + } + + return (0); +} + +int +rl_vi_yank_to (count, key) + int count __attribute__((unused)), key; +{ + int c, save = rl_point; + + if (_rl_uppercase_p (key)) + rl_stuff_char ('$'); + + if (rl_vi_domove (key, &c)) + { + rl_ding (); + return -1; + } + + /* These are the motion commands that do not require adjusting the + mark. */ + if ((strchr (" l|h^0%bB", c) == 0) && (rl_mark < rl_end)) + rl_mark++; + + rl_begin_undo_group (); + rl_kill_text (rl_point, rl_mark); + rl_end_undo_group (); + rl_do_undo (); + rl_point = save; + + return (0); +} + +int +rl_vi_delete (count, key) + int count, key; +{ + int end; + + if (rl_end == 0) + { + rl_ding (); + return -1; + } + + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO); + else + end = rl_point + count; + + if (end >= rl_end) + end = rl_end; + + rl_kill_text (rl_point, end); + + if (rl_point > 0 && rl_point == rl_end) + rl_backward_char (1, key); + return (0); +} + +int +rl_vi_back_to_indent (count, key) + int count __attribute__((unused)), key; +{ + rl_beg_of_line (1, key); + while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point])) + rl_point++; + return (0); +} + +int +rl_vi_first_print (count, key) + int count __attribute__((unused)), key; +{ + return (rl_vi_back_to_indent (1, key)); +} + +int +rl_vi_char_search (count, key) + int count, key; +{ +#if defined (HANDLE_MULTIBYTE) + static char *target; + static int mb_len; +#else + static char target; +#endif + static int orig_dir, dir; + + if (key == ';' || key == ',') + dir = key == ';' ? orig_dir : -orig_dir; + else + { + if (vi_redoing) +#if defined (HANDLE_MULTIBYTE) + target = _rl_vi_last_search_mbchar; +#else + target = _rl_vi_last_search_char; +#endif + else + { +#if defined (HANDLE_MULTIBYTE) + mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX); + target = _rl_vi_last_search_mbchar; +#else + RL_SETSTATE(RL_STATE_MOREINPUT); + _rl_vi_last_search_char = target = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); +#endif + } + + switch (key) + { + case 't': + orig_dir = dir = FTO; + break; + + case 'T': + orig_dir = dir = BTO; + break; + + case 'f': + orig_dir = dir = FFIND; + break; + + case 'F': + orig_dir = dir = BFIND; + break; + } + } + +#if defined (HANDLE_MULTIBYTE) + return (_rl_char_search_internal (count, dir, target, mb_len)); +#else + return (_rl_char_search_internal (count, dir, target)); +#endif +} + +/* Match brackets */ +int +rl_vi_match (ignore, key) + int ignore __attribute__((unused)), key; +{ + int count = 1, brack, pos, tmp, pre; + + pos = rl_point; + if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0) + { + pre = rl_point; + rl_forward_char (1, key); + if (pre == rl_point) + break; + } + } + else + while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 && + rl_point < rl_end - 1) + rl_forward_char (1, key); + + if (brack <= 0) + { + rl_point = pos; + rl_ding (); + return -1; + } + } + + pos = rl_point; + + if (brack < 0) + { + while (count) + { + tmp = pos; + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos--; + else + { + pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY); + if (tmp == pos) + pos--; + } + if (pos >= 0) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + rl_ding (); + return -1; + } + } + } + else + { /* brack > 0 */ + while (count) + { + if (MB_CUR_MAX == 1 || rl_byte_oriented) + pos++; + else + pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY); + + if (pos < rl_end) + { + int b = rl_vi_bracktype (rl_line_buffer[pos]); + if (b == -brack) + count--; + else if (b == brack) + count++; + } + else + { + rl_ding (); + return -1; + } + } + } + rl_point = pos; + return (0); +} + +int +rl_vi_bracktype (c) + int c; +{ + switch (c) + { + case '(': return 1; + case ')': return -1; + case '[': return 2; + case ']': return -2; + case '{': return 3; + case '}': return -3; + default: return 0; + } +} + +/* XXX - think about reading an entire mbchar with _rl_read_mbchar and + inserting it in one bunch instead of the loop below (like in + rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0] + for test against 033 or ^C. Make sure that _rl_read_mbchar does + this right. */ +int +rl_vi_change_char (count, key) + int count, key __attribute__((unused)); +{ + int c; + + if (vi_redoing) + c = _rl_vi_last_replacement; + else + { + RL_SETSTATE(RL_STATE_MOREINPUT); + _rl_vi_last_replacement = c = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + } + + if (c == '\033' || c == CTRL ('C')) + return -1; + + while (count-- && rl_point < rl_end) + { + rl_begin_undo_group (); + + rl_delete (1, c); +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + while (_rl_insert_char (1, c)) + { + RL_SETSTATE (RL_STATE_MOREINPUT); + c = rl_read_key (); + RL_UNSETSTATE (RL_STATE_MOREINPUT); + } + else +#endif + _rl_insert_char (1, c); + if (count == 0) + rl_backward_char (1, c); + + rl_end_undo_group (); + } + return (0); +} + +int +rl_vi_subst (count, key) + int count, key; +{ + /* If we are redoing, rl_vi_change_to will stuff the last motion char */ + if (vi_redoing == 0) + rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */ + + return (rl_vi_change_to (count, 'c')); +} + +int +rl_vi_overstrike (count, key) + int count, key; +{ + if (_rl_vi_doing_insert == 0) + { + _rl_vi_doing_insert = 1; + rl_begin_undo_group (); + } + + if (count > 0) + { + _rl_overwrite_char (count, key); + vi_replace_count += count; + } + + return (0); +} + +int +rl_vi_overstrike_delete (count, key) + int count, key; +{ + int i, s; + + for (i = 0; i < count; i++) + { + if (vi_replace_count == 0) + { + rl_ding (); + break; + } + s = rl_point; + + if (rl_do_undo ()) + vi_replace_count--; + + if (rl_point == s) + rl_backward_char (1, key); + } + + if (vi_replace_count == 0 && _rl_vi_doing_insert) + { + rl_end_undo_group (); + rl_do_undo (); + _rl_vi_doing_insert = 0; + } + return (0); +} + +int +rl_vi_replace (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int i; + + vi_replace_count = 0; + + if (!vi_replace_map) + { + vi_replace_map = rl_make_bare_keymap (); + + for (i = ' '; i < KEYMAP_SIZE; i++) + vi_replace_map[i].function = rl_vi_overstrike; + + vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete; + vi_replace_map[ESC].function = rl_vi_movement_mode; + vi_replace_map[RETURN].function = rl_newline; + vi_replace_map[NEWLINE].function = rl_newline; + + /* If the normal vi insertion keymap has ^H bound to erase, do the + same here. Probably should remove the assignment to RUBOUT up + there, but I don't think it will make a difference in real life. */ + if (vi_insertion_keymap[CTRL ('H')].type == ISFUNC && + vi_insertion_keymap[CTRL ('H')].function == rl_rubout) + vi_replace_map[CTRL ('H')].function = rl_vi_overstrike_delete; + + } + _rl_keymap = vi_replace_map; + return (0); +} + +#if 0 +/* Try to complete the word we are standing on or the word that ends with + the previous character. A space matches everything. Word delimiters are + space and ;. */ +int +rl_vi_possible_completions() +{ + int save_pos = rl_point; + + if (rl_line_buffer[rl_point] != ' ' && rl_line_buffer[rl_point] != ';') + { + while (rl_point < rl_end && rl_line_buffer[rl_point] != ' ' && + rl_line_buffer[rl_point] != ';') + rl_point++; + } + else if (rl_line_buffer[rl_point - 1] == ';') + { + rl_ding (); + return (0); + } + + rl_possible_completions (); + rl_point = save_pos; + + return (0); +} +#endif + +/* Functions to save and restore marks. */ +int +rl_vi_set_mark (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (ch < 'a' || ch > 'z') + { + rl_ding (); + return -1; + } + ch -= 'a'; + vi_mark_chars[ch] = rl_point; + return 0; +} + +int +rl_vi_goto_mark (count, key) + int count __attribute__((unused)), key __attribute__((unused)); +{ + int ch; + + RL_SETSTATE(RL_STATE_MOREINPUT); + ch = rl_read_key (); + RL_UNSETSTATE(RL_STATE_MOREINPUT); + + if (ch == '`') + { + rl_point = rl_mark; + return 0; + } + else if (ch < 'a' || ch > 'z') + { + rl_ding (); + return -1; + } + + ch -= 'a'; + if (vi_mark_chars[ch] == -1) + { + rl_ding (); + return -1; + } + rl_point = vi_mark_chars[ch]; + return 0; +} + +#endif /* VI_MODE */ diff --git a/cmd-line-utils/readline/xmalloc.c b/cmd-line-utils/readline/xmalloc.c new file mode 100644 index 00000000000..8985d340d39 --- /dev/null +++ b/cmd-line-utils/readline/xmalloc.c @@ -0,0 +1,88 @@ +/* xmalloc.c -- safe versions of malloc and realloc */ + +/* Copyright (C) 1991 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +#include <config.h> +#endif + +#include <stdio.h> + +#if defined (HAVE_STDLIB_H) +# include <stdlib.h> +#else +# include "ansi_stdlib.h" +#endif /* HAVE_STDLIB_H */ + +#include "xmalloc.h" + +/* **************************************************************** */ +/* */ +/* Memory Allocation and Deallocation. */ +/* */ +/* **************************************************************** */ + +static void +memory_error_and_abort (fname) + char *fname; +{ + fprintf (stderr, "%s: out of virtual memory\n", fname); + exit (2); +} + +/* Return a pointer to free()able block of memory large enough + to hold BYTES number of bytes. If the memory cannot be allocated, + print an error message and abort. */ +PTR_T +xmalloc (bytes) + size_t bytes; +{ + PTR_T temp; + + temp = malloc (bytes); + if (temp == 0) + memory_error_and_abort ("xmalloc"); + return (temp); +} + +PTR_T +xrealloc (pointer, bytes) + PTR_T pointer; + size_t bytes; +{ + PTR_T temp; + + temp = pointer ? realloc (pointer, bytes) : malloc (bytes); + + if (temp == 0) + memory_error_and_abort ("xrealloc"); + return (temp); +} + +/* Use this as the function to call when adding unwind protects so we + don't need to know what free() returns. */ +void +xfree (string) + PTR_T string; +{ + if (string) + free (string); +} diff --git a/cmd-line-utils/readline/xmalloc.h b/cmd-line-utils/readline/xmalloc.h new file mode 100644 index 00000000000..9cb08ba21f1 --- /dev/null +++ b/cmd-line-utils/readline/xmalloc.h @@ -0,0 +1,46 @@ +/* xmalloc.h -- memory allocation that aborts on errors. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_XMALLOC_H_) +#define _XMALLOC_H_ + +#if defined (READLINE_LIBRARY) +# include "rlstdc.h" +#else +# include <readline/rlstdc.h> +#endif + +#ifndef PTR_T + +#ifdef __STDC__ +# define PTR_T void * +#else +# define PTR_T char * +#endif + +#endif /* !PTR_T */ + +extern PTR_T xmalloc PARAMS((size_t)); +extern PTR_T xrealloc PARAMS((void *, size_t)); +extern void xfree PARAMS((void *)); + +#endif /* _XMALLOC_H_ */ |