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