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