160812Sps/* $FreeBSD$ */ 260786Sps/* 3240121Sdelphij * Copyright (C) 1984-2012 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 * 8240121Sdelphij * For more information, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * User-level command processor. 1460786Sps */ 1560786Sps 1660786Sps#include "less.h" 1789022Sps#if MSDOS_COMPILER==WIN32C 1889022Sps#include <windows.h> 1989022Sps#endif 2060786Sps#include "position.h" 2160786Sps#include "option.h" 2260786Sps#include "cmd.h" 2360786Sps 24161478Sdelphijextern int erase_char, erase2_char, kill_char; 2560786Spsextern int sigs; 2660786Spsextern int quit_if_one_screen; 2760786Spsextern int squished; 2860786Spsextern int sc_width; 2960786Spsextern int sc_height; 3060786Spsextern int swindow; 3160786Spsextern int jump_sline; 3260786Spsextern int quitting; 3360786Spsextern int wscroll; 3460786Spsextern int top_scroll; 3560786Spsextern int ignore_eoi; 3660786Spsextern int secure; 3760786Spsextern int hshift; 3860786Spsextern int show_attn; 39170259Sdelphijextern int less_is_more; 40240121Sdelphijextern POSITION highest_hilite; 4160786Spsextern char *every_first_cmd; 4260786Spsextern char *curr_altfilename; 4360786Spsextern char version[]; 4460786Spsextern struct scrpos initial_scrpos; 4560786Spsextern IFILE curr_ifile; 4660786Spsextern void constant *ml_search; 4760786Spsextern void constant *ml_examine; 4860786Sps#if SHELL_ESCAPE || PIPEC 4960786Spsextern void constant *ml_shell; 5060786Sps#endif 5160786Sps#if EDITOR 5260786Spsextern char *editor; 5360786Spsextern char *editproto; 5460786Sps#endif 5560786Spsextern int screen_trashed; /* The screen has been overwritten */ 5663131Spsextern int shift_count; 57170259Sdelphijextern int oldbot; 58170259Sdelphijextern int forw_prompt; 5960786Sps 6060786Sps#if SHELL_ESCAPE 6160786Spsstatic char *shellcmd = NULL; /* For holding last shell command for "!!" */ 6260786Sps#endif 6360786Spsstatic int mca; /* The multicharacter command (action) */ 6460786Spsstatic int search_type; /* The previous type of search */ 65128348Stjrstatic LINENUM number; /* The number typed by the user */ 66170259Sdelphijstatic long fraction; /* The fractional part of the number */ 67221715Sdelphijstatic struct loption *curropt; 68221715Sdelphijstatic int opt_lower; 6960786Spsstatic int optflag; 7060786Spsstatic int optgetname; 7160786Spsstatic POSITION bottompos; 72161478Sdelphijstatic int save_hshift; 7360786Sps#if PIPEC 7460786Spsstatic char pipec; 7560786Sps#endif 7660786Sps 77221715Sdelphijstruct ungot { 78221715Sdelphij struct ungot *ug_next; 79221715Sdelphij char ug_char; 80221715Sdelphij}; 81221715Sdelphijstatic struct ungot* ungot = NULL; 82221715Sdelphijstatic int unget_end = 0; 83221715Sdelphij 8460786Spsstatic void multi_search(); 8560786Sps 8660786Sps/* 87170259Sdelphij * Move the cursor to start of prompt line before executing a command. 8860786Sps * This looks nicer if the command takes a long time before 8960786Sps * updating the screen. 9060786Sps */ 9160786Sps static void 9260786Spscmd_exec() 9360786Sps{ 94191930Sdelphij#if HILITE_SEARCH 9560786Sps clear_attn(); 96191930Sdelphij#endif 97170967Sdelphij clear_bot(); 9860786Sps flush(); 9960786Sps} 10060786Sps 10160786Sps/* 10260786Sps * Set up the display to start a new multi-character command. 10360786Sps */ 10460786Sps static void 10560786Spsstart_mca(action, prompt, mlist, cmdflags) 10660786Sps int action; 107240121Sdelphij constant char *prompt; 108240121Sdelphij constant void *mlist; 10960786Sps int cmdflags; 11060786Sps{ 11160786Sps mca = action; 112170259Sdelphij clear_bot(); 11360786Sps clear_cmd(); 11460786Sps cmd_putstr(prompt); 11560786Sps set_mlist(mlist, cmdflags); 11660786Sps} 11760786Sps 11860786Sps public int 11960786Spsin_mca() 12060786Sps{ 12160786Sps return (mca != 0 && mca != A_PREFIX); 12260786Sps} 12360786Sps 12460786Sps/* 12560786Sps * Set up the display to start a new search command. 12660786Sps */ 12760786Sps static void 12860786Spsmca_search() 12960786Sps{ 130191930Sdelphij#if HILITE_SEARCH 131191930Sdelphij if (search_type & SRCH_FILTER) 132191930Sdelphij mca = A_FILTER; 133191930Sdelphij else 134191930Sdelphij#endif 13560786Sps if (search_type & SRCH_FORW) 13660786Sps mca = A_F_SEARCH; 13760786Sps else 13860786Sps mca = A_B_SEARCH; 13960786Sps 140170259Sdelphij clear_bot(); 14160786Sps clear_cmd(); 14260786Sps 14360786Sps if (search_type & SRCH_NO_MATCH) 14460786Sps cmd_putstr("Non-match "); 14560786Sps if (search_type & SRCH_FIRST_FILE) 14660786Sps cmd_putstr("First-file "); 14760786Sps if (search_type & SRCH_PAST_EOF) 14860786Sps cmd_putstr("EOF-ignore "); 14960786Sps if (search_type & SRCH_NO_MOVE) 15060786Sps cmd_putstr("Keep-pos "); 15160786Sps if (search_type & SRCH_NO_REGEX) 15260786Sps cmd_putstr("Regex-off "); 15360786Sps 154191930Sdelphij#if HILITE_SEARCH 155191930Sdelphij if (search_type & SRCH_FILTER) 156191930Sdelphij cmd_putstr("&/"); 157191930Sdelphij else 158191930Sdelphij#endif 15960786Sps if (search_type & SRCH_FORW) 16060786Sps cmd_putstr("/"); 16160786Sps else 16260786Sps cmd_putstr("?"); 16360786Sps set_mlist(ml_search, 0); 16460786Sps} 16560786Sps 16660786Sps/* 16760786Sps * Set up the display to start a new toggle-option command. 16860786Sps */ 16960786Sps static void 17060786Spsmca_opt_toggle() 17160786Sps{ 17260786Sps int no_prompt; 17360786Sps int flag; 17460786Sps char *dash; 17560786Sps 17660786Sps no_prompt = (optflag & OPT_NO_PROMPT); 17760786Sps flag = (optflag & ~OPT_NO_PROMPT); 17860786Sps dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; 17960786Sps 18060786Sps mca = A_OPT_TOGGLE; 181170259Sdelphij clear_bot(); 18260786Sps clear_cmd(); 18360786Sps cmd_putstr(dash); 18460786Sps if (optgetname) 18560786Sps cmd_putstr(dash); 18660786Sps if (no_prompt) 18760786Sps cmd_putstr("(P)"); 18860786Sps switch (flag) 18960786Sps { 19060786Sps case OPT_UNSET: 19160786Sps cmd_putstr("+"); 19260786Sps break; 19360786Sps case OPT_SET: 19460786Sps cmd_putstr("!"); 19560786Sps break; 19660786Sps } 19760786Sps set_mlist(NULL, 0); 19860786Sps} 19960786Sps 20060786Sps/* 20160786Sps * Execute a multicharacter command. 20260786Sps */ 20360786Sps static void 20460786Spsexec_mca() 20560786Sps{ 20660786Sps register char *cbuf; 20760786Sps 20860786Sps cmd_exec(); 20960786Sps cbuf = get_cmdbuf(); 21060786Sps 21160786Sps switch (mca) 21260786Sps { 21360786Sps case A_F_SEARCH: 21460786Sps case A_B_SEARCH: 215128348Stjr multi_search(cbuf, (int) number); 21660786Sps break; 217191930Sdelphij#if HILITE_SEARCH 218191930Sdelphij case A_FILTER: 219191930Sdelphij search_type ^= SRCH_NO_MATCH; 220191930Sdelphij set_filter_pattern(cbuf, search_type); 221191930Sdelphij break; 222191930Sdelphij#endif 22360786Sps case A_FIRSTCMD: 22460786Sps /* 22560786Sps * Skip leading spaces or + signs in the string. 22660786Sps */ 22760786Sps while (*cbuf == '+' || *cbuf == ' ') 22860786Sps cbuf++; 22960786Sps if (every_first_cmd != NULL) 23060786Sps free(every_first_cmd); 23160786Sps if (*cbuf == '\0') 23260786Sps every_first_cmd = NULL; 23360786Sps else 23460786Sps every_first_cmd = save(cbuf); 23560786Sps break; 23660786Sps case A_OPT_TOGGLE: 237221715Sdelphij toggle_option(curropt, opt_lower, cbuf, optflag); 238221715Sdelphij curropt = NULL; 23960786Sps break; 24060786Sps case A_F_BRACKET: 241128348Stjr match_brac(cbuf[0], cbuf[1], 1, (int) number); 24260786Sps break; 24360786Sps case A_B_BRACKET: 244128348Stjr match_brac(cbuf[1], cbuf[0], 0, (int) number); 24560786Sps break; 24660786Sps#if EXAMINE 24760786Sps case A_EXAMINE: 24860786Sps if (secure) 24960786Sps break; 25060786Sps edit_list(cbuf); 251128348Stjr#if TAGS 25289022Sps /* If tag structure is loaded then clean it up. */ 25389022Sps cleantags(); 254128348Stjr#endif 25560786Sps break; 25660786Sps#endif 25760786Sps#if SHELL_ESCAPE 25860786Sps case A_SHELL: 25960786Sps /* 26060786Sps * !! just uses whatever is in shellcmd. 26160786Sps * Otherwise, copy cmdbuf to shellcmd, 26260786Sps * expanding any special characters ("%" or "#"). 26360786Sps */ 26460786Sps if (*cbuf != '!') 26560786Sps { 26660786Sps if (shellcmd != NULL) 26760786Sps free(shellcmd); 26860786Sps shellcmd = fexpand(cbuf); 26960786Sps } 27060786Sps 27160786Sps if (secure) 27260786Sps break; 27360786Sps if (shellcmd == NULL) 27460786Sps lsystem("", "!done"); 27560786Sps else 27660786Sps lsystem(shellcmd, "!done"); 27760786Sps break; 27860786Sps#endif 27960786Sps#if PIPEC 28060786Sps case A_PIPE: 28160786Sps if (secure) 28260786Sps break; 28360786Sps (void) pipe_mark(pipec, cbuf); 28460786Sps error("|done", NULL_PARG); 28560786Sps break; 28660786Sps#endif 28760786Sps } 28860786Sps} 28960786Sps 29060786Sps/* 291221715Sdelphij * Is a character an erase or kill char? 29260786Sps */ 29360786Sps static int 294221715Sdelphijis_erase_char(c) 29560786Sps int c; 29660786Sps{ 297221715Sdelphij return (c == erase_char || c == erase2_char || c == kill_char); 298221715Sdelphij} 299221715Sdelphij 300221715Sdelphij/* 301221715Sdelphij * Handle the first char of an option (after the initial dash). 302221715Sdelphij */ 303221715Sdelphij static int 304221715Sdelphijmca_opt_first_char(c) 305222906Sdelphij int c; 306221715Sdelphij{ 307221715Sdelphij int flag = (optflag & ~OPT_NO_PROMPT); 308221715Sdelphij if (flag == OPT_NO_TOGGLE) 309221715Sdelphij { 310221715Sdelphij switch (c) 311221715Sdelphij { 312221715Sdelphij case '_': 313221715Sdelphij /* "__" = long option name. */ 314221715Sdelphij optgetname = TRUE; 315221715Sdelphij mca_opt_toggle(); 316221715Sdelphij return (MCA_MORE); 317221715Sdelphij } 318221715Sdelphij } else 319221715Sdelphij { 320221715Sdelphij switch (c) 321221715Sdelphij { 322221715Sdelphij case '+': 323221715Sdelphij /* "-+" = UNSET. */ 324221715Sdelphij optflag = (flag == OPT_UNSET) ? 325221715Sdelphij OPT_TOGGLE : OPT_UNSET; 326221715Sdelphij mca_opt_toggle(); 327221715Sdelphij return (MCA_MORE); 328221715Sdelphij case '!': 329221715Sdelphij /* "-!" = SET */ 330221715Sdelphij optflag = (flag == OPT_SET) ? 331221715Sdelphij OPT_TOGGLE : OPT_SET; 332221715Sdelphij mca_opt_toggle(); 333221715Sdelphij return (MCA_MORE); 334221715Sdelphij case CONTROL('P'): 335221715Sdelphij optflag ^= OPT_NO_PROMPT; 336221715Sdelphij mca_opt_toggle(); 337221715Sdelphij return (MCA_MORE); 338221715Sdelphij case '-': 339221715Sdelphij /* "--" = long option name. */ 340221715Sdelphij optgetname = TRUE; 341221715Sdelphij mca_opt_toggle(); 342221715Sdelphij return (MCA_MORE); 343221715Sdelphij } 344221715Sdelphij } 345221715Sdelphij /* Char was not handled here. */ 346221715Sdelphij return (NO_MCA); 347221715Sdelphij} 348221715Sdelphij 349221715Sdelphij/* 350221715Sdelphij * Add a char to a long option name. 351221715Sdelphij * See if we've got a match for an option name yet. 352221715Sdelphij * If so, display the complete name and stop 353221715Sdelphij * accepting chars until user hits RETURN. 354221715Sdelphij */ 355221715Sdelphij static int 356221715Sdelphijmca_opt_nonfirst_char(c) 357221715Sdelphij int c; 358221715Sdelphij{ 35960786Sps char *p; 360221715Sdelphij char *oname; 361221715Sdelphij 362221715Sdelphij if (curropt != NULL) 363221715Sdelphij { 364221715Sdelphij /* 365221715Sdelphij * Already have a match for the name. 366221715Sdelphij * Don't accept anything but erase/kill. 367221715Sdelphij */ 368221715Sdelphij if (is_erase_char(c)) 369221715Sdelphij return (MCA_DONE); 370221715Sdelphij return (MCA_MORE); 371221715Sdelphij } 372221715Sdelphij /* 373221715Sdelphij * Add char to cmd buffer and try to match 374221715Sdelphij * the option name. 375221715Sdelphij */ 376221715Sdelphij if (cmd_char(c) == CC_QUIT) 377221715Sdelphij return (MCA_DONE); 378221715Sdelphij p = get_cmdbuf(); 379221715Sdelphij opt_lower = ASCII_IS_LOWER(p[0]); 380221715Sdelphij curropt = findopt_name(&p, &oname, NULL); 381221715Sdelphij if (curropt != NULL) 382221715Sdelphij { 383221715Sdelphij /* 384221715Sdelphij * Got a match. 385221715Sdelphij * Remember the option and 386221715Sdelphij * display the full option name. 387221715Sdelphij */ 388221715Sdelphij cmd_reset(); 389221715Sdelphij mca_opt_toggle(); 390221715Sdelphij for (p = oname; *p != '\0'; p++) 391221715Sdelphij { 392221715Sdelphij c = *p; 393221715Sdelphij if (!opt_lower && ASCII_IS_LOWER(c)) 394221715Sdelphij c = ASCII_TO_UPPER(c); 395221715Sdelphij if (cmd_char(c) != CC_OK) 396221715Sdelphij return (MCA_DONE); 397221715Sdelphij } 398221715Sdelphij } 399221715Sdelphij return (MCA_MORE); 400221715Sdelphij} 401221715Sdelphij 402221715Sdelphij/* 403221715Sdelphij * Handle a char of an option toggle command. 404221715Sdelphij */ 405221715Sdelphij static int 406221715Sdelphijmca_opt_char(c) 407221715Sdelphij int c; 408221715Sdelphij{ 40960786Sps PARG parg; 41060786Sps 411221715Sdelphij /* 412221715Sdelphij * This may be a short option (single char), 413221715Sdelphij * or one char of a long option name, 414221715Sdelphij * or one char of the option parameter. 415221715Sdelphij */ 416221715Sdelphij if (curropt == NULL && len_cmdbuf() == 0) 417221715Sdelphij { 418221715Sdelphij int ret = mca_opt_first_char(c); 419221715Sdelphij if (ret != NO_MCA) 420221715Sdelphij return (ret); 421221715Sdelphij } 422221715Sdelphij if (optgetname) 423221715Sdelphij { 424221715Sdelphij /* We're getting a long option name. */ 425221715Sdelphij if (c != '\n' && c != '\r') 426221715Sdelphij return (mca_opt_nonfirst_char(c)); 427221715Sdelphij if (curropt == NULL) 428221715Sdelphij { 429221715Sdelphij parg.p_string = get_cmdbuf(); 430221715Sdelphij error("There is no --%s option", &parg); 431221715Sdelphij return (MCA_DONE); 432221715Sdelphij } 433221715Sdelphij optgetname = FALSE; 434221715Sdelphij cmd_reset(); 435221715Sdelphij } else 436221715Sdelphij { 437221715Sdelphij if (is_erase_char(c)) 438221715Sdelphij return (NO_MCA); 439221715Sdelphij if (curropt != NULL) 440221715Sdelphij /* We're getting the option parameter. */ 441221715Sdelphij return (NO_MCA); 442221715Sdelphij curropt = findopt(c); 443221715Sdelphij if (curropt == NULL) 444221715Sdelphij { 445221715Sdelphij parg.p_string = propt(c); 446221715Sdelphij error("There is no %s option", &parg); 447221715Sdelphij return (MCA_DONE); 448221715Sdelphij } 449221715Sdelphij } 450221715Sdelphij /* 451221715Sdelphij * If the option which was entered does not take a 452221715Sdelphij * parameter, toggle the option immediately, 453221715Sdelphij * so user doesn't have to hit RETURN. 454221715Sdelphij */ 455221715Sdelphij if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || 456221715Sdelphij !opt_has_param(curropt)) 457221715Sdelphij { 458221715Sdelphij toggle_option(curropt, ASCII_IS_LOWER(c), "", optflag); 459221715Sdelphij return (MCA_DONE); 460221715Sdelphij } 461221715Sdelphij /* 462221715Sdelphij * Display a prompt appropriate for the option parameter. 463221715Sdelphij */ 464221715Sdelphij start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0); 465221715Sdelphij return (MCA_MORE); 466221715Sdelphij} 467221715Sdelphij 468221715Sdelphij/* 469221715Sdelphij * Handle a char of a search command. 470221715Sdelphij */ 471221715Sdelphij static int 472221715Sdelphijmca_search_char(c) 473221715Sdelphij int c; 474221715Sdelphij{ 475221715Sdelphij int flag = 0; 476221715Sdelphij 477221715Sdelphij /* 478221715Sdelphij * Certain characters as the first char of 479221715Sdelphij * the pattern have special meaning: 480221715Sdelphij * ! Toggle the NO_MATCH flag 481221715Sdelphij * * Toggle the PAST_EOF flag 482221715Sdelphij * @ Toggle the FIRST_FILE flag 483221715Sdelphij */ 484221715Sdelphij if (len_cmdbuf() > 0) 485221715Sdelphij return (NO_MCA); 486221715Sdelphij 487221715Sdelphij switch (c) 488221715Sdelphij { 489221715Sdelphij case '*': 490221715Sdelphij if (less_is_more) 491221715Sdelphij break; 492221715Sdelphij case CONTROL('E'): /* ignore END of file */ 493221715Sdelphij if (mca != A_FILTER) 494221715Sdelphij flag = SRCH_PAST_EOF; 495221715Sdelphij break; 496221715Sdelphij case '@': 497221715Sdelphij if (less_is_more) 498221715Sdelphij break; 499221715Sdelphij case CONTROL('F'): /* FIRST file */ 500221715Sdelphij if (mca != A_FILTER) 501221715Sdelphij flag = SRCH_FIRST_FILE; 502221715Sdelphij break; 503221715Sdelphij case CONTROL('K'): /* KEEP position */ 504221715Sdelphij if (mca != A_FILTER) 505221715Sdelphij flag = SRCH_NO_MOVE; 506221715Sdelphij break; 507221715Sdelphij case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ 508221715Sdelphij flag = SRCH_NO_REGEX; 509221715Sdelphij break; 510221715Sdelphij case CONTROL('N'): /* NOT match */ 511221715Sdelphij case '!': 512221715Sdelphij flag = SRCH_NO_MATCH; 513221715Sdelphij break; 514221715Sdelphij } 515221715Sdelphij 516221715Sdelphij if (flag != 0) 517221715Sdelphij { 518221715Sdelphij search_type ^= flag; 519221715Sdelphij mca_search(); 520221715Sdelphij return (MCA_MORE); 521221715Sdelphij } 522221715Sdelphij return (NO_MCA); 523221715Sdelphij} 524221715Sdelphij 525221715Sdelphij/* 526221715Sdelphij * Handle a character of a multi-character command. 527221715Sdelphij */ 528221715Sdelphij static int 529221715Sdelphijmca_char(c) 530221715Sdelphij int c; 531221715Sdelphij{ 532221715Sdelphij int ret; 533221715Sdelphij 53460786Sps switch (mca) 53560786Sps { 53660786Sps case 0: 53760786Sps /* 538221715Sdelphij * We're not in a multicharacter command. 53960786Sps */ 54060786Sps return (NO_MCA); 54160786Sps 54260786Sps case A_PREFIX: 54360786Sps /* 54460786Sps * In the prefix of a command. 54560786Sps * This not considered a multichar command 54660786Sps * (even tho it uses cmdbuf, etc.). 54760786Sps * It is handled in the commands() switch. 54860786Sps */ 54960786Sps return (NO_MCA); 55060786Sps 55160786Sps case A_DIGIT: 55260786Sps /* 55360786Sps * Entering digits of a number. 55460786Sps * Terminated by a non-digit. 55560786Sps */ 556170259Sdelphij if (!((c >= '0' && c <= '9') || c == '.') && 55789022Sps editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) 55860786Sps { 55960786Sps /* 56060786Sps * Not part of the number. 561221715Sdelphij * End the number and treat this char 562221715Sdelphij * as a normal command character. 56360786Sps */ 564170259Sdelphij number = cmd_int(&fraction); 56560786Sps mca = 0; 56660786Sps cmd_accept(); 56760786Sps return (NO_MCA); 56860786Sps } 56960786Sps break; 57060786Sps 57160786Sps case A_OPT_TOGGLE: 572221715Sdelphij ret = mca_opt_char(c); 573221715Sdelphij if (ret != NO_MCA) 574221715Sdelphij return (ret); 575221715Sdelphij break; 57660786Sps 57760786Sps case A_F_SEARCH: 57860786Sps case A_B_SEARCH: 579191930Sdelphij case A_FILTER: 580221715Sdelphij ret = mca_search_char(c); 581221715Sdelphij if (ret != NO_MCA) 582221715Sdelphij return (ret); 583221715Sdelphij break; 58460786Sps 585221715Sdelphij default: 586221715Sdelphij /* Other multicharacter command. */ 58760786Sps break; 58860786Sps } 58960786Sps 59060786Sps /* 591221715Sdelphij * The multichar command is terminated by a newline. 59260786Sps */ 59360786Sps if (c == '\n' || c == '\r') 59460786Sps { 59560786Sps /* 59660786Sps * Execute the command. 59760786Sps */ 59860786Sps exec_mca(); 59960786Sps return (MCA_DONE); 60060786Sps } 60160786Sps 60260786Sps /* 60360786Sps * Append the char to the command buffer. 60460786Sps */ 60560786Sps if (cmd_char(c) == CC_QUIT) 60660786Sps /* 60760786Sps * Abort the multi-char command. 60860786Sps */ 60960786Sps return (MCA_DONE); 61060786Sps 61160786Sps if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) 61260786Sps { 61360786Sps /* 61460786Sps * Special case for the bracket-matching commands. 61560786Sps * Execute the command after getting exactly two 61660786Sps * characters from the user. 61760786Sps */ 61860786Sps exec_mca(); 61960786Sps return (MCA_DONE); 62060786Sps } 62160786Sps 62260786Sps /* 62360786Sps * Need another character. 62460786Sps */ 62560786Sps return (MCA_MORE); 62660786Sps} 62760786Sps 62860786Sps/* 629173685Sdelphij * Discard any buffered file data. 630173685Sdelphij */ 631173685Sdelphij static void 632173685Sdelphijclear_buffers() 633173685Sdelphij{ 634173685Sdelphij if (!(ch_getflags() & CH_CANSEEK)) 635173685Sdelphij return; 636173685Sdelphij ch_flush(); 637173685Sdelphij clr_linenum(); 638173685Sdelphij#if HILITE_SEARCH 639173685Sdelphij clr_hilite(); 640173685Sdelphij#endif 641173685Sdelphij} 642173685Sdelphij 643173685Sdelphij/* 64460786Sps * Make sure the screen is displayed. 64560786Sps */ 64660786Sps static void 64760786Spsmake_display() 64860786Sps{ 64960786Sps /* 65060786Sps * If nothing is displayed yet, display starting from initial_scrpos. 65160786Sps */ 65260786Sps if (empty_screen()) 65360786Sps { 65460786Sps if (initial_scrpos.pos == NULL_POSITION) 65560786Sps /* 65660786Sps * {{ Maybe this should be: 65760786Sps * jump_loc(ch_zero(), jump_sline); 65860786Sps * but this behavior seems rather unexpected 65960786Sps * on the first screen. }} 66060786Sps */ 66160786Sps jump_loc(ch_zero(), 1); 66260786Sps else 66360786Sps jump_loc(initial_scrpos.pos, initial_scrpos.ln); 66460786Sps } else if (screen_trashed) 66560786Sps { 666173685Sdelphij int save_top_scroll = top_scroll; 667173685Sdelphij int save_ignore_eoi = ignore_eoi; 66860786Sps top_scroll = 1; 669173685Sdelphij ignore_eoi = 0; 670173685Sdelphij if (screen_trashed == 2) 671173685Sdelphij { 672173685Sdelphij /* Special case used by ignore_eoi: re-open the input file 673173685Sdelphij * and jump to the end of the file. */ 674173685Sdelphij reopen_curr_ifile(); 675173685Sdelphij jump_forw(); 676173685Sdelphij } 67760786Sps repaint(); 67860786Sps top_scroll = save_top_scroll; 679173685Sdelphij ignore_eoi = save_ignore_eoi; 68060786Sps } 68160786Sps} 68260786Sps 68360786Sps/* 68460786Sps * Display the appropriate prompt. 68560786Sps */ 68660786Sps static void 68760786Spsprompt() 68860786Sps{ 689240121Sdelphij register constant char *p; 69060786Sps 691221715Sdelphij if (ungot != NULL) 69260786Sps { 69360786Sps /* 69460786Sps * No prompt necessary if commands are from 69560786Sps * ungotten chars rather than from the user. 69660786Sps */ 69760786Sps return; 69860786Sps } 69960786Sps 70060786Sps /* 70160786Sps * Make sure the screen is displayed. 70260786Sps */ 70360786Sps make_display(); 70460786Sps bottompos = position(BOTTOM_PLUS_ONE); 70560786Sps 70660786Sps /* 707191930Sdelphij * If we've hit EOF on the last file and the -E flag is set, quit. 70860786Sps */ 709191930Sdelphij if (get_quit_at_eof() == OPT_ONPLUS && 710191930Sdelphij eof_displayed() && !(ch_getflags() & CH_HELPFILE) && 71160786Sps next_ifile(curr_ifile) == NULL_IFILE) 71260786Sps quit(QUIT_OK); 713191930Sdelphij 71460786Sps /* 715191930Sdelphij * If the entire file is displayed and the -F flag is set, quit. 71660786Sps */ 717191930Sdelphij if (quit_if_one_screen && 718191930Sdelphij entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && 71960786Sps next_ifile(curr_ifile) == NULL_IFILE) 72060786Sps quit(QUIT_OK); 72160786Sps 72289022Sps#if MSDOS_COMPILER==WIN32C 72389022Sps /* 72489022Sps * In Win32, display the file name in the window title. 72589022Sps */ 72689022Sps if (!(ch_getflags() & CH_HELPFILE)) 72789022Sps SetConsoleTitle(pr_expand("Less?f - %f.", 0)); 72889022Sps#endif 72960786Sps /* 73060786Sps * Select the proper prompt and display it. 73160786Sps */ 732170259Sdelphij /* 733170259Sdelphij * If the previous action was a forward movement, 734170259Sdelphij * don't clear the bottom line of the display; 735170259Sdelphij * just print the prompt since the forward movement guarantees 736170259Sdelphij * that we're in the right position to display the prompt. 737170259Sdelphij * Clearing the line could cause a problem: for example, if the last 738170259Sdelphij * line displayed ended at the right screen edge without a newline, 739170259Sdelphij * then clearing would clear the last displayed line rather than 740170259Sdelphij * the prompt line. 741170259Sdelphij */ 742170259Sdelphij if (!forw_prompt) 743170259Sdelphij clear_bot(); 74460786Sps clear_cmd(); 745170259Sdelphij forw_prompt = 0; 74660786Sps p = pr_string(); 747191930Sdelphij if (is_filtering()) 748191930Sdelphij putstr("& "); 749161478Sdelphij if (p == NULL || *p == '\0') 75060786Sps putchr(':'); 75160786Sps else 75260786Sps { 753161478Sdelphij at_enter(AT_STANDOUT); 75460786Sps putstr(p); 755161478Sdelphij at_exit(); 75660786Sps } 757170259Sdelphij clear_eol(); 75860786Sps} 75960786Sps 76060786Sps/* 76160786Sps * Display the less version message. 76260786Sps */ 76360786Sps public void 76460786Spsdispversion() 76560786Sps{ 76660786Sps PARG parg; 76760786Sps 76860786Sps parg.p_string = version; 76960786Sps error("less %s", &parg); 77060786Sps} 77160786Sps 77260786Sps/* 77360786Sps * Get command character. 77460786Sps * The character normally comes from the keyboard, 77560786Sps * but may come from ungotten characters 77660786Sps * (characters previously given to ungetcc or ungetsc). 77760786Sps */ 77860786Sps public int 77960786Spsgetcc() 78060786Sps{ 781221715Sdelphij if (unget_end) 782221715Sdelphij { 78360786Sps /* 784221715Sdelphij * We have just run out of ungotten chars. 78560786Sps */ 786221715Sdelphij unget_end = 0; 787221715Sdelphij if (len_cmdbuf() == 0 || !empty_screen()) 788221715Sdelphij return (getchr()); 78960786Sps /* 790221715Sdelphij * Command is incomplete, so try to complete it. 79160786Sps */ 792221715Sdelphij switch (mca) 793221715Sdelphij { 794221715Sdelphij case A_DIGIT: 795221715Sdelphij /* 796221715Sdelphij * We have a number but no command. Treat as #g. 797221715Sdelphij */ 798221715Sdelphij return ('g'); 79960786Sps 800221715Sdelphij case A_F_SEARCH: 801221715Sdelphij case A_B_SEARCH: 802221715Sdelphij /* 803221715Sdelphij * We have "/string" but no newline. Add the \n. 804221715Sdelphij */ 805221715Sdelphij return ('\n'); 80660786Sps 807221715Sdelphij default: 808221715Sdelphij /* 809221715Sdelphij * Some other incomplete command. Let user complete it. 810221715Sdelphij */ 811221715Sdelphij return (getchr()); 812221715Sdelphij } 813221715Sdelphij } 81460786Sps 815221715Sdelphij if (ungot == NULL) 816221715Sdelphij { 81760786Sps /* 818221715Sdelphij * Normal case: no ungotten chars, so get one from the user. 81960786Sps */ 82060786Sps return (getchr()); 82160786Sps } 822221715Sdelphij 823221715Sdelphij /* 824221715Sdelphij * Return the next ungotten char. 825221715Sdelphij */ 826221715Sdelphij { 827221715Sdelphij struct ungot *ug = ungot; 828221715Sdelphij char c = ug->ug_char; 829221715Sdelphij ungot = ug->ug_next; 830221715Sdelphij free(ug); 831221715Sdelphij unget_end = (ungot == NULL); 832221715Sdelphij return (c); 833221715Sdelphij } 83460786Sps} 83560786Sps 83660786Sps/* 83760786Sps * "Unget" a command character. 83860786Sps * The next getcc() will return this character. 83960786Sps */ 84060786Sps public void 84160786Spsungetcc(c) 84260786Sps int c; 84360786Sps{ 844221715Sdelphij struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot)); 845221715Sdelphij 846221715Sdelphij ug->ug_char = c; 847221715Sdelphij ug->ug_next = ungot; 848221715Sdelphij ungot = ug; 849222906Sdelphij unget_end = 0; 85060786Sps} 85160786Sps 85260786Sps/* 85360786Sps * Unget a whole string of command characters. 85460786Sps * The next sequence of getcc()'s will return this string. 85560786Sps */ 85660786Sps public void 85760786Spsungetsc(s) 85860786Sps char *s; 85960786Sps{ 86060786Sps register char *p; 86160786Sps 86260786Sps for (p = s + strlen(s) - 1; p >= s; p--) 86360786Sps ungetcc(*p); 86460786Sps} 86560786Sps 86660786Sps/* 86760786Sps * Search for a pattern, possibly in multiple files. 86860786Sps * If SRCH_FIRST_FILE is set, begin searching at the first file. 86960786Sps * If SRCH_PAST_EOF is set, continue the search thru multiple files. 87060786Sps */ 87160786Sps static void 87260786Spsmulti_search(pattern, n) 87360786Sps char *pattern; 87460786Sps int n; 87560786Sps{ 87660786Sps register int nomore; 87760786Sps IFILE save_ifile; 87860786Sps int changed_file; 87960786Sps 88060786Sps changed_file = 0; 88160786Sps save_ifile = save_curr_ifile(); 88260786Sps 88360786Sps if (search_type & SRCH_FIRST_FILE) 88460786Sps { 88560786Sps /* 88660786Sps * Start at the first (or last) file 88760786Sps * in the command line list. 88860786Sps */ 88960786Sps if (search_type & SRCH_FORW) 89060786Sps nomore = edit_first(); 89160786Sps else 89260786Sps nomore = edit_last(); 89360786Sps if (nomore) 89460786Sps { 89560786Sps unsave_ifile(save_ifile); 89660786Sps return; 89760786Sps } 89860786Sps changed_file = 1; 89960786Sps search_type &= ~SRCH_FIRST_FILE; 90060786Sps } 90160786Sps 90260786Sps for (;;) 90360786Sps { 90460786Sps n = search(search_type, pattern, n); 90560786Sps /* 90660786Sps * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared 90760786Sps * after being used once. This allows "n" to work after 90860786Sps * using a /@@ search. 90960786Sps */ 91060786Sps search_type &= ~SRCH_NO_MOVE; 91160786Sps if (n == 0) 91260786Sps { 91360786Sps /* 91460786Sps * Found it. 91560786Sps */ 91660786Sps unsave_ifile(save_ifile); 91760786Sps return; 91860786Sps } 91960786Sps 92060786Sps if (n < 0) 92160786Sps /* 92260786Sps * Some kind of error in the search. 92360786Sps * Error message has been printed by search(). 92460786Sps */ 92560786Sps break; 92660786Sps 92760786Sps if ((search_type & SRCH_PAST_EOF) == 0) 92860786Sps /* 92960786Sps * We didn't find a match, but we're 93060786Sps * supposed to search only one file. 93160786Sps */ 93260786Sps break; 93360786Sps /* 93460786Sps * Move on to the next file. 93560786Sps */ 93660786Sps if (search_type & SRCH_FORW) 93760786Sps nomore = edit_next(1); 93860786Sps else 93960786Sps nomore = edit_prev(1); 94060786Sps if (nomore) 94160786Sps break; 94260786Sps changed_file = 1; 94360786Sps } 94460786Sps 94560786Sps /* 94660786Sps * Didn't find it. 94760786Sps * Print an error message if we haven't already. 94860786Sps */ 94960786Sps if (n > 0) 95060786Sps error("Pattern not found", NULL_PARG); 95160786Sps 95260786Sps if (changed_file) 95360786Sps { 95460786Sps /* 95560786Sps * Restore the file we were originally viewing. 95660786Sps */ 95760786Sps reedit_ifile(save_ifile); 958161478Sdelphij } else 959161478Sdelphij { 960161478Sdelphij unsave_ifile(save_ifile); 96160786Sps } 96260786Sps} 96360786Sps 96460786Sps/* 965240121Sdelphij * Forward forever, or until a highlighted line appears. 966240121Sdelphij */ 967240121Sdelphij static int 968240121Sdelphijforw_loop(until_hilite) 969240121Sdelphij int until_hilite; 970240121Sdelphij{ 971240121Sdelphij POSITION curr_len; 972240121Sdelphij 973240121Sdelphij if (ch_getflags() & CH_HELPFILE) 974240121Sdelphij return (A_NOACTION); 975240121Sdelphij 976240121Sdelphij cmd_exec(); 977240121Sdelphij jump_forw(); 978240121Sdelphij curr_len = ch_length(); 979240121Sdelphij highest_hilite = until_hilite ? curr_len : NULL_POSITION; 980240121Sdelphij ignore_eoi = 1; 981240121Sdelphij while (!sigs) 982240121Sdelphij { 983240121Sdelphij if (until_hilite && highest_hilite > curr_len) 984240121Sdelphij { 985240121Sdelphij bell(); 986240121Sdelphij break; 987240121Sdelphij } 988240121Sdelphij make_display(); 989240121Sdelphij forward(1, 0, 0); 990240121Sdelphij } 991240121Sdelphij ignore_eoi = 0; 992240121Sdelphij ch_set_eof(); 993240121Sdelphij 994240121Sdelphij /* 995240121Sdelphij * This gets us back in "F mode" after processing 996240121Sdelphij * a non-abort signal (e.g. window-change). 997240121Sdelphij */ 998240121Sdelphij if (sigs && !ABORT_SIGS()) 999240121Sdelphij return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER); 1000240121Sdelphij 1001240121Sdelphij return (A_NOACTION); 1002240121Sdelphij} 1003240121Sdelphij 1004240121Sdelphij/* 100560786Sps * Main command processor. 100660786Sps * Accept and execute commands until a quit command. 100760786Sps */ 100860786Sps public void 100960786Spscommands() 101060786Sps{ 101160786Sps register int c; 101260786Sps register int action; 101360786Sps register char *cbuf; 101460786Sps int newaction; 101560786Sps int save_search_type; 101660786Sps char *extra; 101760786Sps char tbuf[2]; 101860786Sps PARG parg; 101960786Sps IFILE old_ifile; 102060786Sps IFILE new_ifile; 102189022Sps char *tagfile; 1022240121Sdelphij int until_hilite = 0; 102360786Sps 102460786Sps search_type = SRCH_FORW; 102560786Sps wscroll = (sc_height + 1) / 2; 102660786Sps newaction = A_NOACTION; 102760786Sps 102860786Sps for (;;) 102960786Sps { 103060786Sps mca = 0; 103160786Sps cmd_accept(); 103260786Sps number = 0; 1033221715Sdelphij curropt = NULL; 103460786Sps 103560786Sps /* 103660786Sps * See if any signals need processing. 103760786Sps */ 103860786Sps if (sigs) 103960786Sps { 104060786Sps psignals(); 104160786Sps if (quitting) 104260786Sps quit(QUIT_SAVED_STATUS); 104360786Sps } 104460786Sps 104560786Sps /* 104660786Sps * See if window size changed, for systems that don't 104760786Sps * generate SIGWINCH. 104860786Sps */ 104960786Sps check_winch(); 105060786Sps 105160786Sps /* 105260786Sps * Display prompt and accept a character. 105360786Sps */ 105460786Sps cmd_reset(); 105560786Sps prompt(); 105660786Sps if (sigs) 105760786Sps continue; 105860786Sps if (newaction == A_NOACTION) 105960786Sps c = getcc(); 106060786Sps 106160786Sps again: 106260786Sps if (sigs) 106360786Sps continue; 106460786Sps 106560786Sps if (newaction != A_NOACTION) 106660786Sps { 106760786Sps action = newaction; 106860786Sps newaction = A_NOACTION; 106960786Sps } else 107060786Sps { 107160786Sps /* 107260786Sps * If we are in a multicharacter command, call mca_char. 107360786Sps * Otherwise we call fcmd_decode to determine the 107460786Sps * action to be performed. 107560786Sps */ 107660786Sps if (mca) 107760786Sps switch (mca_char(c)) 107860786Sps { 107960786Sps case MCA_MORE: 108060786Sps /* 108160786Sps * Need another character. 108260786Sps */ 108360786Sps c = getcc(); 108460786Sps goto again; 108560786Sps case MCA_DONE: 108660786Sps /* 108760786Sps * Command has been handled by mca_char. 108860786Sps * Start clean with a prompt. 108960786Sps */ 109060786Sps continue; 109160786Sps case NO_MCA: 109260786Sps /* 109360786Sps * Not a multi-char command 109460786Sps * (at least, not anymore). 109560786Sps */ 109660786Sps break; 109760786Sps } 109860786Sps 109960786Sps /* 110060786Sps * Decode the command character and decide what to do. 110160786Sps */ 110260786Sps if (mca) 110360786Sps { 110460786Sps /* 110560786Sps * We're in a multichar command. 110660786Sps * Add the character to the command buffer 110760786Sps * and display it on the screen. 110860786Sps * If the user backspaces past the start 110960786Sps * of the line, abort the command. 111060786Sps */ 111160786Sps if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) 111260786Sps continue; 111360786Sps cbuf = get_cmdbuf(); 111460786Sps } else 111560786Sps { 111660786Sps /* 111760786Sps * Don't use cmd_char if we're starting fresh 111860786Sps * at the beginning of a command, because we 111960786Sps * don't want to echo the command until we know 112060786Sps * it is a multichar command. We also don't 112160786Sps * want erase_char/kill_char to be treated 112260786Sps * as line editing characters. 112360786Sps */ 112460786Sps tbuf[0] = c; 112560786Sps tbuf[1] = '\0'; 112660786Sps cbuf = tbuf; 112760786Sps } 112860786Sps extra = NULL; 112960786Sps action = fcmd_decode(cbuf, &extra); 113060786Sps /* 113160786Sps * If an "extra" string was returned, 113260786Sps * process it as a string of command characters. 113360786Sps */ 113460786Sps if (extra != NULL) 113560786Sps ungetsc(extra); 113660786Sps } 113760786Sps /* 113860786Sps * Clear the cmdbuf string. 113960786Sps * (But not if we're in the prefix of a command, 114060786Sps * because the partial command string is kept there.) 114160786Sps */ 114260786Sps if (action != A_PREFIX) 114360786Sps cmd_reset(); 114460786Sps 114560786Sps switch (action) 114660786Sps { 114760786Sps case A_DIGIT: 114860786Sps /* 114960786Sps * First digit of a number. 115060786Sps */ 115160786Sps start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); 115260786Sps goto again; 115360786Sps 115460786Sps case A_F_WINDOW: 115560786Sps /* 115660786Sps * Forward one window (and set the window size). 115760786Sps */ 115860786Sps if (number > 0) 1159128348Stjr swindow = (int) number; 116060786Sps /* FALLTHRU */ 116160786Sps case A_F_SCREEN: 116260786Sps /* 116360786Sps * Forward one screen. 116460786Sps */ 116560786Sps if (number <= 0) 116660786Sps number = get_swindow(); 116760786Sps cmd_exec(); 116860786Sps if (show_attn) 116960786Sps set_attnpos(bottompos); 1170128348Stjr forward((int) number, 0, 1); 117160786Sps break; 117260786Sps 117360786Sps case A_B_WINDOW: 117460786Sps /* 117560786Sps * Backward one window (and set the window size). 117660786Sps */ 117760786Sps if (number > 0) 1178128348Stjr swindow = (int) number; 117960786Sps /* FALLTHRU */ 118060786Sps case A_B_SCREEN: 118160786Sps /* 118260786Sps * Backward one screen. 118360786Sps */ 118460786Sps if (number <= 0) 118560786Sps number = get_swindow(); 118660786Sps cmd_exec(); 1187128348Stjr backward((int) number, 0, 1); 118860786Sps break; 118960786Sps 119060786Sps case A_F_LINE: 119160786Sps /* 119260786Sps * Forward N (default 1) line. 119360786Sps */ 119460786Sps if (number <= 0) 119560786Sps number = 1; 119660786Sps cmd_exec(); 119760786Sps if (show_attn == OPT_ONPLUS && number > 1) 119860786Sps set_attnpos(bottompos); 1199128348Stjr forward((int) number, 0, 0); 120060786Sps break; 120160786Sps 120260786Sps case A_B_LINE: 120360786Sps /* 120460786Sps * Backward N (default 1) line. 120560786Sps */ 120660786Sps if (number <= 0) 120760786Sps number = 1; 120860786Sps cmd_exec(); 1209128348Stjr backward((int) number, 0, 0); 121060786Sps break; 121160786Sps 121260786Sps case A_FF_LINE: 121360786Sps /* 121460786Sps * Force forward N (default 1) line. 121560786Sps */ 121660786Sps if (number <= 0) 121760786Sps number = 1; 121860786Sps cmd_exec(); 121960786Sps if (show_attn == OPT_ONPLUS && number > 1) 122060786Sps set_attnpos(bottompos); 1221128348Stjr forward((int) number, 1, 0); 122260786Sps break; 122360786Sps 122460786Sps case A_BF_LINE: 122560786Sps /* 122660786Sps * Force backward N (default 1) line. 122760786Sps */ 122860786Sps if (number <= 0) 122960786Sps number = 1; 123060786Sps cmd_exec(); 1231128348Stjr backward((int) number, 1, 0); 123260786Sps break; 123360786Sps 123460786Sps case A_FF_SCREEN: 123560786Sps /* 123660786Sps * Force forward one screen. 123760786Sps */ 123860786Sps if (number <= 0) 123960786Sps number = get_swindow(); 124060786Sps cmd_exec(); 124160786Sps if (show_attn == OPT_ONPLUS) 124260786Sps set_attnpos(bottompos); 1243128348Stjr forward((int) number, 1, 0); 124460786Sps break; 124560786Sps 124660786Sps case A_F_FOREVER: 124760786Sps /* 124860786Sps * Forward forever, ignoring EOF. 124960786Sps */ 1250240121Sdelphij newaction = forw_loop(0); 125160786Sps break; 125260786Sps 1253240121Sdelphij case A_F_UNTIL_HILITE: 1254240121Sdelphij newaction = forw_loop(1); 1255240121Sdelphij break; 1256240121Sdelphij 125760786Sps case A_F_SCROLL: 125860786Sps /* 125960786Sps * Forward N lines 126060786Sps * (default same as last 'd' or 'u' command). 126160786Sps */ 126260786Sps if (number > 0) 1263128348Stjr wscroll = (int) number; 126460786Sps cmd_exec(); 126560786Sps if (show_attn == OPT_ONPLUS) 126660786Sps set_attnpos(bottompos); 126760786Sps forward(wscroll, 0, 0); 126860786Sps break; 126960786Sps 127060786Sps case A_B_SCROLL: 127160786Sps /* 127260786Sps * Forward N lines 127360786Sps * (default same as last 'd' or 'u' command). 127460786Sps */ 127560786Sps if (number > 0) 1276128348Stjr wscroll = (int) number; 127760786Sps cmd_exec(); 127860786Sps backward(wscroll, 0, 0); 127960786Sps break; 128060786Sps 128160786Sps case A_FREPAINT: 128260786Sps /* 128360786Sps * Flush buffers, then repaint screen. 128460786Sps * Don't flush the buffers on a pipe! 128560786Sps */ 1286173685Sdelphij clear_buffers(); 128760786Sps /* FALLTHRU */ 128860786Sps case A_REPAINT: 128960786Sps /* 129060786Sps * Repaint screen. 129160786Sps */ 129260786Sps cmd_exec(); 129360786Sps repaint(); 129460786Sps break; 129560786Sps 129660786Sps case A_GOLINE: 129760786Sps /* 129860786Sps * Go to line N, default beginning of file. 129960786Sps */ 130060786Sps if (number <= 0) 130160786Sps number = 1; 130260786Sps cmd_exec(); 130360786Sps jump_back(number); 130460786Sps break; 130560786Sps 130660786Sps case A_PERCENT: 130760786Sps /* 130860786Sps * Go to a specified percentage into the file. 130960786Sps */ 131060786Sps if (number < 0) 1311170259Sdelphij { 131260786Sps number = 0; 1313170259Sdelphij fraction = 0; 1314170259Sdelphij } 131560786Sps if (number > 100) 1316170259Sdelphij { 131760786Sps number = 100; 1318170259Sdelphij fraction = 0; 1319170259Sdelphij } 132060786Sps cmd_exec(); 1321170259Sdelphij jump_percent((int) number, fraction); 132260786Sps break; 132360786Sps 132460786Sps case A_GOEND: 132560786Sps /* 132660786Sps * Go to line N, default end of file. 132760786Sps */ 132860786Sps cmd_exec(); 132960786Sps if (number <= 0) 133060786Sps jump_forw(); 133160786Sps else 133260786Sps jump_back(number); 133360786Sps break; 133460786Sps 133560786Sps case A_GOPOS: 133660786Sps /* 133760786Sps * Go to a specified byte position in the file. 133860786Sps */ 133960786Sps cmd_exec(); 134060786Sps if (number < 0) 134160786Sps number = 0; 1342128348Stjr jump_line_loc((POSITION) number, jump_sline); 134360786Sps break; 134460786Sps 134560786Sps case A_STAT: 134660786Sps /* 134760786Sps * Print file name, etc. 134860786Sps */ 134960786Sps if (ch_getflags() & CH_HELPFILE) 135060786Sps break; 135160786Sps cmd_exec(); 135260786Sps parg.p_string = eq_message(); 135360786Sps error("%s", &parg); 135460786Sps break; 135560786Sps 135660786Sps case A_VERSION: 135760786Sps /* 135860786Sps * Print version number, without the "@(#)". 135960786Sps */ 136060786Sps cmd_exec(); 136160786Sps dispversion(); 136260786Sps break; 136360786Sps 136460786Sps case A_QUIT: 136560786Sps /* 136660786Sps * Exit. 136760786Sps */ 136860786Sps if (curr_ifile != NULL_IFILE && 136960786Sps ch_getflags() & CH_HELPFILE) 137060786Sps { 137160786Sps /* 137260786Sps * Quit while viewing the help file 137360786Sps * just means return to viewing the 137460786Sps * previous file. 137560786Sps */ 1376161478Sdelphij hshift = save_hshift; 137760786Sps if (edit_prev(1) == 0) 137860786Sps break; 137960786Sps } 138060786Sps if (extra != NULL) 138160786Sps quit(*extra); 138260786Sps quit(QUIT_OK); 138360786Sps break; 138460786Sps 138560786Sps/* 138660786Sps * Define abbreviation for a commonly used sequence below. 138760786Sps */ 1388173685Sdelphij#define DO_SEARCH() \ 1389173685Sdelphij if (number <= 0) number = 1; \ 139060786Sps mca_search(); \ 139160786Sps cmd_exec(); \ 1392128348Stjr multi_search((char *)NULL, (int) number); 139360786Sps 139460786Sps 139560786Sps case A_F_SEARCH: 139660786Sps /* 139760786Sps * Search forward for a pattern. 139860786Sps * Get the first char of the pattern. 139960786Sps */ 140060786Sps search_type = SRCH_FORW; 140160786Sps if (number <= 0) 140260786Sps number = 1; 140360786Sps mca_search(); 140460786Sps c = getcc(); 140560786Sps goto again; 140660786Sps 140760786Sps case A_B_SEARCH: 140860786Sps /* 140960786Sps * Search backward for a pattern. 141060786Sps * Get the first char of the pattern. 141160786Sps */ 141260786Sps search_type = SRCH_BACK; 141360786Sps if (number <= 0) 141460786Sps number = 1; 141560786Sps mca_search(); 141660786Sps c = getcc(); 141760786Sps goto again; 141860786Sps 1419191930Sdelphij case A_FILTER: 1420191930Sdelphij#if HILITE_SEARCH 1421191930Sdelphij search_type = SRCH_FORW | SRCH_FILTER; 1422191930Sdelphij mca_search(); 1423191930Sdelphij c = getcc(); 1424191930Sdelphij goto again; 1425191930Sdelphij#else 1426191930Sdelphij error("Command not available", NULL_PARG); 1427191930Sdelphij break; 1428191930Sdelphij#endif 1429191930Sdelphij 143060786Sps case A_AGAIN_SEARCH: 143160786Sps /* 143260786Sps * Repeat previous search. 143360786Sps */ 143460786Sps DO_SEARCH(); 143560786Sps break; 143660786Sps 143760786Sps case A_T_AGAIN_SEARCH: 143860786Sps /* 143960786Sps * Repeat previous search, multiple files. 144060786Sps */ 144160786Sps search_type |= SRCH_PAST_EOF; 144260786Sps DO_SEARCH(); 144360786Sps break; 144460786Sps 144560786Sps case A_REVERSE_SEARCH: 144660786Sps /* 144760786Sps * Repeat previous search, in reverse direction. 144860786Sps */ 144960786Sps save_search_type = search_type; 145060786Sps search_type = SRCH_REVERSE(search_type); 145160786Sps DO_SEARCH(); 145260786Sps search_type = save_search_type; 145360786Sps break; 145460786Sps 145560786Sps case A_T_REVERSE_SEARCH: 145660786Sps /* 145760786Sps * Repeat previous search, 145860786Sps * multiple files in reverse direction. 145960786Sps */ 146060786Sps save_search_type = search_type; 146160786Sps search_type = SRCH_REVERSE(search_type); 146260786Sps search_type |= SRCH_PAST_EOF; 146360786Sps DO_SEARCH(); 146460786Sps search_type = save_search_type; 146560786Sps break; 146660786Sps 146760786Sps case A_UNDO_SEARCH: 146860786Sps undo_search(); 146960786Sps break; 147060786Sps 147160786Sps case A_HELP: 147260786Sps /* 147360786Sps * Help. 147460786Sps */ 147560786Sps if (ch_getflags() & CH_HELPFILE) 147660786Sps break; 147760786Sps cmd_exec(); 1478161478Sdelphij save_hshift = hshift; 1479161478Sdelphij hshift = 0; 148060786Sps (void) edit(FAKE_HELPFILE); 148160786Sps break; 148260786Sps 148360786Sps case A_EXAMINE: 148460786Sps#if EXAMINE 148560786Sps /* 148660786Sps * Edit a new file. Get the filename. 148760786Sps */ 148860786Sps if (secure) 148960786Sps { 149060786Sps error("Command not available", NULL_PARG); 149160786Sps break; 149260786Sps } 149360786Sps start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); 149460786Sps c = getcc(); 149560786Sps goto again; 149660786Sps#else 149760786Sps error("Command not available", NULL_PARG); 149860786Sps break; 149960786Sps#endif 150060786Sps 150160786Sps case A_VISUAL: 150260786Sps /* 150360786Sps * Invoke an editor on the input file. 150460786Sps */ 150560786Sps#if EDITOR 150660786Sps if (secure) 150760786Sps { 150860786Sps error("Command not available", NULL_PARG); 150960786Sps break; 151060786Sps } 151160786Sps if (ch_getflags() & CH_HELPFILE) 151260786Sps break; 151360786Sps if (strcmp(get_filename(curr_ifile), "-") == 0) 151460786Sps { 151560786Sps error("Cannot edit standard input", NULL_PARG); 151660786Sps break; 151760786Sps } 151860786Sps if (curr_altfilename != NULL) 151960786Sps { 1520161478Sdelphij error("WARNING: This file was viewed via LESSOPEN", 152160786Sps NULL_PARG); 152260786Sps } 152360786Sps start_mca(A_SHELL, "!", ml_shell, 0); 152460786Sps /* 152560786Sps * Expand the editor prototype string 152660786Sps * and pass it to the system to execute. 152760786Sps * (Make sure the screen is displayed so the 152860786Sps * expansion of "+%lm" works.) 152960786Sps */ 153060786Sps make_display(); 153160786Sps cmd_exec(); 153260786Sps lsystem(pr_expand(editproto, 0), (char*)NULL); 153360786Sps break; 153460786Sps#else 153560786Sps error("Command not available", NULL_PARG); 153660786Sps break; 153760786Sps#endif 153860786Sps 153960786Sps case A_NEXT_FILE: 154060786Sps /* 154160786Sps * Examine next file. 154260786Sps */ 1543128348Stjr#if TAGS 154489022Sps if (ntags()) 154589022Sps { 154689022Sps error("No next file", NULL_PARG); 154789022Sps break; 154889022Sps } 1549128348Stjr#endif 155060786Sps if (number <= 0) 155160786Sps number = 1; 1552128348Stjr if (edit_next((int) number)) 155360786Sps { 1554191930Sdelphij if (get_quit_at_eof() && eof_displayed() && 155560786Sps !(ch_getflags() & CH_HELPFILE)) 155660786Sps quit(QUIT_OK); 155760786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 155860786Sps error("No %snext file", &parg); 155960786Sps } 156060786Sps break; 156160786Sps 156260786Sps case A_PREV_FILE: 156360786Sps /* 156460786Sps * Examine previous file. 156560786Sps */ 1566128348Stjr#if TAGS 156789022Sps if (ntags()) 156889022Sps { 156989022Sps error("No previous file", NULL_PARG); 157089022Sps break; 157189022Sps } 1572128348Stjr#endif 157360786Sps if (number <= 0) 157460786Sps number = 1; 1575128348Stjr if (edit_prev((int) number)) 157660786Sps { 157760786Sps parg.p_string = (number > 1) ? "(N-th) " : ""; 157860786Sps error("No %sprevious file", &parg); 157960786Sps } 158060786Sps break; 158160786Sps 158289022Sps case A_NEXT_TAG: 1583128348Stjr#if TAGS 158489022Sps if (number <= 0) 158589022Sps number = 1; 1586128348Stjr tagfile = nexttag((int) number); 158789022Sps if (tagfile == NULL) 158889022Sps { 158989022Sps error("No next tag", NULL_PARG); 159089022Sps break; 159189022Sps } 159289022Sps if (edit(tagfile) == 0) 159389022Sps { 159489022Sps POSITION pos = tagsearch(); 159589022Sps if (pos != NULL_POSITION) 159689022Sps jump_loc(pos, jump_sline); 159789022Sps } 1598128348Stjr#else 1599128348Stjr error("Command not available", NULL_PARG); 1600128348Stjr#endif 160189022Sps break; 160289022Sps 160389022Sps case A_PREV_TAG: 1604128348Stjr#if TAGS 160589022Sps if (number <= 0) 160689022Sps number = 1; 1607128348Stjr tagfile = prevtag((int) number); 160889022Sps if (tagfile == NULL) 160989022Sps { 161089022Sps error("No previous tag", NULL_PARG); 161189022Sps break; 161289022Sps } 161389022Sps if (edit(tagfile) == 0) 161489022Sps { 161589022Sps POSITION pos = tagsearch(); 161689022Sps if (pos != NULL_POSITION) 161789022Sps jump_loc(pos, jump_sline); 161889022Sps } 1619128348Stjr#else 1620128348Stjr error("Command not available", NULL_PARG); 1621128348Stjr#endif 162289022Sps break; 162389022Sps 162460786Sps case A_INDEX_FILE: 162560786Sps /* 162660786Sps * Examine a particular file. 162760786Sps */ 162860786Sps if (number <= 0) 162960786Sps number = 1; 1630128348Stjr if (edit_index((int) number)) 163160786Sps error("No such file", NULL_PARG); 163260786Sps break; 163360786Sps 163460786Sps case A_REMOVE_FILE: 163560786Sps if (ch_getflags() & CH_HELPFILE) 163660786Sps break; 163760786Sps old_ifile = curr_ifile; 163860786Sps new_ifile = getoff_ifile(curr_ifile); 163960786Sps if (new_ifile == NULL_IFILE) 164060786Sps { 164160786Sps bell(); 164260786Sps break; 164360786Sps } 164460786Sps if (edit_ifile(new_ifile) != 0) 164560786Sps { 164660786Sps reedit_ifile(old_ifile); 164760786Sps break; 164860786Sps } 164960786Sps del_ifile(old_ifile); 165060786Sps break; 165160786Sps 165260786Sps case A_OPT_TOGGLE: 165360786Sps optflag = OPT_TOGGLE; 165460786Sps optgetname = FALSE; 165560786Sps mca_opt_toggle(); 165660786Sps c = getcc(); 165760786Sps goto again; 165860786Sps 165960786Sps case A_DISP_OPTION: 166060786Sps /* 166160786Sps * Report a flag setting. 166260786Sps */ 166360786Sps optflag = OPT_NO_TOGGLE; 166460786Sps optgetname = FALSE; 166560786Sps mca_opt_toggle(); 166660786Sps c = getcc(); 166760786Sps goto again; 166860786Sps 166960786Sps case A_FIRSTCMD: 167060786Sps /* 167160786Sps * Set an initial command for new files. 167260786Sps */ 167360786Sps start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); 167460786Sps c = getcc(); 167560786Sps goto again; 167660786Sps 167760786Sps case A_SHELL: 167860786Sps /* 167960786Sps * Shell escape. 168060786Sps */ 168160786Sps#if SHELL_ESCAPE 168260786Sps if (secure) 168360786Sps { 168460786Sps error("Command not available", NULL_PARG); 168560786Sps break; 168660786Sps } 168760786Sps start_mca(A_SHELL, "!", ml_shell, 0); 168860786Sps c = getcc(); 168960786Sps goto again; 169060786Sps#else 169160786Sps error("Command not available", NULL_PARG); 169260786Sps break; 169360786Sps#endif 169460786Sps 169560786Sps case A_SETMARK: 169660786Sps /* 169760786Sps * Set a mark. 169860786Sps */ 169960786Sps if (ch_getflags() & CH_HELPFILE) 170060786Sps break; 170160786Sps start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); 170260786Sps c = getcc(); 1703161478Sdelphij if (c == erase_char || c == erase2_char || 1704161478Sdelphij c == kill_char || c == '\n' || c == '\r') 170560786Sps break; 170660786Sps setmark(c); 170760786Sps break; 170860786Sps 170960786Sps case A_GOMARK: 171060786Sps /* 171160786Sps * Go to a mark. 171260786Sps */ 171360786Sps start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); 171460786Sps c = getcc(); 1715161478Sdelphij if (c == erase_char || c == erase2_char || 1716161478Sdelphij c == kill_char || c == '\n' || c == '\r') 171760786Sps break; 1718191930Sdelphij cmd_exec(); 171960786Sps gomark(c); 172060786Sps break; 172160786Sps 172260786Sps case A_PIPE: 172360786Sps#if PIPEC 172460786Sps if (secure) 172560786Sps { 172660786Sps error("Command not available", NULL_PARG); 172760786Sps break; 172860786Sps } 172960786Sps start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); 173060786Sps c = getcc(); 1731161478Sdelphij if (c == erase_char || c == erase2_char || c == kill_char) 173260786Sps break; 173360786Sps if (c == '\n' || c == '\r') 173460786Sps c = '.'; 173560786Sps if (badmark(c)) 173660786Sps break; 173760786Sps pipec = c; 173860786Sps start_mca(A_PIPE, "!", ml_shell, 0); 173960786Sps c = getcc(); 174060786Sps goto again; 174160786Sps#else 174260786Sps error("Command not available", NULL_PARG); 174360786Sps break; 174460786Sps#endif 174560786Sps 174660786Sps case A_B_BRACKET: 174760786Sps case A_F_BRACKET: 174860786Sps start_mca(action, "Brackets: ", (void*)NULL, 0); 174960786Sps c = getcc(); 175060786Sps goto again; 175160786Sps 175260786Sps case A_LSHIFT: 175389022Sps if (number > 0) 175489022Sps shift_count = number; 175589022Sps else 175663131Sps number = (shift_count > 0) ? 175763131Sps shift_count : sc_width / 2; 175860786Sps if (number > hshift) 175960786Sps number = hshift; 176060786Sps hshift -= number; 176160786Sps screen_trashed = 1; 176260786Sps break; 176360786Sps 176460786Sps case A_RSHIFT: 176589022Sps if (number > 0) 176689022Sps shift_count = number; 176789022Sps else 176863131Sps number = (shift_count > 0) ? 176963131Sps shift_count : sc_width / 2; 177060786Sps hshift += number; 177160786Sps screen_trashed = 1; 177260786Sps break; 177360786Sps 177460786Sps case A_PREFIX: 177560786Sps /* 177660786Sps * The command is incomplete (more chars are needed). 177760786Sps * Display the current char, so the user knows 177860786Sps * what's going on, and get another character. 177960786Sps */ 178060786Sps if (mca != A_PREFIX) 178160786Sps { 178260786Sps cmd_reset(); 178360786Sps start_mca(A_PREFIX, " ", (void*)NULL, 178460786Sps CF_QUIT_ON_ERASE); 178560786Sps (void) cmd_char(c); 178660786Sps } 178760786Sps c = getcc(); 178860786Sps goto again; 178960786Sps 179060786Sps case A_NOACTION: 179160786Sps break; 179260786Sps 179360786Sps default: 179460786Sps bell(); 179560786Sps break; 179660786Sps } 179760786Sps } 179860786Sps} 1799