readline.cxx

Go to the documentation of this file.
00001 // @(#)root/editline:$Id: readline.cxx 37430 2010-12-09 10:09:52Z axel $
00002 // Author: Mary-Louise Gill, 2009
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /*      $NetBSD: readline.c,v 1.19 2001/01/10 08:10:45 jdolecek Exp $   */
00013 
00014 /*-
00015  * Copyright (c) 1992, 1993
00016  *      The Regents of the University of California.  All rights reserved.
00017  *
00018  * This code is derived from software contributed to Berkeley by
00019  * Christos Zoulas of Cornell University.
00020  *
00021  * Redistribution and use in source and binary forms, with or without
00022  * modification, are permitted provided that the following conditions
00023  * are met:
00024  * 1. Redistributions of source code must retain the above copyright
00025  *    notice, this list of conditions and the following disclaimer.
00026  * 2. Redistributions in binary form must reproduce the above copyright
00027  *    notice, this list of conditions and the following disclaimer in the
00028  *    documentation and/or other materials provided with the distribution.
00029  * 3. Neither the name of the University nor the names of its contributors
00030  *    may be used to endorse or promote products derived from this software
00031  *    without specific prior written permission.
00032  *
00033  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00034  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00035  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00036  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00037  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00038  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00039  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00040  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00041  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00042  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00043  * SUCH DAMAGE.
00044  */
00045 
00046 
00047 #include <sys/types.h>
00048 #include <sys/stat.h>
00049 #include <stdio.h>
00050 #include <dirent.h>
00051 #include <string.h>
00052 #include <pwd.h>
00053 #include <ctype.h>
00054 #include <stdlib.h>
00055 #include <unistd.h>
00056 #include <limits.h>
00057 #ifndef __FreeBSD__
00058 #include <alloca.h>
00059 #endif // __FreeBSD__
00060 #include "histedit.h"
00061 // #include "readline/readline.h"
00062 #include "editline.h"
00063 #include "el.h"
00064 #include "compat.h"
00065 #include "TTermManip.h"
00066 #include "enhance.h"
00067 
00068 /* for rl_complete() */
00069 #define TAB '\r'
00070 
00071 /* see comment at the #ifdef for sense of this */
00072 #define GDB_411_HACK
00073 
00074 /* readline compatibility stuff - look at readline sources/documentation */
00075 /* to see what these variables mean */
00076 const char* rl_library_version = "EditLine_t wrapper";
00077 const char* rl_readline_name = "";
00078 FILE* rl_instream = NULL;
00079 FILE* rl_outstream = NULL;
00080 int rl_point = 0;
00081 int rl_end = 0;
00082 char* rl_line_buffer = NULL;
00083 
00084 int history_base = 1;           /* probably never subject to change */
00085 int history_length = 0;
00086 int max_input_history = 0;
00087 char history_expansion_char = '!';
00088 char history_subst_char = '^';
00089 const char* history_no_expand_chars = " \t\n=(";
00090 Function* history_inhibit_expansion_function = NULL;
00091 
00092 int rl_inhibit_completion = 0;
00093 int rl_attempted_completion_over = 0;
00094 const char* rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
00095 char* rl_completer_word_break_characters = NULL;
00096 char* rl_completer_quote_characters = NULL;
00097 CPFunction* rl_completion_entry_function = NULL;
00098 CPPFunction* rl_attempted_completion_function = NULL;
00099 int tab_color = 5;
00100 El_tab_hook_t rl_tab_hook = NULL;
00101 El_in_key_hook_t rl_in_key_hook = NULL;
00102 
00103 /*
00104  * This is set to character indicating type of completion being done by
00105  * rl_complete_internal(); this is available for application completion
00106  * functions.
00107  */
00108 int rl_completion_type = 0;
00109 
00110 /*
00111  * If more than this number of items results from query for possible
00112  * completions, we ask user if they are sure to really display the list.
00113  */
00114 int rl_completion_query_items = 100;
00115 
00116 /*
00117  * List of characters which are word break characters, but should be left
00118  * in the parsed text when it is passed to the completion function.
00119  * Shell uses this to help determine what kind of completing to do.
00120  */
00121 char* rl_special_prefixes = (char*) NULL;
00122 
00123 /*
00124  * This is the character appended to the completed words if at the end of
00125  * the line. Default is ' ' (a space).
00126  */
00127 int rl_completion_append_character = ' ';
00128 
00129 /* stuff below is used internally by libedit for readline emulation */
00130 
00131 /* if not zero, non-unique completions always show list of possible matches */
00132 static int grl_complete_show_all = 0;
00133 
00134 static HistoryFcns_t* gHistory = NULL;
00135 static EditLine_t* gEditLine = NULL;
00136 static int gel_rl_complete_cmdnum = 0;
00137 
00138 /* internal functions */
00139 static unsigned char _el_rl_complete(EditLine_t*, int);
00140 static char* _get_prompt(EditLine_t*);
00141 static HIST_ENTRY* _move_history(int);
00142 static int _history_search_gen(const char*, int, int);
00143 #ifdef EL_HISTORY_EXPAND
00144 static int _history_expand_command(const char*, size_t, char**);
00145 static char* _rl_compat_sub(const char*, const char*,
00146                             const char*, int);
00147 #endif
00148 static int rl_complete_internal(int);
00149 static int _rl_qsort_string_compare(const void*, const void*);
00150 
00151 /*
00152  * needed for prompt switching in readline()
00153  */
00154 static char* gel_rl_prompt = NULL;
00155 
00156 /* ARGSUSED */
00157 static char*
00158 _get_prompt(EditLine_t* /*el*/) {
00159    return gel_rl_prompt;
00160 }
00161 
00162 
00163 /*
00164  * generic function for moving around history
00165  */
00166 static HIST_ENTRY*
00167 _move_history(int op) {
00168    HistEvent_t ev;
00169    static HIST_ENTRY rl_he;
00170 
00171    if (history(gHistory, &ev, op) != 0) {
00172       return (HIST_ENTRY*) NULL;
00173    }
00174 
00175    rl_he.line = ev.fStr;
00176    rl_he.data = "";
00177 
00178    return &rl_he;
00179 }
00180 
00181 
00182 bool
00183 rl_isinitialized() {
00184    return gEditLine != NULL;
00185 }
00186 
00187 /*
00188  * READLINE compatibility stuff
00189  */
00190 
00191 /*
00192  * initialize rl compat stuff
00193  */
00194 int
00195 rl_initialize(void) {
00196    HistEvent_t ev;
00197    const LineInfo_t* li;
00198    int i;
00199    int editmode = 1;
00200    struct termios t;
00201 
00202    if (gEditLine != NULL) {
00203       el_end(gEditLine);
00204    }
00205 
00206    if (gHistory != NULL) {
00207       history_end(gHistory);
00208    }
00209 
00210    if (!rl_instream) {
00211       rl_instream = stdin;
00212    }
00213 
00214    if (!rl_outstream) {
00215       rl_outstream = stdout;
00216    }
00217 
00218    /*
00219     * See if we don't really want to run the editor
00220     */
00221    if (tcgetattr(fileno(rl_instream), &t) != -1 && (t.c_lflag & ECHO) == 0) {
00222       editmode = 0;
00223    }
00224 
00225    gEditLine = el_init(rl_readline_name, rl_instream, rl_outstream, stderr);
00226 
00227    if (!editmode) {
00228       el_set(gEditLine, EL_EDITMODE, 0);
00229    }
00230 
00231    gHistory = history_init();
00232 
00233    if (!gEditLine || !gHistory) {
00234       return -1;
00235    }
00236 
00237    history(gHistory, &ev, H_SETSIZE, INT_MAX);         /* unlimited */
00238    history_length = 0;
00239    max_input_history = INT_MAX;
00240    el_set(gEditLine, EL_HIST, history, gHistory);
00241 
00242    /* for proper prompt printing in readline() */
00243    gel_rl_prompt = strdup("");
00244    el_set(gEditLine, EL_PROMPT, _get_prompt);
00245    el_set(gEditLine, EL_SIGNAL, 1);
00246 
00247 
00248    /* set default mode to "emacs"-style and read setting afterwards */
00249    /* so this can be overriden */
00250    // NO vi at the ROOT prompt, please!
00251    char* editor = 0; // getenv("EDITOR");
00252    // coverity[dead_error_line] - yes, this is always "emacs".
00253    el_set(gEditLine, EL_EDITOR, editor ? editor : "emacs");
00254 
00255    /*
00256     * Word completition - this has to go AFTER rebinding keys
00257     * to emacs-style.
00258     */
00259    el_set(gEditLine, EL_ADDFN, "rl_complete",
00260           "ReadLine compatible completition function",
00261           _el_rl_complete);
00262    el_set(gEditLine, EL_BIND, "^I", "rl_complete", NULL);
00263 
00264    /** added by stephan: default emacs bindings... */
00265    el_set(gEditLine, EL_BIND, "^R", "em-inc-search-prev", NULL);
00266    el_set(gEditLine, EL_BIND, "^S", "em-inc-search-next", NULL);
00267    /** end stephan's personal preferences. */
00268 
00269    /*
00270     * Find out where the rl_complete function was added; this is
00271     * used later to detect that lastcmd was also rl_complete.
00272     */
00273    for (i = EL_NUM_FCNS; i < gEditLine->fMap.fNFunc; i++) {
00274       if (gEditLine->fMap.fFunc[i] == _el_rl_complete) {
00275          gel_rl_complete_cmdnum = i;
00276          break;
00277       }
00278    }
00279 
00280 
00281    /* read settings from configuration file */
00282    el_source(gEditLine, NULL);
00283 
00284    /*
00285     * Unfortunately, some applications really do use rl_point
00286     * and rl_line_buffer directly.
00287     */
00288    li = el_line(gEditLine);
00289    /* LINTED const cast */
00290    rl_line_buffer = (char*) li->fBuffer;
00291    rl_point = rl_end = 0;
00292 
00293    return 0;
00294 } // rl_initialize
00295 
00296 
00297 /*
00298  * Ends readline/editline mode. Intended to be called
00299  * from signal handlers.
00300  *
00301  * Submitted to editline by Alexey Zakhlestin, of Milk Farm Software.
00302  */
00303 void
00304 rl_cleanup_after_signal() {
00305    el_end(gEditLine);
00306    history_end(gHistory);
00307 }
00308 
00309 
00310 /*
00311  * read one line from input stream and return it, chomping
00312  * trailing newline (if there is any)
00313  *
00314  * Calls to libeditline builtin functions are consumed here, and those
00315  * lines are not passed back to the client (who doesn't need
00316  * them). They ARE added to add_history().
00317  */
00318 #include <iostream>
00319 char*
00320 readline(const char* prompt, bool newline) {
00321    HistEvent_t ev;
00322    int count;
00323    const char* ret;
00324 
00325    if (gEditLine == NULL || gHistory == NULL) {
00326       rl_initialize();
00327    }
00328 
00329    /* update prompt accordingly to what has been passed; */
00330    /* also disable prompt if nobody can type at it, or if nobody sees it */
00331    if (!prompt || !isatty(0) || !isatty(1)) {
00332       prompt = "";
00333    }
00334 
00335    if (strcmp(gel_rl_prompt, prompt) != 0) {
00336       free(gel_rl_prompt);
00337       gel_rl_prompt = strdup(prompt);
00338    }
00339 
00340    /* get one line from input stream */
00341    if (newline) {
00342       tty_rawmode(gEditLine);
00343       ret = el_gets_newline(gEditLine, &count);
00344    } else {
00345       ret = el_gets(gEditLine, &count);
00346 
00347       if (rl_in_key_hook && count > 0 && gEditLine->fLine.fLastChar > gEditLine->fLine.fBuffer) {
00348          char* key = gEditLine->fLine.fLastChar;
00349 
00350          if (*key == '\a') {
00351             --key;
00352          }
00353          (*rl_in_key_hook)(*key);
00354       }
00355    }
00356 
00357    // std::cerr <<  "readline(): el_gets(gEditLine,"<<count<<") got ["<<(ret?ret:"NULL")<<"]\n";
00358    //if( 0 == ret ) return NULL;
00359 
00360    // reminder: gEditLine owns the string, actually,
00361    // which is why we duplicate it here:
00362    if (ret) {
00363       if (count <= 0) {
00364          ret = NULL;
00365       }
00366    }
00367 
00368    history(gHistory, &ev, H_GETSIZE);
00369    history_length = ev.fNum;
00370 
00371    if (ret && !strchr(ret, '\a') && ret[strlen(ret) - 1] == '\n') {
00372       tty_cookedmode(gEditLine);
00373    }
00374    /* LINTED const cast */
00375    return (char*) ret;
00376 } // readline
00377 
00378 
00379 void
00380 setColors(const char* colorTab, const char* colorTabComp, const char* colorBracket,
00381           const char* colorBadBracket, const char* colorPrompt) {
00382 
00383    tab_color = term__atocolor(colorTabComp);
00384    prompt_setcolor(term__atocolor(colorPrompt));
00385 
00386    setKeywordColors(term__atocolor(colorTab),
00387                     term__atocolor(colorBracket),
00388                     term__atocolor(colorBadBracket));
00389 }
00390 
00391 
00392 void
00393 termResize(void) {
00394    el_resize(gEditLine);  // this is called by SIGWINCH when term is resized - detects term width itself
00395 }
00396 
00397 
00398 void
00399 setEcho(bool echo) {
00400    if (echo) {
00401       tty_noquotemode(gEditLine);
00402    } else {
00403       tty_quotemode(gEditLine);
00404    }
00405 }
00406 
00407 
00408 /*
00409  * history functions
00410  */
00411 
00412 /*
00413  * is normally called before application starts to use
00414  * history expansion functions
00415  */
00416 void
00417 using_history(void) {
00418    if (gHistory == NULL || gEditLine == NULL) {
00419       rl_initialize();
00420    }
00421 }
00422 
00423 
00424 #ifdef EL_HISTORY_EXPAND
00425 /*
00426  * substitute ``what'' with ``with'', returning resulting string; if
00427  * globally == 1, substitutes all occurences of what, otherwise only the
00428  * first one
00429  */
00430 static char*
00431 _rl_compat_sub(const char* str, const char* what, const char* with,
00432                int globally) {
00433    char* result;
00434    const char* temp, * newp;
00435    size_t len, add;
00436    int with_len, what_len;
00437    size_t size, i;
00438 
00439    result = (char*) malloc((size = 16));
00440    temp = str;
00441    with_len = strlen(with);
00442    what_len = strlen(what);
00443    len = 0;
00444 
00445    do {
00446       newp = strstr(temp, what);
00447 
00448       if (newp) {
00449          i = newp - temp;
00450          add = i + with_len;
00451 
00452          if (i + add + 1 >= size) {
00453             size += add + 1;
00454             result = (char*) realloc(result, size);
00455          }
00456          (void) strncpy(&result[len], temp, i);
00457          len += i;
00458          (void) strcpy(&result[len], with);                     /* safe */
00459          len += with_len;
00460          temp = newp + what_len;
00461       } else {
00462          add = strlen(temp);
00463 
00464          if (len + add + 1 >= size) {
00465             size += add + 1;
00466             result = (char*) realloc(result, size);
00467          }
00468          (void) strcpy(&result[len], temp);                     /* safe */
00469          len += add;
00470          temp = NULL;
00471       }
00472    }
00473    while (temp && globally);
00474    result[len] = '\0';
00475 
00476    return result;
00477 } // _rl_compat_sub
00478 #endif
00479 
00480 
00481 #ifdef EL_HISTORY_EXPAND
00482 /*
00483  * the real function doing history expansion - takes as argument command
00484  * to do and data upon which the command should be executed
00485  * does expansion the way I've understood readline documentation
00486  * word designator ``%'' isn't supported (yet ?)
00487  *
00488  * returns 0 if data was not modified, 1 if it was and 2 if the string
00489  * should be only printed and not executed; in case of error,
00490  * returns -1 and *result points to NULL
00491  * it's callers responsibility to free() string returned in *result
00492  */
00493 static int
00494 _history_expand_command(const char* command, size_t cmdlen, char** result) {
00495    char** arr, * tempcmd, * line, * search = NULL, * cmd;
00496    const char* event_data = NULL;
00497    static char* from = NULL, * to = NULL;
00498    int start = -1, end = -1, max, i, idx;
00499    int gHistory_on = 0, t_on = 0, r_on = 0, gEditLine_on = 0, p_on = 0, g_on = 0;
00500    int event_num = 0, retval;
00501    size_t cmdsize;
00502 
00503    *result = NULL;
00504 
00505    cmd = (char*) alloca(cmdlen + 1);
00506    (void) strncpy(cmd, command, cmdlen);
00507    cmd[cmdlen] = 0;
00508 
00509    idx = 1;
00510 
00511    /* find out which event to take */
00512    if (cmd[idx] == history_expansion_char) {
00513       event_num = history_length;
00514       idx++;
00515    } else {
00516       int off, num;
00517       size_t len;
00518       off = idx;
00519 
00520       while (cmd[off] && !strchr(":^$*-%", cmd[off]))
00521          off++;
00522       num = atoi(&cmd[idx]);
00523 
00524       if (num != 0) {
00525          event_num = num;
00526 
00527          if (num < 0) {
00528             event_num += history_length + 1;
00529          }
00530       } else {
00531          int prefix = 1, curr_num;
00532          HistEvent_t ev;
00533 
00534          len = off - idx;
00535 
00536          if (cmd[idx] == '?') {
00537             idx++, len--;
00538 
00539             if (cmd[off - 1] == '?') {
00540                len--;
00541             } else if (cmd[off] != '\n' && cmd[off] != '\0') {
00542                return -1;
00543             }
00544             prefix = 0;
00545          }
00546          search = (char*) alloca(len + 1);
00547          (void) strncpy(search, &cmd[idx], len);
00548          search[len] = '\0';
00549 
00550          if (history(gHistory, &ev, H_CURR) != 0) {
00551             return -1;
00552          }
00553          curr_num = ev.fNum;
00554 
00555          if (prefix) {
00556             retval = history_search_prefix(search, -1);
00557          } else {
00558             retval = history_search(search, -1);
00559          }
00560 
00561          if (retval == -1) {
00562             fprintf(rl_outstream, "%s: Event not found\n",
00563                     search);
00564             return -1;
00565          }
00566 
00567          if (history(gHistory, &ev, H_CURR) != 0) {
00568             return -1;
00569          }
00570          event_data = ev.fStr;
00571 
00572          /* roll back to original position */
00573          history(gHistory, &ev, H_NEXT_EVENT, curr_num);
00574       }
00575       idx = off;
00576    }
00577 
00578    if (!event_data && event_num >= 0) {
00579       HIST_ENTRY* rl_he;
00580       rl_he = history_get(event_num);
00581 
00582       if (!rl_he) {
00583          return 0;
00584       }
00585       event_data = rl_he->line;
00586    } else {
00587       return -1;
00588    }
00589 
00590    if (cmd[idx] != ':') {
00591       return -1;
00592    }
00593    cmd += idx + 1;
00594 
00595    /* recognize cmd */
00596    if (*cmd == '^') {
00597       start = end = 1, cmd++;
00598    } else if (*cmd == '$') {
00599       start = end = -1, cmd++;
00600    } else if (*cmd == '*') {
00601       start = 1, end = -1, cmd++;
00602    } else if (isdigit((unsigned char) *cmd)) {
00603       const char* temp;
00604       int shifted = 0;
00605 
00606       start = atoi(cmd);
00607       temp = cmd;
00608 
00609       for ( ; isdigit((unsigned char) *cmd); cmd++) {
00610       }
00611 
00612       if (temp != cmd) {
00613          shifted = 1;
00614       }
00615 
00616       if (shifted && *cmd == '-') {
00617          if (!isdigit((unsigned char) *(cmd + 1))) {
00618             end = -2;
00619          } else {
00620             end = atoi(cmd + 1);
00621 
00622             for ( ; isdigit((unsigned char) *cmd); cmd++) {
00623             }
00624          }
00625       } else if (shifted && *cmd == '*') {
00626          end = -1, cmd++;
00627       } else if (shifted) {
00628          end = start;
00629       }
00630    }
00631 
00632    if (*cmd == ':') {
00633       cmd++;
00634    }
00635 
00636    line = strdup(event_data);
00637 
00638    for ( ; *cmd; cmd++) {
00639       if (*cmd == ':') {
00640          continue;
00641       } else if (*cmd == 'h') {
00642          gHistory_on = 1 | g_on, g_on = 0;
00643       } else if (*cmd == 't') {
00644          t_on = 1 | g_on, g_on = 0;
00645       } else if (*cmd == 'r') {
00646          r_on = 1 | g_on, g_on = 0;
00647       } else if (*cmd == 'e') {
00648          gEditLine_on = 1 | g_on, g_on = 0;
00649       } else if (*cmd == 'p') {
00650          p_on = 1 | g_on, g_on = 0;
00651       } else if (*cmd == 'g') {
00652          g_on = 2;
00653       } else if (*cmd == 's' || *cmd == '&') {
00654          char* what, * with, delim;
00655          size_t len, from_len;
00656          size_t size;
00657 
00658          if (*cmd == '&' && (from == NULL || to == NULL)) {
00659             continue;
00660          } else if (*cmd == 's') {
00661             delim = *(++cmd), cmd++;
00662             size = 16;
00663             what = (char*) realloc(from, size);
00664             len = 0;
00665 
00666             for ( ; *cmd && *cmd != delim; cmd++) {
00667                if (*cmd == '\\'
00668                    && *(cmd + 1) == delim) {
00669                   cmd++;
00670                }
00671 
00672                if (len >= size) {
00673                   what = (char*) realloc(what,
00674                                          (size <<= 1));
00675                }
00676                what[len++] = *cmd;
00677             }
00678             what[len] = '\0';
00679             from = what;
00680 
00681             if (*what == '\0') {
00682                free(what);
00683 
00684                if (search) {
00685                   from = strdup(search);
00686                } else {
00687                   from = NULL;
00688                   free(line);
00689                   return -1;
00690                }
00691             }
00692             cmd++;                      /* shift after delim */
00693 
00694             if (!*cmd) {
00695                continue;
00696             }
00697 
00698             size = 16;
00699             with = (char*) realloc(to, size);
00700             len = 0;
00701             from_len = strlen(from);
00702 
00703             for ( ; *cmd && *cmd != delim; cmd++) {
00704                if (len + from_len + 1 >= size) {
00705                   size += from_len + 1;
00706                   with = (char*) realloc(with, size);
00707                }
00708 
00709                if (*cmd == '&') {
00710                   /* safe */
00711                   (void) strcpy(&with[len], from);
00712                   len += from_len;
00713                   continue;
00714                }
00715 
00716                if (*cmd == '\\'
00717                    && (*(cmd + 1) == delim
00718                        || *(cmd + 1) == '&')) {
00719                   cmd++;
00720                }
00721                with[len++] = *cmd;
00722             }
00723             with[len] = '\0';
00724             to = with;
00725 
00726             tempcmd = _rl_compat_sub(line, from, to,
00727                                      (g_on) ? 1 : 0);
00728             free(line);
00729             line = tempcmd;
00730             g_on = 0;
00731          }
00732       }
00733    }
00734 
00735    arr = history_tokenize(line);
00736    free(line);                  /* no more needed */
00737 
00738    if (arr && *arr == NULL) {
00739       free(arr), arr = NULL;
00740    }
00741 
00742    if (!arr) {
00743       return -1;
00744    }
00745 
00746    /* find out max valid idx to array of array */
00747    max = 0;
00748 
00749    for (i = 0; arr[i]; i++) {
00750       max++;
00751    }
00752    max--;
00753 
00754    /* set boundaries to something relevant */
00755    if (start < 0) {
00756       start = 1;
00757    }
00758 
00759    if (end < 0) {
00760       end = max - ((end < -1) ? 1 : 0);
00761    }
00762 
00763    /* check boundaries ... */
00764    if (start > max || end > max || start > end) {
00765       free(arr);
00766       return -1;
00767    }
00768 
00769    for (i = 0; i <= max; i++) {
00770       char* temp;
00771 
00772       if (gHistory_on && (i == 1 || gHistory_on > 1) &&
00773           (temp = strrchr(arr[i], '/'))) {
00774          *(temp + 1) = '\0';
00775       }
00776 
00777       if (t_on && (i == 1 || t_on > 1) &&
00778           (temp = strrchr(arr[i], '/'))) {
00779          (void) strcpy(arr[i], temp + 1);
00780       }
00781 
00782       if (r_on && (i == 1 || r_on > 1) &&
00783           (temp = strrchr(arr[i], '.'))) {
00784          *temp = '\0';
00785       }
00786 
00787       if (gEditLine_on && (i == 1 || gEditLine_on > 1) &&
00788           (temp = strrchr(arr[i], '.'))) {
00789          (void) strcpy(arr[i], temp);
00790       }
00791    }
00792 
00793    cmdsize = 1, cmdlen = 0;
00794    tempcmd = (char*) malloc(cmdsize);
00795 
00796    for (i = start; start <= i && i <= end; i++) {
00797       int arr_len;
00798 
00799       arr_len = strlen(arr[i]);
00800 
00801       if (cmdlen + arr_len + 1 >= cmdsize) {
00802          cmdsize += arr_len + 1;
00803          tempcmd = (char*) realloc(tempcmd, cmdsize);
00804       }
00805       (void) strcpy(&tempcmd[cmdlen], arr[i]);                  /* safe */
00806       cmdlen += arr_len;
00807       tempcmd[cmdlen++] = ' ';                  /* add a space */
00808    }
00809 
00810    while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1]))
00811       cmdlen--;
00812    tempcmd[cmdlen] = '\0';
00813 
00814    *result = tempcmd;
00815 
00816    for (i = 0; i <= max; i++) {
00817       free(arr[i]);
00818    }
00819    free(arr), arr = (char**) NULL;
00820    return (p_on) ? 2 : 1;
00821 } // _history_expand_command
00822 #endif
00823 
00824 /*
00825  * csh-style history expansion
00826  */
00827 #ifdef EL_HISTORY_EXPAND
00828 int
00829 history_expand(char* str, char** output) {
00830    int i, retval = 0, idx;
00831    size_t size;
00832    char* temp, * result;
00833 
00834    if (gHistory == NULL || gEditLine == NULL) {
00835       rl_initialize();
00836    }
00837 
00838    *output = strdup(str);       /* do it early */
00839 
00840    if (str[0] == history_subst_char) {
00841       /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
00842       temp = (char*) alloca(4 + strlen(str) + 1);
00843       temp[0] = temp[1] = history_expansion_char;
00844       temp[2] = ':';
00845       temp[3] = 's';
00846       (void) strcpy(temp + 4, str);
00847       str = temp;
00848    }
00849 #define ADD_STRING(what, len) \
00850    { \
00851       if (idx + len + 1 > size) { \
00852          result = (char*) realloc(result, (size += len + 1)); } \
00853                                            (void) strncpy(&result[idx], what, len); \
00854          idx += len; \
00855          result[idx] = '\0'; \
00856       }
00857 
00858    result = NULL;
00859    size = idx = 0;
00860 
00861    for (i = 0; str[i];) {
00862       int start, j, loop_again;
00863       size_t len;
00864 
00865       loop_again = 1;
00866       start = j = i;
00867 loop:
00868 
00869       for ( ; str[j]; j++) {
00870          if (str[j] == '\\' &&
00871              str[j + 1] == history_expansion_char) {
00872             (void) strcpy(&str[j], &str[j + 1]);
00873             continue;
00874          }
00875 
00876          if (!loop_again) {
00877             if (str[j] == '?') {
00878                while (str[j] && str[++j] != '?')
00879                   ;
00880 
00881                if (str[j] == '?') {
00882                   j++;
00883                }
00884             } else if (isspace((unsigned char) str[j])) {
00885                break;
00886             }
00887          }
00888 
00889          if (str[j] == history_expansion_char
00890              && !strchr(history_no_expand_chars, str[j + 1])
00891              && (!history_inhibit_expansion_function ||
00892                  (*history_inhibit_expansion_function)(str, j) == 0)) {
00893             break;
00894          }
00895       }
00896 
00897       if (str[j] && str[j + 1] != '#' && loop_again) {
00898          i = j;
00899          j++;
00900 
00901          if (str[j] == history_expansion_char) {
00902             j++;
00903          }
00904          loop_again = 0;
00905          goto loop;
00906       }
00907       len = i - start;
00908       temp = &str[start];
00909       ADD_STRING(temp, len);
00910 
00911       if (str[i] == '\0' || str[i] != history_expansion_char
00912           || str[i + 1] == '#') {
00913          len = j - i;
00914          temp = &str[i];
00915          ADD_STRING(temp, len);
00916 
00917          if (start == 0) {
00918             retval = 0;
00919          } else {
00920             retval = 1;
00921          }
00922          break;
00923       }
00924       retval = _history_expand_command(&str[i], (size_t) (j - i),
00925                                        &temp);
00926 
00927       if (retval != -1) {
00928          len = strlen(temp);
00929          ADD_STRING(temp, len);
00930       }
00931       i = j;
00932    }                            /* for(i ...) */
00933 
00934    if (retval == 2) {
00935       add_history(temp);
00936 #ifdef GDB_411_HACK
00937       /* gdb 4.11 has been shipped with readline, where */
00938       /* history_expand() returned -1 when the line       */
00939       /* should not be executed; in readline 2.1+         */
00940       /* it should return 2 in such a case                */
00941       retval = -1;
00942 #endif
00943    }
00944    free(*output);
00945    *output = result;
00946 
00947    return retval;
00948 } // history_expand
00949 #endif
00950 
00951 /*
00952  * Parse the string into individual tokens, similarily to how shell would do it.
00953  */
00954 char**
00955 history_tokenize(const char* str) {
00956    int size = 1, result_idx = 0, i, start;
00957    size_t len;
00958    char** result = NULL, * temp, delim = '\0';
00959 
00960    for (i = 0; str[i]; i++) {
00961       while (isspace((unsigned char) str[i]))
00962          i++;
00963       start = i;
00964 
00965       for ( ; str[i]; i++) {
00966          if (str[i] == '\\') {
00967             if (str[i + 1] != '\0') {
00968                i++;
00969             }
00970          } else if (str[i] == delim) {
00971             delim = '\0';
00972          } else if (!delim &&
00973                     (isspace((unsigned char) str[i]) ||
00974                      strchr("()<>;&|$", str[i]))) {
00975             break;
00976          } else if (!delim && strchr("'`\"", str[i])) {
00977             delim = str[i];
00978          }
00979       }
00980 
00981       if (result_idx + 2 >= size) {
00982          size <<= 1;
00983          result = (char**) realloc(result, size * sizeof(char*));
00984       }
00985       len = i - start;
00986       temp = (char*) malloc(len + 1);
00987       (void) strncpy(temp, &str[start], len);
00988       temp[len] = '\0';
00989       result[result_idx++] = temp;
00990       result[result_idx] = NULL;
00991    }
00992 
00993    return result;
00994 } // history_tokenize
00995 
00996 
00997 /*
00998  * limit size of history record to ``max'' events
00999  */
01000 void
01001 stifle_history(int max) {
01002    HistEvent_t ev;
01003 
01004    if (gHistory == NULL || gEditLine == NULL) {
01005       rl_initialize();
01006    }
01007 
01008    if (history(gHistory, &ev, H_SETSIZE, max) == 0) {
01009       max_input_history = max;
01010    }
01011 }
01012 
01013 
01014 /*
01015  * "unlimit" size of history - set the limit to maximum allowed int value
01016  */
01017 int
01018 unstifle_history(void) {
01019    HistEvent_t ev;
01020    int omax;
01021 
01022    history(gHistory, &ev, H_SETSIZE, INT_MAX);
01023    omax = max_input_history;
01024    max_input_history = INT_MAX;
01025    return omax;                 /* some value _must_ be returned */
01026 }
01027 
01028 
01029 int
01030 history_is_stifled(void) {
01031    /* cannot return true answer */
01032    return max_input_history != INT_MAX;
01033 }
01034 
01035 
01036 /*
01037  * read history from a file given
01038  */
01039 int
01040 read_history(const char* filename) {
01041    HistEvent_t ev;
01042 
01043    if (gHistory == NULL || gEditLine == NULL) {
01044       rl_initialize();
01045    }
01046    return history(gHistory, &ev, H_LOAD, filename);
01047 }
01048 
01049 
01050 /*
01051  * write history to a file given
01052  */
01053 int
01054 write_history(const char* filename) {
01055    HistEvent_t ev;
01056 
01057    if (gHistory == NULL || gEditLine == NULL) {
01058       rl_initialize();
01059    }
01060    return history(gHistory, &ev, H_SAVE, filename);
01061 }
01062 
01063 
01064 /*
01065  * returns history ``num''th event
01066  *
01067  * returned pointer points to static variable
01068  */
01069 HIST_ENTRY*
01070 history_get(int num) {
01071    static HIST_ENTRY she;
01072    HistEvent_t ev;
01073    int i = 1, curr_num;
01074 
01075    if (gHistory == NULL || gEditLine == NULL) {
01076       rl_initialize();
01077    }
01078 
01079    /* rewind to beginning */
01080    if (history(gHistory, &ev, H_CURR) != 0) {
01081       return NULL;
01082    }
01083    curr_num = ev.fNum;
01084 
01085    if (history(gHistory, &ev, H_LAST) != 0) {
01086       return NULL;              /* error */
01087    }
01088 
01089    while (i < num && history(gHistory, &ev, H_PREV) == 0)
01090       i++;
01091 
01092    if (i != num) {
01093       return NULL;              /* not so many entries */
01094 
01095    }
01096    she.line = ev.fStr;
01097    she.data = NULL;
01098 
01099    /* rewind history to the same event it was before */
01100    (void) history(gHistory, &ev, H_FIRST);
01101    (void) history(gHistory, &ev, H_NEXT_EVENT, curr_num);
01102 
01103    return &she;
01104 } // history_get
01105 
01106 
01107 /*
01108  * add the line to history table
01109  */
01110 int
01111 add_history(char* line) {
01112    HistEvent_t ev;
01113 
01114    if (gHistory == NULL || gEditLine == NULL) {
01115       rl_initialize();
01116    }
01117 
01118    size_t len = strlen(line);
01119    char oldlast = line[len - 1];
01120 
01121    if (oldlast == '\n') {
01122       // remove trailing newline; it would add a second, empty history entry
01123       line[len - 1] = 0;
01124    }
01125 
01126    if (line[0]) {
01127       // no empty lines in history, please
01128       (void) history(gHistory, &ev, H_ENTER, line);
01129 
01130       if (history(gHistory, &ev, H_GETSIZE) == 0) {
01131          history_length = ev.fNum;
01132       }
01133    }
01134    line[len - 1] = oldlast;
01135 
01136    return !(history_length > 0);        /* return 0 if all is okay */
01137 } // add_history
01138 
01139 
01140 /*
01141  * clear the history list - delete all entries
01142  */
01143 void
01144 clear_history(void) {
01145    HistEvent_t ev;
01146 
01147    history(gHistory, &ev, H_CLEAR);
01148 }
01149 
01150 
01151 /*
01152  * returns offset of the current history event
01153  */
01154 int
01155 where_history(void) {
01156    HistEvent_t ev;
01157    int curr_num, off;
01158 
01159    if (history(gHistory, &ev, H_CURR) != 0) {
01160       return 0;
01161    }
01162    curr_num = ev.fNum;
01163 
01164    history(gHistory, &ev, H_FIRST);
01165    off = 1;
01166 
01167    while (ev.fNum != curr_num && history(gHistory, &ev, H_NEXT) == 0)
01168       off++;
01169 
01170    return off;
01171 } // where_history
01172 
01173 
01174 /*
01175  * returns current history event or NULL if there is no such event
01176  */
01177 HIST_ENTRY*
01178 current_history(void) {
01179    return _move_history(H_CURR);
01180 }
01181 
01182 
01183 /*
01184  * returns total number of bytes history events' data are using
01185  */
01186 int
01187 history_total_bytes(void) {
01188    HistEvent_t ev;
01189    int curr_num, size;
01190 
01191    if (history(gHistory, &ev, H_CURR) != 0) {
01192       return -1;
01193    }
01194    curr_num = ev.fNum;
01195 
01196    history(gHistory, &ev, H_FIRST);
01197    size = 0;
01198 
01199    do {
01200       size += strlen(ev.fStr);
01201    }
01202    while (history(gHistory, &ev, H_NEXT) == 0);
01203 
01204    /* get to the same position as before */
01205    history(gHistory, &ev, H_PREV_EVENT, curr_num);
01206 
01207    return size;
01208 } // history_total_bytes
01209 
01210 
01211 /*
01212  * sets the position in the history list to ``pos''
01213  */
01214 int
01215 history_set_pos(int pos) {
01216    HistEvent_t ev;
01217    int off, curr_num;
01218 
01219    if (pos > history_length || pos < 0) {
01220       return -1;
01221    }
01222 
01223    history(gHistory, &ev, H_CURR);
01224    curr_num = ev.fNum;
01225    history(gHistory, &ev, H_FIRST);
01226    off = 0;
01227 
01228    while (off < pos && history(gHistory, &ev, H_NEXT) == 0)
01229       off++;
01230 
01231    if (off != pos) {            /* do a rollback in case of error */
01232       history(gHistory, &ev, H_FIRST);
01233       history(gHistory, &ev, H_NEXT_EVENT, curr_num);
01234       return -1;
01235    }
01236    return 0;
01237 } // history_set_pos
01238 
01239 
01240 /*
01241  * returns previous event in history and shifts pointer accordingly
01242  */
01243 HIST_ENTRY*
01244 previous_history(void) {
01245    return _move_history(H_PREV);
01246 }
01247 
01248 
01249 /*
01250  * returns next event in history and shifts pointer accordingly
01251  */
01252 HIST_ENTRY*
01253 next_history(void) {
01254    return _move_history(H_NEXT);
01255 }
01256 
01257 
01258 /*
01259  * generic history search function
01260  */
01261 static int
01262 _history_search_gen(const char* str, int direction, int pos) {
01263    HistEvent_t ev;
01264    const char* strp;
01265    int curr_num;
01266 
01267    if (history(gHistory, &ev, H_CURR) != 0) {
01268       return -1;
01269    }
01270    curr_num = ev.fNum;
01271 
01272    for ( ; ;) {
01273       strp = strstr(ev.fStr, str);
01274 
01275       if (strp && (pos < 0 || &ev.fStr[pos] == strp)) {
01276          return (int) (strp - ev.fStr);
01277       }
01278 
01279       if (history(gHistory, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) {
01280          break;
01281       }
01282    }
01283 
01284    history(gHistory, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
01285 
01286    return -1;
01287 } // _history_search_gen
01288 
01289 
01290 /*
01291  * searches for first history event containing the str
01292  */
01293 int
01294 history_search(const char* str, int direction) {
01295    return _history_search_gen(str, direction, -1);
01296 }
01297 
01298 
01299 /*
01300  * searches for first history event beginning with str
01301  */
01302 int
01303 history_search_prefix(const char* str, int direction) {
01304    return _history_search_gen(str, direction, 0);
01305 }
01306 
01307 
01308 /*
01309  * search for event in history containing str, starting at offset
01310  * abs(pos); continue backward, if pos<0, forward otherwise
01311  */
01312 /* ARGSUSED */
01313 int
01314 history_search_pos(const char* str, int /*direction*/, int pos) {
01315    HistEvent_t ev;
01316    int curr_num, off;
01317 
01318    off = (pos > 0) ? pos : -pos;
01319    pos = (pos > 0) ? 1 : -1;
01320 
01321    if (history(gHistory, &ev, H_CURR) != 0) {
01322       return -1;
01323    }
01324    curr_num = ev.fNum;
01325 
01326    if (history_set_pos(off) != 0 || history(gHistory, &ev, H_CURR) != 0) {
01327       return -1;
01328    }
01329 
01330    for ( ; ;) {
01331       if (strstr(ev.fStr, str)) {
01332          return off;
01333       }
01334 
01335       if (history(gHistory, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) {
01336          break;
01337       }
01338    }
01339 
01340    /* set "current" pointer back to previous state */
01341    history(gHistory, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
01342 
01343    return -1;
01344 } // history_search_pos
01345 
01346 
01347 /********************************/
01348 /* completition functions       */
01349 
01350 /*
01351  * does tilde expansion of strings of type ``~user/foo''
01352  * if ``user'' isn't valid user name or ``txt'' doesn't start
01353  * w/ '~', returns pointer to strdup()ed copy of ``txt''
01354  *
01355  * it's callers's responsibility to free() returned string
01356  */
01357 char*
01358 tilde_expand(char* txt) {
01359    struct passwd* pass;
01360    char* temp;
01361    size_t len = 0;
01362 
01363    if (txt[0] != '~') {
01364       return strdup(txt);
01365    }
01366 
01367    temp = strchr(txt + 1, '/');
01368 
01369    if (temp == NULL) {
01370       temp = strdup(txt + 1);
01371    } else {
01372       len = temp - txt + 1;             /* text until string after slash */
01373       temp = (char*) malloc(len);
01374       (void) strncpy(temp, txt + 1, len - 2);
01375       temp[len - 2] = '\0';
01376    }
01377    pass = getpwnam(temp);
01378    free(temp);                  /* value no more needed */
01379 
01380    if (pass == NULL) {
01381       return strdup(txt);
01382    }
01383 
01384    /* update pointer txt to point at string immedially following */
01385    /* first slash */
01386    txt += len;
01387 
01388    temp = (char*) malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);
01389    (void) sprintf(temp, "%s/%s", pass->pw_dir, txt);
01390 
01391    return temp;
01392 } // tilde_expand
01393 
01394 
01395 /*
01396  * return first found file name starting by the ``text'' or NULL if no
01397  * such file can be found
01398  * value of ``state'' is ignored
01399  *
01400  * it's caller's responsibility to free returned string
01401  */
01402 char*
01403 filename_completion_function(const char* text, int state) {
01404    static DIR* dir = NULL;
01405    static char* filename = NULL, * dirname = NULL;
01406    static size_t filename_len = 0;
01407    struct dirent* entry;
01408    char* temp;
01409    size_t len;
01410 
01411    if (state == 0 || dir == NULL) {
01412       if (dir != NULL) {
01413          closedir(dir);
01414          dir = NULL;
01415       }
01416       temp = strrchr((char*)text, '/');
01417 
01418       if (temp) {
01419          temp++;
01420          filename = (char*) realloc(filename, strlen(temp) + 1);
01421          (void) strcpy(filename, temp);
01422          len = temp - text;                     /* including last slash */
01423          dirname = (char*) realloc(dirname, len + 1);
01424          (void) strncpy(dirname, text, len);
01425          dirname[len] = '\0';
01426       } else {
01427          filename = strdup(text);
01428          dirname = NULL;
01429       }
01430 
01431       /* support for ``~user'' syntax */
01432       if (dirname && *dirname == '~') {
01433          temp = tilde_expand(dirname);
01434          dirname = (char*) realloc(dirname, strlen(temp) + 1);
01435          (void) strcpy(dirname, temp);                  /* safe */
01436          free(temp);                    /* no longer needed */
01437       }
01438       /* will be used in cycle */
01439       filename_len = strlen(filename);
01440 
01441       if (filename_len == 0) {
01442          return NULL;                   /* no expansion possible */
01443 
01444       }
01445       dir = opendir(dirname ? dirname : ".");
01446 
01447       if (!dir) {
01448          return NULL;                   /* cannot open the directory */
01449       }
01450    }
01451 
01452    /* find the match */
01453    while ((entry = readdir(dir)) != NULL) {
01454       /* otherwise, get first entry where first */
01455       /* filename_len characters are equal        */
01456       if (entry->d_name[0] == filename[0]
01457 #if defined(__SVR4) || defined(__linux__) || defined(__CYGWIN__)
01458           && strlen(entry->d_name) >= filename_len
01459 #else
01460           && entry->d_namlen >= filename_len
01461 #endif
01462           && strncmp(entry->d_name, filename,
01463                      filename_len) == 0) {
01464          break;
01465       }
01466    }
01467 
01468    if (entry) {                 /* match found */
01469       struct stat stbuf;
01470 #if defined(__SVR4) || defined(__linux__) || defined(__CYGWIN__)
01471       len = strlen(entry->d_name) +
01472 #else
01473       len = entry->d_namlen +
01474 #endif
01475             ((dirname) ? strlen(dirname) : 0) + 1 + 1;
01476       temp = (char*) malloc(len);
01477       (void) sprintf(temp, "%s%s",
01478                      dirname ? dirname : "", entry->d_name);    /* safe */
01479 
01480       /* test, if it's directory */
01481       if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode)) {
01482          strcat(temp, "/");                     /* safe */
01483       }
01484    } else {
01485       temp = NULL;
01486    }
01487 
01488    return temp;
01489 } // filename_completion_function
01490 
01491 
01492 /*
01493  * a completion generator for usernames; returns _first_ username
01494  * which starts with supplied text
01495  * text contains a partial username preceded by random character
01496  * (usually '~'); state is ignored
01497  * it's callers responsibility to free returned value
01498  */
01499 char*
01500 username_completion_function(const char* text, int state) {
01501    struct passwd* pwd;
01502 
01503    if (text[0] == '\0') {
01504       return NULL;
01505    }
01506 
01507    if (*text == '~') {
01508       text++;
01509    }
01510 
01511    if (state == 0) {
01512       setpwent();
01513    }
01514 
01515    while ((pwd = getpwent()) && text[0] == pwd->pw_name[0]
01516           && strcmp(text, pwd->pw_name) == 0)
01517       ;
01518 
01519    if (pwd == NULL) {
01520       endpwent();
01521       return NULL;
01522    }
01523    return strdup(pwd->pw_name);
01524 } // username_completion_function
01525 
01526 
01527 /*
01528  * el-compatible wrapper around rl_complete; needed for key binding
01529  */
01530 /* ARGSUSED */
01531 static unsigned char
01532 _el_rl_complete(EditLine_t* /*el*/, int ch) {
01533    return (unsigned char) rl_complete(0, ch);
01534 }
01535 
01536 
01537 /*
01538  * returns list of completitions for text given
01539  */
01540 char**
01541 completion_matches(const char* text, CPFunction* genfunc) {
01542    char** match_list = NULL, * retstr, * prevstr;
01543    size_t match_list_len, max_equal, which, i;
01544    size_t matches;
01545 
01546    if (gHistory == NULL || gEditLine == NULL) {
01547       rl_initialize();
01548    }
01549 
01550    matches = 0;
01551    match_list_len = 1;
01552 
01553    while ((retstr = (*genfunc)(text, matches)) != NULL) {
01554       if (matches + 1 >= match_list_len) {
01555          match_list_len <<= 1;
01556          match_list = (char**) realloc(match_list,
01557                                        match_list_len * sizeof(char*));
01558       }
01559       match_list[++matches] = retstr;
01560    }
01561 
01562    if (!match_list) {
01563       return (char**) NULL;             /* nothing found */
01564 
01565    }
01566    /* find least denominator and insert it to match_list[0] */
01567    which = 2;
01568    prevstr = match_list[1];
01569    max_equal = strlen(prevstr);
01570 
01571    for ( ; which <= matches; which++) {
01572       for (i = 0; i < max_equal &&
01573            prevstr[i] == match_list[which][i]; i++) {
01574          continue;
01575       }
01576       max_equal = i;
01577    }
01578 
01579    retstr = (char*) malloc(max_equal + 1);
01580    (void) strncpy(retstr, match_list[1], max_equal);
01581    retstr[max_equal] = '\0';
01582    match_list[0] = retstr;
01583 
01584    /* add NULL as last pointer to the array */
01585    if (matches + 1 >= match_list_len) {
01586       match_list = (char**) realloc(match_list,
01587                                     (match_list_len + 1) * sizeof(char*));
01588    }
01589    match_list[matches + 1] = (char*) NULL;
01590 
01591    return match_list;
01592 } // completion_matches
01593 
01594 
01595 /*
01596  * Sort function for qsort(). Just wrapper around strcasecmp().
01597  */
01598 static int
01599 _rl_qsort_string_compare(const void* i1, const void* i2) {
01600    /*LINTED const castaway*/
01601    const char* s1 = ((const char**) i1)[0];
01602    /*LINTED const castaway*/
01603    const char* s2 = ((const char**) i2)[0];
01604 
01605    return strcasecmp(s1, s2);
01606 }
01607 
01608 
01609 /*
01610  * Display list of strings in columnar format on readline's output stream.
01611  * 'matches' is list of strings, 'len' is number of strings in 'matches',
01612  * 'max' is maximum length of string in 'matches'.
01613  */
01614 void
01615 rl_display_match_list(char** matches, int len, int max) {
01616    int i, idx, limit, count;
01617    int screenwidth = gEditLine->fTerm.fSize.fH;
01618 
01619    /*
01620     * Find out how many entries can be put on one line, count
01621     * with two spaces between strings.
01622     */
01623    limit = screenwidth / (max + 2);
01624 
01625    if (limit == 0) {
01626       limit = 1;
01627    }
01628 
01629    /* how many lines of output */
01630    count = len / limit;
01631 
01632    if (count * limit < len) {
01633       count++;
01634    }
01635 
01636    /* Sort the items if they are not already sorted. */
01637    qsort(&matches[1], (size_t) (len - 1), sizeof(char*),
01638          _rl_qsort_string_compare);
01639 
01640    idx = 1;
01641 
01642    for ( ; count > 0; count--) {
01643       for (i = 0; i < limit && matches[idx]; i++, idx++) {
01644          fprintf(gEditLine->fOutFile, "%-*s  ", max, matches[idx]);
01645       }
01646       fprintf(gEditLine->fOutFile, "\n");
01647    }
01648 } // rl_display_match_list
01649 
01650 
01651 /*
01652  * Complete the word at or before point, called by rl_complete()
01653  * 'what_to_do' says what to do with the completion.
01654  * `?' means list the possible completions.
01655  * TAB means do standard completion.
01656  * `*' means insert all of the possible completions.
01657  * `!' means to do standard completion, and list all possible completions if
01658  * there is more than one.
01659  *
01660  * Note: '*' support is not implemented
01661  */
01662 static int
01663 rl_complete_internal(int what_to_do) {
01664    CPFunction* complet_func;
01665    const LineInfo_t* li;
01666    char* temp, ** matches;
01667    const char* ctemp;
01668    size_t len;
01669 
01670    if (rl_tab_hook) {
01671       int cursorIdx = gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer;
01672       char old = *gEditLine->fLine.fCursor;      // presumably \a
01673       *gEditLine->fLine.fCursor = 0;
01674       term__setcolor(tab_color);
01675       int loc = rl_tab_hook(gEditLine->fLine.fBuffer, 0, &cursorIdx);
01676       term__resetcolor();
01677 
01678       if (loc >= 0 || loc == -2 /* new line */ || cursorIdx != gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer) {
01679          size_t lenbuf = strlen(gEditLine->fLine.fBuffer);
01680          gEditLine->fLine.fBuffer[lenbuf] = old;
01681          gEditLine->fLine.fBuffer[lenbuf + 1] = 0;
01682 
01683          for (int i = gEditLine->fLine.fCursor - gEditLine->fLine.fBuffer; i < cursorIdx; ++i) {
01684             gEditLine->fLine.fBufColor[i] = -1;
01685          }
01686          gEditLine->fLine.fCursor = gEditLine->fLine.fBuffer + cursorIdx;
01687          gEditLine->fLine.fLastChar = gEditLine->fLine.fCursor;
01688 
01689          if (loc == -2) {
01690             // spit out several lines; redraw prompt!
01691             re_clear_display(gEditLine);
01692          }
01693          re_refresh(gEditLine);
01694       } else {
01695          *gEditLine->fLine.fCursor = old;
01696       }
01697       return CC_NORM;
01698    }
01699 
01700    rl_completion_type = what_to_do;
01701 
01702    if (gHistory == NULL || gEditLine == NULL) {
01703       rl_initialize();
01704    }
01705 
01706    complet_func = rl_completion_entry_function;
01707 
01708    if (!complet_func) {
01709       complet_func = filename_completion_function;
01710    }
01711 
01712    /* We now look backwards for the start of a filename/variable word */
01713    li = el_line(gEditLine);
01714    ctemp = (const char*) li->fCursor;
01715 
01716    while (ctemp > li->fBuffer
01717           && !strchr(rl_basic_word_break_characters, ctemp[-1])
01718           && (!rl_special_prefixes
01719               || !strchr(rl_special_prefixes, ctemp[-1])))
01720       ctemp--;
01721 
01722    len = li->fCursor - ctemp;
01723    temp = (char*) alloca(len + 1);
01724    (void) strncpy(temp, ctemp, len);
01725    temp[len] = '\0';
01726 
01727    /* these can be used by function called in completion_matches() */
01728    /* or (*rl_attempted_completion_function)() */
01729    rl_point = li->fCursor - li->fBuffer;
01730    rl_end = li->fLastChar - li->fBuffer;
01731 
01732    if (!rl_attempted_completion_function) {
01733       matches = completion_matches(temp, complet_func);
01734    } else {
01735       int end = li->fCursor - li->fBuffer;
01736       matches = (*rl_attempted_completion_function)(temp, (int)
01737                                                     (end - len), end);
01738    }
01739 
01740    if (matches) {
01741       int i, retval = CC_REFRESH;
01742       int matches_num, maxlen, match_len, match_display = 1;
01743 
01744       /*
01745        * Only replace the completed string with common part of
01746        * possible matches if there is possible completion.
01747        */
01748       if (matches[0][0] != '\0') {
01749          el_deletestr(gEditLine, (int) len);
01750          el_insertstr(gEditLine, matches[0]);
01751       }
01752 
01753       if (what_to_do == '?') {
01754          goto display_matches;
01755       }
01756 
01757       if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) {
01758          /*
01759           * We found exact match. Add a space after
01760           * it, unless we do filename completition and the
01761           * object is a directory.
01762           */
01763          size_t alen = strlen(matches[0]);
01764 
01765          if ((complet_func != filename_completion_function
01766               || (alen > 0 && (matches[0])[alen - 1] != '/'))
01767              && rl_completion_append_character) {
01768             char buf[2];
01769             buf[0] = rl_completion_append_character;
01770             buf[1] = '\0';
01771             el_insertstr(gEditLine, buf);
01772          }
01773       } else if (what_to_do == '!') {
01774 display_matches:
01775 
01776          /*
01777           * More than one match and requested to list possible
01778           * matches.
01779           */
01780 
01781          for (i = 1, maxlen = 0; matches[i]; i++) {
01782             match_len = strlen(matches[i]);
01783 
01784             if (match_len > maxlen) {
01785                maxlen = match_len;
01786             }
01787          }
01788          matches_num = i - 1;
01789 
01790          /* newline to get on next line from command line */
01791          fprintf(gEditLine->fOutFile, "\n");
01792 
01793          /*
01794           * If there are too many items, ask user for display
01795           * confirmation.
01796           */
01797          if (matches_num > rl_completion_query_items) {
01798             fprintf(gEditLine->fOutFile,
01799                     "Display all %d possibilities? (y or n) ",
01800                     matches_num);
01801             fflush(gEditLine->fOutFile);
01802 
01803             if (getc(stdin) != 'y') {
01804                match_display = 0;
01805             }
01806             fprintf(gEditLine->fOutFile, "\n");
01807          }
01808 
01809          if (match_display) {
01810             rl_display_match_list(matches, matches_num,
01811                                   maxlen);
01812          }
01813          retval = CC_REDISPLAY;
01814       } else if (matches[0][0]) {
01815          /*
01816           * There was some common match, but the name was
01817           * not complete enough. Next tab will print possible
01818           * completions.
01819           */
01820          el_beep(gEditLine);
01821       } else {
01822          /* lcd is not a valid object - further specification */
01823          /* is needed */
01824          el_beep(gEditLine);
01825          retval = CC_NORM;
01826       }
01827 
01828       /* free elements of array and the array itself */
01829       for (i = 0; matches[i]; i++) {
01830          free(matches[i]);
01831       }
01832       free(matches), matches = NULL;
01833 
01834       return retval;
01835    }
01836    return CC_NORM;
01837 } // rl_complete_internal
01838 
01839 
01840 /*
01841  * complete word at current point
01842  */
01843 int
01844 rl_complete(int ignore, int invoking_key) {
01845    if (gHistory == NULL || gEditLine == NULL) {
01846       rl_initialize();
01847    }
01848 
01849    if (rl_inhibit_completion) {
01850       rl_insert(ignore, invoking_key);
01851       return CC_REFRESH;
01852    } else if (gEditLine->fState.fLastCmd == gel_rl_complete_cmdnum) {
01853       return rl_complete_internal('?');
01854    } else if (grl_complete_show_all) {
01855       return rl_complete_internal('!');
01856    } else {
01857       return rl_complete_internal(TAB);
01858    }
01859 }
01860 
01861 
01862 /*
01863  * misc other functions
01864  */
01865 
01866 /*
01867  * bind key c to readline-type function func
01868  */
01869 int
01870 rl_bind_key(int c, int func(int, int)) {
01871    int retval = -1;
01872 
01873    if (gHistory == NULL || gEditLine == NULL) {
01874       rl_initialize();
01875    }
01876 
01877    if (func == rl_insert) {
01878       /* XXX notice there is no range checking of ``c'' */
01879       gEditLine->fMap.fKey[c] = ED_INSERT;
01880       retval = 0;
01881    }
01882    return retval;
01883 }
01884 
01885 
01886 /*
01887  * read one key from input - handles chars pushed back
01888  * to input stream also
01889  */
01890 int
01891 rl_read_key(void) {
01892    char fooarr[2 * sizeof(int)];
01893 
01894    if (gEditLine == NULL || gHistory == NULL) {
01895       rl_initialize();
01896    }
01897 
01898    return el_getc(gEditLine, fooarr);
01899 }
01900 
01901 
01902 /*
01903  * reset the terminal
01904  */
01905 /* ARGSUSED */
01906 void
01907 rl_reset_terminal(void) {
01908    if (gHistory == NULL || gEditLine == NULL) {
01909       rl_initialize();
01910    }
01911    el_reset(gEditLine);
01912 }
01913 
01914 
01915 /*
01916  * insert character ``c'' back into input stream, ``count'' times
01917  */
01918 int
01919 rl_insert(int count, int c) {
01920    char arr[2];
01921 
01922    if (gHistory == NULL || gEditLine == NULL) {
01923       rl_initialize();
01924    }
01925 
01926    /* XXX - int -> char conversion can lose on multichars */
01927    arr[0] = c;
01928    arr[1] = '\0';
01929 
01930    for ( ; count > 0; count--) {
01931       el_push(gEditLine, arr);
01932    }
01933 
01934    return 0;
01935 } // rl_insert
01936 
01937 
01938 EditLine_t*
01939 el_readline_el() {
01940    if (NULL == gEditLine) {
01941       rl_initialize();
01942    }
01943    return gEditLine;
01944 }
01945 
01946 
01947 int
01948 rl_eof() {
01949    return el_eof(gEditLine);
01950 }

Generated on Tue Jul 5 14:11:38 2011 for ROOT_528-00b_version by  doxygen 1.5.1