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

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