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.82 retrieving revision 1.93 diff -u -p -r1.82 -r1.93 --- src/lib/libedit/readline.c 2009/03/31 17:53:03 1.82 +++ src/lib/libedit/readline.c 2011/07/28 00:54:26 1.93 @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.82 2009/03/31 17:53:03 christos Exp $ */ +/* $NetBSD: readline.c,v 1.93 2011/07/28 00:54:26 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.82 2009/03/31 17:53:03 christos Exp $"); +__RCSID("$NetBSD: readline.c,v 1.93 2011/07/28 00:54:26 christos Exp $"); #endif /* not lint && not SCCSID */ #include @@ -50,7 +50,7 @@ __RCSID("$NetBSD: readline.c,v 1.82 2009 #ifdef HAVE_VIS_H #include #else -#include "np/vis.h" +#include "vis.h" #endif #include "readline/readline.h" #include "el.h" @@ -70,6 +70,7 @@ void rl_deprep_terminal(void); /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ const char *rl_library_version = "EditLine wrapper"; +int rl_readline_version = RL_READLINE_VERSION; static char empty[] = { '\0' }; static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' }; static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', @@ -118,6 +119,7 @@ Function *rl_startup_hook = NULL; VFunction *rl_completion_display_matches_hook = NULL; VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal; VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal; +KEYMAP_ENTRY_ARRAY emacs_meta_keymap; /* * The current prompt string. @@ -214,6 +216,33 @@ _getc_function(EditLine *el, char *c) return 1; } +static void +_resize_fun(EditLine *el, void *a) +{ + const LineInfo *li; + char **ap = a; + + li = el_line(el); + /* a cheesy way to get rid of const cast. */ + *ap = memchr(li->buffer, *li->buffer, 1); +} + +static const char _dothistory[] = "/.history"; + +static const char * +_default_history_file(void) +{ + struct passwd *p; + static char path[PATH_MAX]; + + if (*path) + return path; + if ((p = getpwuid(getuid())) == NULL) + return NULL; + strlcpy(path, p->pw_dir, PATH_MAX); + strlcat(path, _dothistory, PATH_MAX); + return path; +} /* * READLINE compatibility stuff @@ -250,7 +279,6 @@ int rl_initialize(void) { HistEvent ev; - const LineInfo *li; int editmode = 1; struct termios t; @@ -284,6 +312,9 @@ rl_initialize(void) max_input_history = INT_MAX; el_set(e, EL_HIST, history, h); + /* Setup resize function */ + el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer); + /* setup getc function if valid */ if (rl_getc_function) el_set(e, EL_GETCFN, _getc_function); @@ -329,9 +360,7 @@ rl_initialize(void) * Unfortunately, some applications really do use rl_point * and rl_line_buffer directly. */ - li = el_line(e); - /* a cheesy way to get rid of const cast. */ - rl_line_buffer = memchr(li->buffer, *li->buffer, 1); + _resize_fun(e, &rl_line_buffer); _rl_update_pos(); if (rl_startup_hook) @@ -487,7 +516,7 @@ get_history_event(const char *cmd, int * if (history(h, &ev, H_FIRST) != 0) return(NULL); *cindex = cmd[idx]? (idx + 1):idx; - return(ev.str); + return ev.str; } sign = 0; if (cmd[idx] == '-') { @@ -648,9 +677,11 @@ _history_expand_command(const char *comm return(-1); if (!has_mods) { - *result = strdup(aptr? aptr : ptr); + *result = strdup(aptr ? aptr : ptr); if (aptr) free(aptr); + if (*result == NULL) + return -1; return(1); } @@ -977,15 +1008,13 @@ char * history_arg_extract(int start, int end, const char *str) { size_t i, len, max; - char **arr, *result; + char **arr, *result = NULL; arr = history_tokenize(str); if (!arr) - return(NULL); - if (arr && *arr == NULL) { - free(arr); - return(NULL); - } + return NULL; + if (arr && *arr == NULL) + goto out; for (max = 0; arr[max]; max++) continue; @@ -1000,15 +1029,16 @@ history_arg_extract(int start, int end, if (start < 0) start = end; - if (start < 0 || end < 0 || (size_t)start > max || (size_t)end > max || start > end) - return(NULL); + if (start < 0 || end < 0 || (size_t)start > max || + (size_t)end > max || start > end) + goto out; for (i = start, len = 0; i <= (size_t)end; i++) len += strlen(arr[i]) + 1; len++; result = malloc(len); if (result == NULL) - return NULL; + goto out; for (i = start, len = 0; i <= (size_t)end; i++) { (void)strcpy(result + len, arr[i]); @@ -1018,11 +1048,12 @@ history_arg_extract(int start, int end, } result[len] = '\0'; +out: for (i = 0; arr[i]; i++) free(arr[i]); free(arr); - return(result); + return result; } /* @@ -1125,6 +1156,142 @@ history_is_stifled(void) return (max_input_history != INT_MAX); } +static const char _history_tmp_template[] = "/tmp/.historyXXXXXX"; + +int +history_truncate_file (const char *filename, int nlines) +{ + int ret = 0; + FILE *fp, *tp; + char template[sizeof(_history_tmp_template)]; + char buf[4096]; + int fd; + char *cp; + off_t off; + int count = 0; + ssize_t left = 0; + + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + if ((fp = fopen(filename, "r+")) == NULL) + return errno; + strcpy(template, _history_tmp_template); + if ((fd = mkstemp(template)) == -1) { + ret = errno; + goto out1; + } + + if ((tp = fdopen(fd, "r+")) == NULL) { + close(fd); + ret = errno; + goto out2; + } + + for(;;) { + if (fread(buf, sizeof(buf), 1, fp) != 1) { + if (ferror(fp)) { + ret = errno; + break; + } + if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) == + (off_t)-1) { + ret = errno; + break; + } + left = fread(buf, 1, sizeof(buf), fp); + if (ferror(fp)) { + ret = errno; + break; + } + if (left == 0) { + count--; + left = sizeof(buf); + } else if (fwrite(buf, (size_t)left, 1, tp) != 1) { + ret = errno; + break; + } + fflush(tp); + break; + } + if (fwrite(buf, sizeof(buf), 1, tp) != 1) { + ret = errno; + break; + } + count++; + } + if (ret) + goto out3; + cp = buf + left - 1; + if(*cp != '\n') + cp++; + for(;;) { + while (--cp >= buf) { + if (*cp == '\n') { + if (--nlines == 0) { + if (++cp >= buf + sizeof(buf)) { + count++; + cp = buf; + } + break; + } + } + } + if (nlines <= 0 || count == 0) + break; + count--; + if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) { + ret = errno; + break; + } + if (fread(buf, sizeof(buf), 1, tp) != 1) { + if (ferror(tp)) { + ret = errno; + break; + } + ret = EAGAIN; + break; + } + cp = buf + sizeof(buf); + } + + if (ret || nlines > 0) + goto out3; + + if (fseeko(fp, 0, SEEK_SET) == (off_t)-1) { + ret = errno; + goto out3; + } + + if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) == + (off_t)-1) { + ret = errno; + goto out3; + } + + for(;;) { + if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) { + if (ferror(fp)) + ret = errno; + break; + } + if (fwrite(buf, (size_t)left, 1, fp) != 1) { + ret = errno; + break; + } + } + fflush(fp); + if((off = ftello(fp)) > 0) + (void)ftruncate(fileno(fp), off); +out3: + fclose(tp); +out2: + unlink(template); +out1: + fclose(fp); + + return ret; +} + /* * read history from a file given @@ -1136,7 +1303,10 @@ read_history(const char *filename) if (h == NULL || e == NULL) rl_initialize(); - return (history(h, &ev, H_LOAD, filename) == -1); + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + return (history(h, &ev, H_LOAD, filename) == -1 ? + (errno ? errno : EINVAL) : 0); } @@ -1150,7 +1320,10 @@ write_history(const char *filename) if (h == NULL || e == NULL) rl_initialize(); - return (history(h, &ev, H_SAVE, filename) == -1); + if (filename == NULL && (filename = _default_history_file()) == NULL) + return errno; + return (history(h, &ev, H_SAVE, filename) == -1 ? + (errno ? errno : EINVAL) : 0); } @@ -1174,16 +1347,15 @@ history_get(int num) return (NULL); curr_num = ev.num; - /* start from most recent */ - if (history(h, &ev, H_FIRST) != 0) + /* start from the oldest */ + if (history(h, &ev, H_LAST) != 0) return (NULL); /* error */ - /* look backwards for event matching specified offset */ - if (history(h, &ev, H_NEXT_EVENT, num + 1)) + /* look forwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVDATA, num, &she.data)) return (NULL); she.line = ev.str; - she.data = NULL; /* restore pointer to where it was */ (void)history(h, &ev, H_SET, curr_num); @@ -1217,26 +1389,75 @@ add_history(const char *line) HIST_ENTRY * remove_history(int num) { - HIST_ENTRY *she; + HIST_ENTRY *he; HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); - if (history(h, &ev, H_DEL, num) != 0) + if ((he = malloc(sizeof(*he))) == NULL) return NULL; - if ((she = malloc(sizeof(*she))) == NULL) + if (history(h, &ev, H_DELDATA, num, &he->data) != 0) { + free(he); return NULL; + } - she->line = ev.str; - she->data = NULL; + he->line = ev.str; + if (history(h, &ev, H_GETSIZE) == 0) + history_length = ev.num; - return she; + return he; } /* + * replace the line and data of the num-th entry + */ +HIST_ENTRY * +replace_history_entry(int num, const char *line, histdata_t data) +{ + HIST_ENTRY *he; + HistEvent ev; + int curr_num; + + if (h == NULL || e == NULL) + rl_initialize(); + + /* save current position */ + if (history(h, &ev, H_CURR) != 0) + return NULL; + curr_num = ev.num; + + /* start from the oldest */ + if (history(h, &ev, H_LAST) != 0) + return NULL; /* error */ + + if ((he = malloc(sizeof(*he))) == NULL) + return NULL; + + /* look forwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) + goto out; + + he->line = strdup(ev.str); + if (he->line == NULL) + goto out; + + if (history(h, &ev, H_REPLACE, line, data)) + goto out; + + /* restore pointer to where it was */ + if (history(h, &ev, H_SET, curr_num)) + goto out; + + return he; +out: + free(he); + return NULL; +} + +/* * clear the history list - delete all entries */ void @@ -1244,7 +1465,8 @@ clear_history(void) { HistEvent ev; - history(h, &ev, H_CLEAR); + (void)history(h, &ev, H_CLEAR); + history_length = 0; } @@ -1261,7 +1483,7 @@ where_history(void) return (0); curr_num = ev.num; - history(h, &ev, H_FIRST); + (void)history(h, &ev, H_FIRST); off = 1; while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) off++; @@ -1295,10 +1517,10 @@ history_total_bytes(void) return (-1); curr_num = ev.num; - history(h, &ev, H_FIRST); + (void)history(h, &ev, H_FIRST); size = 0; do - size += strlen(ev.str); + size += strlen(ev.str) * sizeof(*ev.str); while (history(h, &ev, H_NEXT) == 0); /* get to the same position as before */ @@ -1317,14 +1539,18 @@ history_set_pos(int pos) HistEvent ev; int curr_num; - if (pos > history_length || pos < 0) + if (pos >= history_length || pos < 0) return (-1); - history(h, &ev, H_CURR); + (void)history(h, &ev, H_CURR); curr_num = ev.num; - if (history(h, &ev, H_SET, pos)) { - history(h, &ev, H_SET, curr_num); + /* + * use H_DELDATA to set to nth history (without delete) by passing + * (void **)-1 + */ + if (history(h, &ev, H_DELDATA, pos, (void **)-1)) { + (void)history(h, &ev, H_SET, curr_num); return(-1); } return (0); @@ -1373,7 +1599,7 @@ history_search(const char *str, int dire if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } - history(h, &ev, H_SET, curr_num); + (void)history(h, &ev, H_SET, curr_num); return (-1); } @@ -1386,7 +1612,8 @@ history_search_prefix(const char *str, i { HistEvent ev; - return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); + return (history(h, &ev, direction < 0 ? + H_PREV_STR : H_NEXT_STR, str)); } @@ -1412,7 +1639,6 @@ history_search_pos(const char *str, if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) return (-1); - for (;;) { if (strstr(ev.str, str)) return (off); @@ -1421,7 +1647,8 @@ history_search_pos(const char *str, } /* set "current" pointer back to previous state */ - history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); + (void)history(h, &ev, + pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); return (-1); } @@ -1470,9 +1697,9 @@ username_completion_function(const char if (pwd == NULL) { endpwent(); - return (NULL); + return NULL; } - return (strdup(pwd->pw_name)); + return strdup(pwd->pw_name); } @@ -1518,6 +1745,10 @@ _rl_completion_append_character_function int rl_complete(int ignore __attribute__((__unused__)), int invoking_key) { +#ifdef WIDECHAR + static ct_buffer_t wbreak_conv, sprefix_conv; +#endif + if (h == NULL || e == NULL) rl_initialize(); @@ -1533,11 +1764,14 @@ rl_complete(int ignore __attribute__((__ return fn_complete(e, (CPFunction *)rl_completion_entry_function, rl_attempted_completion_function, - rl_basic_word_break_characters, rl_special_prefixes, + ct_decode_string(rl_basic_word_break_characters, &wbreak_conv), + ct_decode_string(rl_special_prefixes, &sprefix_conv), _rl_completion_append_character_function, (size_t)rl_completion_query_items, &rl_completion_type, &rl_attempted_completion_over, &rl_point, &rl_end); + + } @@ -1556,7 +1790,7 @@ _el_rl_complete(EditLine *el __attribute * bind key c to readline-type function func */ int -rl_bind_key(int c, int func(int, int)) +rl_bind_key(int c, rl_command_func_t *func) { int retval = -1; @@ -1623,6 +1857,20 @@ rl_insert(int count, int c) return (0); } +int +rl_insert_text(const char *text) +{ + if (!text || *text == 0) + return (0); + + if (h == NULL || e == NULL) + rl_initialize(); + + if (el_insertstr(e, text) < 0) + return (0); + return (int)strlen(text); +} + /*ARGSUSED*/ int rl_newline(int count, int c) @@ -1686,7 +1934,7 @@ rl_callback_read_char() } else wbuf = NULL; (*(void (*)(const char *))rl_linefunc)(wbuf); - el_set(e, EL_UNBUFFERED, 1); + //el_set(e, EL_UNBUFFERED, 1); } } @@ -1864,6 +2112,7 @@ rl_completion_matches(const char *str, r return NULL; while ((match = (*fun)(str, (int)(len - 1))) != NULL) { + list[len++] = match; if (len == max) { char **nl; max += 10; @@ -1871,7 +2120,6 @@ rl_completion_matches(const char *str, r goto out; list = nl; } - list[len++] = match; } if (len == 1) goto out; @@ -1933,6 +2181,17 @@ _rl_qsort_string_compare(char **s1, char return strcoll(*s1, *s2); } +HISTORY_STATE * +history_get_history_state(void) +{ + HISTORY_STATE *hs; + + if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL) + return (NULL); + hs->length = history_length; + return (hs); +} + int /*ARGSUSED*/ rl_kill_text(int from, int to) @@ -1967,7 +2226,19 @@ rl_generic_bind(int type, const char * k int /*ARGSUSED*/ -rl_bind_key_in_map(int key, Function *fun, Keymap k) +rl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k) +{ + return 0; +} + +/* unsupported, but needed by python */ +void +rl_cleanup_after_signal(void) +{ +} + +int +rl_on_new_line(void) { return 0; }