command.c revision 191930
160812Sps/* $FreeBSD: head/contrib/less/command.c 191930 2009-05-09 01:35:27Z delphij $ */ 260786Sps/* 3191930Sdelphij * Copyright (C) 1984-2008 Mark Nudelman 460786Sps * 560786Sps * You may distribute under the terms of either the GNU General Public 660786Sps * License or the Less License, as specified in the README file. 760786Sps * 860786Sps * For more information about less, or for information on how to 960786Sps * contact the author, see the README file. 1060786Sps */ 1160786Sps 1260786Sps 1360786Sps/* 1460786Sps * User-level command processor. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1889022Sps#if MSDOS_COMPILER==WIN32C 1989022Sps#include <windows.h> 2089022Sps#endif 2160786Sps#include "position.h" 2260786Sps#include "option.h" 2360786Sps#include "cmd.h" 2460786Sps 25161478Sdelphijextern int erase_char, erase2_char, kill_char; 2660786Spsextern int sigs; 2760786Spsextern int quit_if_one_screen; 2860786Spsextern int squished; 2960786Spsextern int sc_width; 3060786Spsextern int sc_height; 3160786Spsextern int swindow; 3260786Spsextern int jump_sline; 3360786Spsextern int quitting; 3460786Spsextern int wscroll; 3560786Spsextern int top_scroll; 3660786Spsextern int ignore_eoi; 3760786Spsextern int secure; 3860786Spsextern int hshift; 3960786Spsextern int show_attn; 40170259Sdelphijextern int less_is_more; 4160786Spsextern char *every_first_cmd; 4260786Spsextern char *curr_altfilename; 4360786Spsextern char version[]; 4460786Spsextern struct scrpos initial_scrpos; 4560786Spsextern IFILE curr_ifile; 4660786Spsextern void constant *ml_search; 4760786Spsextern void constant *ml_examine; 4860786Sps#if SHELL_ESCAPE || PIPEC 4960786Spsextern void constant *ml_shell; 5060786Sps#endif 5160786Sps#if EDITOR 5260786Spsextern char *editor; 5360786Spsextern char *editproto; 5460786Sps#endif 5560786Spsextern int screen_trashed; /* The screen has been overwritten */ 5663131Spsextern int shift_count; 57170259Sdelphijextern int oldbot; 58170259Sdelphijextern int forw_prompt; 5960786Sps 6060786Spsstatic char ungot[UNGOT_SIZE]; 6160786Spsstatic char *ungotp = NULL; 6260786Sps#if SHELL_ESCAPE 6360786Spsstatic char *shellcmd = NULL; /* For holding last shell command for "!!" */ 6460786Sps#endif 6560786Spsstatic int mca; /* The multicharacter command (action) */ 6660786Spsstatic int search_type; /* The previous type of search */ 67128348Stjrstatic LINENUM number; /* The number typed by the user */ 68170259Sdelphijstatic long fraction; /* The fractional part of the number */ 6960786Spsstatic char optchar; 7060786Spsstatic int optflag; 7160786Spsstatic int optgetname; 7260786Spsstatic POSITION bottompos; 73161478Sdelphijstatic int save_hshift; 7460786Sps#if PIPEC 7560786Spsstatic char pipec; 7660786Sps#endif 7760786Sps 7860786Spsstatic void multi_search(); 7960786Sps 8060786Sps/* 81170259Sdelphij * Move the cursor to start of prompt line before executing a command. 8260786Sps * This looks nicer if the command takes a long time before 8360786Sps * updating the screen. 8460786Sps */ 8560786Sps static void 8660786Spscmd_exec() 8760786Sps{ 88191930Sdelphij#if HILITE_SEARCH 8960786Sps clear_attn(); 90191930Sdelphij#endif 91170967Sdelphij clear_bot(); 9260786Sps flush(); 9360786Sps} 9460786Sps 9560786Sps/* 9660786Sps * Set up the display to start a new multi-character command. 9760786Sps */ 9860786Sps static void 9960786Spsstart_mca(action, prompt, mlist, cmdflags) 10060786Sps int action; 10160786Sps char *prompt; 10260786Sps void *mlist; 10360786Sps int cmdflags; 10460786Sps{ 10560786Sps mca = action; 106170259Sdelphij clear_bot(); 10760786Sps clear_cmd(); 10860786Sps cmd_putstr(prompt); 10960786Sps set_mlist(mlist, cmdflags); 11060786Sps} 11160786Sps 11260786Sps public int 11360786Spsin_mca() 11460786Sps{ 11560786Sps return (mca != 0 && mca != A_PREFIX); 11660786Sps} 11760786Sps 11860786Sps/* 11960786Sps * Set up the display to start a new search command. 12060786Sps */ 12160786Sps static void 12260786Spsmca_search() 12360786Sps{ 124191930Sdelphij#if HILITE_SEARCH 125191930Sdelphij if (search_type & SRCH_FILTER) 126191930Sdelphij mca = A_FILTER; 127191930Sdelphij else 128191930Sdelphij#endif 12960786Sps if (search_type & SRCH_FORW) 13060786Sps mca = A_F_SEARCH; 13160786Sps else 13260786Sps mca = A_B_SEARCH; 13360786Sps 134170259Sdelphij clear_bot(); 13560786Sps clear_cmd(); 13660786Sps 13760786Sps if (search_type & SRCH_NO_MATCH) 13860786Sps cmd_putstr("Non-match "); 13960786Sps if (search_type & SRCH_FIRST_FILE) 14060786Sps cmd_putstr("First-file "); 14160786Sps if (search_type & SRCH_PAST_EOF) 14260786Sps cmd_putstr("EOF-ignore "); 14360786Sps if (search_type & SRCH_NO_MOVE) 14460786Sps cmd_putstr("Keep-pos "); 14560786Sps if (search_type & SRCH_NO_REGEX) 14660786Sps cmd_putstr("Regex-off "); 14760786Sps 148191930Sdelphij#if HILITE_SEARCH 149191930Sdelphij if (search_type & SRCH_FILTER) 150191930Sdelphij cmd_putstr("&/"); 151191930Sdelphij else 152191930Sdelphij#endif 15360786Sps if (search_type & SRCH_FORW) 15460786Sps cmd_putstr("/"); 15560786Sps else 15660786Sps cmd_putstr("?"); 15760786Sps set_mlist(ml_search, 0); 15860786Sps} 15960786Sps 16060786Sps/* 16160786Sps * Set up the display to start a new toggle-option command. 16260786Sps */ 16360786Sps static void 16460786Spsmca_opt_toggle() 16560786Sps{ 16660786Sps int no_prompt; 16760786Sps int flag; 16860786Sps char *dash; 16960786Sps 17060786Sps no_prompt = (optflag & OPT_NO_PROMPT); 17160786Sps flag = (optflag & ~OPT_NO_PROMPT); 17260786Sps dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; 17360786Sps 17460786Sps mca = A_OPT_TOGGLE; 175170259Sdelphij clear_bot(); 17660786Sps clear_cmd(); 17760786Sps cmd_putstr(dash); 17860786Sps if (optgetname) 17960786Sps cmd_putstr(dash); 18060786Sps if (no_prompt) 18160786Sps cmd_putstr("(P)"); 18260786Sps switch (flag) 18360786Sps { 18460786Sps case OPT_UNSET: 18560786Sps cmd_putstr("+"); 18660786Sps break; 18760786Sps case OPT_SET: 18860786Sps cmd_putstr("!"); 18960786Sps break; 19060786Sps } 19160786Sps set_mlist(NULL, 0); 19260786Sps} 19360786Sps 19460786Sps/* 19560786Sps * Execute a multicharacter command. 19660786Sps */ 19760786Sps static void 19860786Spsexec_mca() 19960786Sps{ 20060786Sps register char *cbuf; 20160786Sps 20260786Sps cmd_exec(); 20360786Sps cbuf = get_cmdbuf(); 20460786Sps 20560786Sps switch (mca) 20660786Sps { 20760786Sps case A_F_SEARCH: 20860786Sps case A_B_SEARCH: 209128348Stjr multi_search(cbuf, (int) number); 21060786Sps break; 211191930Sdelphij#if HILITE_SEARCH 212191930Sdelphij case A_FILTER: 213191930Sdelphij search_type ^= SRCH_NO_MATCH; 214191930Sdelphij set_filter_pattern(cbuf, search_type); 215191930Sdelphij break; 216191930Sdelphij#endif 21760786Sps case A_FIRSTCMD: 21860786Sps /* 21960786Sps * Skip leading spaces or + signs in the string. 22060786Sps */ 22160786Sps while (*cbuf == '+' || *cbuf == ' ') 22260786Sps cbuf++; 22360786Sps if (every_first_cmd != NULL) 22460786Sps free(every_first_cmd); 22560786Sps if (*cbuf == '\0') 22660786Sps every_first_cmd = NULL; 22760786Sps else 22860786Sps every_first_cmd = save(cbuf); 22960786Sps break; 23060786Sps case A_OPT_TOGGLE: 23160786Sps toggle_option(optchar, cbuf, optflag); 23260786Sps optchar = '\0'; 23360786Sps break; 23460786Sps case A_F_BRACKET: 235128348Stjr match_brac(cbuf[0], cbuf[1], 1, (int) number); 23660786Sps break; 23760786Sps case A_B_BRACKET: 238128348Stjr match_brac(cbuf[1], cbuf[0], 0, (int) number); 23960786Sps break; 24060786Sps#if EXAMINE 24160786Sps case A_EXAMINE: 24260786Sps if (secure) 24360786Sps break; 24460786Sps edit_list(cbuf); 245128348Stjr#if TAGS 24689022Sps /* If tag structure is loaded then clean it up. */ 24789022Sps cleantags(); 248128348Stjr#endif 24960786Sps break; 25060786Sps#endif 25160786Sps#if SHELL_ESCAPE 25260786Sps case A_SHELL: 25360786Sps /* 25460786Sps * !! just uses whatever is in shellcmd. 25560786Sps * Otherwise, copy cmdbuf to shellcmd, 25660786Sps * expanding any special characters ("%" or "#"). 25760786Sps */ 25860786Sps if (*cbuf != '!') 25960786Sps { 26060786Sps if (shellcmd != NULL) 26160786Sps free(shellcmd); 26260786Sps shellcmd = fexpand(cbuf); 26360786Sps } 26460786Sps 26560786Sps if (secure) 26660786Sps break; 26760786Sps if (shellcmd == NULL) 26860786Sps lsystem("", "!done"); 26960786Sps else 27060786Sps lsystem(shellcmd, "!done"); 27160786Sps break; 27260786Sps#endif 27360786Sps#if PIPEC 27460786Sps case A_PIPE: 27560786Sps if (secure) 27660786Sps break; 27760786Sps (void) pipe_mark(pipec, cbuf); 27860786Sps error("|done", NULL_PARG); 27960786Sps break; 28060786Sps#endif 28160786Sps } 28260786Sps} 28360786Sps 28460786Sps/* 28560786Sps * Add a character to a multi-character command. 28660786Sps */ 28760786Sps static int 28860786Spsmca_char(c) 28960786Sps int c; 29060786Sps{ 29160786Sps char *p; 29260786Sps int flag; 29360786Sps char buf[3]; 29460786Sps PARG parg; 29560786Sps 29660786Sps switch (mca) 29760786Sps { 29860786Sps case 0: 29960786Sps /* 30060786Sps * Not in a multicharacter command. 30160786Sps */ 30260786Sps return (NO_MCA); 30360786Sps 30460786Sps case A_PREFIX: 30560786Sps /* 30660786Sps * In the prefix of a command. 30760786Sps * This not considered a multichar command 30860786Sps * (even tho it uses cmdbuf, etc.). 30960786Sps * It is handled in the commands() switch. 31060786Sps */ 31160786Sps return (NO_MCA); 31260786Sps 31360786Sps case A_DIGIT: 31460786Sps /* 31560786Sps * Entering digits of a number. 31660786Sps * Terminated by a non-digit. 31760786Sps */ 318170259Sdelphij if (!((c >= '0' && c <= '9') || c == '.') && 31989022Sps editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) 32060786Sps { 32160786Sps /* 32260786Sps * Not part of the number. 32360786Sps * Treat as a normal command character. 32460786Sps */ 325170259Sdelphij number = cmd_int(&fraction); 32660786Sps mca = 0; 32760786Sps cmd_accept(); 32860786Sps return (NO_MCA); 32960786Sps } 33060786Sps break; 33160786Sps 33260786Sps case A_OPT_TOGGLE: 33360786Sps /* 33460786Sps * Special case for the TOGGLE_OPTION command. 33560786Sps * If the option letter which was entered is a 33660786Sps * single-char option, execute the command immediately, 33760786Sps * so user doesn't have to hit RETURN. 33860786Sps * If the first char is + or -, this indicates 33960786Sps * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE. 34060786Sps * "--" begins inputting a long option name. 34160786Sps */ 34260786Sps if (optchar == '\0' && len_cmdbuf() == 0) 34360786Sps { 34460786Sps flag = (optflag & ~OPT_NO_PROMPT); 34560786Sps if (flag == OPT_NO_TOGGLE) 34660786Sps { 34760786Sps switch (c) 34860786Sps { 34960786Sps case '_': 35060786Sps /* "__" = long option name. */ 35160786Sps optgetname = TRUE; 35260786Sps mca_opt_toggle(); 35360786Sps return (MCA_MORE); 35460786Sps } 35560786Sps } else 35660786Sps { 35760786Sps switch (c) 35860786Sps { 35960786Sps case '+': 36060786Sps /* "-+" = UNSET. */ 36160786Sps optflag = (flag == OPT_UNSET) ? 36260786Sps OPT_TOGGLE : OPT_UNSET; 36360786Sps mca_opt_toggle(); 36460786Sps return (MCA_MORE); 36560786Sps case '!': 36660786Sps /* "-!" = SET */ 36760786Sps optflag = (flag == OPT_SET) ? 36860786Sps OPT_TOGGLE : OPT_SET; 36960786Sps mca_opt_toggle(); 37060786Sps return (MCA_MORE); 37160786Sps case CONTROL('P'): 37260786Sps optflag ^= OPT_NO_PROMPT; 37360786Sps mca_opt_toggle(); 37460786Sps return (MCA_MORE); 37560786Sps case '-': 37660786Sps /* "--" = long option name. */ 37760786Sps optgetname = TRUE; 37860786Sps mca_opt_toggle(); 37960786Sps return (MCA_MORE); 38060786Sps } 38160786Sps } 38260786Sps } 38360786Sps if (optgetname) 38460786Sps { 38560786Sps /* 38660786Sps * We're getting a long option name. 38760786Sps * See if we've matched an option name yet. 38860786Sps * If so, display the complete name and stop 38960786Sps * accepting chars until user hits RETURN. 39060786Sps */ 391128348Stjr struct loption *o; 39260786Sps char *oname; 39360786Sps int lc; 39460786Sps 39560786Sps if (c == '\n' || c == '\r') 39660786Sps { 39760786Sps /* 39860786Sps * When the user hits RETURN, make sure 39960786Sps * we've matched an option name, then 40060786Sps * pretend he just entered the equivalent 40160786Sps * option letter. 40260786Sps */ 40360786Sps if (optchar == '\0') 40460786Sps { 40560786Sps parg.p_string = get_cmdbuf(); 40660786Sps error("There is no --%s option", &parg); 40760786Sps return (MCA_DONE); 40860786Sps } 40960786Sps optgetname = FALSE; 41060786Sps cmd_reset(); 41160786Sps c = optchar; 41260786Sps } else 41360786Sps { 41460786Sps if (optchar != '\0') 41560786Sps { 41660786Sps /* 41760786Sps * Already have a match for the name. 41860786Sps * Don't accept anything but erase/kill. 41960786Sps */ 420161478Sdelphij if (c == erase_char || 421161478Sdelphij c == erase2_char || 422161478Sdelphij c == kill_char) 42360786Sps return (MCA_DONE); 42460786Sps return (MCA_MORE); 42560786Sps } 42660786Sps /* 42760786Sps * Add char to cmd buffer and try to match 42860786Sps * the option name. 42960786Sps */ 43060786Sps if (cmd_char(c) == CC_QUIT) 43160786Sps return (MCA_DONE); 43260786Sps p = get_cmdbuf(); 433161478Sdelphij lc = ASCII_IS_LOWER(p[0]); 43460786Sps o = findopt_name(&p, &oname, NULL); 43560786Sps if (o != NULL) 43660786Sps { 43760786Sps /* 43860786Sps * Got a match. 43960786Sps * Remember the option letter and 44060786Sps * display the full option name. 44160786Sps */ 44260786Sps optchar = o->oletter; 443161478Sdelphij if (!lc && ASCII_IS_LOWER(optchar)) 444161478Sdelphij optchar = ASCII_TO_UPPER(optchar); 44560786Sps cmd_reset(); 44660786Sps mca_opt_toggle(); 44760786Sps for (p = oname; *p != '\0'; p++) 44860786Sps { 44960786Sps c = *p; 450161478Sdelphij if (!lc && ASCII_IS_LOWER(c)) 451161478Sdelphij c = ASCII_TO_UPPER(c); 45260786Sps if (cmd_char(c) != CC_OK) 45360786Sps return (MCA_DONE); 45460786Sps } 45560786Sps } 45660786Sps return (MCA_MORE); 45760786Sps } 45860786Sps } else 45960786Sps { 460161478Sdelphij if (c == erase_char || c == erase2_char || c == kill_char) 46160786Sps break; 46260786Sps if (optchar != '\0') 46360786Sps /* We already have the option letter. */ 46460786Sps break; 46560786Sps } 46660786Sps 46760786Sps optchar = c; 46860786Sps if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || 46960786Sps single_char_option(c)) 47060786Sps { 47160786Sps toggle_option(c, "", optflag); 47260786Sps return (MCA_DONE); 47360786Sps } 47460786Sps /* 47560786Sps * Display a prompt appropriate for the option letter. 47660786Sps */ 47760786Sps if ((p = opt_prompt(c)) == NULL) 47860786Sps { 47960786Sps buf[0] = '-'; 48060786Sps buf[1] = c; 48160786Sps buf[2] = '\0'; 48260786Sps p = buf; 48360786Sps } 48460786Sps start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0); 48560786Sps return (MCA_MORE); 48660786Sps 48760786Sps case A_F_SEARCH: 48860786Sps case A_B_SEARCH: 489191930Sdelphij case A_FILTER: 49060786Sps /* 49160786Sps * Special case for search commands. 49260786Sps * Certain characters as the first char of 49360786Sps * the pattern have special meaning: 49460786Sps * ! Toggle the NO_MATCH flag 49560786Sps * * Toggle the PAST_EOF flag 49660786Sps * @ Toggle the FIRST_FILE flag 49760786Sps */ 49860786Sps if (len_cmdbuf() > 0) 49960786Sps /* 50060786Sps * Only works for the first char of the pattern. 50160786Sps */ 50260786Sps break; 50360786Sps 50460786Sps flag = 0; 50560786Sps switch (c) 50660786Sps { 50760812Sps case '*': 508170259Sdelphij if (less_is_more) 50960812Sps break; 51060786Sps case CONTROL('E'): /* ignore END of file */ 511191930Sdelphij if (mca != A_FILTER) 512191930Sdelphij flag = SRCH_PAST_EOF; 51360786Sps break; 51460812Sps case '@': 515170259Sdelphij if (less_is_more) 51660812Sps break; 51760786Sps case CONTROL('F'): /* FIRST file */ 518191930Sdelphij if (mca != A_FILTER) 519191930Sdelphij flag = SRCH_FIRST_FILE; 52060786Sps break; 52160786Sps case CONTROL('K'): /* KEEP position */ 522191930Sdelphij if (mca != A_FILTER) 523191930Sdelphij flag = SRCH_NO_MOVE; 52460786Sps break; 52560786Sps case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ 52660786Sps flag = SRCH_NO_REGEX; 52760786Sps break; 52860786Sps case CONTROL('N'): /* NOT match */ 52960786Sps case '!': 53060786Sps flag = SRCH_NO_MATCH; 53160786Sps break; 53260786Sps } 53360786Sps if (flag != 0) 53460786Sps { 53560786Sps search_type ^= flag; 53660786Sps mca_search(); 53760786Sps return (MCA_MORE); 53860786Sps } 53960786Sps break; 54060786Sps } 54160786Sps 54260786Sps /* 54360786Sps * Any other multicharacter command 54460786Sps * is terminated by a newline. 54560786Sps */ 54660786Sps if (c == '\n' || c == '\r') 54760786Sps { 54860786Sps /* 54960786Sps * Execute the command. 55060786Sps */ 55160786Sps exec_mca(); 55260786Sps return (MCA_DONE); 55360786Sps } 55460786Sps 55560786Sps /* 55660786Sps * Append the char to the command buffer. 55760786Sps */ 55860786Sps if (cmd_char(c) == CC_QUIT) 55960786Sps /* 56060786Sps * Abort the multi-char command. 56160786Sps */ 56260786Sps return (MCA_DONE); 56360786Sps 56460786Sps if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) 56560786Sps { 56660786Sps /* 56760786Sps * Special case for the bracket-matching commands. 56860786Sps * Execute the command after getting exactly two 56960786Sps * characters from the user. 57060786Sps */ 57160786Sps exec_mca(); 57260786Sps return (MCA_DONE); 57360786Sps } 57460786Sps 57560786Sps /* 57660786Sps * Need another character. 57760786Sps */ 57860786Sps return (MCA_MORE); 57960786Sps} 58060786Sps 58160786Sps/* 582173685Sdelphij * Discard any buffered file data. 583173685Sdelphij */ 584173685Sdelphij static void 585173685Sdelphijclear_buffers() 586173685Sdelphij{ 587173685Sdelphij if (!(ch_getflags() & CH_CANSEEK)) 588173685Sdelphij return; 589173685Sdelphij ch_flush(); 590173685Sdelphij clr_linenum(); 591173685Sdelphij#if HILITE_SEARCH 592173685Sdelphij clr_hilite(); 593173685Sdelphij#endif 594173685Sdelphij} 595173685Sdelphij 596173685Sdelphij/* 59760786Sps * Make sure the screen is displayed. 59860786Sps */ 59960786Sps static void 60060786Spsmake_display() 60160786Sps{ 60260786Sps /* 60360786Sps * If nothing is displayed yet, display starting from initial_scrpos. 60460786Sps */ 60560786Sps if (empty_screen()) 60660786Sps { 60760786Sps if (initial_scrpos.pos == NULL_POSITION) 60860786Sps /* 60960786Sps * {{ Maybe this should be: 61060786Sps * jump_loc(ch_zero(), jump_sline); 61160786Sps * but this behavior seems rather unexpected 61260786Sps * on the first screen. }} 61360786Sps */ 61460786Sps jump_loc(ch_zero(), 1); 61560786Sps else 61660786Sps jump_loc(initial_scrpos.pos, initial_scrpos.ln); 61760786Sps } else if (screen_trashed) 61860786Sps { 619173685Sdelphij int save_top_scroll = top_scroll; 620173685Sdelphij int save_ignore_eoi = ignore_eoi; 62160786Sps top_scroll = 1; 622173685Sdelphij ignore_eoi = 0; 623173685Sdelphij if (screen_trashed == 2) 624173685Sdelphij { 625173685Sdelphij /* Special case used by ignore_eoi: re-open the input file 626173685Sdelphij * and jump to the end of the file. */ 627173685Sdelphij reopen_curr_ifile(); 628173685Sdelphij jump_forw(); 629173685Sdelphij } 63060786Sps repaint(); 63160786Sps top_scroll = save_top_scroll; 632173685Sdelphij ignore_eoi = save_ignore_eoi; 63360786Sps } 63460786Sps} 63560786Sps 63660786Sps/* 63760786Sps * Display the appropriate prompt. 63860786Sps */ 63960786Sps static void 64060786Spsprompt() 64160786Sps{ 64260786Sps register char *p; 64360786Sps 64460786Sps if (ungotp != NULL && ungotp > ungot) 64560786Sps { 64660786Sps /* 64760786Sps * No prompt necessary if commands are from 64860786Sps * ungotten chars rather than from the user. 64960786Sps */ 65060786Sps return; 65160786Sps } 65260786Sps 65360786Sps /* 65460786Sps * Make sure the screen is displayed. 65560786Sps */ 65660786Sps make_display(); 65760786Sps bottompos = position(BOTTOM_PLUS_ONE); 65860786Sps 65960786Sps /* 660191930Sdelphij * If we've hit EOF on the last file and the -E flag is set, quit. 66160786Sps */ 662191930Sdelphij if (get_quit_at_eof() == OPT_ONPLUS && 663191930Sdelphij eof_displayed() && !(ch_getflags() & CH_HELPFILE) && 66460786Sps next_ifile(curr_ifile) == NULL_IFILE) 66560786Sps quit(QUIT_OK); 666191930Sdelphij 66760786Sps /* 668191930Sdelphij * If the entire file is displayed and the -F flag is set, quit. 66960786Sps */ 670191930Sdelphij if (quit_if_one_screen && 671191930Sdelphij entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && 67260786Sps next_ifile(curr_ifile) == NULL_IFILE) 67360786Sps quit(QUIT_OK); 67460786Sps 67589022Sps#if MSDOS_COMPILER==WIN32C 67689022Sps /* 67789022Sps * In Win32, display the file name in the window title. 67889022Sps */ 67989022Sps if (!(ch_getflags() & CH_HELPFILE)) 68089022Sps SetConsoleTitle(pr_expand("Less?f - %f.", 0)); 68189022Sps#endif 68260786Sps /* 68360786Sps * Select the proper prompt and display it. 68460786Sps */ 685170259Sdelphij /* 686170259Sdelphij * If the previous action was a forward movement, 687170259Sdelphij * don't clear the bottom line of the display; 688170259Sdelphij * just print the prompt since the forward movement guarantees 689170259Sdelphij * that we're in the right position to display the prompt. 690170259Sdelphij * Clearing the line could cause a problem: for example, if the last 691170259Sdelphij * line displayed ended at the right screen edge without a newline, 692170259Sdelphij * then clearing would clear the last displayed line rather than 693170259Sdelphij * the prompt line. 694170259Sdelphij */ 695170259Sdelphij if (!forw_prompt) 696170259Sdelphij clear_bot(); 69760786Sps clear_cmd(); 698170259Sdelphij forw_prompt = 0; 69960786Sps p = pr_string(); 700191930Sdelphij if (is_filtering()) 701191930Sdelphij putstr("& "); 702161478Sdelphij if (p == NULL || *p == '\0') 70360786Sps putchr(':'); 70460786Sps else 70560786Sps { 706161478Sdelphij at_enter(AT_STANDOUT); 70760786Sps putstr(p); 708161478Sdelphij at_exit(); 70960786Sps } 710170259Sdelphij clear_eol(); 71160786Sps} 71260786Sps 71360786Sps/* 71460786Sps * Display the less version message. 71560786Sps */ 71660786Sps public void 71760786Spsdispversion() 71860786Sps{ 71960786Sps PARG parg; 72060786Sps 72160786Sps parg.p_string = version; 72260786Sps error("less %s", &parg); 72360786Sps} 72460786Sps 72560786Sps/* 72660786Sps * Get command character. 72760786Sps * The character normally comes from the keyboard, 72860786Sps * but may come from ungotten characters 72960786Sps * (characters previously given to ungetcc or ungetsc). 73060786Sps */ 73160786Sps public int 73260786Spsgetcc() 73360786Sps{ 73460786Sps if (ungotp == NULL) 73560786Sps /* 73660786Sps * Normal case: no ungotten chars, so get one from the user. 73760786Sps */ 73860786Sps return (getchr()); 73960786Sps 74060786Sps if (ungotp > ungot) 74160786Sps /* 74260786Sps * Return the next ungotten char. 74360786Sps */ 74460786Sps return (*--ungotp); 74560786Sps 74660786Sps /* 74760786Sps * We have just run out of ungotten chars. 74860786Sps */ 74960786Sps ungotp = NULL; 75060786Sps if (len_cmdbuf() == 0 || !empty_screen()) 75160786Sps return (getchr()); 75260786Sps /* 75360786Sps * Command is incomplete, so try to complete it. 75460786Sps */ 75560786Sps switch (mca) 75660786Sps { 75760786Sps case A_DIGIT: 75860786Sps /* 75960786Sps * We have a number but no command. Treat as #g. 76060786Sps */ 76160786Sps return ('g'); 76260786Sps 76360786Sps case A_F_SEARCH: 76460786Sps case A_B_SEARCH: 76560786Sps /* 76660786Sps * We have "/string" but no newline. Add the \n. 76760786Sps */ 76860786Sps return ('\n'); 76960786Sps 77060786Sps default: 77160786Sps /* 77260786Sps * Some other incomplete command. Let user complete it. 77360786Sps */ 77460786Sps return (getchr()); 77560786Sps } 77660786Sps} 77760786Sps 77860786Sps/* 77960786Sps * "Unget" a command character. 78060786Sps * The next getcc() will return this character. 78160786Sps */ 78260786Sps public void 78360786Spsungetcc(c) 78460786Sps int c; 78560786Sps{ 78660786Sps if (ungotp == NULL) 78760786Sps ungotp = ungot; 78860786Sps if (ungotp >= ungot + sizeof(ungot)) 78960786Sps { 79060786Sps error("ungetcc overflow", NULL_PARG); 79160786Sps quit(QUIT_ERROR); 79260786Sps } 79360786Sps *ungotp++ = c; 79460786Sps} 79560786Sps 79660786Sps/* 79760786Sps * Unget a whole string of command characters. 79860786Sps * The next sequence of getcc()'s will return this string. 79960786Sps */ 80060786Sps public void 80160786Spsungetsc(s) 80260786Sps char *s; 80360786Sps{ 80460786Sps register char *p; 80560786Sps 80660786Sps for (p = s + strlen(s) - 1; p >= s; p--) 80760786Sps ungetcc(*p); 80860786Sps} 80960786Sps 81060786Sps/* 81160786Sps * Search for a pattern, possibly in multiple files. 81260786Sps * If SRCH_FIRST_FILE is set, begin searching at the first file. 81360786Sps * If SRCH_PAST_EOF is set, continue the search thru multiple files. 81460786Sps */ 81560786Sps static void 81660786Spsmulti_search(pattern, n) 81760786Sps char *pattern; 81860786Sps int n; 81960786Sps{ 82060786Sps register int nomore; 82160786Sps IFILE save_ifile; 82260786Sps int changed_file; 82360786Sps 82460786Sps changed_file = 0; 82560786Sps save_ifile = save_curr_ifile(); 82660786Sps 82760786Sps if (search_type & SRCH_FIRST_FILE) 82860786Sps { 82960786Sps /* 83060786Sps * Start at the first (or last) file 83160786Sps * in the command line list. 83260786Sps */ 83360786Sps if (search_type & SRCH_FORW) 83460786Sps nomore = edit_first(); 83560786Sps else 83660786Sps nomore = edit_last(); 83760786Sps if (nomore) 83860786Sps { 83960786Sps unsave_ifile(save_ifile); 84060786Sps return; 84160786Sps } 84260786Sps changed_file = 1; 84360786Sps search_type &= ~SRCH_FIRST_FILE; 84460786Sps } 84560786Sps 84660786Sps for (;;) 84760786Sps { 84860786Sps n = search(search_type, pattern, n); 84960786Sps /* 85060786Sps * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared 85160786Sps * after being used once. This allows "n" to work after 85260786Sps * using a /@@ search. 85360786Sps */ 85460786Sps search_type &= ~SRCH_NO_MOVE; 85560786Sps if (n == 0) 85660786Sps { 85760786Sps /* 85860786Sps * Found it. 85960786Sps */ 86060786Sps unsave_ifile(save_ifile); 86160786Sps return; 86260786Sps } 86360786Sps 86460786Sps if (n < 0) 86560786Sps /* 86660786Sps * Some kind of error in the search. 86760786Sps * Error message has been printed by search(). 86860786Sps */ 86960786Sps break; 87060786Sps 87160786Sps if ((search_type & SRCH_PAST_EOF) == 0) 87260786Sps /* 87360786Sps * We didn't find a match, but we're 87460786Sps * supposed to search only one file. 87560786Sps */ 87660786Sps break; 87760786Sps /* 87860786Sps * Move on to the next file. 87960786Sps */ 88060786Sps if (search_type & SRCH_FORW) 88160786Sps nomore = edit_next(1); 88260786Sps else 88360786Sps nomore = edit_prev(1); 88460786Sps if (nomore) 88560786Sps break; 88660786Sps changed_file = 1; 88760786Sps } 88860786Sps 88960786Sps /* 89060786Sps * Didn't find it. 89160786Sps * Print an error message if we haven't already. 89260786Sps */ 89360786Sps if (n > 0) 89460786Sps error("Pattern not found", NULL_PARG); 89560786Sps 89660786Sps if (changed_file) 89760786Sps { 89860786Sps /* 89960786Sps * Restore the file we were originally viewing. 90060786Sps */ 90160786Sps reedit_ifile(save_ifile); 902161478Sdelphij } else 903161478Sdelphij { 904161478Sdelphij unsave_ifile(save_ifile); 90560786Sps } 90660786Sps} 90760786Sps 90860786Sps/* 90960786Sps * Main command processor. 91060786Sps * Accept and execute commands until a quit command. 91160786Sps */ 91260786Sps public void 91360786Spscommands() 91460786Sps{ 91560786Sps register int c; 91660786Sps register int action; 91760786Sps register char *cbuf; 91860786Sps int newaction; 91960786Sps int save_search_type; 92060786Sps char *extra; 92160786Sps char tbuf[2]; 92260786Sps PARG parg; 92360786Sps IFILE old_ifile; 92460786Sps IFILE new_ifile; 92589022Sps char *tagfile; 92660786Sps 92760786Sps search_type = SRCH_FORW; 92860786Sps wscroll = (sc_height + 1) / 2; 92960786Sps newaction = A_NOACTION; 93060786Sps 93160786Sps for (;;) 93260786Sps { 93360786Sps mca = 0; 93460786Sps cmd_accept(); 93560786Sps number = 0; 93660786Sps optchar = '\0'; 93760786Sps 93860786Sps /* 93960786Sps * See if any signals need processing. 94060786Sps */ 94160786Sps if (sigs) 94260786Sps { 94360786Sps psignals(); 94460786Sps if (quitting) 94560786Sps quit(QUIT_SAVED_STATUS); 94660786Sps } 94760786Sps 94860786Sps /* 94960786Sps * See if window size changed, for systems that don't 95060786Sps * generate SIGWINCH. 95160786Sps */ 95260786Sps check_winch(); 95360786Sps 95460786Sps /* 95560786Sps * Display prompt and accept a character. 95660786Sps */ 95760786Sps cmd_reset(); 95860786Sps prompt(); 95960786Sps if (sigs) 96060786Sps continue; 96160786Sps if (newaction == A_NOACTION) 96260786Sps c = getcc(); 96360786Sps 96460786Sps again: 96560786Sps if (sigs) 96660786Sps continue; 96760786Sps 96860786Sps if (newaction != A_NOACTION) 96960786Sps { 97060786Sps action = newaction; 97160786Sps newaction = A_NOACTION; 97260786Sps } else 97360786Sps { 97460786Sps /* 97560786Sps * If we are in a multicharacter command, call mca_char. 97660786Sps * Otherwise we call fcmd_decode to determine the 97760786Sps * action to be performed. 97860786Sps */ 97960786Sps if (mca) 98060786Sps switch (mca_char(c)) 98160786Sps { 98260786Sps case MCA_MORE: 98360786Sps /* 98460786Sps * Need another character. 98560786Sps */ 98660786Sps c = getcc(); 98760786Sps goto again; 98860786Sps case MCA_DONE: 98960786Sps /* 99060786Sps * Command has been handled by mca_char. 99160786Sps * Start clean with a prompt. 99260786Sps */ 99360786Sps continue; 99460786Sps case NO_MCA: 99560786Sps /* 99660786Sps * Not a multi-char command 99760786Sps * (at least, not anymore). 99860786Sps */ 99960786Sps break; 100060786Sps } 100160786Sps 100260786Sps /* 100360786Sps * Decode the command character and decide what to do. 100460786Sps */ 100560786Sps if (mca) 100660786Sps { 100760786Sps /* 100860786Sps * We're in a multichar command. 100960786Sps * Add the character to the command buffer 101060786Sps * and display it on the screen. 101160786Sps * If the user backspaces past the start 101260786Sps * of the line, abort the command. 101360786Sps */ 101460786Sps if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) 101560786Sps continue; 101660786Sps cbuf = get_cmdbuf(); 101760786Sps } else 101860786Sps { 101960786Sps /* 102060786Sps * Don't use cmd_char if we're starting fresh 102160786Sps * at the beginning of a command, because we 102260786Sps * don't want to echo the command until we know 102360786Sps * it is a multichar command. We also don't 102460786Sps * want erase_char/kill_char to be treated 102560786Sps * as line editing characters. 102660786Sps */ 102760786Sps tbuf[0] = c; 102860786Sps tbuf[1] = '\0'; 102960786Sps cbuf = tbuf; 103060786Sps } 103160786Sps extra = NULL; 103260786Sps action = fcmd_decode(cbuf, &extra); 103360786Sps /* 103460786Sps * If an "extra" string was returned, 103560786Sps * process it as a string of command characters. 103660786Sps */ 103760786Sps if (extra != NULL) 103860786Sps ungetsc(extra); 103960786Sps } 104060786Sps /* 104160786Sps * Clear the cmdbuf string. 104260786Sps * (But not if we're in the prefix of a command, 104360786Sps * because the partial command string is kept there.) 104460786Sps */ 104560786Sps if (action != A_PREFIX) 104660786Sps cmd_reset(); 104760786Sps 104860786Sps switch (action) 104960786Sps { 105060786Sps case A_DIGIT: 105160786Sps /* 105260786Sps * First digit of a number. 105360786Sps */ 105460786Sps start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); 105560786Sps goto again; 105660786Sps 105760786Sps case A_F_WINDOW: 105860786Sps /* 105960786Sps * Forward one window (and set the window size). 106060786Sps */ 106160786Sps if (number > 0) 1062128348Stjr swindow = (int) number; 106360786Sps /* FALLTHRU */ 106460786Sps case A_F_SCREEN: 106560786Sps /* 106660786Sps * Forward one screen. 106760786Sps */ 106860786Sps if (number <= 0) 106960786Sps number = get_swindow(); 107060786Sps cmd_exec(); 107160786Sps if (show_attn) 107260786Sps set_attnpos(bottompos); 1073128348Stjr forward((int) number, 0, 1); 107460786Sps break; 107560786Sps 107660786Sps case A_B_WINDOW: 107760786Sps /* 107860786Sps * Backward one window (and set the window size). 107960786Sps */ 108060786Sps if (number > 0) 1081128348Stjr swindow = (int) number; 108260786Sps /* FALLTHRU */ 108360786Sps case A_B_SCREEN: 108460786Sps /* 108560786Sps * Backward one screen. 108660786Sps */ 108760786Sps if (number <= 0) 108860786Sps number = get_swindow(); 108960786Sps cmd_exec(); 1090128348Stjr backward((int) number, 0, 1); 109160786Sps break; 109260786Sps 109360786Sps case A_F_LINE: 109460786Sps /* 109560786Sps * Forward N (default 1) line. 109660786Sps */ 109760786Sps if (number <= 0) 109860786Sps number = 1; 109960786Sps cmd_exec(); 110060786Sps if (show_attn == OPT_ONPLUS && number > 1) 110160786Sps set_attnpos(bottompos); 1102128348Stjr forward((int) number, 0, 0); 110360786Sps break; 110460786Sps 110560786Sps case A_B_LINE: 110660786Sps /* 110760786Sps * Backward N (default 1) line. 110860786Sps */ 110960786Sps if (number <= 0) 111060786Sps number = 1; 111160786Sps cmd_exec(); 1112128348Stjr backward((int) number, 0, 0); 111360786Sps break; 111460786Sps 111560786Sps case A_FF_LINE: 111660786Sps /* 111760786Sps * Force forward N (default 1) line. 111860786Sps */ 111960786Sps if (number <= 0) 112060786Sps number = 1; 112160786Sps cmd_exec(); 112260786Sps if (show_attn == OPT_ONPLUS && number > 1) 112360786Sps set_attnpos(bottompos); 1124128348Stjr forward((int) number, 1, 0); 112560786Sps break; 112660786Sps 112760786Sps case A_BF_LINE: 112860786Sps /* 112960786Sps * Force backward N (default 1) line. 113060786Sps */ 113160786Sps if (number <= 0) 113260786Sps number = 1; 113360786Sps cmd_exec(); 1134128348Stjr backward((int) number, 1, 0); 113560786Sps break; 113660786Sps 113760786Sps case A_FF_SCREEN: 113860786Sps /* 113960786Sps * Force forward one screen. 114060786Sps */ 114160786Sps if (number <= 0) 114260786Sps number = get_swindow(); 114360786Sps cmd_exec(); 114460786Sps if (show_attn == OPT_ONPLUS) 114560786Sps set_attnpos(bottompos); 1146128348Stjr forward((int) number, 1, 0); 114760786Sps break; 114860786Sps 114960786Sps case A_F_FOREVER: 115060786Sps /* 115160786Sps * Forward forever, ignoring EOF. 115260786Sps */ 115360786Sps if (ch_getflags() & CH_HELPFILE) 115460786Sps break; 115560786Sps cmd_exec(); 115660786Sps jump_forw(); 115760786Sps ignore_eoi = 1; 115860786Sps while (!sigs) 1159173685Sdelphij { 1160173685Sdelphij make_display(); 116160786Sps forward(1, 0, 0); 1162173685Sdelphij } 116360786Sps ignore_eoi = 0; 116460786Sps /* 116560786Sps * This gets us back in "F mode" after processing 116660786Sps * a non-abort signal (e.g. window-change). 116760786Sps */ 116860786Sps if (sigs && !ABORT_SIGS()) 116960786Sps newaction = A_F_FOREVER; 117060786Sps break; 117160786Sps 117260786Sps case A_F_SCROLL: 117360786Sps /* 117460786Sps * Forward N lines 117560786Sps * (default same as last 'd' or 'u' command). 117660786Sps */ 117760786Sps if (number > 0) 1178128348Stjr wscroll = (int) number; 117960786Sps cmd_exec(); 118060786Sps if (show_attn == OPT_ONPLUS) 118160786Sps set_attnpos(bottompos); 118260786Sps forward(wscroll, 0, 0); 118360786Sps break; 118460786Sps 118560786Sps case A_B_SCROLL: 118660786Sps /* 118760786Sps * Forward N lines 118860786Sps * (default same as last 'd' or 'u' command). 118960786Sps */ 119060786Sps if (number > 0) 1191128348Stjr wscroll = (int) number; 119260786Sps cmd_exec(); 119360786Sps backward(wscroll, 0, 0); 119460786Sps break; 119560786Sps 119660786Sps case A_FREPAINT: 119760786Sps /* 119860786Sps * Flush buffers, then repaint screen. 119960786Sps * Don't flush the buffers on a pipe! 120060786Sps */ 1201173685Sdelphij clear_buffers(); 120260786Sps /* FALLTHRU */ 120360786Sps case A_REPAINT: 120460786Sps /* 120560786Sps * Repaint screen. 120660786Sps */ 120760786Sps cmd_exec(); 120860786Sps repaint(); 120960786Sps break; 121060786Sps 121160786Sps case A_GOLINE: 121260786Sps /* 121360786Sps * Go to line N, default beginning of file. 121460786Sps */ 121560786Sps if (number <= 0) 121660786Sps number = 1; 121760786Sps cmd_exec(); 121860786Sps jump_back(number); 121960786Sps break; 122060786Sps 122160786Sps case A_PERCENT: 122260786Sps /* 122360786Sps * Go to a specified percentage into the file. 122460786Sps */ 122560786Sps if (number < 0) 1226170259Sdelphij { 122760786Sps number = 0; 1228170259Sdelphij fraction = 0; 1229170259Sdelphij } 123060786Sps if (number > 100) 1231170259Sdelphij { 123260786Sps number = 100; 1233170259Sdelphij fraction = 0; 1234170259Sdelphij } 123560786Sps cmd_exec(); 1236170259Sdelphij jump_percent((int) number, fraction); 123760786Sps break; 123860786Sps 123960786Sps case A_GOEND: 124060786Sps /* 124160786Sps * Go to line N, default end of file. 124260786Sps */ 124360786Sps cmd_exec(); 124460786Sps if (number <= 0) 124560786Sps jump_forw(); 124660786Sps else 124760786Sps jump_back(number); 124860786Sps break; 124960786Sps 125060786Sps case A_GOPOS: 125160786Sps /* 125260786Sps * Go to a specified byte position in the file. 125360786Sps */ 125460786Sps cmd_exec(); 125560786Sps if (number < 0) 125660786Sps number = 0; 1257128348Stjr jump_line_loc((POSITION) number, jump_sline); 125860786Sps break; 125960786Sps 126060786Sps case A_STAT: 126160786Sps /* 126260786Sps * Print file name, etc. 126360786Sps */ 126460786Sps if (ch_getflags() & CH_HELPFILE) 126560786Sps break; 126660786Sps cmd_exec(); 126760786Sps parg.p_string = eq_message(); 126860786Sps error("%s", &parg); 126960786Sps break; 127060786Sps 127160786Sps case A_VERSION: 127260786Sps /* 127360786Sps * Print version number, without the "@(#)". 127460786Sps */ 127560786Sps cmd_exec(); 127660786Sps dispversion(); 127760786Sps break; 127860786Sps 127960786Sps case A_QUIT: 128060786Sps /* 128160786Sps * Exit. 128260786Sps */ 128360786Sps if (curr_ifile != NULL_IFILE && 128460786Sps ch_getflags() & CH_HELPFILE) 128560786Sps { 128660786Sps /* 128760786Sps * Quit while viewing the help file 128860786Sps * just means return to viewing the 128960786Sps * previous file. 129060786Sps */ 1291161478Sdelphij hshift = save_hshift; 129260786Sps if (edit_prev(1) == 0) 129360786Sps break; 129460786Sps } 129560786Sps if (extra != NULL) 129660786Sps quit(*extra); 129760786Sps quit(QUIT_OK); 129860786Sps break; 129960786Sps 130060786Sps/* 130160786Sps * Define abbreviation for a commonly used sequence below. 130260786Sps */ 1303173685Sdelphij#define DO_SEARCH() \ 1304173685Sdelphij if (number <= 0) number = 1; \ 130560786Sps mca_search(); \ 130660786Sps cmd_exec(); \ 1307128348Stjr multi_search((char *)NULL, (int) number); 130860786Sps 130960786Sps 131060786Sps case A_F_SEARCH: 131160786Sps /* 131260786Sps * Search forward for a pattern. 131360786Sps * Get the first char of the pattern. 131460786Sps */ 131560786Sps search_type = SRCH_FORW; 131660786Sps if (number <= 0) 131760786Sps number = 1; 131860786Sps mca_search(); 131960786Sps c = getcc(); 132060786Sps goto again; 132160786Sps 132260786Sps case A_B_SEARCH: 132360786Sps /* 132460786Sps * Search backward for a pattern. 132560786Sps * Get the first char of the pattern. 132660786Sps */ 132760786Sps search_type = SRCH_BACK; 132860786Sps if (number <= 0) 132960786Sps number = 1; 133060786Sps mca_search(); 133160786Sps c = getcc(); 133260786Sps goto again; 133360786Sps 1334191930Sdelphij case A_FILTER: 1335191930Sdelphij#if HILITE_SEARCH 1336191930Sdelphij search_type = SRCH_FORW | SRCH_FILTER; 1337191930Sdelphij mca_search(); 1338191930Sdelphij c = getcc(); 1339191930Sdelphij goto again; 1340191930Sdelphij#else 1341191930Sdelphij error("Command not available", NULL_PARG); 1342191930Sdelphij break; 1343191930Sdelphij#endif 1344191930Sdelphij 134560786Sps case A_AGAIN_SEARCH: 134660786Sps /* 134760786Sps * Repeat previous search. 134860786Sps */ 134960786Sps DO_SEARCH(); 135060786Sps break; 135160786Sps 135260786Sps case A_T_AGAIN_SEARCH: 135360786Sps /* 135460786Sps * Repeat previous search, multiple files. 135560786Sps */ 135660786Sps search_type |= SRCH_PAST_EOF; 135760786Sps DO_SEARCH(); 135860786Sps break; 135960786Sps 136060786Sps case A_REVERSE_SEARCH: 136160786Sps /* 136260786Sps * Repeat previous search, in reverse direction. 136360786Sps */ 136460786Sps save_search_type = search_type; 136560786Sps search_type = SRCH_REVERSE(search_type); 136660786Sps DO_SEARCH(); 136760786Sps search_type = save_search_type; 136860786Sps break; 136960786Sps 137060786Sps case A_T_REVERSE_SEARCH: 137160786Sps /* 137260786Sps * Repeat previous search, 137360786Sps * multiple files in reverse direction. 137460786Sps */ 137560786Sps save_search_type = search_type; 137660786Sps search_type = SRCH_REVERSE(search_type); 137760786Sps search_type |= SRCH_PAST_EOF; 137860786Sps DO_SEARCH(); 137960786Sps search_type = save_search_type; 138060786Sps break; 138160786Sps 138260786Sps case A_UNDO_SEARCH: 138360786Sps undo_search(); 138460786Sps break; 138560786Sps 138660786Sps case A_HELP: 138760786Sps /* 138860786Sps * Help. 138960786Sps */ 139060786Sps if (ch_getflags() & CH_HELPFILE) 139160786Sps break; 139260786Sps cmd_exec(); 1393161478Sdelphij save_hshift = hshift; 1394161478Sdelphij hshift = 0; 139560786Sps (void) edit(FAKE_HELPFILE); 139660786Sps break; 139760786Sps 139860786Sps case A_EXAMINE: 139960786Sps#if EXAMINE 140060786Sps /* 140160786Sps * Edit a new file. Get the filename. 140260786Sps */ 140360786Sps if (secure) 140460786Sps { 140560786Sps error("Command not available", NULL_PARG); 140660786Sps break; 140760786Sps } 140860786Sps start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); 140960786Sps c = getcc(); 141060786Sps goto again; 141160786Sps#else 141260786Sps error("Command not available", NULL_PARG); 141360786Sps break; 141460786Sps#endif 141560786Sps 141660786Sps case A_VISUAL: 141760786Sps /* 141860786Sps * Invoke an editor on the input file. 141960786Sps */ 142060786Sps#if EDITOR 142160786Sps if (secure) 142260786Sps { 142360786Sps error("Command not available", NULL_PARG); 142460786Sps break; 142560786Sps } 142660786Sps if (ch_getflags() & CH_HELPFILE) 142760786Sps break; 142860786Sps if (strcmp(get_filename(curr_ifile), "-") == 0) 142960786Sps { 143060786Sps error("Cannot edit standard input", NULL_PARG); 143160786Sps break; 143260786Sps } 143360786Sps if (curr_altfilename != NULL) 143460786Sps { 1435161478Sdelphij error("WARNING: This file was viewed via LESSOPEN", 143660786Sps NULL_PARG); 143760786Sps } 143860786Sps start_mca(A_SHELL, "!", ml_shell, 0); 143960786Sps /* 144060786Sps * Expand the editor prototype string 144160786Sps * and pass it to the system to execute. 144260786Sps * (Make sure the screen is displayed so the 144360786Sps * expansion of "+%lm" works.) 144460786Sps */ 144560786Sps make_display(); 144660786Sps cmd_exec(); 144760786Sps lsystem(pr_expand(editproto, 0), (char*)NULL); 144860786Sps break; 144960786Sps#else 145060786Sps error("Command not available", NULL_PARG); 145160786Sps break; 145260786Sps#endif 145360786Sps 145460786Sps case A_NEXT_FILE: 145560786Sps /* 145660786Sps * Examine next file. 145760786Sps */ 1458128348Stjr#if TAGS 145989022Sps if (ntags()) 146089022Sps { 146189022Sps error("No next file", NULL_PARG); 146289022Sps break; 146389022Sps } 1464128348Stjr#endif 146560786Sps if (number <= 0) 146660786Sps number = 1; 1467128348Stjr if (edit_next((int) number)) 146860786Sps { 1469191930Sdelphij if (get_quit_at_eof() && eof_displayed() && 147060786Sps !(ch_getflags() & CH_HELPFILE)) 147160786Sps quit(QUIT_OK); 147260786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 147360786Sps error("No %snext file", &parg); 147460786Sps } 147560786Sps break; 147660786Sps 147760786Sps case A_PREV_FILE: 147860786Sps /* 147960786Sps * Examine previous file. 148060786Sps */ 1481128348Stjr#if TAGS 148289022Sps if (ntags()) 148389022Sps { 148489022Sps error("No previous file", NULL_PARG); 148589022Sps break; 148689022Sps } 1487128348Stjr#endif 148860786Sps if (number <= 0) 148960786Sps number = 1; 1490128348Stjr if (edit_prev((int) number)) 149160786Sps { 149260786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 149360786Sps error("No %sprevious file", &parg); 149460786Sps } 149560786Sps break; 149660786Sps 149789022Sps case A_NEXT_TAG: 1498128348Stjr#if TAGS 149989022Sps if (number <= 0) 150089022Sps number = 1; 1501128348Stjr tagfile = nexttag((int) number); 150289022Sps if (tagfile == NULL) 150389022Sps { 150489022Sps error("No next tag", NULL_PARG); 150589022Sps break; 150689022Sps } 150789022Sps if (edit(tagfile) == 0) 150889022Sps { 150989022Sps POSITION pos = tagsearch(); 151089022Sps if (pos != NULL_POSITION) 151189022Sps jump_loc(pos, jump_sline); 151289022Sps } 1513128348Stjr#else 1514128348Stjr error("Command not available", NULL_PARG); 1515128348Stjr#endif 151689022Sps break; 151789022Sps 151889022Sps case A_PREV_TAG: 1519128348Stjr#if TAGS 152089022Sps if (number <= 0) 152189022Sps number = 1; 1522128348Stjr tagfile = prevtag((int) number); 152389022Sps if (tagfile == NULL) 152489022Sps { 152589022Sps error("No previous tag", NULL_PARG); 152689022Sps break; 152789022Sps } 152889022Sps if (edit(tagfile) == 0) 152989022Sps { 153089022Sps POSITION pos = tagsearch(); 153189022Sps if (pos != NULL_POSITION) 153289022Sps jump_loc(pos, jump_sline); 153389022Sps } 1534128348Stjr#else 1535128348Stjr error("Command not available", NULL_PARG); 1536128348Stjr#endif 153789022Sps break; 153889022Sps 153960786Sps case A_INDEX_FILE: 154060786Sps /* 154160786Sps * Examine a particular file. 154260786Sps */ 154360786Sps if (number <= 0) 154460786Sps number = 1; 1545128348Stjr if (edit_index((int) number)) 154660786Sps error("No such file", NULL_PARG); 154760786Sps break; 154860786Sps 154960786Sps case A_REMOVE_FILE: 155060786Sps if (ch_getflags() & CH_HELPFILE) 155160786Sps break; 155260786Sps old_ifile = curr_ifile; 155360786Sps new_ifile = getoff_ifile(curr_ifile); 155460786Sps if (new_ifile == NULL_IFILE) 155560786Sps { 155660786Sps bell(); 155760786Sps break; 155860786Sps } 155960786Sps if (edit_ifile(new_ifile) != 0) 156060786Sps { 156160786Sps reedit_ifile(old_ifile); 156260786Sps break; 156360786Sps } 156460786Sps del_ifile(old_ifile); 156560786Sps break; 156660786Sps 156760786Sps case A_OPT_TOGGLE: 156860786Sps optflag = OPT_TOGGLE; 156960786Sps optgetname = FALSE; 157060786Sps mca_opt_toggle(); 157160786Sps c = getcc(); 157260786Sps goto again; 157360786Sps 157460786Sps case A_DISP_OPTION: 157560786Sps /* 157660786Sps * Report a flag setting. 157760786Sps */ 157860786Sps optflag = OPT_NO_TOGGLE; 157960786Sps optgetname = FALSE; 158060786Sps mca_opt_toggle(); 158160786Sps c = getcc(); 158260786Sps goto again; 158360786Sps 158460786Sps case A_FIRSTCMD: 158560786Sps /* 158660786Sps * Set an initial command for new files. 158760786Sps */ 158860786Sps start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); 158960786Sps c = getcc(); 159060786Sps goto again; 159160786Sps 159260786Sps case A_SHELL: 159360786Sps /* 159460786Sps * Shell escape. 159560786Sps */ 159660786Sps#if SHELL_ESCAPE 159760786Sps if (secure) 159860786Sps { 159960786Sps error("Command not available", NULL_PARG); 160060786Sps break; 160160786Sps } 160260786Sps start_mca(A_SHELL, "!", ml_shell, 0); 160360786Sps c = getcc(); 160460786Sps goto again; 160560786Sps#else 160660786Sps error("Command not available", NULL_PARG); 160760786Sps break; 160860786Sps#endif 160960786Sps 161060786Sps case A_SETMARK: 161160786Sps /* 161260786Sps * Set a mark. 161360786Sps */ 161460786Sps if (ch_getflags() & CH_HELPFILE) 161560786Sps break; 161660786Sps start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); 161760786Sps c = getcc(); 1618161478Sdelphij if (c == erase_char || c == erase2_char || 1619161478Sdelphij c == kill_char || c == '\n' || c == '\r') 162060786Sps break; 162160786Sps setmark(c); 162260786Sps break; 162360786Sps 162460786Sps case A_GOMARK: 162560786Sps /* 162660786Sps * Go to a mark. 162760786Sps */ 162860786Sps start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); 162960786Sps c = getcc(); 1630161478Sdelphij if (c == erase_char || c == erase2_char || 1631161478Sdelphij c == kill_char || c == '\n' || c == '\r') 163260786Sps break; 1633191930Sdelphij cmd_exec(); 163460786Sps gomark(c); 163560786Sps break; 163660786Sps 163760786Sps case A_PIPE: 163860786Sps#if PIPEC 163960786Sps if (secure) 164060786Sps { 164160786Sps error("Command not available", NULL_PARG); 164260786Sps break; 164360786Sps } 164460786Sps start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); 164560786Sps c = getcc(); 1646161478Sdelphij if (c == erase_char || c == erase2_char || c == kill_char) 164760786Sps break; 164860786Sps if (c == '\n' || c == '\r') 164960786Sps c = '.'; 165060786Sps if (badmark(c)) 165160786Sps break; 165260786Sps pipec = c; 165360786Sps start_mca(A_PIPE, "!", ml_shell, 0); 165460786Sps c = getcc(); 165560786Sps goto again; 165660786Sps#else 165760786Sps error("Command not available", NULL_PARG); 165860786Sps break; 165960786Sps#endif 166060786Sps 166160786Sps case A_B_BRACKET: 166260786Sps case A_F_BRACKET: 166360786Sps start_mca(action, "Brackets: ", (void*)NULL, 0); 166460786Sps c = getcc(); 166560786Sps goto again; 166660786Sps 166760786Sps case A_LSHIFT: 166889022Sps if (number > 0) 166989022Sps shift_count = number; 167089022Sps else 167163131Sps number = (shift_count > 0) ? 167263131Sps shift_count : sc_width / 2; 167360786Sps if (number > hshift) 167460786Sps number = hshift; 167560786Sps hshift -= number; 167660786Sps screen_trashed = 1; 167760786Sps break; 167860786Sps 167960786Sps case A_RSHIFT: 168089022Sps if (number > 0) 168189022Sps shift_count = number; 168289022Sps else 168363131Sps number = (shift_count > 0) ? 168463131Sps shift_count : sc_width / 2; 168560786Sps hshift += number; 168660786Sps screen_trashed = 1; 168760786Sps break; 168860786Sps 168960786Sps case A_PREFIX: 169060786Sps /* 169160786Sps * The command is incomplete (more chars are needed). 169260786Sps * Display the current char, so the user knows 169360786Sps * what's going on, and get another character. 169460786Sps */ 169560786Sps if (mca != A_PREFIX) 169660786Sps { 169760786Sps cmd_reset(); 169860786Sps start_mca(A_PREFIX, " ", (void*)NULL, 169960786Sps CF_QUIT_ON_ERASE); 170060786Sps (void) cmd_char(c); 170160786Sps } 170260786Sps c = getcc(); 170360786Sps goto again; 170460786Sps 170560786Sps case A_NOACTION: 170660786Sps break; 170760786Sps 170860786Sps default: 170960786Sps bell(); 171060786Sps break; 171160786Sps } 171260786Sps } 171360786Sps} 1714