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

Annotation of src/usr.bin/less/command.c, Revision 1.3

1.3     ! 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:  * User-level command processor.
                     32:  */
                     33:
                     34: #include "less.h"
                     35: #include "position.h"
                     36: #include "option.h"
                     37: #include "cmd.h"
                     38:
                     39: extern int erase_char, kill_char;
                     40: extern int sigs;
                     41: extern int quit_at_eof;
                     42: extern int hit_eof;
                     43: extern int sc_width;
                     44: extern int sc_height;
                     45: extern int swindow;
                     46: extern int jump_sline;
                     47: extern int quitting;
                     48: extern int wscroll;
                     49: extern int nohelp;
                     50: extern int top_scroll;
                     51: extern int ignore_eoi;
                     52: extern char *every_first_cmd;
                     53: extern char *curr_altfilename;
                     54: extern char version[];
                     55: extern struct scrpos initial_scrpos;
                     56: extern IFILE curr_ifile;
                     57: #if CMD_HISTORY
                     58: extern void *ml_search;
                     59: extern void *ml_examine;
                     60: #if SHELL_ESCAPE || PIPEC
                     61: extern void *ml_shell;
                     62: #endif
                     63: #else
                     64: /* No CMD_HISTORY */
                     65: #define        ml_search       NULL
                     66: #define        ml_examine      NULL
                     67: #define        ml_shell        NULL
                     68: #endif
                     69: #if EDITOR
                     70: extern char *editor;
                     71: extern char *editproto;
                     72: #endif
                     73: extern int screen_trashed;     /* The screen has been overwritten */
1.2       etheisen   74: extern int be_helpful;
                     75:
                     76: public int helpprompt;
