From nobody Mon Dec 09 06:53:09 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Y6CHT4pSlz5gLXr; Mon, 09 Dec 2024 06:53:09 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Y6CHT4TLHz4PVJ; Mon, 9 Dec 2024 06:53:09 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733727189; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qU/KqFXSkux0YeN5uzDz0WfkqzOGoCH29E2eReuPNWk=; b=Kk5QB6n9l1L+a0x6HtGfE3Lf1wHy63cS24fIgYoaI65ntlYSGaIhHT4qvzEMGnmwIjZ2Ay YqrXC+253StmBGn15rZyhSdZOsjGlTZbM3Om4X+S7XOyW2w8kwgdoonUkc+Re1ba5VDC7V KuhKOvDP1hxEHd61nQRbWGbNzvF5z2RA10l6Lcb2eUe+Plc6GxWqMGTz+4uGfRloPrxrcp KzOXE7rWuRus6dOwIqh1tNPdc6tlZ4IXHvDpxv5Gtb0lFaMSwFD98TSR8vjPeggzAaDCkv BK8UP2tM6aLEZqbbV853LihmVUgqU0WUldufBtnfRhBniMaChusMasccFnVktA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733727189; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=qU/KqFXSkux0YeN5uzDz0WfkqzOGoCH29E2eReuPNWk=; b=NA2y4ZoeAIve5MB5lQ42z7+nBIayH4cq26OeyVw8/GrBFaeZ2oICPt72gG12nZOGZi6osc F/1vi/mhEYc3s3++9lq1/Axivr97MQ567VEtrb6QswowhITqu2NxkpcgDExCTqwmeyeynn bYjr35JM63lBKHs/35u1P1D2BgkDzSFXU9OaMNVfbKMIFQfHjPyYs3Q0X7/7COJ5qzGDUR wcvroaJzrGhrgRBxg6VmLcf8KbrIUgQBsov2UomQosgGIn0fJFMCJSChyyGYY1MsbdROgK 516cF5HbY6raro7zHr3hNIDAPhpak1XjBtBXjCiDxohJjW+vlMQwsqDiLIPRXQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1733727189; a=rsa-sha256; cv=none; b=Z7LSWSefm/f5GlhF9lS3yjzTXy7IOv/+H85ujgFYY7YWCxfXuAcI4O+LxEuq3JK0tgDhYz z8hfQWvyNJ4RXAJO6AHxC67K7vuso0AMbtW5rayMLiUfTdyzm9Dw237AI7eusjJn9iEXsB Rb0nyDk3Xf7fkbEowyTf8WhOgkP2hpPAoO9HGPffzPFYxiOyG3nXf/yny4LmvRONS+c4K9 5FZmPijzeDiPJs6fOIv+8uRh3bMOmLv9VxPx1u/Ef8s54xr5tjXdZ9rVshFIEOMQiIHUFQ WX019/EbTuybKQ/ZMbr6GvCye/SZCQyY6DhD05qgdrItQiK2jpRSnR85inkzQg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Y6CHT44cWzS16; Mon, 9 Dec 2024 06:53:09 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4B96r9rv072601; Mon, 9 Dec 2024 06:53:09 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4B96r9Ef072598; Mon, 9 Dec 2024 06:53:09 GMT (envelope-from git) Date: Mon, 9 Dec 2024 06:53:09 GMT Message-Id: <202412090653.4B96r9Ef072598@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Xin LI Subject: git: c77c48892655 - main - MFV: less v668. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: delphij X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c77c488926555ca344ae3a417544cf7a720e1de1 Auto-Submitted: auto-generated The branch main has been updated by delphij: URL: https://cgit.FreeBSD.org/src/commit/?id=c77c488926555ca344ae3a417544cf7a720e1de1 commit c77c488926555ca344ae3a417544cf7a720e1de1 Merge: 908f215e80fa 8c9fd1007159 Author: Xin LI AuthorDate: 2024-12-09 04:50:00 +0000 Commit: Xin LI CommitDate: 2024-12-09 05:22:12 +0000 MFV: less v668. MFC after: 2 weeks contrib/less/LICENSE | 2 +- contrib/less/NEWS | 134 ++++++++ contrib/less/brac.c | 2 +- contrib/less/ch.c | 131 ++++---- contrib/less/charset.c | 181 +++++----- contrib/less/charset.h | 2 +- contrib/less/cmd.h | 6 +- contrib/less/cmdbuf.c | 217 ++++++------ contrib/less/command.c | 392 ++++++++++++++-------- contrib/less/compose.uni | 2 +- contrib/less/cvt.c | 33 +- contrib/less/decode.c | 376 +++++++++++++++------ contrib/less/edit.c | 362 ++++++++++---------- contrib/less/evar.c | 192 +++++++++++ contrib/less/filename.c | 430 ++++++++++++------------ contrib/less/fmt.uni | 2 +- contrib/less/forwback.c | 84 +++-- contrib/less/funcs.h | 387 ++++++++++++---------- contrib/less/help.c | 54 +-- contrib/less/ifile.c | 18 +- contrib/less/input.c | 109 +++--- contrib/less/jump.c | 51 ++- contrib/less/lang.h | 57 ++++ contrib/less/less.h | 125 ++++--- contrib/less/less.hlp | 52 ++- contrib/less/less.nro | 389 +++++++++++++++++----- contrib/less/lessecho.c | 15 +- contrib/less/lessecho.nro | 6 +- contrib/less/lesskey.c | 73 ++-- contrib/less/lesskey.h | 24 +- contrib/less/lesskey.nro | 38 ++- contrib/less/lesskey_parse.c | 114 +++++-- contrib/less/lglob.h | 2 +- contrib/less/line.c | 440 ++++++++++++++++-------- contrib/less/linenum.c | 83 +++-- contrib/less/lsystem.c | 17 +- contrib/less/main.c | 272 ++++++++++++--- contrib/less/mark.c | 36 +- contrib/less/optfunc.c | 533 ++++++++++++++++++----------- contrib/less/option.c | 262 ++++++++++----- contrib/less/option.h | 9 +- contrib/less/opttbl.c | 113 ++++--- contrib/less/os.c | 64 ++-- contrib/less/output.c | 501 ++++++++++++++++------------ contrib/less/pattern.c | 40 +-- contrib/less/pattern.h | 6 +- contrib/less/pckeys.h | 2 +- contrib/less/position.c | 70 +++- contrib/less/position.h | 2 +- contrib/less/prompt.c | 112 ++++--- contrib/less/regexp.c | 120 +++---- contrib/less/regexp.h | 14 +- contrib/less/screen.c | 744 ++++++++++++++++++++++++++--------------- contrib/less/scrsize.c | 2 +- contrib/less/search.c | 774 +++++++++++++++++++++++++++++++++++++------ contrib/less/signal.c | 22 +- contrib/less/tags.c | 79 ++--- contrib/less/ttyin.c | 47 ++- contrib/less/ubin.uni | 2 +- contrib/less/version.c | 47 ++- contrib/less/wide.uni | 6 +- contrib/less/xbuf.c | 64 +++- contrib/less/xbuf.h | 13 +- usr.bin/less/Makefile | 2 +- usr.bin/less/defines.h | 62 ++-- 65 files changed, 5718 insertions(+), 2904 deletions(-) diff --cc contrib/less/command.c index c1003d55fada,000000000000..27eba082e520 mode 100644,000000..100644 --- a/contrib/less/command.c +++ b/contrib/less/command.c @@@ -1,2096 -1,0 +1,2226 @@@ +/* $FreeBSD$ */ +/* - * Copyright (C) 1984-2023 Mark Nudelman ++ * Copyright (C) 1984-2024 Mark Nudelman + * + * You may distribute under the terms of either the GNU General Public + * License or the Less License, as specified in the README file. + * + * For more information, see the README file. + */ + + +/* + * User-level command processor. + */ + +#include "less.h" +#if MSDOS_COMPILER==WIN32C +#include +#endif +#include "position.h" +#include "option.h" +#include "cmd.h" + +extern int erase_char, erase2_char, kill_char; +extern int sigs; +extern int quit_if_one_screen; +extern int one_screen; - extern int squished; +extern int sc_width; +extern int sc_height; +extern char *kent; +extern int swindow; +extern int jump_sline; +extern int quitting; +extern int wscroll; +extern int top_scroll; +extern int ignore_eoi; - extern int secure; +extern int hshift; +extern int bs_mode; +extern int proc_backspace; +extern int show_attn; +extern int less_is_more; - extern int status_col; +extern POSITION highest_hilite; - extern POSITION start_attnpos; - extern POSITION end_attnpos; +extern char *every_first_cmd; +extern char version[]; +extern struct scrpos initial_scrpos; +extern IFILE curr_ifile; +extern void *ml_search; +extern void *ml_examine; +extern int wheel_lines; - extern int header_lines; +extern int def_search_type; - extern int updown_match; ++extern lbool search_wrapped; +#if SHELL_ESCAPE || PIPEC +extern void *ml_shell; +#endif +#if EDITOR - extern char *editor; - extern char *editproto; ++extern constant char *editproto; ++#endif ++#if OSC8_LINK ++extern char *osc8_uri; +#endif - extern int screen_trashed; /* The screen has been overwritten */ +extern int shift_count; - extern int oldbot; +extern int forw_prompt; +extern int incr_search; +extern int full_screen; +#if MSDOS_COMPILER==WIN32C +extern int utf_mode; ++extern unsigned less_acp; +#endif + +#if SHELL_ESCAPE +static char *shellcmd = NULL; /* For holding last shell command for "!!" */ +#endif +static int mca; /* The multicharacter command (action) */ +static int search_type; /* The previous type of search */ +static int last_search_type; /* Type of last executed search */ +static LINENUM number; /* The number typed by the user */ +static long fraction; /* The fractional part of the number */ +static struct loption *curropt; +static int opt_lower; +static int optflag; - static int optgetname; ++static lbool optgetname; +static POSITION bottompos; +static int save_hshift; +static int save_bs_mode; +static int save_proc_backspace; ++static int screen_trashed_value = 0; ++static lbool literal_char = FALSE; +#if PIPEC +static char pipec; +#endif + +/* Stack of ungotten chars (via ungetcc) */ +struct ungot { + struct ungot *ug_next; - LWCHAR ug_char; ++ char ug_char; ++ lbool ug_end_command; +}; +static struct ungot* ungot = NULL; + - static void multi_search (char *pattern, int n, int silent); ++static void multi_search(constant char *pattern, int n, int silent); + +/* + * Move the cursor to start of prompt line before executing a command. + * This looks nicer if the command takes a long time before + * updating the screen. + */ +static void cmd_exec(void) +{ + clear_attn(); + clear_bot(); + flush(); +} + +/* + * Indicate we are reading a multi-character command. + */ +static void set_mca(int action) +{ + mca = action; + clear_bot(); + clear_cmd(); +} + +/* + * Indicate we are not reading a multi-character command. + */ +static void clear_mca(void) +{ + if (mca == 0) + return; + mca = 0; +} + +/* + * Set up the display to start a new multi-character command. + */ +static void start_mca(int action, constant char *prompt, void *mlist, int cmdflags) +{ + set_mca(action); + cmd_putstr(prompt); + set_mlist(mlist, cmdflags); +} + +public int in_mca(void) +{ + return (mca != 0 && mca != A_PREFIX); +} + +/* + * Set up the display to start a new search command. + */ +static void mca_search1(void) +{ + int i; + +#if HILITE_SEARCH + if (search_type & SRCH_FILTER) + set_mca(A_FILTER); + else +#endif + if (search_type & SRCH_FORW) + set_mca(A_F_SEARCH); + else + set_mca(A_B_SEARCH); + + if (search_type & SRCH_NO_MATCH) + cmd_putstr("Non-match "); + if (search_type & SRCH_FIRST_FILE) + cmd_putstr("First-file "); + if (search_type & SRCH_PAST_EOF) + cmd_putstr("EOF-ignore "); + if (search_type & SRCH_NO_MOVE) + cmd_putstr("Keep-pos "); + if (search_type & SRCH_NO_REGEX) + cmd_putstr("Regex-off "); + if (search_type & SRCH_WRAP) + cmd_putstr("Wrap "); + for (i = 1; i <= NUM_SEARCH_COLORS; i++) + { + if (search_type & SRCH_SUBSEARCH(i)) + { + char buf[INT_STRLEN_BOUND(int)+8]; + SNPRINTF1(buf, sizeof(buf), "Sub-%d ", i); + cmd_putstr(buf); + } + } ++ if (literal_char) ++ cmd_putstr("Lit "); + +#if HILITE_SEARCH + if (search_type & SRCH_FILTER) + cmd_putstr("&/"); + else +#endif + if (search_type & SRCH_FORW) + cmd_putstr("/"); + else + cmd_putstr("?"); + forw_prompt = 0; +} + +static void mca_search(void) +{ + mca_search1(); + set_mlist(ml_search, 0); +} + +/* + * Set up the display to start a new toggle-option command. + */ +static void mca_opt_toggle(void) +{ - int no_prompt; - int flag; - char *dash; ++ int no_prompt = (optflag & OPT_NO_PROMPT); ++ int flag = (optflag & ~OPT_NO_PROMPT); ++ constant char *dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; + - no_prompt = (optflag & OPT_NO_PROMPT); - flag = (optflag & ~OPT_NO_PROMPT); - dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; - + set_mca(A_OPT_TOGGLE); + cmd_putstr(dash); + if (optgetname) + cmd_putstr(dash); + if (no_prompt) + cmd_putstr("(P)"); + switch (flag) + { + case OPT_UNSET: + cmd_putstr("+"); + break; + case OPT_SET: + cmd_putstr("!"); + break; + } + forw_prompt = 0; + set_mlist(NULL, 0); +} + +/* + * Execute a multicharacter command. + */ +static void exec_mca(void) +{ - char *cbuf; ++ constant char *cbuf; ++ char *p; + + cmd_exec(); + cbuf = get_cmdbuf(); + if (cbuf == NULL) + return; + + switch (mca) + { + case A_F_SEARCH: + case A_B_SEARCH: + multi_search(cbuf, (int) number, 0); + break; +#if HILITE_SEARCH + case A_FILTER: + search_type ^= SRCH_NO_MATCH; + set_filter_pattern(cbuf, search_type); + break; +#endif + case A_FIRSTCMD: + /* + * Skip leading spaces or + signs in the string. + */ + while (*cbuf == '+' || *cbuf == ' ') + cbuf++; + if (every_first_cmd != NULL) + free(every_first_cmd); + if (*cbuf == '\0') + every_first_cmd = NULL; + else + every_first_cmd = save(cbuf); + break; + case A_OPT_TOGGLE: + toggle_option(curropt, opt_lower, cbuf, optflag); + curropt = NULL; + break; + case A_F_BRACKET: + match_brac(cbuf[0], cbuf[1], 1, (int) number); + break; + case A_B_BRACKET: + match_brac(cbuf[1], cbuf[0], 0, (int) number); + break; +#if EXAMINE + case A_EXAMINE: - if (secure) ++ if (!secure_allow(SF_EXAMINE)) + break; - edit_list(cbuf); ++ p = save(cbuf); ++ edit_list(p); ++ free(p); +#if TAGS + /* If tag structure is loaded then clean it up. */ + cleantags(); +#endif + break; +#endif +#if SHELL_ESCAPE - case A_SHELL: ++ case A_SHELL: { + /* + * !! just uses whatever is in shellcmd. + * Otherwise, copy cmdbuf to shellcmd, + * expanding any special characters ("%" or "#"). + */ ++ constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "!done"; ++ if (done_msg == NULL) ++ ++cbuf; + if (*cbuf != '!') + { + if (shellcmd != NULL) + free(shellcmd); + shellcmd = fexpand(cbuf); + } - - if (secure) ++ if (!secure_allow(SF_SHELL)) + break; + if (shellcmd == NULL) - lsystem("", "!done"); - else - lsystem(shellcmd, "!done"); - break; - case A_PSHELL: - if (secure) ++ shellcmd = ""; ++ lsystem(shellcmd, done_msg); ++ break; } ++ case A_PSHELL: { ++ constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "#done"; ++ if (done_msg == NULL) ++ ++cbuf; ++ if (!secure_allow(SF_SHELL)) + break; - lsystem(pr_expand(cbuf), "#done"); - break; ++ lsystem(pr_expand(cbuf), done_msg); ++ break; } +#endif +#if PIPEC - case A_PIPE: - if (secure) ++ case A_PIPE: { ++ constant char *done_msg = (*cbuf == CONTROL('P')) ? NULL : "|done"; ++ if (done_msg == NULL) ++ ++cbuf; ++ if (!secure_allow(SF_PIPE)) + break; + (void) pipe_mark(pipec, cbuf); - error("|done", NULL_PARG); - break; ++ if (done_msg != NULL) ++ error(done_msg, NULL_PARG); ++ break; } +#endif + } +} + +/* + * Is a character an erase or kill char? + */ - static int is_erase_char(int c) ++static lbool is_erase_char(char c) +{ + return (c == erase_char || c == erase2_char || c == kill_char); +} + +/* + * Is a character a carriage return or newline? + */ - static int is_newline_char(int c) ++static lbool is_newline_char(char c) +{ + return (c == '\n' || c == '\r'); +} + +/* + * Handle the first char of an option (after the initial dash). + */ - static int mca_opt_first_char(int c) ++static int mca_opt_first_char(char c) +{ + int no_prompt = (optflag & OPT_NO_PROMPT); + int flag = (optflag & ~OPT_NO_PROMPT); + if (flag == OPT_NO_TOGGLE) + { + switch (c) + { + case '_': + /* "__" = long option name. */ + optgetname = TRUE; + mca_opt_toggle(); + return (MCA_MORE); + } + } else + { + switch (c) + { + case '+': + /* "-+" = UNSET. */ + optflag = no_prompt | ((flag == OPT_UNSET) ? + OPT_TOGGLE : OPT_UNSET); + mca_opt_toggle(); + return (MCA_MORE); + case '!': + /* "-!" = SET */ + optflag = no_prompt | ((flag == OPT_SET) ? + OPT_TOGGLE : OPT_SET); + mca_opt_toggle(); + return (MCA_MORE); + case CONTROL('P'): + optflag ^= OPT_NO_PROMPT; + mca_opt_toggle(); + return (MCA_MORE); + case '-': + /* "--" = long option name. */ + optgetname = TRUE; + mca_opt_toggle(); + return (MCA_MORE); + } + } + /* Char was not handled here. */ + return (NO_MCA); +} + +/* + * Add a char to a long option name. + * See if we've got a match for an option name yet. + * If so, display the complete name and stop + * accepting chars until user hits RETURN. + */ - static int mca_opt_nonfirst_char(int c) ++static int mca_opt_nonfirst_char(char c) +{ - char *p; - char *oname; - int err; ++ constant char *p; ++ constant char *oname; ++ lbool ambig; + + if (curropt != NULL) + { + /* + * Already have a match for the name. + * Don't accept anything but erase/kill. + */ + if (is_erase_char(c)) + return (MCA_DONE); + return (MCA_MORE); + } + /* + * Add char to cmd buffer and try to match + * the option name. + */ + if (cmd_char(c) == CC_QUIT) + return (MCA_DONE); + p = get_cmdbuf(); + if (p == NULL) + return (MCA_MORE); + opt_lower = ASCII_IS_LOWER(p[0]); - err = 0; - curropt = findopt_name(&p, &oname, &err); ++ curropt = findopt_name(&p, &oname, &ambig); + if (curropt != NULL) + { + /* + * Got a match. + * Remember the option and + * display the full option name. + */ + cmd_reset(); + mca_opt_toggle(); + for (p = oname; *p != '\0'; p++) + { + c = *p; + if (!opt_lower && ASCII_IS_LOWER(c)) + c = ASCII_TO_UPPER(c); + if (cmd_char(c) != CC_OK) + return (MCA_DONE); + } - } else if (err != OPT_AMBIG) ++ } else if (!ambig) + { + bell(); + } + return (MCA_MORE); +} + +/* + * Handle a char of an option toggle command. + */ - static int mca_opt_char(int c) ++static int mca_opt_char(char c) +{ + PARG parg; + + /* + * This may be a short option (single char), + * or one char of a long option name, + * or one char of the option parameter. + */ + if (curropt == NULL && len_cmdbuf() == 0) + { + int ret = mca_opt_first_char(c); + if (ret != NO_MCA) + return (ret); + } + if (optgetname) + { + /* We're getting a long option name. */ + if (!is_newline_char(c) && c != '=') + return (mca_opt_nonfirst_char(c)); + if (curropt == NULL) + { + parg.p_string = get_cmdbuf(); + if (parg.p_string == NULL) + return (MCA_MORE); + error("There is no --%s option", &parg); + return (MCA_DONE); + } + optgetname = FALSE; + cmd_reset(); + } else + { + if (is_erase_char(c)) + return (NO_MCA); + if (curropt != NULL) + /* We're getting the option parameter. */ + return (NO_MCA); + curropt = findopt(c); + if (curropt == NULL) + { + parg.p_string = propt(c); + error("There is no %s option", &parg); + return (MCA_DONE); + } + opt_lower = ASCII_IS_LOWER(c); + } + /* + * If the option which was entered does not take a + * parameter, toggle the option immediately, + * so user doesn't have to hit RETURN. + */ + if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || + !opt_has_param(curropt)) + { + toggle_option(curropt, opt_lower, "", optflag); + return (MCA_DONE); + } + /* + * Display a prompt appropriate for the option parameter. + */ - start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0); ++ start_mca(A_OPT_TOGGLE, opt_prompt(curropt), NULL, 0); + return (MCA_MORE); +} + +/* + * Normalize search type. + */ +public int norm_search_type(int st) +{ + /* WRAP and PAST_EOF are mutually exclusive. */ + if ((st & (SRCH_PAST_EOF|SRCH_WRAP)) == (SRCH_PAST_EOF|SRCH_WRAP)) + st ^= SRCH_PAST_EOF; + return st; +} + +/* + * Handle a char of a search command. + */ - static int mca_search_char(int c) ++static int mca_search_char(char c) +{ + int flag = 0; + + /* + * Certain characters as the first char of + * the pattern have special meaning: + * ! Toggle the NO_MATCH flag + * * Toggle the PAST_EOF flag + * @ Toggle the FIRST_FILE flag + */ - if (len_cmdbuf() > 0) ++ if (len_cmdbuf() > 0 || literal_char) ++ { ++ literal_char = FALSE; + return (NO_MCA); ++ } + + switch (c) + { + case '*': + if (less_is_more) + break; + case CONTROL('E'): /* ignore END of file */ + if (mca != A_FILTER) + flag = SRCH_PAST_EOF; + search_type &= ~SRCH_WRAP; + break; + case '@': + if (less_is_more) + break; + case CONTROL('F'): /* FIRST file */ + if (mca != A_FILTER) + flag = SRCH_FIRST_FILE; + break; + case CONTROL('K'): /* KEEP position */ + if (mca != A_FILTER) + flag = SRCH_NO_MOVE; + break; + case CONTROL('S'): { /* SUBSEARCH */ + char buf[INT_STRLEN_BOUND(int)+24]; + SNPRINTF1(buf, sizeof(buf), "Sub-pattern (1-%d):", NUM_SEARCH_COLORS); + clear_bot(); + cmd_putstr(buf); + flush(); + c = getcc(); + if (c >= '1' && c <= '0'+NUM_SEARCH_COLORS) + flag = SRCH_SUBSEARCH(c-'0'); + else + flag = -1; /* calls mca_search() below to repaint */ + break; } + case CONTROL('W'): /* WRAP around */ + if (mca != A_FILTER) + flag = SRCH_WRAP; + break; + case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ + flag = SRCH_NO_REGEX; + break; + case CONTROL('N'): /* NOT match */ + case '!': + flag = SRCH_NO_MATCH; + break; ++ case CONTROL('L'): ++ literal_char = TRUE; ++ flag = -1; ++ break; + } + + if (flag != 0) + { + if (flag != -1) + search_type = norm_search_type(search_type ^ flag); + mca_search(); + return (MCA_MORE); + } + return (NO_MCA); +} + +/* + * Handle a character of a multi-character command. + */ - static int mca_char(int c) ++static int mca_char(char c) +{ + int ret; + + switch (mca) + { + case 0: + /* + * We're not in a multicharacter command. + */ + return (NO_MCA); + + case A_PREFIX: + /* + * In the prefix of a command. + * This not considered a multichar command + * (even tho it uses cmdbuf, etc.). + * It is handled in the commands() switch. + */ + return (NO_MCA); + + case A_DIGIT: + /* + * Entering digits of a number. + * Terminated by a non-digit. + */ + if ((c >= '0' && c <= '9') || c == '.') + break; + switch (editchar(c, ECF_PEEK|ECF_NOHISTORY|ECF_NOCOMPLETE|ECF_NORIGHTLEFT)) + { + case A_NOACTION: + /* + * Ignore this char and get another one. + */ + return (MCA_MORE); + case A_INVALID: + /* + * Not part of the number. + * End the number and treat this char + * as a normal command character. + */ + number = cmd_int(&fraction); + clear_mca(); + cmd_accept(); + return (NO_MCA); + } + break; + + case A_OPT_TOGGLE: + ret = mca_opt_char(c); + if (ret != NO_MCA) + return (ret); + break; + + case A_F_SEARCH: + case A_B_SEARCH: + case A_FILTER: + ret = mca_search_char(c); + if (ret != NO_MCA) + return (ret); + break; + + default: + /* Other multicharacter command. */ + break; + } + + /* + * The multichar command is terminated by a newline. + */ + if (is_newline_char(c)) + { + /* + * Execute the command. + */ + exec_mca(); + return (MCA_DONE); + } + + /* + * Append the char to the command buffer. + */ + if (cmd_char(c) == CC_QUIT) + /* + * Abort the multi-char command. + */ + return (MCA_DONE); + + switch (mca) + { + case A_F_BRACKET: + case A_B_BRACKET: + if (len_cmdbuf() >= 2) + { + /* + * Special case for the bracket-matching commands. + * Execute the command after getting exactly two + * characters from the user. + */ + exec_mca(); + return (MCA_DONE); + } + break; + case A_F_SEARCH: + case A_B_SEARCH: + if (incr_search) + { + /* Incremental search: do a search after every input char. */ + int st = (search_type & (SRCH_FORW|SRCH_BACK|SRCH_NO_MATCH|SRCH_NO_REGEX|SRCH_NO_MOVE|SRCH_WRAP|SRCH_SUBSEARCH_ALL)); - char *pattern = get_cmdbuf(); ++ ssize_t save_updown; ++ constant char *pattern = get_cmdbuf(); + if (pattern == NULL) + return (MCA_MORE); + /* + * Must save updown_match because mca_search + * reinits it. That breaks history scrolling. + * {{ This is ugly. mca_search probably shouldn't call set_mlist. }} + */ - int save_updown_match = updown_match; ++ save_updown = save_updown_match(); + cmd_exec(); + if (*pattern == '\0') + { + /* User has backspaced to an empty pattern. */ + undo_search(1); + } else + { + if (search(st | SRCH_INCR, pattern, 1) != 0) + /* No match, invalid pattern, etc. */ + undo_search(1); + } + /* Redraw the search prompt and search string. */ - if (!full_screen) ++ if (is_screen_trashed() || !full_screen) + { + clear(); + repaint(); + } + mca_search1(); - updown_match = save_updown_match; ++ restore_updown_match(save_updown); + cmd_repaint(NULL); + } + break; + } + + /* + * Need another character. + */ + return (MCA_MORE); +} + +/* + * Discard any buffered file data. + */ +static void clear_buffers(void) +{ + if (!(ch_getflags() & CH_CANSEEK)) + return; + ch_flush(); + clr_linenum(); +#if HILITE_SEARCH + clr_hilite(); +#endif +} + ++public void screen_trashed_num(int trashed) ++{ ++ screen_trashed_value = trashed; ++} ++ ++public void screen_trashed(void) ++{ ++ screen_trashed_num(1); ++} ++ ++public int is_screen_trashed(void) ++{ ++ return screen_trashed_value; ++} ++ +/* + * Make sure the screen is displayed. + */ +static void make_display(void) +{ + /* + * If not full_screen, we can't rely on scrolling to fill the screen. + * We need to clear and repaint screen before any change. + */ + if (!full_screen && !(quit_if_one_screen && one_screen)) + clear(); + /* + * If nothing is displayed yet, display starting from initial_scrpos. + */ + if (empty_screen()) + { + if (initial_scrpos.pos == NULL_POSITION) + jump_loc(ch_zero(), 1); + else + jump_loc(initial_scrpos.pos, initial_scrpos.ln); - } else if (screen_trashed || !full_screen) ++ } else if (is_screen_trashed() || !full_screen) + { + int save_top_scroll = top_scroll; + int save_ignore_eoi = ignore_eoi; + top_scroll = 1; + ignore_eoi = 0; - if (screen_trashed == 2) ++ if (is_screen_trashed() == 2) + { + /* Special case used by ignore_eoi: re-open the input file + * and jump to the end of the file. */ + reopen_curr_ifile(); + jump_forw(); + } + repaint(); + top_scroll = save_top_scroll; + ignore_eoi = save_ignore_eoi; *** 3006 LINES SKIPPED ***