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

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