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

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