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

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