1.1       etheisen   77:
                     78: static char ungot[100];
                     79: static char *ungotp = NULL;
                     80: #if SHELL_ESCAPE
                     81: static char *shellcmd = NULL;  /* For holding last shell command for "!!" */
                     82: #endif
                     83: static int mca;                        /* The multicharacter command (action) */
                     84: static int search_type;                /* The previous type of search */
                     85: static int number;             /* The number typed by the user */
                     86: static char optchar;
                     87: static int optflag;
                     88: #if PIPEC
                     89: static char pipec;
                     90: #endif
                     91:
                     92: static void multi_search();
                     93:
                     94: /*
                     95:  * Move the cursor to lower left before executing a command.
                     96:  * This looks nicer if the command takes a long time before
                     97:  * updating the screen.
                     98:  */
                     99:        static void
                    100: cmd_exec()
                    101: {
                    102:        lower_left();
                    103:        flush();
                    104: }
                    105:
                    106: /*
                    107:  * Set up the display to start a new multi-character command.
                    108:  */
                    109:        static void
                    110: start_mca(action, prompt, mlist)
                    111:        int action;
                    112:        char *prompt;
                    113:        void *mlist;
                    114: {
                    115:        mca = action;
                    116:        clear_bot();
                    117:        cmd_putstr(prompt);
                    118: #if CMD_HISTORY
                    119:        set_mlist(mlist);
                    120: #endif
                    121: }
                    122:
                    123:        public int
                    124: in_mca()
                    125: {
                    126:        return (mca != 0 && mca != A_PREFIX);
                    127: }
                    128:
                    129: /*
                    130:  * Set up the display to start a new search command.
                    131:  */
                    132:        static void
                    133: mca_search()
                    134: {
                    135:        if (search_type & SRCH_FORW)
                    136:                mca = A_F_SEARCH;
                    137:        else
                    138:                mca = A_B_SEARCH;
                    139:
                    140:        clear_bot();
                    141:
                    142:        if (search_type & SRCH_FIRST_FILE)
                    143:                cmd_putstr("@");
                    144:
                    145:        if (search_type & SRCH_PAST_EOF)
                    146:                cmd_putstr("*");
                    147:
                    148:        if (search_type & SRCH_NOMATCH)
                    149:                cmd_putstr("!");
                    150:
                    151:        if (search_type & SRCH_FORW)
                    152:                cmd_putstr("/");
                    153:        else
                    154:                cmd_putstr("?");
                    155: #if CMD_HISTORY
                    156:        set_mlist(ml_search);
                    157: #endif
                    158: }
                    159:
                    160: /*
                    161:  * Execute a multicharacter command.
                    162:  */
                    163:        static void
                    164: exec_mca()
                    165: {
                    166:        register char *cbuf;
                    167:
                    168:        cmd_exec();
                    169:        cbuf = get_cmdbuf();
                    170:
                    171:        switch (mca)
                    172:        {
                    173:        case A_F_SEARCH:
                    174:        case A_B_SEARCH:
                    175:                multi_search(cbuf, number);
                    176:                break;
                    177:        case A_FIRSTCMD:
                    178:                /*
                    179:                 * Skip leading spaces or + signs in the string.
                    180:                 */
                    181:                while (*cbuf == '+' || *cbuf == ' ')
                    182:                        cbuf++;
                    183:                if (every_first_cmd != NULL)
                    184:                        free(every_first_cmd);
                    185:                if (*cbuf == '\0')
                    186:                        every_first_cmd = NULL;
                    187:                else
                    188:                        every_first_cmd = save(cbuf);
                    189:                break;
                    190:        case A_OPT_TOGGLE:
                    191:                toggle_option(optchar, cbuf, optflag);
                    192:                optchar = '\0';
                    193:                break;
                    194:        case A_F_BRACKET:
                    195:                match_brac(cbuf[0], cbuf[1], 1, number);
                    196:                break;
                    197:        case A_B_BRACKET:
                    198:                match_brac(cbuf[1], cbuf[0], 0, number);
                    199:                break;
                    200: #if EXAMINE
                    201:        case A_EXAMINE:
                    202:                edit_list(cbuf);
                    203:                break;
                    204: #endif
                    205: #if SHELL_ESCAPE
                    206:        case A_SHELL:
                    207:                /*
                    208:                 * !! just uses whatever is in shellcmd.
                    209:                 * Otherwise, copy cmdbuf to shellcmd,
                    210:                 * expanding any special characters ("%" or "#").
                    211:                 */
                    212:                if (*cbuf != '!')
                    213:                {
                    214:                        if (shellcmd != NULL)
                    215:                                free(shellcmd);
                    216:                        shellcmd = fexpand(cbuf);
                    217:                }
                    218:
                    219:                if (shellcmd == NULL)
                    220:                        lsystem("");
                    221:                else
                    222:                        lsystem(shellcmd);
                    223:                error("!done", NULL_PARG);
                    224:                break;
                    225: #endif
                    226: #if PIPEC
                    227:        case A_PIPE:
                    228:                (void) pipe_mark(pipec, cbuf);
                    229:                error("|done", NULL_PARG);
                    230:                break;
                    231: #endif
                    232:        }
                    233: }
                    234:
                    235: /*
                    236:  * Add a character to a multi-character command.
                    237:  */
                    238:        static int
                    239: mca_char(c)
                    240:        int c;
                    241: {
                    242:        char *p;
                    243:        int flag;
                    244:        char buf[3];
                    245:
                    246:        switch (mca)
                    247:        {
                    248:        case 0:
                    249:                /*
                    250:                 * Not in a multicharacter command.
                    251:                 */
                    252:                return (NO_MCA);
                    253:
                    254:        case A_PREFIX:
                    255:                /*
                    256:                 * In the prefix of a command.
                    257:                 * This not considered a multichar command
                    258:                 * (even tho it uses cmdbuf, etc.).
                    259:                 * It is handled in the commands() switch.
                    260:                 */
                    261:                return (NO_MCA);
                    262:
                    263:        case A_DIGIT:
                    264:                /*
                    265:                 * Entering digits of a number.
                    266:                 * Terminated by a non-digit.
                    267:                 */
                    268:                if ((c < '0' || c > '9') &&
                    269:                  editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE) == A_INVALID)
                    270:                {
                    271:                        /*
                    272:                         * Not part of the number.
                    273:                         * Treat as a normal command character.
                    274:                         */
                    275:                        number = cmd_int();
                    276:                        mca = 0;
                    277:                        cmd_accept();
                    278:                        return (NO_MCA);
                    279:                }
                    280:                break;
                    281:
                    282:        case A_OPT_TOGGLE:
                    283:                /*
                    284:                 * Special case for the TOGGLE_OPTION command.
                    285:                 * If the option letter which was entered is a
                    286:                 * single-char option, execute the command immediately,
                    287:                 * so user doesn't have to hit RETURN.
                    288:                 * If the first char is + or -, this indicates
                    289:                 * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE.
                    290:                 */
                    291:                if (c == erase_char || c == kill_char)
                    292:                        break;
                    293:                if (optchar != '\0' && optchar != '+' && optchar != '-')
                    294:                        /*
                    295:                         * We already have the option letter.
                    296:                         */
                    297:                        break;
                    298:                switch (c)
                    299:                {
                    300:                case '+':
                    301:                        optflag = OPT_UNSET;
                    302:                        break;
                    303:                case '-':
                    304:                        optflag = OPT_SET;
                    305:                        break;
                    306:                default:
                    307:                        optchar = c;
                    308:                        if (optflag != OPT_TOGGLE || single_char_option(c))
                    309:                        {
                    310:                                toggle_option(c, "", optflag);
                    311:                                return (MCA_DONE);
                    312:                        }
                    313:                        break;
                    314:                }
                    315:                if (optchar == '+' || optchar == '-')
                    316:                {
                    317:                        optchar = c;
                    318:                        break;
                    319:                }
                    320:                /*
                    321:                 * Display a prompt appropriate for the option letter.
                    322:                 */
                    323:                if ((p = opt_prompt(c)) == NULL)
                    324:                {
                    325:                        buf[0] = '-';
                    326:                        buf[1] = c;
                    327:                        buf[2] = '\0';
                    328:                        p = buf;
                    329:                }
                    330:                start_mca(A_OPT_TOGGLE, p, (void*)NULL);
                    331:                return (MCA_MORE);
                    332:
                    333:        case A_F_SEARCH:
                    334:        case A_B_SEARCH:
                    335:                /*
                    336:                 * Special case for search commands.
                    337:                 * Certain characters as the first char of
                    338:                 * the pattern have special meaning:
                    339:                 *      !  Toggle the NOMATCH flag
                    340:                 *      *  Toggle the PAST_EOF flag
                    341:                 *      @  Toggle the FIRST_FILE flag
                    342:                 */
                    343:                if (len_cmdbuf() > 0)
                    344:                        /*
                    345:                         * Only works for the first char of the pattern.
                    346:                         */
                    347:                        break;
                    348:
                    349:                flag = 0;
                    350:                switch (c)
                    351:                {
                    352:                case '!':
                    353:                        flag = SRCH_NOMATCH;
                    354:                        break;
                    355:                case '@':
                    356:                        flag = SRCH_FIRST_FILE;
                    357:                        break;
                    358:                case '*':
                    359:                        flag = SRCH_PAST_EOF;
                    360:                        break;
                    361:                }
                    362:                if (flag != 0)
                    363:                {
                    364:                        search_type ^= flag;
                    365:                        mca_search();
                    366:                        return (MCA_MORE);
                    367:                }
                    368:                break;
                    369:        }
                    370:
                    371:        /*
                    372:         * Any other multicharacter command
                    373:         * is terminated by a newline.
                    374:         */
                    375:        if (c == '\n' || c == '\r')
                    376:        {
                    377:                /*
                    378:                 * Execute the command.
                    379:                 */
                    380:                exec_mca();
                    381:                return (MCA_DONE);
                    382:        }
                    383:        /*
                    384:         * Append the char to the command buffer.
                    385:         */
                    386:        if (cmd_char(c) == CC_QUIT)
                    387:                /*
                    388:                 * Abort the multi-char command.
                    389:                 */
                    390:                return (MCA_DONE);
                    391:
                    392:        if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
                    393:        {
                    394:                /*
                    395:                 * Special case for the bracket-matching commands.
                    396:                 * Execute the command after getting exactly two
                    397:                 * characters from the user.
                    398:                 */
                    399:                exec_mca();
                    400:                return (MCA_DONE);
                    401:        }
                    402:
                    403:        /*
                    404:         * Need another character.
                    405:         */
                    406:        return (MCA_MORE);
                    407: }
                    408:
                    409: /*
                    410:  * Display the appropriate prompt.
                    411:  */
                    412:        static void
                    413: prompt()
                    414: {
                    415:        register char *p;
                    416:
                    417:        if (ungotp != NULL && ungotp > ungot)
                    418:        {
                    419:                /*
                    420:                 * No prompt necessary if commands are from
                    421:                 * ungotten chars rather than from the user.
                    422:                 */
                    423:                return;
                    424:        }
                    425:
                    426:        /*
                    427:         * If nothing is displayed yet, display starting from initial_scrpos.
                    428:         */
                    429:        if (empty_screen())
                    430:        {
                    431:                if (initial_scrpos.pos == NULL_POSITION)
                    432:                        /*
                    433:                         * {{ Maybe this should be:
                    434:                         *    jump_loc(ch_zero(), jump_sline);
                    435:                         *    but this behavior seems rather unexpected
                    436:                         *    on the first screen. }}
                    437:                         */
                    438:                        jump_loc(ch_zero(), 1);
                    439:                else
                    440:                        jump_loc(initial_scrpos.pos, initial_scrpos.ln);
                    441:        } else if (screen_trashed)
                    442:        {
                    443:                int save_top_scroll;
                    444:                save_top_scroll = top_scroll;
                    445:                top_scroll = 1;
                    446:                repaint();
                    447:                top_scroll = save_top_scroll;
                    448:        }
                    449:
                    450:        /*
                    451:         * If the -E flag is set and we've hit EOF on the last file, quit.
                    452:         */
                    453:        if (quit_at_eof == OPT_ONPLUS && hit_eof &&
                    454:            next_ifile(curr_ifile) == NULL_IFILE)
                    455:                quit(QUIT_OK);
                    456:
                    457:        /*
                    458:         * Select the proper prompt and display it.
                    459:         */
                    460:        clear_bot();
1.2       etheisen  461:        if (helpprompt) {
1.1       etheisen  462:                so_enter();
1.2       etheisen  463:                putstr("[Press 'h' for instructions.]");
1.1       etheisen  464:                so_exit();
1.2       etheisen  465:                helpprompt = 0;
                    466:        } else {
                    467:                p = pr_string();
                    468:                if (p == NULL)
                    469:                        putchr(':');
                    470:                else
                    471:                {
                    472:                        so_enter();
                    473:                        putstr(p);
                    474:                        if (be_helpful)
                    475:                                putstr(" [Press space to continue, 'q' to quit.]");
                    476:                        so_exit();
                    477:                }
1.1       etheisen  478:        }
                    479: }
                    480:
                    481:        public void
                    482: dispversion()
                    483: {
                    484:        PARG parg;
                    485:
                    486:        parg.p_string = version;
                    487:        error("less  version %s", &parg);
                    488: }
                    489:
                    490: /*
                    491:  * Get command character.
                    492:  * The character normally comes from the keyboard,
                    493:  * but may come from ungotten characters
                    494:  * (characters previously given to ungetcc or ungetsc).
                    495:  */
                    496:        public int
                    497: getcc()
                    498: {
                    499:        if (ungotp == NULL)
                    500:                /*
                    501:                 * Normal case: no ungotten chars, so get one from the user.
                    502:                 */
                    503:                return (getchr());
                    504:
                    505:        if (ungotp > ungot)
                    506:                /*
                    507:                 * Return the next ungotten char.
                    508:                 */
                    509:                return (*--ungotp);
                    510:
                    511:        /*
                    512:         * We have just run out of ungotten chars.
                    513:         */
                    514:        ungotp = NULL;
                    515:        if (len_cmdbuf() == 0 || !empty_screen())
                    516:                return (getchr());
                    517:        /*
                    518:         * Command is incomplete, so try to complete it.
                    519:         */
                    520:        switch (mca)
                    521:        {
                    522:        case A_DIGIT:
                    523:                /*
                    524:                 * We have a number but no command.  Treat as #g.
                    525:                 */
                    526:                return ('g');
                    527:
                    528:        case A_F_SEARCH:
                    529:        case A_B_SEARCH:
                    530:                /*
                    531:                 * We have "/string" but no newline.  Add the \n.
                    532:                 */
                    533:                return ('\n');
                    534:
                    535:        default:
                    536:                /*
                    537:                 * Some other incomplete command.  Let user complete it.
                    538:                 */
                    539:                return (getchr());
                    540:        }
                    541: }
                    542:
                    543: /*
                    544:  * "Unget" a command character.
                    545:  * The next getcc() will return this character.
                    546:  */
                    547:        public void
                    548: ungetcc(c)
                    549:        int c;
                    550: {
                    551:        if (ungotp == NULL)
                    552:                ungotp = ungot;
                    553:        if (ungotp >= ungot + sizeof(ungot))
                    554:        {
                    555:                error("ungetcc overflow", NULL_PARG);
                    556:                quit(QUIT_ERROR);
                    557:        }
                    558:        *ungotp++ = c;
                    559: }
                    560:
                    561: /*
                    562:  * Unget a whole string of command characters.
                    563:  * The next sequence of getcc()'s will return this string.
                    564:  */
                    565:        public void
                    566: ungetsc(s)
                    567:        char *s;
                    568: {
                    569:        register char *p;
                    570:
                    571:        for (p = s + strlen(s) - 1;  p >= s;  p--)
                    572:                ungetcc(*p);
                    573: }
                    574:
                    575: /*
                    576:  * Search for a pattern, possibly in multiple files.
                    577:  * If SRCH_FIRST_FILE is set, begin searching at the first file.
                    578:  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
                    579:  */
                    580:        static void
                    581: multi_search(pattern, n)
                    582:        char *pattern;
                    583:        int n;
                    584: {
                    585:        register int nomore;
                    586:        IFILE save_ifile;
                    587:        int changed_file;
                    588:
                    589:        changed_file = 0;
                    590:        save_ifile = curr_ifile;
                    591:
                    592:        if (search_type & SRCH_FIRST_FILE)
                    593:        {
                    594:                /*
                    595:                 * Start at the first (or last) file
                    596:                 * in the command line list.
                    597:                 */
                    598:                if (search_type & SRCH_FORW)
                    599:                        nomore = edit_first();
                    600:                else
                    601:                        nomore = edit_last();
                    602:                if (nomore)
                    603:                        return;
                    604:                changed_file = 1;
                    605:                search_type &= ~SRCH_FIRST_FILE;
                    606:        }
                    607:
                    608:        for (;;)
                    609:        {
                    610:                if ((n = search(search_type, pattern, n)) == 0)
                    611:                        /*
                    612:                         * Found it.
                    613:                         */
                    614:                        return;
                    615:
                    616:                if (n < 0)
                    617:                        /*
                    618:                         * Some kind of error in the search.
                    619:                         * Error message has been printed by search().
                    620:                         */
                    621:                        break;
                    622:
                    623:                if ((search_type & SRCH_PAST_EOF) == 0)
                    624:                        /*
                    625:                         * We didn't find a match, but we're
                    626:                         * supposed to search only one file.
                    627:                         */
                    628:                        break;
                    629:                /*
                    630:                 * Move on to the next file.
                    631:                 */
                    632:                if (search_type & SRCH_FORW)
                    633:                        nomore = edit_next(1);
                    634:                else
                    635:                        nomore = edit_prev(1);
                    636:                if (nomore)
                    637:                        break;
                    638:                changed_file = 1;
                    639:        }
                    640:
                    641:        /*
                    642:         * Didn't find it.
                    643:         * Print an error message if we haven't already.
                    644:         */
                    645:        if (n > 0)
                    646:                error("Pattern not found", NULL_PARG);
                    647:
                    648:        if (changed_file)
                    649:        {
                    650:                /*
                    651:                 * Restore the file we were originally viewing.
                    652:                 */
                    653:                if (edit_ifile(save_ifile))
                    654:                        quit(QUIT_ERROR);
                    655:        }
                    656: }
                    657:
                    658: /*
                    659:  * Main command processor.
                    660:  * Accept and execute commands until a quit command.
                    661:  */
                    662:        public void
                    663: commands()
                    664: {
                    665:        register int c;
                    666:        register int action;
                    667:        register char *cbuf;
                    668:        int save_search_type;
                    669:        char *s;
                    670:        char tbuf[2];
                    671:        PARG parg;
                    672:
                    673:        search_type = SRCH_FORW;
                    674:        wscroll = (sc_height + 1) / 2;
                    675:
                    676:        for (;;)
                    677:        {
                    678:                mca = 0;
                    679:                cmd_accept();
                    680:                number = 0;
                    681:                optchar = '\0';
                    682:
                    683:                /*
                    684:                 * See if any signals need processing.
                    685:                 */
                    686:                if (sigs)
                    687:                {
                    688:                        psignals();
                    689:                        if (quitting)
                    690:                                quit(QUIT_SAVED_STATUS);
                    691:                }
                    692:
                    693:                /*
                    694:                 * Display prompt and accept a character.
                    695:                 */
                    696:                cmd_reset();
                    697:                prompt();
                    698:                if (sigs)
                    699:                        continue;
                    700:                c = getcc();
                    701:
                    702:        again:
                    703:                if (sigs)
                    704:                        continue;
                    705:
                    706:                /*
                    707:                 * If we are in a multicharacter command, call mca_char.
                    708:                 * Otherwise we call fcmd_decode to determine the
                    709:                 * action to be performed.
                    710:                 */
                    711:                if (mca)
                    712:                        switch (mca_char(c))
                    713:                        {
                    714:                        case MCA_MORE:
                    715:                                /*
                    716:                                 * Need another character.
                    717:                                 */
                    718:                                c = getcc();
                    719:                                goto again;
                    720:                        case MCA_DONE:
                    721:                                /*
                    722:                                 * Command has been handled by mca_char.
                    723:                                 * Start clean with a prompt.
                    724:                                 */
                    725:                                continue;
                    726:                        case NO_MCA:
                    727:                                /*
                    728:                                 * Not a multi-char command
                    729:                                 * (at least, not anymore).
                    730:                                 */
                    731:                                break;
                    732:                        }
                    733:
                    734:                /*
                    735:                 * Decode the command character and decide what to do.
                    736:                 */
                    737:                if (mca)
                    738:                {
                    739:                        /*
                    740:                         * We're in a multichar command.
                    741:                         * Add the character to the command buffer
                    742:                         * and display it on the screen.
                    743:                         * If the user backspaces past the start
                    744:                         * of the line, abort the command.
                    745:                         */
                    746:                        if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
                    747:                                continue;
                    748:                        cbuf = get_cmdbuf();
                    749:                } else
                    750:                {
                    751:                        /*
                    752:                         * Don't use cmd_char if we're starting fresh
                    753:                         * at the beginning of a command, because we
                    754:                         * don't want to echo the command until we know
                    755:                         * it is a multichar command.  We also don't
                    756:                         * want erase_char/kill_char to be treated
                    757:                         * as line editing characters.
                    758:                         */
                    759:                        tbuf[0] = c;
                    760:                        tbuf[1] = '\0';
                    761:                        cbuf = tbuf;
                    762:                }
                    763:                s = NULL;
                    764:                action = fcmd_decode(cbuf, &s);
                    765:                /*
                    766:                 * If an "extra" string was returned,
                    767:                 * process it as a string of command characters.
                    768:                 */
                    769:                if (s != NULL)
                    770:                        ungetsc(s);
                    771:                /*
                    772:                 * Clear the cmdbuf string.
                    773:                 * (But not if we're in the prefix of a command,
                    774:                 * because the partial command string is kept there.)
                    775:                 */
                    776:                if (action != A_PREFIX)
                    777:                        cmd_reset();
                    778:
                    779:                switch (action)
                    780:                {
                    781:                case A_DIGIT:
                    782:                        /*
                    783:                         * First digit of a number.
                    784:                         */
                    785:                        start_mca(A_DIGIT, ":", (void*)NULL);
                    786:                        goto again;
                    787:
                    788:                case A_F_WINDOW:
                    789:                        /*
                    790:                         * Forward one window (and set the window size).
                    791:                         */
                    792:                        if (number > 0)
                    793:                                swindow = number;
                    794:                        /* FALLTHRU */
                    795:                case A_F_SCREEN:
                    796:                        /*
                    797:                         * Forward one screen.
                    798:                         */
                    799:                        if (number <= 0)
                    800:                                number = get_swindow();
                    801:                        cmd_exec();
                    802:                        forward(number, 0, 1);
                    803:                        break;
                    804:
                    805:                case A_B_WINDOW:
                    806:                        /*
                    807:                         * Backward one window (and set the window size).
                    808:                         */
                    809:                        if (number > 0)
                    810:                                swindow = number;
                    811:                        /* FALLTHRU */
                    812:                case A_B_SCREEN:
                    813:                        /*
                    814:                         * Backward one screen.
                    815:                         */
                    816:                        if (number <= 0)
                    817:                                number = get_swindow();
                    818:                        cmd_exec();
                    819:                        backward(number, 0, 1);
                    820:                        break;
                    821:
                    822:                case A_F_LINE:
                    823:                        /*
                    824:                         * Forward N (default 1) line.
                    825:                         */
                    826:                        if (number <= 0)
                    827:                                number = 1;
                    828:                        cmd_exec();
                    829:                        forward(number, 0, 0);
                    830:                        break;
                    831:
                    832:                case A_B_LINE:
                    833:                        /*
                    834:                         * Backward N (default 1) line.
                    835:                         */
                    836:                        if (number <= 0)
                    837:                                number = 1;
                    838:                        cmd_exec();
                    839:                        backward(number, 0, 0);
                    840:                        break;
                    841:
                    842:                case A_FF_LINE:
                    843:                        /*
                    844:                         * Force forward N (default 1) line.
                    845:                         */
                    846:                        if (number <= 0)
                    847:                                number = 1;
                    848:                        cmd_exec();
                    849:                        forward(number, 1, 0);
                    850:                        break;
                    851:
                    852:                case A_BF_LINE:
                    853:                        /*
                    854:                         * Force backward N (default 1) line.
                    855:                         */
                    856:                        if (number <= 0)
                    857:                                number = 1;
                    858:                        cmd_exec();
                    859:                        backward(number, 1, 0);
                    860:                        break;
                    861:
                    862:                case A_F_FOREVER:
                    863:                        /*
                    864:                         * Forward forever, ignoring EOF.
                    865:                         */
                    866:                        cmd_exec();
                    867:                        jump_forw();
                    868:                        ignore_eoi = 1;
                    869:                        hit_eof = 0;
                    870:                        while (!ABORT_SIGS())
                    871:                                forward(1, 0, 0);
                    872:                        ignore_eoi = 0;
                    873:                        break;
                    874:
                    875:                case A_F_SCROLL:
                    876:                        /*
                    877:                         * Forward N lines
                    878:                         * (default same as last 'd' or 'u' command).
                    879:                         */
                    880:                        if (number > 0)
                    881:                                wscroll = number;
                    882:                        cmd_exec();
                    883:                        forward(wscroll, 0, 0);
                    884:                        break;
                    885:
                    886:                case A_B_SCROLL:
                    887:                        /*
                    888:                         * Forward N lines
                    889:                         * (default same as last 'd' or 'u' command).
                    890:                         */
                    891:                        if (number > 0)
                    892:                                wscroll = number;
                    893:                        cmd_exec();
                    894:                        backward(wscroll, 0, 0);
                    895:                        break;
                    896:
                    897:                case A_FREPAINT:
                    898:                        /*
                    899:                         * Flush buffers, then repaint screen.
                    900:                         * Don't flush the buffers on a pipe!
                    901:                         */
                    902:                        if (ch_getflags() & CH_CANSEEK)
                    903:                        {
                    904:                                ch_flush();
                    905:                                clr_linenum();
                    906:                        }
                    907:                        /* FALLTHRU */
                    908:                case A_REPAINT:
                    909:                        /*
                    910:                         * Repaint screen.
                    911:                         */
                    912:                        cmd_exec();
                    913:                        repaint();
                    914:                        break;
                    915:
                    916:                case A_GOLINE:
                    917:                        /*
                    918:                         * Go to line N, default beginning of file.
                    919:                         */
                    920:                        if (number <= 0)
                    921:                                number = 1;
                    922:                        cmd_exec();
                    923:                        jump_back(number);
                    924:                        break;
                    925:
                    926:                case A_PERCENT:
                    927:                        /*
                    928:                         * Go to a specified percentage into the file.
                    929:                         */
                    930:                        if (number < 0)
                    931:                                number = 0;
                    932:                        if (number > 100)
                    933:                                number = 100;
                    934:                        cmd_exec();
                    935:                        jump_percent(number);
                    936:                        break;
                    937:
                    938:                case A_GOEND:
                    939:                        /*
                    940:                         * Go to line N, default end of file.
                    941:                         */
                    942:                        cmd_exec();
                    943:                        if (number <= 0)
                    944:                                jump_forw();
                    945:                        else
                    946:                                jump_back(number);
                    947:                        break;
                    948:
                    949:                case A_GOPOS:
                    950:                        /*
                    951:                         * Go to a specified byte position in the file.
                    952:                         */
                    953:                        cmd_exec();
                    954:                        if (number < 0)
                    955:                                number = 0;
                    956:                        jump_line_loc((POSITION)number, jump_sline);
                    957:                        break;
                    958:
                    959:                case A_STAT:
                    960:                        /*
                    961:                         * Print file name, etc.
                    962:                         */
                    963:                        cmd_exec();
                    964:                        parg.p_string = eq_message();
                    965:                        error("%s", &parg);
                    966:                        break;
                    967:
                    968:                case A_VERSION:
                    969:                        /*
                    970:                         * Print version number, without the "@(#)".
                    971:                         */
                    972:                        cmd_exec();
                    973:                        dispversion();
                    974:                        break;
                    975:
                    976:                case A_QUIT:
                    977:                        /*
                    978:                         * Exit.
                    979:                         */
                    980:                        quit(QUIT_OK);
                    981:
                    982: /*
                    983:  * Define abbreviation for a commonly used sequence below.
                    984:  */
                    985: #define        DO_SEARCH()     if (number <= 0) number = 1;    \
                    986:                        mca_search();                   \
                    987:                        cmd_exec();                     \
                    988:                        multi_search((char *)NULL, number);
                    989:
                    990:
                    991:                case A_F_SEARCH:
                    992:                        /*
                    993:                         * Search forward for a pattern.
                    994:                         * Get the first char of the pattern.
                    995:                         */
                    996:                        search_type = SRCH_FORW;
                    997:                        if (number <= 0)
                    998:                                number = 1;
                    999:                        mca_search();
                   1000:                        c = getcc();
                   1001:                        goto again;
                   1002:
                   1003:                case A_B_SEARCH:
                   1004:                        /*
                   1005:                         * Search backward for a pattern.
                   1006:                         * Get the first char of the pattern.
                   1007:                         */
                   1008:                        search_type = SRCH_BACK;
                   1009:                        if (number <= 0)
                   1010:                                number = 1;
                   1011:                        mca_search();
                   1012:                        c = getcc();
                   1013:                        goto again;
                   1014:
                   1015:                case A_AGAIN_SEARCH:
                   1016:                        /*
                   1017:                         * Repeat previous search.
                   1018:                         */
                   1019:                        DO_SEARCH();
                   1020:                        break;
                   1021:
                   1022:                case A_T_AGAIN_SEARCH:
                   1023:                        /*
                   1024:                         * Repeat previous search, multiple files.
                   1025:                         */
                   1026:                        search_type |= SRCH_PAST_EOF;
                   1027:                        DO_SEARCH();
                   1028:                        break;
                   1029:
                   1030:                case A_REVERSE_SEARCH:
                   1031:                        /*
                   1032:                         * Repeat previous search, in reverse direction.
                   1033:                         */
                   1034:                        save_search_type = search_type;
                   1035:                        search_type = SRCH_REVERSE(search_type);
                   1036:                        DO_SEARCH();
                   1037:                        search_type = save_search_type;
                   1038:                        break;
                   1039:
                   1040:                case A_T_REVERSE_SEARCH:
                   1041:                        /*
                   1042:                         * Repeat previous search,
                   1043:                         * multiple files in reverse direction.
                   1044:                         */
                   1045:                        save_search_type = search_type;
                   1046:                        search_type = SRCH_REVERSE(search_type);
                   1047:                        search_type |= SRCH_PAST_EOF;
                   1048:                        DO_SEARCH();
                   1049:                        search_type = save_search_type;
                   1050:                        break;
                   1051:
                   1052:                case A_UNDO_SEARCH:
                   1053:                        undo_search();
                   1054:                        break;
                   1055:
                   1056:                case A_HELP:
                   1057:                        /*
                   1058:                         * Help.
                   1059:                         */
                   1060:                        if (nohelp)
                   1061:                        {
                   1062:                                bell();
                   1063:                                break;
                   1064:                        }
                   1065:                        clear_bot();
                   1066:                        putstr(" help");
                   1067:                        cmd_exec();
                   1068:                        help(0);
                   1069:                        break;
                   1070:
                   1071:                case A_EXAMINE:
                   1072: #if EXAMINE
                   1073:                        /*
                   1074:                         * Edit a new file.  Get the filename.
                   1075:                         */
                   1076:                        start_mca(A_EXAMINE, "Examine: ", ml_examine);
                   1077:                        c = getcc();
                   1078:                        goto again;
                   1079: #else
                   1080:                        error("Command not available", NULL_PARG);
                   1081:                        break;
                   1082: #endif
                   1083:
                   1084:                case A_VISUAL:
                   1085:                        /*
                   1086:                         * Invoke an editor on the input file.
                   1087:                         */
                   1088: #if EDITOR
                   1089:                        if (strcmp(get_filename(curr_ifile), "-") == 0)
                   1090:                        {
                   1091:                                error("Cannot edit standard input", NULL_PARG);
                   1092:                                break;
                   1093:                        }
                   1094:                        if (curr_altfilename != NULL)
                   1095:                        {
                   1096:                                error("Cannot edit file processed with LESSOPEN",
                   1097:                                        NULL_PARG);
                   1098:                                break;
                   1099:                        }
                   1100:                        /*
                   1101:                         * Expand the editor prototype string
                   1102:                         * and pass it to the system to execute.
                   1103:                         */
                   1104:                        cmd_exec();
                   1105:                        lsystem(pr_expand(editproto, 0));
                   1106:                        /*
                   1107:                         * Re-edit the file, since data may have changed.
                   1108:                         * Some editors even recreate the file, so flushing
                   1109:                         * buffers is not sufficient.
                   1110:                         */
                   1111:                        if (edit_ifile(curr_ifile))
                   1112:                                quit(QUIT_ERROR);
                   1113:                        break;
                   1114: #else
                   1115:                        error("Command not available", NULL_PARG);
                   1116:                        break;
                   1117: #endif
                   1118:
                   1119:                case A_NEXT_FILE:
                   1120:                        /*
                   1121:                         * Examine next file.
                   1122:                         */
                   1123:                        if (number <= 0)
                   1124:                                number = 1;
                   1125:                        if (edit_next(number))
                   1126:                        {
                   1127:                                if (quit_at_eof && hit_eof)
                   1128:                                        quit(QUIT_OK);
                   1129:                                parg.p_string = (number > 1) ? "(N-th) " : "";
                   1130:                                error("No %snext file", &parg);
                   1131:                        }
                   1132:                        break;
                   1133:
                   1134:                case A_PREV_FILE:
                   1135:                        /*
                   1136:                         * Examine previous file.
                   1137:                         */
                   1138:                        if (number <= 0)
                   1139:                                number = 1;
                   1140:                        if (edit_prev(number))
                   1141:                        {
                   1142:                                parg.p_string = (number > 1) ? "(N-th) " : "";
                   1143:                                error("No %sprevious file", &parg);
                   1144:                        }
                   1145:                        break;
                   1146:
                   1147:                case A_INDEX_FILE:
                   1148:                        /*
                   1149:                         * Examine a particular file.
                   1150:                         */
                   1151:                        if (number <= 0)
                   1152:                                number = 1;
                   1153:                        if (edit_index(number))
                   1154:                                error("No such file", NULL_PARG);
                   1155:                        break;
                   1156:
                   1157:                case A_OPT_TOGGLE:
                   1158:                        start_mca(A_OPT_TOGGLE, "-", (void*)NULL);
                   1159:                        optflag = OPT_TOGGLE;
                   1160:                        c = getcc();
                   1161:                        goto again;
                   1162:
                   1163:                case A_DISP_OPTION:
                   1164:                        /*
                   1165:                         * Report a flag setting.
                   1166:                         */
                   1167:                        start_mca(A_DISP_OPTION, "_", (void*)NULL);
                   1168:                        c = getcc();
                   1169:                        if (c == erase_char || c == kill_char)
                   1170:                                break;
                   1171:                        toggle_option(c, "", OPT_NO_TOGGLE);
                   1172:                        break;
                   1173:
                   1174:                case A_FIRSTCMD:
                   1175:                        /*
                   1176:                         * Set an initial command for new files.
                   1177:                         */
                   1178:                        start_mca(A_FIRSTCMD, "+", (void*)NULL);
                   1179:                        c = getcc();
                   1180:                        goto again;
                   1181:
                   1182:                case A_SHELL:
                   1183:                        /*
                   1184:                         * Shell escape.
                   1185:                         */
                   1186: #if SHELL_ESCAPE
                   1187:                        start_mca(A_SHELL, "!", ml_shell);
                   1188:                        c = getcc();
                   1189:                        goto again;
                   1190: #else
                   1191:                        error("Command not available", NULL_PARG);
                   1192:                        break;
                   1193: #endif
                   1194:
                   1195:                case A_SETMARK:
                   1196:                        /*
                   1197:                         * Set a mark.
                   1198:                         */
                   1199:                        start_mca(A_SETMARK, "mark: ", (void*)NULL);
                   1200:                        c = getcc();
                   1201:                        if (c == erase_char || c == kill_char ||
                   1202:                            c == '\n' || c == '\r')
                   1203:                                break;
                   1204:                        setmark(c);
                   1205:                        break;
                   1206:
                   1207:                case A_GOMARK:
                   1208:                        /*
                   1209:                         * Go to a mark.
                   1210:                         */
                   1211:                        start_mca(A_GOMARK, "goto mark: ", (void*)NULL);
                   1212:                        c = getcc();
                   1213:                        if (c == erase_char || c == kill_char ||
                   1214:                            c == '\n' || c == '\r')
                   1215:                                break;
                   1216:                        gomark(c);
                   1217:                        break;
                   1218:
                   1219:                case A_PIPE:
                   1220: #if PIPEC
                   1221:                        start_mca(A_PIPE, "|mark: ", (void*)NULL);
                   1222:                        c = getcc();
                   1223:                        if (c == erase_char || c == kill_char)
                   1224:                                break;
                   1225:                        if (c == '\n' || c == '\r')
                   1226:                                c = '.';
                   1227:                        if (badmark(c))
                   1228:                                break;
                   1229:                        pipec = c;
                   1230:                        start_mca(A_PIPE, "!", ml_shell);
                   1231:                        c = getcc();
                   1232:                        goto again;
                   1233: #else
                   1234:                        error("Command not available", NULL_PARG);
                   1235:                        break;
                   1236: #endif
                   1237:
                   1238:                case A_B_BRACKET:
                   1239:                case A_F_BRACKET:
                   1240:                        start_mca(action, "Brackets: ", (void*)NULL);
                   1241:                        c = getcc();
                   1242:                        goto again;
                   1243:
                   1244:                case A_PREFIX:
                   1245:                        /*
                   1246:                         * The command is incomplete (more chars are needed).
                   1247:                         * Display the current char, so the user knows
                   1248:                         * what's going on, and get another character.
                   1249:                         */
                   1250:                        if (mca != A_PREFIX)
                   1251:                        {
                   1252:                                start_mca(A_PREFIX, " ", (void*)NULL);
                   1253:                                cmd_reset();
                   1254:                                (void) cmd_char(c);
                   1255:                        }
                   1256:                        c = getcc();
                   1257:                        goto again;
                   1258:
                   1259:                case A_NOACTION:
                   1260:                        break;
                   1261:
                   1262:                default:
1.2       etheisen 1263:                        if (be_helpful)
                   1264:                                helpprompt = 1;
                   1265:                        else
                   1266:                                bell();
1.1       etheisen 1267:                        break;
                   1268:                }
                   1269:        }
                   1270: }