"Fossies" - the Fresh Open Source Software Archive

Member "tnftp-20200705/libedit/readline.c" (4 Jul 2020, 49989 Bytes) of package /linux/privat/tnftp-20200705.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "readline.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20151004_vs_20200705.

    1 /*  $NetBSD: readline.c,v 1.8 2020/07/04 13:43:21 lukem Exp $   */
    2 /*  from    NetBSD: readline.c,v 1.159 2019/10/09 14:31:07 christos Exp */
    3 
    4 /*-
    5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jaromir Dolecek.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include "config.h"
   34 
   35 #if 0 /* tnftp */
   36 #if !defined(lint) && !defined(SCCSID)
   37 __RCSID(" NetBSD: readline.c,v 1.159 2019/10/09 14:31:07 christos Exp  ");
   38 #endif /* not lint && not SCCSID */
   39 
   40 #include <sys/types.h>
   41 #include <sys/stat.h>
   42 #include <ctype.h>
   43 #include <dirent.h>
   44 #include <errno.h>
   45 #include <fcntl.h>
   46 #include <limits.h>
   47 #include <pwd.h>
   48 #include <setjmp.h>
   49 #include <stdint.h>
   50 #include <stdio.h>
   51 #include <stdlib.h>
   52 #include <string.h>
   53 #include <unistd.h>
   54 #include <vis.h>
   55 #endif /* tnftp */
   56 
   57 #include "readline/readline.h"
   58 #include "el.h"
   59 #include "fcns.h"
   60 #include "filecomplete.h"
   61 
   62 void rl_prep_terminal(int);
   63 void rl_deprep_terminal(void);
   64 
   65 /* for rl_complete() */
   66 #define TAB     '\r'
   67 
   68 /* see comment at the #ifdef for sense of this */
   69 /* #define GDB_411_HACK */
   70 
   71 /* readline compatibility stuff - look at readline sources/documentation */
   72 /* to see what these variables mean */
   73 const char *rl_library_version = "EditLine wrapper";
   74 int rl_readline_version = RL_READLINE_VERSION;
   75 static char empty[] = { '\0' };
   76 static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
   77 static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
   78     '>', '<', '=', ';', '|', '&', '{', '(', '\0' };
   79 const char *rl_readline_name = empty;
   80 FILE *rl_instream = NULL;
   81 FILE *rl_outstream = NULL;
   82 int rl_point = 0;
   83 int rl_end = 0;
   84 char *rl_line_buffer = NULL;
   85 rl_vcpfunc_t *rl_linefunc = NULL;
   86 int rl_done = 0;
   87 rl_hook_func_t *rl_event_hook = NULL;
   88 KEYMAP_ENTRY_ARRAY emacs_standard_keymap,
   89     emacs_meta_keymap,
   90     emacs_ctlx_keymap;
   91 /*
   92  * The following is not implemented; we always catch signals in the
   93  * libedit fashion: set handlers on entry to el_gets() and clear them
   94  * on the way out. This simplistic approach works for most cases; if
   95  * it does not work for your application, please let us know.
   96  */
   97 int rl_catch_signals = 1;
   98 int rl_catch_sigwinch = 1;
   99 
  100 int history_base = 1;       /* probably never subject to change */
  101 int history_length = 0;
  102 int history_offset = 0;
  103 int max_input_history = 0;
  104 char history_expansion_char = '!';
  105 char history_subst_char = '^';
  106 char *history_no_expand_chars = expand_chars;
  107 Function *history_inhibit_expansion_function = NULL;
  108 char *history_arg_extract(int start, int end, const char *str);
  109 
  110 int rl_inhibit_completion = 0;
  111 int rl_attempted_completion_over = 0;
  112 const char *rl_basic_word_break_characters = break_chars;
  113 char *rl_completer_word_break_characters = NULL;
  114 const char *rl_completer_quote_characters = NULL;
  115 rl_compentry_func_t *rl_completion_entry_function = NULL;
  116 char *(*rl_completion_word_break_hook)(void) = NULL;
  117 rl_completion_func_t *rl_attempted_completion_function = NULL;
  118 Function *rl_pre_input_hook = NULL;
  119 Function *rl_startup1_hook = NULL;
  120 int (*rl_getc_function)(FILE *) = NULL;
  121 char *rl_terminal_name = NULL;
  122 int rl_already_prompted = 0;
  123 int rl_filename_completion_desired = 0;
  124 int rl_ignore_completion_duplicates = 0;
  125 int readline_echoing_p = 1;
  126 int _rl_print_completions_horizontally = 0;
  127 VFunction *rl_redisplay_function = NULL;
  128 Function *rl_startup_hook = NULL;
  129 int rl_did_startup_hook = 0;
  130 VFunction *rl_completion_display_matches_hook = NULL;
  131 VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
  132 VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
  133 KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
  134 
  135 /*
  136  * The current prompt string.
  137  */
  138 char *rl_prompt = NULL;
  139 /*
  140  * This is set to character indicating type of completion being done by
  141  * rl_complete_internal(); this is available for application completion
  142  * functions.
  143  */
  144 int rl_completion_type = 0;
  145 
  146 /*
  147  * If more than this number of items results from query for possible
  148  * completions, we ask user if they are sure to really display the list.
  149  */
  150 int rl_completion_query_items = 100;
  151 
  152 /*
  153  * List of characters which are word break characters, but should be left
  154  * in the parsed text when it is passed to the completion function.
  155  * Shell uses this to help determine what kind of completing to do.
  156  */
  157 const char *rl_special_prefixes = NULL;
  158 
  159 /*
  160  * This is the character appended to the completed words if at the end of
  161  * the line. Default is ' ' (a space).
  162  */
  163 int rl_completion_append_character = ' ';
  164 
  165 /* stuff below is used internally by libedit for readline emulation */
  166 
  167 static History *h = NULL;
  168 static EditLine *e = NULL;
  169 static rl_command_func_t *map[256];
  170 static jmp_buf topbuf;
  171 
  172 /* internal functions */
  173 static unsigned char     _el_rl_complete(EditLine *, int);
  174 static unsigned char     _el_rl_tstp(EditLine *, int);
  175 static char     *_get_prompt(EditLine *);
  176 static int       _getc_function(EditLine *, wchar_t *);
  177 static int       _history_expand_command(const char *, size_t, size_t,
  178     char **);
  179 static char     *_rl_compat_sub(const char *, const char *,
  180     const char *, int);
  181 static int       _rl_event_read_char(EditLine *, wchar_t *);
  182 static void      _rl_update_pos(void);
  183 
  184 static HIST_ENTRY rl_he;
  185 
  186 /* ARGSUSED */
  187 static char *
  188 _get_prompt(EditLine *el __attribute__((__unused__)))
  189 {
  190     rl_already_prompted = 1;
  191     return rl_prompt;
  192 }
  193 
  194 
  195 /*
  196  * read one key from user defined input function
  197  */
  198 static int
  199 /*ARGSUSED*/
  200 _getc_function(EditLine *el __attribute__((__unused__)), wchar_t *c)
  201 {
  202     int i;
  203 
  204     i = (*rl_getc_function)(rl_instream);
  205     if (i == -1)
  206         return 0;
  207     *c = (wchar_t)i;
  208     return 1;
  209 }
  210 
  211 static void
  212 _resize_fun(EditLine *el, void *a)
  213 {
  214     const LineInfo *li;
  215     char **ap = a;
  216 
  217     li = el_line(el);
  218     /* a cheesy way to get rid of const cast. */
  219     *ap = memchr(li->buffer, *li->buffer, (size_t)1);
  220 }
  221 
  222 static const char *
  223 _default_history_file(void)
  224 {
  225     struct passwd *p;
  226     static char *path;
  227     size_t len;
  228 
  229     if (path)
  230         return path;
  231 
  232     if ((p = getpwuid(getuid())) == NULL)
  233         return NULL;
  234 
  235     len = strlen(p->pw_dir) + sizeof("/.history");
  236     if ((path = malloc(len)) == NULL)
  237         return NULL;
  238 
  239     (void)snprintf(path, len, "%s/.history", p->pw_dir);
  240     return path;
  241 }
  242 
  243 /*
  244  * READLINE compatibility stuff
  245  */
  246 
  247 /*
  248  * Set the prompt
  249  */
  250 int
  251 rl_set_prompt(const char *prompt)
  252 {
  253     char *p;
  254 
  255     if (!prompt)
  256         prompt = "";
  257     if (rl_prompt != NULL && strcmp(rl_prompt, prompt) == 0)
  258         return 0;
  259     if (rl_prompt)
  260         el_free(rl_prompt);
  261     rl_prompt = strdup(prompt);
  262     if (rl_prompt == NULL)
  263         return -1;
  264 
  265     while ((p = strchr(rl_prompt, RL_PROMPT_END_IGNORE)) != NULL) {
  266         /* Remove adjacent end/start markers to avoid double-escapes. */
  267         if (p[1] == RL_PROMPT_START_IGNORE) {
  268             memmove(p, p + 2, 1 + strlen(p + 2));
  269         } else {
  270             *p = RL_PROMPT_START_IGNORE;
  271         }
  272     }
  273 
  274     return 0;
  275 }
  276 
  277 /*
  278  * initialize rl compat stuff
  279  */
  280 int
  281 rl_initialize(void)
  282 {
  283     HistEvent ev;
  284     int editmode = 1;
  285     struct termios t;
  286 
  287     if (e != NULL)
  288         el_end(e);
  289     if (h != NULL)
  290         history_end(h);
  291 
  292     if (!rl_instream)
  293         rl_instream = stdin;
  294     if (!rl_outstream)
  295         rl_outstream = stdout;
  296 
  297     /*
  298      * See if we don't really want to run the editor
  299      */
  300     if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0)
  301         editmode = 0;
  302 
  303     e = el_init_internal(rl_readline_name, rl_instream, rl_outstream,
  304         stderr, fileno(rl_instream), fileno(rl_outstream), fileno(stderr),
  305         NO_RESET);
  306 
  307     if (!editmode)
  308         el_set(e, EL_EDITMODE, 0);
  309 
  310     h = history_init();
  311     if (!e || !h)
  312         return -1;
  313 
  314     history(h, &ev, H_SETSIZE, INT_MAX);    /* unlimited */
  315     history_length = 0;
  316     max_input_history = INT_MAX;
  317     el_set(e, EL_HIST, history, h);
  318 
  319     /* Setup resize function */
  320     el_set(e, EL_RESIZE, _resize_fun, &rl_line_buffer);
  321 
  322     /* setup getc function if valid */
  323     if (rl_getc_function)
  324         el_set(e, EL_GETCFN, _getc_function);
  325 
  326     /* for proper prompt printing in readline() */
  327     if (rl_set_prompt("") == -1) {
  328         history_end(h);
  329         el_end(e);
  330         return -1;
  331     }
  332     el_set(e, EL_PROMPT_ESC, _get_prompt, RL_PROMPT_START_IGNORE);
  333     el_set(e, EL_SIGNAL, rl_catch_signals);
  334 
  335     /* set default mode to "emacs"-style and read setting afterwards */
  336     /* so this can be overridden */
  337     el_set(e, EL_EDITOR, "emacs");
  338     if (rl_terminal_name != NULL)
  339         el_set(e, EL_TERMINAL, rl_terminal_name);
  340     else
  341         el_get(e, EL_TERMINAL, &rl_terminal_name);
  342 
  343     /*
  344      * Word completion - this has to go AFTER rebinding keys
  345      * to emacs-style.
  346      */
  347     el_set(e, EL_ADDFN, "rl_complete",
  348         "ReadLine compatible completion function",
  349         _el_rl_complete);
  350     el_set(e, EL_BIND, "^I", "rl_complete", NULL);
  351 
  352     /*
  353      * Send TSTP when ^Z is pressed.
  354      */
  355     el_set(e, EL_ADDFN, "rl_tstp",
  356         "ReadLine compatible suspend function",
  357         _el_rl_tstp);
  358     el_set(e, EL_BIND, "^Z", "rl_tstp", NULL);
  359 
  360     /*
  361      * Set some readline compatible key-bindings.
  362      */
  363     el_set(e, EL_BIND, "^R", "em-inc-search-prev", NULL);
  364 
  365     /*
  366      * Allow the use of Home/End keys.
  367      */
  368     el_set(e, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
  369     el_set(e, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
  370     el_set(e, EL_BIND, "\\e[7~", "ed-move-to-beg", NULL);
  371     el_set(e, EL_BIND, "\\e[8~", "ed-move-to-end", NULL);
  372     el_set(e, EL_BIND, "\\e[H", "ed-move-to-beg", NULL);
  373     el_set(e, EL_BIND, "\\e[F", "ed-move-to-end", NULL);
  374 
  375     /*
  376      * Allow the use of the Delete/Insert keys.
  377      */
  378     el_set(e, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
  379     el_set(e, EL_BIND, "\\e[2~", "ed-quoted-insert", NULL);
  380 
  381     /*
  382      * Ctrl-left-arrow and Ctrl-right-arrow for word moving.
  383      */
  384     el_set(e, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
  385     el_set(e, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
  386     el_set(e, EL_BIND, "\\e[5C", "em-next-word", NULL);
  387     el_set(e, EL_BIND, "\\e[5D", "ed-prev-word", NULL);
  388     el_set(e, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
  389     el_set(e, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
  390 
  391     /* read settings from configuration file */
  392     el_source(e, NULL);
  393 
  394     /*
  395      * Unfortunately, some applications really do use rl_point
  396      * and rl_line_buffer directly.
  397      */
  398     _resize_fun(e, &rl_line_buffer);
  399     _rl_update_pos();
  400 
  401     tty_end(e, TCSADRAIN);
  402 
  403     return 0;
  404 }
  405 
  406 
  407 /*
  408  * read one line from input stream and return it, chomping
  409  * trailing newline (if there is any)
  410  */
  411 char *
  412 readline(const char *p)
  413 {
  414     HistEvent ev;
  415     const char * volatile prompt = p;
  416     int count;
  417     const char *ret;
  418     char *buf;
  419     static int used_event_hook;
  420 
  421     if (e == NULL || h == NULL)
  422         rl_initialize();
  423     if (rl_did_startup_hook == 0 && rl_startup_hook) {
  424         rl_did_startup_hook = 1;
  425         (*rl_startup_hook)(NULL, 0);
  426     }
  427     tty_init(e);
  428 
  429 
  430     rl_done = 0;
  431 
  432     (void)setjmp(topbuf);
  433     buf = NULL;
  434 
  435     /* update prompt accordingly to what has been passed */
  436     if (rl_set_prompt(prompt) == -1)
  437         goto out;
  438 
  439     if (rl_pre_input_hook)
  440         (*rl_pre_input_hook)(NULL, 0);
  441 
  442     if (rl_event_hook && !(e->el_flags & NO_TTY)) {
  443         el_set(e, EL_GETCFN, _rl_event_read_char);
  444         used_event_hook = 1;
  445     }
  446 
  447     if (!rl_event_hook && used_event_hook) {
  448         el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN);
  449         used_event_hook = 0;
  450     }
  451 
  452     rl_already_prompted = 0;
  453 
  454     /* get one line from input stream */
  455     ret = el_gets(e, &count);
  456 
  457     if (ret && count > 0) {
  458         int lastidx;
  459 
  460         buf = strdup(ret);
  461         if (buf == NULL)
  462             goto out;
  463         lastidx = count - 1;
  464         if (buf[lastidx] == '\n')
  465             buf[lastidx] = '\0';
  466     } else
  467         buf = NULL;
  468 
  469     history(h, &ev, H_GETSIZE);
  470     history_length = ev.num;
  471 
  472 out:
  473     tty_end(e, TCSADRAIN);
  474     return buf;
  475 }
  476 
  477 /*
  478  * history functions
  479  */
  480 
  481 /*
  482  * is normally called before application starts to use
  483  * history expansion functions
  484  */
  485 void
  486 using_history(void)
  487 {
  488     if (h == NULL || e == NULL)
  489         rl_initialize();
  490     history_offset = history_length;
  491 }
  492 
  493 
  494 /*
  495  * substitute ``what'' with ``with'', returning resulting string; if
  496  * globally == 1, substitutes all occurrences of what, otherwise only the
  497  * first one
  498  */
  499 static char *
  500 _rl_compat_sub(const char *str, const char *what, const char *with,
  501     int globally)
  502 {
  503     const   char    *s;
  504     char    *r, *result;
  505     size_t  len, with_len, what_len;
  506 
  507     len = strlen(str);
  508     with_len = strlen(with);
  509     what_len = strlen(what);
  510 
  511     /* calculate length we need for result */
  512     s = str;
  513     while (*s) {
  514         if (*s == *what && !strncmp(s, what, what_len)) {
  515             len += with_len - what_len;
  516             if (!globally)
  517                 break;
  518             s += what_len;
  519         } else
  520             s++;
  521     }
  522     r = result = el_calloc(len + 1, sizeof(*r));
  523     if (result == NULL)
  524         return NULL;
  525     s = str;
  526     while (*s) {
  527         if (*s == *what && !strncmp(s, what, what_len)) {
  528             memcpy(r, with, with_len);
  529             r += with_len;
  530             s += what_len;
  531             if (!globally) {
  532                 (void)strcpy(r, s);
  533                 return result;
  534             }
  535         } else
  536             *r++ = *s++;
  537     }
  538     *r = '\0';
  539     return result;
  540 }
  541 
  542 static  char    *last_search_pat;   /* last !?pat[?] search pattern */
  543 static  char    *last_search_match; /* last !?pat[?] that matched */
  544 
  545 const char *
  546 get_history_event(const char *cmd, int *cindex, int qchar)
  547 {
  548     int idx, sign, sub, num, begin, ret;
  549     size_t len;
  550     char    *pat;
  551     const char *rptr;
  552     HistEvent ev;
  553 
  554     idx = *cindex;
  555     if (cmd[idx++] != history_expansion_char)
  556         return NULL;
  557 
  558     /* find out which event to take */
  559     if (cmd[idx] == history_expansion_char || cmd[idx] == '\0') {
  560         if (history(h, &ev, H_FIRST) != 0)
  561             return NULL;
  562         *cindex = cmd[idx]? (idx + 1):idx;
  563         return ev.str;
  564     }
  565     sign = 0;
  566     if (cmd[idx] == '-') {
  567         sign = 1;
  568         idx++;
  569     }
  570 
  571     if ('0' <= cmd[idx] && cmd[idx] <= '9') {
  572         HIST_ENTRY *he;
  573 
  574         num = 0;
  575         while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
  576             num = num * 10 + cmd[idx] - '0';
  577             idx++;
  578         }
  579         if (sign)
  580             num = history_length - num + history_base;
  581 
  582         if (!(he = history_get(num)))
  583             return NULL;
  584 
  585         *cindex = idx;
  586         return he->line;
  587     }
  588     sub = 0;
  589     if (cmd[idx] == '?') {
  590         sub = 1;
  591         idx++;
  592     }
  593     begin = idx;
  594     while (cmd[idx]) {
  595         if (cmd[idx] == '\n')
  596             break;
  597         if (sub && cmd[idx] == '?')
  598             break;
  599         if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
  600                     || cmd[idx] == '\t' || cmd[idx] == qchar))
  601             break;
  602         idx++;
  603     }
  604     len = (size_t)idx - (size_t)begin;
  605     if (sub && cmd[idx] == '?')
  606         idx++;
  607     if (sub && len == 0 && last_search_pat && *last_search_pat)
  608         pat = last_search_pat;
  609     else if (len == 0)
  610         return NULL;
  611     else {
  612         if ((pat = el_calloc(len + 1, sizeof(*pat))) == NULL)
  613             return NULL;
  614         (void)strlcpy(pat, cmd + begin, len + 1);
  615     }
  616 
  617     if (history(h, &ev, H_CURR) != 0) {
  618         if (pat != last_search_pat)
  619             el_free(pat);
  620         return NULL;
  621     }
  622     num = ev.num;
  623 
  624     if (sub) {
  625         if (pat != last_search_pat) {
  626             if (last_search_pat)
  627                 el_free(last_search_pat);
  628             last_search_pat = pat;
  629         }
  630         ret = history_search(pat, -1);
  631     } else
  632         ret = history_search_prefix(pat, -1);
  633 
  634     if (ret == -1) {
  635         /* restore to end of list on failed search */
  636         history(h, &ev, H_FIRST);
  637         (void)fprintf(rl_outstream, "%s: Event not found\n", pat);
  638         if (pat != last_search_pat)
  639             el_free(pat);
  640         return NULL;
  641     }
  642 
  643     if (sub && len) {
  644         if (last_search_match && last_search_match != pat)
  645             el_free(last_search_match);
  646         last_search_match = pat;
  647     }
  648 
  649     if (pat != last_search_pat)
  650         el_free(pat);
  651 
  652     if (history(h, &ev, H_CURR) != 0)
  653         return NULL;
  654     *cindex = idx;
  655     rptr = ev.str;
  656 
  657     /* roll back to original position */
  658     (void)history(h, &ev, H_SET, num);
  659 
  660     return rptr;
  661 }
  662 
  663 /*
  664  * the real function doing history expansion - takes as argument command
  665  * to do and data upon which the command should be executed
  666  * does expansion the way I've understood readline documentation
  667  *
  668  * returns 0 if data was not modified, 1 if it was and 2 if the string
  669  * should be only printed and not executed; in case of error,
  670  * returns -1 and *result points to NULL
  671  * it's the caller's responsibility to free() the string returned in *result
  672  */
  673 static int
  674 _history_expand_command(const char *command, size_t offs, size_t cmdlen,
  675     char **result)
  676 {
  677     char *tmp, *search = NULL, *aptr;
  678     const char *ptr, *cmd;
  679     static char *from = NULL, *to = NULL;
  680     int start, end, idx, has_mods = 0;
  681     int p_on = 0, g_on = 0;
  682 
  683     *result = NULL;
  684     aptr = NULL;
  685     ptr = NULL;
  686 
  687     /* First get event specifier */
  688     idx = 0;
  689 
  690     if (strchr(":^*$", command[offs + 1])) {
  691         char str[4];
  692         /*
  693         * "!:" is shorthand for "!!:".
  694         * "!^", "!*" and "!$" are shorthand for
  695         * "!!:^", "!!:*" and "!!:$" respectively.
  696         */
  697         str[0] = str[1] = '!';
  698         str[2] = '0';
  699         ptr = get_history_event(str, &idx, 0);
  700         idx = (command[offs + 1] == ':')? 1:0;
  701         has_mods = 1;
  702     } else {
  703         if (command[offs + 1] == '#') {
  704             /* use command so far */
  705             if ((aptr = el_calloc(offs + 1, sizeof(*aptr)))
  706                 == NULL)
  707                 return -1;
  708             (void)strlcpy(aptr, command, offs + 1);
  709             idx = 1;
  710         } else {
  711             int qchar;
  712 
  713             qchar = (offs > 0 && command[offs - 1] == '"')? '"':0;
  714             ptr = get_history_event(command + offs, &idx, qchar);
  715         }
  716         has_mods = command[offs + (size_t)idx] == ':';
  717     }
  718 
  719     if (ptr == NULL && aptr == NULL)
  720         return -1;
  721 
  722     if (!has_mods) {
  723         *result = strdup(aptr ? aptr : ptr);
  724         if (aptr)
  725             el_free(aptr);
  726         if (*result == NULL)
  727             return -1;
  728         return 1;
  729     }
  730 
  731     cmd = command + offs + idx + 1;
  732 
  733     /* Now parse any word designators */
  734 
  735     if (*cmd == '%')    /* last word matched by ?pat? */
  736         tmp = strdup(last_search_match? last_search_match:"");
  737     else if (strchr("^*$-0123456789", *cmd)) {
  738         start = end = -1;
  739         if (*cmd == '^')
  740             start = end = 1, cmd++;
  741         else if (*cmd == '$')
  742             start = -1, cmd++;
  743         else if (*cmd == '*')
  744             start = 1, cmd++;
  745            else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
  746             start = 0;
  747             while (*cmd && '0' <= *cmd && *cmd <= '9')
  748                 start = start * 10 + *cmd++ - '0';
  749 
  750             if (*cmd == '-') {
  751                 if (isdigit((unsigned char) cmd[1])) {
  752                     cmd++;
  753                     end = 0;
  754                     while (*cmd && '0' <= *cmd && *cmd <= '9')
  755                         end = end * 10 + *cmd++ - '0';
  756                 } else if (cmd[1] == '$') {
  757                     cmd += 2;
  758                     end = -1;
  759                 } else {
  760                     cmd++;
  761                     end = -2;
  762                 }
  763             } else if (*cmd == '*')
  764                 end = -1, cmd++;
  765             else
  766                 end = start;
  767         }
  768         tmp = history_arg_extract(start, end, aptr? aptr:ptr);
  769         if (tmp == NULL) {
  770             (void)fprintf(rl_outstream, "%s: Bad word specifier",
  771                 command + offs + idx);
  772             if (aptr)
  773                 el_free(aptr);
  774             return -1;
  775         }
  776     } else
  777         tmp = strdup(aptr? aptr:ptr);
  778 
  779     if (aptr)
  780         el_free(aptr);
  781 
  782     if (*cmd == '\0' || ((size_t)(cmd - (command + offs)) >= cmdlen)) {
  783         *result = tmp;
  784         return 1;
  785     }
  786 
  787     for (; *cmd; cmd++) {
  788         if (*cmd == ':')
  789             continue;
  790         else if (*cmd == 'h') {     /* remove trailing path */
  791             if ((aptr = strrchr(tmp, '/')) != NULL)
  792                 *aptr = '\0';
  793         } else if (*cmd == 't') {   /* remove leading path */
  794             if ((aptr = strrchr(tmp, '/')) != NULL) {
  795                 aptr = strdup(aptr + 1);
  796                 el_free(tmp);
  797                 tmp = aptr;
  798             }
  799         } else if (*cmd == 'r') {   /* remove trailing suffix */
  800             if ((aptr = strrchr(tmp, '.')) != NULL)
  801                 *aptr = '\0';
  802         } else if (*cmd == 'e') {   /* remove all but suffix */
  803             if ((aptr = strrchr(tmp, '.')) != NULL) {
  804                 aptr = strdup(aptr);
  805                 el_free(tmp);
  806                 tmp = aptr;
  807             }
  808         } else if (*cmd == 'p')     /* print only */
  809             p_on = 1;
  810         else if (*cmd == 'g')
  811             g_on = 2;
  812         else if (*cmd == 's' || *cmd == '&') {
  813             char *what, *with, delim;
  814             size_t len, from_len;
  815             size_t size;
  816 
  817             if (*cmd == '&' && (from == NULL || to == NULL))
  818                 continue;
  819             else if (*cmd == 's') {
  820                 delim = *(++cmd), cmd++;
  821                 size = 16;
  822                 what = el_realloc(from, size * sizeof(*what));
  823                 if (what == NULL) {
  824                     el_free(from);
  825                     el_free(tmp);
  826                     return 0;
  827                 }
  828                 len = 0;
  829                 for (; *cmd && *cmd != delim; cmd++) {
  830                     if (*cmd == '\\' && cmd[1] == delim)
  831                         cmd++;
  832                     if (len >= size) {
  833                         char *nwhat;
  834                         nwhat = el_realloc(what,
  835                             (size <<= 1) *
  836                             sizeof(*nwhat));
  837                         if (nwhat == NULL) {
  838                             el_free(what);
  839                             el_free(tmp);
  840                             return 0;
  841                         }
  842                         what = nwhat;
  843                     }
  844                     what[len++] = *cmd;
  845                 }
  846                 what[len] = '\0';
  847                 from = what;
  848                 if (*what == '\0') {
  849                     el_free(what);
  850                     if (search) {
  851                         from = strdup(search);
  852                         if (from == NULL) {
  853                             el_free(tmp);
  854                             return 0;
  855                         }
  856                     } else {
  857                         from = NULL;
  858                         el_free(tmp);
  859                         return -1;
  860                     }
  861                 }
  862                 cmd++;  /* shift after delim */
  863                 if (!*cmd)
  864                     continue;
  865 
  866                 size = 16;
  867                 with = el_realloc(to, size * sizeof(*with));
  868                 if (with == NULL) {
  869                     el_free(to);
  870                     el_free(tmp);
  871                     return -1;
  872                 }
  873                 len = 0;
  874                 from_len = strlen(from);
  875                 for (; *cmd && *cmd != delim; cmd++) {
  876                     if (len + from_len + 1 >= size) {
  877                         char *nwith;
  878                         size += from_len + 1;
  879                         nwith = el_realloc(with,
  880                             size * sizeof(*nwith));
  881                         if (nwith == NULL) {
  882                             el_free(with);
  883                             el_free(tmp);
  884                             return -1;
  885                         }
  886                         with = nwith;
  887                     }
  888                     if (*cmd == '&') {
  889                         /* safe */
  890                         (void)strcpy(&with[len], from);
  891                         len += from_len;
  892                         continue;
  893                     }
  894                     if (*cmd == '\\'
  895                         && (*(cmd + 1) == delim
  896                         || *(cmd + 1) == '&'))
  897                         cmd++;
  898                     with[len++] = *cmd;
  899                 }
  900                 with[len] = '\0';
  901                 to = with;
  902             }
  903 
  904             aptr = _rl_compat_sub(tmp, from, to, g_on);
  905             if (aptr) {
  906                 el_free(tmp);
  907                 tmp = aptr;
  908             }
  909             g_on = 0;
  910         }
  911     }
  912     *result = tmp;
  913     return p_on? 2:1;
  914 }
  915 
  916 
  917 /*
  918  * csh-style history expansion
  919  */
  920 int
  921 history_expand(char *str, char **output)
  922 {
  923     int ret = 0;
  924     size_t idx, i, size;
  925     char *tmp, *result;
  926 
  927     if (h == NULL || e == NULL)
  928         rl_initialize();
  929 
  930     if (history_expansion_char == 0) {
  931         *output = strdup(str);
  932         return 0;
  933     }
  934 
  935     *output = NULL;
  936     if (str[0] == history_subst_char) {
  937         /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
  938         *output = el_calloc(strlen(str) + 4 + 1, sizeof(**output));
  939         if (*output == NULL)
  940             return 0;
  941         (*output)[0] = (*output)[1] = history_expansion_char;
  942         (*output)[2] = ':';
  943         (*output)[3] = 's';
  944         (void)strcpy((*output) + 4, str);
  945         str = *output;
  946     } else {
  947         *output = strdup(str);
  948         if (*output == NULL)
  949             return 0;
  950     }
  951 
  952 #define ADD_STRING(what, len, fr)                   \
  953     {                               \
  954         if (idx + len + 1 > size) {             \
  955             char *nresult = el_realloc(result,      \
  956                 (size += len + 1) * sizeof(*nresult));  \
  957             if (nresult == NULL) {              \
  958                 el_free(*output);           \
  959                 if (/*CONSTCOND*/fr)            \
  960                     el_free(tmp);           \
  961                 return 0;               \
  962             }                       \
  963             result = nresult;               \
  964         }                           \
  965         (void)strlcpy(&result[idx], what, len + 1);     \
  966         idx += len;                     \
  967     }
  968 
  969     result = NULL;
  970     size = idx = 0;
  971     tmp = NULL;
  972     for (i = 0; str[i];) {
  973         int qchar, loop_again;
  974         size_t len, start, j;
  975 
  976         qchar = 0;
  977         loop_again = 1;
  978         start = j = i;
  979 loop:
  980         for (; str[j]; j++) {
  981             if (str[j] == '\\' &&
  982                 str[j + 1] == history_expansion_char) {
  983                 len = strlen(&str[j + 1]) + 1;
  984                 memmove(&str[j], &str[j + 1], len);
  985                 continue;
  986             }
  987             if (!loop_again) {
  988                 if (isspace((unsigned char) str[j])
  989                     || str[j] == qchar)
  990                     break;
  991             }
  992             if (str[j] == history_expansion_char
  993                 && !strchr(history_no_expand_chars, str[j + 1])
  994                 && (!history_inhibit_expansion_function ||
  995                 (*history_inhibit_expansion_function)(str,
  996                 (int)j) == 0))
  997                 break;
  998         }
  999 
 1000         if (str[j] && loop_again) {
 1001             i = j;
 1002             qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
 1003             j++;
 1004             if (str[j] == history_expansion_char)
 1005                 j++;
 1006             loop_again = 0;
 1007             goto loop;
 1008         }
 1009         len = i - start;
 1010         ADD_STRING(&str[start], len, 0);
 1011 
 1012         if (str[i] == '\0' || str[i] != history_expansion_char) {
 1013             len = j - i;
 1014             ADD_STRING(&str[i], len, 0);
 1015             if (start == 0)
 1016                 ret = 0;
 1017             else
 1018                 ret = 1;
 1019             break;
 1020         }
 1021         ret = _history_expand_command (str, i, (j - i), &tmp);
 1022         if (ret > 0 && tmp) {
 1023             len = strlen(tmp);
 1024             ADD_STRING(tmp, len, 1);
 1025         }
 1026         if (tmp) {
 1027             el_free(tmp);
 1028             tmp = NULL;
 1029         }
 1030         i = j;
 1031     }
 1032 
 1033     /* ret is 2 for "print only" option */
 1034     if (ret == 2) {
 1035         add_history(result);
 1036 #ifdef GDB_411_HACK
 1037         /* gdb 4.11 has been shipped with readline, where */
 1038         /* history_expand() returned -1 when the line     */
 1039         /* should not be executed; in readline 2.1+   */
 1040         /* it should return 2 in such a case          */
 1041         ret = -1;
 1042 #endif
 1043     }
 1044     el_free(*output);
 1045     *output = result;
 1046 
 1047     return ret;
 1048 }
 1049 
 1050 /*
 1051 * Return a string consisting of arguments of "str" from "start" to "end".
 1052 */
 1053 char *
 1054 history_arg_extract(int start, int end, const char *str)
 1055 {
 1056     size_t  i, len, max;
 1057     char    **arr, *result = NULL;
 1058 
 1059     arr = history_tokenize(str);
 1060     if (!arr)
 1061         return NULL;
 1062     if (arr && *arr == NULL)
 1063         goto out;
 1064 
 1065     for (max = 0; arr[max]; max++)
 1066         continue;
 1067     max--;
 1068 
 1069     if (start == '$')
 1070         start = (int)max;
 1071     if (end == '$')
 1072         end = (int)max;
 1073     if (end < 0)
 1074         end = (int)max + end + 1;
 1075     if (start < 0)
 1076         start = end;
 1077 
 1078     if (start < 0 || end < 0 || (size_t)start > max ||
 1079         (size_t)end > max || start > end)
 1080         goto out;
 1081 
 1082     for (i = (size_t)start, len = 0; i <= (size_t)end; i++)
 1083         len += strlen(arr[i]) + 1;
 1084     len++;
 1085     result = el_calloc(len, sizeof(*result));
 1086     if (result == NULL)
 1087         goto out;
 1088 
 1089     for (i = (size_t)start, len = 0; i <= (size_t)end; i++) {
 1090         (void)strcpy(result + len, arr[i]);
 1091         len += strlen(arr[i]);
 1092         if (i < (size_t)end)
 1093             result[len++] = ' ';
 1094     }
 1095     result[len] = '\0';
 1096 
 1097 out:
 1098     for (i = 0; arr[i]; i++)
 1099         el_free(arr[i]);
 1100     el_free(arr);
 1101 
 1102     return result;
 1103 }
 1104 
 1105 /*
 1106  * Parse the string into individual tokens,
 1107  * similar to how shell would do it.
 1108  */
 1109 char **
 1110 history_tokenize(const char *str)
 1111 {
 1112     int size = 1, idx = 0, i, start;
 1113     size_t len;
 1114     char **result = NULL, *temp, delim = '\0';
 1115 
 1116     for (i = 0; str[i];) {
 1117         while (isspace((unsigned char) str[i]))
 1118             i++;
 1119         start = i;
 1120         for (; str[i];) {
 1121             if (str[i] == '\\') {
 1122                 if (str[i+1] != '\0')
 1123                     i++;
 1124             } else if (str[i] == delim)
 1125                 delim = '\0';
 1126             else if (!delim &&
 1127                     (isspace((unsigned char) str[i]) ||
 1128                 strchr("()<>;&|$", str[i])))
 1129                 break;
 1130             else if (!delim && strchr("'`\"", str[i]))
 1131                 delim = str[i];
 1132             if (str[i])
 1133                 i++;
 1134         }
 1135 
 1136         if (idx + 2 >= size) {
 1137             char **nresult;
 1138             size <<= 1;
 1139             nresult = el_realloc(result, (size_t)size * sizeof(*nresult));
 1140             if (nresult == NULL) {
 1141                 el_free(result);
 1142                 return NULL;
 1143             }
 1144             result = nresult;
 1145         }
 1146         len = (size_t)i - (size_t)start;
 1147         temp = el_calloc(len + 1, sizeof(*temp));
 1148         if (temp == NULL) {
 1149             for (i = 0; i < idx; i++)
 1150                 el_free(result[i]);
 1151             el_free(result);
 1152             return NULL;
 1153         }
 1154         (void)strlcpy(temp, &str[start], len + 1);
 1155         result[idx++] = temp;
 1156         result[idx] = NULL;
 1157         if (str[i])
 1158             i++;
 1159     }
 1160     return result;
 1161 }
 1162 
 1163 
 1164 /*
 1165  * limit size of history record to ``max'' events
 1166  */
 1167 void
 1168 stifle_history(int max)
 1169 {
 1170     HistEvent ev;
 1171     HIST_ENTRY *he;
 1172 
 1173     if (h == NULL || e == NULL)
 1174         rl_initialize();
 1175 
 1176     if (history(h, &ev, H_SETSIZE, max) == 0) {
 1177         max_input_history = max;
 1178         if (history_length > max)
 1179             history_base = history_length - max;
 1180         while (history_length > max) {
 1181             he = remove_history(0);
 1182             el_free(he->data);
 1183             el_free((void *)(unsigned long)he->line);
 1184             el_free(he);
 1185         }
 1186     }
 1187 }
 1188 
 1189 
 1190 /*
 1191  * "unlimit" size of history - set the limit to maximum allowed int value
 1192  */
 1193 int
 1194 unstifle_history(void)
 1195 {
 1196     HistEvent ev;
 1197     int omax;
 1198 
 1199     history(h, &ev, H_SETSIZE, INT_MAX);
 1200     omax = max_input_history;
 1201     max_input_history = INT_MAX;
 1202     return omax;        /* some value _must_ be returned */
 1203 }
 1204 
 1205 
 1206 int
 1207 history_is_stifled(void)
 1208 {
 1209 
 1210     /* cannot return true answer */
 1211     return max_input_history != INT_MAX;
 1212 }
 1213 
 1214 static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
 1215 
 1216 int
 1217 history_truncate_file (const char *filename, int nlines)
 1218 {
 1219     int ret = 0;
 1220     FILE *fp, *tp;
 1221     char template[sizeof(_history_tmp_template)];
 1222     char buf[4096];
 1223     int fd;
 1224     char *cp;
 1225     off_t off;
 1226     int count = 0;
 1227     ssize_t left = 0;
 1228 
 1229     if (filename == NULL && (filename = _default_history_file()) == NULL)
 1230         return errno;
 1231     if ((fp = fopen(filename, "r+")) == NULL)
 1232         return errno;
 1233     strcpy(template, _history_tmp_template);
 1234     if ((fd = mkstemp(template)) == -1) {
 1235         ret = errno;
 1236         goto out1;
 1237     }
 1238 
 1239     if ((tp = fdopen(fd, "r+")) == NULL) {
 1240         close(fd);
 1241         ret = errno;
 1242         goto out2;
 1243     }
 1244 
 1245     for(;;) {
 1246         if (fread(buf, sizeof(buf), (size_t)1, fp) != 1) {
 1247             if (ferror(fp)) {
 1248                 ret = errno;
 1249                 break;
 1250             }
 1251             if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) ==
 1252                 (off_t)-1) {
 1253                 ret = errno;
 1254                 break;
 1255             }
 1256             left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), fp);
 1257             if (ferror(fp)) {
 1258                 ret = errno;
 1259                 break;
 1260             }
 1261             if (left == 0) {
 1262                 count--;
 1263                 left = sizeof(buf);
 1264             } else if (fwrite(buf, (size_t)left, (size_t)1, tp)
 1265                 != 1) {
 1266                 ret = errno;
 1267                 break;
 1268             }
 1269             fflush(tp);
 1270             break;
 1271         }
 1272         if (fwrite(buf, sizeof(buf), (size_t)1, tp) != 1) {
 1273             ret = errno;
 1274             break;
 1275         }
 1276         count++;
 1277     }
 1278     if (ret)
 1279         goto out3;
 1280     cp = buf + left - 1;
 1281     if(*cp != '\n')
 1282         cp++;
 1283     for(;;) {
 1284         while (--cp >= buf) {
 1285             if (*cp == '\n') {
 1286                 if (--nlines == 0) {
 1287                     if (++cp >= buf + sizeof(buf)) {
 1288                         count++;
 1289                         cp = buf;
 1290                     }
 1291                     break;
 1292                 }
 1293             }
 1294         }
 1295         if (nlines <= 0 || count == 0)
 1296             break;
 1297         count--;
 1298         if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
 1299             ret = errno;
 1300             break;
 1301         }
 1302         if (fread(buf, sizeof(buf), (size_t)1, tp) != 1) {
 1303             if (ferror(tp)) {
 1304                 ret = errno;
 1305                 break;
 1306             }
 1307             ret = EAGAIN;
 1308             break;
 1309         }
 1310         cp = buf + sizeof(buf);
 1311     }
 1312 
 1313     if (ret || nlines > 0)
 1314         goto out3;
 1315 
 1316     if (fseeko(fp, (off_t)0, SEEK_SET) == (off_t)-1) {
 1317         ret = errno;
 1318         goto out3;
 1319     }
 1320 
 1321     if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) ==
 1322         (off_t)-1) {
 1323         ret = errno;
 1324         goto out3;
 1325     }
 1326 
 1327     for(;;) {
 1328         if ((left = (ssize_t)fread(buf, (size_t)1, sizeof(buf), tp)) == 0) {
 1329             if (ferror(fp))
 1330                 ret = errno;
 1331             break;
 1332         }
 1333         if (fwrite(buf, (size_t)left, (size_t)1, fp) != 1) {
 1334             ret = errno;
 1335             break;
 1336         }
 1337     }
 1338     fflush(fp);
 1339     if((off = ftello(fp)) > 0)
 1340         (void)ftruncate(fileno(fp), off);
 1341 out3:
 1342     fclose(tp);
 1343 out2:
 1344     unlink(template);
 1345 out1:
 1346     fclose(fp);
 1347 
 1348     return ret;
 1349 }
 1350 
 1351 
 1352 /*
 1353  * read history from a file given
 1354  */
 1355 int
 1356 read_history(const char *filename)
 1357 {
 1358     HistEvent ev;
 1359 
 1360     if (h == NULL || e == NULL)
 1361         rl_initialize();
 1362     if (filename == NULL && (filename = _default_history_file()) == NULL)
 1363         return errno;
 1364     errno = 0;
 1365     if (history(h, &ev, H_LOAD, filename) == -1)
 1366         return errno ? errno : EINVAL;
 1367     if (history(h, &ev, H_GETSIZE) == 0)
 1368         history_length = ev.num;
 1369     if (history_length < 0)
 1370         return EINVAL;
 1371     return 0;
 1372 }
 1373 
 1374 
 1375 /*
 1376  * write history to a file given
 1377  */
 1378 int
 1379 write_history(const char *filename)
 1380 {
 1381     HistEvent ev;
 1382 
 1383     if (h == NULL || e == NULL)
 1384         rl_initialize();
 1385     if (filename == NULL && (filename = _default_history_file()) == NULL)
 1386         return errno;
 1387     return history(h, &ev, H_SAVE, filename) == -1 ?
 1388         (errno ? errno : EINVAL) : 0;
 1389 }
 1390 
 1391 int
 1392 append_history(int n, const char *filename)
 1393 {
 1394     HistEvent ev;
 1395     FILE *fp;
 1396 
 1397     if (h == NULL || e == NULL)
 1398         rl_initialize();
 1399     if (filename == NULL && (filename = _default_history_file()) == NULL)
 1400         return errno;
 1401 
 1402     if ((fp = fopen(filename, "a")) == NULL)
 1403         return errno;
 1404 
 1405     if (history(h, &ev, H_NSAVE_FP, (size_t)n,  fp) == -1) {
 1406         int serrno = errno ? errno : EINVAL;
 1407         fclose(fp);
 1408         return serrno;
 1409     }
 1410     fclose(fp);
 1411     return 0;
 1412 }
 1413 
 1414 /*
 1415  * returns history ``num''th event
 1416  *
 1417  * returned pointer points to static variable
 1418  */
 1419 HIST_ENTRY *
 1420 history_get(int num)
 1421 {
 1422     static HIST_ENTRY she;
 1423     HistEvent ev;
 1424     int curr_num;
 1425 
 1426     if (h == NULL || e == NULL)
 1427         rl_initialize();
 1428 
 1429     if (num < history_base)
 1430         return NULL;
 1431 
 1432     /* save current position */
 1433     if (history(h, &ev, H_CURR) != 0)
 1434         return NULL;
 1435     curr_num = ev.num;
 1436 
 1437     /*
 1438      * use H_DELDATA to set to nth history (without delete) by passing
 1439      * (void **)-1  -- as in history_set_pos
 1440      */
 1441     if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0)
 1442         goto out;
 1443 
 1444     /* get current entry */
 1445     if (history(h, &ev, H_CURR) != 0)
 1446         goto out;
 1447     if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0)
 1448         goto out;
 1449     she.line = ev.str;
 1450 
 1451     /* restore pointer to where it was */
 1452     (void)history(h, &ev, H_SET, curr_num);
 1453 
 1454     return &she;
 1455 
 1456 out:
 1457     /* restore pointer to where it was */
 1458     (void)history(h, &ev, H_SET, curr_num);
 1459     return NULL;
 1460 }
 1461 
 1462 
 1463 /*
 1464  * add the line to history table
 1465  */
 1466 int
 1467 add_history(const char *line)
 1468 {
 1469     HistEvent ev;
 1470 
 1471     if (h == NULL || e == NULL)
 1472         rl_initialize();
 1473 
 1474     if (history(h, &ev, H_ENTER, line) == -1)
 1475         return 0;
 1476 
 1477     (void)history(h, &ev, H_GETSIZE);
 1478     if (ev.num == history_length)
 1479         history_base++;
 1480     else {
 1481         history_offset++;
 1482         history_length = ev.num;
 1483     }
 1484     return 0;
 1485 }
 1486 
 1487 
 1488 /*
 1489  * remove the specified entry from the history list and return it.
 1490  */
 1491 HIST_ENTRY *
 1492 remove_history(int num)
 1493 {
 1494     HIST_ENTRY *he;
 1495     HistEvent ev;
 1496 
 1497     if (h == NULL || e == NULL)
 1498         rl_initialize();
 1499 
 1500     if ((he = el_malloc(sizeof(*he))) == NULL)
 1501         return NULL;
 1502 
 1503     if (history(h, &ev, H_DELDATA, num, &he->data) != 0) {
 1504         el_free(he);
 1505         return NULL;
 1506     }
 1507 
 1508     he->line = ev.str;
 1509     if (history(h, &ev, H_GETSIZE) == 0)
 1510         history_length = ev.num;
 1511 
 1512     return he;
 1513 }
 1514 
 1515 
 1516 /*
 1517  * replace the line and data of the num-th entry
 1518  */
 1519 HIST_ENTRY *
 1520 replace_history_entry(int num, const char *line, histdata_t data)
 1521 {
 1522     HIST_ENTRY *he;
 1523     HistEvent ev;
 1524     int curr_num;
 1525 
 1526     if (h == NULL || e == NULL)
 1527         rl_initialize();
 1528 
 1529     /* save current position */
 1530     if (history(h, &ev, H_CURR) != 0)
 1531         return NULL;
 1532     curr_num = ev.num;
 1533 
 1534     /* start from the oldest */
 1535     if (history(h, &ev, H_LAST) != 0)
 1536         return NULL;    /* error */
 1537 
 1538     if ((he = el_malloc(sizeof(*he))) == NULL)
 1539         return NULL;
 1540 
 1541     /* look forwards for event matching specified offset */
 1542     if (history(h, &ev, H_NEXT_EVDATA, num, &he->data))
 1543         goto out;
 1544 
 1545     he->line = strdup(ev.str);
 1546     if (he->line == NULL)
 1547         goto out;
 1548 
 1549     if (history(h, &ev, H_REPLACE, line, data))
 1550         goto out;
 1551 
 1552     /* restore pointer to where it was */
 1553     if (history(h, &ev, H_SET, curr_num))
 1554         goto out;
 1555 
 1556     return he;
 1557 out:
 1558     el_free(he);
 1559     return NULL;
 1560 }
 1561 
 1562 /*
 1563  * clear the history list - delete all entries
 1564  */
 1565 void
 1566 clear_history(void)
 1567 {
 1568     HistEvent ev;
 1569 
 1570     if (h == NULL || e == NULL)
 1571         rl_initialize();
 1572 
 1573     (void)history(h, &ev, H_CLEAR);
 1574     history_offset = history_length = 0;
 1575 }
 1576 
 1577 
 1578 /*
 1579  * returns offset of the current history event
 1580  */
 1581 int
 1582 where_history(void)
 1583 {
 1584     return history_offset;
 1585 }
 1586 
 1587 static HIST_ENTRY **_history_listp;
 1588 static HIST_ENTRY *_history_list;
 1589 
 1590 HIST_ENTRY **
 1591 history_list(void)
 1592 {
 1593     HistEvent ev;
 1594     HIST_ENTRY **nlp, *nl;
 1595     int i;
 1596 
 1597     if (history(h, &ev, H_LAST) != 0)
 1598         return NULL;
 1599 
 1600     if ((nlp = el_realloc(_history_listp,
 1601         ((size_t)history_length + 1) * sizeof(*nlp))) == NULL)
 1602         return NULL;
 1603     _history_listp = nlp;
 1604 
 1605     if ((nl = el_realloc(_history_list,
 1606         (size_t)history_length * sizeof(*nl))) == NULL)
 1607         return NULL;
 1608     _history_list = nl;
 1609 
 1610     i = 0;
 1611     do {
 1612         _history_listp[i] = &_history_list[i];
 1613         _history_list[i].line = ev.str;
 1614         _history_list[i].data = NULL;
 1615         if (i++ == history_length)
 1616             abort();
 1617     } while (history(h, &ev, H_PREV) == 0);
 1618     _history_listp[i] = NULL;
 1619     return _history_listp;
 1620 }
 1621 
 1622 /*
 1623  * returns current history event or NULL if there is no such event
 1624  */
 1625 HIST_ENTRY *
 1626 current_history(void)
 1627 {
 1628     HistEvent ev;
 1629 
 1630     if (history(h, &ev, H_PREV_EVENT, history_offset + 1) != 0)
 1631         return NULL;
 1632 
 1633     rl_he.line = ev.str;
 1634     rl_he.data = NULL;
 1635     return &rl_he;
 1636 }
 1637 
 1638 
 1639 /*
 1640  * returns total number of bytes history events' data are using
 1641  */
 1642 int
 1643 history_total_bytes(void)
 1644 {
 1645     HistEvent ev;
 1646     int curr_num;
 1647     size_t size;
 1648 
 1649     if (history(h, &ev, H_CURR) != 0)
 1650         return -1;
 1651     curr_num = ev.num;
 1652 
 1653     (void)history(h, &ev, H_FIRST);
 1654     size = 0;
 1655     do
 1656         size += strlen(ev.str) * sizeof(*ev.str);
 1657     while (history(h, &ev, H_NEXT) == 0);
 1658 
 1659     /* get to the same position as before */
 1660     history(h, &ev, H_PREV_EVENT, curr_num);
 1661 
 1662     return (int)size;
 1663 }
 1664 
 1665 
 1666 /*
 1667  * sets the position in the history list to ``pos''
 1668  */
 1669 int
 1670 history_set_pos(int pos)
 1671 {
 1672     if (pos >= history_length || pos < 0)
 1673         return 0;
 1674 
 1675     history_offset = pos;
 1676     return 1;
 1677 }
 1678 
 1679 
 1680 /*
 1681  * returns previous event in history and shifts pointer accordingly
 1682  * Note that readline and editline define directions in opposite ways.
 1683  */
 1684 HIST_ENTRY *
 1685 previous_history(void)
 1686 {
 1687     HistEvent ev;
 1688 
 1689     if (history_offset == 0)
 1690         return NULL;
 1691 
 1692     if (history(h, &ev, H_LAST) != 0)
 1693         return NULL;
 1694 
 1695     history_offset--;
 1696     return current_history();
 1697 }
 1698 
 1699 
 1700 /*
 1701  * returns next event in history and shifts pointer accordingly
 1702  */
 1703 HIST_ENTRY *
 1704 next_history(void)
 1705 {
 1706     HistEvent ev;
 1707 
 1708     if (history_offset >= history_length)
 1709         return NULL;
 1710 
 1711     if (history(h, &ev, H_LAST) != 0)
 1712         return NULL;
 1713 
 1714     history_offset++;
 1715     return current_history();
 1716 }
 1717 
 1718 
 1719 /*
 1720  * searches for first history event containing the str
 1721  */
 1722 int
 1723 history_search(const char *str, int direction)
 1724 {
 1725     HistEvent ev;
 1726     const char *strp;
 1727     int curr_num;
 1728 
 1729     if (history(h, &ev, H_CURR) != 0)
 1730         return -1;
 1731     curr_num = ev.num;
 1732 
 1733     for (;;) {
 1734         if ((strp = strstr(ev.str, str)) != NULL)
 1735             return (int)(strp - ev.str);
 1736         if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
 1737             break;
 1738     }
 1739     (void)history(h, &ev, H_SET, curr_num);
 1740     return -1;
 1741 }
 1742 
 1743 
 1744 /*
 1745  * searches for first history event beginning with str
 1746  */
 1747 int
 1748 history_search_prefix(const char *str, int direction)
 1749 {
 1750     HistEvent ev;
 1751 
 1752     return (history(h, &ev, direction < 0 ?
 1753         H_PREV_STR : H_NEXT_STR, str));
 1754 }
 1755 
 1756 
 1757 /*
 1758  * search for event in history containing str, starting at offset
 1759  * abs(pos); continue backward, if pos<0, forward otherwise
 1760  */
 1761 /* ARGSUSED */
 1762 int
 1763 history_search_pos(const char *str,
 1764            int direction __attribute__((__unused__)), int pos)
 1765 {
 1766     HistEvent ev;
 1767     int curr_num, off;
 1768 
 1769     off = (pos > 0) ? pos : -pos;
 1770     pos = (pos > 0) ? 1 : -1;
 1771 
 1772     if (history(h, &ev, H_CURR) != 0)
 1773         return -1;
 1774     curr_num = ev.num;
 1775 
 1776     if (!history_set_pos(off) || history(h, &ev, H_CURR) != 0)
 1777         return -1;
 1778 
 1779     for (;;) {
 1780         if (strstr(ev.str, str))
 1781             return off;
 1782         if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
 1783             break;
 1784     }
 1785 
 1786     /* set "current" pointer back to previous state */
 1787     (void)history(h, &ev,
 1788         pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
 1789 
 1790     return -1;
 1791 }
 1792 
 1793 
 1794 /********************************/
 1795 /* completion functions */
 1796 
 1797 char *
 1798 tilde_expand(char *name)
 1799 {
 1800     return fn_tilde_expand(name);
 1801 }
 1802 
 1803 char *
 1804 filename_completion_function(const char *name, int state)
 1805 {
 1806     return fn_filename_completion_function(name, state);
 1807 }
 1808 
 1809 /*
 1810  * a completion generator for usernames; returns _first_ username
 1811  * which starts with supplied text
 1812  * text contains a partial username preceded by random character
 1813  * (usually '~'); state resets search from start (??? should we do that anyway)
 1814  * it's the caller's responsibility to free the returned value
 1815  */
 1816 char *
 1817 username_completion_function(const char *text, int state)
 1818 {
 1819 #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
 1820     struct passwd pwres;
 1821     char pwbuf[1024];
 1822 #endif
 1823     struct passwd *pass = NULL;
 1824 
 1825     if (text[0] == '\0')
 1826         return NULL;
 1827 
 1828     if (*text == '~')
 1829         text++;
 1830 
 1831     if (state == 0)
 1832         setpwent();
 1833 
 1834     while (
 1835 #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT)
 1836         getpwent_r(&pwres, pwbuf, sizeof(pwbuf), &pass) == 0 && pass != NULL
 1837 #else
 1838         (pass = getpwent()) != NULL
 1839 #endif
 1840         && text[0] == pass->pw_name[0]
 1841         && strcmp(text, pass->pw_name) == 0)
 1842         continue;
 1843 
 1844     if (pass == NULL) {
 1845         endpwent();
 1846         return NULL;
 1847     }
 1848     return strdup(pass->pw_name);
 1849 }
 1850 
 1851 
 1852 /*
 1853  * el-compatible wrapper to send TSTP on ^Z
 1854  */
 1855 /* ARGSUSED */
 1856 static unsigned char
 1857 _el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__)))
 1858 {
 1859     (void)kill(0, SIGTSTP);
 1860     return CC_NORM;
 1861 }
 1862 
 1863 static const char *
 1864 /*ARGSUSED*/
 1865 _rl_completion_append_character_function(const char *dummy
 1866     __attribute__((__unused__)))
 1867 {
 1868     static char buf[2];
 1869     buf[0] = (char)rl_completion_append_character;
 1870     buf[1] = '\0';
 1871     return buf;
 1872 }
 1873 
 1874 
 1875 /*
 1876  * Display list of strings in columnar format on readline's output stream.
 1877  * 'matches' is list of strings, 'len' is number of strings in 'matches',
 1878  * 'max' is maximum length of string in 'matches'.
 1879  */
 1880 void
 1881 rl_display_match_list(char **matches, int len, int max)
 1882 {
 1883 
 1884     fn_display_match_list(e, matches, (size_t)len, (size_t)max,
 1885         _rl_completion_append_character_function);
 1886 }
 1887 
 1888 /*
 1889  * complete word at current point
 1890  */
 1891 /* ARGSUSED */
 1892 int
 1893 rl_complete(int ignore __attribute__((__unused__)), int invoking_key)
 1894 {
 1895     static ct_buffer_t wbreak_conv, sprefix_conv;
 1896     const char *breakchars;
 1897 
 1898     if (h == NULL || e == NULL)
 1899         rl_initialize();
 1900 
 1901     if (rl_inhibit_completion) {
 1902         char arr[2];
 1903         arr[0] = (char)invoking_key;
 1904         arr[1] = '\0';
 1905         el_insertstr(e, arr);
 1906         return CC_REFRESH;
 1907     }
 1908 
 1909     if (rl_completion_word_break_hook != NULL)
 1910         breakchars = (*rl_completion_word_break_hook)();
 1911     else
 1912         breakchars = rl_basic_word_break_characters;
 1913 
 1914     _rl_update_pos();
 1915 
 1916     /* Just look at how many global variables modify this operation! */
 1917     return fn_complete(e,
 1918         (rl_compentry_func_t *)rl_completion_entry_function,
 1919         rl_attempted_completion_function,
 1920         ct_decode_string(rl_basic_word_break_characters, &wbreak_conv),
 1921         ct_decode_string(breakchars, &sprefix_conv),
 1922         _rl_completion_append_character_function,
 1923         (size_t)rl_completion_query_items,
 1924         &rl_completion_type, &rl_attempted_completion_over,
 1925         &rl_point, &rl_end);
 1926 
 1927 
 1928 }
 1929 
 1930 
 1931 /* ARGSUSED */
 1932 static unsigned char
 1933 _el_rl_complete(EditLine *el __attribute__((__unused__)), int ch)
 1934 {
 1935     return (unsigned char)rl_complete(0, ch);
 1936 }
 1937 
 1938 /*
 1939  * misc other functions
 1940  */
 1941 
 1942 /*
 1943  * bind key c to readline-type function func
 1944  */
 1945 int
 1946 rl_bind_key(int c, rl_command_func_t *func)
 1947 {
 1948     int retval = -1;
 1949 
 1950     if (h == NULL || e == NULL)
 1951         rl_initialize();
 1952 
 1953     if (func == rl_insert) {
 1954         /* XXX notice there is no range checking of ``c'' */
 1955         e->el_map.key[c] = ED_INSERT;
 1956         retval = 0;
 1957     }
 1958     return retval;
 1959 }
 1960 
 1961 
 1962 /*
 1963  * read one key from input - handles chars pushed back
 1964  * to input stream also
 1965  */
 1966 int
 1967 rl_read_key(void)
 1968 {
 1969     char fooarr[2 * sizeof(int)];
 1970 
 1971     if (e == NULL || h == NULL)
 1972         rl_initialize();
 1973 
 1974     return el_getc(e, fooarr);
 1975 }
 1976 
 1977 
 1978 /*
 1979  * reset the terminal
 1980  */
 1981 /* ARGSUSED */
 1982 int
 1983 rl_reset_terminal(const char *p __attribute__((__unused__)))
 1984 {
 1985 
 1986     if (h == NULL || e == NULL)
 1987         rl_initialize();
 1988     el_reset(e);
 1989     return 0;
 1990 }
 1991 
 1992 
 1993 /*
 1994  * insert character ``c'' back into input stream, ``count'' times
 1995  */
 1996 int
 1997 rl_insert(int count, int c)
 1998 {
 1999     char arr[2];
 2000 
 2001     if (h == NULL || e == NULL)
 2002         rl_initialize();
 2003 
 2004     /* XXX - int -> char conversion can lose on multichars */
 2005     arr[0] = (char)c;
 2006     arr[1] = '\0';
 2007 
 2008     for (; count > 0; count--)
 2009         el_push(e, arr);
 2010 
 2011     return 0;
 2012 }
 2013 
 2014 int
 2015 rl_insert_text(const char *text)
 2016 {
 2017     if (!text || *text == 0)
 2018         return 0;
 2019 
 2020     if (h == NULL || e == NULL)
 2021         rl_initialize();
 2022 
 2023     if (el_insertstr(e, text) < 0)
 2024         return 0;
 2025     return (int)strlen(text);
 2026 }
 2027 
 2028 /*ARGSUSED*/
 2029 int
 2030 rl_newline(int count __attribute__((__unused__)),
 2031     int c __attribute__((__unused__)))
 2032 {
 2033     /*
 2034      * Readline-4.0 appears to ignore the args.
 2035      */
 2036     return rl_insert(1, '\n');
 2037 }
 2038 
 2039 /*ARGSUSED*/
 2040 static unsigned char
 2041 rl_bind_wrapper(EditLine *el __attribute__((__unused__)), unsigned char c)
 2042 {
 2043     if (map[c] == NULL)
 2044         return CC_ERROR;
 2045 
 2046     _rl_update_pos();
 2047 
 2048     (*map[c])(1, c);
 2049 
 2050     /* If rl_done was set by the above call, deal with it here */
 2051     if (rl_done)
 2052         return CC_EOF;
 2053 
 2054     return CC_NORM;
 2055 }
 2056 
 2057 int
 2058 rl_add_defun(const char *name, rl_command_func_t *fun, int c)
 2059 {
 2060     char dest[8];
 2061     if ((size_t)c >= sizeof(map) / sizeof(map[0]) || c < 0)
 2062         return -1;
 2063     map[(unsigned char)c] = fun;
 2064     el_set(e, EL_ADDFN, name, name, rl_bind_wrapper);
 2065     vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0);
 2066     el_set(e, EL_BIND, dest, name, NULL);
 2067     return 0;
 2068 }
 2069 
 2070 void
 2071 rl_callback_read_char(void)
 2072 {
 2073     int count = 0, done = 0;
 2074     const char *buf = el_gets(e, &count);
 2075     char *wbuf;
 2076 
 2077     if (buf == NULL || count-- <= 0)
 2078         return;
 2079     if (count == 0 && buf[0] == e->el_tty.t_c[TS_IO][C_EOF])
 2080         done = 1;
 2081     if (buf[count] == '\n' || buf[count] == '\r')
 2082         done = 2;
 2083 
 2084     if (done && rl_linefunc != NULL) {
 2085         el_set(e, EL_UNBUFFERED, 0);
 2086         if (done == 2) {
 2087             if ((wbuf = strdup(buf)) != NULL)
 2088                 wbuf[count] = '\0';
 2089         } else
 2090             wbuf = NULL;
 2091         (*(void (*)(const char *))rl_linefunc)(wbuf);
 2092         el_set(e, EL_UNBUFFERED, 1);
 2093     }
 2094 }
 2095 
 2096 void
 2097 rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *linefunc)
 2098 {
 2099     if (e == NULL) {
 2100         rl_initialize();
 2101     }
 2102     (void)rl_set_prompt(prompt);
 2103     rl_linefunc = linefunc;
 2104     el_set(e, EL_UNBUFFERED, 1);
 2105 }
 2106 
 2107 void
 2108 rl_callback_handler_remove(void)
 2109 {
 2110     rl_linefunc = NULL;
 2111     el_end(e);
 2112     e = NULL;
 2113 }
 2114 
 2115 void
 2116 rl_redisplay(void)
 2117 {
 2118     char a[2];
 2119     a[0] = (char)e->el_tty.t_c[TS_IO][C_REPRINT];
 2120     a[1] = '\0';
 2121     el_push(e, a);
 2122 }
 2123 
 2124 int
 2125 rl_get_previous_history(int count, int key)
 2126 {
 2127     char a[2];
 2128     a[0] = (char)key;
 2129     a[1] = '\0';
 2130     while (count--)
 2131         el_push(e, a);
 2132     return 0;
 2133 }
 2134 
 2135 void
 2136 /*ARGSUSED*/
 2137 rl_prep_terminal(int meta_flag __attribute__((__unused__)))
 2138 {
 2139     el_set(e, EL_PREP_TERM, 1);
 2140 }
 2141 
 2142 void
 2143 rl_deprep_terminal(void)
 2144 {
 2145     el_set(e, EL_PREP_TERM, 0);
 2146 }
 2147 
 2148 int
 2149 rl_read_init_file(const char *s)
 2150 {
 2151     return el_source(e, s);
 2152 }
 2153 
 2154 int
 2155 rl_parse_and_bind(const char *line)
 2156 {
 2157     const char **argv;
 2158     int argc;
 2159     Tokenizer *tok;
 2160 
 2161     tok = tok_init(NULL);
 2162     tok_str(tok, line, &argc, &argv);
 2163     argc = el_parse(e, argc, argv);
 2164     tok_end(tok);
 2165     return argc ? 1 : 0;
 2166 }
 2167 
 2168 int
 2169 rl_variable_bind(const char *var, const char *value)
 2170 {
 2171     /*
 2172      * The proper return value is undocument, but this is what the
 2173      * readline source seems to do.
 2174      */
 2175     return el_set(e, EL_BIND, "", var, value, NULL) == -1 ? 1 : 0;
 2176 }
 2177 
 2178 int
 2179 rl_stuff_char(int c)
 2180 {
 2181     char buf[2];
 2182 
 2183     buf[0] = (char)c;
 2184     buf[1] = '\0';
 2185     el_insertstr(e, buf);
 2186     return 1;
 2187 }
 2188 
 2189 static int
 2190 _rl_event_read_char(EditLine *el, wchar_t *wc)
 2191 {
 2192     char    ch;
 2193     int n;
 2194     ssize_t num_read = 0;
 2195 
 2196     ch = '\0';
 2197     *wc = L'\0';
 2198     while (rl_event_hook) {
 2199 
 2200         (*rl_event_hook)();
 2201 
 2202 #if defined(FIONREAD)
 2203         if (ioctl(el->el_infd, FIONREAD, &n) < 0)
 2204             return -1;
 2205         if (n)
 2206             num_read = read(el->el_infd, &ch, (size_t)1);
 2207         else
 2208             num_read = 0;
 2209 #elif defined(F_SETFL) && defined(O_NDELAY)
 2210         if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0)
 2211             return -1;
 2212         if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0)
 2213             return -1;
 2214         num_read = read(el->el_infd, &ch, 1);
 2215         if (fcntl(el->el_infd, F_SETFL, n))
 2216             return -1;
 2217 #else
 2218         /* not non-blocking, but what you gonna do? */
 2219         num_read = read(el->el_infd, &ch, 1);
 2220         return -1;
 2221 #endif
 2222 
 2223         if (num_read < 0 && errno == EAGAIN)
 2224             continue;
 2225         if (num_read == 0)
 2226             continue;
 2227         break;
 2228     }
 2229     if (!rl_event_hook)
 2230         el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN);
 2231     *wc = (wchar_t)ch;
 2232     return (int)num_read;
 2233 }
 2234 
 2235 static void
 2236 _rl_update_pos(void)
 2237 {
 2238     const LineInfo *li = el_line(e);
 2239 
 2240     rl_point = (int)(li->cursor - li->buffer);
 2241     rl_end = (int)(li->lastchar - li->buffer);
 2242     rl_line_buffer[rl_end] = '\0';
 2243 }
 2244 
 2245 void
 2246 rl_get_screen_size(int *rows, int *cols)
 2247 {
 2248     if (rows)
 2249         el_get(e, EL_GETTC, "li", rows);
 2250     if (cols)
 2251         el_get(e, EL_GETTC, "co", cols);
 2252 }
 2253 
 2254 void
 2255 rl_set_screen_size(int rows, int cols)
 2256 {
 2257     char buf[64];
 2258     (void)snprintf(buf, sizeof(buf), "%d", rows);
 2259     el_set(e, EL_SETTC, "li", buf, NULL);
 2260     (void)snprintf(buf, sizeof(buf), "%d", cols);
 2261     el_set(e, EL_SETTC, "co", buf, NULL);
 2262 }
 2263 
 2264 char **
 2265 rl_completion_matches(const char *str, rl_compentry_func_t *fun)
 2266 {
 2267     size_t len, max, i, j, min;
 2268     char **list, *match, *a, *b;
 2269 
 2270     len = 1;
 2271     max = 10;
 2272     if ((list = el_calloc(max, sizeof(*list))) == NULL)
 2273         return NULL;
 2274 
 2275     while ((match = (*fun)(str, (int)(len - 1))) != NULL) {
 2276         list[len++] = match;
 2277         if (len == max) {
 2278             char **nl;
 2279             max += 10;
 2280             if ((nl = el_realloc(list, max * sizeof(*nl))) == NULL)
 2281                 goto out;
 2282             list = nl;
 2283         }
 2284     }
 2285     if (len == 1)
 2286         goto out;
 2287     list[len] = NULL;
 2288     if (len == 2) {
 2289         if ((list[0] = strdup(list[1])) == NULL)
 2290             goto out;
 2291         return list;
 2292     }
 2293     qsort(&list[1], len - 1, sizeof(*list),
 2294         (int (*)(const void *, const void *)) strcmp);
 2295     min = SIZE_MAX;
 2296     for (i = 1, a = list[i]; i < len - 1; i++, a = b) {
 2297         b = list[i + 1];
 2298         for (j = 0; a[j] && a[j] == b[j]; j++)
 2299             continue;
 2300         if (min > j)
 2301             min = j;
 2302     }
 2303     if (min == 0 && *str) {
 2304         if ((list[0] = strdup(str)) == NULL)
 2305             goto out;
 2306     } else {
 2307         if ((list[0] = el_calloc(min + 1, sizeof(*list[0]))) == NULL)
 2308             goto out;
 2309         (void)memcpy(list[0], list[1], min);
 2310         list[0][min] = '\0';
 2311     }
 2312     return list;
 2313 
 2314 out:
 2315     el_free(list);
 2316     return NULL;
 2317 }
 2318 
 2319 char *
 2320 rl_filename_completion_function (const char *text, int state)
 2321 {
 2322     return fn_filename_completion_function(text, state);
 2323 }
 2324 
 2325 void
 2326 rl_forced_update_display(void)
 2327 {
 2328     el_set(e, EL_REFRESH);
 2329 }
 2330 
 2331 int
 2332 _rl_abort_internal(void)
 2333 {
 2334     el_beep(e);
 2335     longjmp(topbuf, 1);
 2336     /*NOTREACHED*/
 2337 }
 2338 
 2339 int
 2340 _rl_qsort_string_compare(char **s1, char **s2)
 2341 {
 2342     return strcoll(*s1, *s2);
 2343 }
 2344 
 2345 HISTORY_STATE *
 2346 history_get_history_state(void)
 2347 {
 2348     HISTORY_STATE *hs;
 2349 
 2350     if ((hs = el_malloc(sizeof(*hs))) == NULL)
 2351         return NULL;
 2352     hs->length = history_length;
 2353     return hs;
 2354 }
 2355 
 2356 int
 2357 /*ARGSUSED*/
 2358 rl_kill_text(int from __attribute__((__unused__)),
 2359     int to __attribute__((__unused__)))
 2360 {
 2361     return 0;
 2362 }
 2363 
 2364 Keymap
 2365 rl_make_bare_keymap(void)
 2366 {
 2367     return NULL;
 2368 }
 2369 
 2370 Keymap
 2371 rl_get_keymap(void)
 2372 {
 2373     return NULL;
 2374 }
 2375 
 2376 void
 2377 /*ARGSUSED*/
 2378 rl_set_keymap(Keymap k __attribute__((__unused__)))
 2379 {
 2380 }
 2381 
 2382 int
 2383 /*ARGSUSED*/
 2384 rl_generic_bind(int type __attribute__((__unused__)),
 2385     const char * keyseq __attribute__((__unused__)),
 2386     const char * data __attribute__((__unused__)),
 2387     Keymap k __attribute__((__unused__)))
 2388 {
 2389     return 0;
 2390 }
 2391 
 2392 int
 2393 /*ARGSUSED*/
 2394 rl_bind_key_in_map(int key __attribute__((__unused__)),
 2395     rl_command_func_t *fun __attribute__((__unused__)),
 2396     Keymap k __attribute__((__unused__)))
 2397 {
 2398     return 0;
 2399 }
 2400 
 2401 /* unsupported, but needed by python */
 2402 void
 2403 rl_cleanup_after_signal(void)
 2404 {
 2405 }
 2406 
 2407 int
 2408 rl_on_new_line(void)
 2409 {
 2410     return 0;
 2411 }
 2412 
 2413 void
 2414 rl_free_line_state(void)
 2415 {
 2416 }
 2417 
 2418 int
 2419 /*ARGSUSED*/
 2420 rl_set_keyboard_input_timeout(int u __attribute__((__unused__)))
 2421 {
 2422     return 0;
 2423 }
 2424 
 2425 void
 2426 rl_resize_terminal(void)
 2427 {
 2428     el_resize(e);
 2429 }
 2430 
 2431 void
 2432 rl_reset_after_signal(void)
 2433 {
 2434     if (rl_prep_term_function)
 2435         (*rl_prep_term_function)();
 2436 }
 2437 
 2438 void
 2439 rl_echo_signal_char(int sig)
 2440 {
 2441     int c = tty_get_signal_character(e, sig);
 2442     if (c == -1)
 2443         return;
 2444     re_putc(e, c, 0);
 2445 }