Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libedit/readline.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/libedit/readline.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.28 retrieving revision 1.38 diff -u -p -r1.28 -r1.38 --- src/lib/libedit/readline.c 2003/03/10 01:14:54 1.28 +++ src/lib/libedit/readline.c 2003/10/16 22:26:32 1.38 @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $ */ +/* $NetBSD: readline.c,v 1.38 2003/10/16 22:26:32 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $"); +__RCSID("$NetBSD: readline.c,v 1.38 2003/10/16 22:26:32 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -51,12 +51,20 @@ __RCSID("$NetBSD: readline.c,v 1.28 2003 #include #include #include +#include +#include +#ifdef HAVE_VIS_H +#include +#else +#include "np/vis.h" +#endif #ifdef HAVE_ALLOCA_H #include #endif #include "histedit.h" #include "readline/readline.h" #include "el.h" +#include "tokenizer.h" #include "fcns.h" /* for EL_NUM_FCNS */ /* for rl_complete() */ @@ -78,6 +86,9 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; +VFunction *rl_linefunc = NULL; +int rl_done = 0; +VFunction *rl_event_hook = NULL; int history_base = 1; /* probably never subject to change */ int history_length = 0; @@ -92,10 +103,26 @@ int rl_attempted_completion_over = 0; char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; char *rl_completer_quote_characters = NULL; -CPFunction *rl_completion_entry_function = NULL; +Function *rl_completion_entry_function = NULL; CPPFunction *rl_attempted_completion_function = NULL; +Function *rl_pre_input_hook = NULL; +Function *rl_startup1_hook = NULL; +Function *rl_getc_function = NULL; +char *rl_terminal_name = NULL; +int rl_already_prompted = 0; +int rl_filename_completion_desired = 0; +int rl_ignore_completion_duplicates = 0; +VFunction *rl_redisplay_function = NULL; +Function *rl_startup_hook = NULL; +VFunction *rl_completion_display_matches_hook = NULL; +VFunction *rl_prep_term_function = NULL; +VFunction *rl_deprep_term_function = NULL; /* + * The current prompt string. + */ +char *rl_prompt = NULL; +/* * This is set to character indicating type of completion being done by * rl_complete_internal(); this is available for application completion * functions. @@ -128,6 +155,7 @@ static int _rl_complete_show_all = 0; static History *h = NULL; static EditLine *e = NULL; +static Function *map[256]; static int el_rl_complete_cmdnum = 0; /* internal functions */ @@ -140,18 +168,15 @@ static char *_rl_compat_sub(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; +static int _rl_event_read_char(EditLine *, char *); /* ARGSUSED */ static char * -_get_prompt(EditLine *el) +_get_prompt(EditLine *el __attribute__((__unused__))) { - return (el_rl_prompt); + rl_already_prompted = 1; + return (rl_prompt); } @@ -221,8 +246,8 @@ rl_initialize(void) el_set(e, EL_HIST, history, h); /* for proper prompt printing in readline() */ - el_rl_prompt = strdup(""); - if (el_rl_prompt == NULL) { + rl_prompt = strdup(""); + if (rl_prompt == NULL) { history_end(h); el_end(e); return -1; @@ -233,16 +258,19 @@ rl_initialize(void) /* set default mode to "emacs"-style and read setting afterwards */ /* so this can be overriden */ el_set(e, EL_EDITOR, "emacs"); + if (rl_terminal_name != NULL) + el_set(e, EL_TERMINAL, rl_terminal_name); + else + el_get(e, EL_TERMINAL, &rl_terminal_name); /* - * Word completition - this has to go AFTER rebinding keys + * Word completion - this has to go AFTER rebinding keys * to emacs-style. */ el_set(e, EL_ADDFN, "rl_complete", - "ReadLine compatible completition function", + "ReadLine compatible completion function", _el_rl_complete); el_set(e, EL_BIND, "^I", "rl_complete", NULL); - /* * Find out where the rl_complete function was added; this is * used later to detect that lastcmd was also rl_complete. @@ -266,6 +294,9 @@ rl_initialize(void) rl_line_buffer = memchr(li->buffer, *li->buffer, 1); rl_point = rl_end = 0; + if (rl_startup_hook) + (*rl_startup_hook)(NULL, 0); + return (0); } @@ -281,19 +312,38 @@ readline(const char *prompt) int count; const char *ret; char *buf; + static int used_event_hook; if (e == NULL || h == NULL) rl_initialize(); + rl_done = 0; + /* update prompt accordingly to what has been passed */ if (!prompt) prompt = ""; - if (strcmp(el_rl_prompt, prompt) != 0) { - free(el_rl_prompt); - el_rl_prompt = strdup(prompt); - if (el_rl_prompt == NULL) + if (strcmp(rl_prompt, prompt) != 0) { + free(rl_prompt); + rl_prompt = strdup(prompt); + if (rl_prompt == NULL) return NULL; } + + if (rl_pre_input_hook) + (*rl_pre_input_hook)(NULL, 0); + + if (rl_event_hook && !(e->el_flags&NO_TTY)) { + el_set(e, EL_GETCFN, _rl_event_read_char); + used_event_hook = 1; + } + + if (!rl_event_hook && used_event_hook) { + el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); + used_event_hook = 0; + } + + rl_already_prompted = 0; + /* get one line from input stream */ ret = el_gets(e, &count); @@ -333,7 +383,7 @@ using_history(void) /* * substitute ``what'' with ``with'', returning resulting string; if - * globally == 1, substitutes all occurences of what, otherwise only the + * globally == 1, substitutes all occurrences of what, otherwise only the * first one */ static char * @@ -342,7 +392,7 @@ _rl_compat_sub(const char *str, const ch { char *result; const char *temp, *new; - int len, with_len, what_len, add; + size_t len, with_len, what_len, add; size_t size, i; result = malloc((size = 16)); @@ -544,7 +594,7 @@ _history_expand_command(const char *comm g_on = 2; else if (*cmd == 's' || *cmd == '&') { char *what, *with, delim; - int len, from_len; + size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) @@ -1185,7 +1235,8 @@ history_search_prefix(const char *str, i */ /* ARGSUSED */ int -history_search_pos(const char *str, int direction, int pos) +history_search_pos(const char *str, + int direction __attribute__((__unused__)), int pos) { HistEvent ev; int curr_num, off; @@ -1216,7 +1267,7 @@ history_search_pos(const char *str, int /********************************/ -/* completition functions */ +/* completion functions */ /* * does tilde expansion of strings of type ``~user/foo'' @@ -1419,32 +1470,33 @@ username_completion_function(const char */ /* ARGSUSED */ static unsigned char -_el_rl_complete(EditLine *el, int ch) +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) { return (unsigned char) rl_complete(0, ch); } /* - * returns list of completitions for text given + * returns list of completions for text given */ char ** completion_matches(const char *text, CPFunction *genfunc) { char **match_list = NULL, *retstr, *prevstr; size_t match_list_len, max_equal, which, i; - int matches; + size_t matches; if (h == NULL || e == NULL) rl_initialize(); matches = 0; match_list_len = 1; - while ((retstr = (*genfunc) (text, matches)) != NULL) { + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { /* allow for list terminator here */ - if (matches + 2 >= match_list_len) { + if (matches + 3 >= match_list_len) { char **nmatch_list; - match_list_len <<= 1; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; nmatch_list = realloc(match_list, match_list_len * sizeof(char *)); if (nmatch_list == NULL) { @@ -1551,7 +1603,7 @@ rl_display_match_list (matches, len, max static int rl_complete_internal(int what_to_do) { - CPFunction *complet_func; + Function *complet_func; const LineInfo *li; char *temp, **matches; const char *ctemp; @@ -1564,7 +1616,7 @@ rl_complete_internal(int what_to_do) complet_func = rl_completion_entry_function; if (!complet_func) - complet_func = filename_completion_function; + complet_func = (Function *)(void *)filename_completion_function; /* We now look backwards for the start of a filename/variable word */ li = el_line(e); @@ -1586,7 +1638,7 @@ rl_complete_internal(int what_to_do) rl_end = li->lastchar - li->buffer; if (!rl_attempted_completion_function) - matches = completion_matches(temp, complet_func); + matches = completion_matches(temp, (CPFunction *)complet_func); else { int end = li->cursor - li->buffer; matches = (*rl_attempted_completion_function) (temp, (int) @@ -1612,11 +1664,12 @@ rl_complete_internal(int what_to_do) 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 + * it, unless we do filename completion and the * object is a directory. */ size_t alen = strlen(matches[0]); - if ((complet_func != filename_completion_function + if ((complet_func != + (Function *)filename_completion_function || (alen > 0 && (matches[0])[alen - 1] != '/')) && rl_completion_append_character) { char buf[2]; @@ -1750,7 +1803,7 @@ rl_read_key(void) */ /* ARGSUSED */ void -rl_reset_terminal(const char *p) +rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) @@ -1779,3 +1832,190 @@ rl_insert(int count, int c) return (0); } + +/*ARGSUSED*/ +int +rl_newline(int count, int c) +{ + /* + * Readline-4.0 appears to ignore the args. + */ + return rl_insert(1, '\n'); +} + +/*ARGSUSED*/ +static unsigned char +rl_bind_wrapper(EditLine *el, unsigned char c) +{ + if (map[c] == NULL) + return CC_ERROR; + (*map[c])(NULL, c); + + /* If rl_done was set by the above call, deal with it here */ + if (rl_done) + return CC_EOF; + + return CC_NORM; +} + +int +rl_add_defun(const char *name, Function *fun, int c) +{ + char dest[8]; + if (c >= sizeof(map) / sizeof(map[0]) || c < 0) + return -1; + map[(unsigned char)c] = fun; + el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); + vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); + el_set(e, EL_BIND, dest, name); + return 0; +} + +void +rl_callback_read_char() +{ + int count = 0, done = 0; + const char *buf = el_gets(e, &count); + char *wbuf; + + if (buf == NULL || count-- <= 0) + return; + if (count == 0 && buf[0] == CTRL('d')) + done = 1; + if (buf[count] == '\n' || buf[count] == '\r') + done = 2; + + if (done && rl_linefunc != NULL) { + el_set(e, EL_UNBUFFERED, 0); + if (done == 2) { + if ((wbuf = strdup(buf)) != NULL) + wbuf[count] = '\0'; + } else + wbuf = NULL; + (*(void (*)(const char *))rl_linefunc)(wbuf); + } +} + +void +rl_callback_handler_install (const char *prompt, VFunction *linefunc) +{ + if (e == NULL) { + rl_initialize(); + } + if (rl_prompt) + free(rl_prompt); + rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; + rl_linefunc = linefunc; + el_set(e, EL_UNBUFFERED, 1); +} + +void +rl_callback_handler_remove(void) +{ + el_set(e, EL_UNBUFFERED, 0); +} + +void +rl_redisplay(void) +{ + char a[2]; + a[0] = CTRL('r'); + a[1] = '\0'; + el_push(e, a); +} + +int +rl_get_previous_history(int count, int key) +{ + char a[2]; + a[0] = key; + a[1] = '\0'; + while (count--) + el_push(e, a); + return 0; +} + +void +/*ARGSUSED*/ +rl_prep_terminal(int meta_flag) +{ + el_set(e, EL_PREP_TERM, 1); +} + +void +rl_deprep_terminal() +{ + el_set(e, EL_PREP_TERM, 0); +} + +int +rl_read_init_file(const char *s) +{ + return(el_source(e, s)); +} + +int +rl_parse_and_bind(const char *line) +{ + const char **argv; + int argc; + Tokenizer *tok; + + tok = tok_init(NULL); + tok_line(tok, line, &argc, &argv); + argc = el_parse(e, argc, argv); + tok_end(tok); + return (argc ? 1 : 0); +} + +void +rl_stuff_char(int c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + el_insertstr(e, buf); +} + +static int +_rl_event_read_char(EditLine *el, char *cp) +{ + int n, num_read; + + *cp = 0; + while (rl_event_hook) { + + (*rl_event_hook)(); + +#if defined(FIONREAD) + if (ioctl(el->el_infd, FIONREAD, &n) < 0) + return(-1); + if (n) + num_read = read(el->el_infd, cp, 1); + else + num_read = 0; +#elif defined(F_SETFL) && defined(O_NDELAY) + if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) + return(-1); + if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) + return(-1); + num_read = read(el->el_infd, cp, 1); + if (fcntl(el->el_infd, F_SETFL, n)) + return(-1); +#else + /* not non-blocking, but what you gonna do? */ + num_read = read(el->el_infd, cp, 1); + return(-1); +#endif + + if (num_read < 0 && errno == EAGAIN) + continue; + if (num_read == 0) + continue; + break; + } + if (!rl_event_hook) + el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); + return(num_read); +}