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

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