[BACK]Return to decode.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/decode.c, Revision 1.1.1.1

1.1       etheisen    1: /*
                      2:  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice in the documentation and/or other materials provided with
                     12:  *    the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
                     15:  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     17:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
                     18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     19:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
                     20:  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
                     21:  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     22:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
                     23:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
                     24:  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27:
                     28: /*
                     29:  * Routines to decode user commands.
                     30:  *
                     31:  * This is all table driven.
                     32:  * A command table is a sequence of command descriptors.
                     33:  * Each command descriptor is a sequence of bytes with the following format:
                     34:  *     <c1><c2>...<cN><0><action>
                     35:  * The characters c1,c2,...,cN are the command string; that is,
                     36:  * the characters which the user must type.
                     37:  * It is terminated by a null <0> byte.
                     38:  * The byte after the null byte is the action code associated
                     39:  * with the command string.
                     40:  * If an action byte is OR-ed with A_EXTRA, this indicates
                     41:  * that the option byte is followed by an extra string.
                     42:  *
                     43:  * There may be many command tables.
                     44:  * The first (default) table is built-in.
                     45:  * Other tables are read in from "lesskey" files.
                     46:  * All the tables are linked together and are searched in order.
                     47:  */
                     48:
                     49: #include "less.h"
                     50: #include "cmd.h"
                     51: #include "lesskey.h"
                     52:
                     53: extern int erase_char, kill_char;
                     54:
                     55: /*
                     56:  * Command table is ordered roughly according to expected
                     57:  * frequency of use, so the common commands are near the beginning.
                     58:  */
                     59: static unsigned char cmdtable[] =
                     60: {
                     61:        '\r',0,                         A_F_LINE,
                     62:        '\n',0,                         A_F_LINE,
                     63:        'e',0,                          A_F_LINE,
                     64:        'j',0,                          A_F_LINE,
                     65:        CONTROL('E'),0,                 A_F_LINE,
                     66:        CONTROL('N'),0,                 A_F_LINE,
                     67:        'k',0,                          A_B_LINE,
                     68:        'y',0,                          A_B_LINE,
                     69:        CONTROL('Y'),0,                 A_B_LINE,
                     70:        CONTROL('K'),0,                 A_B_LINE,
                     71:        CONTROL('P'),0,                 A_B_LINE,
                     72:        'J',0,                          A_FF_LINE,
                     73:        'K',0,                          A_BF_LINE,
                     74:        'Y',0,                          A_BF_LINE,
                     75:        'd',0,                          A_F_SCROLL,
                     76:        CONTROL('D'),0,                 A_F_SCROLL,
                     77:        'u',0,                          A_B_SCROLL,
                     78:        CONTROL('U'),0,                 A_B_SCROLL,
                     79:        ' ',0,                          A_F_SCREEN,
                     80:        'f',0,                          A_F_SCREEN,
                     81:        CONTROL('F'),0,                 A_F_SCREEN,
                     82:        CONTROL('V'),0,                 A_F_SCREEN,
                     83:        'b',0,                          A_B_SCREEN,
                     84:        CONTROL('B'),0,                 A_B_SCREEN,
                     85:        ESC,'v',0,                      A_B_SCREEN,
                     86:        'z',0,                          A_F_WINDOW,
                     87:        'w',0,                          A_B_WINDOW,
                     88:        'F',0,                          A_F_FOREVER,
                     89:        'R',0,                          A_FREPAINT,
                     90:        'r',0,                          A_REPAINT,
                     91:        CONTROL('R'),0,                 A_REPAINT,
                     92:        CONTROL('L'),0,                 A_REPAINT,
                     93:        ESC,'u',0,                      A_UNDO_SEARCH,
                     94:        'g',0,                          A_GOLINE,
                     95:        '<',0,                          A_GOLINE,
                     96:        ESC,'<',0,                      A_GOLINE,
                     97:        'p',0,                          A_PERCENT,
                     98:        '%',0,                          A_PERCENT,
                     99:        '{',0,                          A_F_BRACKET|A_EXTRA,    '{','}',0,
                    100:        '}',0,                          A_B_BRACKET|A_EXTRA,    '{','}',0,
                    101:        '(',0,                          A_F_BRACKET|A_EXTRA,    '(',')',0,
                    102:        ')',0,                          A_B_BRACKET|A_EXTRA,    '(',')',0,
                    103:        '[',0,                          A_F_BRACKET|A_EXTRA,    '[',']',0,
                    104:        ']',0,                          A_B_BRACKET|A_EXTRA,    '[',']',0,
                    105:        ESC,CONTROL('F'),0,             A_F_BRACKET,
                    106:        ESC,CONTROL('B'),0,             A_B_BRACKET,
                    107:        'G',0,                          A_GOEND,
                    108:        ESC,'>',0,                      A_GOEND,
                    109:        '>',0,                          A_GOEND,
                    110:        'P',0,                          A_GOPOS,
                    111:
                    112:        '0',0,                          A_DIGIT,
                    113:        '1',0,                          A_DIGIT,
                    114:        '2',0,                          A_DIGIT,
                    115:        '3',0,                          A_DIGIT,
                    116:        '4',0,                          A_DIGIT,
                    117:        '5',0,                          A_DIGIT,
                    118:        '6',0,                          A_DIGIT,
                    119:        '7',0,                          A_DIGIT,
                    120:        '8',0,                          A_DIGIT,
                    121:        '9',0,                          A_DIGIT,
                    122:
                    123:        '=',0,                          A_STAT,
                    124:        CONTROL('G'),0,                 A_STAT,
                    125:        ':','f',0,                      A_STAT,
                    126:        '/',0,                          A_F_SEARCH,
                    127:        '?',0,                          A_B_SEARCH,
                    128:        ESC,'/',0,                      A_F_SEARCH|A_EXTRA,     '*',0,
                    129:        ESC,'?',0,                      A_B_SEARCH|A_EXTRA,     '*',0,
                    130:        'n',0,                          A_AGAIN_SEARCH,
                    131:        ESC,'n',0,                      A_T_AGAIN_SEARCH,
                    132:        'N',0,                          A_REVERSE_SEARCH,
                    133:        ESC,'N',0,                      A_T_REVERSE_SEARCH,
                    134:        'm',0,                          A_SETMARK,
                    135:        '\'',0,                         A_GOMARK,
                    136:        CONTROL('X'),CONTROL('X'),0,    A_GOMARK,
                    137:        'E',0,                          A_EXAMINE,
                    138:        ':','e',0,                      A_EXAMINE,
                    139:        CONTROL('X'),CONTROL('V'),0,    A_EXAMINE,
                    140:        ':','n',0,                      A_NEXT_FILE,
                    141:        ':','p',0,                      A_PREV_FILE,
                    142:        ':','x',0,                      A_INDEX_FILE,
                    143:        '-',0,                          A_OPT_TOGGLE,
                    144:        ':','t',0,                      A_OPT_TOGGLE|A_EXTRA,   't',0,
                    145:        's',0,                          A_OPT_TOGGLE|A_EXTRA,   'o',0,
                    146:        '_',0,                          A_DISP_OPTION,
                    147:        '|',0,                          A_PIPE,
                    148:        'v',0,                          A_VISUAL,
                    149:        '!',0,                          A_SHELL,
                    150:        '+',0,                          A_FIRSTCMD,
                    151:
                    152:        'H',0,                          A_HELP,
                    153:        'h',0,                          A_HELP,
                    154:        'V',0,                          A_VERSION,
                    155:        'q',0,                          A_QUIT,
                    156:        ':','q',0,                      A_QUIT,
                    157:        ':','Q',0,                      A_QUIT,
                    158:        'Z','Z',0,                      A_QUIT
                    159: };
                    160:
                    161: static unsigned char edittable[] =
                    162: {
                    163:        '\t',0,                 EC_F_COMPLETE,  /* TAB */
                    164:        '\17',0,                EC_B_COMPLETE,  /* BACKTAB */
                    165:        '\14',0,                EC_EXPAND,      /* CTRL-L */
                    166:        CONTROL('V'),0,         EC_LITERAL,     /* BACKSLASH */
                    167:        CONTROL('A'),0,         EC_LITERAL,     /* BACKSLASH */
                    168:        ESC,'l',0,              EC_RIGHT,       /* ESC l */
                    169:        ESC,'h',0,              EC_LEFT,        /* ESC h */
                    170:        ESC,'b',0,              EC_W_LEFT,      /* ESC b */
                    171:        ESC,'w',0,              EC_W_RIGHT,     /* ESC w */
                    172:        ESC,'i',0,              EC_INSERT,      /* ESC i */
                    173:        ESC,'x',0,              EC_DELETE,      /* ESC x */
                    174:        ESC,'X',0,              EC_W_DELETE,    /* ESC X */
                    175:        ESC,'\b',0,             EC_W_BACKSPACE, /* ESC BACKSPACE */
                    176:        ESC,'0',0,              EC_HOME,        /* ESC 0 */
                    177:        ESC,'$',0,              EC_END,         /* ESC $ */
                    178:        ESC,'k',0,              EC_UP,          /* ESC k */
                    179:        ESC,'j',0,              EC_DOWN,        /* ESC j */
                    180:        ESC,'\t',0,             EC_B_COMPLETE   /* ESC TAB */
                    181: };
                    182:
                    183: /*
                    184:  * Structure to support a list of command tables.
                    185:  */
                    186: struct tablelist
                    187: {
                    188:        struct tablelist *t_next;
                    189:        char *t_start;
                    190:        char *t_end;
                    191: };
                    192:
                    193: /*
                    194:  * List of command tables and list of line-edit tables.
                    195:  */
                    196: static struct tablelist *list_fcmd_tables = NULL;
                    197: static struct tablelist *list_ecmd_tables = NULL;
                    198:
                    199:
                    200: /*
                    201:  * Initialize the command lists.
                    202:  */
                    203:        public void
                    204: init_cmds()
                    205: {
                    206:        /*
                    207:         * Add the default command tables.
                    208:         */
                    209:        add_fcmd_table((char*)cmdtable, sizeof(cmdtable));
                    210:        add_ecmd_table((char*)edittable, sizeof(edittable));
                    211:        get_editkeys();
                    212: #if USERFILE
                    213:        /*
                    214:         * Try to add the tables in the standard lesskey file "$HOME/.less".
                    215:         */
                    216:        add_hometable();
                    217: #endif
                    218: }
                    219:
                    220: /*
                    221:  *
                    222:  */
                    223:        static int
                    224: add_cmd_table(tlist, buf, len)
                    225:        struct tablelist **tlist;
                    226:        char *buf;
                    227:        int len;
                    228: {
                    229:        register struct tablelist *t;
                    230:
                    231:        if (len == 0)
                    232:                return (0);
                    233:        /*
                    234:         * Allocate a tablelist structure, initialize it,
                    235:         * and link it into the list of tables.
                    236:         */
                    237:        if ((t = (struct tablelist *)
                    238:                        calloc(1, sizeof(struct tablelist))) == NULL)
                    239:        {
                    240:                return (-1);
                    241:        }
                    242:        t->t_start = buf;
                    243:        t->t_end = buf + len;
                    244:        t->t_next = *tlist;
                    245:        *tlist = t;
                    246:        return (0);
                    247: }
                    248:
                    249: /*
                    250:  * Add a command table.
                    251:  */
                    252:        public void
                    253: add_fcmd_table(buf, len)
                    254:        char *buf;
                    255:        int len;
                    256: {
                    257:        if (add_cmd_table(&list_fcmd_tables, buf, len) < 0)
                    258:                error("Warning: some commands disabled", NULL_PARG);
                    259: }
                    260:
                    261: /*
                    262:  * Add an editing command table.
                    263:  */
                    264:        public void
                    265: add_ecmd_table(buf, len)
                    266:        char *buf;
                    267:        int len;
                    268: {
                    269:        if (add_cmd_table(&list_ecmd_tables, buf, len) < 0)
                    270:                error("Warning: some edit commands disabled", NULL_PARG);
                    271: }
                    272:
                    273: /*
                    274:  * Search a single command table for the command string in cmd.
                    275:  */
                    276:        public int
                    277: cmd_search(cmd, table, endtable, sp)
                    278:        char *cmd;
                    279:        char *table;
                    280:        char *endtable;
                    281:        char **sp;
                    282: {
                    283:        register char *p;
                    284:        register char *q;
                    285:        register int a;
                    286:
                    287:        for (p = table, q = cmd;  p < endtable;  p++, q++)
                    288:        {
                    289:                if (*p == *q)
                    290:                {
                    291:                        /*
                    292:                         * Current characters match.
                    293:                         * If we're at the end of the string, we've found it.
                    294:                         * Return the action code, which is the character
                    295:                         * after the null at the end of the string
                    296:                         * in the command table.
                    297:                         */
                    298:                        if (*p == '\0')
                    299:                        {
                    300:                                a = *++p & 0377;
                    301:                                if (a == A_END_LIST)
                    302:                                {
                    303:                                        /*
                    304:                                         * We get here only if the original
                    305:                                         * cmd string passed in was empty ("").
                    306:                                         * I don't think that can happen,
                    307:                                         * but just in case ...
                    308:                                         */
                    309:                                        return (A_UINVALID);
                    310:                                }
                    311:                                /*
                    312:                                 * Check for an "extra" string.
                    313:                                 */
                    314:                                if (a & A_EXTRA)
                    315:                                {
                    316:                                        *sp = ++p;
                    317:                                        a &= ~A_EXTRA;
                    318:                                } else
                    319:                                        *sp = NULL;
                    320:                                return (a);
                    321:                        }
                    322:                } else if (*q == '\0')
                    323:                {
                    324:                        /*
                    325:                         * Hit the end of the user's command,
                    326:                         * but not the end of the string in the command table.
                    327:                         * The user's command is incomplete.
                    328:                         */
                    329:                        return (A_PREFIX);
                    330:                } else
                    331:                {
                    332:                        /*
                    333:                         * Not a match.
                    334:                         * Skip ahead to the next command in the
                    335:                         * command table, and reset the pointer
                    336:                         * to the beginning of the user's command.
                    337:                         */
                    338:                        if (*p == '\0' && p[1] == A_END_LIST)
                    339:                        {
                    340:                                /*
                    341:                                 * A_END_LIST is a special marker that tells
                    342:                                 * us to abort the cmd search.
                    343:                                 */
                    344:                                return (A_UINVALID);
                    345:                        }
                    346:                        while (*p++ != '\0') ;
                    347:                        if (*p & A_EXTRA)
                    348:                                while (*++p != '\0') ;
                    349:                        q = cmd-1;
                    350:                }
                    351:        }
                    352:        /*
                    353:         * No match found in the entire command table.
                    354:         */
                    355:        return (A_INVALID);
                    356: }
                    357:
                    358: /*
                    359:  * Decode a command character and return the associated action.
                    360:  * The "extra" string, if any, is returned in sp.
                    361:  */
                    362:        static int
                    363: cmd_decode(tlist, cmd, sp)
                    364:        struct tablelist *tlist;
                    365:        char *cmd;
                    366:        char **sp;
                    367: {
                    368:        register struct tablelist *t;
                    369:        register int action = A_INVALID;
                    370:
                    371:        /*
                    372:         * Search thru all the command tables.
                    373:         * Stop when we find an action which is not A_INVALID.
                    374:         */
                    375:        for (t = tlist;  t != NULL;  t = t->t_next)
                    376:        {
                    377:                action = cmd_search(cmd, t->t_start, t->t_end, sp);
                    378:                if (action != A_INVALID)
                    379:                        break;
                    380:        }
                    381:        return (action);
                    382: }
                    383:
                    384: /*
                    385:  * Decode a command from the cmdtables list.
                    386:  */
                    387:        public int
                    388: fcmd_decode(cmd, sp)
                    389:        char *cmd;
                    390:        char **sp;
                    391: {
                    392:        return (cmd_decode(list_fcmd_tables, cmd, sp));
                    393: }
                    394:
                    395: /*
                    396:  * Decode a command from the edittables list.
                    397:  */
                    398:        public int
                    399: ecmd_decode(cmd, sp)
                    400:        char *cmd;
                    401:        char **sp;
                    402: {
                    403:        return (cmd_decode(list_ecmd_tables, cmd, sp));
                    404: }
                    405:
                    406: #if USERFILE
                    407:        static int
                    408: gint(sp)
                    409:        char **sp;
                    410: {
                    411:        int n;
                    412:
                    413:        n = *(*sp)++;
                    414:        n += *(*sp)++ * KRADIX;
                    415:        return (n);
                    416: }
                    417:
                    418:        static int
                    419: old_lesskey(buf, len)
                    420:        char *buf;
                    421:        int len;
                    422: {
                    423:        /*
                    424:         * Old-style lesskey file.
                    425:         * The file must end with either
                    426:         *     ...,cmd,0,action
                    427:         * or  ...,cmd,0,action|A_EXTRA,string,0
                    428:         * So the last byte or the second to last byte must be zero.
                    429:         */
                    430:        if (buf[len-1] != '\0' && buf[len-2] != '\0')
                    431:                return (-1);
                    432:        add_fcmd_table(buf, len);
                    433:        return (0);
                    434: }
                    435:
                    436:        static int
                    437: new_lesskey(buf, len)
                    438:        char *buf;
                    439:        int len;
                    440: {
                    441:        char *p;
                    442:        register int c;
                    443:        register int done;
                    444:        register int n;
                    445:
                    446:        /*
                    447:         * New-style lesskey file.
                    448:         * Extract the pieces.
                    449:         */
                    450:        if (buf[len-3] != C0_END_LESSKEY_MAGIC ||
                    451:            buf[len-2] != C1_END_LESSKEY_MAGIC ||
                    452:            buf[len-1] != C2_END_LESSKEY_MAGIC)
                    453:                return (-1);
                    454:        p = buf + 4;
                    455:        done = 0;
                    456:        while (!done)
                    457:        {
                    458:                c = *p++;
                    459:                switch (c)
                    460:                {
                    461:                case CMD_SECTION:
                    462:                        n = gint(&p);
                    463:                        add_fcmd_table(p, n);
                    464:                        p += n;
                    465:                        break;
                    466:                case EDIT_SECTION:
                    467:                        n = gint(&p);
                    468:                        add_ecmd_table(p, n);
                    469:                        p += n;
                    470:                        break;
                    471:                case END_SECTION:
                    472:                        done = 1;
                    473:                        break;
                    474:                default:
                    475:                        free(buf);
                    476:                        return (-1);
                    477:                }
                    478:        }
                    479:        return (0);
                    480: }
                    481:
                    482: /*
                    483:  * Set up a user command table, based on a "lesskey" file.
                    484:  */
                    485:        public int
                    486: lesskey(filename)
                    487:        char *filename;
                    488: {
                    489:        register char *buf;
                    490:        register POSITION len;
                    491:        register long n;
                    492:        register int f;
                    493:
                    494:        /*
                    495:         * Try to open the lesskey file.
                    496:         */
                    497:        f = open(filename, OPEN_READ);
                    498:        if (f < 0)
                    499:                return (1);
                    500:
                    501:        /*
                    502:         * Read the file into a buffer.
                    503:         * We first figure out the size of the file and allocate space for it.
                    504:         * {{ Minimal error checking is done here.
                    505:         *    A garbage .less file will produce strange results.
                    506:         *    To avoid a large amount of error checking code here, we
                    507:         *    rely on the lesskey program to generate a good .less file. }}
                    508:         */
                    509:        len = filesize(f);
                    510:        if (len == NULL_POSITION || len < 3)
                    511:        {
                    512:                /*
                    513:                 * Bad file (valid file must have at least 3 chars).
                    514:                 */
                    515:                close(f);
                    516:                return (-1);
                    517:        }
                    518:        if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL)
                    519:        {
                    520:                close(f);
                    521:                return (-1);
                    522:        }
                    523:        if (lseek(f, (off_t)0, 0) == BAD_LSEEK)
                    524:        {
                    525:                free(buf);
                    526:                close(f);
                    527:                return (-1);
                    528:        }
                    529:        n = read(f, buf, (unsigned int) len);
                    530:        close(f);
                    531:        if (n != len)
                    532:        {
                    533:                free(buf);
                    534:                return (-1);
                    535:        }
                    536:
                    537:        /*
                    538:         * Figure out if this is an old-style (before version 241)
                    539:         * or new-style lesskey file format.
                    540:         */
                    541:        if (buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC ||
                    542:            buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC)
                    543:                return (old_lesskey(buf, (int)len));
                    544:        return (new_lesskey(buf, (int)len));
                    545: }
                    546:
                    547: /*
                    548:  * Add the standard lesskey file "$HOME/.less"
                    549:  */
                    550:        public void
                    551: add_hometable()
                    552: {
                    553:        char *filename;
                    554:        PARG parg;
                    555:
                    556:        filename = homefile(LESSKEYFILE);
                    557:        if (filename == NULL)
                    558:                return;
                    559:        if (lesskey(filename) < 0)
                    560:        {
                    561:                parg.p_string = filename;
                    562:                error("Cannot use lesskey file \"%s\"", &parg);
                    563:        }
                    564:        free(filename);
                    565: }
                    566: #endif
                    567:
                    568: /*
                    569:  * See if a char is a special line-editing command.
                    570:  */
                    571:        public int
                    572: editchar(c, flags)
                    573:        int c;
                    574:        int flags;
                    575: {
                    576:        int action;
                    577:        int nch;
                    578:        char *s;
                    579:        char usercmd[MAX_CMDLEN+1];
                    580:
                    581:        /*
                    582:         * An editing character could actually be a sequence of characters;
                    583:         * for example, an escape sequence sent by pressing the uparrow key.
                    584:         * To match the editing string, we use the command decoder
                    585:         * but give it the edit-commands command table
                    586:         * This table is constructed to match the user's keyboard.
                    587:         */
                    588:        if (c == erase_char)
                    589:                return (EC_BACKSPACE);
                    590:        if (c == kill_char)
                    591:                return (EC_LINEKILL);
                    592:
                    593:        /*
                    594:         * Collect characters in a buffer.
                    595:         * Start with the one we have, and get more if we need them.
                    596:         */
                    597:        nch = 0;
                    598:        do {
                    599:                if (nch > 0)
                    600:                        c = getcc();
                    601:                usercmd[nch] = c;
                    602:                usercmd[nch+1] = '\0';
                    603:                nch++;
                    604:                action = ecmd_decode(usercmd, &s);
                    605:        } while (action == A_PREFIX);
                    606:
                    607:        if (flags & EC_NOHISTORY)
                    608:        {
                    609:                /*
                    610:                 * The caller says there is no history list.
                    611:                 * Reject any history-manipulation action.
                    612:                 */
                    613:                switch (action)
                    614:                {
                    615:                case EC_UP:
                    616:                case EC_DOWN:
                    617:                        action = A_INVALID;
                    618:                        break;
                    619:                }
                    620:        }
                    621:        if (flags & EC_NOCOMPLETE)
                    622:        {
                    623:                /*
                    624:                 * The caller says we don't want any filename completion cmds.
                    625:                 * Reject them.
                    626:                 */
                    627:                switch (action)
                    628:                {
                    629:                case EC_F_COMPLETE:
                    630:                case EC_B_COMPLETE:
                    631:                case EC_EXPAND:
                    632:                        action = A_INVALID;
                    633:                        break;
                    634:                }
                    635:        }
                    636:        if ((flags & EC_PEEK) || action == A_INVALID)
                    637:        {
                    638:                /*
                    639:                 * We're just peeking, or we didn't understand the command.
                    640:                 * Unget all the characters we read in the loop above.
                    641:                 * This does NOT include the original character that was
                    642:                 * passed in as a parameter.
                    643:                 */
                    644:                while (nch > 1) {
                    645:                        ungetcc(usercmd[--nch]);
                    646:                }
                    647:        } else
                    648:        {
                    649:                if (s != NULL)
                    650:                        ungetsc(s);
                    651:        }
                    652:        return action;
                    653: }
                    654: