Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Jun 2025 06:07:25 GMT
From:      Xin LI <delphij@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 47807edf0ac2 - stable/13 - MFC: MFV: less v678.
Message-ID:  <202506100607.55A67Pgk004116@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by delphij:

URL: https://cgit.FreeBSD.org/src/commit/?id=47807edf0ac29cbc6c11c49d6152d740040f387d

commit 47807edf0ac29cbc6c11c49d6152d740040f387d
Author:     Xin LI <delphij@FreeBSD.org>
AuthorDate: 2025-05-20 03:44:02 +0000
Commit:     Xin LI <delphij@FreeBSD.org>
CommitDate: 2025-06-10 06:05:19 +0000

    MFC: MFV: less v678.
    
    (cherry picked from commit 252d6dde57d5dd0184929d1f8fb65e7713f51c6d)
---
 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 --git a/contrib/less/LICENSE b/contrib/less/LICENSE
index d4f3bf6d1ce6..b9b72a3d088b 100644
--- a/contrib/less/LICENSE
+++ b/contrib/less/LICENSE
@@ -2,7 +2,7 @@
                           ------------
 
 Less
-Copyright (C) 1984-2024  Mark Nudelman
+Copyright (C) 1984-2025  Mark Nudelman
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
diff --git a/contrib/less/NEWS b/contrib/less/NEWS
index e869439ea4ee..5767ded21a00 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -9,6 +9,79 @@
   Report bugs, suggestions or comments at 
   https://github.com/gwsw/less/issues.
 
+======================================================================
+
+	Major changes between "less" versions 668 and 678
+
+* Treat -r in LESS environment variable as -R.
+
+* Add ESC-j and ESC-k commands (github #560).
+
+* Add --no-paste option (github #523).
+
+* Add --no-edit-warn option (github #513).
+
+* Add --form-feed option (github #496).
+
+* Add ESC-b command (github #615).
+
+* Make TAB complete option name in -- command (github #531).
+
+* Update the file size on an attempt to go past end of file.
+
+* Make -R able to pass through any OSC escape sequences,
+  not just OSC 8 (github #504).
+
+* Setting LESS_IS_MORE=0 now disables "more" compatibility even
+  if invoked via a file link named "more" (github #500).
+
+* Pass through escape sequences in prompts even if -R is not set.
+
+* Add LESS_SHELL_LINES to support shell prompts which use more than
+  one line (github #514).
+
+* Add LESSANSIOSCALLOW to define OSC types which may be passed through.
+
+* Add LESSANSIOSCCHARS to define non-standard OSC intro chars.
+
+* Add LESS_SIGUSR1 to define user signal handler (github #582).
+
+* Add mouse and mouse6 commands to lesskey (github #569).
+
+* Improve behavior of ^O^N and ^O^P commands.
+
+* Leave stty tabs setting unchanged (github #620).
+
+* Fix unexpected behavior when entering a partial command followed by 
+  a valid command (github #543).
+
+* Fix bug when coloring prompt string with SGR sequences (github #516).
+
+* Fix bug when searching for text near an invalid UTF-8 sequence (github #542).
+
+* Fix display bug when file contains ESC followed by NUL (github #550).
+
+* Fix bug when using +:n +:p +:x or +:d on the command line (github #552).
+
+* Fix bug with --no-number-headers when header is not at start of file
+  (github #566).
+
+* Fix bug where lesstest fails if window is resized (github #570).
+
+* Fix bug using "configure --with-secure=no" (github #584).
+
+* Fix bug using multibyte command chars (github #595).
+
+* Fix auto_wrap setting on Windows (github #497).
+
+* Fix two bugs using ^S search modifier (github #605).
+
+* Fix bug searching for UTF-8 strings with the PCRE2 library (github #610).
+
+* Fix bug highlighting OSC 8 links when opening a new file.
+
+* Fix bug when & filtering is active (github #618).
+
 ======================================================================
 
 	Major changes between "less" versions 661 and 668
diff --git a/contrib/less/brac.c b/contrib/less/brac.c
index 170cd73da516..36f31d0316f4 100644
--- a/contrib/less/brac.c
+++ b/contrib/less/brac.c
@@ -1,5 +1,5 @@
 /*
- * 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.
diff --git a/contrib/less/ch.c b/contrib/less/ch.c
index 336af7792120..870028c73a23 100644
--- a/contrib/less/ch.c
+++ b/contrib/less/ch.c
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -149,10 +149,7 @@ static int ch_get(void)
 	struct buf *bp;
 	struct bufnode *bn;
 	ssize_t n;
-	lbool read_again;
 	int h;
-	POSITION pos;
-	POSITION len;
 
 	if (thisfile == NULL)
 		return (EOI);
@@ -224,12 +221,28 @@ static int ch_get(void)
 
 	for (;;)
 	{
-		pos = ch_position(ch_block, bp->datasize);
+		lbool read_again;
+		POSITION len;
+		POSITION pos = ch_position(ch_block, bp->datasize);
+		lbool read_pipe_at_eof = FALSE;
 		if ((len = ch_length()) != NULL_POSITION && pos >= len)
+		{
 			/*
-			 * At end of file.
+			 * Apparently at end of file.
+			 * Double-check the file size in case it has changed.
 			 */
-			return (EOI);
+			ch_resize();
+			if ((len = ch_length()) != NULL_POSITION && pos >= len)
+			{
+				if (ch_flags & (CH_CANSEEK|CH_HELPFILE))
+					return (EOI);
+				/* ch_length doesn't work for pipes, so just try to
+				 * read from the pipe to see if more data has appeared.
+				 * This can happen only in limited situations, such as
+				 * a fifo that the writer has closed and reopened. */
+				read_pipe_at_eof = TRUE;
+			}
+		}
 
 		if (pos != ch_fpos)
 		{
@@ -271,7 +284,8 @@ static int ch_get(void)
 		read_again = FALSE;
 		if (n == READ_INTR)
 		{
-			ch_fsize = pos;
+			if (ch_flags & CH_CANSEEK)
+				ch_fsize = pos;
 			return (EOI);
 		}
 		if (n == READ_AGAIN)
@@ -304,6 +318,8 @@ static int ch_get(void)
 
 		ch_fpos += n;
 		bp->datasize += (size_t) n;
+		if (read_pipe_at_eof)
+			ch_set_eof(); /* update length of pipe */
 
 		if (n == 0)
 		{
@@ -331,6 +347,9 @@ static int ch_get(void)
 			}
 			if (sigs)
 				return (EOI);
+			if (read_pipe_at_eof)
+				/* No new data; we are still at EOF on the pipe. */
+				return (EOI);
 		}
 
 		found:
@@ -400,6 +419,8 @@ public void end_logfile(void)
 	logfile = -1;
 	free(namelogfile);
 	namelogfile = NULL;
+	putstr("\n");
+	flush();
 }
 
 /*
@@ -412,6 +433,7 @@ public void sync_logfile(void)
 	struct buf *bp;
 	struct bufnode *bn;
 	lbool warned = FALSE;
+	int h;
 	BLOCKNUM block;
 	BLOCKNUM nblocks;
 
@@ -421,7 +443,8 @@ public void sync_logfile(void)
 	for (block = 0;  block < nblocks;  block++)
 	{
 		lbool wrote = FALSE;
-		FOR_BUFS(bn)
+		h = BUFHASH(block);
+		FOR_BUFS_IN_CHAIN(h, bn)
 		{
 			bp = bufnode_buf(bn);
 			if (bp->block == block)
@@ -599,6 +622,20 @@ public POSITION ch_length(void)
 	return (ch_fsize);
 }
 
+/*
+ * Update the file size, in case it has changed.
+ */
+public void ch_resize(void)
+{
+	POSITION fsize;
+
+	if (!(ch_flags & CH_CANSEEK))
+		return;
+	fsize = filesize(ch_file);
+	if (fsize != NULL_POSITION)
+		ch_fsize = fsize;
+}
+
 /*
  * Return the current position in the file.
  */
diff --git a/contrib/less/charset.c b/contrib/less/charset.c
index 3e8fb0fa9354..5e5df2a4e60f 100644
--- a/contrib/less/charset.c
+++ b/contrib/less/charset.c
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -756,24 +756,38 @@ public LWCHAR step_charc(constant char **pp, signed int dir, constant char *limi
 			ch = (LWCHAR) (unsigned char) ((p > limit) ? *--p : 0);
 	} else if (dir > 0)
 	{
-		len = utf_len(*p);
-		if (p + len > limit)
-		{
+		if (p >= limit)
 			ch = 0;
-			p = (char *) limit;
-		} else
+		else 
 		{
-			ch = get_wchar(p);
-			p += len;
+			len = utf_len(*p);
+			if (p + len > limit || !is_utf8_well_formed(p, len))
+			{
+				ch = (LWCHAR) (unsigned char) *p++;
+			} else
+			{
+				ch = get_wchar(p);
+				p += len;
+			}
 		}
 	} else
 	{
 		while (p > limit && IS_UTF8_TRAIL(p[-1]))
 			p--;
-		if (p > limit)
-			ch = get_wchar(--p);
-		else
+		if (p <= limit)
 			ch = 0;
+		else
+		{
+			len = utf_len(*--p);
+			if (p + len != *pp || !is_utf8_well_formed(p, len))
+			{
+				p = *pp - 1;
+				ch = (LWCHAR) (unsigned char) *p;
+			} else
+			{
+				ch = get_wchar(p);
+			}
+		}
 	}
 	*pp = p;
 	return ch;
diff --git a/contrib/less/charset.h b/contrib/less/charset.h
index b5a9067c028b..4acf494b4ed5 100644
--- a/contrib/less/charset.h
+++ b/contrib/less/charset.h
@@ -1,5 +1,5 @@
 /*
- * 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.
diff --git a/contrib/less/cmd.h b/contrib/less/cmd.h
index 0c7218c93e95..07c57b111aee 100644
--- a/contrib/less/cmd.h
+++ b/contrib/less/cmd.h
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -31,6 +31,7 @@
 #define A_HELP                 19
 #define A_NEXT_FILE            20
 #define A_PERCENT              21
+#define A_BF_SCREEN            22
 #define A_PREV_FILE            23
 #define A_QUIT                 24
 #define A_REPAINT              25
@@ -68,6 +69,8 @@
 #define A_GOEND_BUF            57
 #define A_LLSHIFT              58
 #define A_RRSHIFT              59
+#define A_F_NEWLINE            60
+#define A_B_NEWLINE            61
 #define A_CLRMARK              62
 #define A_SETMARKBOT           63
 #define A_X11MOUSE_IN          64
@@ -81,6 +84,8 @@
 #define A_OSC8_B_SEARCH        72
 #define A_OSC8_OPEN            73
 #define A_OSC8_JUMP            74
+#define A_START_PASTE          75 /* must not overlap EC_* */
+#define A_END_PASTE            76 /* must not overlap EC_* */
 
 /* These values must not conflict with any A_* or EC_* value. */
 #define A_INVALID              100
@@ -117,6 +122,8 @@
 #define EC_ABORT               20
 #define EC_X11MOUSE            21
 #define EC_X116MOUSE           22
+#define EC_START_PASTE         A_START_PASTE
+#define EC_END_PASTE           A_END_PASTE
 
 #define EC_UINVALID            102
 
diff --git a/contrib/less/cmdbuf.c b/contrib/less/cmdbuf.c
index 73dd2975b100..f2963cf4c9da 100644
--- a/contrib/less/cmdbuf.c
+++ b/contrib/less/cmdbuf.c
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -24,6 +24,8 @@ extern int sc_width;
 extern int utf_mode;
 extern int no_hist_dups;
 extern int marks_modified;
+extern int no_paste;
+public lbool pasting = FALSE;
 
 static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */
 static int cmd_col;              /* Current column of the cursor */
@@ -34,7 +36,6 @@ static lbool literal;            /* Next input char should not be interpreted */
 static size_t updown_match;      /* Prefix length in up/down movement */
 static lbool have_updown_match = FALSE;
 
-#if TAB_COMPLETE_FILENAME
 static int cmd_complete(int action);
 /*
  * These variables are statics used by cmd_complete.
@@ -45,7 +46,6 @@ static char *tk_original;
 static constant char *tk_ipoint;
 static constant char *tk_trial = NULL;
 static struct textlist tk_tlist;
-#endif
 
 static int cmd_left();
 static int cmd_right();
@@ -182,6 +182,16 @@ public int len_cmdbuf(void)
 	return (len);
 }
 
+/*
+ * Is the command buffer empty?
+ * It is considered nonempty if there is any text in it,
+ * or if a multibyte command is being entered but not yet complete.
+ */
+public lbool cmdbuf_empty(void)
+{
+	return cp == cmdbuf && cmd_mbc_buf_len == 0;
+}
+
 /*
  * Common part of cmd_step_right() and cmd_step_left().
  * {{ Returning pwidth and bswidth separately is a historical artifact
@@ -304,6 +314,16 @@ public void cmd_repaint(constant char *old_cp)
 		cmd_left();
 }
 
+/*
+ * Repaint the entire line, without moving the cursor.
+ */
+static void cmd_repaint_curr(void)
+{
+	char *save_cp = cp;
+	cmd_home();
+	cmd_repaint(save_cp);
+}
+
 /*
  * Shift the cmdbuf display left a half-screen.
  */
@@ -804,17 +824,13 @@ public void cmd_accept(void)
  *      CC_OK   Line edit function done.
  *      CC_QUIT The char requests the current command to be aborted.
  */
-static int cmd_edit(char c)
+static int cmd_edit(char c, lbool stay_in_completion)
 {
 	int action;
 	int flags;
 
-#if TAB_COMPLETE_FILENAME
-#define not_in_completion()     in_completion = 0
-#else
-#define not_in_completion(void)
-#endif
-	
+#define not_in_completion()     do { if (!stay_in_completion) in_completion = FALSE; } while(0)
+
 	/*
 	 * See if the char is indeed a line-editing command.
 	 */
@@ -826,21 +842,35 @@ static int cmd_edit(char c)
 		 */
 		flags |= ECF_NOHISTORY;
 #endif
+
+	/*
+	 * Don't accept completion cmds in contexts 
+	 * such as search pattern, digits, etc.
+	 */
+	if ((curr_mlist == NULL && (curr_cmdflags & CF_OPTION))
 #if TAB_COMPLETE_FILENAME
-	if (curr_mlist == ml_search || curr_mlist == NULL)
-		/*
-		 * Don't accept file-completion cmds in contexts 
-		 * such as search pattern, digits, long option name, etc.
-		 */
-		flags |= ECF_NOCOMPLETE;
+		|| curr_mlist == ml_examine || curr_mlist == ml_shell
 #endif
+		)
+		; /* allow completion */
+	else
+		flags |= ECF_NOCOMPLETE;
 
 	action = editchar(c, flags);
+	if (is_ignoring_input(action))
+		return (CC_OK);
 
 	switch (action)
 	{
 	case A_NOACTION:
 		return (CC_OK);
+	case EC_START_PASTE:
+		if (no_paste)
+			pasting = TRUE;
+		return (CC_OK);
+	case EC_END_PASTE:
+		stop_ignoring_input();
+		return (CC_OK);
 	case EC_RIGHT:
 		not_in_completion();
 		return (cmd_right());
@@ -903,19 +933,16 @@ static int cmd_edit(char c)
 		not_in_completion();
 		return (cmd_updown(action));
 #endif
-#if TAB_COMPLETE_FILENAME
 	case EC_F_COMPLETE:
 	case EC_B_COMPLETE:
 	case EC_EXPAND:
 		return (cmd_complete(action));
-#endif
 	default:
 		not_in_completion();
 		return (CC_PASS);
 	}
 }
 
-#if TAB_COMPLETE_FILENAME
 /*
  * Insert a string into the command buffer, at the current position.
  */
@@ -936,6 +963,18 @@ static int cmd_istr(constant char *str)
 	return (CC_OK);
 }
 
+/*
+ * Set tk_original to word.
+ */
+static void set_tk_original(constant char *word)
+{
+	if (tk_original != NULL)
+		free(tk_original);
+	tk_original = (char *) ecalloc(ptr_diff(cp,word)+1, sizeof(char));
+	strncpy(tk_original, word, ptr_diff(cp,word));
+}
+
+#if TAB_COMPLETE_FILENAME
 /*
  * Find the beginning and end of the "current" word.
  * This is the word which the cursor (cp) is inside or at the end of.
@@ -1024,23 +1063,15 @@ static char * delimit_word(void)
 }
 
 /*
- * Set things up to enter completion mode.
+ * Set things up to enter file completion mode.
  * Expand the word under the cursor into a list of filenames 
  * which start with that word, and set tk_text to that list.
  */
-static void init_compl(void)
+static void init_file_compl(void)
 {
 	char *word;
 	char c;
 	
-	/*
-	 * Get rid of any previous tk_text.
-	 */
-	if (tk_text != NULL)
-	{
-		free(tk_text);
-		tk_text = NULL;
-	}
 	/*
 	 * Find the original (uncompleted) word in the command buffer.
 	 */
@@ -1052,13 +1083,7 @@ static void init_compl(void)
 	 * where the original (uncompleted) word now sits.
 	 */
 	tk_ipoint = word;
-	/*
-	 * Save the original (uncompleted) word
-	 */
-	if (tk_original != NULL)
-		free(tk_original);
-	tk_original = (char *) ecalloc(ptr_diff(cp,word)+1, sizeof(char));
-	strncpy(tk_original, word, ptr_diff(cp,word));
+	set_tk_original(word);
 	/*
 	 * Get the expanded filename.
 	 * This may result in a single filename, or
@@ -1086,6 +1111,17 @@ static void init_compl(void)
 	}
 	*cp = c;
 }
+#endif /* TAB_COMPLETE_FILENAME */
+
+/*
+ * Set things up to enter option completion mode.
+ */
+static void init_opt_compl(void)
+{
+	tk_ipoint = cmdbuf;
+	set_tk_original(cmdbuf);
+	tk_text = findopts_name(cmdbuf);
+}
 
 /*
  * Return the next word in the current completion list.
@@ -1120,7 +1156,19 @@ static int cmd_complete(int action)
 		 * use the first word in the expansion 
 		 * (or the entire expansion if we're doing EC_EXPAND).
 		 */
-		init_compl();
+		if (tk_text != NULL)
+		{
+			free(tk_text);
+			tk_text = NULL;
+		}
+		if (curr_cmdflags & CF_OPTION)
+			init_opt_compl();
+		else
+#if TAB_COMPLETE_FILENAME
+			init_file_compl();
+#else
+			quit(QUIT_ERROR); /* cannot happen */
+#endif /* TAB_COMPLETE_FILENAME */
 		if (tk_text == NULL)
 		{
 			bell();
@@ -1195,25 +1243,20 @@ fail:
 	return (CC_OK);
 }
 
-#endif /* TAB_COMPLETE_FILENAME */
-
 /*
- * Process a single character of a multi-character command, such as
- * a number, or the pattern of a search command.
+ * Build a UTF-8 char in cmd_mbc_buf.
  * Returns:
- *      CC_OK           The char was accepted.
- *      CC_QUIT         The char requests the command to be aborted.
- *      CC_ERROR        The char could not be accepted due to an error.
+ *      CC_OK    Char has been stored but we don't have a complete UTF-8 sequence yet.
+ *      CC_ERROR This is an invalid UTF-8 sequence.
+ *      CC_PASS  There is a complete UTF-8 sequence in cmd_mbc_buf.
+ *               The length of the complete sequence is returned in *plen.
  */
-public int cmd_char(char c)
+static int cmd_uchar(char c, size_t *plen)
 {
-	int action;
-	size_t len;
-
 	if (!utf_mode)
 	{
 		cmd_mbc_buf[0] = c;
-		len = 1;
+		*plen = 1;
 	} else
 	{
 		/* Perform strict validation in all possible cases.  */
@@ -1262,9 +1305,26 @@ public int cmd_char(char c)
 			goto retry;
 		}
 
-		len = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
+		*plen = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
 		cmd_mbc_buf_len = 0;
 	}
+	return (CC_PASS);
+}
+
+/*
+ * Process a single character of a multi-character command, such as
+ * a number, or the pattern of a search command.
+ * Returns:
+ *      CC_OK           The char was accepted.
+ *      CC_QUIT         The char requests the command to be aborted.
+ *      CC_ERROR        The char could not be accepted due to an error.
+ */
+static int cmd_char2(char c, lbool stay_in_completion)
+{
+	size_t len;
+	int action = cmd_uchar(c, &len);
+	if (action != CC_PASS)
+		return (action);
 
 	if (literal)
 	{
@@ -1280,7 +1340,7 @@ public int cmd_char(char c)
 	 */
 	if (in_mca() && len == 1)
 	{
-		action = cmd_edit(c);
+		action = cmd_edit(c, stay_in_completion);
 		switch (action)
 		{
 		case CC_OK:
@@ -1297,6 +1357,30 @@ public int cmd_char(char c)
 	return (cmd_ichar(cmd_mbc_buf, len));
 }
 
+public int cmd_char(char c)
+{
+	return cmd_char2(c, FALSE);
+}
+
+/*
+ * Copy an ASCII string to the command buffer.
+ */
+public int cmd_setstring(constant char *s, lbool uc)
+{
+	while (*s != '\0')
+	{
+		int action;
+		char c = *s++;
+		if (uc && ASCII_IS_LOWER(c))
+			c = ASCII_TO_UPPER(c);
+		action = cmd_char2(c, TRUE);
+		if (action != CC_OK)
+			return (action);
+	}
+	cmd_repaint_curr();
+	return (CC_OK);
+}
+
 /*
  * Return the number currently in the command buffer.
  */
@@ -1464,6 +1548,7 @@ static void read_cmdhist2(void (*action)(void*,struct mlist*,constant char*), vo
 #else
 			ml = NULL;
 			skip = NULL;
+			(void) skip_shell;
 #endif
 		} else if (strcmp(line, HISTFILE_MARK_SECTION) == 0)
 		{
@@ -1674,6 +1759,8 @@ public void save_cmdhist(void)
 		skip_search = mlist_size(&mlist_search) - histsize;
 #if SHELL_ESCAPE || PIPEC
 		skip_shell = mlist_size(&mlist_shell) - histsize;
+#else
+		skip_shell = 0; /* not actually used */
 #endif
 		fprintf(fout, "%s\n", HISTFILE_FIRST_LINE);
 		ctx.fout = fout;
diff --git a/contrib/less/command.c b/contrib/less/command.c
index 27eba082e520..3ec1f9b48358 100644
--- a/contrib/less/command.c
+++ b/contrib/less/command.c
@@ -1,6 +1,5 @@
-/* $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.
@@ -30,7 +29,7 @@ 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;
@@ -39,6 +38,7 @@ 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[];
@@ -49,6 +49,10 @@ 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
@@ -76,7 +80,7 @@ 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;
@@ -85,6 +89,10 @@ 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
@@ -104,7 +112,7 @@ static void multi_search(constant char *pattern, int n, int silent);
  * 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();
@@ -230,7 +238,7 @@ static void mca_opt_toggle(void)
 		break;
 	}
 	forw_prompt = 0;
-	set_mlist(NULL, 0);
+	set_mlist(NULL, CF_OPTION);
 }
 
 /*
@@ -239,7 +247,6 @@ static void mca_opt_toggle(void)
 static void exec_mca(void)
 {
 	constant char *cbuf;
-	char *p;
 
 	cmd_exec();
 	cbuf = get_cmdbuf();
@@ -256,6 +263,7 @@ static void exec_mca(void)
 	case A_FILTER:
 		search_type ^= SRCH_NO_MATCH;
 		set_filter_pattern(cbuf, search_type);
+		soft_eof = NULL_POSITION;
 		break;
 #endif
 	case A_FIRSTCMD:
@@ -282,7 +290,8 @@ static void exec_mca(void)
 		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);
@@ -292,7 +301,7 @@ static void exec_mca(void)
 		/* If tag structure is loaded then clean it up. */
 		cleantags();
 #endif
-		break;
+		break; }
 #endif
 #if SHELL_ESCAPE
 	case A_SHELL: {
@@ -415,16 +424,18 @@ 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
@@ -433,26 +444,23 @@ static int mca_opt_nonfirst_char(char c)
 	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)
 	{
@@ -473,7 +481,7 @@ static int mca_opt_char(char c)
 	 * 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)
*** 6463 LINES SKIPPED ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506100607.55A67Pgk004116>