[BACK]Return to command.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/command.c, Revision 1.1.1.4

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