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

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