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.49.2.1 retrieving revision 1.57 diff -u -p -r1.49.2.1 -r1.57 --- src/lib/libedit/readline.c 2005/05/28 14:02:27 1.49.2.1 +++ src/lib/libedit/readline.c 2005/06/11 18:18:59 1.57 @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.49.2.1 2005/05/28 14:02:27 tron Exp $ */ +/* $NetBSD: readline.c,v 1.57 2005/06/11 18:18:59 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.49.2.1 2005/05/28 14:02:27 tron Exp $"); +__RCSID("$NetBSD: readline.c,v 1.57 2005/06/11 18:18:59 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -65,6 +65,7 @@ __RCSID("$NetBSD: readline.c,v 1.49.2.1 #include "fcns.h" /* for EL_NUM_FCNS */ #include "histedit.h" #include "readline/readline.h" +#include "filecomplete.h" /* for rl_complete() */ #define TAB '\r' @@ -85,7 +86,7 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; -VFunction *rl_linefunc = NULL; +VCPFunction *rl_linefunc = NULL; int rl_done = 0; VFunction *rl_event_hook = NULL; @@ -141,7 +142,7 @@ int rl_completion_query_items = 100; * in the parsed text when it is passed to the completion function. * Shell uses this to help determine what kind of completing to do. */ -char *rl_special_prefixes = (char *)NULL; +char *rl_special_prefixes = NULL; /* * This is the character appended to the completed words if at the end of @@ -151,13 +152,9 @@ 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 Function *map[256]; -static int el_rl_complete_cmdnum = 0; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); @@ -168,8 +165,6 @@ static int _history_expand_command(con 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 *); static int _rl_event_read_char(EditLine *, char *); static void _rl_update_pos(void); @@ -214,7 +209,6 @@ rl_initialize(void) { HistEvent ev; const LineInfo *li; - int i; int editmode = 1; struct termios t; @@ -282,17 +276,6 @@ rl_initialize(void) "ReadLine compatible suspend function", _el_rl_tstp); el_set(e, EL_BIND, "^Z", "rl_tstp", 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); @@ -1368,178 +1351,18 @@ history_search_pos(const char *str, /********************************/ /* completion functions */ -/* - * does tilde expansion of strings of type ``~user/foo'' - * if ``user'' isn't valid user name or ``txt'' doesn't start - * w/ '~', returns pointer to strdup()ed copy of ``txt'' - * - * it's callers's responsibility to free() returned string - */ char * -tilde_expand(char *txt) +tilde_expand(char *name) { - struct passwd *pass; - char *temp; - size_t len = 0; - - if (txt[0] != '~') - return (strdup(txt)); - - temp = strchr(txt + 1, '/'); - if (temp == NULL) { - temp = strdup(txt + 1); - if (temp == NULL) - return NULL; - } else { - len = temp - txt + 1; /* text until string after slash */ - temp = malloc(len); - if (temp == NULL) - return NULL; - (void)strncpy(temp, txt + 1, len - 2); - temp[len - 2] = '\0'; - } - 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); - if (temp == NULL) - return NULL; - (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); - - return (temp); + return fn_tilde_expand(name); } - -/* - * return first found file name starting by the ``text'' or NULL if no - * such file can be found - * value of ``state'' is ignored - * - * it's caller's responsibility to free returned string - */ char * -filename_completion_function(const char *text, int state) +filename_completion_function(const char *name, int state) { - static DIR *dir = NULL; - static char *filename = NULL, *dirname = NULL; - static size_t filename_len = 0; - struct dirent *entry; - char *temp; - size_t len; - - if (state == 0 || dir == NULL) { - temp = strrchr(text, '/'); - if (temp) { - char *nptr; - temp++; - nptr = realloc(filename, strlen(temp) + 1); - if (nptr == NULL) { - free(filename); - return NULL; - } - filename = nptr; - (void)strcpy(filename, temp); - len = temp - text; /* including last slash */ - nptr = realloc(dirname, len + 1); - if (nptr == NULL) { - free(filename); - return NULL; - } - dirname = nptr; - (void)strncpy(dirname, text, len); - dirname[len] = '\0'; - } else { - if (*text == 0) - filename = NULL; - else { - filename = strdup(text); - if (filename == NULL) - return NULL; - } - dirname = NULL; - } - - /* support for ``~user'' syntax */ - if (dirname && *dirname == '~') { - char *nptr; - temp = tilde_expand(dirname); - if (temp == NULL) - return NULL; - nptr = realloc(dirname, strlen(temp) + 1); - if (nptr == NULL) { - free(dirname); - return NULL; - } - dirname = nptr; - (void)strcpy(dirname, temp); /* safe */ - free(temp); /* no longer needed */ - } - /* will be used in cycle */ - filename_len = filename ? strlen(filename) : 0; - - if (dir != NULL) { - (void)closedir(dir); - dir = NULL; - } - dir = opendir(dirname ? dirname : "."); - if (!dir) - return (NULL); /* cannot open the directory */ - } - /* find the match */ - while ((entry = readdir(dir)) != NULL) { - /* skip . and .. */ - if (entry->d_name[0] == '.' && (!entry->d_name[1] - || (entry->d_name[1] == '.' && !entry->d_name[2]))) - continue; - if (filename_len == 0) - break; - /* otherwise, get first entry where first */ - /* filename_len characters are equal */ - if (entry->d_name[0] == filename[0] -#if defined(__SVR4) || defined(__linux__) - && strlen(entry->d_name) >= filename_len -#else - && entry->d_namlen >= filename_len -#endif - && strncmp(entry->d_name, filename, - filename_len) == 0) - break; - } - - if (entry) { /* match found */ - - 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); - if (temp == NULL) - return NULL; - (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 { - (void)closedir(dir); - dir = NULL; - temp = NULL; - } - - return (temp); + return fn_filename_completion_function(name, state); } - /* * a completion generator for usernames; returns _first_ username * which starts with supplied text @@ -1550,7 +1373,8 @@ filename_completion_function(const char char * username_completion_function(const char *text, int state) { - struct passwd *pwd; + struct passwd *pwd, pwres; + char pwbuf[1024]; if (text[0] == '\0') return (NULL); @@ -1561,7 +1385,8 @@ username_completion_function(const char if (state == 0) setpwent(); - while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] + while (getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pwd) == 0 + && pwd != NULL && text[0] == pwd->pw_name[0] && strcmp(text, pwd->pw_name) == 0); if (pwd == NULL) { @@ -1573,16 +1398,6 @@ username_completion_function(const char /* - * 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); -} - -/* * el-compatible wrapper to send TSTP on ^Z */ /* ARGSUSED */ @@ -1594,273 +1409,34 @@ _el_rl_tstp(EditLine *el __attribute__(( } /* - * 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; - size_t matches; - - if (h == NULL || e == NULL) - rl_initialize(); - - matches = 0; - match_list_len = 1; - while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { - /* allow for list terminator here */ - if (matches + 3 >= match_list_len) { - char **nmatch_list; - while (matches + 3 >= match_list_len) - match_list_len <<= 1; - nmatch_list = realloc(match_list, - match_list_len * sizeof(char *)); - if (nmatch_list == NULL) { - free(match_list); - return NULL; - } - match_list = nmatch_list; - - } - match_list[++matches] = retstr; - } - - if (!match_list) - return NULL; /* nothing found */ - - /* find least denominator and insert it to match_list[0] */ - which = 2; - prevstr = match_list[1]; - max_equal = strlen(prevstr); - for (; which <= matches; which++) { - for (i = 0; i < max_equal && - prevstr[i] == match_list[which][i]; i++) - continue; - max_equal = i; - } - - retstr = malloc(max_equal + 1); - if (retstr == NULL) { - free(match_list); - return NULL; - } - (void)strncpy(retstr, match_list[1], max_equal); - retstr[max_equal] = '\0'; - match_list[0] = retstr; - - /* add NULL as last pointer to the array */ - match_list[matches + 1] = (char *) NULL; - - return (match_list); -} - -/* - * Sort function for qsort(). Just wrapper around strcasecmp(). - */ -static int -_rl_qsort_string_compare(i1, i2) - const void *i1, *i2; -{ - const char *s1 = ((const char * const *)i1)[0]; - const char *s2 = ((const char * const *)i2)[0]; - - return strcasecmp(s1, s2); -} - -/* * Display list of strings in columnar format on readline's output stream. * 'matches' is list of strings, 'len' is number of strings in 'matches', * 'max' is maximum length of string in 'matches'. */ void -rl_display_match_list (matches, len, max) - char **matches; - int len, max; +rl_display_match_list(char **matches, int len, int max) { - int i, idx, limit, count; - int screenwidth = e->el_term.t_size.h; - /* - * Find out how many entries can be put on one line, count - * with two spaces between strings. - */ - limit = screenwidth / (max + 2); - if (limit == 0) - limit = 1; - - /* how many lines of output */ - count = len / limit; - if (count * limit < len) - count++; - - /* Sort the items if they are not already sorted. */ - qsort(&matches[1], (size_t)(len - 1), sizeof(char *), - _rl_qsort_string_compare); - - idx = 1; - for(; count > 0; count--) { - for(i = 0; i < limit && matches[idx]; i++, idx++) - (void)fprintf(e->el_outfile, "%-*s ", max, - matches[idx]); - (void)fprintf(e->el_outfile, "\n"); - } + fn_display_match_list(e, matches, len, max); } -/* - * Complete the word at or before point, called by rl_complete() - * 'what_to_do' says what to do with the completion. - * `?' means list the possible completions. - * TAB means do standard completion. - * `*' means insert all of the possible completions. - * `!' means to do standard completion, and list all possible completions if - * there is more than one. - * - * Note: '*' support is not implemented - */ -static int -_rl_complete_internal(int what_to_do) +static const char * +/*ARGSUSED*/ +_rl_completion_append_character_function(const char *dummy + __attribute__((__unused__))) { - Function *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 = (Function *)(void *)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_update_pos(); - - if (rl_attempted_completion_function) { - int end = li->cursor - li->buffer; - matches = (*rl_attempted_completion_function) (temp, (int) - (end - len), end); - } else - matches = 0; - if (!rl_attempted_completion_function || !matches) - matches = completion_matches(temp, (CPFunction *)complet_func); - - 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 completion and the - * object is a directory. - */ - size_t alen = strlen(matches[0]); - if ((complet_func != - (Function *)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 */ - (void)fprintf(e->el_outfile, "\n"); - - /* - * If there are too many items, ask user for display - * confirmation. - */ - if (matches_num > rl_completion_query_items) { - (void)fprintf(e->el_outfile, - "Display all %d possibilities? (y or n) ", - matches_num); - (void)fflush(e->el_outfile); - if (getc(stdin) != 'y') - match_display = 0; - (void)fprintf(e->el_outfile, "\n"); - } - - if (match_display) - rl_display_match_list(matches, matches_num, - maxlen); - retval = CC_REDISPLAY; - } else if (matches[0][0]) { - /* - * There was some common match, but the name was - * not complete enough. Next tab will print possible - * completions. - */ - el_beep(e); - } else { - /* lcd is not a valid object - further specification */ - /* is needed */ - el_beep(e); - retval = CC_NORM; - } - - /* free elements of array and the array itself */ - for (i = 0; matches[i]; i++) - free(matches[i]); - free(matches), matches = NULL; - - return (retval); - } - return (CC_NORM); + static char buf[2]; + buf[1] = rl_completion_append_character; + return buf; } /* * complete word at current point */ +/* ARGSUSED */ int -/*ARGSUSED*/ -rl_complete(int ignore, int invoking_key) +rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { if (h == NULL || e == NULL) rl_initialize(); @@ -1871,15 +1447,26 @@ rl_complete(int ignore, int invoking_key arr[1] = '\0'; el_insertstr(e, arr); return (CC_REFRESH); - } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) - return _rl_complete_internal('?'); - else if (_rl_complete_show_all) - return _rl_complete_internal('!'); - else - return _rl_complete_internal(TAB); + } + + /* Just look at how many global variables modify this operation! */ + return fn_complete(e, + (CPFunction *)rl_completion_entry_function, + rl_attempted_completion_function, + rl_basic_word_break_characters, rl_special_prefixes, + _rl_completion_append_character_function, rl_completion_query_items, + &rl_completion_type, &rl_attempted_completion_over, + &rl_point, &rl_end); } +/* ARGSUSED */ +static unsigned char +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) +{ + return (unsigned char)rl_complete(0, ch); +} + /* * misc other functions */ @@ -2094,6 +1681,16 @@ rl_parse_and_bind(const char *line) return (argc ? 1 : 0); } +int +rl_variable_bind(const char *var, const char *value) +{ + /* + * The proper return value is undocument, but this is what the + * readline source seems to do. + */ + return ((el_set(e, EL_BIND, "", var, value) == -1) ? 1 : 0); +} + void rl_stuff_char(int c) {