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

1.1       etheisen    1: /*
1.6       millert     2:  * Copyright (C) 1984-2002  Mark Nudelman
1.1       etheisen    3:  *
1.6       millert     4:  * You may distribute under the terms of either the GNU General Public
                      5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.6       millert     7:  * For more information about less, or for information on how to
                      8:  * contact the author, see the README file.
1.1       etheisen    9:  */
                     10:
                     11:
                     12: /*
                     13:  * User-level command processor.
                     14:  */
                     15:
                     16: #include "less.h"
1.6       millert    17: #if MSDOS_COMPILER==WIN32C
                     18: #include <windows.h>
                     19: #endif
1.1       etheisen   20: #include "position.h"
                     21: #include "option.h"
                     22: #include "cmd.h"
                     23:
                     24: extern int erase_char, kill_char;
                     25: extern int sigs;
                     26: extern int quit_at_eof;
1.6       millert    27: extern int quit_if_one_screen;
                     28: extern int squished;
1.1       etheisen   29: extern int hit_eof;
                     30: extern int sc_width;
                     31: extern int sc_height;
                     32: extern int swindow;
                     33: extern int jump_sline;
                     34: extern int quitting;
                     35: extern int wscroll;
1.7       millert    36: extern int nohelp;
1.1       etheisen   37: extern int top_scroll;
                     38: extern int ignore_eoi;
1.6       millert    39: extern int secure;
                     40: extern int hshift;
                     41: extern int show_attn;
1.1       etheisen   42: extern char *every_first_cmd;
                     43: extern char *curr_altfilename;
                     44: extern char version[];
                     45: extern struct scrpos initial_scrpos;
                     46: extern IFILE curr_ifile;
1.6       millert    47: extern void constant *ml_search;
                     48: extern void constant *ml_examine;
1.1       etheisen   49: #if SHELL_ESCAPE || PIPEC
1.6       millert    50: extern void constant *ml_shell;
1.1       etheisen   51: #endif
                     52: #if EDITOR
                     53: extern char *editor;
                     54: extern char *editproto;
                     55: #endif
                     56: extern int screen_trashed;     /* The screen has been overwritten */
1.6       millert    57: extern int shift_count;
1.2       etheisen   58: extern int be_helpful;
                     59:
1.6       millert    60: static char ungot[UNGOT_SIZE];
1.1       etheisen   61: static char *ungotp = NULL;
                     62: #if SHELL_ESCAPE
                     63: static char *shellcmd = NULL;  /* For holding last shell command for "!!" */
                     64: #endif
                     65: static int mca;                        /* The multicharacter command (action) */
                     66: static int search_type;                /* The previous type of search */
1.6       millert    67: static LINENUM number;         /* The number typed by the user */
1.1       etheisen   68: static char optchar;
                     69: static int optflag;
1.6       millert    70: static int optgetname;
                     71: static POSITION bottompos;
                     72: static char *help_prompt;
1.1       etheisen   73: #if PIPEC
                     74: static char pipec;
                     75: #endif
                     76:
                     77: static void multi_search();
                     78:
                     79: /*
                     80:  * Move the cursor to lower left before executing a command.
                     81:  * This looks nicer if the command takes a long time before
                     82:  * updating the screen.
                     83:  */
                     84:        static void
                     85: cmd_exec()
                     86: {
1.6       millert    87:        clear_attn();
1.1       etheisen   88:        lower_left();
                     89:        flush();
                     90: }
                     91:
                     92: /*
                     93:  * Set up the display to start a new multi-character command.
                     94:  */
                     95:        static void
1.6       millert    96: start_mca(action, prompt, mlist, cmdflags)
1.1       etheisen   97:        int action;
                     98:        char *prompt;
                     99:        void *mlist;
