command.c revision 170259
11556Srgrimes/* $FreeBSD: head/contrib/less/command.c 170259 2007-06-04 01:43:11Z delphij $ */ 21556Srgrimes/* 31556Srgrimes * Copyright (C) 1984-2007 Mark Nudelman 41556Srgrimes * 51556Srgrimes * You may distribute under the terms of either the GNU General Public 61556Srgrimes * License or the Less License, as specified in the README file. 71556Srgrimes * 81556Srgrimes * For more information about less, or for information on how to 91556Srgrimes * contact the author, see the README file. 101556Srgrimes */ 111556Srgrimes 121556Srgrimes 131556Srgrimes/* 141556Srgrimes * User-level command processor. 151556Srgrimes */ 161556Srgrimes 171556Srgrimes#include "less.h" 181556Srgrimes#if MSDOS_COMPILER==WIN32C 191556Srgrimes#include <windows.h> 201556Srgrimes#endif 211556Srgrimes#include "position.h" 221556Srgrimes#include "option.h" 231556Srgrimes#include "cmd.h" 241556Srgrimes 251556Srgrimesextern int erase_char, erase2_char, kill_char; 261556Srgrimesextern int sigs; 271556Srgrimesextern int quit_if_one_screen; 281556Srgrimesextern int squished; 291556Srgrimesextern int hit_eof; 301556Srgrimesextern int sc_width; 311556Srgrimesextern int sc_height; 321556Srgrimesextern int swindow; 331556Srgrimesextern int jump_sline; 3436150Scharnierextern int quitting; 3536150Scharnierextern int wscroll; 3636150Scharnierextern int top_scroll; 371556Srgrimesextern int ignore_eoi; 3899110Sobrienextern int secure; 3999110Sobrienextern int hshift; 401556Srgrimesextern int show_attn; 4117987Speterextern int less_is_more; 4217987Speterextern char *every_first_cmd; 43114763Sobrienextern char *curr_altfilename; 4417987Speterextern char version[]; 451556Srgrimesextern struct scrpos initial_scrpos; 461556Srgrimesextern IFILE curr_ifile; 471556Srgrimesextern void constant *ml_search; 481556Srgrimesextern void constant *ml_examine; 4917525Sache#if SHELL_ESCAPE || PIPEC 5017525Sacheextern void constant *ml_shell; 511556Srgrimes#endif 521556Srgrimes#if EDITOR 531556Srgrimesextern char *editor; 541556Srgrimesextern char *editproto; 551556Srgrimes#endif 561556Srgrimesextern int screen_trashed; /* The screen has been overwritten */ 571556Srgrimesextern int shift_count; 581556Srgrimesextern int oldbot; 591556Srgrimesextern int forw_prompt; 601556Srgrimes 611556Srgrimesstatic char ungot[UNGOT_SIZE]; 621556Srgrimesstatic char *ungotp = NULL; 631556Srgrimes#if SHELL_ESCAPE 6420425Sstevestatic char *shellcmd = NULL; /* For holding last shell command for "!!" */ 6517987Speter#endif 6617987Speterstatic int mca; /* The multicharacter command (action) */ 6717987Speterstatic int search_type; /* The previous type of search */ 681556Srgrimesstatic LINENUM number; /* The number typed by the user */ 691556Srgrimesstatic long fraction; /* The fractional part of the number */ 701556Srgrimesstatic char optchar; 711556Srgrimesstatic int optflag; 721556Srgrimesstatic int optgetname; 731556Srgrimesstatic POSITION bottompos; 741556Srgrimesstatic int save_hshift; 751556Srgrimes#if PIPEC 76201056Sjillesstatic char pipec; 7790111Simp#endif 781556Srgrimes 791556Srgrimesstatic void multi_search(); 801556Srgrimes 8117987Speter/* 821556Srgrimes * Move the cursor to start of prompt line before executing a command. 83208755Sjilles * This looks nicer if the command takes a long time before 8417987Speter * updating the screen. 851556Srgrimes */ 861556Srgrimes static void 871556Srgrimescmd_exec() 881556Srgrimes{ 8997689Stjr clear_attn(); 901556Srgrimes line_left(); 911556Srgrimes flush(); 92159632Sstefanf} 931556Srgrimes 94213760Sobrien/* 951556Srgrimes * Set up the display to start a new multi-character command. 96213760Sobrien */ 9717987Speter static void 98201056Sjillesstart_mca(action, prompt, mlist, cmdflags) 9920425Ssteve int action; 10017987Speter char *prompt; 101201056Sjilles void *mlist; 10220425Ssteve int cmdflags; 103201056Sjilles{ 10420425Ssteve mca = action; 105201056Sjilles clear_bot(); 10620425Ssteve clear_cmd(); 107201056Sjilles cmd_putstr(prompt); 10820425Ssteve set_mlist(mlist, cmdflags); 109201056Sjilles} 11097689Stjr 1118855Srgrimes public int 1121556Srgrimesin_mca() 1131556Srgrimes{ 114201056Sjilles return (mca != 0 && mca != A_PREFIX); 11520425Ssteve} 116201056Sjilles 117159632Sstefanf/* 118208755Sjilles * Set up the display to start a new search command. 119208755Sjilles */ 120208755Sjilles static void 121208755Sjillesmca_search() 122201056Sjilles{ 12320425Ssteve if (search_type & SRCH_FORW) 12420425Ssteve mca = A_F_SEARCH; 12520425Ssteve else 1261556Srgrimes mca = A_B_SEARCH; 1271556Srgrimes 128213760Sobrien clear_bot(); 1291556Srgrimes clear_cmd(); 130213760Sobrien 131207678Sjilles if (search_type & SRCH_NO_MATCH) 132207678Sjilles cmd_putstr("Non-match "); 133207678Sjilles if (search_type & SRCH_FIRST_FILE) 134213760Sobrien cmd_putstr("First-file "); 135207678Sjilles if (search_type & SRCH_PAST_EOF) 136207678Sjilles cmd_putstr("EOF-ignore "); 137207678Sjilles if (search_type & SRCH_NO_MOVE) 138213811Sobrien cmd_putstr("Keep-pos "); 139213811Sobrien if (search_type & SRCH_NO_REGEX) 140213811Sobrien cmd_putstr("Regex-off "); 1411556Srgrimes 1421556Srgrimes if (search_type & SRCH_FORW) 143155302Sschweikh cmd_putstr("/"); 1441556Srgrimes else 1451556Srgrimes cmd_putstr("?"); 1461556Srgrimes set_mlist(ml_search, 0); 1471556Srgrimes} 148201053Sjilles 1491556Srgrimes/* 1501556Srgrimes * Set up the display to start a new toggle-option command. 1511556Srgrimes */ 1521556Srgrimes static void 1531556Srgrimesmca_opt_toggle() 1541556Srgrimes{ 1551556Srgrimes int no_prompt; 1561556Srgrimes int flag; 1571556Srgrimes char *dash; 1581556Srgrimes 1591556Srgrimes no_prompt = (optflag & OPT_NO_PROMPT); 1601556Srgrimes flag = (optflag & ~OPT_NO_PROMPT); 1611556Srgrimes dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; 1621556Srgrimes 1631556Srgrimes mca = A_OPT_TOGGLE; 1641556Srgrimes clear_bot(); 1651556Srgrimes clear_cmd(); 1661556Srgrimes cmd_putstr(dash); 1671556Srgrimes if (optgetname) 16890111Simp cmd_putstr(dash); 16990111Simp if (no_prompt) 17097689Stjr cmd_putstr("(P)"); 1711556Srgrimes switch (flag) 1721556Srgrimes { 1731556Srgrimes case OPT_UNSET: 1741556Srgrimes cmd_putstr("+"); 1751556Srgrimes break; 1761556Srgrimes case OPT_SET: 1771556Srgrimes cmd_putstr("!"); 1781556Srgrimes break; 1791556Srgrimes } 180201056Sjilles set_mlist(NULL, 0); 181201056Sjilles} 18220425Ssteve 1831556Srgrimes/* 1841556Srgrimes * Execute a multicharacter command. 1851556Srgrimes */ 1861556Srgrimes static void 1871556Srgrimesexec_mca() 1881556Srgrimes{ 1891556Srgrimes register char *cbuf; 1901556Srgrimes 1911556Srgrimes cmd_exec(); 192201056Sjilles cbuf = get_cmdbuf(); 1931556Srgrimes 1941556Srgrimes switch (mca) 19597689Stjr { 19697689Stjr case A_F_SEARCH: 19797689Stjr case A_B_SEARCH: 19897689Stjr multi_search(cbuf, (int) number); 1991556Srgrimes break; 2001556Srgrimes case A_FIRSTCMD: 2011556Srgrimes /* 20220425Ssteve * Skip leading spaces or + signs in the string. 20320425Ssteve */ 20420425Ssteve while (*cbuf == '+' || *cbuf == ' ') 20520425Ssteve cbuf++; 206200956Sjilles if (every_first_cmd != NULL) 20720425Ssteve free(every_first_cmd); 20820425Ssteve if (*cbuf == '\0') 209194765Sjilles every_first_cmd = NULL; 21020425Ssteve else 211199660Sjilles every_first_cmd = save(cbuf); 21220425Ssteve break; 213199660Sjilles case A_OPT_TOGGLE: 21420425Ssteve toggle_option(optchar, cbuf, optflag); 21520425Ssteve optchar = '\0'; 21620425Ssteve break; 21720425Ssteve case A_F_BRACKET: 21820425Ssteve match_brac(cbuf[0], cbuf[1], 1, (int) number); 21920425Ssteve break; 22020425Ssteve case A_B_BRACKET: 221199660Sjilles match_brac(cbuf[1], cbuf[0], 0, (int) number); 22220425Ssteve break; 22320425Ssteve#if EXAMINE 22420425Ssteve case A_EXAMINE: 22520425Ssteve if (secure) 226155302Sschweikh break; 2271556Srgrimes edit_list(cbuf); 2281556Srgrimes#if TAGS 2291556Srgrimes /* If tag structure is loaded then clean it up. */ 2301556Srgrimes cleantags(); 231200956Sjilles#endif 23217987Speter break; 233200956Sjilles#endif 2341556Srgrimes#if SHELL_ESCAPE 2351556Srgrimes case A_SHELL: 2361556Srgrimes /* 2371556Srgrimes * !! just uses whatever is in shellcmd. 2381556Srgrimes * Otherwise, copy cmdbuf to shellcmd, 2391556Srgrimes * expanding any special characters ("%" or "#"). 2401556Srgrimes */ 24117525Sache if (*cbuf != '!') 2421556Srgrimes { 24317525Sache if (shellcmd != NULL) 2441556Srgrimes free(shellcmd); 2451556Srgrimes shellcmd = fexpand(cbuf); 2461556Srgrimes } 2471556Srgrimes 2481556Srgrimes if (secure) 2491556Srgrimes break; 2501556Srgrimes if (shellcmd == NULL) 2511556Srgrimes lsystem("", "!done"); 2521556Srgrimes else 2531556Srgrimes lsystem(shellcmd, "!done"); 2541556Srgrimes break; 2551556Srgrimes#endif 2561556Srgrimes#if PIPEC 2571556Srgrimes case A_PIPE: 2581556Srgrimes if (secure) 2591556Srgrimes break; 2601556Srgrimes (void) pipe_mark(pipec, cbuf); 261200956Sjilles error("|done", NULL_PARG); 262200956Sjilles break; 263200956Sjilles#endif 2641556Srgrimes } 265200956Sjilles} 266200956Sjilles 267200956Sjilles/* 2681556Srgrimes * Add a character to a multi-character command. 2691556Srgrimes */ 2701556Srgrimes static int 271213811Sobrienmca_char(c) 272200956Sjilles int c; 27390111Simp{ 274207678Sjilles char *p; 2751556Srgrimes int flag; 27617525Sache char buf[3]; 27717525Sache PARG parg; 27817525Sache 27917525Sache switch (mca) 28017525Sache { 28117525Sache case 0: 282207678Sjilles /* 283207678Sjilles * Not in a multicharacter command. 284207678Sjilles */ 285207678Sjilles return (NO_MCA); 28617525Sache 28717525Sache case A_PREFIX: 28817525Sache /* 2891556Srgrimes * In the prefix of a command. 290171268Sscf * This not considered a multichar command 2911556Srgrimes * (even tho it uses cmdbuf, etc.). 292171268Sscf * It is handled in the commands() switch. 293171268Sscf */ 294171268Sscf return (NO_MCA); 295213811Sobrien 296200956Sjilles case A_DIGIT: 297171268Sscf /* 298171268Sscf * Entering digits of a number. 299171268Sscf * Terminated by a non-digit. 300171268Sscf */ 301171268Sscf if (!((c >= '0' && c <= '9') || c == '.') && 302171268Sscf editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) 303171268Sscf { 304171268Sscf /* 305171268Sscf * Not part of the number. 306171268Sscf * Treat as a normal command character. 307171268Sscf */ 308171268Sscf number = cmd_int(&fraction); 309171268Sscf mca = 0; 310171268Sscf cmd_accept(); 311171268Sscf return (NO_MCA); 312171268Sscf } 313171268Sscf break; 314171268Sscf 3151556Srgrimes case A_OPT_TOGGLE: 3161556Srgrimes /* 3171556Srgrimes * Special case for the TOGGLE_OPTION command. 3181556Srgrimes * If the option letter which was entered is a 3191556Srgrimes * single-char option, execute the command immediately, 3201556Srgrimes * so user doesn't have to hit RETURN. 3211556Srgrimes * If the first char is + or -, this indicates 32290111Simp * OPT_UNSET or OPT_SET respectively, instead of OPT_TOGGLE. 32317987Speter * "--" begins inputting a long option name. 3241556Srgrimes */ 32590112Simp if (optchar == '\0' && len_cmdbuf() == 0) 3261556Srgrimes { 32745263Scracauer flag = (optflag & ~OPT_NO_PROMPT); 32845263Scracauer if (flag == OPT_NO_TOGGLE) 3291556Srgrimes { 3301556Srgrimes switch (c) 3311556Srgrimes { 3321556Srgrimes case '_': 33390112Simp /* "__" = long option name. */ 3341556Srgrimes optgetname = TRUE; 3351556Srgrimes mca_opt_toggle(); 336216870Sjilles return (MCA_MORE); 337216870Sjilles } 3381556Srgrimes } else 33920425Ssteve { 34020425Ssteve switch (c) 34120425Ssteve { 34220425Ssteve case '+': 3431556Srgrimes /* "-+" = UNSET. */ 3441556Srgrimes optflag = (flag == OPT_UNSET) ? 34520425Ssteve OPT_TOGGLE : OPT_UNSET; 34620425Ssteve mca_opt_toggle(); 3471556Srgrimes return (MCA_MORE); 3481556Srgrimes case '!': 34920425Ssteve /* "-!" = SET */ 35020425Ssteve optflag = (flag == OPT_SET) ? 35120425Ssteve OPT_TOGGLE : OPT_SET; 35220425Ssteve mca_opt_toggle(); 353203576Sjilles return (MCA_MORE); 354203576Sjilles case CONTROL('P'): 355203576Sjilles optflag ^= OPT_NO_PROMPT; 356203576Sjilles mca_opt_toggle(); 35720425Ssteve return (MCA_MORE); 358203576Sjilles case '-': 359203576Sjilles /* "--" = long option name. */ 3601556Srgrimes optgetname = TRUE; 36117525Sache mca_opt_toggle(); 362171268Sscf return (MCA_MORE); 36317525Sache } 36417525Sache } 3651556Srgrimes } 3661556Srgrimes if (optgetname) 3671556Srgrimes { 3681556Srgrimes /* 3691556Srgrimes * We're getting a long option name. 370216870Sjilles * See if we've matched an option name yet. 371216870Sjilles * If so, display the complete name and stop 3721556Srgrimes * accepting chars until user hits RETURN. 3731556Srgrimes */ 3741556Srgrimes struct loption *o; 3751556Srgrimes char *oname; 37620425Ssteve int lc; 37717525Sache 3781556Srgrimes if (c == '\n' || c == '\r') 37917525Sache { 380171268Sscf /* 38117525Sache * When the user hits RETURN, make sure 38217525Sache * we've matched an option name, then 38317525Sache * pretend he just entered the equivalent 3841556Srgrimes * option letter. 3851556Srgrimes */ 3861556Srgrimes if (optchar == '\0') 3871556Srgrimes { 3881556Srgrimes parg.p_string = get_cmdbuf(); 3891556Srgrimes error("There is no --%s option", &parg); 3901556Srgrimes return (MCA_DONE); 3911556Srgrimes } 3921556Srgrimes optgetname = FALSE; 393216870Sjilles cmd_reset(); 39490111Simp c = optchar; 3951556Srgrimes } else 3961556Srgrimes { 3971556Srgrimes if (optchar != '\0') 3981556Srgrimes { 399216870Sjilles /* 4001556Srgrimes * Already have a match for the name. 4011556Srgrimes * Don't accept anything but erase/kill. 4021556Srgrimes */ 4031556Srgrimes if (c == erase_char || 4041556Srgrimes c == erase2_char || 4051556Srgrimes c == kill_char) 4061556Srgrimes return (MCA_DONE); 4071556Srgrimes return (MCA_MORE); 4081556Srgrimes } 4091556Srgrimes /* 4101556Srgrimes * Add char to cmd buffer and try to match 411200956Sjilles * the option name. 41290111Simp */ 4131556Srgrimes if (cmd_char(c) == CC_QUIT) 4141556Srgrimes return (MCA_DONE); 4151556Srgrimes p = get_cmdbuf(); 4161556Srgrimes lc = ASCII_IS_LOWER(p[0]); 4171556Srgrimes o = findopt_name(&p, &oname, NULL); 4181556Srgrimes if (o != NULL) 4191556Srgrimes { 4201556Srgrimes /* 4211556Srgrimes * Got a match. 4221556Srgrimes * Remember the option letter and 4231556Srgrimes * display the full option name. 4241556Srgrimes */ 4251556Srgrimes optchar = o->oletter; 4261556Srgrimes if (!lc && ASCII_IS_LOWER(optchar)) 4271556Srgrimes optchar = ASCII_TO_UPPER(optchar); 4281556Srgrimes cmd_reset(); 4291556Srgrimes mca_opt_toggle(); 4301556Srgrimes for (p = oname; *p != '\0'; p++) 4311556Srgrimes { 4321556Srgrimes c = *p; 4331556Srgrimes if (!lc && ASCII_IS_LOWER(c)) 434200956Sjilles c = ASCII_TO_UPPER(c); 43517987Speter if (cmd_char(c) != CC_OK) 4361556Srgrimes return (MCA_DONE); 4371556Srgrimes } 438212467Sjilles } 4391556Srgrimes return (MCA_MORE); 440212467Sjilles } 4411556Srgrimes } else 4421556Srgrimes { 443212467Sjilles if (c == erase_char || c == erase2_char || c == kill_char) 4441556Srgrimes break; 445212467Sjilles if (optchar != '\0') 446212467Sjilles /* We already have the option letter. */ 4471556Srgrimes break; 4481556Srgrimes } 44917987Speter 45017987Speter optchar = c; 4511556Srgrimes if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || 4521556Srgrimes single_char_option(c)) 4531556Srgrimes { 4541556Srgrimes toggle_option(c, "", optflag); 4551556Srgrimes return (MCA_DONE); 4561556Srgrimes } 4571556Srgrimes /* 4581556Srgrimes * Display a prompt appropriate for the option letter. 459207678Sjilles */ 460207678Sjilles if ((p = opt_prompt(c)) == NULL) 461207678Sjilles { 462207678Sjilles buf[0] = '-'; 463207678Sjilles buf[1] = c; 464207678Sjilles buf[2] = '\0'; 465207678Sjilles p = buf; 466207678Sjilles } 467207678Sjilles start_mca(A_OPT_TOGGLE, p, (void*)NULL, 0); 468207678Sjilles return (MCA_MORE); 4691556Srgrimes 470207678Sjilles case A_F_SEARCH: 471207678Sjilles case A_B_SEARCH: 472207678Sjilles /* 473207678Sjilles * Special case for search commands. 474207678Sjilles * Certain characters as the first char of 475207678Sjilles * the pattern have special meaning: 476207678Sjilles * ! Toggle the NO_MATCH flag 477207678Sjilles * * Toggle the PAST_EOF flag 478207678Sjilles * @ Toggle the FIRST_FILE flag 479207678Sjilles */ 480207678Sjilles if (len_cmdbuf() > 0) 481207678Sjilles /* 482207678Sjilles * Only works for the first char of the pattern. 483207678Sjilles */ 484207678Sjilles break; 485207678Sjilles 486207678Sjilles flag = 0; 487207678Sjilles switch (c) 488207678Sjilles { 489207678Sjilles case '*': 490207678Sjilles if (less_is_more) 491207678Sjilles break; 492207678Sjilles case CONTROL('E'): /* ignore END of file */ 493207678Sjilles flag = SRCH_PAST_EOF; 494207678Sjilles break; 495207678Sjilles case '@': 4961556Srgrimes if (less_is_more) 497207678Sjilles break; 498207678Sjilles case CONTROL('F'): /* FIRST file */ 499207678Sjilles flag = SRCH_FIRST_FILE; 500207678Sjilles break; 501207678Sjilles case CONTROL('K'): /* KEEP position */ 502207678Sjilles flag = SRCH_NO_MOVE; 503207678Sjilles break; 504207678Sjilles case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ 505207678Sjilles flag = SRCH_NO_REGEX; 506207678Sjilles break; 507207678Sjilles case CONTROL('N'): /* NOT match */ 508207678Sjilles case '!': 509207678Sjilles flag = SRCH_NO_MATCH; 510207678Sjilles break; 511207678Sjilles } 512207678Sjilles if (flag != 0) 513207678Sjilles { 514207678Sjilles search_type ^= flag; 515207678Sjilles mca_search(); 5161556Srgrimes return (MCA_MORE); 5171556Srgrimes } 5181556Srgrimes break; 5191556Srgrimes } 5201556Srgrimes 52190111Simp /* 52290111Simp * Any other multicharacter command 5231556Srgrimes * is terminated by a newline. 5241556Srgrimes */ 5251556Srgrimes if (c == '\n' || c == '\r') 5261556Srgrimes { 5271556Srgrimes /* 5281556Srgrimes * Execute the command. 5291556Srgrimes */ 5301556Srgrimes exec_mca(); 5311556Srgrimes return (MCA_DONE); 5321556Srgrimes } 5331556Srgrimes 5341556Srgrimes /* 5351556Srgrimes * Append the char to the command buffer. 5361556Srgrimes */ 5371556Srgrimes if (cmd_char(c) == CC_QUIT) 5381556Srgrimes /* 5391556Srgrimes * Abort the multi-char command. 5401556Srgrimes */ 5411556Srgrimes return (MCA_DONE); 5421556Srgrimes 5431556Srgrimes if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) 5441556Srgrimes { 5451556Srgrimes /* 5461556Srgrimes * Special case for the bracket-matching commands. 5471556Srgrimes * Execute the command after getting exactly two 5481556Srgrimes * characters from the user. 5491556Srgrimes */ 5501556Srgrimes exec_mca(); 551149016Sstefanf return (MCA_DONE); 5521556Srgrimes } 553201053Sjilles 5541556Srgrimes /* 5551556Srgrimes * Need another character. 5561556Srgrimes */ 5571556Srgrimes return (MCA_MORE); 5581556Srgrimes} 5591556Srgrimes 56090111Simp/* 56190111Simp * Make sure the screen is displayed. 5621556Srgrimes */ 5631556Srgrimes static void 5641556Srgrimesmake_display() 5651556Srgrimes{ 5661556Srgrimes /* 5671556Srgrimes * If nothing is displayed yet, display starting from initial_scrpos. 5681556Srgrimes */ 5691556Srgrimes if (empty_screen()) 5701556Srgrimes { 5711556Srgrimes if (initial_scrpos.pos == NULL_POSITION) 5721556Srgrimes /* 5731556Srgrimes * {{ Maybe this should be: 5741556Srgrimes * jump_loc(ch_zero(), jump_sline); 5751556Srgrimes * but this behavior seems rather unexpected 5761556Srgrimes * on the first screen. }} 5771556Srgrimes */ 5781556Srgrimes jump_loc(ch_zero(), 1); 5791556Srgrimes else 5801556Srgrimes jump_loc(initial_scrpos.pos, initial_scrpos.ln); 5811556Srgrimes } else if (screen_trashed) 5821556Srgrimes { 5831556Srgrimes int save_top_scroll; 5841556Srgrimes save_top_scroll = top_scroll; 5851556Srgrimes top_scroll = 1; 586213811Sobrien repaint(); 587158145Sstefanf top_scroll = save_top_scroll; 588158145Sstefanf } 589158145Sstefanf} 5901556Srgrimes 591158145Sstefanf/* 592158145Sstefanf * Display the appropriate prompt. 593158145Sstefanf */ 594158145Sstefanf static void 595158145Sstefanfprompt() 596158145Sstefanf{ 597158145Sstefanf register char *p; 598158145Sstefanf 599158145Sstefanf if (ungotp != NULL && ungotp > ungot) 600158145Sstefanf { 601158145Sstefanf /* 6021556Srgrimes * No prompt necessary if commands are from 6031556Srgrimes * ungotten chars rather than from the user. 6041556Srgrimes */ 6051556Srgrimes return; 6061556Srgrimes } 6071556Srgrimes 6081556Srgrimes /* 60990111Simp * Make sure the screen is displayed. 61017987Speter */ 6111556Srgrimes make_display(); 6121556Srgrimes bottompos = position(BOTTOM_PLUS_ONE); 61397915Stjr 614158145Sstefanf /* 615158145Sstefanf * If we've hit EOF on the last file, and the -E flag is set 6161556Srgrimes * (or -F is set and this is the first prompt), then quit. 617158145Sstefanf * {{ Relying on "first prompt" to detect a single-screen file 618158145Sstefanf * fails if +G is used, for example. }} 619158145Sstefanf */ 620158145Sstefanf if ((get_quit_at_eof() == OPT_ONPLUS || quit_if_one_screen) && 621158145Sstefanf hit_eof && !(ch_getflags() & CH_HELPFILE) && 622158145Sstefanf next_ifile(curr_ifile) == NULL_IFILE) 623158145Sstefanf quit(QUIT_OK); 624158145Sstefanf quit_if_one_screen = FALSE; 6251556Srgrimes#if 0 /* This doesn't work well because some "te"s clear the screen. */ 6261556Srgrimes /* 627158145Sstefanf * If the -e flag is set and we've hit EOF on the last file, 628158145Sstefanf * and the file is squished (shorter than the screen), quit. 629158145Sstefanf */ 630158145Sstefanf if (get_quit_at_eof() && squished && 631158145Sstefanf next_ifile(curr_ifile) == NULL_IFILE) 632158145Sstefanf quit(QUIT_OK); 633158145Sstefanf#endif 634158145Sstefanf 635158145Sstefanf#if MSDOS_COMPILER==WIN32C 636158145Sstefanf /* 637158145Sstefanf * In Win32, display the file name in the window title. 638158145Sstefanf */ 639158145Sstefanf if (!(ch_getflags() & CH_HELPFILE)) 640215567Sjilles SetConsoleTitle(pr_expand("Less?f - %f.", 0)); 641215567Sjilles#endif 642215567Sjilles /* 643215567Sjilles * Select the proper prompt and display it. 644158145Sstefanf */ 645158145Sstefanf /* 646158145Sstefanf * If the previous action was a forward movement, 647158145Sstefanf * don't clear the bottom line of the display; 648158145Sstefanf * just print the prompt since the forward movement guarantees 6491556Srgrimes * that we're in the right position to display the prompt. 6501556Srgrimes * Clearing the line could cause a problem: for example, if the last 6511556Srgrimes * line displayed ended at the right screen edge without a newline, 6521556Srgrimes * then clearing would clear the last displayed line rather than 6531556Srgrimes * the prompt line. 6541556Srgrimes */ 6551556Srgrimes if (!forw_prompt) 6561556Srgrimes clear_bot(); 6571556Srgrimes clear_cmd(); 6581556Srgrimes forw_prompt = 0; 65990111Simp p = pr_string(); 66017987Speter if (p == NULL || *p == '\0') 6611556Srgrimes putchr(':'); 6621556Srgrimes else 6631556Srgrimes { 6641556Srgrimes at_enter(AT_STANDOUT); 66597914Stjr putstr(p); 66697914Stjr at_exit(); 6671556Srgrimes } 6681556Srgrimes clear_eol(); 66997914Stjr} 67097914Stjr 671100663Stjr/* 67297914Stjr * Display the less version message. 67397914Stjr */ 67497914Stjr public void 67597914Stjrdispversion() 67697914Stjr{ 67797914Stjr PARG parg; 67897914Stjr 67997914Stjr parg.p_string = version; 68097914Stjr error("less %s", &parg); 68197914Stjr} 68297914Stjr 68397914Stjr/* 68497914Stjr * Get command character. 68597914Stjr * The character normally comes from the keyboard, 686149919Sstefanf * but may come from ungotten characters 687149919Sstefanf * (characters previously given to ungetcc or ungetsc). 68897914Stjr */ 689149919Sstefanf public int 6901556Srgrimesgetcc() 6911556Srgrimes{ 6921556Srgrimes if (ungotp == NULL) 6931556Srgrimes /* 6941556Srgrimes * Normal case: no ungotten chars, so get one from the user. 6951556Srgrimes */ 69690111Simp return (getchr()); 6971556Srgrimes 69817525Sache if (ungotp > ungot) 699171268Sscf /* 70017525Sache * Return the next ungotten char. 70117525Sache */ 7021556Srgrimes return (*--ungotp); 7031556Srgrimes 7041556Srgrimes /* 7051556Srgrimes * We have just run out of ungotten chars. 7061556Srgrimes */ 7071556Srgrimes ungotp = NULL; 7081556Srgrimes if (len_cmdbuf() == 0 || !empty_screen()) 7091556Srgrimes return (getchr()); 7101556Srgrimes /* 7111556Srgrimes * Command is incomplete, so try to complete it. 7121556Srgrimes */ 71397914Stjr switch (mca) 71497914Stjr { 71597914Stjr case A_DIGIT: 71697914Stjr /* 717215567Sjilles * We have a number but no command. Treat as #g. 71897914Stjr */ 719215567Sjilles return ('g'); 720215567Sjilles 721215567Sjilles case A_F_SEARCH: 722215567Sjilles case A_B_SEARCH: 723215567Sjilles /* 724215567Sjilles * We have "/string" but no newline. Add the \n. 725215567Sjilles */ 7261556Srgrimes return ('\n'); 7271556Srgrimes 7281556Srgrimes default: 7291556Srgrimes /* 7301556Srgrimes * Some other incomplete command. Let user complete it. 7311556Srgrimes */ 7321556Srgrimes return (getchr()); 7331556Srgrimes } 7341556Srgrimes} 7351556Srgrimes 7361556Srgrimes/* 7371556Srgrimes * "Unget" a command character. 7381556Srgrimes * The next getcc() will return this character. 73917987Speter */ 74090111Simp public void 74117987Speterungetcc(c) 7421556Srgrimes int c; 7431556Srgrimes{ 7441556Srgrimes if (ungotp == NULL) 7451556Srgrimes ungotp = ungot; 7461556Srgrimes if (ungotp >= ungot + sizeof(ungot)) 7471556Srgrimes { 7481556Srgrimes error("ungetcc overflow", NULL_PARG); 7491556Srgrimes quit(QUIT_ERROR); 7501556Srgrimes } 7511556Srgrimes *ungotp++ = c; 7521556Srgrimes} 7531556Srgrimes 7541556Srgrimes/* 7551556Srgrimes * Unget a whole string of command characters. 7561556Srgrimes * The next sequence of getcc()'s will return this string. 7571556Srgrimes */ 7581556Srgrimes public void 7591556Srgrimesungetsc(s) 7601556Srgrimes char *s; 76190111Simp{ 76290111Simp register char *p; 7631556Srgrimes 7641556Srgrimes for (p = s + strlen(s) - 1; p >= s; p--) 7651556Srgrimes ungetcc(*p); 7661556Srgrimes} 7671556Srgrimes 7681556Srgrimes/* 7691556Srgrimes * Search for a pattern, possibly in multiple files. 7701556Srgrimes * If SRCH_FIRST_FILE is set, begin searching at the first file. 77117987Speter * If SRCH_PAST_EOF is set, continue the search thru multiple files. 7721556Srgrimes */ 7731556Srgrimes static void 7741556Srgrimesmulti_search(pattern, n) 7751556Srgrimes char *pattern; 7761556Srgrimes int n; 7771556Srgrimes{ 7781556Srgrimes register int nomore; 7791556Srgrimes IFILE save_ifile; 7801556Srgrimes int changed_file; 7811556Srgrimes 7821556Srgrimes changed_file = 0; 7831556Srgrimes save_ifile = save_curr_ifile(); 7841556Srgrimes 7851556Srgrimes if (search_type & SRCH_FIRST_FILE) 7861556Srgrimes { 7871556Srgrimes /* 7881556Srgrimes * Start at the first (or last) file 7891556Srgrimes * in the command line list. 7901556Srgrimes */ 7911556Srgrimes if (search_type & SRCH_FORW) 7921556Srgrimes nomore = edit_first(); 7931556Srgrimes else 7941556Srgrimes nomore = edit_last(); 7951556Srgrimes if (nomore) 7961556Srgrimes { 7971556Srgrimes unsave_ifile(save_ifile); 7981556Srgrimes return; 7991556Srgrimes } 8001556Srgrimes changed_file = 1; 8011556Srgrimes search_type &= ~SRCH_FIRST_FILE; 8021556Srgrimes } 8031556Srgrimes 80490111Simp for (;;) 80590111Simp { 8061556Srgrimes n = search(search_type, pattern, n); 8071556Srgrimes /* 8081556Srgrimes * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared 8091556Srgrimes * after being used once. This allows "n" to work after 8101556Srgrimes * using a /@@ search. 8111556Srgrimes */ 8121556Srgrimes search_type &= ~SRCH_NO_MOVE; 81317987Speter if (n == 0) 8141556Srgrimes { 815215266Sjilles /* 8161556Srgrimes * Found it. 8171556Srgrimes */ 8181556Srgrimes unsave_ifile(save_ifile); 8191556Srgrimes return; 8201556Srgrimes } 8211556Srgrimes 8221556Srgrimes if (n < 0) 8231556Srgrimes /* 8241556Srgrimes * Some kind of error in the search. 8251556Srgrimes * Error message has been printed by search(). 8261556Srgrimes */ 8271556Srgrimes break; 8281556Srgrimes 82917987Speter if ((search_type & SRCH_PAST_EOF) == 0) 83090111Simp /* 83117987Speter * We didn't find a match, but we're 8321556Srgrimes * supposed to search only one file. 8331556Srgrimes */ 8341556Srgrimes break; 8351556Srgrimes /* 8361556Srgrimes * Move on to the next file. 837214538Sjilles */ 8381556Srgrimes if (search_type & SRCH_FORW) 8391556Srgrimes nomore = edit_next(1); 8401556Srgrimes else 8411556Srgrimes nomore = edit_prev(1); 8421556Srgrimes if (nomore) 8431556Srgrimes break; 8441556Srgrimes changed_file = 1; 8451556Srgrimes } 8461556Srgrimes 8471556Srgrimes /* 84817987Speter * Didn't find it. 84990111Simp * Print an error message if we haven't already. 85017987Speter */ 8511556Srgrimes if (n > 0) 8521556Srgrimes error("Pattern not found", NULL_PARG); 8531556Srgrimes 8541556Srgrimes if (changed_file) 8551556Srgrimes { 8561556Srgrimes /* 8571556Srgrimes * Restore the file we were originally viewing. 8581556Srgrimes */ 8591556Srgrimes reedit_ifile(save_ifile); 8601556Srgrimes } else 8611556Srgrimes { 8621556Srgrimes unsave_ifile(save_ifile); 8631556Srgrimes } 8641556Srgrimes} 8658855Srgrimes 8661556Srgrimes/* 8671556Srgrimes * Main command processor. 8681556Srgrimes * Accept and execute commands until a quit command. 8691556Srgrimes */ 8701556Srgrimes public void 8711556Srgrimescommands() 8721556Srgrimes{ 8731556Srgrimes register int c; 8741556Srgrimes register int action; 8751556Srgrimes register char *cbuf; 8761556Srgrimes int newaction; 8771556Srgrimes int save_search_type; 8781556Srgrimes char *extra; 8791556Srgrimes char tbuf[2]; 88020425Ssteve PARG parg; 881200956Sjilles IFILE old_ifile; 88290111Simp IFILE new_ifile; 8831556Srgrimes char *tagfile; 8841556Srgrimes 8851556Srgrimes search_type = SRCH_FORW; 8861556Srgrimes wscroll = (sc_height + 1) / 2; 8871556Srgrimes newaction = A_NOACTION; 8881556Srgrimes 8891556Srgrimes for (;;) 8901556Srgrimes { 8911556Srgrimes mca = 0; 8921556Srgrimes cmd_accept(); 8931556Srgrimes number = 0; 89417525Sache optchar = '\0'; 895171268Sscf 89617525Sache /* 89717525Sache * See if any signals need processing. 89820425Ssteve */ 8991556Srgrimes if (sigs) 9001556Srgrimes { 9011556Srgrimes psignals(); 9021556Srgrimes if (quitting) 9031556Srgrimes quit(QUIT_SAVED_STATUS); 9041556Srgrimes } 9051556Srgrimes 9061556Srgrimes /* 9071556Srgrimes * See if window size changed, for systems that don't 9081556Srgrimes * generate SIGWINCH. 9091556Srgrimes */ 9101556Srgrimes check_winch(); 911135856Sdes 9121556Srgrimes /* 9131556Srgrimes * Display prompt and accept a character. 9141556Srgrimes */ 9151556Srgrimes cmd_reset(); 9161556Srgrimes prompt(); 9171556Srgrimes if (sigs) 9181556Srgrimes continue; 9191556Srgrimes if (newaction == A_NOACTION) 920213811Sobrien c = getcc(); 921200956Sjilles 92290111Simp again: 9231556Srgrimes if (sigs) 9241556Srgrimes continue; 92520425Ssteve 9261556Srgrimes if (newaction != A_NOACTION) 92720425Ssteve { 9281556Srgrimes action = newaction; 9291556Srgrimes newaction = A_NOACTION; 9301556Srgrimes } else 9311556Srgrimes { 9321556Srgrimes /* 9331556Srgrimes * If we are in a multicharacter command, call mca_char. 9341556Srgrimes * Otherwise we call fcmd_decode to determine the 9351556Srgrimes * action to be performed. 9361556Srgrimes */ 9371556Srgrimes if (mca) 9381556Srgrimes switch (mca_char(c)) 939213811Sobrien { 940200956Sjilles case MCA_MORE: 94190111Simp /* 9421556Srgrimes * Need another character. 9431556Srgrimes */ 9441556Srgrimes c = getcc(); 9451556Srgrimes goto again; 9461556Srgrimes case MCA_DONE: 9471556Srgrimes /* 9481556Srgrimes * Command has been handled by mca_char. 9491556Srgrimes * Start clean with a prompt. 950 */ 951 continue; 952 case NO_MCA: 953 /* 954 * Not a multi-char command 955 * (at least, not anymore). 956 */ 957 break; 958 } 959 960 /* 961 * Decode the command character and decide what to do. 962 */ 963 if (mca) 964 { 965 /* 966 * We're in a multichar command. 967 * Add the character to the command buffer 968 * and display it on the screen. 969 * If the user backspaces past the start 970 * of the line, abort the command. 971 */ 972 if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) 973 continue; 974 cbuf = get_cmdbuf(); 975 } else 976 { 977 /* 978 * Don't use cmd_char if we're starting fresh 979 * at the beginning of a command, because we 980 * don't want to echo the command until we know 981 * it is a multichar command. We also don't 982 * want erase_char/kill_char to be treated 983 * as line editing characters. 984 */ 985 tbuf[0] = c; 986 tbuf[1] = '\0'; 987 cbuf = tbuf; 988 } 989 extra = NULL; 990 action = fcmd_decode(cbuf, &extra); 991 /* 992 * If an "extra" string was returned, 993 * process it as a string of command characters. 994 */ 995 if (extra != NULL) 996 ungetsc(extra); 997 } 998 /* 999 * Clear the cmdbuf string. 1000 * (But not if we're in the prefix of a command, 1001 * because the partial command string is kept there.) 1002 */ 1003 if (action != A_PREFIX) 1004 cmd_reset(); 1005 1006 switch (action) 1007 { 1008 case A_DIGIT: 1009 /* 1010 * First digit of a number. 1011 */ 1012 start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); 1013 goto again; 1014 1015 case A_F_WINDOW: 1016 /* 1017 * Forward one window (and set the window size). 1018 */ 1019 if (number > 0) 1020 swindow = (int) number; 1021 /* FALLTHRU */ 1022 case A_F_SCREEN: 1023 /* 1024 * Forward one screen. 1025 */ 1026 if (number <= 0) 1027 number = get_swindow(); 1028 cmd_exec(); 1029 if (show_attn) 1030 set_attnpos(bottompos); 1031 forward((int) number, 0, 1); 1032 break; 1033 1034 case A_B_WINDOW: 1035 /* 1036 * Backward one window (and set the window size). 1037 */ 1038 if (number > 0) 1039 swindow = (int) number; 1040 /* FALLTHRU */ 1041 case A_B_SCREEN: 1042 /* 1043 * Backward one screen. 1044 */ 1045 if (number <= 0) 1046 number = get_swindow(); 1047 cmd_exec(); 1048 backward((int) number, 0, 1); 1049 break; 1050 1051 case A_F_LINE: 1052 /* 1053 * Forward N (default 1) line. 1054 */ 1055 if (number <= 0) 1056 number = 1; 1057 cmd_exec(); 1058 if (show_attn == OPT_ONPLUS && number > 1) 1059 set_attnpos(bottompos); 1060 forward((int) number, 0, 0); 1061 break; 1062 1063 case A_B_LINE: 1064 /* 1065 * Backward N (default 1) line. 1066 */ 1067 if (number <= 0) 1068 number = 1; 1069 cmd_exec(); 1070 backward((int) number, 0, 0); 1071 break; 1072 1073 case A_FF_LINE: 1074 /* 1075 * Force forward N (default 1) line. 1076 */ 1077 if (number <= 0) 1078 number = 1; 1079 cmd_exec(); 1080 if (show_attn == OPT_ONPLUS && number > 1) 1081 set_attnpos(bottompos); 1082 forward((int) number, 1, 0); 1083 break; 1084 1085 case A_BF_LINE: 1086 /* 1087 * Force backward N (default 1) line. 1088 */ 1089 if (number <= 0) 1090 number = 1; 1091 cmd_exec(); 1092 backward((int) number, 1, 0); 1093 break; 1094 1095 case A_FF_SCREEN: 1096 /* 1097 * Force forward one screen. 1098 */ 1099 if (number <= 0) 1100 number = get_swindow(); 1101 cmd_exec(); 1102 if (show_attn == OPT_ONPLUS) 1103 set_attnpos(bottompos); 1104 forward((int) number, 1, 0); 1105 break; 1106 1107 case A_F_FOREVER: 1108 /* 1109 * Forward forever, ignoring EOF. 1110 */ 1111 if (ch_getflags() & CH_HELPFILE) 1112 break; 1113 cmd_exec(); 1114 jump_forw(); 1115 ignore_eoi = 1; 1116 hit_eof = 0; 1117 while (!sigs) 1118 forward(1, 0, 0); 1119 ignore_eoi = 0; 1120 /* 1121 * This gets us back in "F mode" after processing 1122 * a non-abort signal (e.g. window-change). 1123 */ 1124 if (sigs && !ABORT_SIGS()) 1125 newaction = A_F_FOREVER; 1126 break; 1127 1128 case A_F_SCROLL: 1129 /* 1130 * Forward N lines 1131 * (default same as last 'd' or 'u' command). 1132 */ 1133 if (number > 0) 1134 wscroll = (int) number; 1135 cmd_exec(); 1136 if (show_attn == OPT_ONPLUS) 1137 set_attnpos(bottompos); 1138 forward(wscroll, 0, 0); 1139 break; 1140 1141 case A_B_SCROLL: 1142 /* 1143 * Forward N lines 1144 * (default same as last 'd' or 'u' command). 1145 */ 1146 if (number > 0) 1147 wscroll = (int) number; 1148 cmd_exec(); 1149 backward(wscroll, 0, 0); 1150 break; 1151 1152 case A_FREPAINT: 1153 /* 1154 * Flush buffers, then repaint screen. 1155 * Don't flush the buffers on a pipe! 1156 */ 1157 if (ch_getflags() & CH_CANSEEK) 1158 { 1159 ch_flush(); 1160 clr_linenum(); 1161#if HILITE_SEARCH 1162 clr_hilite(); 1163#endif 1164 } 1165 /* FALLTHRU */ 1166 case A_REPAINT: 1167 /* 1168 * Repaint screen. 1169 */ 1170 cmd_exec(); 1171 repaint(); 1172 break; 1173 1174 case A_GOLINE: 1175 /* 1176 * Go to line N, default beginning of file. 1177 */ 1178 if (number <= 0) 1179 number = 1; 1180 cmd_exec(); 1181 jump_back(number); 1182 break; 1183 1184 case A_PERCENT: 1185 /* 1186 * Go to a specified percentage into the file. 1187 */ 1188 if (number < 0) 1189 { 1190 number = 0; 1191 fraction = 0; 1192 } 1193 if (number > 100) 1194 { 1195 number = 100; 1196 fraction = 0; 1197 } 1198 cmd_exec(); 1199 jump_percent((int) number, fraction); 1200 break; 1201 1202 case A_GOEND: 1203 /* 1204 * Go to line N, default end of file. 1205 */ 1206 cmd_exec(); 1207 if (number <= 0) 1208 jump_forw(); 1209 else 1210 jump_back(number); 1211 break; 1212 1213 case A_GOPOS: 1214 /* 1215 * Go to a specified byte position in the file. 1216 */ 1217 cmd_exec(); 1218 if (number < 0) 1219 number = 0; 1220 jump_line_loc((POSITION) number, jump_sline); 1221 break; 1222 1223 case A_STAT: 1224 /* 1225 * Print file name, etc. 1226 */ 1227 if (ch_getflags() & CH_HELPFILE) 1228 break; 1229 cmd_exec(); 1230 parg.p_string = eq_message(); 1231 error("%s", &parg); 1232 break; 1233 1234 case A_VERSION: 1235 /* 1236 * Print version number, without the "@(#)". 1237 */ 1238 cmd_exec(); 1239 dispversion(); 1240 break; 1241 1242 case A_QUIT: 1243 /* 1244 * Exit. 1245 */ 1246 if (curr_ifile != NULL_IFILE && 1247 ch_getflags() & CH_HELPFILE) 1248 { 1249 /* 1250 * Quit while viewing the help file 1251 * just means return to viewing the 1252 * previous file. 1253 */ 1254 hshift = save_hshift; 1255 if (edit_prev(1) == 0) 1256 break; 1257 } 1258 if (extra != NULL) 1259 quit(*extra); 1260 quit(QUIT_OK); 1261 break; 1262 1263/* 1264 * Define abbreviation for a commonly used sequence below. 1265 */ 1266#define DO_SEARCH() if (number <= 0) number = 1; \ 1267 mca_search(); \ 1268 cmd_exec(); \ 1269 multi_search((char *)NULL, (int) number); 1270 1271 1272 case A_F_SEARCH: 1273 /* 1274 * Search forward for a pattern. 1275 * Get the first char of the pattern. 1276 */ 1277 search_type = SRCH_FORW; 1278 if (number <= 0) 1279 number = 1; 1280 mca_search(); 1281 c = getcc(); 1282 goto again; 1283 1284 case A_B_SEARCH: 1285 /* 1286 * Search backward for a pattern. 1287 * Get the first char of the pattern. 1288 */ 1289 search_type = SRCH_BACK; 1290 if (number <= 0) 1291 number = 1; 1292 mca_search(); 1293 c = getcc(); 1294 goto again; 1295 1296 case A_AGAIN_SEARCH: 1297 /* 1298 * Repeat previous search. 1299 */ 1300 DO_SEARCH(); 1301 break; 1302 1303 case A_T_AGAIN_SEARCH: 1304 /* 1305 * Repeat previous search, multiple files. 1306 */ 1307 search_type |= SRCH_PAST_EOF; 1308 DO_SEARCH(); 1309 break; 1310 1311 case A_REVERSE_SEARCH: 1312 /* 1313 * Repeat previous search, in reverse direction. 1314 */ 1315 save_search_type = search_type; 1316 search_type = SRCH_REVERSE(search_type); 1317 DO_SEARCH(); 1318 search_type = save_search_type; 1319 break; 1320 1321 case A_T_REVERSE_SEARCH: 1322 /* 1323 * Repeat previous search, 1324 * multiple files in reverse direction. 1325 */ 1326 save_search_type = search_type; 1327 search_type = SRCH_REVERSE(search_type); 1328 search_type |= SRCH_PAST_EOF; 1329 DO_SEARCH(); 1330 search_type = save_search_type; 1331 break; 1332 1333 case A_UNDO_SEARCH: 1334 undo_search(); 1335 break; 1336 1337 case A_HELP: 1338 /* 1339 * Help. 1340 */ 1341 if (ch_getflags() & CH_HELPFILE) 1342 break; 1343 cmd_exec(); 1344 save_hshift = hshift; 1345 hshift = 0; 1346 (void) edit(FAKE_HELPFILE); 1347 break; 1348 1349 case A_EXAMINE: 1350#if EXAMINE 1351 /* 1352 * Edit a new file. Get the filename. 1353 */ 1354 if (secure) 1355 { 1356 error("Command not available", NULL_PARG); 1357 break; 1358 } 1359 start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); 1360 c = getcc(); 1361 goto again; 1362#else 1363 error("Command not available", NULL_PARG); 1364 break; 1365#endif 1366 1367 case A_VISUAL: 1368 /* 1369 * Invoke an editor on the input file. 1370 */ 1371#if EDITOR 1372 if (secure) 1373 { 1374 error("Command not available", NULL_PARG); 1375 break; 1376 } 1377 if (ch_getflags() & CH_HELPFILE) 1378 break; 1379 if (strcmp(get_filename(curr_ifile), "-") == 0) 1380 { 1381 error("Cannot edit standard input", NULL_PARG); 1382 break; 1383 } 1384 if (curr_altfilename != NULL) 1385 { 1386 error("WARNING: This file was viewed via LESSOPEN", 1387 NULL_PARG); 1388 } 1389 start_mca(A_SHELL, "!", ml_shell, 0); 1390 /* 1391 * Expand the editor prototype string 1392 * and pass it to the system to execute. 1393 * (Make sure the screen is displayed so the 1394 * expansion of "+%lm" works.) 1395 */ 1396 make_display(); 1397 cmd_exec(); 1398 lsystem(pr_expand(editproto, 0), (char*)NULL); 1399 break; 1400#else 1401 error("Command not available", NULL_PARG); 1402 break; 1403#endif 1404 1405 case A_NEXT_FILE: 1406 /* 1407 * Examine next file. 1408 */ 1409#if TAGS 1410 if (ntags()) 1411 { 1412 error("No next file", NULL_PARG); 1413 break; 1414 } 1415#endif 1416 if (number <= 0) 1417 number = 1; 1418 if (edit_next((int) number)) 1419 { 1420 if (get_quit_at_eof() && hit_eof && 1421 !(ch_getflags() & CH_HELPFILE)) 1422 quit(QUIT_OK); 1423 parg.p_string = (number > 1) ? "(N-th) " : ""; 1424 error("No %snext file", &parg); 1425 } 1426 break; 1427 1428 case A_PREV_FILE: 1429 /* 1430 * Examine previous file. 1431 */ 1432#if TAGS 1433 if (ntags()) 1434 { 1435 error("No previous file", NULL_PARG); 1436 break; 1437 } 1438#endif 1439 if (number <= 0) 1440 number = 1; 1441 if (edit_prev((int) number)) 1442 { 1443 parg.p_string = (number > 1) ? "(N-th) " : ""; 1444 error("No %sprevious file", &parg); 1445 } 1446 break; 1447 1448 case A_NEXT_TAG: 1449#if TAGS 1450 if (number <= 0) 1451 number = 1; 1452 tagfile = nexttag((int) number); 1453 if (tagfile == NULL) 1454 { 1455 error("No next tag", NULL_PARG); 1456 break; 1457 } 1458 if (edit(tagfile) == 0) 1459 { 1460 POSITION pos = tagsearch(); 1461 if (pos != NULL_POSITION) 1462 jump_loc(pos, jump_sline); 1463 } 1464#else 1465 error("Command not available", NULL_PARG); 1466#endif 1467 break; 1468 1469 case A_PREV_TAG: 1470#if TAGS 1471 if (number <= 0) 1472 number = 1; 1473 tagfile = prevtag((int) number); 1474 if (tagfile == NULL) 1475 { 1476 error("No previous tag", NULL_PARG); 1477 break; 1478 } 1479 if (edit(tagfile) == 0) 1480 { 1481 POSITION pos = tagsearch(); 1482 if (pos != NULL_POSITION) 1483 jump_loc(pos, jump_sline); 1484 } 1485#else 1486 error("Command not available", NULL_PARG); 1487#endif 1488 break; 1489 1490 case A_INDEX_FILE: 1491 /* 1492 * Examine a particular file. 1493 */ 1494 if (number <= 0) 1495 number = 1; 1496 if (edit_index((int) number)) 1497 error("No such file", NULL_PARG); 1498 break; 1499 1500 case A_REMOVE_FILE: 1501 if (ch_getflags() & CH_HELPFILE) 1502 break; 1503 old_ifile = curr_ifile; 1504 new_ifile = getoff_ifile(curr_ifile); 1505 if (new_ifile == NULL_IFILE) 1506 { 1507 bell(); 1508 break; 1509 } 1510 if (edit_ifile(new_ifile) != 0) 1511 { 1512 reedit_ifile(old_ifile); 1513 break; 1514 } 1515 del_ifile(old_ifile); 1516 break; 1517 1518 case A_OPT_TOGGLE: 1519 optflag = OPT_TOGGLE; 1520 optgetname = FALSE; 1521 mca_opt_toggle(); 1522 c = getcc(); 1523 goto again; 1524 1525 case A_DISP_OPTION: 1526 /* 1527 * Report a flag setting. 1528 */ 1529 optflag = OPT_NO_TOGGLE; 1530 optgetname = FALSE; 1531 mca_opt_toggle(); 1532 c = getcc(); 1533 goto again; 1534 1535 case A_FIRSTCMD: 1536 /* 1537 * Set an initial command for new files. 1538 */ 1539 start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); 1540 c = getcc(); 1541 goto again; 1542 1543 case A_SHELL: 1544 /* 1545 * Shell escape. 1546 */ 1547#if SHELL_ESCAPE 1548 if (secure) 1549 { 1550 error("Command not available", NULL_PARG); 1551 break; 1552 } 1553 start_mca(A_SHELL, "!", ml_shell, 0); 1554 c = getcc(); 1555 goto again; 1556#else 1557 error("Command not available", NULL_PARG); 1558 break; 1559#endif 1560 1561 case A_SETMARK: 1562 /* 1563 * Set a mark. 1564 */ 1565 if (ch_getflags() & CH_HELPFILE) 1566 break; 1567 start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); 1568 c = getcc(); 1569 if (c == erase_char || c == erase2_char || 1570 c == kill_char || c == '\n' || c == '\r') 1571 break; 1572 setmark(c); 1573 break; 1574 1575 case A_GOMARK: 1576 /* 1577 * Go to a mark. 1578 */ 1579 start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); 1580 c = getcc(); 1581 if (c == erase_char || c == erase2_char || 1582 c == kill_char || c == '\n' || c == '\r') 1583 break; 1584 gomark(c); 1585 break; 1586 1587 case A_PIPE: 1588#if PIPEC 1589 if (secure) 1590 { 1591 error("Command not available", NULL_PARG); 1592 break; 1593 } 1594 start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); 1595 c = getcc(); 1596 if (c == erase_char || c == erase2_char || c == kill_char) 1597 break; 1598 if (c == '\n' || c == '\r') 1599 c = '.'; 1600 if (badmark(c)) 1601 break; 1602 pipec = c; 1603 start_mca(A_PIPE, "!", ml_shell, 0); 1604 c = getcc(); 1605 goto again; 1606#else 1607 error("Command not available", NULL_PARG); 1608 break; 1609#endif 1610 1611 case A_B_BRACKET: 1612 case A_F_BRACKET: 1613 start_mca(action, "Brackets: ", (void*)NULL, 0); 1614 c = getcc(); 1615 goto again; 1616 1617 case A_LSHIFT: 1618 if (number > 0) 1619 shift_count = number; 1620 else 1621 number = (shift_count > 0) ? 1622 shift_count : sc_width / 2; 1623 if (number > hshift) 1624 number = hshift; 1625 hshift -= number; 1626 screen_trashed = 1; 1627 break; 1628 1629 case A_RSHIFT: 1630 if (number > 0) 1631 shift_count = number; 1632 else 1633 number = (shift_count > 0) ? 1634 shift_count : sc_width / 2; 1635 hshift += number; 1636 screen_trashed = 1; 1637 break; 1638 1639 case A_PREFIX: 1640 /* 1641 * The command is incomplete (more chars are needed). 1642 * Display the current char, so the user knows 1643 * what's going on, and get another character. 1644 */ 1645 if (mca != A_PREFIX) 1646 { 1647 cmd_reset(); 1648 start_mca(A_PREFIX, " ", (void*)NULL, 1649 CF_QUIT_ON_ERASE); 1650 (void) cmd_char(c); 1651 } 1652 c = getcc(); 1653 goto again; 1654 1655 case A_NOACTION: 1656 break; 1657 1658 default: 1659 bell(); 1660 break; 1661 } 1662 } 1663} 1664