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.8 retrieving revision 1.13 diff -u -p -r1.8 -r1.13 --- src/lib/libedit/readline.c 1999/07/03 11:55:51 1.8 +++ src/lib/libedit/readline.c 2000/12/31 09:50:32 1.13 @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.8 1999/07/03 11:55:51 lukem Exp $ */ +/* $NetBSD: readline.c,v 1.13 2000/12/31 09:50:32 jdolecek Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ #include #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.8 1999/07/03 11:55:51 lukem Exp $"); +__RCSID("$NetBSD: readline.c,v 1.13 2000/12/31 09:50:32 jdolecek Exp $"); #endif /* not lint && not SCCSID */ #include @@ -55,72 +55,93 @@ __RCSID("$NetBSD: readline.c,v 1.8 1999/ #include "readline.h" #include "sys.h" #include "el.h" +#include "fcns.h" /* for EL_NUM_FCNS */ /* for rl_complete() */ -#define TAB '\r' +#define TAB '\r' /* see comment at the #ifdef for sense of this */ -#define GDB_411_HACK +#define GDB_411_HACK /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ -const char *rl_library_version = "EditLine wrapper"; -char *rl_readline_name = ""; -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 = '^'; -char *history_no_expand_chars = " \t\n=("; -Function *history_inhibit_expansion_function = NULL; - -int rl_inhibit_completion = 0; -int rl_attempted_completion_over = 0; -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; +const char *rl_library_version = "EditLine wrapper"; +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 = '^'; +char *history_no_expand_chars = " \t\n=("; +Function *history_inhibit_expansion_function = NULL; + +int rl_inhibit_completion = 0; +int rl_attempted_completion_over = 0; +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; + +/* + * If not zero, non-unique completions always show list of possible matches. + */ +static int _rl_complete_show_all = 0; /* used for readline emulation */ static History *h = NULL; static EditLine *e = NULL; +static int el_rl_complete_cmdnum = 0; /* internal functions */ -static unsigned char _el_rl_complete __P((EditLine *, int)); -static char *_get_prompt __P((EditLine *)); -static HIST_ENTRY *_move_history __P((int)); -static int _history_search_gen __P((const char *, int, int)); -static int _history_expand_command __P((const char *, size_t, char **)); -static char *_rl_compat_sub __P((const char *, const char *, - const char *, int)); -static int rl_complete_internal __P((int)); +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 easy prompt switching + * needed for prompt switching in readline() */ -static char *el_rl_prompt = NULL; +static char *el_rl_prompt = NULL; + /* ARGSUSED */ static char * -_get_prompt(el) - EditLine *el; +_get_prompt(EditLine *el) { - return el_rl_prompt; + return (el_rl_prompt); } + /* * generic function for moving around history */ static HIST_ENTRY * -_move_history(op) - int op; +_move_history(int op) { HistEvent ev; static HIST_ENTRY rl_he; @@ -131,7 +152,7 @@ _move_history(op) rl_he.line = ev.str; rl_he.data = ""; - return &rl_he; + return (&rl_he); } @@ -143,10 +164,11 @@ _move_history(op) * initialize rl compat stuff */ int -rl_initialize() +rl_initialize(void) { HistEvent ev; const LineInfo *li; + int i; if (e != NULL) el_end(e); @@ -161,7 +183,7 @@ rl_initialize() h = history_init(); if (!e || !h) - return -1; + return (-1); history(h, &ev, H_SETSIZE, INT_MAX); /* unlimited */ history_length = 0; @@ -177,25 +199,42 @@ rl_initialize() /* so this can be overriden */ el_set(e, EL_EDITOR, "emacs"); - /* for word completition - this has to go AFTER rebinding keys */ - /* to emacs-style */ + /* + * 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); + "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); - /* some readline apps do use this */ + /* + * 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; + return (0); } + /* * read one line from input stream and return it, chomping * trailing newline (if there is any) @@ -210,7 +249,9 @@ readline(const char *prompt) if (e == NULL || h == NULL) rl_initialize(); - /* set the prompt */ + /* 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); @@ -247,27 +288,26 @@ readline(const char *prompt) * history expansion functions */ void -using_history() +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 */ -/* ARGSUSED */ -static char * -_rl_compat_sub(str, what, with, globally) - const char *str, *what, *with; - int globally; -{ - char *result; - const char *temp, *new; - int len, with_len, what_len, add; - size_t size, i; +static char * +_rl_compat_sub(const char *str, const char *what, const char *with, + int globally) +{ + char *result; + const char *temp, *new; + int len, with_len, what_len, add; + size_t size, i; result = malloc((size = 16)); temp = str; @@ -283,9 +323,9 @@ _rl_compat_sub(str, what, with, globally size += add + 1; result = realloc(result, size); } - (void)strncpy(&result[len], temp, i); + (void) strncpy(&result[len], temp, i); len += i; - (void)strcpy(&result[len], with); /* safe */ + (void) strcpy(&result[len], with); /* safe */ len += with_len; temp = new + what_len; } else { @@ -294,16 +334,17 @@ _rl_compat_sub(str, what, with, globally size += add + 1; result = realloc(result, size); } - (void)strcpy(&result[len], temp); /* safe */ + (void) strcpy(&result[len], temp); /* safe */ len += add; temp = NULL; } - } while (temp); + } while (temp && globally); result[len] = '\0'; - return result; + return (result); } + /* * the real function doing history expansion - takes as argument command * to do and data upon which the command should be executed @@ -316,24 +357,20 @@ _rl_compat_sub(str, what, with, globally * it's callers responsibility to free() string returned in *result */ static int -_history_expand_command(command, cmdlen, result) - 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; +_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); + (void) strncpy(cmd, command, cmdlen); cmd[cmdlen] = 0; idx = 1; @@ -342,7 +379,7 @@ _history_expand_command(command, cmdlen, event_num = history_length; idx++; } else { - int off, num; + int off, num; size_t len; off = idx; while (cmd[off] && !strchr(":^$*-%", cmd[off])) @@ -362,15 +399,15 @@ _history_expand_command(command, cmdlen, if (cmd[off - 1] == '?') len--; else if (cmd[off] != '\n' && cmd[off] != '\0') - return -1; + return (-1); prefix = 0; } search = alloca(len + 1); - (void)strncpy(search, &cmd[idx], len); + (void) strncpy(search, &cmd[idx], len); search[len] = '\0'; if (history(h, &ev, H_CURR) != 0) - return -1; + return (-1); curr_num = ev.num; if (prefix) @@ -380,11 +417,11 @@ _history_expand_command(command, cmdlen, if (retval == -1) { fprintf(rl_outstream, "%s: Event not found\n", - search); - return -1; + search); + return (-1); } if (history(h, &ev, H_CURR) != 0) - return -1; + return (-1); event_data = ev.str; /* roll back to original position */ @@ -397,13 +434,13 @@ _history_expand_command(command, cmdlen, HIST_ENTRY *rl_he; rl_he = history_get(event_num); if (!rl_he) - return 0; + return (0); event_data = rl_he->line; } else - return -1; + return (-1); if (cmd[idx] != ':') - return -1; + return (-1); cmd += idx + 1; /* recognize cmd */ @@ -454,8 +491,8 @@ _history_expand_command(command, cmdlen, else if (*cmd == 'g') g_on = 2; else if (*cmd == 's' || *cmd == '&') { - char *what, *with, delim; - int len, from_len; + char *what, *with, delim; + int len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) @@ -482,7 +519,7 @@ _history_expand_command(command, cmdlen, from = strdup(search); else { from = NULL; - return -1; + return (-1); } } cmd++; /* shift after delim */ @@ -500,7 +537,7 @@ _history_expand_command(command, cmdlen, } if (*cmd == '&') { /* safe */ - (void)strcpy(&with[len], from); + (void) strcpy(&with[len], from); len += from_len; continue; } @@ -527,7 +564,7 @@ _history_expand_command(command, cmdlen, if (arr && *arr == NULL) free(arr), arr = NULL; if (!arr) - return -1; + return (-1); /* find out max valid idx to array of array */ max = 0; @@ -543,35 +580,35 @@ _history_expand_command(command, cmdlen, /* check boundaries ... */ if (start > max || end > max || start > end) - return -1; + return (-1); for (i = 0; i <= max; i++) { - char *temp; + 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); + (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); + (void) strcpy(arr[i], temp); } cmdsize = 1, cmdlen = 0; tempcmd = malloc(cmdsize); for (i = start; start <= i && i <= end; i++) { - int arr_len; + 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 */ + (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ cmdlen += arr_len; tempcmd[cmdlen++] = ' '; /* add a space */ } @@ -587,17 +624,16 @@ _history_expand_command(command, cmdlen, return (p_on) ? 2 : 1; } + /* * csh-style history expansion */ int -history_expand(str, output) - char *str; - char **output; -{ - int i, retval = 0, idx; - size_t size; - char *temp, *result; +history_expand(char *str, char **output) +{ + int i, retval = 0, idx; + size_t size; + char *temp, *result; if (h == NULL || e == NULL) rl_initialize(); @@ -610,10 +646,10 @@ history_expand(str, output) temp[0] = temp[1] = history_expansion_char; temp[2] = ':'; temp[3] = 's'; - (void)strcpy(temp + 4, str); + (void) strcpy(temp + 4, str); str = temp; } -#define ADD_STRING(what, len) \ +#define ADD_STRING(what, len) \ { \ if (idx + len + 1 > size) \ result = realloc(result, (size += len + 1)); \ @@ -634,7 +670,7 @@ loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { - (void)strcpy(&str[j], &str[j + 1]); + (void) strcpy(&str[j], &str[j + 1]); continue; } if (!loop_again) { @@ -648,7 +684,7 @@ loop: if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || - (*history_inhibit_expansion_function) (str, j) == 0)) + (*history_inhibit_expansion_function)(str, j) == 0)) break; } @@ -675,8 +711,8 @@ loop: retval = 1; break; } - retval = _history_expand_command(&str[i], (size_t)(j - i), - &temp); + retval = _history_expand_command(&str[i], (size_t) (j - i), + &temp); if (retval != -1) { len = strlen(temp); ADD_STRING(temp, len); @@ -697,17 +733,17 @@ loop: free(*output); *output = result; - return retval; + return (retval); } + /* - * returns array of tokens parsed out of string, much as the shell might + * Parse the string into individual tokens, similarily to how shell would do it. */ char ** -history_tokenize(str) - const char *str; +history_tokenize(const char *str) { - int size = 1, result_idx = 0, i, start; + int size = 1, result_idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; @@ -716,13 +752,14 @@ history_tokenize(str) i++; start = i; for (; str[i]; i++) { - if (str[i] == '\\') - i++; - else if (str[i] == delim) + if (str[i] == '\\') { + if (str[i] != '\0') + i++; + } else if (str[i] == delim) delim = '\0'; else if (!delim && - (isspace((unsigned char) str[i]) || - strchr("()<>;&|$", str[i]))) + (isspace((unsigned char) str[i]) || + strchr("()<>;&|$", str[i]))) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; @@ -734,21 +771,21 @@ history_tokenize(str) } len = i - start; temp = malloc(len + 1); - (void)strncpy(temp, &str[start], len); + (void) strncpy(temp, &str[start], len); temp[len] = '\0'; result[result_idx++] = temp; result[result_idx] = NULL; } - return result; + return (result); } + /* * limit size of history record to ``max'' events */ void -stifle_history(max) - int max; +stifle_history(int max) { HistEvent ev; @@ -759,11 +796,12 @@ stifle_history(max) max_input_history = max; } + /* * "unlimit" size of history - set the limit to maximum allowed int value */ int -unstifle_history() +unstifle_history(void) { HistEvent ev; int omax; @@ -771,52 +809,54 @@ unstifle_history() history(h, &ev, H_SETSIZE, INT_MAX); omax = max_input_history; max_input_history = INT_MAX; - return omax; /* some value _must_ be returned */ + return (omax); /* some value _must_ be returned */ } + int -history_is_stifled() +history_is_stifled(void) { + /* cannot return true answer */ return (max_input_history != INT_MAX); } + /* * read history from a file given */ int -read_history(filename) - const char *filename; +read_history(const char *filename) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); - return history(h, &ev, H_LOAD, filename); + return (history(h, &ev, H_LOAD, filename)); } + /* * write history to a file given */ int -write_history(filename) - const char *filename; +write_history(const char *filename) { HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); - return history(h, &ev, H_SAVE, filename); + return (history(h, &ev, H_SAVE, filename)); } + /* * returns history ``num''th event * * returned pointer points to static variable */ HIST_ENTRY * -history_get(num) - int num; +history_get(int num) { static HIST_ENTRY she; HistEvent ev; @@ -827,14 +867,14 @@ history_get(num) /* rewind to beginning */ if (history(h, &ev, H_CURR) != 0) - return NULL; + return (NULL); curr_num = ev.num; if (history(h, &ev, H_LAST) != 0) - return NULL; /* error */ + return (NULL); /* error */ while (i < num && history(h, &ev, H_PREV) == 0) i++; if (i != num) - return NULL; /* not so many entries */ + return (NULL); /* not so many entries */ she.line = ev.str; she.data = NULL; @@ -843,15 +883,15 @@ history_get(num) (void) history(h, &ev, H_FIRST); (void) history(h, &ev, H_NEXT_EVENT, curr_num); - return &she; + return (&she); } + /* * add the line to history table */ int -add_history(line) - const char *line; +add_history(const char *line) { HistEvent ev; @@ -865,27 +905,30 @@ add_history(line) return (!(history_length > 0)); /* return 0 if all is okay */ } + /* * clear the history list - delete all entries */ void -clear_history() +clear_history(void) { HistEvent ev; + history(h, &ev, H_CLEAR); } + /* * returns offset of the current history event */ int -where_history() +where_history(void) { HistEvent ev; int curr_num, off; if (history(h, &ev, H_CURR) != 0) - return 0; + return (0); curr_num = ev.num; history(h, &ev, H_FIRST); @@ -893,29 +936,32 @@ where_history() while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) off++; - return off; + return (off); } + /* * returns current history event or NULL if there is no such event */ HIST_ENTRY * -current_history() +current_history(void) { - return _move_history(H_CURR); + + return (_move_history(H_CURR)); } + /* * returns total number of bytes history events' data are using */ int -history_total_bytes() +history_total_bytes(void) { HistEvent ev; int curr_num, size; if (history(h, &ev, H_CURR) != 0) - return -1; + return (-1); curr_num = ev.num; history(h, &ev, H_FIRST); @@ -927,21 +973,21 @@ history_total_bytes() /* get to the same position as before */ history(h, &ev, H_PREV_EVENT, curr_num); - return size; + return (size); } + /* * sets the position in the history list to ``pos'' */ int -history_set_pos(pos) - int pos; +history_set_pos(int pos) { HistEvent ev; int off, curr_num; if (pos > history_length || pos < 0) - return -1; + return (-1); history(h, &ev, H_CURR); curr_num = ev.num; @@ -953,43 +999,46 @@ history_set_pos(pos) 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 (-1); } - return 0; + return (0); } + /* * returns previous event in history and shifts pointer accordingly */ HIST_ENTRY * -previous_history() +previous_history(void) { - return _move_history(H_PREV); + + return (_move_history(H_PREV)); } + /* * returns next event in history and shifts pointer accordingly */ HIST_ENTRY * -next_history() +next_history(void) { - return _move_history(H_NEXT); + + return (_move_history(H_NEXT)); } + /* * generic history search function */ static int -_history_search_gen(str, direction, pos) - const char *str; - int direction, pos; -{ - HistEvent ev; - const char *strp; - int curr_num; +_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; + return (-1); curr_num = ev.num; for (;;) { @@ -1002,58 +1051,57 @@ _history_search_gen(str, direction, pos) history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - return -1; + return (-1); } + /* * searches for first history event containing the str */ int -history_search(str, direction) - const char *str; - int direction; +history_search(const char *str, int direction) { - return _history_search_gen(str, direction, -1); + + return (_history_search_gen(str, direction, -1)); } + /* * searches for first history event beginning with str */ int -history_search_prefix(str, direction) - const char *str; - int direction; +history_search_prefix(const char *str, int direction) { - return _history_search_gen(str, direction, 0); + + 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(str, direction, pos) - const char *str; - int direction, pos; +history_search_pos(const char *str, int direction, int pos) { - HistEvent ev; - int curr_num, off; + 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; + return (-1); curr_num = ev.num; if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) - return -1; + return (-1); for (;;) { if (strstr(ev.str, str)) - return off; + return (off); if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) break; } @@ -1061,12 +1109,12 @@ history_search_pos(str, direction, pos) /* set "current" pointer back to previous state */ history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - return -1; + return (-1); } /********************************/ -/* completition functions */ +/* completition functions */ /* * does tilde expansion of strings of type ``~user/foo'' @@ -1076,15 +1124,14 @@ history_search_pos(str, direction, pos) * it's callers's responsibility to free() returned string */ char * -tilde_expand(txt) - char *txt; +tilde_expand(char *txt) { - struct passwd *pass; - char *temp; - size_t len = 0; + struct passwd *pass; + char *temp; + size_t len = 0; if (txt[0] != '~') - return strdup(txt); + return (strdup(txt)); temp = strchr(txt + 1, '/'); if (temp == NULL) @@ -1092,24 +1139,25 @@ tilde_expand(txt) else { len = temp - txt + 1; /* text until string after slash */ temp = malloc(len); - (void)strncpy(temp, txt + 1, len - 2); + (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); + 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); + (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); - return temp; + return (temp); } + /* * return first found file name starting by the ``text'' or NULL if no * such file can be found @@ -1117,17 +1165,15 @@ tilde_expand(txt) * * it's caller's responsibility to free returned string */ -char * -filename_completion_function(text, state) - 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; +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) { @@ -1138,10 +1184,10 @@ filename_completion_function(text, state if (temp) { temp++; filename = realloc(filename, strlen(temp) + 1); - (void)strcpy(filename, temp); + (void) strcpy(filename, temp); len = temp - text; /* including last slash */ dirname = realloc(dirname, len + 1); - (void)strncpy(dirname, text, len); + (void) strncpy(dirname, text, len); dirname[len] = '\0'; } else { filename = strdup(text); @@ -1152,17 +1198,17 @@ filename_completion_function(text, state if (dirname && *dirname == '~') { temp = tilde_expand(dirname); dirname = realloc(dirname, strlen(temp) + 1); - (void)strcpy(dirname, temp); /* safe */ - free(temp); /* no more needed */ + (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 */ + return (NULL); /* no expansion possible */ dir = opendir(dirname ? dirname : "."); if (!dir) - return NULL; /* cannot open the directory */ + return (NULL); /* cannot open the directory */ } /* find the match */ while ((entry = readdir(dir)) != NULL) { @@ -1175,22 +1221,22 @@ filename_completion_function(text, state && entry->d_namlen >= filename_len #endif && strncmp(entry->d_name, filename, - filename_len) == 0) + filename_len) == 0) break; } if (entry) { /* match found */ - struct stat stbuf; + 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; + ((dirname) ? strlen(dirname) : 0) + 1 + 1; temp = malloc(len); - (void)sprintf(temp, "%s%s", - dirname ? dirname : "", entry->d_name); /* safe */ + (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)) @@ -1198,9 +1244,10 @@ filename_completion_function(text, state } else temp = NULL; - return temp; + return (temp); } + /* * a completion generator for usernames; returns _first_ username * which starts with supplied text @@ -1208,15 +1255,13 @@ filename_completion_function(text, state * (usually '~'); state is ignored * it's callers responsibility to free returned value */ -char * -username_completion_function(text, state) - const char *text; - int state; +char * +username_completion_function(const char *text, int state) { - struct passwd *pwd; + struct passwd *pwd; if (text[0] == '\0') - return NULL; + return (NULL); if (*text == '~') text++; @@ -1225,49 +1270,47 @@ username_completion_function(text, state setpwent(); while ((pwd = getpwent()) && text[0] == pwd->pw_name[0] - && strcmp(text, pwd->pw_name) == 0); + && strcmp(text, pwd->pw_name) == 0); if (pwd == NULL) { endpwent(); - return NULL; + return (NULL); } - return strdup(pwd->pw_name); + return (strdup(pwd->pw_name)); } + /* * el-compatible wrapper around rl_complete; needed for key binding */ /* ARGSUSED */ static unsigned char -_el_rl_complete(el, ch) - EditLine *el; - int ch; +_el_rl_complete(EditLine *el, int ch) { return (unsigned char) rl_complete(0, ch); } + /* * returns list of completitions for text given */ -char ** -completion_matches(text, genfunc) - const char *text; - CPFunction *genfunc; -{ - char **match_list = NULL, *retstr, *prevstr; - size_t math_list_len, max_equal, which, i; - int matches; +char ** +completion_matches(const char *text, CPFunction *genfunc) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + int matches; if (h == NULL || e == NULL) rl_initialize(); matches = 0; - math_list_len = 1; + match_list_len = 1; while ((retstr = (*genfunc) (text, matches)) != NULL) { - if (matches + 1 >= math_list_len) { - math_list_len <<= 1; + if (matches + 1 >= match_list_len) { + match_list_len <<= 1; match_list = realloc(match_list, - math_list_len * sizeof(char *)); + match_list_len * sizeof(char *)); } match_list[++matches] = retstr; } @@ -1279,7 +1322,7 @@ completion_matches(text, genfunc) which = 2; prevstr = match_list[1]; max_equal = strlen(prevstr); - for (; which < matches; which++) { + for (; which <= matches; which++) { for (i = 0; i < max_equal && prevstr[i] == match_list[which][i]; i++) continue; @@ -1287,31 +1330,90 @@ completion_matches(text, genfunc) } retstr = malloc(max_equal + 1); - (void)strncpy(retstr, match_list[1], max_equal); + (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 >= math_list_len) + if (matches + 1 >= match_list_len) match_list = realloc(match_list, - (math_list_len + 1) * sizeof(char *)); + (match_list_len + 1) * sizeof(char *)); match_list[matches + 1] = (char *) NULL; - return match_list; + return (match_list); } /* - * called by rl_complete() + * 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 **)i1)[0]; + 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], 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 */ -/* ARGSUSED */ static int -rl_complete_internal(what_to_do) - int what_to_do; +rl_complete_internal(int what_to_do) { - CPFunction *complet_func; + CPFunction *complet_func; const LineInfo *li; - char *temp, *temp2, **arr; - size_t len; + char *temp, **matches; + const char *ctemp; + size_t len; + + rl_completion_type = what_to_do; if (h == NULL || e == NULL) rl_initialize(); @@ -1321,16 +1423,14 @@ rl_complete_internal(what_to_do) complet_func = filename_completion_function; li = el_line(e); - /* LINTED const cast */ - temp = (char *) li->cursor; - while (temp > li->buffer && - !strchr(rl_basic_word_break_characters, *(temp - 1))) - temp--; - - len = li->cursor - temp; - temp2 = alloca(len + 1); - (void)strncpy(temp2, temp, len); - temp = temp2; + ctemp = (char *) li->cursor; + while (ctemp > li->buffer && + !strchr(rl_basic_word_break_characters, *(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() */ @@ -1339,58 +1439,107 @@ rl_complete_internal(what_to_do) rl_end = li->lastchar - li->buffer; if (!rl_attempted_completion_function) - arr = completion_matches(temp, complet_func); + matches = completion_matches(temp, complet_func); else { - int end = li->cursor - li->buffer; - arr = (*rl_attempted_completion_function) (temp, (int) - (end - len), end); - } - - if (arr) { - int i; - - el_deletestr(e, (int)len); - el_insertstr(e, arr[0]); - if (strcmp(arr[0], arr[1]) == 0) { - /* lcd is valid object, so add a space to mark it */ - /* in case of filename completition, add a space */ - /* only if object found is not directory */ - size_t alen = strlen(arr[0]); + 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; + + 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 && (arr[0])[alen - 1] != '/')) + || (alen > 0 && (matches[0])[alen - 1] != '/')) el_insertstr(e, " "); - } else + } 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 { /* 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; arr[i]; i++) - free(arr[i]); - free(arr), arr = NULL; + for (i = 0; matches[i]; i++) + free(matches[i]); + free(matches), matches = NULL; - return CC_REFRESH; + return (retval); } - return CC_NORM; + return (CC_NORM); } + /* * complete word at current point */ int -rl_complete(ignore, invoking_key) - int ignore, invoking_key; +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 - return rl_complete_internal(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 */ @@ -1399,11 +1548,9 @@ rl_complete(ignore, invoking_key) * bind key c to readline-type function func */ int -rl_bind_key(c, func) - int c; - int func __P((int, int)); +rl_bind_key(int c, int func(int, int)) { - int retval = -1; + int retval = -1; if (h == NULL || e == NULL) rl_initialize(); @@ -1413,45 +1560,47 @@ rl_bind_key(c, func) e->el_map.key[c] = ED_INSERT; retval = 0; } - return retval; + return (retval); } + /* * read one key from input - handles chars pushed back * to input stream also */ int -rl_read_key() +rl_read_key(void) { - char fooarr[2 * sizeof(int)]; + char fooarr[2 * sizeof(int)]; if (e == NULL || h == NULL) rl_initialize(); - return el_getc(e, fooarr); + return (el_getc(e, fooarr)); } + /* * reset the terminal */ /* ARGSUSED */ void -rl_reset_terminal(p) - const char *p; +rl_reset_terminal(const char *p) { + if (h == NULL || e == NULL) rl_initialize(); el_reset(e); } + /* * insert character ``c'' back into input stream, ``count'' times */ int -rl_insert(count, c) - int count, c; +rl_insert(int count, int c) { - char arr[2]; + char arr[2]; if (h == NULL || e == NULL) rl_initialize(); @@ -1463,5 +1612,5 @@ rl_insert(count, c) for (; count > 0; count--) el_push(e, arr); - return 0; + return (0); }