command.c revision 170967
160812Sps/* $FreeBSD: head/contrib/less/command.c 170967 2007-06-21 10:44:50Z delphij $ */ 260786Sps/* 3170259Sdelphij * Copyright (C) 1984-2007 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 hit_eof; 3060786Spsextern int sc_width; 3160786Spsextern int sc_height; 3260786Spsextern int swindow; 3360786Spsextern int jump_sline; 3460786Spsextern int quitting; 3560786Spsextern int wscroll; 3660786Spsextern int top_scroll; 3760786Spsextern int ignore_eoi; 3860786Spsextern int secure; 3960786Spsextern int hshift; 4060786Spsextern int show_attn; 41170259Sdelphijextern int less_is_more; 4260786Spsextern char *every_first_cmd; 4360786Spsextern char *curr_altfilename; 4460786Spsextern char version[]; 4560786Spsextern struct scrpos initial_scrpos; 4660786Spsextern IFILE curr_ifile; 4760786Spsextern void constant *ml_search; 4860786Spsextern void constant *ml_examine; 4960786Sps#if SHELL_ESCAPE || PIPEC 5060786Spsextern void constant *ml_shell; 5160786Sps#endif 5260786Sps#if EDITOR 5360786Spsextern char *editor; 5460786Spsextern char *editproto; 5560786Sps#endif 5660786Spsextern int screen_trashed; /* The screen has been overwritten */ 5763131Spsextern int shift_count; 58170259Sdelphijextern int oldbot; 59170259Sdelphijextern int forw_prompt; 6060786Sps 6160786Spsstatic char ungot[UNGOT_SIZE]; 6260786Spsstatic char *ungotp = NULL; 6360786Sps#if SHELL_ESCAPE 6460786Spsstatic char *shellcmd = NULL; /* For holding last shell command for "!!" */ 6560786Sps#endif 6660786Spsstatic int mca; /* The multicharacter command (action) */ 6760786Spsstatic int search_type; /* The previous type of search */ 68128348Stjrstatic LINENUM number; /* The number typed by the user */ 69170259Sdelphijstatic long fraction; /* The fractional part of the number */ 7060786Spsstatic char optchar; 7160786Spsstatic int optflag; 7260786Spsstatic int optgetname; 7360786Spsstatic POSITION bottompos; 74161478Sdelphijstatic int save_hshift; 7560786Sps#if PIPEC 7660786Spsstatic char pipec; 7760786Sps#endif 7860786Sps 7960786Spsstatic void multi_search(); 8060786Sps 8160786Sps/* 82170259Sdelphij * Move the cursor to start of prompt line before executing a command. 8360786Sps * This looks nicer if the command takes a long time before 8460786Sps * updating the screen. 8560786Sps */ 8660786Sps static void 8760786Spscmd_exec() 8860786Sps{ 8960786Sps clear_attn(); 90170967Sdelphij clear_bot(); 9160786Sps flush(); 9260786Sps} 9360786Sps 9460786Sps/* 9560786Sps * Set up the display to start a new multi-character command. 9660786Sps */ 9760786Sps static void 9860786Spsstart_mca(action, prompt, mlist, cmdflags) 9960786Sps int action; 10060786Sps char *prompt; 10160786Sps void *mlist; 10260786Sps int cmdflags; 10360786Sps{ 10460786Sps mca = action; 105170259Sdelphij clear_bot(); 10660786Sps clear_cmd(); 10760786Sps cmd_putstr(prompt); 10860786Sps set_mlist(mlist, cmdflags); 10960786Sps} 11060786Sps 11160786Sps public int 11260786Spsin_mca() 11360786Sps{ 11460786Sps return (mca != 0 && mca != A_PREFIX); 11560786Sps} 11660786Sps 11760786Sps/* 11860786Sps * Set up the display to start a new search command. 11960786Sps */ 12060786Sps static void 12160786Spsmca_search() 12260786Sps{ 12360786Sps if (search_type & SRCH_FORW) 12460786Sps mca = A_F_SEARCH; 12560786Sps else 12660786Sps mca = A_B_SEARCH; 12760786Sps 128170259Sdelphij clear_bot(); 12960786Sps clear_cmd(); 13060786Sps 13160786Sps if (search_type & SRCH_NO_MATCH) 13260786Sps cmd_putstr("Non-match "); 13360786Sps if (search_type & SRCH_FIRST_FILE) 13460786Sps cmd_putstr("First-file "); 13560786Sps if (search_type & SRCH_PAST_EOF) 13660786Sps cmd_putstr("EOF-ignore "); 13760786Sps if (search_type & SRCH_NO_MOVE) 13860786Sps cmd_putstr("Keep-pos "); 13960786Sps if (search_type & SRCH_NO_REGEX) 14060786Sps cmd_putstr("Regex-off "); 14160786Sps 14260786Sps if (search_type & SRCH_FORW) 14360786Sps cmd_putstr("/"); 14460786Sps else 14560786Sps cmd_putstr("?"); 14660786Sps set_mlist(ml_search, 0); 14760786Sps} 14860786Sps 14960786Sps/* 15060786Sps * Set up the display to start a new toggle-option command. 15160786Sps */ 15260786Sps static void 15360786Spsmca_opt_toggle() 15460786Sps{ 15560786Sps int no_prompt; 15660786Sps int flag; 15760786Sps char *dash; 15860786Sps 15960786Sps no_prompt = (optflag & OPT_NO_PROMPT); 16060786Sps flag = (optflag & ~OPT_NO_PROMPT); 16160786Sps dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; 16260786Sps 16360786Sps mca = A_OPT_TOGGLE; 164170259Sdelphij clear_bot(); 16560786Sps clear_cmd(); 16660786Sps cmd_putstr(dash); 16760786Sps if (optgetname) 16860786Sps cmd_putstr(dash); 16960786Sps if (no_prompt) 17060786Sps cmd_putstr("(P)"); 17160786Sps switch (flag) 17260786Sps { 17360786Sps case OPT_UNSET: 17460786Sps cmd_putstr("+"); 17560786Sps break; 17660786Sps case OPT_SET: 17760786Sps cmd_putstr("!"); 17860786Sps break; 17960786Sps } 18060786Sps set_mlist(NULL, 0); 18160786Sps} 18260786Sps 18360786Sps/* 18460786Sps * Execute a multicharacter command. 18560786Sps */ 18660786Sps static void 18760786Spsexec_mca() 18860786Sps{ 18960786Sps register char *cbuf; 19060786Sps 19160786Sps cmd_exec(); 19260786Sps cbuf = get_cmdbuf(); 19360786Sps 19460786Sps switch (mca) 19560786Sps { 19660786Sps case A_F_SEARCH: 19760786Sps case A_B_SEARCH: 198128348Stjr multi_search(cbuf, (int) number); 19960786Sps break; 20060786Sps case A_FIRSTCMD: 20160786Sps /* 20260786Sps * Skip leading spaces or + signs in the string. 20360786Sps */ 20460786Sps while (*cbuf == '+' || *cbuf == ' ') 20560786Sps cbuf++; 20660786Sps if (every_first_cmd != NULL) 20760786Sps free(every_first_cmd); 20860786Sps if (*cbuf == '\0') 20960786Sps every_first_cmd = NULL; 21060786Sps else 21160786Sps every_first_cmd = save(cbuf); 21260786Sps break; 21360786Sps case A_OPT_TOGGLE: 21460786Sps toggle_option(optchar, cbuf, optflag); 21560786Sps optchar = '\0'; 21660786Sps break; 21760786Sps case A_F_BRACKET: 218128348Stjr match_brac(cbuf[0], cbuf[1], 1, (int) number); 21960786Sps break; 22060786Sps case A_B_BRACKET: 221128348Stjr match_brac(cbuf[1], cbuf[0], 0, (int) number); 22260786Sps break; 22360786Sps#if EXAMINE 22460786Sps case A_EXAMINE: 22560786Sps if (secure) 22660786Sps break; 22760786Sps edit_list(cbuf); 228128348Stjr#if TAGS 22989022Sps /* If tag structure is loaded then clean it up. */ 23089022Sps cleantags(); 231128348Stjr#endif 23260786Sps break; 23360786Sps#endif 23460786Sps#if SHELL_ESCAPE 23560786Sps case A_SHELL: 23660786Sps /* 23760786Sps * !! just uses whatever is in shellcmd. 23860786Sps * Otherwise, copy cmdbuf to shellcmd, 23960786Sps * expanding any special characters ("%" or "#"). 24060786Sps */ 24160786Sps if (*cbuf != '!') 24260786Sps { 24360786Sps if (shellcmd != NULL) 24460786Sps free(shellcmd); 24560786Sps shellcmd = fexpand(cbuf); 24660786Sps } 24760786Sps 24860786Sps if (secure) 24960786Sps break; 25060786Sps if (shellcmd == NULL) 25160786Sps lsystem("", "!done"); 25260786Sps else 25360786Sps lsystem(shellcmd, "!done"); 25460786Sps break; 25560786Sps#endif 25660786Sps#if PIPEC 25760786Sps case A_PIPE: 25860786Sps if (secure) 25960786Sps break; 26060786Sps (void) pipe_mark(pipec, cbuf); 26160786Sps error("|done", NULL_PARG); 26260786Sps break; 26360786Sps#endif 26460786Sps } 26560786Sps} 26660786Sps 26760786Sps/* 26860786Sps * Add a character to a multi-character command. 26960786Sps */ 27060786Sps static int 27160786Spsmca_char(c) 27260786Sps int c; 27360786Sps{ 27460786Sps char *p; 27560786Sps int flag; 27660786Sps char buf[3]; 27760786Sps PARG parg; 27860786Sps 27960786Sps switch (mca) 28060786Sps { 28160786Sps case 0: 28260786Sps /* 28360786Sps * Not in a multicharacter command. 28460786Sps */ 28560786Sps return (NO_MCA); 28660786Sps 28760786Sps case A_PREFIX: 28860786Sps /* 28960786Sps * In the prefix of a command. 29060786Sps * This not considered a multichar command 29160786Sps * (even tho it uses cmdbuf, etc.). 29260786Sps * It is handled in the commands() switch. 29360786Sps */ 29460786Sps return (NO_MCA); 29560786Sps 29660786Sps case A_DIGIT: 29760786Sps /* 29860786Sps * Entering digits of a number. 29960786Sps * Terminated by a non-digit. 30060786Sps */ 301170259Sdelphij if (!((c >= '0' && c <= '9') || c == '.') && 30289022Sps editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) 30360786Sps { 30460786Sps /* 30560786Sps * Not part of the number. 30660786Sps * Treat as a normal command character. 30760786Sps */ 308170259Sdelphij number = cmd_int(&fraction); 30960786Sps mca = 0; 31060786Sps cmd_accept(); 31160786Sps return (NO_MCA); 31260786Sps } 31360786Sps break; 31460786Sps 31560786Sps case A_OPT_TOGGLE: 31660786Sps /* 31760786Sps * Special case for the TOGGLE_OPTION command. 31860786Sps * If the option letter which was entered is a 31960786Sps * single-char option, execute the command immediately, 32060786Sps * so user doesn't have to hit RETURN. 32160786Sps * If the first char is + or -, this indicates 32260786Sps * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE. 32360786Sps * "--" begins inputting a long option name. 32460786Sps */ 32560786Sps if (optchar == '\0' && len_cmdbuf() == 0) 32660786Sps { 32760786Sps flag = (optflag & ~OPT_NO_PROMPT); 32860786Sps if (flag == OPT_NO_TOGGLE) 32960786Sps { 33060786Sps switch (c) 33160786Sps { 33260786Sps case '_': 33360786Sps /* "__" = long option name. */ 33460786Sps optgetname = TRUE; 33560786Sps mca_opt_toggle(); 33660786Sps return (MCA_MORE); 33760786Sps } 33860786Sps } else 33960786Sps { 34060786Sps switch (c) 34160786Sps { 34260786Sps case '+': 34360786Sps /* "-+" = UNSET. */ 34460786Sps optflag = (flag == OPT_UNSET) ? 34560786Sps OPT_TOGGLE : OPT_UNSET; 34660786Sps mca_opt_toggle(); 34760786Sps return (MCA_MORE); 34860786Sps case '!': 34960786Sps /* "-!" = SET */ 35060786Sps optflag = (flag == OPT_SET) ? 35160786Sps OPT_TOGGLE : OPT_SET; 35260786Sps mca_opt_toggle(); 35360786Sps return (MCA_MORE); 35460786Sps case CONTROL('P'): 35560786Sps optflag ^= OPT_NO_PROMPT; 35660786Sps mca_opt_toggle(); 35760786Sps return (MCA_MORE); 35860786Sps case '-': 35960786Sps /* "--" = long option name. */ 36060786Sps optgetname = TRUE; 36160786Sps mca_opt_toggle(); 36260786Sps return (MCA_MORE); 36360786Sps } 36460786Sps } 36560786Sps } 36660786Sps if (optgetname) 36760786Sps { 36860786Sps /* 36960786Sps * We're getting a long option name. 37060786Sps * See if we've matched an option name yet. 37160786Sps * If so, display the complete name and stop 37260786Sps * accepting chars until user hits RETURN. 37360786Sps */ 374128348Stjr struct loption *o; 37560786Sps char *oname; 37660786Sps int lc; 37760786Sps 37860786Sps if (c == '\n' || c == '\r') 37960786Sps { 38060786Sps /* 38160786Sps * When the user hits RETURN, make sure 38260786Sps * we've matched an option name, then 38360786Sps * pretend he just entered the equivalent 38460786Sps * option letter. 38560786Sps */ 38660786Sps if (optchar == '\0') 38760786Sps { 38860786Sps parg.p_string = get_cmdbuf(); 38960786Sps error("There is no --%s option", &parg); 39060786Sps return (MCA_DONE); 39160786Sps } 39260786Sps optgetname = FALSE; 39360786Sps cmd_reset(); 39460786Sps c = optchar; 39560786Sps } else 39660786Sps { 39760786Sps if (optchar != '\0') 39860786Sps { 39960786Sps /* 40060786Sps * Already have a match for the name. 40160786Sps * Don't accept anything but erase/kill. 40260786Sps */ 403161478Sdelphij if (c == erase_char || 404161478Sdelphij c == erase2_char || 405161478Sdelphij c == kill_char) 40660786Sps return (MCA_DONE); 40760786Sps return (MCA_MORE); 40860786Sps } 40960786Sps /* 41060786Sps * Add char to cmd buffer and try to match 41160786Sps * the option name. 41260786Sps */ 41360786Sps if (cmd_char(c) == CC_QUIT) 41460786Sps return (MCA_DONE); 41560786Sps p = get_cmdbuf(); 416161478Sdelphij lc = ASCII_IS_LOWER(p[0]); 41760786Sps o = findopt_name(&p, &oname, NULL); 41860786Sps if (o != NULL) 41960786Sps { 42060786Sps /* 42160786Sps * Got a match. 42260786Sps * Remember the option letter and 42360786Sps * display the full option name. 42460786Sps */ 42560786Sps optchar = o->oletter; 426161478Sdelphij if (!lc && ASCII_IS_LOWER(optchar)) 427161478Sdelphij optchar = ASCII_TO_UPPER(optchar); 42860786Sps cmd_reset(); 42960786Sps mca_opt_toggle(); 43060786Sps for (p = oname; *p != '\0'; p++) 43160786Sps { 43260786Sps c = *p; 433161478Sdelphij if (!lc && ASCII_IS_LOWER(c)) 434161478Sdelphij c = ASCII_TO_UPPER(c); 43560786Sps if (cmd_char(c) != CC_OK) 43660786Sps return (MCA_DONE); 43760786Sps } 43860786Sps } 43960786Sps return (MCA_MORE); 44060786Sps } 44160786Sps } else 44260786Sps { 443161478Sdelphij if (c == erase_char || c == erase2_char || c == kill_char) 44460786Sps break; 44560786Sps if (optchar != '\0') 44660786Sps /* We already have the option letter. */ 44760786Sps break; 44860786Sps } 44960786Sps 45060786Sps optchar = c; 45160786Sps if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || 45260786Sps single_char_option(c)) 45360786Sps { 45460786Sps toggle_option(c, "", optflag); 45560786Sps return (MCA_DONE); 45660786Sps } 45760786Sps /* 45860786Sps * Display a prompt appropriate for the option letter. 45960786Sps */ 46060786Sps if ((p = opt_prompt(c)) == NULL) 46160786Sps { 46260786Sps buf[0] = '-'; 46360786Sps buf[1] = c; 46460786Sps buf[2] = '\0'; 46560786Sps p = buf; 46660786Sps } 46760786Sps start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0); 46860786Sps return (MCA_MORE); 46960786Sps 47060786Sps case A_F_SEARCH: 47160786Sps case A_B_SEARCH: 47260786Sps /* 47360786Sps * Special case for search commands. 47460786Sps * Certain characters as the first char of 47560786Sps * the pattern have special meaning: 47660786Sps * ! Toggle the NO_MATCH flag 47760786Sps * * Toggle the PAST_EOF flag 47860786Sps * @ Toggle the FIRST_FILE flag 47960786Sps */ 48060786Sps if (len_cmdbuf() > 0) 48160786Sps /* 48260786Sps * Only works for the first char of the pattern. 48360786Sps */ 48460786Sps break; 48560786Sps 48660786Sps flag = 0; 48760786Sps switch (c) 48860786Sps { 48960812Sps case '*': 490170259Sdelphij if (less_is_more) 49160812Sps break; 49260786Sps case CONTROL('E'): /* ignore END of file */ 49360786Sps flag = SRCH_PAST_EOF; 49460786Sps break; 49560812Sps case '@': 496170259Sdelphij if (less_is_more) 49760812Sps break; 49860786Sps case CONTROL('F'): /* FIRST file */ 49960786Sps flag = SRCH_FIRST_FILE; 50060786Sps break; 50160786Sps case CONTROL('K'): /* KEEP position */ 50260786Sps flag = SRCH_NO_MOVE; 50360786Sps break; 50460786Sps case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ 50560786Sps flag = SRCH_NO_REGEX; 50660786Sps break; 50760786Sps case CONTROL('N'): /* NOT match */ 50860786Sps case '!': 50960786Sps flag = SRCH_NO_MATCH; 51060786Sps break; 51160786Sps } 51260786Sps if (flag != 0) 51360786Sps { 51460786Sps search_type ^= flag; 51560786Sps mca_search(); 51660786Sps return (MCA_MORE); 51760786Sps } 51860786Sps break; 51960786Sps } 52060786Sps 52160786Sps /* 52260786Sps * Any other multicharacter command 52360786Sps * is terminated by a newline. 52460786Sps */ 52560786Sps if (c == '\n' || c == '\r') 52660786Sps { 52760786Sps /* 52860786Sps * Execute the command. 52960786Sps */ 53060786Sps exec_mca(); 53160786Sps return (MCA_DONE); 53260786Sps } 53360786Sps 53460786Sps /* 53560786Sps * Append the char to the command buffer. 53660786Sps */ 53760786Sps if (cmd_char(c) == CC_QUIT) 53860786Sps /* 53960786Sps * Abort the multi-char command. 54060786Sps */ 54160786Sps return (MCA_DONE); 54260786Sps 54360786Sps if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) 54460786Sps { 54560786Sps /* 54660786Sps * Special case for the bracket-matching commands. 54760786Sps * Execute the command after getting exactly two 54860786Sps * characters from the user. 54960786Sps */ 55060786Sps exec_mca(); 55160786Sps return (MCA_DONE); 55260786Sps } 55360786Sps 55460786Sps /* 55560786Sps * Need another character. 55660786Sps */ 55760786Sps return (MCA_MORE); 55860786Sps} 55960786Sps 56060786Sps/* 56160786Sps * Make sure the screen is displayed. 56260786Sps */ 56360786Sps static void 56460786Spsmake_display() 56560786Sps{ 56660786Sps /* 56760786Sps * If nothing is displayed yet, display starting from initial_scrpos. 56860786Sps */ 56960786Sps if (empty_screen()) 57060786Sps { 57160786Sps if (initial_scrpos.pos == NULL_POSITION) 57260786Sps /* 57360786Sps * {{ Maybe this should be: 57460786Sps * jump_loc(ch_zero(), jump_sline); 57560786Sps * but this behavior seems rather unexpected 57660786Sps * on the first screen. }} 57760786Sps */ 57860786Sps jump_loc(ch_zero(), 1); 57960786Sps else 58060786Sps jump_loc(initial_scrpos.pos, initial_scrpos.ln); 58160786Sps } else if (screen_trashed) 58260786Sps { 58360786Sps int save_top_scroll; 58460786Sps save_top_scroll = top_scroll; 58560786Sps top_scroll = 1; 58660786Sps repaint(); 58760786Sps top_scroll = save_top_scroll; 58860786Sps } 58960786Sps} 59060786Sps 59160786Sps/* 59260786Sps * Display the appropriate prompt. 59360786Sps */ 59460786Sps static void 59560786Spsprompt() 59660786Sps{ 59760786Sps register char *p; 59860786Sps 59960786Sps if (ungotp != NULL && ungotp > ungot) 60060786Sps { 60160786Sps /* 60260786Sps * No prompt necessary if commands are from 60360786Sps * ungotten chars rather than from the user. 60460786Sps */ 60560786Sps return; 60660786Sps } 60760786Sps 60860786Sps /* 60960786Sps * Make sure the screen is displayed. 61060786Sps */ 61160786Sps make_display(); 61260786Sps bottompos = position(BOTTOM_PLUS_ONE); 61360786Sps 61460786Sps /* 615161478Sdelphij * If we've hit EOF on the last file, and the -E flag is set 616161478Sdelphij * (or -F is set and this is the first prompt), then quit. 617161478Sdelphij * {{ Relying on "first prompt" to detect a single-screen file 618161478Sdelphij * fails if +G is used, for example. }} 61960786Sps */ 620170259Sdelphij if ((get_quit_at_eof() == OPT_ONPLUS || quit_if_one_screen) && 62160786Sps hit_eof && !(ch_getflags() & CH_HELPFILE) && 62260786Sps next_ifile(curr_ifile) == NULL_IFILE) 62360786Sps quit(QUIT_OK); 62460786Sps quit_if_one_screen = FALSE; 62560786Sps#if 0 /* This doesn't work well because some "te"s clear the screen. */ 62660786Sps /* 62760786Sps * If the -e flag is set and we've hit EOF on the last file, 62860786Sps * and the file is squished (shorter than the screen), quit. 62960786Sps */ 630170259Sdelphij if (get_quit_at_eof() && squished && 63160786Sps next_ifile(curr_ifile) == NULL_IFILE) 63260786Sps quit(QUIT_OK); 63360786Sps#endif 63460786Sps 63589022Sps#if MSDOS_COMPILER==WIN32C 63689022Sps /* 63789022Sps * In Win32, display the file name in the window title. 63889022Sps */ 63989022Sps if (!(ch_getflags() & CH_HELPFILE)) 64089022Sps SetConsoleTitle(pr_expand("Less?f - %f.", 0)); 64189022Sps#endif 64260786Sps /* 64360786Sps * Select the proper prompt and display it. 64460786Sps */ 645170259Sdelphij /* 646170259Sdelphij * If the previous action was a forward movement, 647170259Sdelphij * don't clear the bottom line of the display; 648170259Sdelphij * just print the prompt since the forward movement guarantees 649170259Sdelphij * that we're in the right position to display the prompt. 650170259Sdelphij * Clearing the line could cause a problem: for example, if the last 651170259Sdelphij * line displayed ended at the right screen edge without a newline, 652170259Sdelphij * then clearing would clear the last displayed line rather than 653170259Sdelphij * the prompt line. 654170259Sdelphij */ 655170259Sdelphij if (!forw_prompt) 656170259Sdelphij clear_bot(); 65760786Sps clear_cmd(); 658170259Sdelphij forw_prompt = 0; 65960786Sps p = pr_string(); 660161478Sdelphij if (p == NULL || *p == '\0') 66160786Sps putchr(':'); 66260786Sps else 66360786Sps { 664161478Sdelphij at_enter(AT_STANDOUT); 66560786Sps putstr(p); 666161478Sdelphij at_exit(); 66760786Sps } 668170259Sdelphij clear_eol(); 66960786Sps} 67060786Sps 67160786Sps/* 67260786Sps * Display the less version message. 67360786Sps */ 67460786Sps public void 67560786Spsdispversion() 67660786Sps{ 67760786Sps PARG parg; 67860786Sps 67960786Sps parg.p_string = version; 68060786Sps error("less %s", &parg); 68160786Sps} 68260786Sps 68360786Sps/* 68460786Sps * Get command character. 68560786Sps * The character normally comes from the keyboard, 68660786Sps * but may come from ungotten characters 68760786Sps * (characters previously given to ungetcc or ungetsc). 68860786Sps */ 68960786Sps public int 69060786Spsgetcc() 69160786Sps{ 69260786Sps if (ungotp == NULL) 69360786Sps /* 69460786Sps * Normal case: no ungotten chars, so get one from the user. 69560786Sps */ 69660786Sps return (getchr()); 69760786Sps 69860786Sps if (ungotp > ungot) 69960786Sps /* 70060786Sps * Return the next ungotten char. 70160786Sps */ 70260786Sps return (*--ungotp); 70360786Sps 70460786Sps /* 70560786Sps * We have just run out of ungotten chars. 70660786Sps */ 70760786Sps ungotp = NULL; 70860786Sps if (len_cmdbuf() == 0 || !empty_screen()) 70960786Sps return (getchr()); 71060786Sps /* 71160786Sps * Command is incomplete, so try to complete it. 71260786Sps */ 71360786Sps switch (mca) 71460786Sps { 71560786Sps case A_DIGIT: 71660786Sps /* 71760786Sps * We have a number but no command. Treat as #g. 71860786Sps */ 71960786Sps return ('g'); 72060786Sps 72160786Sps case A_F_SEARCH: 72260786Sps case A_B_SEARCH: 72360786Sps /* 72460786Sps * We have "/string" but no newline. Add the \n. 72560786Sps */ 72660786Sps return ('\n'); 72760786Sps 72860786Sps default: 72960786Sps /* 73060786Sps * Some other incomplete command. Let user complete it. 73160786Sps */ 73260786Sps return (getchr()); 73360786Sps } 73460786Sps} 73560786Sps 73660786Sps/* 73760786Sps * "Unget" a command character. 73860786Sps * The next getcc() will return this character. 73960786Sps */ 74060786Sps public void 74160786Spsungetcc(c) 74260786Sps int c; 74360786Sps{ 74460786Sps if (ungotp == NULL) 74560786Sps ungotp = ungot; 74660786Sps if (ungotp >= ungot + sizeof(ungot)) 74760786Sps { 74860786Sps error("ungetcc overflow", NULL_PARG); 74960786Sps quit(QUIT_ERROR); 75060786Sps } 75160786Sps *ungotp++ = c; 75260786Sps} 75360786Sps 75460786Sps/* 75560786Sps * Unget a whole string of command characters. 75660786Sps * The next sequence of getcc()'s will return this string. 75760786Sps */ 75860786Sps public void 75960786Spsungetsc(s) 76060786Sps char *s; 76160786Sps{ 76260786Sps register char *p; 76360786Sps 76460786Sps for (p = s + strlen(s) - 1; p >= s; p--) 76560786Sps ungetcc(*p); 76660786Sps} 76760786Sps 76860786Sps/* 76960786Sps * Search for a pattern, possibly in multiple files. 77060786Sps * If SRCH_FIRST_FILE is set, begin searching at the first file. 77160786Sps * If SRCH_PAST_EOF is set, continue the search thru multiple files. 77260786Sps */ 77360786Sps static void 77460786Spsmulti_search(pattern, n) 77560786Sps char *pattern; 77660786Sps int n; 77760786Sps{ 77860786Sps register int nomore; 77960786Sps IFILE save_ifile; 78060786Sps int changed_file; 78160786Sps 78260786Sps changed_file = 0; 78360786Sps save_ifile = save_curr_ifile(); 78460786Sps 78560786Sps if (search_type & SRCH_FIRST_FILE) 78660786Sps { 78760786Sps /* 78860786Sps * Start at the first (or last) file 78960786Sps * in the command line list. 79060786Sps */ 79160786Sps if (search_type & SRCH_FORW) 79260786Sps nomore = edit_first(); 79360786Sps else 79460786Sps nomore = edit_last(); 79560786Sps if (nomore) 79660786Sps { 79760786Sps unsave_ifile(save_ifile); 79860786Sps return; 79960786Sps } 80060786Sps changed_file = 1; 80160786Sps search_type &= ~SRCH_FIRST_FILE; 80260786Sps } 80360786Sps 80460786Sps for (;;) 80560786Sps { 80660786Sps n = search(search_type, pattern, n); 80760786Sps /* 80860786Sps * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared 80960786Sps * after being used once. This allows "n" to work after 81060786Sps * using a /@@ search. 81160786Sps */ 81260786Sps search_type &= ~SRCH_NO_MOVE; 81360786Sps if (n == 0) 81460786Sps { 81560786Sps /* 81660786Sps * Found it. 81760786Sps */ 81860786Sps unsave_ifile(save_ifile); 81960786Sps return; 82060786Sps } 82160786Sps 82260786Sps if (n < 0) 82360786Sps /* 82460786Sps * Some kind of error in the search. 82560786Sps * Error message has been printed by search(). 82660786Sps */ 82760786Sps break; 82860786Sps 82960786Sps if ((search_type & SRCH_PAST_EOF) == 0) 83060786Sps /* 83160786Sps * We didn't find a match, but we're 83260786Sps * supposed to search only one file. 83360786Sps */ 83460786Sps break; 83560786Sps /* 83660786Sps * Move on to the next file. 83760786Sps */ 83860786Sps if (search_type & SRCH_FORW) 83960786Sps nomore = edit_next(1); 84060786Sps else 84160786Sps nomore = edit_prev(1); 84260786Sps if (nomore) 84360786Sps break; 84460786Sps changed_file = 1; 84560786Sps } 84660786Sps 84760786Sps /* 84860786Sps * Didn't find it. 84960786Sps * Print an error message if we haven't already. 85060786Sps */ 85160786Sps if (n > 0) 85260786Sps error("Pattern not found", NULL_PARG); 85360786Sps 85460786Sps if (changed_file) 85560786Sps { 85660786Sps /* 85760786Sps * Restore the file we were originally viewing. 85860786Sps */ 85960786Sps reedit_ifile(save_ifile); 860161478Sdelphij } else 861161478Sdelphij { 862161478Sdelphij unsave_ifile(save_ifile); 86360786Sps } 86460786Sps} 86560786Sps 86660786Sps/* 86760786Sps * Main command processor. 86860786Sps * Accept and execute commands until a quit command. 86960786Sps */ 87060786Sps public void 87160786Spscommands() 87260786Sps{ 87360786Sps register int c; 87460786Sps register int action; 87560786Sps register char *cbuf; 87660786Sps int newaction; 87760786Sps int save_search_type; 87860786Sps char *extra; 87960786Sps char tbuf[2]; 88060786Sps PARG parg; 88160786Sps IFILE old_ifile; 88260786Sps IFILE new_ifile; 88389022Sps char *tagfile; 88460786Sps 88560786Sps search_type = SRCH_FORW; 88660786Sps wscroll = (sc_height + 1) / 2; 88760786Sps newaction = A_NOACTION; 88860786Sps 88960786Sps for (;;) 89060786Sps { 89160786Sps mca = 0; 89260786Sps cmd_accept(); 89360786Sps number = 0; 89460786Sps optchar = '\0'; 89560786Sps 89660786Sps /* 89760786Sps * See if any signals need processing. 89860786Sps */ 89960786Sps if (sigs) 90060786Sps { 90160786Sps psignals(); 90260786Sps if (quitting) 90360786Sps quit(QUIT_SAVED_STATUS); 90460786Sps } 90560786Sps 90660786Sps /* 90760786Sps * See if window size changed, for systems that don't 90860786Sps * generate SIGWINCH. 90960786Sps */ 91060786Sps check_winch(); 91160786Sps 91260786Sps /* 91360786Sps * Display prompt and accept a character. 91460786Sps */ 91560786Sps cmd_reset(); 91660786Sps prompt(); 91760786Sps if (sigs) 91860786Sps continue; 91960786Sps if (newaction == A_NOACTION) 92060786Sps c = getcc(); 92160786Sps 92260786Sps again: 92360786Sps if (sigs) 92460786Sps continue; 92560786Sps 92660786Sps if (newaction != A_NOACTION) 92760786Sps { 92860786Sps action = newaction; 92960786Sps newaction = A_NOACTION; 93060786Sps } else 93160786Sps { 93260786Sps /* 93360786Sps * If we are in a multicharacter command, call mca_char. 93460786Sps * Otherwise we call fcmd_decode to determine the 93560786Sps * action to be performed. 93660786Sps */ 93760786Sps if (mca) 93860786Sps switch (mca_char(c)) 93960786Sps { 94060786Sps case MCA_MORE: 94160786Sps /* 94260786Sps * Need another character. 94360786Sps */ 94460786Sps c = getcc(); 94560786Sps goto again; 94660786Sps case MCA_DONE: 94760786Sps /* 94860786Sps * Command has been handled by mca_char. 94960786Sps * Start clean with a prompt. 95060786Sps */ 95160786Sps continue; 95260786Sps case NO_MCA: 95360786Sps /* 95460786Sps * Not a multi-char command 95560786Sps * (at least, not anymore). 95660786Sps */ 95760786Sps break; 95860786Sps } 95960786Sps 96060786Sps /* 96160786Sps * Decode the command character and decide what to do. 96260786Sps */ 96360786Sps if (mca) 96460786Sps { 96560786Sps /* 96660786Sps * We're in a multichar command. 96760786Sps * Add the character to the command buffer 96860786Sps * and display it on the screen. 96960786Sps * If the user backspaces past the start 97060786Sps * of the line, abort the command. 97160786Sps */ 97260786Sps if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) 97360786Sps continue; 97460786Sps cbuf = get_cmdbuf(); 97560786Sps } else 97660786Sps { 97760786Sps /* 97860786Sps * Don't use cmd_char if we're starting fresh 97960786Sps * at the beginning of a command, because we 98060786Sps * don't want to echo the command until we know 98160786Sps * it is a multichar command. We also don't 98260786Sps * want erase_char/kill_char to be treated 98360786Sps * as line editing characters. 98460786Sps */ 98560786Sps tbuf[0] = c; 98660786Sps tbuf[1] = '\0'; 98760786Sps cbuf = tbuf; 98860786Sps } 98960786Sps extra = NULL; 99060786Sps action = fcmd_decode(cbuf, &extra); 99160786Sps /* 99260786Sps * If an "extra" string was returned, 99360786Sps * process it as a string of command characters. 99460786Sps */ 99560786Sps if (extra != NULL) 99660786Sps ungetsc(extra); 99760786Sps } 99860786Sps /* 99960786Sps * Clear the cmdbuf string. 100060786Sps * (But not if we're in the prefix of a command, 100160786Sps * because the partial command string is kept there.) 100260786Sps */ 100360786Sps if (action != A_PREFIX) 100460786Sps cmd_reset(); 100560786Sps 100660786Sps switch (action) 100760786Sps { 100860786Sps case A_DIGIT: 100960786Sps /* 101060786Sps * First digit of a number. 101160786Sps */ 101260786Sps start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); 101360786Sps goto again; 101460786Sps 101560786Sps case A_F_WINDOW: 101660786Sps /* 101760786Sps * Forward one window (and set the window size). 101860786Sps */ 101960786Sps if (number > 0) 1020128348Stjr swindow = (int) number; 102160786Sps /* FALLTHRU */ 102260786Sps case A_F_SCREEN: 102360786Sps /* 102460786Sps * Forward one screen. 102560786Sps */ 102660786Sps if (number <= 0) 102760786Sps number = get_swindow(); 102860786Sps cmd_exec(); 102960786Sps if (show_attn) 103060786Sps set_attnpos(bottompos); 1031128348Stjr forward((int) number, 0, 1); 103260786Sps break; 103360786Sps 103460786Sps case A_B_WINDOW: 103560786Sps /* 103660786Sps * Backward one window (and set the window size). 103760786Sps */ 103860786Sps if (number > 0) 1039128348Stjr swindow = (int) number; 104060786Sps /* FALLTHRU */ 104160786Sps case A_B_SCREEN: 104260786Sps /* 104360786Sps * Backward one screen. 104460786Sps */ 104560786Sps if (number <= 0) 104660786Sps number = get_swindow(); 104760786Sps cmd_exec(); 1048128348Stjr backward((int) number, 0, 1); 104960786Sps break; 105060786Sps 105160786Sps case A_F_LINE: 105260786Sps /* 105360786Sps * Forward N (default 1) line. 105460786Sps */ 105560786Sps if (number <= 0) 105660786Sps number = 1; 105760786Sps cmd_exec(); 105860786Sps if (show_attn == OPT_ONPLUS && number > 1) 105960786Sps set_attnpos(bottompos); 1060128348Stjr forward((int) number, 0, 0); 106160786Sps break; 106260786Sps 106360786Sps case A_B_LINE: 106460786Sps /* 106560786Sps * Backward N (default 1) line. 106660786Sps */ 106760786Sps if (number <= 0) 106860786Sps number = 1; 106960786Sps cmd_exec(); 1070128348Stjr backward((int) number, 0, 0); 107160786Sps break; 107260786Sps 107360786Sps case A_FF_LINE: 107460786Sps /* 107560786Sps * Force forward N (default 1) line. 107660786Sps */ 107760786Sps if (number <= 0) 107860786Sps number = 1; 107960786Sps cmd_exec(); 108060786Sps if (show_attn == OPT_ONPLUS && number > 1) 108160786Sps set_attnpos(bottompos); 1082128348Stjr forward((int) number, 1, 0); 108360786Sps break; 108460786Sps 108560786Sps case A_BF_LINE: 108660786Sps /* 108760786Sps * Force backward N (default 1) line. 108860786Sps */ 108960786Sps if (number <= 0) 109060786Sps number = 1; 109160786Sps cmd_exec(); 1092128348Stjr backward((int) number, 1, 0); 109360786Sps break; 109460786Sps 109560786Sps case A_FF_SCREEN: 109660786Sps /* 109760786Sps * Force forward one screen. 109860786Sps */ 109960786Sps if (number <= 0) 110060786Sps number = get_swindow(); 110160786Sps cmd_exec(); 110260786Sps if (show_attn == OPT_ONPLUS) 110360786Sps set_attnpos(bottompos); 1104128348Stjr forward((int) number, 1, 0); 110560786Sps break; 110660786Sps 110760786Sps case A_F_FOREVER: 110860786Sps /* 110960786Sps * Forward forever, ignoring EOF. 111060786Sps */ 111160786Sps if (ch_getflags() & CH_HELPFILE) 111260786Sps break; 111360786Sps cmd_exec(); 111460786Sps jump_forw(); 111560786Sps ignore_eoi = 1; 111660786Sps hit_eof = 0; 111760786Sps while (!sigs) 111860786Sps forward(1, 0, 0); 111960786Sps ignore_eoi = 0; 112060786Sps /* 112160786Sps * This gets us back in "F mode" after processing 112260786Sps * a non-abort signal (e.g. window-change). 112360786Sps */ 112460786Sps if (sigs && !ABORT_SIGS()) 112560786Sps newaction = A_F_FOREVER; 112660786Sps break; 112760786Sps 112860786Sps case A_F_SCROLL: 112960786Sps /* 113060786Sps * Forward N lines 113160786Sps * (default same as last 'd' or 'u' command). 113260786Sps */ 113360786Sps if (number > 0) 1134128348Stjr wscroll = (int) number; 113560786Sps cmd_exec(); 113660786Sps if (show_attn == OPT_ONPLUS) 113760786Sps set_attnpos(bottompos); 113860786Sps forward(wscroll, 0, 0); 113960786Sps break; 114060786Sps 114160786Sps case A_B_SCROLL: 114260786Sps /* 114360786Sps * Forward N lines 114460786Sps * (default same as last 'd' or 'u' command). 114560786Sps */ 114660786Sps if (number > 0) 1147128348Stjr wscroll = (int) number; 114860786Sps cmd_exec(); 114960786Sps backward(wscroll, 0, 0); 115060786Sps break; 115160786Sps 115260786Sps case A_FREPAINT: 115360786Sps /* 115460786Sps * Flush buffers, then repaint screen. 115560786Sps * Don't flush the buffers on a pipe! 115660786Sps */ 115760786Sps if (ch_getflags() & CH_CANSEEK) 115860786Sps { 115960786Sps ch_flush(); 116060786Sps clr_linenum(); 116160786Sps#if HILITE_SEARCH 116260786Sps clr_hilite(); 116360786Sps#endif 116460786Sps } 116560786Sps /* FALLTHRU */ 116660786Sps case A_REPAINT: 116760786Sps /* 116860786Sps * Repaint screen. 116960786Sps */ 117060786Sps cmd_exec(); 117160786Sps repaint(); 117260786Sps break; 117360786Sps 117460786Sps case A_GOLINE: 117560786Sps /* 117660786Sps * Go to line N, default beginning of file. 117760786Sps */ 117860786Sps if (number <= 0) 117960786Sps number = 1; 118060786Sps cmd_exec(); 118160786Sps jump_back(number); 118260786Sps break; 118360786Sps 118460786Sps case A_PERCENT: 118560786Sps /* 118660786Sps * Go to a specified percentage into the file. 118760786Sps */ 118860786Sps if (number < 0) 1189170259Sdelphij { 119060786Sps number = 0; 1191170259Sdelphij fraction = 0; 1192170259Sdelphij } 119360786Sps if (number > 100) 1194170259Sdelphij { 119560786Sps number = 100; 1196170259Sdelphij fraction = 0; 1197170259Sdelphij } 119860786Sps cmd_exec(); 1199170259Sdelphij jump_percent((int) number, fraction); 120060786Sps break; 120160786Sps 120260786Sps case A_GOEND: 120360786Sps /* 120460786Sps * Go to line N, default end of file. 120560786Sps */ 120660786Sps cmd_exec(); 120760786Sps if (number <= 0) 120860786Sps jump_forw(); 120960786Sps else 121060786Sps jump_back(number); 121160786Sps break; 121260786Sps 121360786Sps case A_GOPOS: 121460786Sps /* 121560786Sps * Go to a specified byte position in the file. 121660786Sps */ 121760786Sps cmd_exec(); 121860786Sps if (number < 0) 121960786Sps number = 0; 1220128348Stjr jump_line_loc((POSITION) number, jump_sline); 122160786Sps break; 122260786Sps 122360786Sps case A_STAT: 122460786Sps /* 122560786Sps * Print file name, etc. 122660786Sps */ 122760786Sps if (ch_getflags() & CH_HELPFILE) 122860786Sps break; 122960786Sps cmd_exec(); 123060786Sps parg.p_string = eq_message(); 123160786Sps error("%s", &parg); 123260786Sps break; 123360786Sps 123460786Sps case A_VERSION: 123560786Sps /* 123660786Sps * Print version number, without the "@(#)". 123760786Sps */ 123860786Sps cmd_exec(); 123960786Sps dispversion(); 124060786Sps break; 124160786Sps 124260786Sps case A_QUIT: 124360786Sps /* 124460786Sps * Exit. 124560786Sps */ 124660786Sps if (curr_ifile != NULL_IFILE && 124760786Sps ch_getflags() & CH_HELPFILE) 124860786Sps { 124960786Sps /* 125060786Sps * Quit while viewing the help file 125160786Sps * just means return to viewing the 125260786Sps * previous file. 125360786Sps */ 1254161478Sdelphij hshift = save_hshift; 125560786Sps if (edit_prev(1) == 0) 125660786Sps break; 125760786Sps } 125860786Sps if (extra != NULL) 125960786Sps quit(*extra); 126060786Sps quit(QUIT_OK); 126160786Sps break; 126260786Sps 126360786Sps/* 126460786Sps * Define abbreviation for a commonly used sequence below. 126560786Sps */ 126660786Sps#define DO_SEARCH() if (number <= 0) number = 1; \ 126760786Sps mca_search(); \ 126860786Sps cmd_exec(); \ 1269128348Stjr multi_search((char *)NULL, (int) number); 127060786Sps 127160786Sps 127260786Sps case A_F_SEARCH: 127360786Sps /* 127460786Sps * Search forward for a pattern. 127560786Sps * Get the first char of the pattern. 127660786Sps */ 127760786Sps search_type = SRCH_FORW; 127860786Sps if (number <= 0) 127960786Sps number = 1; 128060786Sps mca_search(); 128160786Sps c = getcc(); 128260786Sps goto again; 128360786Sps 128460786Sps case A_B_SEARCH: 128560786Sps /* 128660786Sps * Search backward for a pattern. 128760786Sps * Get the first char of the pattern. 128860786Sps */ 128960786Sps search_type = SRCH_BACK; 129060786Sps if (number <= 0) 129160786Sps number = 1; 129260786Sps mca_search(); 129360786Sps c = getcc(); 129460786Sps goto again; 129560786Sps 129660786Sps case A_AGAIN_SEARCH: 129760786Sps /* 129860786Sps * Repeat previous search. 129960786Sps */ 130060786Sps DO_SEARCH(); 130160786Sps break; 130260786Sps 130360786Sps case A_T_AGAIN_SEARCH: 130460786Sps /* 130560786Sps * Repeat previous search, multiple files. 130660786Sps */ 130760786Sps search_type |= SRCH_PAST_EOF; 130860786Sps DO_SEARCH(); 130960786Sps break; 131060786Sps 131160786Sps case A_REVERSE_SEARCH: 131260786Sps /* 131360786Sps * Repeat previous search, in reverse direction. 131460786Sps */ 131560786Sps save_search_type = search_type; 131660786Sps search_type = SRCH_REVERSE(search_type); 131760786Sps DO_SEARCH(); 131860786Sps search_type = save_search_type; 131960786Sps break; 132060786Sps 132160786Sps case A_T_REVERSE_SEARCH: 132260786Sps /* 132360786Sps * Repeat previous search, 132460786Sps * multiple files in reverse direction. 132560786Sps */ 132660786Sps save_search_type = search_type; 132760786Sps search_type = SRCH_REVERSE(search_type); 132860786Sps search_type |= SRCH_PAST_EOF; 132960786Sps DO_SEARCH(); 133060786Sps search_type = save_search_type; 133160786Sps break; 133260786Sps 133360786Sps case A_UNDO_SEARCH: 133460786Sps undo_search(); 133560786Sps break; 133660786Sps 133760786Sps case A_HELP: 133860786Sps /* 133960786Sps * Help. 134060786Sps */ 134160786Sps if (ch_getflags() & CH_HELPFILE) 134260786Sps break; 134360786Sps cmd_exec(); 1344161478Sdelphij save_hshift = hshift; 1345161478Sdelphij hshift = 0; 134660786Sps (void) edit(FAKE_HELPFILE); 134760786Sps break; 134860786Sps 134960786Sps case A_EXAMINE: 135060786Sps#if EXAMINE 135160786Sps /* 135260786Sps * Edit a new file. Get the filename. 135360786Sps */ 135460786Sps if (secure) 135560786Sps { 135660786Sps error("Command not available", NULL_PARG); 135760786Sps break; 135860786Sps } 135960786Sps start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); 136060786Sps c = getcc(); 136160786Sps goto again; 136260786Sps#else 136360786Sps error("Command not available", NULL_PARG); 136460786Sps break; 136560786Sps#endif 136660786Sps 136760786Sps case A_VISUAL: 136860786Sps /* 136960786Sps * Invoke an editor on the input file. 137060786Sps */ 137160786Sps#if EDITOR 137260786Sps if (secure) 137360786Sps { 137460786Sps error("Command not available", NULL_PARG); 137560786Sps break; 137660786Sps } 137760786Sps if (ch_getflags() & CH_HELPFILE) 137860786Sps break; 137960786Sps if (strcmp(get_filename(curr_ifile), "-") == 0) 138060786Sps { 138160786Sps error("Cannot edit standard input", NULL_PARG); 138260786Sps break; 138360786Sps } 138460786Sps if (curr_altfilename != NULL) 138560786Sps { 1386161478Sdelphij error("WARNING: This file was viewed via LESSOPEN", 138760786Sps NULL_PARG); 138860786Sps } 138960786Sps start_mca(A_SHELL, "!", ml_shell, 0); 139060786Sps /* 139160786Sps * Expand the editor prototype string 139260786Sps * and pass it to the system to execute. 139360786Sps * (Make sure the screen is displayed so the 139460786Sps * expansion of "+%lm" works.) 139560786Sps */ 139660786Sps make_display(); 139760786Sps cmd_exec(); 139860786Sps lsystem(pr_expand(editproto, 0), (char*)NULL); 139960786Sps break; 140060786Sps#else 140160786Sps error("Command not available", NULL_PARG); 140260786Sps break; 140360786Sps#endif 140460786Sps 140560786Sps case A_NEXT_FILE: 140660786Sps /* 140760786Sps * Examine next file. 140860786Sps */ 1409128348Stjr#if TAGS 141089022Sps if (ntags()) 141189022Sps { 141289022Sps error("No next file", NULL_PARG); 141389022Sps break; 141489022Sps } 1415128348Stjr#endif 141660786Sps if (number <= 0) 141760786Sps number = 1; 1418128348Stjr if (edit_next((int) number)) 141960786Sps { 1420170259Sdelphij if (get_quit_at_eof() && hit_eof && 142160786Sps !(ch_getflags() & CH_HELPFILE)) 142260786Sps quit(QUIT_OK); 142360786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 142460786Sps error("No %snext file", &parg); 142560786Sps } 142660786Sps break; 142760786Sps 142860786Sps case A_PREV_FILE: 142960786Sps /* 143060786Sps * Examine previous file. 143160786Sps */ 1432128348Stjr#if TAGS 143389022Sps if (ntags()) 143489022Sps { 143589022Sps error("No previous file", NULL_PARG); 143689022Sps break; 143789022Sps } 1438128348Stjr#endif 143960786Sps if (number <= 0) 144060786Sps number = 1; 1441128348Stjr if (edit_prev((int) number)) 144260786Sps { 144360786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 144460786Sps error("No %sprevious file", &parg); 144560786Sps } 144660786Sps break; 144760786Sps 144889022Sps case A_NEXT_TAG: 1449128348Stjr#if TAGS 145089022Sps if (number <= 0) 145189022Sps number = 1; 1452128348Stjr tagfile = nexttag((int) number); 145389022Sps if (tagfile == NULL) 145489022Sps { 145589022Sps error("No next tag", NULL_PARG); 145689022Sps break; 145789022Sps } 145889022Sps if (edit(tagfile) == 0) 145989022Sps { 146089022Sps POSITION pos = tagsearch(); 146189022Sps if (pos != NULL_POSITION) 146289022Sps jump_loc(pos, jump_sline); 146389022Sps } 1464128348Stjr#else 1465128348Stjr error("Command not available", NULL_PARG); 1466128348Stjr#endif 146789022Sps break; 146889022Sps 146989022Sps case A_PREV_TAG: 1470128348Stjr#if TAGS 147189022Sps if (number <= 0) 147289022Sps number = 1; 1473128348Stjr tagfile = prevtag((int) number); 147489022Sps if (tagfile == NULL) 147589022Sps { 147689022Sps error("No previous tag", NULL_PARG); 147789022Sps break; 147889022Sps } 147989022Sps if (edit(tagfile) == 0) 148089022Sps { 148189022Sps POSITION pos = tagsearch(); 148289022Sps if (pos != NULL_POSITION) 148389022Sps jump_loc(pos, jump_sline); 148489022Sps } 1485128348Stjr#else 1486128348Stjr error("Command not available", NULL_PARG); 1487128348Stjr#endif 148889022Sps break; 148989022Sps 149060786Sps case A_INDEX_FILE: 149160786Sps /* 149260786Sps * Examine a particular file. 149360786Sps */ 149460786Sps if (number <= 0) 149560786Sps number = 1; 1496128348Stjr if (edit_index((int) number)) 149760786Sps error("No such file", NULL_PARG); 149860786Sps break; 149960786Sps 150060786Sps case A_REMOVE_FILE: 150160786Sps if (ch_getflags() & CH_HELPFILE) 150260786Sps break; 150360786Sps old_ifile = curr_ifile; 150460786Sps new_ifile = getoff_ifile(curr_ifile); 150560786Sps if (new_ifile == NULL_IFILE) 150660786Sps { 150760786Sps bell(); 150860786Sps break; 150960786Sps } 151060786Sps if (edit_ifile(new_ifile) != 0) 151160786Sps { 151260786Sps reedit_ifile(old_ifile); 151360786Sps break; 151460786Sps } 151560786Sps del_ifile(old_ifile); 151660786Sps break; 151760786Sps 151860786Sps case A_OPT_TOGGLE: 151960786Sps optflag = OPT_TOGGLE; 152060786Sps optgetname = FALSE; 152160786Sps mca_opt_toggle(); 152260786Sps c = getcc(); 152360786Sps goto again; 152460786Sps 152560786Sps case A_DISP_OPTION: 152660786Sps /* 152760786Sps * Report a flag setting. 152860786Sps */ 152960786Sps optflag = OPT_NO_TOGGLE; 153060786Sps optgetname = FALSE; 153160786Sps mca_opt_toggle(); 153260786Sps c = getcc(); 153360786Sps goto again; 153460786Sps 153560786Sps case A_FIRSTCMD: 153660786Sps /* 153760786Sps * Set an initial command for new files. 153860786Sps */ 153960786Sps start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); 154060786Sps c = getcc(); 154160786Sps goto again; 154260786Sps 154360786Sps case A_SHELL: 154460786Sps /* 154560786Sps * Shell escape. 154660786Sps */ 154760786Sps#if SHELL_ESCAPE 154860786Sps if (secure) 154960786Sps { 155060786Sps error("Command not available", NULL_PARG); 155160786Sps break; 155260786Sps } 155360786Sps start_mca(A_SHELL, "!", ml_shell, 0); 155460786Sps c = getcc(); 155560786Sps goto again; 155660786Sps#else 155760786Sps error("Command not available", NULL_PARG); 155860786Sps break; 155960786Sps#endif 156060786Sps 156160786Sps case A_SETMARK: 156260786Sps /* 156360786Sps * Set a mark. 156460786Sps */ 156560786Sps if (ch_getflags() & CH_HELPFILE) 156660786Sps break; 156760786Sps start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); 156860786Sps c = getcc(); 1569161478Sdelphij if (c == erase_char || c == erase2_char || 1570161478Sdelphij c == kill_char || c == '\n' || c == '\r') 157160786Sps break; 157260786Sps setmark(c); 157360786Sps break; 157460786Sps 157560786Sps case A_GOMARK: 157660786Sps /* 157760786Sps * Go to a mark. 157860786Sps */ 157960786Sps start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); 158060786Sps c = getcc(); 1581161478Sdelphij if (c == erase_char || c == erase2_char || 1582161478Sdelphij c == kill_char || c == '\n' || c == '\r') 158360786Sps break; 158460786Sps gomark(c); 158560786Sps break; 158660786Sps 158760786Sps case A_PIPE: 158860786Sps#if PIPEC 158960786Sps if (secure) 159060786Sps { 159160786Sps error("Command not available", NULL_PARG); 159260786Sps break; 159360786Sps } 159460786Sps start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); 159560786Sps c = getcc(); 1596161478Sdelphij if (c == erase_char || c == erase2_char || c == kill_char) 159760786Sps break; 159860786Sps if (c == '\n' || c == '\r') 159960786Sps c = '.'; 160060786Sps if (badmark(c)) 160160786Sps break; 160260786Sps pipec = c; 160360786Sps start_mca(A_PIPE, "!", ml_shell, 0); 160460786Sps c = getcc(); 160560786Sps goto again; 160660786Sps#else 160760786Sps error("Command not available", NULL_PARG); 160860786Sps break; 160960786Sps#endif 161060786Sps 161160786Sps case A_B_BRACKET: 161260786Sps case A_F_BRACKET: 161360786Sps start_mca(action, "Brackets: ", (void*)NULL, 0); 161460786Sps c = getcc(); 161560786Sps goto again; 161660786Sps 161760786Sps case A_LSHIFT: 161889022Sps if (number > 0) 161989022Sps shift_count = number; 162089022Sps else 162163131Sps number = (shift_count > 0) ? 162263131Sps shift_count : sc_width / 2; 162360786Sps if (number > hshift) 162460786Sps number = hshift; 162560786Sps hshift -= number; 162660786Sps screen_trashed = 1; 162760786Sps break; 162860786Sps 162960786Sps case A_RSHIFT: 163089022Sps if (number > 0) 163189022Sps shift_count = number; 163289022Sps else 163363131Sps number = (shift_count > 0) ? 163463131Sps shift_count : sc_width / 2; 163560786Sps hshift += number; 163660786Sps screen_trashed = 1; 163760786Sps break; 163860786Sps 163960786Sps case A_PREFIX: 164060786Sps /* 164160786Sps * The command is incomplete (more chars are needed). 164260786Sps * Display the current char, so the user knows 164360786Sps * what's going on, and get another character. 164460786Sps */ 164560786Sps if (mca != A_PREFIX) 164660786Sps { 164760786Sps cmd_reset(); 164860786Sps start_mca(A_PREFIX, " ", (void*)NULL, 164960786Sps CF_QUIT_ON_ERASE); 165060786Sps (void) cmd_char(c); 165160786Sps } 165260786Sps c = getcc(); 165360786Sps goto again; 165460786Sps 165560786Sps case A_NOACTION: 165660786Sps break; 165760786Sps 165860786Sps default: 165960786Sps bell(); 166060786Sps break; 166160786Sps } 166260786Sps } 166360786Sps} 1664