1.6       millert   100:        int cmdflags;
1.1       etheisen  101: {
                    102:        mca = action;
1.6       millert   103:        clear_cmd();
1.1       etheisen  104:        cmd_putstr(prompt);
1.6       millert   105:        set_mlist(mlist, cmdflags);
1.1       etheisen  106: }
                    107:
                    108:        public int
                    109: in_mca()
                    110: {
                    111:        return (mca != 0 && mca != A_PREFIX);
                    112: }
                    113:
                    114: /*
                    115:  * Set up the display to start a new search command.
                    116:  */
                    117:        static void
                    118: mca_search()
                    119: {
                    120:        if (search_type & SRCH_FORW)
                    121:                mca = A_F_SEARCH;
                    122:        else
                    123:                mca = A_B_SEARCH;
                    124:
1.6       millert   125:        clear_cmd();
1.1       etheisen  126:
1.6       millert   127:        if (search_type & SRCH_NO_MATCH)
                    128:                cmd_putstr("Non-match ");
1.1       etheisen  129:        if (search_type & SRCH_FIRST_FILE)
1.6       millert   130:                cmd_putstr("First-file ");
1.1       etheisen  131:        if (search_type & SRCH_PAST_EOF)
1.6       millert   132:                cmd_putstr("EOF-ignore ");
                    133:        if (search_type & SRCH_NO_MOVE)
                    134:                cmd_putstr("Keep-pos ");
                    135:        if (search_type & SRCH_NO_REGEX)
                    136:                cmd_putstr("Regex-off ");
1.1       etheisen  137:
                    138:        if (search_type & SRCH_FORW)
                    139:                cmd_putstr("/");
                    140:        else
                    141:                cmd_putstr("?");
1.6       millert   142:        set_mlist(ml_search, 0);
                    143: }
                    144:
                    145: /*
                    146:  * Set up the display to start a new toggle-option command.
                    147:  */
                    148:        static void
                    149: mca_opt_toggle()
                    150: {
                    151:        int no_prompt;
                    152:        int flag;
                    153:        char *dash;
                    154:
                    155:        no_prompt = (optflag & OPT_NO_PROMPT);
                    156:        flag = (optflag & ~OPT_NO_PROMPT);
                    157:        dash = (flag == OPT_NO_TOGGLE) ? "_" : "-";
                    158:
                    159:        mca = A_OPT_TOGGLE;
                    160:        clear_cmd();
                    161:        cmd_putstr(dash);
1.8     ! millert   162: #if GNU_OPTIONS
1.6       millert   163:        if (optgetname)
                    164:                cmd_putstr(dash);
1.8     ! millert   165: #endif
1.6       millert   166:        if (no_prompt)
                    167:                cmd_putstr("(P)");
                    168:        switch (flag)
                    169:        {
                    170:        case OPT_UNSET:
                    171:                cmd_putstr("+");
                    172:                break;
                    173:        case OPT_SET:
                    174:                cmd_putstr("!");
                    175:                break;
                    176:        }
                    177:        set_mlist(NULL, 0);
1.1       etheisen  178: }
                    179:
                    180: /*
                    181:  * Execute a multicharacter command.
                    182:  */
                    183:        static void
                    184: exec_mca()
                    185: {
1.6       millert   186:        register char *cbuf;
1.1       etheisen  187:
                    188:        cmd_exec();
                    189:        cbuf = get_cmdbuf();
                    190:
                    191:        switch (mca)
                    192:        {
                    193:        case A_F_SEARCH:
                    194:        case A_B_SEARCH:
1.6       millert   195:                multi_search(cbuf, (int) number);
1.1       etheisen  196:                break;
                    197:        case A_FIRSTCMD:
                    198:                /*
                    199:                 * Skip leading spaces or + signs in the string.
                    200:                 */
                    201:                while (*cbuf == '+' || *cbuf == ' ')
                    202:                        cbuf++;
                    203:                if (every_first_cmd != NULL)
                    204:                        free(every_first_cmd);
                    205:                if (*cbuf == '\0')
                    206:                        every_first_cmd = NULL;
                    207:                else
                    208:                        every_first_cmd = save(cbuf);
                    209:                break;
                    210:        case A_OPT_TOGGLE:
                    211:                toggle_option(optchar, cbuf, optflag);
                    212:                optchar = '\0';
                    213:                break;
                    214:        case A_F_BRACKET:
1.6       millert   215:                match_brac(cbuf[0], cbuf[1], 1, (int) number);
1.1       etheisen  216:                break;
                    217:        case A_B_BRACKET:
1.6       millert   218:                match_brac(cbuf[1], cbuf[0], 0, (int) number);
1.1       etheisen  219:                break;
                    220: #if EXAMINE
                    221:        case A_EXAMINE:
1.6       millert   222:                if (secure)
                    223:                        break;
1.1       etheisen  224:                edit_list(cbuf);
1.6       millert   225: #if TAGS
                    226:                /* If tag structure is loaded then clean it up. */
                    227:                cleantags();
                    228: #endif
1.1       etheisen  229:                break;
                    230: #endif
                    231: #if SHELL_ESCAPE
                    232:        case A_SHELL:
                    233:                /*
                    234:                 * !! just uses whatever is in shellcmd.
                    235:                 * Otherwise, copy cmdbuf to shellcmd,
                    236:                 * expanding any special characters ("%" or "#").
                    237:                 */
                    238:                if (*cbuf != '!')
                    239:                {
                    240:                        if (shellcmd != NULL)
                    241:                                free(shellcmd);
                    242:                        shellcmd = fexpand(cbuf);
                    243:                }
                    244:
1.6       millert   245:                if (secure)
                    246:                        break;
1.1       etheisen  247:                if (shellcmd == NULL)
1.6       millert   248:                        lsystem("", "!done");
1.1       etheisen  249:                else
1.6       millert   250:                        lsystem(shellcmd, "!done");
1.1       etheisen  251:                break;
                    252: #endif
                    253: #if PIPEC
                    254:        case A_PIPE:
1.6       millert   255:                if (secure)
                    256:                        break;
1.1       etheisen  257:                (void) pipe_mark(pipec, cbuf);
                    258:                error("|done", NULL_PARG);
                    259:                break;
                    260: #endif
                    261:        }
                    262: }
                    263:
                    264: /*
                    265:  * Add a character to a multi-character command.
                    266:  */
                    267:        static int
                    268: mca_char(c)
                    269:        int c;
                    270: {
                    271:        char *p;
                    272:        int flag;
                    273:        char buf[3];
1.6       millert   274:        PARG parg;
1.1       etheisen  275:
                    276:        switch (mca)
                    277:        {
                    278:        case 0:
                    279:                /*
                    280:                 * Not in a multicharacter command.
                    281:                 */
                    282:                return (NO_MCA);
                    283:
                    284:        case A_PREFIX:
                    285:                /*
                    286:                 * In the prefix of a command.
                    287:                 * This not considered a multichar command
                    288:                 * (even tho it uses cmdbuf, etc.).
                    289:                 * It is handled in the commands() switch.
                    290:                 */
                    291:                return (NO_MCA);
                    292:
                    293:        case A_DIGIT:
                    294:                /*
                    295:                 * Entering digits of a number.
                    296:                 * Terminated by a non-digit.
                    297:                 */
                    298:                if ((c < '0' || c > '9') &&
1.6       millert   299:                  editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID)
1.1       etheisen  300:                {
                    301:                        /*
                    302:                         * Not part of the number.
                    303:                         * Treat as a normal command character.
                    304:                         */
                    305:                        number = cmd_int();
                    306:                        mca = 0;
                    307:                        cmd_accept();
                    308:                        return (NO_MCA);
                    309:                }
                    310:                break;
                    311:
                    312:        case A_OPT_TOGGLE:
                    313:                /*
                    314:                 * Special case for the TOGGLE_OPTION command.
                    315:                 * If the option letter which was entered is a
                    316:                 * single-char option, execute the command immediately,
                    317:                 * so user doesn't have to hit RETURN.
                    318:                 * If the first char is + or -, this indicates
                    319:                 * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE.
1.6       millert   320:                 * "--" begins inputting a long option name.
1.1       etheisen  321:                 */
1.6       millert   322:                if (optchar == '\0' && len_cmdbuf() == 0)
                    323:                {
                    324:                        flag = (optflag & ~OPT_NO_PROMPT);
1.8     ! millert   325: #if GNU_OPTIONS
1.6       millert   326:                        if (flag == OPT_NO_TOGGLE)
                    327:                        {
                    328:                                switch (c)
                    329:                                {
                    330:                                case '_':
                    331:                                        /* "__" = long option name. */
                    332:                                        optgetname = TRUE;
                    333:                                        mca_opt_toggle();
                    334:                                        return (MCA_MORE);
                    335:                                }
                    336:                        } else
1.8     ! millert   337: #endif
1.6       millert   338:                        {
                    339:                                switch (c)
                    340:                                {
                    341:                                case '+':
                    342:                                        /* "-+" = UNSET. */
                    343:                                        optflag = (flag == OPT_UNSET) ?
                    344:                                                OPT_TOGGLE : OPT_UNSET;
                    345:                                        mca_opt_toggle();
                    346:                                        return (MCA_MORE);
                    347:                                case '!':
                    348:                                        /* "-!" = SET */
                    349:                                        optflag = (flag == OPT_SET) ?
                    350:                                                OPT_TOGGLE : OPT_SET;
                    351:                                        mca_opt_toggle();
                    352:                                        return (MCA_MORE);
                    353:                                case CONTROL('P'):
                    354:                                        optflag ^= OPT_NO_PROMPT;
                    355:                                        mca_opt_toggle();
                    356:                                        return (MCA_MORE);
1.8     ! millert   357: #if GNU_OPTIONS
1.6       millert   358:                                case '-':
                    359:                                        /* "--" = long option name. */
                    360:                                        optgetname = TRUE;
                    361:                                        mca_opt_toggle();
                    362:                                        return (MCA_MORE);
1.8     ! millert   363: #endif
1.6       millert   364:                                }
                    365:                        }
                    366:                }
1.8     ! millert   367: #if GNU_OPTIONS
1.6       millert   368:                if (optgetname)
                    369:                {
1.1       etheisen  370:                        /*
1.6       millert   371:                         * We're getting a long option name.
                    372:                         * See if we've matched an option name yet.
                    373:                         * If so, display the complete name and stop
                    374:                         * accepting chars until user hits RETURN.
                    375:                         */
                    376:                        struct loption *o;
                    377:                        char *oname;
                    378:                        int lc;
                    379:
                    380:                        if (c == '\n' || c == '\r')
                    381:                        {
                    382:                                /*
                    383:                                 * When the user hits RETURN, make sure
                    384:                                 * we've matched an option name, then
                    385:                                 * pretend he just entered the equivalent
                    386:                                 * option letter.
                    387:                                 */
                    388:                                if (optchar == '\0')
                    389:                                {
                    390:                                        parg.p_string = get_cmdbuf();
                    391:                                        error("There is no --%s option", &parg);
                    392:                                        return (MCA_DONE);
                    393:                                }
                    394:                                optgetname = FALSE;
                    395:                                cmd_reset();
                    396:                                c = optchar;
                    397:                        } else
1.1       etheisen  398:                        {
1.6       millert   399:                                if (optchar != '\0')
                    400:                                {
                    401:                                        /*
                    402:                                         * Already have a match for the name.
                    403:                                         * Don't accept anything but erase/kill.
                    404:                                         */
                    405:                                        if (c == erase_char || c == kill_char)
                    406:                                                return (MCA_DONE);
                    407:                                        return (MCA_MORE);
                    408:                                }
                    409:                                /*
                    410:                                 * Add char to cmd buffer and try to match
                    411:                                 * the option name.
                    412:                                 */
                    413:                                if (cmd_char(c) == CC_QUIT)
                    414:                                        return (MCA_DONE);
                    415:                                p = get_cmdbuf();
                    416:                                lc = islower(p[0]);
                    417:                                o = findopt_name(&p, &oname, NULL);
                    418:                                if (o != NULL)
                    419:                                {
                    420:                                        /*
                    421:                                         * Got a match.
                    422:                                         * Remember the option letter and
                    423:                                         * display the full option name.
                    424:                                         */
                    425:                                        optchar = o->oletter;
                    426:                                        if (!lc && islower(optchar))
                    427:                                                optchar = toupper(optchar);
                    428:                                        cmd_reset();
                    429:                                        mca_opt_toggle();
                    430:                                        for (p = oname;  *p != '\0';  p++)
                    431:                                        {
                    432:                                                c = *p;
                    433:                                                if (!lc && islower(c))
                    434:                                                        c = toupper(c);
                    435:                                                if (cmd_char(c) != CC_OK)
                    436:                                                        return (MCA_DONE);
                    437:                                        }
                    438:                                }
                    439:                                return (MCA_MORE);
1.1       etheisen  440:                        }
1.6       millert   441:                } else
1.8     ! millert   442: #endif
1.6       millert   443:                {
                    444:                        if (c == erase_char || c == kill_char)
                    445:                                break;
                    446:                        if (optchar != '\0')
                    447:                                /* We already have the option letter. */
                    448:                                break;
1.1       etheisen  449:                }
1.6       millert   450:
                    451:                optchar = c;
                    452:                if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE ||
                    453:                    single_char_option(c))
1.1       etheisen  454:                {
1.6       millert   455:                        toggle_option(c, "", optflag);
                    456:                        return (MCA_DONE);
1.1       etheisen  457:                }
                    458:                /*
                    459:                 * Display a prompt appropriate for the option letter.
                    460:                 */
                    461:                if ((p = opt_prompt(c)) == NULL)
                    462:                {
                    463:                        buf[0] = '-';
                    464:                        buf[1] = c;
                    465:                        buf[2] = '\0';
                    466:                        p = buf;
                    467:                }
1.6       millert   468:                start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0);
1.1       etheisen  469:                return (MCA_MORE);
                    470:
                    471:        case A_F_SEARCH:
                    472:        case A_B_SEARCH:
                    473:                /*
                    474:                 * Special case for search commands.
                    475:                 * Certain characters as the first char of
                    476:                 * the pattern have special meaning:
1.6       millert   477:                 *      !  Toggle the NO_MATCH flag
1.1       etheisen  478:                 *      *  Toggle the PAST_EOF flag
                    479:                 *      @  Toggle the FIRST_FILE flag
                    480:                 */
                    481:                if (len_cmdbuf() > 0)
                    482:                        /*
                    483:                         * Only works for the first char of the pattern.
                    484:                         */
                    485:                        break;
                    486:
                    487:                flag = 0;
                    488:                switch (c)
                    489:                {
1.6       millert   490:                case CONTROL('E'): /* ignore END of file */
                    491:                case '*':
                    492:                        flag = SRCH_PAST_EOF;
1.1       etheisen  493:                        break;
1.6       millert   494:                case CONTROL('F'): /* FIRST file */
1.1       etheisen  495:                case '@':
                    496:                        flag = SRCH_FIRST_FILE;
                    497:                        break;
1.6       millert   498:                case CONTROL('K'): /* KEEP position */
                    499:                        flag = SRCH_NO_MOVE;
                    500:                        break;
                    501:                case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */
                    502:                        flag = SRCH_NO_REGEX;
                    503:                        break;
                    504:                case CONTROL('N'): /* NOT match */
                    505:                case '!':
                    506:                        flag = SRCH_NO_MATCH;
1.1       etheisen  507:                        break;
                    508:                }
                    509:                if (flag != 0)
                    510:                {
                    511:                        search_type ^= flag;
                    512:                        mca_search();
                    513:                        return (MCA_MORE);
                    514:                }
                    515:                break;
                    516:        }
                    517:
                    518:        /*
                    519:         * Any other multicharacter command
                    520:         * is terminated by a newline.
                    521:         */
                    522:        if (c == '\n' || c == '\r')
                    523:        {
                    524:                /*
                    525:                 * Execute the command.
                    526:                 */
                    527:                exec_mca();
                    528:                return (MCA_DONE);
                    529:        }
