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

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