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

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