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