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