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

Annotation of src/usr.bin/less/cmdbuf.c, Revision 1.2

1.2     ! niklas      1: /*     $OpenBSD$       */
        !             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:  * Functions which manipulate the command buffer.
                     32:  * Used only by command() and related functions.
                     33:  */
                     34:
                     35: #include "less.h"
                     36: #include "cmd.h"
                     37:
                     38: extern int sc_width;
                     39:
                     40: static char cmdbuf[120];       /* Buffer for holding a multi-char command */
                     41: static int cmd_col;            /* Current column of the multi-char command */
                     42: static char *cp;               /* Pointer into cmdbuf */
                     43: static int literal;
                     44:
                     45: #if TAB_COMPLETE_FILENAME
                     46: static int cmd_complete();
                     47: /*
                     48:  * These variables are statics used by cmd_complete.
                     49:  */
                     50: static int in_completion = 0;
                     51: static char *tk_text;
                     52: static char *tk_original;
                     53: static char *tk_ipoint;
                     54: static char *tk_trial;
                     55: static struct textlist tk_tlist;
                     56: #endif
                     57:
                     58: #if CMD_HISTORY
                     59: /*
                     60:  * A mlist structure represents a command history.
                     61:  */
                     62: struct mlist
                     63: {
                     64:        struct mlist *next;
                     65:        struct mlist *prev;
                     66:        struct mlist *curr_mp;
                     67:        char *string;
                     68: };
                     69:
                     70: /*
                     71:  * These are the various command histories that exist.
                     72:  */
                     73: struct mlist mlist_search =
                     74:        { &mlist_search,  &mlist_search,  &mlist_search,  NULL };
                     75: public void *ml_search = (void *) &mlist_search;
                     76: struct mlist mlist_examine =
                     77:        { &mlist_examine, &mlist_examine, &mlist_examine, NULL };
                     78: public void *ml_examine = (void *) &mlist_examine;
                     79: #if SHELL_ESCAPE || PIPEC
                     80: struct mlist mlist_shell =
                     81:        { &mlist_shell,   &mlist_shell,   &mlist_shell,   NULL };
                     82: public void *ml_shell = (void *) &mlist_shell;
                     83: #endif /* SHELL_ESCAPE || PIPEC */
                     84:
                     85: /*
                     86:  * History for the current command.
                     87:  */
                     88: static struct mlist *curr_mlist = NULL;
                     89:
                     90: #endif /* CMD_HISTORY */
                     91:
                     92: /*
                     93:  * Reset command buffer (to empty).
                     94:  */
                     95:        public void
                     96: cmd_reset()
                     97: {
                     98:        cp = cmdbuf;
                     99:        *cp = '\0';
                    100:        cmd_col = 0;
                    101:        literal = 0;
                    102: }
                    103:
                    104: /*
                    105:  * How many characters are in the command buffer?
                    106:  */
                    107:        public int
                    108: len_cmdbuf()
                    109: {
                    110:        return (strlen(cmdbuf));
                    111: }
                    112:
                    113: /*
                    114:  * Backspace in the command buffer.
                    115:  * Delete the char to the left of the cursor.
                    116:  */
                    117:        static int
                    118: cmd_erase()
                    119: {
                    120:        register char *s;
                    121:        char *p;
                    122:        int col;
                    123:
                    124:        if (cp == cmdbuf)
                    125:        {
                    126:                /*
                    127:                 * Backspace past beginning of the buffer:
                    128:                 * this usually means abort the command.
                    129:                 */
                    130:                return (CC_QUIT);
                    131:        }
                    132:        /*
                    133:         * Back up the pointer.
                    134:         */
                    135:        --cp;
                    136:        /*
                    137:         * Remember the current cursor column and
                    138:         * set it back the width of the char being erased.
                    139:         */
                    140:        col = cmd_col;
                    141:        p = prchar(*cp);
                    142:        cmd_col -= strlen(p);
                    143:        /*
                    144:         * Shift left the buffer after the erased char.
                    145:         */
                    146:        for (s = cp;  *s != '\0';  s++)
                    147:                s[0] = s[1];
                    148:        /*
                    149:         * Back up the cursor to the position of the erased char,
                    150:         * clear the tail of the line,
                    151:         * and reprint the line after the erased char.
                    152:         */
                    153:        while (col > cmd_col)
                    154:        {
                    155:                putbs();
                    156:                col--;
                    157:        }
                    158:        clear_eol();
                    159:        for (s = cp;  *s != '\0';  s++)
                    160:        {
                    161:                p = prchar(*s);
                    162:                putstr(p);
                    163:                col += strlen(p);
                    164:        }
                    165:        /*
                    166:         * Back up the cursor again.
                    167:         */
                    168:        while (col > cmd_col)
                    169:        {
                    170:                putbs();
                    171:                col--;
                    172:        }
                    173:
                    174:        /*
                    175:         * This is rather weird.
                    176:         * We say that erasing the entire command string causes us
                    177:         * to abort the current command, BUT ONLY IF there is no history
                    178:         * for this type of command.  This causes commands like search (/)
                    179:         * and edit (:e) to stay active even if we erase the entire string,
                    180:         * but commands like <digit> and - go away when we erase the string.
                    181:         * (See same thing in cmd_kill.)
                    182:         */
                    183:        if (curr_mlist == NULL && cp == cmdbuf && *cp == '\0')
                    184:                return (CC_QUIT);
                    185:        return (CC_OK);
                    186: }
                    187:
                    188: /*
                    189:  * Delete the char under the cursor.
                    190:  */
                    191:        static int
                    192: cmd_delete()
                    193: {
                    194:        char *p;
                    195:
                    196:        if (*cp == '\0')
                    197:        {
                    198:                /*
                    199:                 * At end of string; there is no char under the cursor.
                    200:                 */
                    201:                return (CC_OK);
                    202:        }
                    203:        /*
                    204:         * Move right, then use cmd_erase.
                    205:         */
                    206:        p = prchar(*cp);
                    207:        cp++;
                    208:        putstr(p);
                    209:        cmd_col += strlen(p);
                    210:        cmd_erase();
                    211:        return (CC_OK);
                    212: }
                    213:
                    214: /*
                    215:  * Delete the "word" to the left of the cursor.
                    216:  */
                    217:        static int
                    218: cmd_werase()
                    219: {
                    220:        if (cp > cmdbuf && cp[-1] == ' ')
                    221:        {
                    222:                /*
                    223:                 * If the char left of cursor is a space,
                    224:                 * erase all the spaces left of cursor (to the first non-space).
                    225:                 */
                    226:                while (cp > cmdbuf && cp[-1] == ' ')
                    227:                        (void) cmd_erase();
                    228:        } else
                    229:        {
                    230:                /*
                    231:                 * If the char left of cursor is not a space,
                    232:                 * erase all the nonspaces left of cursor (the whole "word").
                    233:                 */
                    234:                while (cp > cmdbuf && cp[-1] != ' ')
                    235:                        (void) cmd_erase();
                    236:        }
                    237:        return (CC_OK);
                    238: }
                    239:
                    240: /*
                    241:  * Delete the "word" under the cursor.
                    242:  */
                    243:        static int
                    244: cmd_wdelete()
                    245: {
                    246:        if (*cp == ' ')
                    247:        {
                    248:                /*
                    249:                 * If the char under the cursor is a space,
                    250:                 * delete it and all the spaces right of cursor.
                    251:                 */
                    252:                while (*cp == ' ')
                    253:                        (void) cmd_delete();
                    254:        } else
                    255:        {
                    256:                /*
                    257:                 * If the char under the cursor is not a space,
                    258:                 * delete it and all nonspaces right of cursor (the whole word).
                    259:                 */
                    260:                while (*cp != ' ' && *cp != '\0')
                    261:                        (void) cmd_delete();
                    262:        }
                    263:        return (CC_OK);
                    264: }
                    265:
                    266: /*
                    267:  * Move cursor to start of command buffer.
                    268:  */
                    269:        static int
                    270: cmd_home()
                    271: {
                    272:        char *p;
                    273:
                    274:        /*
                    275:         * Back up until we hit start of buffer.
                    276:         */
                    277:        while (cp > cmdbuf)
                    278:        {
                    279:                cp--;
                    280:                p = prchar(*cp);
                    281:                cmd_col -= strlen(p);
                    282:                while (*p++ != '\0')
                    283:                        putbs();
                    284:        }
                    285:        return (CC_OK);
                    286: }
                    287:
                    288: /*
                    289:  * Delete all chars in the command buffer.
                    290:  */
                    291:        static int
                    292: cmd_kill()
                    293: {
                    294:        if (cmdbuf[0] == '\0')
                    295:        {
                    296:                /*
                    297:                 * Buffer is already empty; abort the current command.
                    298:                 */
                    299:                return (CC_QUIT);
                    300:        }
                    301:        (void) cmd_home();
                    302:        *cp = '\0';
                    303:        clear_eol();
                    304:        /*
                    305:         * Same weirdness as in cmd_erase.
                    306:         * If the current command has no history, abort the current command.
                    307:         */
                    308:        if (curr_mlist == NULL)
                    309:                return (CC_QUIT);
                    310:        return (CC_OK);
                    311: }
                    312:
                    313: /*
                    314:  * Move cursor right one character.
                    315:  */
                    316:        static int
                    317: cmd_right()
                    318: {
                    319:        char *p;
                    320:
                    321:        if (*cp == '\0')
                    322:        {
                    323:                /*
                    324:                 * Already at the end of the line.
                    325:                 */
                    326:                return (CC_OK);
                    327:        }
                    328:        p = prchar(*cp);
                    329:        cp++;
                    330:        putstr(p);
                    331:        cmd_col += strlen(p);
                    332:        return (CC_OK);
                    333: }
                    334:
                    335: /*
                    336:  * Move cursor left one character.
                    337:  */
                    338:        static int
                    339: cmd_left()
                    340: {
                    341:        char *p;
                    342:
                    343:        if (cp <= cmdbuf)
                    344:        {
                    345:                /* Already at the beginning of the line */
                    346:                return (CC_OK);
                    347:        }
                    348:        cp--;
                    349:        p = prchar(*cp);
                    350:        cmd_col -= strlen(p);
                    351:        while (*p++ != '\0')
                    352:                putbs();
                    353:        return (CC_OK);
                    354: }
                    355:
                    356: #if CMD_HISTORY
                    357: /*
                    358:  * Select an mlist structure to be the current command history.
                    359:  */
                    360:        public void
                    361: set_mlist(mlist)
                    362:        void *mlist;
                    363: {
                    364:        curr_mlist = (struct mlist *) mlist;
                    365: }
                    366:
                    367: /*
                    368:  * Move up or down in the currently selected command history list.
                    369:  */
                    370:        static int
                    371: cmd_updown(action)
                    372:        int action;
                    373: {
                    374:        char *p;
                    375:        char *s;
                    376:
                    377:        if (curr_mlist == NULL)
                    378:        {
                    379:                /*
                    380:                 * The current command has no history list.
                    381:                 */
                    382:                bell();
                    383:                return (CC_OK);
                    384:        }
                    385:        cmd_home();
                    386:        clear_eol();
                    387:        /*
                    388:         * Move curr_mp to the next/prev entry.
                    389:         */
                    390:        if (action == EC_UP)
                    391:                curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
                    392:        else
                    393:                curr_mlist->curr_mp = curr_mlist->curr_mp->next;
                    394:        /*
                    395:         * Copy the entry into cmdbuf and echo it on the screen.
                    396:         */
                    397:        s = curr_mlist->curr_mp->string;
                    398:        if (s == NULL)
                    399:                s = "";
                    400:        for (cp = cmdbuf;  *s != '\0';  s++, cp++)
                    401:        {
                    402:                *cp = *s;
                    403:                p = prchar(*cp);
                    404:                cmd_col += strlen(p);
                    405:                putstr(p);
                    406:        }
                    407:        *cp = '\0';
                    408:        return (CC_OK);
                    409: }
                    410:
                    411: /*
                    412:  * Accept the command in the command buffer.
                    413:  * Add it to the currently selected history list.
                    414:  */
                    415:        public void
                    416: cmd_accept()
                    417: {
                    418:        struct mlist *ml;
                    419:
                    420:        /*
                    421:         * Nothing to do if there is no currently selected history list.
                    422:         */
                    423:        if (curr_mlist == NULL)
                    424:                return;
                    425:        /*
                    426:         * Don't save a trivial command.
                    427:         */
                    428:        if (strlen(cmdbuf) == 0)
                    429:                return;
                    430:        /*
                    431:         * Don't save if a duplicate of a command which is already in the history.
                    432:         * But select the one already in the history to be current.
                    433:         */
                    434:        for (ml = curr_mlist->next;  ml != curr_mlist;  ml = ml->next)
                    435:        {
                    436:                if (strcmp(ml->string, cmdbuf) == 0)
                    437:                        break;
                    438:        }
                    439:        if (ml == curr_mlist)
                    440:        {
                    441:                /*
                    442:                 * Did not find command in history.
                    443:                 * Save the command and put it at the end of the history list.
                    444:                 */
                    445:                ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
                    446:                ml->string = save(cmdbuf);
                    447:                ml->next = curr_mlist;
                    448:                ml->prev = curr_mlist->prev;
                    449:                curr_mlist->prev->next = ml;
                    450:                curr_mlist->prev = ml;
                    451:        }
                    452:        /*
                    453:         * Point to the cmd just after the just-accepted command.
                    454:         * Thus, an UPARROW will always retrieve the previous command.
                    455:         */
                    456:        curr_mlist->curr_mp = ml->next;
                    457: }
                    458: #endif
                    459:
                    460: /*
                    461:  * Try to perform a line-edit function on the command buffer,
                    462:  * using a specified char as a line-editing command.
                    463:  * Returns:
                    464:  *     CC_PASS The char does not invoke a line edit function.
                    465:  *     CC_OK   Line edit function done.
                    466:  *     CC_QUIT The char requests the current command to be aborted.
                    467:  */
                    468:        static int
                    469: cmd_edit(c)
                    470:        int c;
                    471: {
                    472:        int action;
                    473:        int flags;
                    474:
                    475: #if TAB_COMPLETE_FILENAME
                    476: #define        not_in_completion()     in_completion = 0
                    477: #else
                    478: #define        not_in_completion()
                    479: #endif
                    480:
                    481:        /*
                    482:         * See if the char is indeed a line-editing command.
                    483:         */
                    484:        flags = 0;
                    485:        if (curr_mlist == NULL)
                    486:                /*
                    487:                 * No current history; don't accept history manipulation cmds.
                    488:                 */
                    489:                flags |= EC_NOHISTORY;
                    490:        if (curr_mlist == &mlist_search)
                    491:                /*
                    492:                 * In a search command; don't accept file-completion cmds.
                    493:                 */
                    494:                flags |= EC_NOCOMPLETE;
                    495:
                    496:        action = editchar(c, flags);
                    497:
                    498:        switch (action)
                    499:        {
                    500:        case EC_RIGHT:
                    501:                not_in_completion();
                    502:                return (cmd_right());
                    503:        case EC_LEFT:
                    504:                not_in_completion();
                    505:                return (cmd_left());
                    506:        case EC_W_RIGHT:
                    507:                not_in_completion();
                    508:                while (*cp != '\0' && *cp != ' ')
                    509:                        cmd_right();
                    510:                while (*cp == ' ')
                    511:                        cmd_right();
                    512:                return (CC_OK);
                    513:        case EC_W_LEFT:
                    514:                not_in_completion();
                    515:                while (cp > cmdbuf && cp[-1] == ' ')
                    516:                        cmd_left();
                    517:                while (cp > cmdbuf && cp[-1] != ' ')
                    518:                        cmd_left();
                    519:                return (CC_OK);
                    520:        case EC_HOME:
                    521:                not_in_completion();
                    522:                return (cmd_home());
                    523:        case EC_END:
                    524:                not_in_completion();
                    525:                while (*cp != '\0')
                    526:                        cmd_right();
                    527:                return (CC_OK);
                    528:        case EC_INSERT:
                    529:                not_in_completion();
                    530:                return (CC_OK);
                    531:        case EC_BACKSPACE:
                    532:                not_in_completion();
                    533:                return (cmd_erase());
                    534:        case EC_LINEKILL:
                    535:                not_in_completion();
                    536:                return (cmd_kill());
                    537:        case EC_W_BACKSPACE:
                    538:                not_in_completion();
                    539:                return (cmd_werase());
                    540:        case EC_DELETE:
                    541:                not_in_completion();
                    542:                return (cmd_delete());
                    543:        case EC_W_DELETE:
                    544:                not_in_completion();
                    545:                return (cmd_wdelete());
                    546:        case EC_LITERAL:
                    547:                literal = 1;
                    548:                return (CC_OK);
                    549: #if CMD_HISTORY
                    550:        case EC_UP:
                    551:        case EC_DOWN:
                    552:                not_in_completion();
                    553:                return (cmd_updown(action));
                    554: #endif
                    555: #if TAB_COMPLETE_FILENAME
                    556:        case EC_F_COMPLETE:
                    557:        case EC_B_COMPLETE:
                    558:        case EC_EXPAND:
                    559:                return (cmd_complete(action));
                    560: #endif
                    561:        default:
                    562:                not_in_completion();
                    563:                return (CC_PASS);
                    564:        }
                    565: }
                    566:
                    567: /*
                    568:  * Insert a char into the command buffer, at the current position.
                    569:  */
                    570:        static int
                    571: cmd_ichar(c)
                    572:        int c;
                    573: {
                    574:        int col;
                    575:        char *p;
                    576:        char *s;
                    577:
                    578:        if (strlen(cmdbuf) >= sizeof(cmdbuf)-2)
                    579:        {
                    580:                /*
                    581:                 * No room in the command buffer for another char.
                    582:                 */
                    583:                bell();
                    584:                return (CC_ERROR);
                    585:        }
                    586:
                    587:        /*
                    588:         * Remember the current cursor column and
                    589:         * move it forward the width of the char being inserted.
                    590:         */
                    591:        col = cmd_col;
                    592:        p = prchar(c);
                    593:        cmd_col += strlen(p);
                    594:        if (cmd_col >= sc_width-1)
                    595:        {
                    596:                cmd_col -= strlen(p);
                    597:                bell();
                    598:                return (CC_ERROR);
                    599:        }
                    600:        /*
                    601:         * Insert the character in the string.
                    602:         * First, make room for the new char.
                    603:         */
                    604:        for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
                    605:                s[1] = s[0];
                    606:        *cp++ = c;
                    607:        /*
                    608:         * Reprint the tail of the line after the inserted char.
                    609:         */
                    610:        clear_eol();
                    611:        for (s = cp-1;  *s != '\0';  s++)
                    612:        {
                    613:                p = prchar(*s);
                    614:                col += strlen(p);
                    615:                if (col >= sc_width-1)
                    616:                {
                    617:                        /*
                    618:                         * Oops.  There is no room on the screen
                    619:                         * for the new char.  Back up the cursor to
                    620:                         * just after the inserted char and erase it.
                    621:                         */
                    622:                        col -= strlen(p);
                    623:                        while (col > cmd_col)
                    624:                        {
                    625:                                putbs();
                    626:                                col--;
                    627:                        }
                    628:                        (void) cmd_erase();
                    629:                        bell();
                    630:                        return (CC_ERROR);
                    631:                }
                    632:                putstr(p);
                    633:        }
                    634:        /*
                    635:         * Back up the cursor to just after the inserted char.
                    636:         */
                    637:        while (col > cmd_col)
                    638:        {
                    639:                putbs();
                    640:                col--;
                    641:        }
                    642:        return (CC_OK);
                    643: }
                    644:
                    645: #if TAB_COMPLETE_FILENAME
                    646: /*
                    647:  * Insert a string into the command buffer, at the current position.
                    648:  */
                    649:        static int
                    650: cmd_istr(str)
                    651:        char *str;
                    652: {
                    653:        char *s;
                    654:        int action;
                    655:
                    656:        for (s = str;  *s != '\0';  s++)
                    657:        {
                    658:                action = cmd_ichar(*s);
                    659:                if (action != CC_OK)
                    660:                {
                    661:                        bell();
                    662:                        return (action);
                    663:                }
                    664:        }
                    665:        return (CC_OK);
                    666: }
                    667:
                    668: /*
                    669:  * Find the beginning and end of the "current" word.
                    670:  * This is the word which the cursor (cp) is inside or at the end of.
                    671:  * Return pointer to the beginning of the word and put the
                    672:  * cursor at the end of the word.
                    673:  */
                    674:        static char *
                    675: delimit_word()
                    676: {
                    677:        char *word;
                    678:
                    679:        /*
                    680:         * Move cursor to end of word.
                    681:         */
                    682:        if (*cp != ' ' && *cp != '\0')
                    683:        {
                    684:                /*
                    685:                 * Cursor is on a nonspace.
                    686:                 * Move cursor right to the next space.
                    687:                 */
                    688:                while (*cp != ' ' && *cp != '\0')
                    689:                        cmd_right();
                    690:        } else if (cp > cmdbuf && cp[-1] != ' ')
                    691:        {
                    692:                /*
                    693:                 * Cursor is on a space, and char to the left is a nonspace.
                    694:                 * We're already at the end of the word.
                    695:                 */
                    696:                ;
                    697:        } else
                    698:        {
                    699:                /*
                    700:                 * Cursor is on a space and char to the left is a space.
                    701:                 * Huh? There's no word here.
                    702:                 */
                    703:                return (NULL);
                    704:        }
                    705:        /*
                    706:         * Search backwards for beginning of the word.
                    707:         */
                    708:        if (cp == cmdbuf)
                    709:                return (NULL);
                    710:        for (word = cp-1;  word > cmdbuf;  word--)
                    711:                if (word[-1] == ' ')
                    712:                        break;
                    713:        return (word);
                    714: }
                    715:
                    716: /*
                    717:  * Set things up to enter completion mode.
                    718:  * Expand the word under the cursor into a list of filenames
                    719:  * which start with that word, and set tk_text to that list.
                    720:  */
                    721:        static void
                    722: init_compl()
                    723: {
                    724:        char *word;
                    725:        char c;
                    726:
                    727:        /*
                    728:         * Get rid of any previous tk_text.
                    729:         */
                    730:        if (tk_text != NULL)
                    731:        {
                    732:                free(tk_text);
                    733:                tk_text = NULL;
                    734:        }
                    735:        /*
                    736:         * Find the original (uncompleted) word in the command buffer.
                    737:         */
                    738:        word = delimit_word();
                    739:        if (word == NULL)
                    740:                return;
                    741:        /*
                    742:         * Set the insertion point to the point in the command buffer
                    743:         * where the original (uncompleted) word now sits.
                    744:         */
                    745:        tk_ipoint = word;
                    746:        /*
                    747:         * Save the original (uncompleted) word
                    748:         */
                    749:        if (tk_original != NULL)
                    750:                free(tk_original);
                    751:        tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
                    752:        strncpy(tk_original, word, cp-word);
                    753:        /*
                    754:         * Get the expanded filename.
                    755:         * This may result in a single filename, or
                    756:         * a blank-separated list of filenames.
                    757:         */
                    758:        c = *cp;
                    759:        *cp = '\0';
                    760:        tk_text = fcomplete(word);
                    761:        *cp = c;
                    762: }
                    763:
                    764: /*
                    765:  * Return the next word in the current completion list.
                    766:  */
                    767:        static char *
                    768: next_compl(action, prev)
                    769:        int action;
                    770:        char *prev;
                    771: {
                    772:        switch (action)
                    773:        {
                    774:        case EC_F_COMPLETE:
                    775:                return (forw_textlist(&tk_tlist, prev));
                    776:        case EC_B_COMPLETE:
                    777:                return (back_textlist(&tk_tlist, prev));
                    778:        default:
                    779:                /* Cannot happen */
                    780:                return ("?");
                    781:        }
                    782: }
                    783:
                    784: /*
                    785:  * Complete the filename before (or under) the cursor.
                    786:  * cmd_complete may be called multiple times.  The global in_completion
                    787:  * remembers whether this call is the first time (create the list),
                    788:  * or a subsequent time (step thru the list).
                    789:  */
                    790:        static int
                    791: cmd_complete(action)
                    792:        int action;
                    793: {
                    794:
                    795:        if (!in_completion || action == EC_EXPAND)
                    796:        {
                    797:                /*
                    798:                 * Expand the word under the cursor and
                    799:                 * use the first word in the expansion
                    800:                 * (or the entire expansion if we're doing EC_EXPAND).
                    801:                 */
                    802:                init_compl();
                    803:                if (tk_text == NULL)
                    804:                {
                    805:                        bell();
                    806:                        return (CC_OK);
                    807:                }
                    808:                if (action == EC_EXPAND)
                    809:                {
                    810:                        /*
                    811:                         * Use the whole list.
                    812:                         */
                    813:                        tk_trial = tk_text;
                    814:                } else
                    815:                {
                    816:                        /*
                    817:                         * Use the first filename in the list.
                    818:                         */
                    819:                        in_completion = 1;
                    820:                        init_textlist(&tk_tlist, tk_text);
                    821:                        tk_trial = next_compl(action, (char*)NULL);
                    822:                }
                    823:        } else
                    824:        {
                    825:                /*
                    826:                 * We already have a completion list.
                    827:                 * Use the next/previous filename from the list.
                    828:                 */
                    829:                tk_trial = next_compl(action, tk_trial);
                    830:        }
                    831:
                    832:        /*
                    833:         * Remove the original word, or the previous trial completion.
                    834:         */
                    835:        while (cp > tk_ipoint)
                    836:                (void) cmd_erase();
                    837:
                    838:        if (tk_trial == NULL)
                    839:        {
                    840:                /*
                    841:                 * There are no more trial completions.
                    842:                 * Insert the original (uncompleted) filename.
                    843:                 */
                    844:                in_completion = 0;
                    845:                if (cmd_istr(tk_original) != CC_OK)
                    846:                        goto fail;
                    847:        } else
                    848:        {
                    849:                /*
                    850:                 * Insert trial completion.
                    851:                 */
                    852:                if (cmd_istr(tk_trial) != CC_OK)
                    853:                        goto fail;
                    854:        }
                    855:
                    856:        return (CC_OK);
                    857:
                    858: fail:
                    859:        in_completion = 0;
                    860:        bell();
                    861:        return (CC_OK);
                    862: }
                    863:
                    864: #endif /* TAB_COMPLETE_FILENAME */
                    865:
                    866: /*
                    867:  * Process a single character of a multi-character command, such as
                    868:  * a number, or the pattern of a search command.
                    869:  * Returns:
                    870:  *     CC_OK           The char was accepted.
                    871:  *     CC_QUIT         The char requests the command to be aborted.
                    872:  *     CC_ERROR        The char could not be accepted due to an error.
                    873:  */
                    874:        public int
                    875: cmd_char(c)
                    876:        int c;
                    877: {
                    878:        int action;
                    879:
                    880:        if (literal)
                    881:        {
                    882:                /*
                    883:                 * Insert the char, even if it is a line-editing char.
                    884:                 */
                    885:                literal = 0;
                    886:                return (cmd_ichar(c));
                    887:        }
                    888:
                    889:        /*
                    890:         * See if it is a special line-editing character.
                    891:         */
                    892:        if (in_mca())
                    893:        {
                    894:                action = cmd_edit(c);
                    895:                switch (action)
                    896:                {
                    897:                case CC_OK:
                    898:                case CC_QUIT:
                    899:                        return (action);
                    900:                case CC_PASS:
                    901:                        break;
                    902:                }
                    903:        }
                    904:
                    905:        /*
                    906:         * Insert the char into the command buffer.
                    907:         */
                    908:        action = cmd_ichar(c);
                    909:        if (action != CC_OK)
                    910:                return (action);
                    911:        return (CC_OK);
                    912: }
                    913:
                    914: /*
                    915:  * Return the number currently in the command buffer.
                    916:  */
                    917:        public int
                    918: cmd_int()
                    919: {
                    920:        return (atoi(cmdbuf));
                    921: }
                    922:
                    923: /*
                    924:  * Display a string, usually as a prompt for input into the command buffer.
                    925:  */
                    926:        public void
                    927: cmd_putstr(s)
                    928:        char *s;
                    929: {
                    930:        putstr(s);
                    931:        cmd_col += strlen(s);
                    932: }
                    933:
                    934: /*
                    935:  * Return a pointer to the command buffer.
                    936:  */
                    937:        public char *
                    938: get_cmdbuf()
                    939: {
                    940:        return (cmdbuf);
                    941: }