Annotation of src/usr.bin/less/command.c, Revision 1.1.1.4
1.1 etheisen 1: /*
1.1.1.4 ! shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.1 etheisen 3: *
1.1.1.2 millert 4: * You may distribute under the terms of either the GNU General Public
5: * License or the Less License, as specified in the README file.
1.1 etheisen 6: *
1.1.1.4 ! 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.1.1.2 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.1.1.3 shadchin 23: extern int erase_char, erase2_char, kill_char;
1.1.1.4 ! shadchin 24: extern volatile sig_atomic_t sigs;
1.1.1.2 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.1.1.2 millert 35: extern int secure;
36: extern int hshift;
37: extern int show_attn;
1.1.1.4 ! 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.1.1.2 millert 44: extern void constant *ml_search;
45: extern void constant *ml_examine;
1.1 etheisen 46: #if SHELL_ESCAPE || PIPEC
1.1.1.2 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.1.1.2 millert 54: extern int shift_count;
1.1.1.3 shadchin 55: extern int oldbot;
56: extern int forw_prompt;
1.1.1.4 ! shadchin 57: extern int be_helpful;
! 58: extern int less_is_more;
! 59: extern int quit_at_eof;
1.1 etheisen 60:
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.1.1.2 millert 66: static LINENUM number; /* The number typed by the user */
1.1.1.3 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.1.1.2 millert 71: static int optgetname;
72: static POSITION bottompos;
1.1.1.3 shadchin 73: static int save_hshift;
1.1.1.4 ! shadchin 74: static char *help_prompt;
1.1 etheisen 75: #if PIPEC
76: static char pipec;
77: #endif
78:
1.1.1.3 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.1.1.3 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.1.1.3 shadchin 96: #if HILITE_SEARCH
1.1.1.2 millert 97: clear_attn();
1.1.1.3 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.1.1.2 millert 107: start_mca(action, prompt, mlist, cmdflags)
1.1 etheisen 108: int action;
1.1.1.4 ! shadchin 109: constant char *prompt;
! 110: constant void *mlist;
1.1.1.2 millert 111: int cmdflags;
1.1 etheisen 112: {
113: mca = action;
1.1.1.3 shadchin 114: clear_bot();
1.1.1.2 millert 115: clear_cmd();
1.1 etheisen 116: cmd_putstr(prompt);
1.1.1.2 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.1.1.3 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.1.1.3 shadchin 142: clear_bot();
1.1.1.2 millert 143: clear_cmd();
1.1 etheisen 144:
1.1.1.2 millert 145: if (search_type & SRCH_NO_MATCH)
146: cmd_putstr("Non-match ");
1.1 etheisen 147: if (search_type & SRCH_FIRST_FILE)
1.1.1.2 millert 148: cmd_putstr("First-file ");
1.1 etheisen 149: if (search_type & SRCH_PAST_EOF)
1.1.1.2 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.1.1.3 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.1.1.2 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.1.1.3 shadchin 183: clear_bot();
1.1.1.2 millert 184: clear_cmd();
185: cmd_putstr(dash);
1.1.1.4 ! shadchin 186: #if GNU_OPTIONS
1.1.1.2 millert 187: if (optgetname)
188: cmd_putstr(dash);
1.1.1.4 ! shadchin 189: #endif
1.1.1.2 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: {
210: register char *cbuf;
211:
212: cmd_exec();
213: cbuf = get_cmdbuf();
214:
215: switch (mca)
216: {
217: case A_F_SEARCH:
218: case A_B_SEARCH:
1.1.1.2 millert 219: multi_search(cbuf, (int) number);
1.1 etheisen 220: break;
1.1.1.3 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.1.1.3 shadchin 241: toggle_option(curropt, opt_lower, cbuf, optflag);
242: curropt = NULL;
1.1 etheisen 243: break;
244: case A_F_BRACKET:
1.1.1.2 millert 245: match_brac(cbuf[0], cbuf[1], 1, (int) number);
1.1 etheisen 246: break;
247: case A_B_BRACKET:
1.1.1.2 millert 248: match_brac(cbuf[1], cbuf[0], 0, (int) number);
1.1 etheisen 249: break;
250: #if EXAMINE
251: case A_EXAMINE:
1.1.1.2 millert 252: if (secure)
253: break;
1.1 etheisen 254: edit_list(cbuf);
1.1.1.2 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.1.1.2 millert 275: if (secure)
276: break;
1.1 etheisen 277: if (shellcmd == NULL)
1.1.1.2 millert 278: lsystem("", "!done");
1.1 etheisen 279: else
1.1.1.2 millert 280: lsystem(shellcmd, "!done");
1.1 etheisen 281: break;
282: #endif
283: #if PIPEC
284: case A_PIPE:
1.1.1.2 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.1.1.3 shadchin 295: * Is a character an erase or kill char?
1.1 etheisen 296: */
297: static int
1.1.1.3 shadchin 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);
1.1.1.4 ! shadchin 312: #if GNU_OPTIONS
1.1.1.3 shadchin 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
1.1.1.4 ! shadchin 324: #endif
1.1.1.3 shadchin 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);
1.1.1.4 ! shadchin 344: #if GNU_OPTIONS
1.1.1.3 shadchin 345: case '-':
346: /* "--" = long option name. */
347: optgetname = TRUE;
348: mca_opt_toggle();
349: return (MCA_MORE);
1.1.1.4 ! shadchin 350: #endif
1.1.1.3 shadchin 351: }
352: }
353: /* Char was not handled here. */
354: return (NO_MCA);
355: }
356:
1.1.1.4 ! shadchin 357: #if GNU_OPTIONS
1.1.1.3 shadchin 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.
363: */
364: static int
365: mca_opt_nonfirst_char(c)
1.1 etheisen 366: int c;
367: {
368: char *p;
1.1.1.3 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: }
1.1.1.4 ! shadchin 410: #endif
1.1.1.3 shadchin 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.1.1.2 millert 419: PARG parg;
1.1 etheisen 420:
1.1.1.3 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: }
1.1.1.4 ! shadchin 432: #if GNU_OPTIONS
1.1.1.3 shadchin 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
1.1.1.4 ! shadchin 447: #endif
1.1.1.3 shadchin 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.1.1.3 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.1.1.3 shadchin 564: if (!((c >= '0' && c <= '9') || c == '.') &&
1.1.1.2 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.1.1.3 shadchin 569: * End the number and treat this char
570: * as a normal command character.
1.1 etheisen 571: */
1.1.1.3 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.1.1.3 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.1.1.3 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.1.1.3 shadchin 593: default:
594: /* Other multicharacter command. */
1.1 etheisen 595: break;
596: }
597:
598: /*
1.1.1.3 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.1.1.2 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.1.1.3 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.1.1.2 millert 652: * Make sure the screen is displayed.
1.1 etheisen 653: */
654: static void
1.1.1.2 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.1.1.3 shadchin 674: int save_top_scroll = top_scroll;
675: int save_ignore_eoi = ignore_eoi;
1.1 etheisen 676: top_scroll = 1;
1.1.1.3 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.1.1.3 shadchin 687: ignore_eoi = save_ignore_eoi;
1.1 etheisen 688: }
1.1.1.2 millert 689: }
690:
691: /*
692: * Display the appropriate prompt.
693: */
694: static void
695: prompt()
696: {
1.1.1.4 ! shadchin 697: register constant char *p;
1.1.1.2 millert 698:
1.1.1.3 shadchin 699: if (ungot != NULL)
1.1.1.2 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.1.1.3 shadchin 715: * If we've hit EOF on the last file and the -E flag is set, quit.
1.1 etheisen 716: */
1.1.1.3 shadchin 717: if (get_quit_at_eof() == OPT_ONPLUS &&
718: eof_displayed() && !(ch_getflags() & CH_HELPFILE) &&
1.1 etheisen 719: next_ifile(curr_ifile) == NULL_IFILE)
720: quit(QUIT_OK);
1.1.1.3 shadchin 721:
1.1.1.2 millert 722: /*
1.1.1.3 shadchin 723: * If the entire file is displayed and the -F flag is set, quit.
1.1.1.2 millert 724: */
1.1.1.3 shadchin 725: if (quit_if_one_screen &&
726: entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) &&
1.1.1.2 millert 727: next_ifile(curr_ifile) == NULL_IFILE)
728: quit(QUIT_OK);
1.1 etheisen 729:
1.1.1.2 millert 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));
736: #endif
1.1 etheisen 737: /*
738: * Select the proper prompt and display it.
739: */
1.1.1.3 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.1.1.2 millert 752: clear_cmd();
1.1.1.3 shadchin 753: forw_prompt = 0;
1.1.1.4 ! shadchin 754: p = help_prompt ? help_prompt : pr_string();
1.1.1.3 shadchin 755: if (is_filtering())
756: putstr("& ");
757: if (p == NULL || *p == '\0')
1.1 etheisen 758: putchr(':');
759: else
760: {
1.1.1.3 shadchin 761: at_enter(AT_STANDOUT);
1.1 etheisen 762: putstr(p);
1.1.1.4 ! shadchin 763: if (be_helpful && !help_prompt && strlen(p) + 40 < sc_width)
! 764: putstr(" [Press space to continue, 'q' to quit.]");
1.1.1.3 shadchin 765: at_exit();
1.1 etheisen 766: }
1.1.1.4 ! shadchin 767: help_prompt = NULL;
1.1.1.3 shadchin 768: clear_eol();
1.1 etheisen 769: }
770:
1.1.1.2 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.1.1.2 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.1.1.3 shadchin 792: if (unget_end)
793: {
1.1 etheisen 794: /*
1.1.1.3 shadchin 795: * We have just run out of ungotten chars.
1.1 etheisen 796: */
1.1.1.3 shadchin 797: unget_end = 0;
798: if (len_cmdbuf() == 0 || !empty_screen())
799: return (getchr());
1.1 etheisen 800: /*
1.1.1.3 shadchin 801: * Command is incomplete, so try to complete it.
1.1 etheisen 802: */
1.1.1.3 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.1.1.3 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.1.1.3 shadchin 818: default:
819: /*
820: * Some other incomplete command. Let user complete it.
821: */
822: return (getchr());
823: }
824: }
1.1 etheisen 825:
1.1.1.3 shadchin 826: if (ungot == NULL)
827: {
1.1 etheisen 828: /*
1.1.1.3 shadchin 829: * Normal case: no ungotten chars, so get one from the user.
1.1 etheisen 830: */
831: return (getchr());
832: }
1.1.1.3 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.1.1.3 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: {
871: register char *p;
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: {
887: register int nomore;
888: IFILE save_ifile;
889: int changed_file;
890:
891: changed_file = 0;
1.1.1.2 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.1.1.2 millert 905: {
906: unsave_ifile(save_ifile);
1.1 etheisen 907: return;
1.1.1.2 millert 908: }
1.1 etheisen 909: changed_file = 1;
910: search_type &= ~SRCH_FIRST_FILE;
911: }
912:
913: for (;;)
914: {
1.1.1.2 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.1.1.2 millert 927: unsave_ifile(save_ifile);
1.1 etheisen 928: return;
1.1.1.2 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.1.1.2 millert 968: reedit_ifile(save_ifile);
1.1.1.3 shadchin 969: } else
970: {
971: unsave_ifile(save_ifile);
1.1 etheisen 972: }
973: }
974:
975: /*
1.1.1.4 ! shadchin 976: * Forward forever, or until a highlighted line appears.
! 977: */
! 978: static int
! 979: forw_loop(until_hilite)
! 980: int until_hilite;
! 981: {
! 982: POSITION curr_len;
! 983:
! 984: if (ch_getflags() & CH_HELPFILE)
! 985: return (A_NOACTION);
! 986:
! 987: cmd_exec();
! 988: jump_forw();
! 989: curr_len = ch_length();
! 990: highest_hilite = until_hilite ? curr_len : NULL_POSITION;
! 991: ignore_eoi = 1;
! 992: while (!sigs)
! 993: {
! 994: if (until_hilite && highest_hilite > curr_len)
! 995: {
! 996: bell();
! 997: break;
! 998: }
! 999: make_display();
! 1000: forward(1, 0, 0);
! 1001: }
! 1002: ignore_eoi = 0;
! 1003: ch_set_eof();
! 1004:
! 1005: /*
! 1006: * This gets us back in "F mode" after processing
! 1007: * a non-abort signal (e.g. window-change).
! 1008: */
! 1009: if (sigs && !ABORT_SIGS())
! 1010: return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
! 1011:
! 1012: return (A_NOACTION);
! 1013: }
! 1014:
! 1015: /*
1.1 etheisen 1016: * Main command processor.
1017: * Accept and execute commands until a quit command.
1018: */
1019: public void
1020: commands()
1021: {
1022: register int c;
1023: register int action;
1024: register char *cbuf;
1.1.1.2 millert 1025: int newaction;
1.1 etheisen 1026: int save_search_type;
1.1.1.2 millert 1027: char *extra;
1.1 etheisen 1028: char tbuf[2];
1029: PARG parg;
1.1.1.2 millert 1030: IFILE old_ifile;
1031: IFILE new_ifile;
1032: char *tagfile;
1.1.1.4 ! shadchin 1033: int until_hilite = 0;
1.1 etheisen 1034:
1035: search_type = SRCH_FORW;
1036: wscroll = (sc_height + 1) / 2;
1.1.1.2 millert 1037: newaction = A_NOACTION;
1.1 etheisen 1038:
1039: for (;;)
1040: {
1041: mca = 0;
1042: cmd_accept();
1043: number = 0;
1.1.1.3 shadchin 1044: curropt = NULL;
1.1 etheisen 1045:
1046: /*
1047: * See if any signals need processing.
1048: */
1049: if (sigs)
1050: {
1051: psignals();
1052: if (quitting)
1053: quit(QUIT_SAVED_STATUS);
1054: }
1.1.1.2 millert 1055:
1056: /*
1057: * See if window size changed, for systems that don't
1058: * generate SIGWINCH.
1059: */
1060: check_winch();
1061:
1.1 etheisen 1062: /*
1063: * Display prompt and accept a character.
1064: */
1065: cmd_reset();
1066: prompt();
1067: if (sigs)
1068: continue;
1.1.1.2 millert 1069: if (newaction == A_NOACTION)
1070: c = getcc();
1.1 etheisen 1071:
1072: again:
1073: if (sigs)
1074: continue;
1075:
1.1.1.2 millert 1076: if (newaction != A_NOACTION)
1077: {
1078: action = newaction;
1079: newaction = A_NOACTION;
1080: } else
1081: {
1082: /*
1083: * If we are in a multicharacter command, call mca_char.
1084: * Otherwise we call fcmd_decode to determine the
1085: * action to be performed.
1086: */
1087: if (mca)
1088: switch (mca_char(c))
1089: {
1090: case MCA_MORE:
1091: /*
1092: * Need another character.
1093: */
1094: c = getcc();
1095: goto again;
1096: case MCA_DONE:
1097: /*
1098: * Command has been handled by mca_char.
1099: * Start clean with a prompt.
1100: */
1101: continue;
1102: case NO_MCA:
1103: /*
1104: * Not a multi-char command
1105: * (at least, not anymore).
1106: */
1107: break;
1108: }
1109:
1110: /*
1111: * Decode the command character and decide what to do.
1112: */
1113: if (mca)
1.1 etheisen 1114: {
1115: /*
1.1.1.2 millert 1116: * We're in a multichar command.
1117: * Add the character to the command buffer
1118: * and display it on the screen.
1119: * If the user backspaces past the start
1120: * of the line, abort the command.
1.1 etheisen 1121: */
1.1.1.2 millert 1122: if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0)
1123: continue;
1124: cbuf = get_cmdbuf();
1125: } else
1126: {
1.1 etheisen 1127: /*
1.1.1.2 millert 1128: * Don't use cmd_char if we're starting fresh
1129: * at the beginning of a command, because we
1130: * don't want to echo the command until we know
1131: * it is a multichar command. We also don't
1132: * want erase_char/kill_char to be treated
1133: * as line editing characters.
1.1 etheisen 1134: */
1.1.1.2 millert 1135: tbuf[0] = c;
1136: tbuf[1] = '\0';
1137: cbuf = tbuf;
1.1 etheisen 1138: }
1.1.1.2 millert 1139: extra = NULL;
1140: action = fcmd_decode(cbuf, &extra);
1.1 etheisen 1141: /*
1.1.1.2 millert 1142: * If an "extra" string was returned,
1143: * process it as a string of command characters.
1144: */
1145: if (extra != NULL)
1146: ungetsc(extra);
1.1 etheisen 1147: }
1148: /*
1149: * Clear the cmdbuf string.
1150: * (But not if we're in the prefix of a command,
1151: * because the partial command string is kept there.)
1152: */
1153: if (action != A_PREFIX)
1154: cmd_reset();
1155:
1156: switch (action)
1157: {
1158: case A_DIGIT:
1159: /*
1160: * First digit of a number.
1161: */
1.1.1.2 millert 1162: start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE);
1.1 etheisen 1163: goto again;
1164:
1165: case A_F_WINDOW:
1166: /*
1167: * Forward one window (and set the window size).
1168: */
1169: if (number > 0)
1.1.1.2 millert 1170: swindow = (int) number;
1.1 etheisen 1171: /* FALLTHRU */
1172: case A_F_SCREEN:
1173: /*
1174: * Forward one screen.
1175: */
1176: if (number <= 0)
1177: number = get_swindow();
1178: cmd_exec();
1.1.1.2 millert 1179: if (show_attn)
1180: set_attnpos(bottompos);
1181: forward((int) number, 0, 1);
1.1 etheisen 1182: break;
1183:
1184: case A_B_WINDOW:
1185: /*
1186: * Backward one window (and set the window size).
1187: */
1188: if (number > 0)
1.1.1.2 millert 1189: swindow = (int) number;
1.1 etheisen 1190: /* FALLTHRU */
1191: case A_B_SCREEN:
1192: /*
1193: * Backward one screen.
1194: */
1195: if (number <= 0)
1196: number = get_swindow();
1197: cmd_exec();
1.1.1.2 millert 1198: backward((int) number, 0, 1);
1.1 etheisen 1199: break;
1200:
1201: case A_F_LINE:
1202: /*
1203: * Forward N (default 1) line.
1204: */
1205: if (number <= 0)
1206: number = 1;
1207: cmd_exec();
1.1.1.2 millert 1208: if (show_attn == OPT_ONPLUS && number > 1)
1209: set_attnpos(bottompos);
1210: forward((int) number, 0, 0);
1.1 etheisen 1211: break;
1212:
1213: case A_B_LINE:
1214: /*
1215: * Backward N (default 1) line.
1216: */
1217: if (number <= 0)
1218: number = 1;
1219: cmd_exec();
1.1.1.2 millert 1220: backward((int) number, 0, 0);
1.1 etheisen 1221: break;
1222:
1223: case A_FF_LINE:
1224: /*
1225: * Force forward N (default 1) line.
1226: */
1227: if (number <= 0)
1228: number = 1;
1229: cmd_exec();
1.1.1.2 millert 1230: if (show_attn == OPT_ONPLUS && number > 1)
1231: set_attnpos(bottompos);
1232: forward((int) number, 1, 0);
1.1 etheisen 1233: break;
1234:
1235: case A_BF_LINE:
1236: /*
1237: * Force backward N (default 1) line.
1238: */
1239: if (number <= 0)
1240: number = 1;
1241: cmd_exec();
1.1.1.2 millert 1242: backward((int) number, 1, 0);
1.1 etheisen 1243: break;
1244:
1.1.1.2 millert 1245: case A_FF_SCREEN:
1246: /*
1247: * Force forward one screen.
1248: */
1249: if (number <= 0)
1250: number = get_swindow();
1251: cmd_exec();
1252: if (show_attn == OPT_ONPLUS)
1253: set_attnpos(bottompos);
1254: forward((int) number, 1, 0);
1255: break;
1256:
1.1 etheisen 1257: case A_F_FOREVER:
1258: /*
1259: * Forward forever, ignoring EOF.
1260: */
1.1.1.4 ! shadchin 1261: newaction = forw_loop(0);
! 1262: if (less_is_more)
! 1263: quit_at_eof = OPT_ON;
! 1264: break;
! 1265:
! 1266: case A_F_UNTIL_HILITE:
! 1267: newaction = forw_loop(1);
1.1 etheisen 1268: break;
1269:
1270: case A_F_SCROLL:
1271: /*
1272: * Forward N lines
1273: * (default same as last 'd' or 'u' command).
1274: */
1275: if (number > 0)
1.1.1.2 millert 1276: wscroll = (int) number;
1.1 etheisen 1277: cmd_exec();
1.1.1.2 millert 1278: if (show_attn == OPT_ONPLUS)
1279: set_attnpos(bottompos);
1.1 etheisen 1280: forward(wscroll, 0, 0);
1281: break;
1282:
1283: case A_B_SCROLL:
1284: /*
1285: * Forward N lines
1286: * (default same as last 'd' or 'u' command).
1287: */
1288: if (number > 0)
1.1.1.2 millert 1289: wscroll = (int) number;
1.1 etheisen 1290: cmd_exec();
1291: backward(wscroll, 0, 0);
1292: break;
1293:
1294: case A_FREPAINT:
1295: /*
1296: * Flush buffers, then repaint screen.
1297: * Don't flush the buffers on a pipe!
1298: */
1.1.1.3 shadchin 1299: clear_buffers();
1.1 etheisen 1300: /* FALLTHRU */
1301: case A_REPAINT:
1302: /*
1303: * Repaint screen.
1304: */
1305: cmd_exec();
1306: repaint();
1307: break;
1308:
1309: case A_GOLINE:
1310: /*
1311: * Go to line N, default beginning of file.
1312: */
1313: if (number <= 0)
1314: number = 1;
1315: cmd_exec();
1316: jump_back(number);
1317: break;
1318:
1319: case A_PERCENT:
1320: /*
1321: * Go to a specified percentage into the file.
1322: */
1323: if (number < 0)
1.1.1.3 shadchin 1324: {
1.1 etheisen 1325: number = 0;
1.1.1.3 shadchin 1326: fraction = 0;
1327: }
1.1 etheisen 1328: if (number > 100)
1.1.1.3 shadchin 1329: {
1.1 etheisen 1330: number = 100;
1.1.1.3 shadchin 1331: fraction = 0;
1332: }
1.1 etheisen 1333: cmd_exec();
1.1.1.3 shadchin 1334: jump_percent((int) number, fraction);
1.1 etheisen 1335: break;
1336:
1337: case A_GOEND:
1338: /*
1339: * Go to line N, default end of file.
1340: */
1341: cmd_exec();
1342: if (number <= 0)
1343: jump_forw();
1344: else
1345: jump_back(number);
1346: break;
1347:
1348: case A_GOPOS:
1349: /*
1350: * Go to a specified byte position in the file.
1351: */
1352: cmd_exec();
1353: if (number < 0)
1354: number = 0;
1.1.1.2 millert 1355: jump_line_loc((POSITION) number, jump_sline);
1.1 etheisen 1356: break;
1357:
1358: case A_STAT:
1359: /*
1360: * Print file name, etc.
1361: */
1.1.1.2 millert 1362: if (ch_getflags() & CH_HELPFILE)
1363: break;
1.1 etheisen 1364: cmd_exec();
1365: parg.p_string = eq_message();
1366: error("%s", &parg);
1367: break;
1.1.1.2 millert 1368:
1.1 etheisen 1369: case A_VERSION:
1370: /*
1371: * Print version number, without the "@(#)".
1372: */
1373: cmd_exec();
1374: dispversion();
1375: break;
1376:
1377: case A_QUIT:
1378: /*
1379: * Exit.
1380: */
1.1.1.4 ! shadchin 1381: #if !SMALL
1.1.1.2 millert 1382: if (curr_ifile != NULL_IFILE &&
1383: ch_getflags() & CH_HELPFILE)
1384: {
1385: /*
1386: * Quit while viewing the help file
1387: * just means return to viewing the
1388: * previous file.
1389: */
1.1.1.3 shadchin 1390: hshift = save_hshift;
1.1.1.2 millert 1391: if (edit_prev(1) == 0)
1392: break;
1393: }
1.1.1.4 ! shadchin 1394: #endif /* !SMALL */
1.1.1.2 millert 1395: if (extra != NULL)
1396: quit(*extra);
1.1 etheisen 1397: quit(QUIT_OK);
1.1.1.2 millert 1398: break;
1.1 etheisen 1399:
1400: /*
1401: * Define abbreviation for a commonly used sequence below.
1402: */
1.1.1.3 shadchin 1403: #define DO_SEARCH() \
1404: if (number <= 0) number = 1; \
1.1 etheisen 1405: mca_search(); \
1406: cmd_exec(); \
1.1.1.2 millert 1407: multi_search((char *)NULL, (int) number);
1.1 etheisen 1408:
1409:
1410: case A_F_SEARCH:
1411: /*
1412: * Search forward for a pattern.
1413: * Get the first char of the pattern.
1414: */
1415: search_type = SRCH_FORW;
1416: if (number <= 0)
1417: number = 1;
1418: mca_search();
1419: c = getcc();
1420: goto again;
1421:
1422: case A_B_SEARCH:
1423: /*
1424: * Search backward for a pattern.
1425: * Get the first char of the pattern.
1426: */
1427: search_type = SRCH_BACK;
1428: if (number <= 0)
1429: number = 1;
1430: mca_search();
1431: c = getcc();
1432: goto again;
1433:
1.1.1.3 shadchin 1434: case A_FILTER:
1435: #if HILITE_SEARCH
1436: search_type = SRCH_FORW | SRCH_FILTER;
1437: mca_search();
1438: c = getcc();
1439: goto again;
1440: #else
1441: error("Command not available", NULL_PARG);
1442: break;
1443: #endif
1444:
1.1 etheisen 1445: case A_AGAIN_SEARCH:
1446: /*
1447: * Repeat previous search.
1448: */
1449: DO_SEARCH();
1450: break;
1451:
1452: case A_T_AGAIN_SEARCH:
1453: /*
1454: * Repeat previous search, multiple files.
1455: */
1456: search_type |= SRCH_PAST_EOF;
1457: DO_SEARCH();
1458: break;
1459:
1460: case A_REVERSE_SEARCH:
1461: /*
1462: * Repeat previous search, in reverse direction.
1463: */
1464: save_search_type = search_type;
1465: search_type = SRCH_REVERSE(search_type);
1466: DO_SEARCH();
1467: search_type = save_search_type;
1468: break;
1469:
1470: case A_T_REVERSE_SEARCH:
1471: /*
1472: * Repeat previous search,
1473: * multiple files in reverse direction.
1474: */
1475: save_search_type = search_type;
1476: search_type = SRCH_REVERSE(search_type);
1477: search_type |= SRCH_PAST_EOF;
1478: DO_SEARCH();
1479: search_type = save_search_type;
1480: break;
1481:
1482: case A_UNDO_SEARCH:
1483: undo_search();
1484: break;
1485:
1486: case A_HELP:
1487: /*
1488: * Help.
1489: */
1.1.1.4 ! shadchin 1490: #if !SMALL
1.1.1.2 millert 1491: if (ch_getflags() & CH_HELPFILE)
1.1 etheisen 1492: break;
1.1.1.4 ! shadchin 1493: if (ungot != NULL || unget_end) {
! 1494: error(less_is_more
! 1495: ? "Invalid option -p h"
! 1496: : "Invalid option ++h",
! 1497: NULL_PARG);
! 1498: break;
! 1499: }
1.1 etheisen 1500: cmd_exec();
1.1.1.3 shadchin 1501: save_hshift = hshift;
1502: hshift = 0;
1.1.1.4 ! shadchin 1503: (void) edit(HELPFILE);
! 1504: #endif /* !SMALL */
1.1 etheisen 1505: break;
1506:
1507: case A_EXAMINE:
1508: #if EXAMINE
1509: /*
1510: * Edit a new file. Get the filename.
1511: */
1.1.1.2 millert 1512: if (secure)
1513: {
1514: error("Command not available", NULL_PARG);
1515: break;
1516: }
1517: start_mca(A_EXAMINE, "Examine: ", ml_examine, 0);
1.1 etheisen 1518: c = getcc();
1519: goto again;
1520: #else
1521: error("Command not available", NULL_PARG);
1522: break;
1523: #endif
1524:
1525: case A_VISUAL:
1526: /*
1527: * Invoke an editor on the input file.
1528: */
1529: #if EDITOR
1.1.1.2 millert 1530: if (secure)
1531: {
1532: error("Command not available", NULL_PARG);
1533: break;
1534: }
1535: if (ch_getflags() & CH_HELPFILE)
1536: break;
1.1 etheisen 1537: if (strcmp(get_filename(curr_ifile), "-") == 0)
1538: {
1539: error("Cannot edit standard input", NULL_PARG);
1540: break;
1541: }
1542: if (curr_altfilename != NULL)
1543: {
1.1.1.3 shadchin 1544: error("WARNING: This file was viewed via LESSOPEN",
1.1 etheisen 1545: NULL_PARG);
1546: }
1.1.1.2 millert 1547: start_mca(A_SHELL, "!", ml_shell, 0);
1.1 etheisen 1548: /*
1549: * Expand the editor prototype string
1550: * and pass it to the system to execute.
1.1.1.2 millert 1551: * (Make sure the screen is displayed so the
1552: * expansion of "+%lm" works.)
1.1 etheisen 1553: */
1.1.1.2 millert 1554: make_display();
1.1 etheisen 1555: cmd_exec();
1.1.1.2 millert 1556: lsystem(pr_expand(editproto, 0), (char*)NULL);
1.1 etheisen 1557: break;
1558: #else
1559: error("Command not available", NULL_PARG);
1560: break;
1561: #endif
1562:
1563: case A_NEXT_FILE:
1564: /*
1565: * Examine next file.
1566: */
1.1.1.2 millert 1567: #if TAGS
1568: if (ntags())
1569: {
1570: error("No next file", NULL_PARG);
1571: break;
1572: }
1573: #endif
1.1 etheisen 1574: if (number <= 0)
1575: number = 1;
1.1.1.2 millert 1576: if (edit_next((int) number))
1.1 etheisen 1577: {
1.1.1.3 shadchin 1578: if (get_quit_at_eof() && eof_displayed() &&
1.1.1.2 millert 1579: !(ch_getflags() & CH_HELPFILE))
1.1 etheisen 1580: quit(QUIT_OK);
1581: parg.p_string = (number > 1) ? "(N-th) " : "";
1582: error("No %snext file", &parg);
1583: }
1584: break;
1585:
1586: case A_PREV_FILE:
1587: /*
1588: * Examine previous file.
1589: */
1.1.1.2 millert 1590: #if TAGS
1591: if (ntags())
1592: {
1593: error("No previous file", NULL_PARG);
1594: break;
1595: }
1596: #endif
1.1 etheisen 1597: if (number <= 0)
1598: number = 1;
1.1.1.2 millert 1599: if (edit_prev((int) number))
1.1 etheisen 1600: {
1601: parg.p_string = (number > 1) ? "(N-th) " : "";
1602: error("No %sprevious file", &parg);
1603: }
1604: break;
1605:
1.1.1.2 millert 1606: case A_NEXT_TAG:
1607: #if TAGS
1608: if (number <= 0)
1609: number = 1;
1610: tagfile = nexttag((int) number);
1611: if (tagfile == NULL)
1612: {
1613: error("No next tag", NULL_PARG);
1614: break;
1615: }
1616: if (edit(tagfile) == 0)
1617: {
1618: POSITION pos = tagsearch();
1619: if (pos != NULL_POSITION)
1620: jump_loc(pos, jump_sline);
1621: }
1622: #else
1623: error("Command not available", NULL_PARG);
1624: #endif
1625: break;
1626:
1627: case A_PREV_TAG:
1628: #if TAGS
1629: if (number <= 0)
1630: number = 1;
1631: tagfile = prevtag((int) number);
1632: if (tagfile == NULL)
1633: {
1634: error("No previous tag", NULL_PARG);
1635: break;
1636: }
1637: if (edit(tagfile) == 0)
1638: {
1639: POSITION pos = tagsearch();
1640: if (pos != NULL_POSITION)
1641: jump_loc(pos, jump_sline);
1642: }
1643: #else
1644: error("Command not available", NULL_PARG);
1645: #endif
1646: break;
1647:
1.1 etheisen 1648: case A_INDEX_FILE:
1649: /*
1650: * Examine a particular file.
1651: */
1652: if (number <= 0)
1653: number = 1;
1.1.1.2 millert 1654: if (edit_index((int) number))
1.1 etheisen 1655: error("No such file", NULL_PARG);
1656: break;
1657:
1.1.1.2 millert 1658: case A_REMOVE_FILE:
1659: if (ch_getflags() & CH_HELPFILE)
1660: break;
1661: old_ifile = curr_ifile;
1662: new_ifile = getoff_ifile(curr_ifile);
1663: if (new_ifile == NULL_IFILE)
1664: {
1665: bell();
1666: break;
1667: }
1668: if (edit_ifile(new_ifile) != 0)
1669: {
1670: reedit_ifile(old_ifile);
1671: break;
1672: }
1673: del_ifile(old_ifile);
1674: break;
1675:
1.1 etheisen 1676: case A_OPT_TOGGLE:
1677: optflag = OPT_TOGGLE;
1.1.1.2 millert 1678: optgetname = FALSE;
1679: mca_opt_toggle();
1.1 etheisen 1680: c = getcc();
1681: goto again;
1682:
1683: case A_DISP_OPTION:
1684: /*
1685: * Report a flag setting.
1686: */
1.1.1.2 millert 1687: optflag = OPT_NO_TOGGLE;
1688: optgetname = FALSE;
1689: mca_opt_toggle();
1.1 etheisen 1690: c = getcc();
1.1.1.2 millert 1691: goto again;
1.1 etheisen 1692:
1693: case A_FIRSTCMD:
1694: /*
1695: * Set an initial command for new files.
1696: */
1.1.1.2 millert 1697: start_mca(A_FIRSTCMD, "+", (void*)NULL, 0);
1.1 etheisen 1698: c = getcc();
1699: goto again;
1700:
1701: case A_SHELL:
1702: /*
1703: * Shell escape.
1704: */
1705: #if SHELL_ESCAPE
1.1.1.2 millert 1706: if (secure)
1707: {
1708: error("Command not available", NULL_PARG);
1709: break;
1710: }
1711: start_mca(A_SHELL, "!", ml_shell, 0);
1.1 etheisen 1712: c = getcc();
1713: goto again;
1714: #else
1715: error("Command not available", NULL_PARG);
1716: break;
1717: #endif
1718:
1719: case A_SETMARK:
1720: /*
1721: * Set a mark.
1722: */
1.1.1.2 millert 1723: if (ch_getflags() & CH_HELPFILE)
1724: break;
1725: start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
1.1 etheisen 1726: c = getcc();
1.1.1.3 shadchin 1727: if (c == erase_char || c == erase2_char ||
1728: c == kill_char || c == '\n' || c == '\r')
1.1 etheisen 1729: break;
1730: setmark(c);
1731: break;
1732:
1733: case A_GOMARK:
1734: /*
1735: * Go to a mark.
1736: */
1.1.1.2 millert 1737: start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
1.1 etheisen 1738: c = getcc();
1.1.1.3 shadchin 1739: if (c == erase_char || c == erase2_char ||
1740: c == kill_char || c == '\n' || c == '\r')
1.1 etheisen 1741: break;
1.1.1.3 shadchin 1742: cmd_exec();
1.1 etheisen 1743: gomark(c);
1744: break;
1745:
1746: case A_PIPE:
1747: #if PIPEC
1.1.1.2 millert 1748: if (secure)
1749: {
1750: error("Command not available", NULL_PARG);
1751: break;
1752: }
1753: start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
1.1 etheisen 1754: c = getcc();
1.1.1.3 shadchin 1755: if (c == erase_char || c == erase2_char || c == kill_char)
1.1 etheisen 1756: break;
1757: if (c == '\n' || c == '\r')
1758: c = '.';
1759: if (badmark(c))
1760: break;
1761: pipec = c;
1.1.1.2 millert 1762: start_mca(A_PIPE, "!", ml_shell, 0);
1.1 etheisen 1763: c = getcc();
1764: goto again;
1765: #else
1766: error("Command not available", NULL_PARG);
1767: break;
1768: #endif
1769:
1770: case A_B_BRACKET:
1771: case A_F_BRACKET:
1.1.1.2 millert 1772: start_mca(action, "Brackets: ", (void*)NULL, 0);
1.1 etheisen 1773: c = getcc();
1774: goto again;
1775:
1.1.1.2 millert 1776: case A_LSHIFT:
1777: if (number > 0)
1778: shift_count = number;
1779: else
1780: number = (shift_count > 0) ?
1781: shift_count : sc_width / 2;
1782: if (number > hshift)
1783: number = hshift;
1784: hshift -= number;
1785: screen_trashed = 1;
1786: break;
1787:
1788: case A_RSHIFT:
1789: if (number > 0)
1790: shift_count = number;
1791: else
1792: number = (shift_count > 0) ?
1793: shift_count : sc_width / 2;
1794: hshift += number;
1795: screen_trashed = 1;
1796: break;
1797:
1.1 etheisen 1798: case A_PREFIX:
1799: /*
1800: * The command is incomplete (more chars are needed).
1801: * Display the current char, so the user knows
1802: * what's going on, and get another character.
1803: */
1804: if (mca != A_PREFIX)
1805: {
1806: cmd_reset();
1.1.1.2 millert 1807: start_mca(A_PREFIX, " ", (void*)NULL,
1808: CF_QUIT_ON_ERASE);
1.1 etheisen 1809: (void) cmd_char(c);
1810: }
1811: c = getcc();
1812: goto again;
1813:
1814: case A_NOACTION:
1815: break;
1816:
1817: default:
1.1.1.4 ! shadchin 1818: if (be_helpful)
! 1819: help_prompt = "[Press 'h' for instructions.]";
! 1820: else
! 1821: bell();
1.1 etheisen 1822: break;
1823: }
1824: }
1825: }