1.6       millert   530:
1.1       etheisen  531:        /*
                    532:         * Append the char to the command buffer.
                    533:         */
                    534:        if (cmd_char(c) == CC_QUIT)
                    535:                /*
                    536:                 * Abort the multi-char command.
                    537:                 */
                    538:                return (MCA_DONE);
                    539:
                    540:        if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2)
                    541:        {
                    542:                /*
                    543:                 * Special case for the bracket-matching commands.
                    544:                 * Execute the command after getting exactly two
                    545:                 * characters from the user.
                    546:                 */
                    547:                exec_mca();
                    548:                return (MCA_DONE);
                    549:        }
                    550:
                    551:        /*
                    552:         * Need another character.
                    553:         */
                    554:        return (MCA_MORE);
                    555: }
                    556:
                    557: /*
1.6       millert   558:  * Make sure the screen is displayed.
1.1       etheisen  559:  */
                    560:        static void
1.6       millert   561: make_display()
1.1       etheisen  562: {
                    563:        /*
                    564:         * If nothing is displayed yet, display starting from initial_scrpos.
                    565:         */
                    566:        if (empty_screen())
                    567:        {
                    568:                if (initial_scrpos.pos == NULL_POSITION)
                    569:                        /*
                    570:                         * {{ Maybe this should be:
                    571:                         *    jump_loc(ch_zero(), jump_sline);
                    572:                         *    but this behavior seems rather unexpected
                    573:                         *    on the first screen. }}
                    574:                         */
                    575:                        jump_loc(ch_zero(), 1);
                    576:                else
                    577:                        jump_loc(initial_scrpos.pos, initial_scrpos.ln);
                    578:        } else if (screen_trashed)
                    579:        {
                    580:                int save_top_scroll;
                    581:                save_top_scroll = top_scroll;
                    582:                top_scroll = 1;
                    583:                repaint();
                    584:                top_scroll = save_top_scroll;
                    585:        }
1.6       millert   586: }
                    587:
                    588: /*
                    589:  * Display the appropriate prompt.
                    590:  */
                    591:        static void
                    592: prompt()
                    593: {
                    594:        register char *p;
                    595:
                    596:        if (ungotp != NULL && ungotp > ungot)
                    597:        {
                    598:                /*
                    599:                 * No prompt necessary if commands are from
                    600:                 * ungotten chars rather than from the user.
                    601:                 */
                    602:                return;
                    603:        }
                    604:
                    605:        /*
                    606:         * Make sure the screen is displayed.
                    607:         */
                    608:        make_display();
                    609:        bottompos = position(BOTTOM_PLUS_ONE);
1.1       etheisen  610:
                    611:        /*
                    612:         * If the -E flag is set and we've hit EOF on the last file, quit.
                    613:         */
1.6       millert   614:        if ((quit_at_eof == OPT_ONPLUS || quit_if_one_screen) &&
1.7       millert   615:            hit_eof && next_ifile(curr_ifile) == NULL_IFILE)
1.1       etheisen  616:                quit(QUIT_OK);
1.6       millert   617:        quit_if_one_screen = FALSE;
                    618: #if 0 /* This doesn't work well because some "te"s clear the screen. */
                    619:        /*
                    620:         * If the -e flag is set and we've hit EOF on the last file,
                    621:         * and the file is squished (shorter than the screen), quit.
                    622:         */
                    623:        if (quit_at_eof && squished &&
                    624:            next_ifile(curr_ifile) == NULL_IFILE)
                    625:                quit(QUIT_OK);
                    626: #endif
1.1       etheisen  627:
                    628:        /*
                    629:         * Select the proper prompt and display it.
                    630:         */
1.6       millert   631:        clear_cmd();
                    632:        p = help_prompt ? help_prompt : pr_string();
                    633:        if (p == NULL)
                    634:                putchr(':');
                    635:        else
                    636:        {
1.1       etheisen  637:                so_enter();
1.6       millert   638:                putstr(p);
                    639:                if (be_helpful && !help_prompt && strlen(p) + 40 < sc_width)
                    640:                        putstr(" [Press space to continue, 'q' to quit.]");
1.1       etheisen  641:                so_exit();
                    642:        }
1.6       millert   643:        help_prompt = NULL;
1.1       etheisen  644: }
                    645:
