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

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