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