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.20 retrieving revision 1.37 diff -u -p -r1.20 -r1.37 --- src/lib/libedit/readline.c 2002/03/18 16:00:57 1.20 +++ src/lib/libedit/readline.c 2003/10/15 18:08:40 1.37 @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.20 2002/03/18 16:00:57 christos Exp $ */ +/* $NetBSD: readline.c,v 1.37 2003/10/15 18:08:40 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.20 2002/03/18 16:00:57 christos Exp $"); +__RCSID("$NetBSD: readline.c,v 1.37 2003/10/15 18:08:40 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -51,6 +51,10 @@ __RCSID("$NetBSD: readline.c,v 1.20 2002 #include #include #include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif #include "histedit.h" #include "readline/readline.h" #include "el.h" @@ -75,6 +79,7 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; +VFunction *rl_linefunc = NULL; int history_base = 1; /* probably never subject to change */ int history_length = 0; @@ -89,10 +94,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. @@ -125,6 +146,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 */ @@ -138,17 +160,13 @@ static char *_rl_compat_sub(const char 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) +_get_prompt(EditLine *el __attribute__((__unused__))) { - return (el_rl_prompt); + rl_already_prompted = 1; + return (rl_prompt); } @@ -218,23 +236,31 @@ rl_initialize(void) el_set(e, EL_HIST, history, h); /* for proper prompt printing in readline() */ - el_rl_prompt = strdup(""); + rl_prompt = strdup(""); + if (rl_prompt == NULL) { + history_end(h); + el_end(e); + return -1; + } 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"); + 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. @@ -258,6 +284,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); } @@ -280,10 +309,18 @@ readline(const char *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); + 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); + + rl_already_prompted = 0; + /* get one line from input stream */ ret = el_gets(e, &count); @@ -291,6 +328,8 @@ readline(const char *prompt) int lastidx; buf = strdup(ret); + if (buf == NULL) + return NULL; lastidx = count - 1; if (buf[lastidx] == '\n') buf[lastidx] = '\0'; @@ -321,7 +360,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 * @@ -330,10 +369,12 @@ _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)); + if (result == NULL) + return NULL; temp = str; with_len = strlen(with); what_len = strlen(what); @@ -344,8 +385,14 @@ _rl_compat_sub(const char *str, const ch i = new - temp; add = i + with_len; if (i + add + 1 >= size) { + char *nresult; size += add + 1; - result = realloc(result, size); + nresult = realloc(result, size); + if (nresult == NULL) { + free(result); + return NULL; + } + result = nresult; } (void) strncpy(&result[len], temp, i); len += i; @@ -355,8 +402,14 @@ _rl_compat_sub(const char *str, const ch } else { add = strlen(temp); if (len + add + 1 >= size) { + char *nresult; size += add + 1; - result = realloc(result, size); + nresult = realloc(result, size); + if (nresult == NULL) { + free(result); + return NULL; + } + result = nresult; } (void) strcpy(&result[len], temp); /* safe */ len += add; @@ -499,6 +552,8 @@ _history_expand_command(const char *comm cmd++; line = strdup(event_data); + if (line == NULL) + return 0; for (; *cmd; cmd++) { if (*cmd == ':') continue; @@ -516,7 +571,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)) @@ -525,23 +580,36 @@ _history_expand_command(const char *comm delim = *(++cmd), cmd++; size = 16; what = realloc(from, size); + if (what == NULL) { + free(from); + return 0; + } len = 0; for (; *cmd && *cmd != delim; cmd++) { if (*cmd == '\\' && *(cmd + 1) == delim) cmd++; - if (len >= size) - what = realloc(what, + if (len >= size) { + char *nwhat; + nwhat = realloc(what, (size <<= 1)); + if (nwhat == NULL) { + free(what); + return 0; + } + what = nwhat; + } what[len++] = *cmd; } what[len] = '\0'; from = what; if (*what == '\0') { free(what); - if (search) + if (search) { from = strdup(search); - else { + if (from == NULL) + return 0; + } else { from = NULL; return (-1); } @@ -552,12 +620,22 @@ _history_expand_command(const char *comm size = 16; with = realloc(to, size); + if (with == NULL) { + free(to); + return -1; + } len = 0; from_len = strlen(from); for (; *cmd && *cmd != delim; cmd++) { if (len + from_len + 1 >= size) { + char *nwith; size += from_len + 1; - with = realloc(with, size); + nwith = realloc(with, size); + if (nwith == NULL) { + free(with); + return -1; + } + with = nwith; } if (*cmd == '&') { /* safe */ @@ -576,8 +654,10 @@ _history_expand_command(const char *comm tempcmd = _rl_compat_sub(line, from, to, (g_on) ? 1 : 0); - free(line); - line = tempcmd; + if (tempcmd) { + free(line); + line = tempcmd; + } g_on = 0; } } @@ -623,14 +703,21 @@ _history_expand_command(const char *comm } cmdsize = 1, cmdlen = 0; - tempcmd = malloc(cmdsize); + if ((tempcmd = malloc(cmdsize)) == NULL) + return 0; for (i = start; start <= i && i <= end; i++) { int arr_len; arr_len = strlen(arr[i]); if (cmdlen + arr_len + 1 >= cmdsize) { + char *ntempcmd; cmdsize += arr_len + 1; - tempcmd = realloc(tempcmd, cmdsize); + ntempcmd = realloc(tempcmd, cmdsize); + if (ntempcmd == NULL) { + free(tempcmd); + return 0; + } + tempcmd = ntempcmd; } (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ cmdlen += arr_len; @@ -663,6 +750,8 @@ history_expand(char *str, char **output) rl_initialize(); *output = strdup(str); /* do it early */ + if (*output == NULL) + return 0; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ @@ -675,8 +764,14 @@ history_expand(char *str, char **output) } #define ADD_STRING(what, len) \ { \ - if (idx + len + 1 > size) \ - result = realloc(result, (size += len + 1)); \ + if (idx + len + 1 > size) { \ + char *nresult = realloc(result, (size += len + 1));\ + if (nresult == NULL) { \ + free(*output); \ + return 0; \ + } \ + result = nresult; \ + } \ (void)strncpy(&result[idx], what, len); \ idx += len; \ result[idx] = '\0'; \ @@ -790,11 +885,21 @@ history_tokenize(const char *str) } if (result_idx + 2 >= size) { + char **nresult; size <<= 1; - result = realloc(result, size * sizeof(char *)); + nresult = realloc(result, size * sizeof(char *)); + if (nresult == NULL) { + free(result); + return NULL; + } + result = nresult; } len = i - start; temp = malloc(len + 1); + if (temp == NULL) { + free(result); + return NULL; + } (void) strncpy(temp, &str[start], len); temp[len] = '\0'; result[result_idx++] = temp; @@ -1107,7 +1212,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; @@ -1138,7 +1244,7 @@ history_search_pos(const char *str, int /********************************/ -/* completition functions */ +/* completion functions */ /* * does tilde expansion of strings of type ``~user/foo'' @@ -1158,11 +1264,15 @@ tilde_expand(char *txt) return (strdup(txt)); temp = strchr(txt + 1, '/'); - if (temp == NULL) + if (temp == NULL) { temp = strdup(txt + 1); - else { + 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'; } @@ -1176,6 +1286,8 @@ tilde_expand(char *txt) 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); @@ -1200,28 +1312,45 @@ filename_completion_function(const char size_t len; if (state == 0 || dir == NULL) { - if (dir != NULL) { - closedir(dir); - dir = NULL; - } temp = strrchr(text, '/'); if (temp) { + char *nptr; temp++; - filename = realloc(filename, strlen(temp) + 1); + 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 */ - dirname = realloc(dirname, len + 1); + nptr = realloc(dirname, len + 1); + if (nptr == NULL) { + free(filename); + return NULL; + } + dirname = nptr; (void) strncpy(dirname, text, len); dirname[len] = '\0'; } else { filename = strdup(text); + if (filename == NULL) + return NULL; dirname = NULL; } /* support for ``~user'' syntax */ if (dirname && *dirname == '~') { + char *nptr; temp = tilde_expand(dirname); - dirname = realloc(dirname, strlen(temp) + 1); + 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 */ } @@ -1230,6 +1359,10 @@ filename_completion_function(const char if (filename_len == 0) return (NULL); /* no expansion possible */ + if (dir != NULL) { + (void)closedir(dir); + dir = NULL; + } dir = opendir(dirname ? dirname : "."); if (!dir) return (NULL); /* cannot open the directory */ @@ -1259,14 +1392,19 @@ filename_completion_function(const char #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 + } else { + (void)closedir(dir); + dir = NULL; temp = NULL; + } return (temp); } @@ -1309,38 +1447,47 @@ 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) { - if (matches + 1 >= match_list_len) { - match_list_len <<= 1; - match_list = realloc(match_list, + 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 (char **) NULL; /* nothing found */ + return NULL; /* nothing found */ /* find least denominator and insert it to match_list[0] */ which = 2; @@ -1354,14 +1501,15 @@ completion_matches(const char *text, CPF } 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 */ - 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); @@ -1374,8 +1522,8 @@ 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]; + const char *s1 = ((const char * const *)i1)[0]; + const char *s2 = ((const char * const *)i2)[0]; return strcasecmp(s1, s2); } @@ -1432,7 +1580,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; @@ -1445,7 +1593,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); @@ -1467,7 +1615,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) @@ -1493,11 +1641,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]; @@ -1631,7 +1780,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) @@ -1660,3 +1809,100 @@ 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); + 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; +}