1.6       millert   646: /*
                    647:  * Display the less version message.
                    648:  */
1.1       etheisen  649:        public void
                    650: dispversion()
                    651: {
                    652:        PARG parg;
                    653:
                    654:        parg.p_string = version;
1.6       millert   655:        error("less %s", &parg);
1.1       etheisen  656: }
                    657:
                    658: /*
                    659:  * Get command character.
                    660:  * The character normally comes from the keyboard,
                    661:  * but may come from ungotten characters
                    662:  * (characters previously given to ungetcc or ungetsc).
                    663:  */
                    664:        public int
                    665: getcc()
                    666: {
                    667:        if (ungotp == NULL)
                    668:                /*
                    669:                 * Normal case: no ungotten chars, so get one from the user.
                    670:                 */
                    671:                return (getchr());
                    672:
                    673:        if (ungotp > ungot)
                    674:                /*
                    675:                 * Return the next ungotten char.
                    676:                 */
                    677:                return (*--ungotp);
                    678:
                    679:        /*
                    680:         * We have just run out of ungotten chars.
                    681:         */
                    682:        ungotp = NULL;
                    683:        if (len_cmdbuf() == 0 || !empty_screen())
                    684:                return (getchr());
                    685:        /*
                    686:         * Command is incomplete, so try to complete it.
                    687:         */
                    688:        switch (mca)
                    689:        {
                    690:        case A_DIGIT:
                    691:                /*
                    692:                 * We have a number but no command.  Treat as #g.
                    693:                 */
                    694:                return ('g');
                    695:
                    696:        case A_F_SEARCH:
                    697:        case A_B_SEARCH:
                    698:                /*
                    699:                 * We have "/string" but no newline.  Add the \n.
                    700:                 */
                    701:                return ('\n');
                    702:
                    703:        default:
                    704:                /*
                    705:                 * Some other incomplete command.  Let user complete it.
                    706:                 */
                    707:                return (getchr());
                    708:        }
                    709: }
                    710:
                    711: /*
                    712:  * "Unget" a command character.
                    713:  * The next getcc() will return this character.
                    714:  */
                    715:        public void
                    716: ungetcc(c)
                    717:        int c;
                    718: {
                    719:        if (ungotp == NULL)
                    720:                ungotp = ungot;
                    721:        if (ungotp >= ungot + sizeof(ungot))
                    722:        {
                    723:                error("ungetcc overflow", NULL_PARG);
                    724:                quit(QUIT_ERROR);
                    725:        }
                    726:        *ungotp++ = c;
                    727: }
                    728:
                    729: /*
                    730:  * Unget a whole string of command characters.
                    731:  * The next sequence of getcc()'s will return this string.
                    732:  */
                    733:        public void
                    734: ungetsc(s)
                    735:        char *s;
                    736: {
1.6       millert   737:        register char *p;
1.1       etheisen  738:
                    739:        for (p = s + strlen(s) - 1;  p >= s;  p--)
                    740:                ungetcc(*p);
                    741: }
                    742:
                    743: /*
                    744:  * Search for a pattern, possibly in multiple files.
                    745:  * If SRCH_FIRST_FILE is set, begin searching at the first file.
                    746:  * If SRCH_PAST_EOF is set, continue the search thru multiple files.
                    747:  */
                    748:        static void
                    749: multi_search(pattern, n)
                    750:        char *pattern;
                    751:        int n;
                    752: {
1.6       millert   753:        register int nomore;
1.1       etheisen  754:        IFILE save_ifile;
                    755:        int changed_file;
                    756:
                    757:        changed_file = 0;
1.6       millert   758:        save_ifile = save_curr_ifile();
1.1       etheisen  759:
                    760:        if (search_type & SRCH_FIRST_FILE)
                    761:        {
                    762:                /*
                    763:                 * Start at the first (or last) file
                    764:                 * in the command line list.
                    765:                 */
                    766:                if (search_type & SRCH_FORW)
                    767:                        nomore = edit_first();
                    768:                else
                    769:                        nomore = edit_last();
                    770:                if (nomore)
1.6       millert   771:                {
                    772:                        unsave_ifile(save_ifile);
1.1       etheisen  773:                        return;
1.6       millert   774:                }
1.1       etheisen  775:                changed_file = 1;
                    776:                search_type &= ~SRCH_FIRST_FILE;
                    777:        }
                    778:
                    779:        for (;;)
                    780:        {
1.6       millert   781:                n = search(search_type, pattern, n);
                    782:                /*
                    783:                 * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared
                    784:                 * after being used once.  This allows "n" to work after
                    785:                 * using a /@@ search.
                    786:                 */
                    787:                search_type &= ~SRCH_NO_MOVE;
                    788:                if (n == 0)
                    789:                {
1.1       etheisen  790:                        /*
                    791:                         * Found it.
                    792:                         */
1.6       millert   793:                        unsave_ifile(save_ifile);
1.1       etheisen  794:                        return;
1.6       millert   795:                }
1.1       etheisen  796:
                    797:                if (n < 0)
                    798:                        /*
                    799:                         * Some kind of error in the search.
                    800:                         * Error message has been printed by search().
                    801:                         */
                    802:                        break;
                    803:
                    804:                if ((search_type & SRCH_PAST_EOF) == 0)
                    805:                        /*
                    806:                         * We didn't find a match, but we're
                    807:                         * supposed to search only one file.
                    808:                         */
                    809:                        break;
                    810:                /*
                    811:                 * Move on to the next file.
                    812:                 */
                    813:                if (search_type & SRCH_FORW)
                    814:                        nomore = edit_next(1);
                    815:                else
                    816:                        nomore = edit_prev(1);
                    817:                if (nomore)
                    818:                        break;
                    819:                changed_file = 1;
                    820:        }
                    821:
                    822:        /*
                    823:         * Didn't find it.
                    824:         * Print an error message if we haven't already.
                    825:         */
                    826:        if (n > 0)
                    827:                error("Pattern not found", NULL_PARG);
                    828:
                    829:        if (changed_file)
                    830:        {
                    831:                /*
                    832:                 * Restore the file we were originally viewing.
                    833:                 */
1.6       millert   834:                reedit_ifile(save_ifile);
1.1       etheisen  835:        }
                    836: }
                    837:
                    838: /*
                    839:  * Main command processor.
                    840:  * Accept and execute commands until a quit command.
                    841:  */
                    842:        public void
                    843: commands()
                    844: {
1.6       millert   845:        register int c;
                    846:        register int action;
                    847:        register char *cbuf;
                    848:        int newaction;
1.1       etheisen  849:        int save_search_type;
1.6       millert   850:        char *extra;
1.1       etheisen  851:        char tbuf[2];
                    852:        PARG parg;
1.6       millert   853:        IFILE old_ifile;
                    854:        IFILE new_ifile;
                    855:        char *tagfile;
1.1       etheisen  856:
                    857:        search_type = SRCH_FORW;
                    858:        wscroll = (sc_height + 1) / 2;
1.6       millert   859:        newaction = A_NOACTION;
1.1       etheisen  860:
                    861:        for (;;)
                    862:        {
                    863:                mca = 0;
                    864:                cmd_accept();
                    865:                number = 0;
                    866:                optchar = '\0';
                    867:
                    868:                /*
                    869:                 * See if any signals need processing.
                    870:                 */
                    871:                if (sigs)
                    872:                {
                    873:                        psignals();
                    874:                        if (quitting)
                    875:                                quit(QUIT_SAVED_STATUS);
                    876:                }
1.6       millert   877:
                    878:                /*
                    879:                 * See if window size changed, for systems that don't
                    880:                 * generate SIGWINCH.
                    881:                 */
                    882:                check_winch();
                    883:
1.1       etheisen  884:                /*
                    885:                 * Display prompt and accept a character.
                    886:                 */
                    887:                cmd_reset();
                    888:                prompt();
                    889:                if (sigs)
                    890:                        continue;
1.6       millert   891:                if (newaction == A_NOACTION)
                    892:                        c = getcc();
1.1       etheisen  893:
                    894:        again:
                    895:                if (sigs)
                    896:                        continue;
                    897:
1.6       millert   898:                if (newaction != A_NOACTION)
                    899:                {
                    900:                        action = newaction;
                    901:                        newaction = A_NOACTION;
                    902:                } else
                    903:                {
                    904:                        /*
                    905:                         * If we are in a multicharacter command, call mca_char.
                    906:                         * Otherwise we call fcmd_decode to determine the
                    907:                         * action to be performed.
                    908:                         */
                    909:                        if (mca)
                    910:                                switch (mca_char(c))
                    911:                                {
                    912:                                case MCA_MORE:
                    913:                                        /*
                    914:                                         * Need another character.
                    915:                                         */
                    916:                                        c = getcc();
                    917:                                        goto again;
                    918:                                case MCA_DONE:
                    919:                                        /*
                    920:                                         * Command has been handled by mca_char.
                    921:                                         * Start clean with a prompt.
                    922:                                         */
                    923:                                        continue;
                    924:                                case NO_MCA:
                    925:                                        /*
                    926:                                         * Not a multi-char command
                    927:                                         * (at least, not anymore).
                    928:                                         */
                    929:                                        break;
                    930:                                }
                    931:
                    932:                        /*
                    933:                         * Decode the command character and decide what to do.
                    934:                         */
                    935:                        if (mca)
1.1       etheisen  936:                        {
                    937:                                /*
1.6       millert   938:                                 * We're in a multichar command.
                    939:                                 * Add the character to the command buffer
                    940:                                 * and display it on the screen.
                    941:                                 * If the user backspaces past the start
                    942:                                 * of the line, abort the command.
1.1       etheisen  943:                                 */
1.6       millert   944:                                if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
                    945:                                        continue;
                    946:                                cbuf = get_cmdbuf();
                    947:                        } else
                    948:                        {
1.1       etheisen  949:                                /*
1.6       millert   950:                                 * Don't use cmd_char if we're starting fresh
                    951:                                 * at the beginning of a command, because we
                    952:                                 * don't want to echo the command until we know
                    953:                                 * it is a multichar command.  We also don't
                    954:                                 * want erase_char/kill_char to be treated
                    955:                                 * as line editing characters.
1.1       etheisen  956:                                 */
1.6       millert   957:                                tbuf[0] = c;
                    958:                                tbuf[1] = '\0';
                    959:                                cbuf = tbuf;
1.1       etheisen  960:                        }
1.6       millert   961:                        extra = NULL;
                    962:                        action = fcmd_decode(cbuf, &extra);
1.1       etheisen  963:                        /*
1.6       millert   964:                         * If an "extra" string was returned,
                    965:                         * process it as a string of command characters.
                    966:                         */
                    967:                        if (extra != NULL)
                    968:                                ungetsc(extra);
1.1       etheisen  969:                }
                    970:                /*
                    971:                 * Clear the cmdbuf string.
                    972:                 * (But not if we're in the prefix of a command,
                    973:                 * because the partial command string is kept there.)
                    974:                 */
                    975:                if (action != A_PREFIX)
                    976:                        cmd_reset();
                    977:
                    978:                switch (action)
                    979:                {
                    980:                case A_DIGIT:
                    981:                        /*
                    982:                         * First digit of a number.
                    983:                         */
1.6       millert   984:                        start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1.1       etheisen  985:                        goto again;
                    986:
                    987:                case A_F_WINDOW:
                    988:                        /*
                    989:                         * Forward one window (and set the window size).
                    990:                         */
                    991:                        if (number > 0)
1.6       millert   992:                                swindow = (int) number;
1.1       etheisen  993:                        /* FALLTHRU */
                    994:                case A_F_SCREEN:
                    995:                        /*
                    996:                         * Forward one screen.
                    997:                         */
                    998:                        if (number <= 0)
                    999:                                number = get_swindow();
                   1000:                        cmd_exec();
1.6       millert  1001:                        if (show_attn)
                   1002:                                set_attnpos(bottompos);
                   1003:                        forward((int) number, 0, 1);
1.1       etheisen 1004:                        break;
                   1005:
                   1006:                case A_B_WINDOW:
                   1007:                        /*
                   1008:                         * Backward one window (and set the window size).
                   1009:                         */
                   1010:                        if (number > 0)
1.6       millert  1011:                                swindow = (int) number;
1.1       etheisen 1012:                        /* FALLTHRU */
                   1013:                case A_B_SCREEN:
                   1014:                        /*
                   1015:                         * Backward one screen.
                   1016:                         */
                   1017:                        if (number <= 0)
                   1018:                                number = get_swindow();
                   1019:                        cmd_exec();
1.6       millert  1020:                        backward((int) number, 0, 1);
1.1       etheisen 1021:                        break;
                   1022:
                   1023:                case A_F_LINE:
                   1024:                        /*
                   1025:                         * Forward N (default 1) line.
                   1026:                         */
                   1027:                        if (number <= 0)
                   1028:                                number = 1;
                   1029:                        cmd_exec();
1.6       millert  1030:                        if (show_attn == OPT_ONPLUS && number > 1)
                   1031:                                set_attnpos(bottompos);
                   1032:                        forward((int) number, 0, 0);
1.1       etheisen 1033:                        break;
                   1034:
                   1035:                case A_B_LINE:
                   1036:                        /*
                   1037:                         * Backward N (default 1) line.
                   1038:                         */
                   1039:                        if (number <= 0)
                   1040:                                number = 1;
                   1041:                        cmd_exec();
1.6       millert  1042:                        backward((int) number, 0, 0);
1.1       etheisen 1043:                        break;
                   1044:
                   1045:                case A_FF_LINE:
                   1046:                        /*
                   1047:                         * Force forward N (default 1) line.
                   1048:                         */
                   1049:                        if (number <= 0)
                   1050:                                number = 1;
                   1051:                        cmd_exec();
1.6       millert  1052:                        if (show_attn == OPT_ONPLUS && number > 1)
                   1053:                                set_attnpos(bottompos);
                   1054:                        forward((int) number, 1, 0);
1.1       etheisen 1055:                        break;
                   1056:
                   1057:                case A_BF_LINE:
                   1058:                        /*
                   1059:                         * Force backward N (default 1) line.
                   1060:                         */
                   1061:                        if (number <= 0)
                   1062:                                number = 1;
                   1063:                        cmd_exec();
1.6       millert  1064:                        backward((int) number, 1, 0);
1.1       etheisen 1065:                        break;
                   1066:
1.6       millert  1067:                case A_FF_SCREEN:
                   1068:                        /*
                   1069:                         * Force forward one screen.
                   1070:                         */
                   1071:                        if (number <= 0)
                   1072:                                number = get_swindow();
                   1073:                        cmd_exec();
                   1074:                        if (show_attn == OPT_ONPLUS)
                   1075:                                set_attnpos(bottompos);
                   1076:                        forward((int) number, 1, 0);
                   1077:                        break;
                   1078:
1.1       etheisen 1079:                case A_F_FOREVER:
                   1080:                        /*
                   1081:                         * Forward forever, ignoring EOF.
                   1082:                         */
                   1083:                        cmd_exec();
                   1084:                        jump_forw();
                   1085:                        ignore_eoi = 1;
                   1086:                        hit_eof = 0;
1.6       millert  1087:                        while (!sigs)
1.1       etheisen 1088:                                forward(1, 0, 0);
                   1089:                        ignore_eoi = 0;
1.6       millert  1090:                        /*
                   1091:                         * This gets us back in "F mode" after processing
                   1092:                         * a non-abort signal (e.g. window-change).
                   1093:                         */
                   1094:                        if (sigs && !ABORT_SIGS())
                   1095:                                newaction = A_F_FOREVER;
1.1       etheisen 1096:                        break;
                   1097:
                   1098:                case A_F_SCROLL:
                   1099:                        /*
                   1100:                         * Forward N lines
                   1101:                         * (default same as last 'd' or 'u' command).
                   1102:                         */
                   1103:                        if (number > 0)
1.6       millert  1104:                                wscroll = (int) number;
1.1       etheisen 1105:                        cmd_exec();
1.6       millert  1106:                        if (show_attn == OPT_ONPLUS)
                   1107:                                set_attnpos(bottompos);
1.1       etheisen 1108:                        forward(wscroll, 0, 0);
                   1109:                        break;
                   1110:
                   1111:                case A_B_SCROLL:
                   1112:                        /*
                   1113:                         * Forward N lines
                   1114:                         * (default same as last 'd' or 'u' command).
                   1115:                         */
                   1116:                        if (number > 0)
1.6       millert  1117:                                wscroll = (int) number;
1.1       etheisen 1118:                        cmd_exec();
                   1119:                        backward(wscroll, 0, 0);
                   1120:                        break;
                   1121:
                   1122:                case A_FREPAINT:
                   1123:                        /*
                   1124:                         * Flush buffers, then repaint screen.
                   1125:                         * Don't flush the buffers on a pipe!
                   1126:                         */
                   1127:                        if (ch_getflags() & CH_CANSEEK)
                   1128:                        {
                   1129:                                ch_flush();
                   1130:                                clr_linenum();
1.6       millert  1131: #if HILITE_SEARCH
                   1132:                                clr_hilite();
                   1133: #endif
1.1       etheisen 1134:                        }
                   1135:                        /* FALLTHRU */
                   1136:                case A_REPAINT:
                   1137:                        /*
                   1138:                         * Repaint screen.
                   1139:                         */
                   1140:                        cmd_exec();
                   1141:                        repaint();
                   1142:                        break;
                   1143:
                   1144:                case A_GOLINE:
                   1145:                        /*
                   1146:                         * Go to line N, default beginning of file.
                   1147:                         */
                   1148:                        if (number <= 0)
                   1149:                                number = 1;
                   1150:                        cmd_exec();
                   1151:                        jump_back(number);
                   1152:                        break;
                   1153:
                   1154:                case A_PERCENT:
                   1155:                        /*
                   1156:                         * Go to a specified percentage into the file.
                   1157:                         */
                   1158:                        if (number < 0)
                   1159:                                number = 0;
                   1160:                        if (number > 100)
                   1161:                                number = 100;
                   1162:                        cmd_exec();
1.6       millert  1163:                        jump_percent((int) number);
1.1       etheisen 1164:                        break;
                   1165:
                   1166:                case A_GOEND:
                   1167:                        /*
                   1168:                         * Go to line N, default end of file.
                   1169:                         */
                   1170:                        cmd_exec();
                   1171:                        if (number <= 0)
                   1172:                                jump_forw();
                   1173:                        else
                   1174:                                jump_back(number);
                   1175:                        break;
                   1176:
                   1177:                case A_GOPOS:
                   1178:                        /*
                   1179:                         * Go to a specified byte position in the file.
                   1180:                         */
                   1181:                        cmd_exec();
                   1182:                        if (number < 0)
                   1183:                                number = 0;
1.6       millert  1184:                        jump_line_loc((POSITION) number, jump_sline);
1.1       etheisen 1185:                        break;
                   1186:
                   1187:                case A_STAT:
                   1188:                        /*
                   1189:                         * Print file name, etc.
                   1190:                         */
                   1191:                        cmd_exec();
                   1192:                        parg.p_string = eq_message();
                   1193:                        error("%s", &parg);
                   1194:                        break;
1.6       millert  1195:
1.1       etheisen 1196:                case A_VERSION:
                   1197:                        /*
                   1198:                         * Print version number, without the "@(#)".
                   1199:                         */
                   1200:                        cmd_exec();
                   1201:                        dispversion();
                   1202:                        break;
                   1203:
                   1204:                case A_QUIT:
                   1205:                        /*
                   1206:                         * Exit.
                   1207:                         */
1.6       millert  1208:                        if (extra != NULL)
                   1209:                                quit(*extra);
1.1       etheisen 1210:                        quit(QUIT_OK);
1.6       millert  1211:                        break;
1.1       etheisen 1212:
                   1213: /*
                   1214:  * Define abbreviation for a commonly used sequence below.
                   1215:  */
                   1216: #define        DO_SEARCH()     if (number <= 0) number = 1;    \
                   1217:                        mca_search();                   \
                   1218:                        cmd_exec();                     \
1.6       millert  1219:                        multi_search((char *)NULL, (int) number);
1.1       etheisen 1220:
                   1221:
                   1222:                case A_F_SEARCH:
                   1223:                        /*
                   1224:                         * Search forward for a pattern.
                   1225:                         * Get the first char of the pattern.
                   1226:                         */
                   1227:                        search_type = SRCH_FORW;
                   1228:                        if (number <= 0)
                   1229:                                number = 1;
                   1230:                        mca_search();
                   1231:                        c = getcc();
                   1232:                        goto again;
                   1233:
                   1234:                case A_B_SEARCH:
                   1235:                        /*
                   1236:                         * Search backward for a pattern.
                   1237:                         * Get the first char of the pattern.
                   1238:                         */
                   1239:                        search_type = SRCH_BACK;
                   1240:                        if (number <= 0)
                   1241:                                number = 1;
                   1242:                        mca_search();
                   1243:                        c = getcc();
                   1244:                        goto again;
                   1245:
                   1246:                case A_AGAIN_SEARCH:
                   1247:                        /*
                   1248:                         * Repeat previous search.
                   1249:                         */
                   1250:                        DO_SEARCH();
                   1251:                        break;
                   1252:
                   1253:                case A_T_AGAIN_SEARCH:
                   1254:                        /*
                   1255:                         * Repeat previous search, multiple files.
                   1256:                         */
                   1257:                        search_type |= SRCH_PAST_EOF;
                   1258:                        DO_SEARCH();
                   1259:                        break;
                   1260:
                   1261:                case A_REVERSE_SEARCH:
                   1262:                        /*
                   1263:                         * Repeat previous search, in reverse direction.
                   1264:                         */
                   1265:                        save_search_type = search_type;
                   1266:                        search_type = SRCH_REVERSE(search_type);
                   1267:                        DO_SEARCH();
                   1268:                        search_type = save_search_type;
                   1269:                        break;
                   1270:
                   1271:                case A_T_REVERSE_SEARCH:
                   1272:                        /*
                   1273:                         * Repeat previous search,
                   1274:                         * multiple files in reverse direction.
                   1275:                         */
                   1276:                        save_search_type = search_type;
                   1277:                        search_type = SRCH_REVERSE(search_type);
                   1278:                        search_type |= SRCH_PAST_EOF;
                   1279:                        DO_SEARCH();
                   1280:                        search_type = save_search_type;
                   1281:                        break;
                   1282:
                   1283:                case A_UNDO_SEARCH:
                   1284:                        undo_search();
                   1285:                        break;
                   1286:
                   1287:                case A_HELP:
                   1288:                        /*
                   1289:                         * Help.
                   1290:                         */
1.7       millert  1291:                        if (nohelp)
                   1292:                        {
                   1293:                                bell();
1.1       etheisen 1294:                                break;
1.7       millert  1295:                        }
                   1296:                        clear_bot();
                   1297:                        putstr(" help");
1.1       etheisen 1298:                        cmd_exec();
1.7       millert  1299:                        help(0);
1.1       etheisen 1300:                        break;
                   1301:
                   1302:                case A_EXAMINE:
                   1303: #if EXAMINE
                   1304:                        /*
                   1305:                         * Edit a new file.  Get the filename.
                   1306:                         */
1.6       millert  1307:                        if (secure)
                   1308:                        {
                   1309:                                error("Command not available", NULL_PARG);
                   1310:                                break;
                   1311:                        }
                   1312:                        start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1.1       etheisen 1313:                        c = getcc();
                   1314:                        goto again;
                   1315: #else
                   1316:                        error("Command not available", NULL_PARG);
                   1317:                        break;
                   1318: #endif
                   1319:
                   1320:                case A_VISUAL:
                   1321:                        /*
                   1322:                         * Invoke an editor on the input file.
                   1323:                         */
                   1324: #if EDITOR
1.6       millert  1325:                        if (secure)
                   1326:                        {
                   1327:                                error("Command not available", NULL_PARG);
                   1328:                                break;
                   1329:                        }
1.1       etheisen 1330:                        if (strcmp(get_filename(curr_ifile), "-") == 0)
                   1331:                        {
                   1332:                                error("Cannot edit standard input", NULL_PARG);
                   1333:                                break;
                   1334:                        }
                   1335:                        if (curr_altfilename != NULL)
                   1336:                        {
                   1337:                                error("Cannot edit file processed with LESSOPEN",
                   1338:                                        NULL_PARG);
                   1339:                                break;
                   1340:                        }
1.6       millert  1341:                        start_mca(A_SHELL, "!", ml_shell, 0);
1.1       etheisen 1342:                        /*
                   1343:                         * Expand the editor prototype string
                   1344:                         * and pass it to the system to execute.
1.6       millert  1345:                         * (Make sure the screen is displayed so the
                   1346:                         * expansion of "+%lm" works.)
1.1       etheisen 1347:                         */
1.6       millert  1348:                        make_display();
1.1       etheisen 1349:                        cmd_exec();
1.6       millert  1350:                        lsystem(pr_expand(editproto, 0), (char*)NULL);
1.1       etheisen 1351:                        break;
                   1352: #else
                   1353:                        error("Command not available", NULL_PARG);
                   1354:                        break;
                   1355: #endif
                   1356:
                   1357:                case A_NEXT_FILE:
                   1358:                        /*
                   1359:                         * Examine next file.
                   1360:                         */
1.6       millert  1361: #if TAGS
                   1362:                        if (ntags())
                   1363:                        {
                   1364:                                error("No next file", NULL_PARG);
                   1365:                                break;
                   1366:                        }
                   1367: #endif
1.1       etheisen 1368:                        if (number <= 0)
                   1369:                                number = 1;
1.6       millert  1370:                        if (edit_next((int) number))
1.1       etheisen 1371:                        {
1.7       millert  1372:                                if (quit_at_eof && hit_eof)
1.1       etheisen 1373:                                        quit(QUIT_OK);
                   1374:                                parg.p_string = (number > 1) ? "(N-th) " : "";
                   1375:                                error("No %snext file", &parg);
                   1376:                        }
                   1377:                        break;
                   1378:
                   1379:                case A_PREV_FILE:
                   1380:                        /*
                   1381:                         * Examine previous file.
                   1382:                         */
1.6       millert  1383: #if TAGS
                   1384:                        if (ntags())
                   1385:                        {
                   1386:                                error("No previous file", NULL_PARG);
                   1387:                                break;
                   1388:                        }
                   1389: #endif
1.1       etheisen 1390:                        if (number <= 0)
                   1391:                                number = 1;
1.6       millert  1392:                        if (edit_prev((int) number))
1.1       etheisen 1393:                        {
                   1394:                                parg.p_string = (number > 1) ? "(N-th) " : "";
                   1395:                                error("No %sprevious file", &parg);
                   1396:                        }
                   1397:                        break;
                   1398:
1.6       millert  1399:                case A_NEXT_TAG:
                   1400: #if TAGS
                   1401:                        if (number <= 0)
                   1402:                                number = 1;
                   1403:                        tagfile = nexttag((int) number);
                   1404:                        if (tagfile == NULL)
                   1405:                        {
                   1406:                                error("No next tag", NULL_PARG);
                   1407:                                break;
                   1408:                        }
                   1409:                        if (edit(tagfile) == 0)
                   1410:                        {
                   1411:                                POSITION pos = tagsearch();
                   1412:                                if (pos != NULL_POSITION)
                   1413:                                        jump_loc(pos, jump_sline);
                   1414:                        }
                   1415: #else
                   1416:                        error("Command not available", NULL_PARG);
                   1417: #endif
                   1418:                        break;
                   1419:
                   1420:                case A_PREV_TAG:
                   1421: #if TAGS
                   1422:                        if (number <= 0)
                   1423:                                number = 1;
                   1424:                        tagfile = prevtag((int) number);
                   1425:                        if (tagfile == NULL)
                   1426:                        {
                   1427:                                error("No previous tag", NULL_PARG);
                   1428:                                break;
                   1429:                        }
                   1430:                        if (edit(tagfile) == 0)
                   1431:                        {
                   1432:                                POSITION pos = tagsearch();
                   1433:                                if (pos != NULL_POSITION)
                   1434:                                        jump_loc(pos, jump_sline);
                   1435:                        }
                   1436: #else
                   1437:                        error("Command not available", NULL_PARG);
                   1438: #endif
                   1439:                        break;
                   1440:
1.1       etheisen 1441:                case A_INDEX_FILE:
                   1442:                        /*
                   1443:                         * Examine a particular file.
                   1444:                         */
                   1445:                        if (number <= 0)
                   1446:                                number = 1;
1.6       millert  1447:                        if (edit_index((int) number))
1.1       etheisen 1448:                                error("No such file", NULL_PARG);
                   1449:                        break;
                   1450:
1.6       millert  1451:                case A_REMOVE_FILE:
                   1452:                        old_ifile = curr_ifile;
                   1453:                        new_ifile = getoff_ifile(curr_ifile);
                   1454:                        if (new_ifile == NULL_IFILE)
                   1455:                        {
                   1456:                                bell();
                   1457:                                break;
                   1458:                        }
                   1459:                        if (edit_ifile(new_ifile) != 0)
                   1460:                        {
                   1461:                                reedit_ifile(old_ifile);
                   1462:                                break;
                   1463:                        }
                   1464:                        del_ifile(old_ifile);
                   1465:                        break;
                   1466:
1.1       etheisen 1467:                case A_OPT_TOGGLE:
                   1468:                        optflag = OPT_TOGGLE;
1.6       millert  1469:                        optgetname = FALSE;
                   1470:                        mca_opt_toggle();
1.1       etheisen 1471:                        c = getcc();
                   1472:                        goto again;
                   1473:
                   1474:                case A_DISP_OPTION:
                   1475:                        /*
                   1476:                         * Report a flag setting.
                   1477:                         */
1.6       millert  1478:                        optflag = OPT_NO_TOGGLE;
                   1479:                        optgetname = FALSE;
                   1480:                        mca_opt_toggle();
1.1       etheisen 1481:                        c = getcc();
1.6       millert  1482:                        goto again;
1.1       etheisen 1483:
                   1484:                case A_FIRSTCMD:
                   1485:                        /*
                   1486:                         * Set an initial command for new files.
                   1487:                         */
1.6       millert  1488:                        start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1.1       etheisen 1489:                        c = getcc();
                   1490:                        goto again;
                   1491:
                   1492:                case A_SHELL:
                   1493:                        /*
                   1494:                         * Shell escape.
                   1495:                         */
                   1496: #if SHELL_ESCAPE
1.6       millert  1497:                        if (secure)
                   1498:                        {
                   1499:                                error("Command not available", NULL_PARG);
                   1500:                                break;
                   1501:                        }
                   1502:                        start_mca(A_SHELL, "!", ml_shell, 0);
1.1       etheisen 1503:                        c = getcc();
                   1504:                        goto again;
                   1505: #else
                   1506:                        error("Command not available", NULL_PARG);
                   1507:                        break;
                   1508: #endif
                   1509:
                   1510:                case A_SETMARK:
                   1511:                        /*
                   1512:                         * Set a mark.
                   1513:                         */
1.6       millert  1514:                        start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
1.1       etheisen 1515:                        c = getcc();
                   1516:                        if (c == erase_char || c == kill_char ||
                   1517:                            c == '\n' || c == '\r')
                   1518:                                break;
                   1519:                        setmark(c);
                   1520:                        break;
                   1521:
                   1522:                case A_GOMARK:
                   1523:                        /*
                   1524:                         * Go to a mark.
                   1525:                         */
1.6       millert  1526:                        start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1.1       etheisen 1527:                        c = getcc();
                   1528:                        if (c == erase_char || c == kill_char ||
                   1529:                            c == '\n' || c == '\r')
                   1530:                                break;
                   1531:                        gomark(c);
                   1532:                        break;
                   1533:
                   1534:                case A_PIPE:
                   1535: #if PIPEC
1.6       millert  1536:                        if (secure)
                   1537:                        {
                   1538:                                error("Command not available", NULL_PARG);
                   1539:                                break;
                   1540:                        }
                   1541:                        start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1.1       etheisen 1542:                        c = getcc();
                   1543:                        if (c == erase_char || c == kill_char)
                   1544:                                break;
                   1545:                        if (c == '\n' || c == '\r')
                   1546:                                c = '.';
                   1547:                        if (badmark(c))
                   1548:                                break;
                   1549:                        pipec = c;
1.6       millert  1550:                        start_mca(A_PIPE, "!", ml_shell, 0);
1.1       etheisen 1551:                        c = getcc();
                   1552:                        goto again;
                   1553: #else
                   1554:                        error("Command not available", NULL_PARG);
                   1555:                        break;
                   1556: #endif
                   1557:
                   1558:                case A_B_BRACKET:
                   1559:                case A_F_BRACKET:
1.6       millert  1560:                        start_mca(action, "Brackets: ", (void*)NULL, 0);
1.1       etheisen 1561:                        c = getcc();
                   1562:                        goto again;
                   1563:
1.6       millert  1564:                case A_LSHIFT:
                   1565:                        if (number > 0)
                   1566:                                shift_count = number;
                   1567:                        else
                   1568:                                number = (shift_count > 0) ?
                   1569:                                        shift_count : sc_width / 2;
                   1570:                        if (number > hshift)
                   1571:                                number = hshift;
                   1572:                        hshift -= number;
                   1573:                        screen_trashed = 1;
                   1574:                        break;
                   1575:
                   1576:                case A_RSHIFT:
                   1577:                        if (number > 0)
                   1578:                                shift_count = number;
                   1579:                        else
                   1580:                                number = (shift_count > 0) ?
                   1581:                                        shift_count : sc_width / 2;
                   1582:                        hshift += number;
                   1583:                        screen_trashed = 1;
                   1584:                        break;
                   1585:
1.1       etheisen 1586:                case A_PREFIX:
                   1587:                        /*
                   1588:                         * The command is incomplete (more chars are needed).
                   1589:                         * Display the current char, so the user knows
                   1590:                         * what's going on, and get another character.
                   1591:                         */
                   1592:                        if (mca != A_PREFIX)
                   1593:                        {
                   1594:                                cmd_reset();
1.6       millert  1595:                                start_mca(A_PREFIX, " ", (void*)NULL,
                   1596:                                        CF_QUIT_ON_ERASE);
1.1       etheisen 1597:                                (void) cmd_char(c);
                   1598:                        }
                   1599:                        c = getcc();
                   1600:                        goto again;
                   1601:
                   1602:                case A_NOACTION:
                   1603:                        break;
                   1604:
                   1605:                default:
1.2       etheisen 1606:                        if (be_helpful)
1.6       millert  1607:                                help_prompt = "[Press 'h' for instructions.]";
1.2       etheisen 1608:                        else
                   1609:                                bell();
1.1       etheisen 1610:                        break;
                   1611:                }
                   1612:        }
                   1613: }