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