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