[BACK]Return to readline.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libedit

Annotation of src/lib/libedit/readline.c, Revision 1.1

1.1     ! christos    1: /*     $NetBSD$        */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 1997 The NetBSD Foundation, Inc.
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to The NetBSD Foundation
        !             8:  * by Jaromir Dolecek.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *     This product includes software developed by the NetBSD
        !            21:  *     Foundation, Inc. and its contributors.
        !            22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            23:  *    contributors may be used to endorse or promote products derived
        !            24:  *    from this software without specific prior written permission.
        !            25:  *
        !            26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            36:  * POSSIBILITY OF SUCH DAMAGE.
        !            37:  */
        !            38:
        !            39: #include <sys/cdefs.h>
        !            40: #if !defined(lint) && !defined(SCCSID)
        !            41: __RCSID("$NetBSD$");
        !            42: #endif /* not lint && not SCCSID */
        !            43:
        !            44: #include <sys/types.h>
        !            45: #include <sys/stat.h>
        !            46: #include <stdio.h>
        !            47: #include <dirent.h>
        !            48: #include <string.h>
        !            49: #include <pwd.h>
        !            50: #include <ctype.h>
        !            51: #include <stdlib.h>
        !            52: #include <unistd.h>
        !            53: #include <limits.h>
        !            54: #include "histedit.h"
        !            55: #include "readline.h"
        !            56: #include "sys.h"
        !            57: #include "el.h"
        !            58:
        !            59: /* for rl_complete() */
        !            60: #define TAB            '\r'
        !            61:
        !            62: /* see comment at the #ifdef for sense of this */
        !            63: #define GDB_411_HACK
        !            64:
        !            65: /* readline compatibility stuff - look at readline sources/documentation */
        !            66: /* to see what these variables mean */
        !            67: const char     *rl_library_version = "EditLine wrapper";
        !            68: char           *rl_readline_name = "";
        !            69: FILE           *rl_instream = NULL;
        !            70: FILE           *rl_outstream = NULL;
        !            71: int             rl_point = 0;
        !            72: int             rl_end = 0;
        !            73: char           *rl_line_buffer = NULL;
        !            74:
        !            75: int             history_base = 1;      /* probably never subject to change */
        !            76: int             history_length = 0;
        !            77: int             max_input_history = 0;
        !            78: char            history_expansion_char = '!';
        !            79: char            history_subst_char = '^';
        !            80: char           *history_no_expand_chars = " \t\n=(";
        !            81: Function       *history_inhibit_expansion_function = NULL;
        !            82:
        !            83: int             rl_inhibit_completion = 0;
        !            84: int             rl_attempted_completion_over = 0;
        !            85: char           *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
        !            86: char           *rl_completer_word_break_characters = NULL;
        !            87: char           *rl_completer_quote_characters = NULL;
        !            88: CPFunction     *rl_completion_entry_function = NULL;
        !            89: CPPFunction    *rl_attempted_completion_function = NULL;
        !            90:
        !            91: /* used for readline emulation */
        !            92: static History *h = NULL;
        !            93: static EditLine *e = NULL;
        !            94:
        !            95: /* internal functions */
        !            96: static unsigned char _el_rl_complete __P((EditLine *, int));
        !            97: static char *_get_prompt __P((EditLine *));
        !            98: static const HIST_ENTRY *_move_history __P((int));
        !            99: static int _history_search_gen __P((const char *, int, int));
        !           100: static int _history_expand_command __P((const char *, int, char **));
        !           101: static char *_rl_compat_sub __P((const char *, const char *,
        !           102:      const char *, int));
        !           103: static int rl_complete_internal __P((int));
        !           104:
        !           105: /*
        !           106:  * needed for easy prompt switching
        !           107:  */
        !           108: static char    *el_rl_prompt = NULL;
        !           109: static char *
        !           110: _get_prompt(el)
        !           111:        EditLine *el;
        !           112: {
        !           113:        return el_rl_prompt;
        !           114: }
        !           115:
        !           116: /*
        !           117:  * generic function for moving around history
        !           118:  */
        !           119: static const HIST_ENTRY *
        !           120: _move_history(op)
        !           121:        int op;
        !           122: {
        !           123:        HistEvent ev;
        !           124:        static HIST_ENTRY rl_he;
        !           125:
        !           126:        if (history(h, &ev, op) != 0)
        !           127:                return (HIST_ENTRY *) NULL;
        !           128:
        !           129:        rl_he.line = ev.str;
        !           130:        rl_he.data = "";
        !           131:
        !           132:        return &rl_he;
        !           133: }
        !           134:
        !           135:
        !           136: /*
        !           137:  * READLINE compatibility stuff
        !           138:  */
        !           139:
        !           140: /*
        !           141:  * initialize rl compat stuff
        !           142:  */
        !           143: int
        !           144: rl_initialize()
        !           145: {
        !           146:        HistEvent ev;
        !           147:        const LineInfo *li;
        !           148:
        !           149:        if (e != NULL)
        !           150:                el_end(e);
        !           151:        if (h != NULL)
        !           152:                history_end(h);
        !           153:
        !           154:        if (!rl_instream)
        !           155:                rl_instream = stdin;
        !           156:        if (!rl_outstream)
        !           157:                rl_outstream = stdout;
        !           158:        e = el_init(rl_readline_name, rl_instream, rl_outstream);
        !           159:
        !           160:        h = history_init();
        !           161:        if (!e || !h)
        !           162:                return -1;
        !           163:
        !           164:        history(h, &ev, H_SETMAXSIZE, INT_MAX); /* unlimited */
        !           165:        history_length = 0;
        !           166:        max_input_history = INT_MAX;
        !           167:        el_set(e, EL_HIST, history, h);
        !           168:
        !           169:        /* for proper prompt printing in readline() */
        !           170:        el_rl_prompt = strdup("");
        !           171:        el_set(e, EL_PROMPT, _get_prompt);
        !           172:        el_set(e, EL_SIGNAL, 1);
        !           173:
        !           174:        /* set default mode to "emacs"-style and read setting afterwards */
        !           175:        /* so this can be overriden */
        !           176:        el_set(e, EL_EDITOR, "emacs");
        !           177:
        !           178:        /* for word completition - this has to go AFTER rebinding keys */
        !           179:        /* to emacs-style */
        !           180:        el_set(e, EL_ADDFN, "rl_complete",
        !           181:               "ReadLine compatible completition function",
        !           182:               _el_rl_complete);
        !           183:        el_set(e, EL_BIND, "^I", "rl_complete", NULL);
        !           184:
        !           185:        /* read settings from configuration file */
        !           186:        el_source(e, NULL);
        !           187:
        !           188:        /* some readline apps do use this */
        !           189:        li = el_line(e);
        !           190:        rl_line_buffer = (char *) li->buffer;
        !           191:        rl_point = rl_end = 0;
        !           192:
        !           193:        return 0;
        !           194: }
        !           195:
        !           196: /*
        !           197:  * read one line from input stream and return it, chomping
        !           198:  * trailing newline (if there is any)
        !           199:  */
        !           200: char *
        !           201: readline(const char *prompt)
        !           202: {
        !           203:        HistEvent ev;
        !           204:        size_t count;
        !           205:        const char *ret;
        !           206:
        !           207:        if (e == NULL || h == NULL)
        !           208:                rl_initialize();
        !           209:
        !           210:        /* set the prompt */
        !           211:        if (strcmp(el_rl_prompt, prompt) != 0) {
        !           212:                free(el_rl_prompt);
        !           213:                el_rl_prompt = strdup(prompt);
        !           214:        }
        !           215:        /* get one line from input stream */
        !           216:        ret = el_gets(e, &count);
        !           217:
        !           218:        if (ret && count > 0) {
        !           219:                char *foo;
        !           220:                off_t lastidx;
        !           221:
        !           222:                foo = strdup(ret);
        !           223:                lastidx = count - 1;
        !           224:                if (foo[lastidx] == '\n')
        !           225:                        foo[lastidx] = '\0';
        !           226:
        !           227:                ret = foo;
        !           228:        } else
        !           229:                ret = NULL;
        !           230:
        !           231:        history(h, &ev, H_GETSIZE);
        !           232:        history_length = ev.num;
        !           233:
        !           234:        return (char *) ret;
        !           235: }
        !           236:
        !           237: /*
        !           238:  * history functions
        !           239:  */
        !           240:
        !           241: /*
        !           242:  * is normally called before application starts to use
        !           243:  * history expansion functions
        !           244:  */
        !           245: void
        !           246: using_history()
        !           247: {
        !           248:        if (h == NULL || e == NULL)
        !           249:                rl_initialize();
        !           250: }
        !           251:
        !           252: /*
        !           253:  * substitute ``what'' with ``with'', returning resulting string; if
        !           254:  * globally == 1, substitutes all occurences of what, otherwise only the
        !           255:  * first one
        !           256:  */
        !           257: static char    *
        !           258: _rl_compat_sub(str, what, with, globally)
        !           259:        const char     *str, *what, *with;
        !           260:        int             globally;
        !           261: {
        !           262:        char           *result;
        !           263:        const char     *temp, *new;
        !           264:        int             size, len, i, with_len, what_len, add;
        !           265:
        !           266:        result = malloc((size = 16));
        !           267:        temp = str;
        !           268:        with_len = strlen(with);
        !           269:        what_len = strlen(what);
        !           270:        len = 0;
        !           271:        do {
        !           272:                new = strstr(temp, what);
        !           273:                if (new) {
        !           274:                        i = new - temp;
        !           275:                        add = i + with_len;
        !           276:                        if (i + add + 1 >= size) {
        !           277:                                size += add + 1;
        !           278:                                result = realloc(result, size);
        !           279:                        }
        !           280:                        (void)strncpy(&result[len], temp, i);
        !           281:                        len += i;
        !           282:                        (void)strcpy(&result[len], with);       /* safe */
        !           283:                        len += with_len;
        !           284:                        temp = new + what_len;
        !           285:                } else {
        !           286:                        add = strlen(temp);
        !           287:                        if (len + add + 1 >= size) {
        !           288:                                size += add + 1;
        !           289:                                result = realloc(result, size);
        !           290:                        }
        !           291:                        (void)strcpy(&result[len], temp);       /* safe */
        !           292:                        len += add;
        !           293:                        temp = NULL;
        !           294:                }
        !           295:        } while (temp);
        !           296:        result[len] = '\0';
        !           297:
        !           298:        return result;
        !           299: }
        !           300:
        !           301: /*
        !           302:  * the real function doing history expansion - takes as argument command
        !           303:  * to do and data upon which the command should be executed
        !           304:  * does expansion the way I've understood readline documentation
        !           305:  * word designator ``%'' isn't supported (yet ?)
        !           306:  *
        !           307:  * returns 0 if data was not modified, 1 if it was and 2 if the string
        !           308:  * should be only printed and not executed; in case of error,
        !           309:  * returns -1 and *result points to NULL
        !           310:  * it's callers responsibility to free() string returned in *result
        !           311:  */
        !           312: static int
        !           313: _history_expand_command(command, len, result)
        !           314:        const char     *command;
        !           315:        int             len;
        !           316:        char          **result;
        !           317: {
        !           318:        char          **arr, *temp, *line, *search = NULL, *cmd;
        !           319:        const char     *event_data = NULL;
        !           320:        static const char *from = NULL, *to = NULL;
        !           321:        int             start = -1, end = -1, max, i, size, idx;
        !           322:        int             h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0,
        !           323:                        g_on = 0;
        !           324:        int             event_num = 0, retval;
        !           325:
        !           326:        *result = NULL;
        !           327:
        !           328:        cmd = alloca(len + 1);
        !           329:        (void)strncpy(cmd, command, len);
        !           330:        cmd[len] = 0;
        !           331:
        !           332:        idx = 1;
        !           333:        /* find out which event to take */
        !           334:        if (cmd[idx] == history_expansion_char) {
        !           335:                event_num = history_length;
        !           336:                idx++;
        !           337:        } else {
        !           338:                int             off, len, num;
        !           339:                off = idx;
        !           340:                while (cmd[off] && !strchr(":^$*-%", cmd[off]))
        !           341:                        off++;
        !           342:                num = atoi(&cmd[idx]);
        !           343:                if (num != 0) {
        !           344:                        event_num = num;
        !           345:                        if (num < 0)
        !           346:                                event_num += history_length + 1;
        !           347:                } else {
        !           348:                        int prefix = 1, curr_num;
        !           349:                        HistEvent ev;
        !           350:
        !           351:                        len = off - idx;
        !           352:                        if (cmd[idx] == '?') {
        !           353:                                idx++, len--;
        !           354:                                if (cmd[off - 1] == '?')
        !           355:                                        len--;
        !           356:                                else if (cmd[off] != '\n' && cmd[off] != '\0')
        !           357:                                        return -1;
        !           358:                                prefix = 0;
        !           359:                        }
        !           360:                        search = alloca(len + 1);
        !           361:                        (void)strncpy(search, &cmd[idx], len);
        !           362:                        search[len] = '\0';
        !           363:
        !           364:                        if (history(h, &ev, H_CURR) != 0)
        !           365:                                return -1;
        !           366:                        curr_num = ev.num;
        !           367:
        !           368:                        if (prefix)
        !           369:                                retval = history_search_prefix(search, -1);
        !           370:                        else
        !           371:                                retval = history_search(search, -1);
        !           372:
        !           373:                        if (retval == -1) {
        !           374:                                fprintf(rl_outstream, "%s: Event not found\n",
        !           375:                                        search);
        !           376:                                return -1;
        !           377:                        }
        !           378:                        if (history(h, &ev, H_CURR) != 0)
        !           379:                                return -1;
        !           380:                        event_data = ev.str;
        !           381:
        !           382:                        /* roll back to original position */
        !           383:                        history(h, &ev, H_NEXT_EVENT, curr_num);
        !           384:                }
        !           385:                idx = off;
        !           386:        }
        !           387:
        !           388:        if (!event_data && event_num >= 0) {
        !           389:                const HIST_ENTRY *rl_he;
        !           390:                rl_he = history_get(event_num);
        !           391:                if (!rl_he)
        !           392:                        return 0;
        !           393:                event_data = rl_he->line;
        !           394:        } else
        !           395:                return -1;
        !           396:
        !           397:        if (cmd[idx] != ':')
        !           398:                return -1;
        !           399:        cmd += idx + 1;
        !           400:
        !           401:        /* recognize cmd */
        !           402:        if (*cmd == '^')
        !           403:                start = end = 1, cmd++;
        !           404:        else if (*cmd == '$')
        !           405:                start = end = -1, cmd++;
        !           406:        else if (*cmd == '*')
        !           407:                start = 1, end = -1, cmd++;
        !           408:        else if (isdigit(*cmd)) {
        !           409:                const char *temp;
        !           410:                int shifted = 0;
        !           411:
        !           412:                start = atoi(cmd);
        !           413:                temp = cmd;
        !           414:                for (; isdigit(*cmd); cmd++);
        !           415:                if (temp != cmd)
        !           416:                        shifted = 1;
        !           417:                if (shifted && *cmd == '-') {
        !           418:                        if (!isdigit(*(cmd + 1)))
        !           419:                                end = -2;
        !           420:                        else {
        !           421:                                end = atoi(cmd + 1);
        !           422:                                for (; isdigit(*cmd); cmd++);
        !           423:                        }
        !           424:                } else if (shifted && *cmd == '*')
        !           425:                        end = -1, cmd++;
        !           426:                else if (shifted)
        !           427:                        end = start;
        !           428:        }
        !           429:        if (*cmd == ':')
        !           430:                cmd++;
        !           431:
        !           432:        line = strdup(event_data);
        !           433:        for (; *cmd; cmd++) {
        !           434:                if (*cmd == ':')
        !           435:                        continue;
        !           436:                else if (*cmd == 'h')
        !           437:                        h_on = 1 | g_on, g_on = 0;
        !           438:                else if (*cmd == 't')
        !           439:                        t_on = 1 | g_on, g_on = 0;
        !           440:                else if (*cmd == 'r')
        !           441:                        r_on = 1 | g_on, g_on = 0;
        !           442:                else if (*cmd == 'e')
        !           443:                        e_on = 1 | g_on, g_on = 0;
        !           444:                else if (*cmd == 'p')
        !           445:                        p_on = 1 | g_on, g_on = 0;
        !           446:                else if (*cmd == 'g')
        !           447:                        g_on = 2;
        !           448:                else if (*cmd == 's' || *cmd == '&') {
        !           449:                        char           *what, *with, delim;
        !           450:                        int             len, size, from_len;
        !           451:
        !           452:                        if (*cmd == '&' && (from == NULL || to == NULL))
        !           453:                                continue;
        !           454:                        else if (*cmd == 's') {
        !           455:                                delim = *(++cmd), cmd++;
        !           456:                                size = 16;
        !           457:                                what = realloc((void *) from, size);
        !           458:                                len = 0;
        !           459:                                for (; *cmd && *cmd != delim; cmd++) {
        !           460:                                        if (*cmd == '\\'
        !           461:                                            && *(cmd + 1) == delim)
        !           462:                                                cmd++;
        !           463:                                        if (len >= size)
        !           464:                                                what = realloc(what,
        !           465:                                                    (size <<= 1));
        !           466:                                        what[len++] = *cmd;
        !           467:                                }
        !           468:                                what[len] = '\0';
        !           469:                                from = what;
        !           470:                                if (*what == '\0') {
        !           471:                                        free(what);
        !           472:                                        if (search)
        !           473:                                                from = strdup(search);
        !           474:                                        else {
        !           475:                                                from = NULL;
        !           476:                                                return -1;
        !           477:                                        }
        !           478:                                }
        !           479:                                cmd++;  /* shift after delim */
        !           480:                                if (!*cmd)
        !           481:                                        continue;
        !           482:
        !           483:                                size = 16;
        !           484:                                with = realloc((void *) to, size);
        !           485:                                len = 0;
        !           486:                                from_len = strlen(from);
        !           487:                                for (; *cmd && *cmd != delim; cmd++) {
        !           488:                                        if (len + from_len + 1 >= size) {
        !           489:                                                size += from_len + 1;
        !           490:                                                with = realloc(with, size);
        !           491:                                        }
        !           492:                                        if (*cmd == '&') {
        !           493:                                                /* safe */
        !           494:                                                (void)strcpy(&with[len], from);
        !           495:                                                len += from_len;
        !           496:                                                continue;
        !           497:                                        }
        !           498:                                        if (*cmd == '\\'
        !           499:                                            && (*(cmd + 1) == delim
        !           500:                                                || *(cmd + 1) == '&'))
        !           501:                                                cmd++;
        !           502:                                        with[len++] = *cmd;
        !           503:                                }
        !           504:                                with[len] = '\0';
        !           505:                                to = with;
        !           506:
        !           507:                                temp = _rl_compat_sub(line, from, to,
        !           508:                                    (g_on) ? 1 : 0);
        !           509:                                free(line);
        !           510:                                line = temp;
        !           511:                                g_on = 0;
        !           512:                        }
        !           513:                }
        !           514:        }
        !           515:
        !           516:        arr = history_tokenize(line);
        !           517:        free(line);             /* no more needed */
        !           518:        if (arr && *arr == NULL)
        !           519:                free(arr), arr = NULL;
        !           520:        if (!arr)
        !           521:                return -1;
        !           522:
        !           523:        /* find out max valid idx to array of array */
        !           524:        max = 0;
        !           525:        for (i = 0; arr[i]; i++)
        !           526:                max++;
        !           527:        max--;
        !           528:
        !           529:        /* set boundaries to something relevant */
        !           530:        if (start < 0)
        !           531:                start = 1;
        !           532:        if (end < 0)
        !           533:                end = max - ((end < -1) ? 1 : 0);
        !           534:
        !           535:        /* check boundaries ... */
        !           536:        if (start > max || end > max || start > end)
        !           537:                return -1;
        !           538:
        !           539:        for (i = 0; i <= max; i++) {
        !           540:                char           *temp;
        !           541:                if (h_on && (i == 1 || h_on > 1) &&
        !           542:                    (temp = strrchr(arr[i], '/')))
        !           543:                        *(temp + 1) = '\0';
        !           544:                if (t_on && (i == 1 || t_on > 1) &&
        !           545:                    (temp = strrchr(arr[i], '/')))
        !           546:                        (void)strcpy(arr[i], temp + 1);
        !           547:                if (r_on && (i == 1 || r_on > 1) &&
        !           548:                    (temp = strrchr(arr[i], '.')))
        !           549:                        *temp = '\0';
        !           550:                if (e_on && (i == 1 || e_on > 1) &&
        !           551:                    (temp = strrchr(arr[i], '.')))
        !           552:                        (void)strcpy(arr[i], temp);
        !           553:        }
        !           554:
        !           555:        size = 1, len = 0;
        !           556:        temp = malloc(size);
        !           557:        for (i = start; start <= i && i <= end; i++) {
        !           558:                int             arr_len;
        !           559:
        !           560:                arr_len = strlen(arr[i]);
        !           561:                if (len + arr_len + 1 >= size) {
        !           562:                        size += arr_len + 1;
        !           563:                        temp = realloc(temp, size);
        !           564:                }
        !           565:                (void)strcpy(&temp[len], arr[i]);       /* safe */
        !           566:                len += arr_len;
        !           567:                temp[len++] = ' ';      /* add a space */
        !           568:        }
        !           569:        while (len > 0 && isspace(temp[len - 1]))
        !           570:                len--;
        !           571:        temp[len] = '\0';
        !           572:
        !           573:        *result = temp;
        !           574:
        !           575:        for (i = 0; i <= max; i++)
        !           576:                free(arr[i]);
        !           577:        free(arr), arr = (char **) NULL;
        !           578:        return (p_on) ? 2 : 1;
        !           579: }
        !           580:
        !           581: /*
        !           582:  * csh-style history expansion
        !           583:  */
        !           584: int
        !           585: history_expand(str, output)
        !           586:        char           *str;
        !           587:        char          **output;
        !           588: {
        !           589:        int             i, retval = 0, size, idx;
        !           590:        char           *temp, *result;
        !           591:
        !           592:        if (h == NULL || e == NULL)
        !           593:                rl_initialize();
        !           594:
        !           595:        *output = strdup(str);  /* do it early */
        !           596:
        !           597:        if (str[0] == history_subst_char) {
        !           598:                /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
        !           599:                temp = alloca(4 + strlen(str) + 1);
        !           600:                temp[0] = temp[1] = history_expansion_char;
        !           601:                temp[2] = ':';
        !           602:                temp[3] = 's';
        !           603:                (void)strcpy(temp + 4, str);
        !           604:                str = temp;
        !           605:        }
        !           606: #define ADD_STRING(what, len)                                          \
        !           607:        {                                                               \
        !           608:                if (idx + len + 1 > size)                               \
        !           609:                        result = realloc(result, (size += len + 1));    \
        !           610:                (void)strncpy(&result[idx], what, len);                 \
        !           611:                idx += len;                                             \
        !           612:                result[idx] = '\0';                                     \
        !           613:        }
        !           614:
        !           615:        result = NULL;
        !           616:        size = idx = 0;
        !           617:        for (i = 0; str[i];) {
        !           618:                int start, j, len, loop_again;
        !           619:
        !           620:                loop_again = 1;
        !           621:                start = j = i;
        !           622: loop:
        !           623:                for (; str[j]; j++) {
        !           624:                        if (str[j] == '\\' &&
        !           625:                            str[j + 1] == history_expansion_char) {
        !           626:                                (void)strcpy(&str[j], &str[j + 1]);
        !           627:                                continue;
        !           628:                        }
        !           629:                        if (!loop_again) {
        !           630:                                if (str[j] == '?') {
        !           631:                                        while (str[j] && str[++j] != '?');
        !           632:                                        if (str[j] == '?')
        !           633:                                                j++;
        !           634:                                } else if (isspace(str[j]))
        !           635:                                        break;
        !           636:                        }
        !           637:                        if (str[j] == history_expansion_char
        !           638:                            && !strchr(history_no_expand_chars, str[j + 1])
        !           639:                            && (!history_inhibit_expansion_function ||
        !           640:                        (*history_inhibit_expansion_function) (str, j) == 0))
        !           641:                                break;
        !           642:                }
        !           643:
        !           644:                if (str[j] && str[j + 1] != '#' && loop_again) {
        !           645:                        i = j;
        !           646:                        j++;
        !           647:                        if (str[j] == history_expansion_char)
        !           648:                                j++;
        !           649:                        loop_again = 0;
        !           650:                        goto loop;
        !           651:                }
        !           652:                len = i - start;
        !           653:                temp = &str[start];
        !           654:                ADD_STRING(temp, len);
        !           655:
        !           656:                if (str[i] == '\0' || str[i] != history_expansion_char
        !           657:                    || str[i + 1] == '#') {
        !           658:                        len = j - i;
        !           659:                        temp = &str[i];
        !           660:                        ADD_STRING(temp, len);
        !           661:                        if (start == 0)
        !           662:                                retval = 0;
        !           663:                        else
        !           664:                                retval = 1;
        !           665:                        break;
        !           666:                }
        !           667:                retval = _history_expand_command(&str[i], j - i, &temp);
        !           668:                if (retval != -1) {
        !           669:                        len = strlen(temp);
        !           670:                        ADD_STRING(temp, len);
        !           671:                }
        !           672:                i = j;
        !           673:        }                       /* for(i ...) */
        !           674:
        !           675:        if (retval == 2) {
        !           676:                add_history(temp);
        !           677: #ifdef GDB_411_HACK
        !           678:                /* gdb 4.11 has been shipped with readline, where */
        !           679:                /* history_expand() returned -1 when the line     */
        !           680:                /* should not be executed; in readline 2.1+       */
        !           681:                /* it should return 2 in such a case              */
        !           682:                retval = -1;
        !           683: #endif
        !           684:        }
        !           685:        free(*output);
        !           686:        *output = result;
        !           687:
        !           688:        return retval;
        !           689: }
        !           690:
        !           691: /*
        !           692:  * returns array of tokens parsed out of string, much as the shell might
        !           693:  */
        !           694: char **
        !           695: history_tokenize(str)
        !           696:        const char     *str;
        !           697: {
        !           698:        int  size = 1, result_idx = 0, i, start, len;
        !           699:        char **result = NULL, *temp, delim = '\0';
        !           700:
        !           701:        for (i = 0; str[i]; i++) {
        !           702:                while (isspace(str[i]))
        !           703:                        i++;
        !           704:                start = i;
        !           705:                for (; str[i]; i++) {
        !           706:                        if (str[i] == '\\')
        !           707:                                i++;
        !           708:                        else if (str[i] == delim)
        !           709:                                delim = '\0';
        !           710:                        else if (!delim &&
        !           711:                            (isspace(str[i]) || strchr("()<>;&|$", str[i])))
        !           712:                                break;
        !           713:                        else if (!delim && strchr("'`\"", str[i]))
        !           714:                                delim = str[i];
        !           715:                }
        !           716:
        !           717:                if (result_idx + 2 >= size) {
        !           718:                        size <<= 1;
        !           719:                        result = realloc(result, size * sizeof(char *));
        !           720:                }
        !           721:                len = i - start;
        !           722:                temp = malloc(len + 1);
        !           723:                (void)strncpy(temp, &str[start], len);
        !           724:                temp[len] = '\0';
        !           725:                result[result_idx++] = temp;
        !           726:                result[result_idx] = NULL;
        !           727:        }
        !           728:
        !           729:        return result;
        !           730: }
        !           731:
        !           732: /*
        !           733:  * limit size of history record to ``max'' events
        !           734:  */
        !           735: void
        !           736: stifle_history(max)
        !           737:        int max;
        !           738: {
        !           739:        HistEvent ev;
        !           740:
        !           741:        if (h == NULL || e == NULL)
        !           742:                rl_initialize();
        !           743:
        !           744:        if (history(h, &ev, H_SETMAXSIZE, max) == 0)
        !           745:                max_input_history = max;
        !           746: }
        !           747:
        !           748: /*
        !           749:  * "unlimit" size of history - set the limit to maximum allowed int value
        !           750:  */
        !           751: int
        !           752: unstifle_history()
        !           753: {
        !           754:        HistEvent ev;
        !           755:        int omax;
        !           756:
        !           757:        history(h, &ev, H_SETMAXSIZE, INT_MAX);
        !           758:        omax = max_input_history;
        !           759:        max_input_history = INT_MAX;
        !           760:        return omax;            /* some value _must_ be returned */
        !           761: }
        !           762:
        !           763: int
        !           764: history_is_stifled()
        !           765: {
        !           766:        /* cannot return true answer */
        !           767:        return (max_input_history != INT_MAX);
        !           768: }
        !           769:
        !           770: /*
        !           771:  * read history from a file given
        !           772:  */
        !           773: int
        !           774: read_history(filename)
        !           775:        const char *filename;
        !           776: {
        !           777:        HistEvent ev;
        !           778:
        !           779:        if (h == NULL || e == NULL)
        !           780:                rl_initialize();
        !           781:        return history(h, &ev, H_LOAD, filename);
        !           782: }
        !           783:
        !           784: /*
        !           785:  * write history to a file given
        !           786:  */
        !           787: int
        !           788: write_history(filename)
        !           789:        const char *filename;
        !           790: {
        !           791:        HistEvent ev;
        !           792:
        !           793:        if (h == NULL || e == NULL)
        !           794:                rl_initialize();
        !           795:        return history(h, &ev, H_SAVE, filename);
        !           796: }
        !           797:
        !           798: /*
        !           799:  * returns history ``num''th event
        !           800:  *
        !           801:  * returned pointer points to static variable
        !           802:  */
        !           803: const HIST_ENTRY *
        !           804: history_get(num)
        !           805:        int             num;
        !           806: {
        !           807:        static HIST_ENTRY she;
        !           808:        HistEvent ev;
        !           809:        int i = 1, curr_num;
        !           810:
        !           811:        if (h == NULL || e == NULL)
        !           812:                rl_initialize();
        !           813:
        !           814:        /* rewind to beginning */
        !           815:        if (history(h, &ev, H_CURR) != 0)
        !           816:                return NULL;
        !           817:        curr_num = ev.num;
        !           818:        if (history(h, &ev, H_LAST) != 0)
        !           819:                return NULL;    /* error */
        !           820:        while (i < num && history(h, &ev, H_PREV) == 0)
        !           821:                i++;
        !           822:        if (i != num)
        !           823:                return NULL;    /* not so many entries */
        !           824:
        !           825:        she.line = ev.str;
        !           826:        she.data = NULL;
        !           827:
        !           828:        /* rewind history to the same event it was before */
        !           829:        (void) history(h, &ev, H_FIRST);
        !           830:        (void) history(h, &ev, H_NEXT_EVENT, curr_num);
        !           831:
        !           832:        return &she;
        !           833: }
        !           834:
        !           835: /*
        !           836:  * add the line to history table
        !           837:  */
        !           838: int
        !           839: add_history(line)
        !           840:        const char *line;
        !           841: {
        !           842:        HistEvent ev;
        !           843:
        !           844:        if (h == NULL || e == NULL)
        !           845:                rl_initialize();
        !           846:
        !           847:        (void) history(h, &ev, H_ENTER, line);
        !           848:        if (history(h, &ev, H_GETSIZE) == 0)
        !           849:                history_length = ev.num;
        !           850:
        !           851:        return (!(history_length > 0)); /* return 0 if all is okay */
        !           852: }
        !           853:
        !           854: /*
        !           855:  * clear the history list - delete all entries
        !           856:  */
        !           857: void
        !           858: clear_history()
        !           859: {
        !           860:        HistEvent ev;
        !           861:        history(h, &ev, H_CLEAR);
        !           862: }
        !           863:
        !           864: /*
        !           865:  * returns offset of the current history event
        !           866:  */
        !           867: int
        !           868: where_history()
        !           869: {
        !           870:        HistEvent ev;
        !           871:        int curr_num, off;
        !           872:
        !           873:        if (history(h, &ev, H_CURR) != 0)
        !           874:                return 0;
        !           875:        curr_num = ev.num;
        !           876:
        !           877:        history(h, &ev, H_FIRST);
        !           878:        off = 1;
        !           879:        while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0)
        !           880:                off++;
        !           881:
        !           882:        return off;
        !           883: }
        !           884:
        !           885: /*
        !           886:  * returns current history event or NULL if there is no such event
        !           887:  */
        !           888: const HIST_ENTRY *
        !           889: current_history()
        !           890: {
        !           891:        return _move_history(H_CURR);
        !           892: }
        !           893:
        !           894: /*
        !           895:  * returns total number of bytes history events' data are using
        !           896:  */
        !           897: int
        !           898: history_total_bytes()
        !           899: {
        !           900:        HistEvent ev;
        !           901:        int curr_num, size;
        !           902:
        !           903:        if (history(h, &ev, H_CURR) != 0)
        !           904:                return -1;
        !           905:        curr_num = ev.num;
        !           906:
        !           907:        history(h, &ev, H_FIRST);
        !           908:        size = 0;
        !           909:        do
        !           910:                size += strlen(ev.str);
        !           911:        while (history(h, &ev, H_NEXT) == 0);
        !           912:
        !           913:        /* get to the same position as before */
        !           914:        history(h, &ev, H_PREV_EVENT, curr_num);
        !           915:
        !           916:        return size;
        !           917: }
        !           918:
        !           919: /*
        !           920:  * sets the position in the history list to ``pos''
        !           921:  */
        !           922: int
        !           923: history_set_pos(pos)
        !           924:        int pos;
        !           925: {
        !           926:        HistEvent ev;
        !           927:        int off, curr_num;
        !           928:
        !           929:        if (pos > history_length || pos < 0)
        !           930:                return -1;
        !           931:
        !           932:        history(h, &ev, H_CURR);
        !           933:        curr_num = ev.num;
        !           934:        history(h, &ev, H_FIRST);
        !           935:        off = 0;
        !           936:        while (off < pos && history(h, &ev, H_NEXT) == 0)
        !           937:                off++;
        !           938:
        !           939:        if (off != pos) {       /* do a rollback in case of error */
        !           940:                history(h, &ev, H_FIRST);
        !           941:                history(h, &ev, H_NEXT_EVENT, curr_num);
        !           942:                return -1;
        !           943:        }
        !           944:        return 0;
        !           945: }
        !           946:
        !           947: /*
        !           948:  * returns previous event in history and shifts pointer accordingly
        !           949:  */
        !           950: const HIST_ENTRY *
        !           951: previous_history()
        !           952: {
        !           953:        return _move_history(H_PREV);
        !           954: }
        !           955:
        !           956: /*
        !           957:  * returns next event in history and shifts pointer accordingly
        !           958:  */
        !           959: const HIST_ENTRY *
        !           960: next_history()
        !           961: {
        !           962:        return _move_history(H_NEXT);
        !           963: }
        !           964:
        !           965: /*
        !           966:  * generic history search function
        !           967:  */
        !           968: static int
        !           969: _history_search_gen(str, direction, pos)
        !           970:        const char *str;
        !           971:        int direction, pos;
        !           972: {
        !           973:        HistEvent       ev;
        !           974:        const char     *strp;
        !           975:        int             curr_num;
        !           976:
        !           977:        if (history(h, &ev, H_CURR) != 0)
        !           978:                return -1;
        !           979:        curr_num = ev.num;
        !           980:
        !           981:        for (;;) {
        !           982:                strp = strstr(ev.str, str);
        !           983:                if (strp && (pos < 0 || &ev.str[pos] == strp))
        !           984:                        return (int) (strp - ev.str);
        !           985:                if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0)
        !           986:                        break;
        !           987:        }
        !           988:
        !           989:        history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
        !           990:
        !           991:        return -1;
        !           992: }
        !           993:
        !           994: /*
        !           995:  * searches for first history event containing the str
        !           996:  */
        !           997: int
        !           998: history_search(str, direction)
        !           999:        const char     *str;
        !          1000:        int             direction;
        !          1001: {
        !          1002:        return _history_search_gen(str, direction, -1);
        !          1003: }
        !          1004:
        !          1005: /*
        !          1006:  * searches for first history event beginning with str
        !          1007:  */
        !          1008: int
        !          1009: history_search_prefix(str, direction)
        !          1010:        const char     *str;
        !          1011:        int             direction;
        !          1012: {
        !          1013:        return _history_search_gen(str, direction, 0);
        !          1014: }
        !          1015:
        !          1016: /*
        !          1017:  * search for event in history containing str, starting at offset
        !          1018:  * abs(pos); continue backward, if pos<0, forward otherwise
        !          1019:  */
        !          1020: int
        !          1021: history_search_pos(str, direction, pos)
        !          1022:        const char     *str;
        !          1023:        int             direction, pos;
        !          1024: {
        !          1025:        HistEvent       ev;
        !          1026:        int             curr_num, off;
        !          1027:
        !          1028:        off = (pos > 0) ? pos : -pos;
        !          1029:        pos = (pos > 0) ? 1 : -1;
        !          1030:
        !          1031:        if (history(h, &ev, H_CURR) != 0)
        !          1032:                return -1;
        !          1033:        curr_num = ev.num;
        !          1034:
        !          1035:        if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0)
        !          1036:                return -1;
        !          1037:
        !          1038:
        !          1039:        for (;;) {
        !          1040:                if (strstr(ev.str, str))
        !          1041:                        return off;
        !          1042:                if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0)
        !          1043:                        break;
        !          1044:        }
        !          1045:
        !          1046:        /* set "current" pointer back to previous state */
        !          1047:        history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
        !          1048:
        !          1049:        return -1;
        !          1050: }
        !          1051:
        !          1052:
        !          1053: /********************************/
        !          1054: /* completition functions       */
        !          1055:
        !          1056: /*
        !          1057:  * does tilde expansion of strings of type ``~user/foo''
        !          1058:  * if ``user'' isn't valid user name or ``txt'' doesn't start
        !          1059:  * w/ '~', returns pointer to strdup()ed copy of ``txt''
        !          1060:  *
        !          1061:  * it's callers's responsibility to free() returned string
        !          1062:  */
        !          1063: char           *
        !          1064: tilde_expand(txt)
        !          1065:        const char     *txt;
        !          1066: {
        !          1067:        struct passwd  *pass;
        !          1068:        char           *temp;
        !          1069:        size_t          len = 0;
        !          1070:
        !          1071:        if (txt[0] != '~')
        !          1072:                return strdup(txt);
        !          1073:
        !          1074:        temp = strchr(txt + 1, '/');
        !          1075:        if (temp == NULL)
        !          1076:                temp = strdup(txt + 1);
        !          1077:        else {
        !          1078:                len = temp - txt + 1;   /* text until string after slash */
        !          1079:                temp = malloc(len);
        !          1080:                (void)strncpy(temp, txt + 1, len - 2);
        !          1081:                temp[len - 2] = '\0';
        !          1082:        }
        !          1083:        pass = getpwnam(temp);
        !          1084:        free(temp);             /* value no more needed */
        !          1085:        if (pass == NULL)
        !          1086:                return strdup(txt);
        !          1087:
        !          1088:        /* update pointer txt to point at string immedially following */
        !          1089:        /* first slash */
        !          1090:        txt += len;
        !          1091:
        !          1092:        temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);
        !          1093:        (void)sprintf(temp, "%s/%s", pass->pw_dir, txt);
        !          1094:
        !          1095:        return temp;
        !          1096: }
        !          1097:
        !          1098: /*
        !          1099:  * return first found file name starting by the ``text'' or NULL if no
        !          1100:  * such file can be found
        !          1101:  * value of ``state'' is ignored
        !          1102:  *
        !          1103:  * it's caller's responsibility to free returned string
        !          1104:  */
        !          1105: char           *
        !          1106: filename_completion_function(text, state)
        !          1107:        const char     *text;
        !          1108:        int             state;
        !          1109: {
        !          1110:        static DIR     *dir = NULL;
        !          1111:        static char    *filename = NULL, *dirname = NULL;
        !          1112:        static size_t   filename_len = 0;
        !          1113:        struct dirent  *entry;
        !          1114:        char           *temp;
        !          1115:        size_t          len;
        !          1116:
        !          1117:        if (state == 0 || dir == NULL) {
        !          1118:                if (dir != NULL) {
        !          1119:                        closedir(dir);
        !          1120:                        dir = NULL;
        !          1121:                }
        !          1122:                temp = strrchr(text, '/');
        !          1123:                if (temp) {
        !          1124:                        temp++;
        !          1125:                        filename = realloc(filename, strlen(temp) + 1);
        !          1126:                        (void)strcpy(filename, temp);
        !          1127:                        len = temp - text;      /* including last slash */
        !          1128:                        dirname = realloc(dirname, len + 1);
        !          1129:                        (void)strncpy(dirname, text, len);
        !          1130:                        dirname[len] = '\0';
        !          1131:                } else {
        !          1132:                        filename = strdup(text);
        !          1133:                        dirname = NULL;
        !          1134:                }
        !          1135:
        !          1136:                /* support for ``~user'' syntax */
        !          1137:                if (dirname && *dirname == '~') {
        !          1138:                        temp = tilde_expand(dirname);
        !          1139:                        dirname = realloc(dirname, strlen(temp) + 1);
        !          1140:                        (void)strcpy(dirname, temp);    /* safe */
        !          1141:                        free(temp);     /* no more needed */
        !          1142:                }
        !          1143:                /* will be used in cycle */
        !          1144:                filename_len = strlen(filename);
        !          1145:                if (filename_len == 0)
        !          1146:                        return NULL;    /* no expansion possible */
        !          1147:
        !          1148:                dir = opendir(dirname ? dirname : ".");
        !          1149:                if (!dir)
        !          1150:                        return NULL;    /* cannot open the directory */
        !          1151:        }
        !          1152:        /* find the match */
        !          1153:        while ((entry = readdir(dir))) {
        !          1154:                /* otherwise, get first entry where first */
        !          1155:                /* filename_len characters are equal      */
        !          1156:                if (entry->d_name[0] == filename[0]
        !          1157:                    && entry->d_namlen >= filename_len
        !          1158:                    && strncmp(entry->d_name, filename,
        !          1159:                               filename_len) == 0)
        !          1160:                        break;
        !          1161:        }
        !          1162:
        !          1163:        if (entry) {            /* match found */
        !          1164:
        !          1165:                struct stat     stbuf;
        !          1166:                len = entry->d_namlen +
        !          1167:                        ((dirname) ? strlen(dirname) : 0) + 1 + 1;
        !          1168:                temp = malloc(len);
        !          1169:                (void)sprintf(temp, "%s%s",
        !          1170:                        dirname ? dirname : "", entry->d_name); /* safe */
        !          1171:
        !          1172:                /* test, if it's directory */
        !          1173:                if (stat(temp, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
        !          1174:                        strcat(temp, "/");      /* safe */
        !          1175:        } else
        !          1176:                temp = NULL;
        !          1177:
        !          1178:        return temp;
        !          1179: }
        !          1180:
        !          1181: /*
        !          1182:  * a completion generator for usernames; returns _first_ username
        !          1183:  * which starts with supplied text
        !          1184:  * text contains a partial username preceded by random character
        !          1185:  * (usually '~'); state is ignored
        !          1186:  * it's callers responsibility to free returned value
        !          1187:  */
        !          1188: char           *
        !          1189: username_completion_function(text, state)
        !          1190:        const char     *text;
        !          1191:        int             state;
        !          1192: {
        !          1193:        struct passwd  *pwd;
        !          1194:
        !          1195:        if (text[0] == '\0')
        !          1196:                return NULL;
        !          1197:
        !          1198:        if (*text == '~')
        !          1199:                text++;
        !          1200:
        !          1201:        if (state == 0)
        !          1202:                setpwent();
        !          1203:
        !          1204:        while ((pwd = getpwent()) && text[0] == pwd->pw_name[0]
        !          1205:               && strcmp(text, pwd->pw_name) == 0);
        !          1206:
        !          1207:        if (pwd == NULL) {
        !          1208:                endpwent();
        !          1209:                return NULL;
        !          1210:        }
        !          1211:        return strdup(pwd->pw_name);
        !          1212: }
        !          1213:
        !          1214: /*
        !          1215:  * el-compatible wrapper around rl_complete; needed for key binding
        !          1216:  */
        !          1217: static unsigned char
        !          1218: _el_rl_complete(el, ch)
        !          1219:        EditLine       *el;
        !          1220:        int             ch;
        !          1221: {
        !          1222:        return (unsigned char) rl_complete(0, ch);
        !          1223: }
        !          1224:
        !          1225: /*
        !          1226:  * returns list of completitions for text given
        !          1227:  */
        !          1228: char          **
        !          1229: completion_matches(text, genfunc)
        !          1230:        const char     *text;
        !          1231:        CPFunction     *genfunc;
        !          1232: {
        !          1233:        char          **match_list = NULL, *retstr, *prevstr;
        !          1234:        size_t          matches, math_list_len, max_equal, len, which,
        !          1235:                        i;
        !          1236:
        !          1237:        if (h == NULL || e == NULL)
        !          1238:                rl_initialize();
        !          1239:
        !          1240:        matches = 0;
        !          1241:        math_list_len = 1;
        !          1242:        while ((retstr = (*genfunc) (text, matches))) {
        !          1243:                if (matches + 1 >= math_list_len) {
        !          1244:                        math_list_len <<= 1;
        !          1245:                        match_list = realloc(match_list,
        !          1246:                            math_list_len * sizeof(char *));
        !          1247:                }
        !          1248:                match_list[++matches] = retstr;
        !          1249:        }
        !          1250:
        !          1251:        if (!match_list)
        !          1252:                return (char **) NULL;  /* nothing found */
        !          1253:
        !          1254:        /* find least denominator and insert it to match_list[0] */
        !          1255:        which = 2;
        !          1256:        prevstr = match_list[1];
        !          1257:        len = max_equal = strlen(prevstr);
        !          1258:        for (; which < matches; which++) {
        !          1259:                for (i = 0; i < max_equal &&
        !          1260:                    prevstr[i] == match_list[which][i]; i++)
        !          1261:                        continue;
        !          1262:                max_equal = i;
        !          1263:        }
        !          1264:
        !          1265:        retstr = malloc(max_equal + 1);
        !          1266:        (void)strncpy(retstr, match_list[1], max_equal);
        !          1267:        retstr[max_equal] = '\0';
        !          1268:        match_list[0] = retstr;
        !          1269:
        !          1270:        /* add NULL as last pointer to the array */
        !          1271:        if (matches + 1 >= math_list_len)
        !          1272:                match_list = realloc(match_list,
        !          1273:                    (math_list_len + 1) * sizeof(char *));
        !          1274:        match_list[matches + 1] = (char *) NULL;
        !          1275:
        !          1276:        return match_list;
        !          1277: }
        !          1278:
        !          1279: /*
        !          1280:  * called by rl_complete()
        !          1281:  */
        !          1282: static int
        !          1283: rl_complete_internal(what_to_do)
        !          1284:        int             what_to_do;
        !          1285: {
        !          1286:        CPFunction     *complet_func;
        !          1287:        const LineInfo *li;
        !          1288:        char           *temp, *temp2, **arr;
        !          1289:        int             len;
        !          1290:
        !          1291:        if (h == NULL || e == NULL)
        !          1292:                rl_initialize();
        !          1293:
        !          1294:        complet_func = rl_completion_entry_function;
        !          1295:        if (!complet_func)
        !          1296:                complet_func = filename_completion_function;
        !          1297:
        !          1298:        li = el_line(e);
        !          1299:        temp = (char *) li->cursor;
        !          1300:        while (temp > li->buffer &&
        !          1301:            !strchr(rl_basic_word_break_characters, *(temp - 1)))
        !          1302:                temp--;
        !          1303:
        !          1304:        len = li->cursor - temp;
        !          1305:        temp2 = alloca(len + 1);
        !          1306:        (void)strncpy(temp2, temp, len);
        !          1307:        temp = temp2;
        !          1308:        temp[len] = '\0';
        !          1309:
        !          1310:        /* these can be used by function called in completion_matches() */
        !          1311:        /* or (*rl_attempted_completion_function)() */
        !          1312:        rl_point = li->cursor - li->buffer;
        !          1313:        rl_end = li->lastchar - li->buffer;
        !          1314:
        !          1315:        if (!rl_attempted_completion_function)
        !          1316:                arr = completion_matches(temp, complet_func);
        !          1317:        else {
        !          1318:                int             end = li->cursor - li->buffer;
        !          1319:                arr = (*rl_attempted_completion_function) (temp,
        !          1320:                                                           end - len, end);
        !          1321:        }
        !          1322:        free(temp);             /* no more needed */
        !          1323:
        !          1324:        if (arr) {
        !          1325:                int             i;
        !          1326:
        !          1327:                el_deletestr(e, len);
        !          1328:                el_insertstr(e, arr[0]);
        !          1329:                if (strcmp(arr[0], arr[1]) == 0) {
        !          1330:                        /* lcd is valid object, so add a space to mark it */
        !          1331:                        /* in case of filename completition, add a space  */
        !          1332:                        /* only if object found is not directory          */
        !          1333:                        int             len = strlen(arr[0]);
        !          1334:                        if (complet_func != filename_completion_function
        !          1335:                            || (len > 0 && (arr[0])[len - 1] != '/'))
        !          1336:                                el_insertstr(e, " ");
        !          1337:                } else
        !          1338:                        /* lcd is not a valid object - further specification */
        !          1339:                        /* is needed */
        !          1340:                        term_beep(e);
        !          1341:
        !          1342:                /* free elements of array and the array itself */
        !          1343:                for (i = 0; arr[i]; i++)
        !          1344:                        free(arr[i]);
        !          1345:                free(arr), arr = NULL;
        !          1346:
        !          1347:                return CC_REFRESH;
        !          1348:        }
        !          1349:        return CC_NORM;
        !          1350: }
        !          1351:
        !          1352: /*
        !          1353:  * complete word at current point
        !          1354:  */
        !          1355: int
        !          1356: rl_complete(ignore, invoking_key)
        !          1357:        int             ignore, invoking_key;
        !          1358: {
        !          1359:        if (h == NULL || e == NULL)
        !          1360:                rl_initialize();
        !          1361:
        !          1362:        if (rl_inhibit_completion) {
        !          1363:                rl_insert(ignore, invoking_key);
        !          1364:                return CC_REFRESH;
        !          1365:        } else
        !          1366:                return rl_complete_internal(invoking_key);
        !          1367:
        !          1368:        return CC_REFRESH;
        !          1369: }
        !          1370:
        !          1371: /*
        !          1372:  * misc other functions
        !          1373:  */
        !          1374:
        !          1375: /*
        !          1376:  * bind key c to readline-type function func
        !          1377:  */
        !          1378: int
        !          1379: rl_bind_key(c, func)
        !          1380:        int             c;
        !          1381:        int func        __P((int, int));
        !          1382: {
        !          1383:        int             retval = -1;
        !          1384:
        !          1385:        if (h == NULL || e == NULL)
        !          1386:                rl_initialize();
        !          1387:
        !          1388:        if (func == rl_insert) {
        !          1389:                /* XXX notice there is no range checking of ``c'' */
        !          1390:                e->el_map.key[c] = ED_INSERT;
        !          1391:                retval = 0;
        !          1392:        }
        !          1393:        return retval;
        !          1394: }
        !          1395:
        !          1396: /*
        !          1397:  * read one key from input - handles chars pushed back
        !          1398:  * to input stream also
        !          1399:  */
        !          1400: int
        !          1401: rl_read_key()
        !          1402: {
        !          1403:        char            fooarr[2 * sizeof(int)];
        !          1404:
        !          1405:        if (e == NULL || h == NULL)
        !          1406:                rl_initialize();
        !          1407:
        !          1408:        return el_getc(e, fooarr);
        !          1409: }
        !          1410:
        !          1411: /*
        !          1412:  * reset the terminal
        !          1413:  */
        !          1414: void
        !          1415: rl_reset_terminal(p)
        !          1416:        const char     *p;
        !          1417: {
        !          1418:        if (h == NULL || e == NULL)
        !          1419:                rl_initialize();
        !          1420:        el_reset(e);
        !          1421: }
        !          1422:
        !          1423: /*
        !          1424:  * insert character ``c'' back into input stream, ``count'' times
        !          1425:  */
        !          1426: int
        !          1427: rl_insert(count, c)
        !          1428:        int             count, c;
        !          1429: {
        !          1430:        char            arr[2];
        !          1431:
        !          1432:        if (h == NULL || e == NULL)
        !          1433:                rl_initialize();
        !          1434:
        !          1435:        /* XXX - int -> char conversion can lose on multichars */
        !          1436:        arr[0] = c;
        !          1437:        arr[1] = '\0';
        !          1438:
        !          1439:        for (; count > 0; count--)
        !          1440:                el_push(e, arr);
        !          1441:
        !          1442:        return 0;
        !          1443: }

CVSweb <webmaster@jp.NetBSD.org>