[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.11

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

CVSweb <webmaster@jp.NetBSD.org>