git: 252d6dde57d5 - main - MFV: less v678.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 20 May 2025 03:47:40 UTC
The branch main has been updated by delphij:
URL: https://cgit.FreeBSD.org/src/commit/?id=252d6dde57d5dd0184929d1f8fb65e7713f51c6d
commit 252d6dde57d5dd0184929d1f8fb65e7713f51c6d
Merge: 9b5ddb2accfc 48b0a08b8724
Author: Xin LI <delphij@FreeBSD.org>
AuthorDate: 2025-05-20 03:44:02 +0000
Commit: Xin LI <delphij@FreeBSD.org>
CommitDate: 2025-05-20 03:44:02 +0000
MFV: less v678.
MFC after: 2 weeks
contrib/less/LICENSE | 2 +-
contrib/less/NEWS | 73 ++++++++++
contrib/less/brac.c | 2 +-
contrib/less/ch.c | 55 ++++++--
contrib/less/charset.c | 36 +++--
contrib/less/charset.h | 2 +-
contrib/less/cmd.h | 9 +-
contrib/less/cmdbuf.c | 189 +++++++++++++++++++-------
contrib/less/command.c | 206 ++++++++++++++++++++--------
contrib/less/compose.uni | 19 ++-
contrib/less/cvt.c | 2 +-
contrib/less/decode.c | 315 ++++++++++++++++++++++++-------------------
contrib/less/edit.c | 7 +-
contrib/less/evar.c | 6 +-
contrib/less/filename.c | 6 +-
contrib/less/fmt.uni | 2 +-
contrib/less/forwback.c | 163 +++++++++++-----------
contrib/less/funcs.h | 51 ++++---
contrib/less/help.c | 12 +-
contrib/less/ifile.c | 2 +-
contrib/less/input.c | 48 ++++---
contrib/less/jump.c | 27 ++--
contrib/less/lang.h | 2 +-
contrib/less/less.h | 41 +++---
contrib/less/less.hlp | 10 ++
contrib/less/less.nro | 212 +++++++++++++++++++----------
contrib/less/lessecho.c | 2 +-
contrib/less/lessecho.nro | 6 +-
contrib/less/lesskey.c | 2 +-
contrib/less/lesskey.h | 2 +-
contrib/less/lesskey.nro | 23 +++-
contrib/less/lesskey_parse.c | 9 +-
contrib/less/lglob.h | 2 +-
contrib/less/line.c | 279 +++++++++++++++++++++++++++++---------
contrib/less/linenum.c | 24 ++--
contrib/less/lsystem.c | 2 +-
contrib/less/main.c | 33 +++--
contrib/less/mark.c | 2 +-
contrib/less/mkutable | 7 +-
contrib/less/optfunc.c | 25 +++-
contrib/less/option.c | 80 +++++------
contrib/less/option.h | 26 ++--
contrib/less/opttbl.c | 231 ++++++++++++++++++++-----------
contrib/less/os.c | 115 ++++++++++++----
contrib/less/output.c | 19 +--
contrib/less/pattern.c | 52 ++++---
contrib/less/pattern.h | 2 +-
contrib/less/pckeys.h | 2 +-
contrib/less/position.c | 15 ++-
contrib/less/position.h | 3 +-
contrib/less/prompt.c | 11 +-
contrib/less/screen.c | 120 +++++++++++------
contrib/less/scrsize.c | 2 +-
contrib/less/search.c | 184 ++++++++++---------------
contrib/less/signal.c | 55 ++++++--
contrib/less/tags.c | 2 +-
contrib/less/ttyin.c | 8 +-
contrib/less/ubin.uni | 2 +-
contrib/less/version.c | 19 ++-
contrib/less/wide.uni | 22 +--
usr.bin/less/defines.h | 15 ++-
61 files changed, 1903 insertions(+), 999 deletions(-)
diff --cc contrib/less/command.c
index 27eba082e520,000000000000..3ec1f9b48358
mode 100644,000000..100644
--- a/contrib/less/command.c
+++ b/contrib/less/command.c
@@@ -1,2226 -1,0 +1,2320 @@@
- /* $FreeBSD$ */
+/*
- * Copyright (C) 1984-2024 Mark Nudelman
++ * Copyright (C) 1984-2025 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 <windows.h>
+#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 sc_width;
+extern int sc_height;
+extern char *kent;
+extern int swindow;
+extern int jump_sline;
- extern int quitting;
++extern lbool quitting;
+extern int wscroll;
+extern int top_scroll;
+extern int ignore_eoi;
+extern int hshift;
+extern int bs_mode;
+extern int proc_backspace;
+extern int show_attn;
+extern int less_is_more;
++extern int chopline;
+extern POSITION highest_hilite;
+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 def_search_type;
+extern lbool search_wrapped;
++extern int no_paste;
++extern lbool pasting;
++extern int no_edit_warn;
++extern POSITION soft_eof;
+#if SHELL_ESCAPE || PIPEC
+extern void *ml_shell;
+#endif
+#if EDITOR
+extern constant char *editproto;
+#endif
+#if OSC8_LINK
+extern char *osc8_uri;
+#endif
+extern int shift_count;
+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 lbool opt_lower;
+static int optflag;
+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;
++static lbool ignoring_input = FALSE;
++#if HAVE_TIME
++static time_type ignoring_input_time;
++#endif
+#if PIPEC
+static char pipec;
+#endif
+
+/* Stack of ungotten chars (via ungetcc) */
+struct ungot {
+ struct ungot *ug_next;
+ char ug_char;
+ lbool ug_end_command;
+};
+static struct ungot* ungot = NULL;
+
+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)
++public 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 = (optflag & OPT_NO_PROMPT);
+ int flag = (optflag & ~OPT_NO_PROMPT);
+ constant char *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);
++ set_mlist(NULL, CF_OPTION);
+}
+
+/*
+ * Execute a multicharacter command.
+ */
+static void exec_mca(void)
+{
+ 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);
++ soft_eof = NULL_POSITION;
+ 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:
++ case A_EXAMINE: {
++ char *p;
+ if (!secure_allow(SF_EXAMINE))
+ break;
+ p = save(cbuf);
+ edit_list(p);
+ free(p);
+#if TAGS
+ /* If tag structure is loaded then clean it up. */
+ cleantags();
+#endif
- break;
++ break; }
+#endif
+#if SHELL_ESCAPE
+ 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_allow(SF_SHELL))
+ break;
+ if (shellcmd == NULL)
+ 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_msg);
+ break; }
+#endif
+#if PIPEC
+ 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);
+ if (done_msg != NULL)
+ error(done_msg, NULL_PARG);
+ break; }
+#endif
+ }
+}
+
+/*
+ * Is a character an erase or kill char?
+ */
+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 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(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(char c)
+{
+ constant char *p;
+ constant char *oname;
+ lbool ambig;
++ struct loption *was_curropt;
+
+ if (curropt != NULL)
+ {
- /*
- * Already have a match for the name.
- * Don't accept anything but erase/kill.
- */
++ /* Already have a match for the name. */
+ if (is_erase_char(c))
+ return (MCA_DONE);
- return (MCA_MORE);
++ /* {{ Checking for TAB here is ugly.
++ * Also doesn't extend well -- can't do BACKTAB this way
++ * because it's a multichar sequence. }} */
++ if (c != '\t')
++ 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)
++ if (p == NULL || p[0] == '\0')
+ return (MCA_MORE);
+ opt_lower = ASCII_IS_LOWER(p[0]);
++ was_curropt = curropt;
+ 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++)
++ if (was_curropt == NULL)
+ {
- c = *p;
- if (!opt_lower && ASCII_IS_LOWER(c))
- c = ASCII_TO_UPPER(c);
- if (cmd_char(c) != CC_OK)
- return (MCA_DONE);
++ /*
++ * Got a match.
++ * Remember the option and
++ * display the full option name.
++ */
++ cmd_reset();
++ mca_opt_toggle();
++ cmd_setstring(oname, !opt_lower);
+ }
+ } else if (!ambig)
+ {
+ bell();
+ }
+ return (MCA_MORE);
+}
+
+/*
+ * Handle a char of an option toggle command.
+ */
+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)
++ if (curropt == NULL && cmdbuf_empty())
+ {
+ 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), NULL, 0);
++ start_mca(A_OPT_TOGGLE, opt_prompt(curropt), NULL, CF_OPTION);
+ 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(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 || literal_char)
++ if (!cmdbuf_empty() || 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(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.
- */
++ if (pasting && no_paste)
++ {
++ /* Ignore pasted input after (and including) the first newline */
++ start_ignoring_input();
++ return (MCA_MORE);
++ }
++ /* 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));
+ 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. }}
+ */
+ 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 (is_screen_trashed() || !full_screen)
+ {
+ clear();
+ repaint();
+ }
+ mca_search1();
+ 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 (is_screen_trashed() || !full_screen)
+ {
+ int save_top_scroll = top_scroll;
+ int save_ignore_eoi = ignore_eoi;
+ top_scroll = 1;
+ ignore_eoi = 0;
+ 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;
+ }
+}
+
+/*
+ * Display the appropriate prompt.
+ */
+static void prompt(void)
+{
+ constant char *p;
+
+ if (ungot != NULL && !ungot->ug_end_command)
+ {
+ /*
+ * No prompt necessary if commands are from
+ * ungotten chars rather than from the user.
+ */
+ return;
+ }
+
*** 2968 LINES SKIPPED ***