git: c62065236a70 - stable/15 - MFV: less v704.

Xin LI <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a83c1e7.1fa20.16b5a4ef__28581.7445417464$1787019779$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by delphij:

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

commit c62065236a7054b4a98dd46b876fda79dead45fc
Author:     Xin LI <[email protected]>
AuthorDate: 2026-08-15 05:55:38 +0000
Commit:     Xin LI <[email protected]>
CommitDate: 2026-08-18 02:21:58 +0000

    MFV: less v704.
    
    (cherry picked from commit fa0dc4f0f96a1b77d4be7bcdbf965897cda14521)
---
 contrib/less/NEWS              | 126 ++++++++++++++++
 contrib/less/README            |   8 -
 contrib/less/ch.c              |  10 +-
 contrib/less/charset.c         |  25 +--
 contrib/less/charset.h         |   2 +
 contrib/less/cmd.h             |   3 +
 contrib/less/cmdbuf.c          |   6 +-
 contrib/less/command.c         | 186 ++++++++++++++++-------
 contrib/less/decode.c          | 334 ++++++++++++++++++++++++++++++-----------
 contrib/less/edit.c            |  42 ++++--
 contrib/less/filename.c        |  20 +--
 contrib/less/forwback.c        |  53 +++++--
 contrib/less/funcs.h           |  41 +++--
 contrib/less/help.c            |  28 ++--
 contrib/less/input.c           |  12 +-
 contrib/less/jump.c            |  31 ++--
 contrib/less/less-osc8-open.sh |  64 ++++++++
 contrib/less/less.h            |  44 ++++--
 contrib/less/less.hlp          |  26 ++--
 contrib/less/less.nro          | 331 ++++++++++++++++++++++++++--------------
 contrib/less/lessecho.nro      |   2 +-
 contrib/less/lesskey.nro       |   3 +-
 contrib/less/lesskey_parse.c   |   2 +
 contrib/less/line.c            |  62 ++++----
 contrib/less/lsystem.c         |   2 +-
 contrib/less/main.c            |  73 ++-------
 contrib/less/mark.c            |  50 ++++--
 contrib/less/optfunc.c         | 200 ++++++++++++++++++++----
 contrib/less/opttbl.c          |  60 ++++++--
 contrib/less/os.c              |  45 +++---
 contrib/less/output.c          |  68 +++++----
 contrib/less/pattern.c         |   8 +-
 contrib/less/pattern.h         |  10 +-
 contrib/less/position.c        |  82 ++++++----
 contrib/less/prompt.c          |  33 ++--
 contrib/less/regexp.c          | 206 +++++++++++++++++--------
 contrib/less/regexp.h          |   5 +-
 contrib/less/screen.c          | 105 +++++++++----
 contrib/less/search.c          | 140 ++++++++++-------
 contrib/less/tags.c            |   8 +-
 contrib/less/ttyin.c           |   2 +-
 contrib/less/version.c         |  37 ++++-
 usr.bin/less/Makefile          |   2 +-
 usr.bin/less/defines.h         |  12 ++
 44 files changed, 1845 insertions(+), 764 deletions(-)

diff --git a/contrib/less/NEWS b/contrib/less/NEWS
index 0f767aaeb059..a031353acf46 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -9,6 +9,132 @@
   Report bugs, suggestions or comments at 
   https://github.com/gwsw/less/issues.
 
+======================================================================
+
+	Major changes between "less" versions 702 and 704
+
+* Fix possibly passing unsafe options to man when opening an
+  OSC 8 link (github #779).
+
+* Fix possibly sending unsafe OSC sequence to terminal when file
+  contains an unterminated OSC sequence (github #781).
+
+* In Examine and Shell commands, expand % and # to shell-escaped
+  filenames (github #784).
+
+======================================================================
+
+	Major changes between "less" versions 692 and 702
+
+* Add --hilite-target option and -DJ to color target line (github #745).
+
+* Add --past-eof option.
+
+* Add --end-prompt option.
+
+* Add --emouse and --rmouse options, and horizontal mouse scrolling
+  and dragging (github #744).
+
+* Add -DT option to format tilde lines (github #725).
+
+* Change OSC 8 link handling: replace LESS_OSC8_xxx with LESS_OSC8_OPEN_xxx.
+  Remove %O from prompt expansion as no longer needed.
+  Any use of environment variables LESS_OSC8_xxx need to be manually
+  changed to use LESS_OSC8_OPEN_xxx.
+
+* Add ?o to prompt strings, to detect whether an OSC 8 link is selected.
+
+* When scrolling past end-of-file or before beginning-of-file,
+  stop when exactly one line is left on screen.
+
+* Make -w/-W highlight lines when moving backward as well as forward
+  (github #729).
+
+* Display pattern in "Pattern not found" message (github #731).
+
+* Allow m and M commands to take a numeric argument to specify the
+  line to be marked (github #736).
+
+* Allow ' command to take a numeric argument to specify the screen
+  position on which to place the marked line.
+
+* Allow lesskey to map keypad ENTER with \kpe (github #761).
+
+* Add "noaction" as a possible action in #line-edit section
+  in a lesskey file (github #761).
+
+* Support POSIX character classes with the built-in V8 regex library
+  (github #732).
+
+* Change | command to pipe just one line if the marked line is at the
+  top of the screen (github #733).
+
+* If OSC8 handler command begins with "-", suppress command echo,
+  and if it begins with ctrl-P, suppress "done" message (github #747).
+
+* Don't ask for confirmation when input is a binary file and stdout is
+  redirected. Fixes infinite loop in that situation (github #719).
+
+* Make early error messages go to stderr if stdout is redirected
+  (github #719).
+
+* Don't retry read after read error; fixes hang when attempting to read
+  a directory or other unreadable file (github #741).
+
+* Fix incorrect restoration of saved mark if not at top of screen.
+
+* With --save-marks, don't save a mark that was cleared with ESC-m.
+
+* Fix buffer overflow when using malformed lesskey file (github #721).
+
+* Fix unexpected scrolling past end of file (github #720).
+
+* Fix bug when env var in LESSKEY_CONTENT partially matches env var
+  defined in lesskey file (github #727).
+
+* Fix bug when env var in lesskey file matches tail of env var used
+  by less (github #728).
+
+* Fix command parsing bug when one command is a substring of another.
+  Also fixes --no-paste option (github #724).
+
+* Fix incorrect display using --color to set character attributes
+  without color, such as -DS-u (github #730).
+
+* Fix crash when tags file contains invalid line number 0 (github #743).
+
+* Fix build when tparm() doesn't use varargs (github #748).
+
+* Fix prompt overflow when filtering with long prompt (github #749).
+
+* Fix incorrect highlighting when change -i while filtering (github #750).
+
+* Fix erroneous error mesage using --show-preproc-error with
+  some shells (github #753).
+
+* Fix erroneous highlighting when using a search pattern containing more
+  than 5 pairs of parentheses with PCRE2 (github #754).
+
+* When ^X interrupts F mode, discard pending keys as is done when
+  ^C interrupts it (github #757).
+
+* Fix bug in Windows where pressing any key during "waiting for data" would
+  prevent a subsequent ^X from working.
+
+* Fix erroneous display in some situations when using LESS_LINES (github #759).
+
+* Fix erroneous display after certain messages are displayed in a
+  very narrow terminal (github #760).
+
+* Don't init terminal if stdout is not a tty (github #768).
+
+* Fix bug clicking OSC 8 link that crosses a screen line boundary
+  (github #775).
+
+* Fix beeps when resizing window on Windows (github #771).
+
+* Fix beeps when paging continuously on Windows (github #772).
+
 ======================================================================
 
 	Major changes between "less" versions 691 and 692
diff --git a/contrib/less/README b/contrib/less/README
index a6954eb67c1e..384d99155616 100644
--- a/contrib/less/README
+++ b/contrib/less/README
@@ -108,14 +108,6 @@ INSTALLATION (Unix & Linux systems only):
    bindir and/or mandir to the appropriate directories.
 
 
-Note to hackers: comments noting possible improvements are enclosed
-in double curly brackets {{ like this }}.
-
-(Note that the above note was originally written at a time when 
-"hackers" most commonly meant "enthusiastic and dedicated computer 
-programmers", not "persons who attempt to circumvent computer security".)
-
-
 
 =======================================================================
 INSTALLATION (Windows-95, Windows-98 and Windows-NT systems only,
diff --git a/contrib/less/ch.c b/contrib/less/ch.c
index 47d31ecffadd..dfe1e7169f72 100644
--- a/contrib/less/ch.c
+++ b/contrib/less/ch.c
@@ -23,6 +23,7 @@
 typedef POSITION BLOCKNUM;
 
 public lbool ignore_eoi = FALSE;
+public lbool read_error = FALSE;
 
 /*
  * Pool of buffers holding the most recently used blocks of the input file.
@@ -292,13 +293,14 @@ static int ch_get(void)
 		if (n < 0)
 		{
 #if MSDOS_COMPILER==WIN32C
-			if (errno != EPIPE)
+			if (errno == EPIPE)
+				n = 0;
+			else
 #endif
 			{
-				error("read error", NULL_PARG);
-				clear_eol();
+				read_error = TRUE;
+				return (EOI);
 			}
-			n = 0;
 		}
 
 #if LOGFILE
diff --git a/contrib/less/charset.c b/contrib/less/charset.c
index 74159404148b..f2020e4ef5c5 100644
--- a/contrib/less/charset.c
+++ b/contrib/less/charset.c
@@ -585,20 +585,21 @@ public constant char * prutfchar(LWCHAR ch)
 /*
  * Get the length of a UTF-8 character in bytes.
  */
-public int utf_len(char ch)
+public int utf_len(char ach)
 {
-	if ((ch & 0x80) == 0)
+	unsigned char ch = (unsigned char) ach;
+	if (IS_ASCII_OCTET(ch))
 		return 1;
-	if ((ch & 0xE0) == 0xC0)
+	if (IS_UTF8_LEAD2(ch))
 		return 2;
-	if ((ch & 0xF0) == 0xE0)
+	if (IS_UTF8_LEAD3(ch))
 		return 3;
-	if ((ch & 0xF8) == 0xF0)
+	if (IS_UTF8_LEAD4(ch))
 		return 4;
 #if 0
-	if ((ch & 0xFC) == 0xF8)
+	if (IS_UTF8_LEAD5(ch))
 		return 5;
-	if ((ch & 0xFE) == 0xFC)
+	if (IS_UTF8_LEAD6(ch))
 		return 6;
 #endif
 	/* Invalid UTF-8 encoding. */
@@ -608,16 +609,17 @@ public int utf_len(char ch)
 /*
  * Does the parameter point to the lead byte of a well-formed UTF-8 character?
  */
-public lbool is_utf8_well_formed(constant char *ss, int slen)
+public lbool is_utf8_well_formed(constant char *ssa, int slen)
 {
 	int i;
 	int len;
-	unsigned char s0 = (unsigned char) ss[0];
+	constant unsigned char *ss = (constant unsigned char *) ssa;
+	unsigned char s0 = ss[0];
 
-	if (IS_UTF8_INVALID(s0))
+	if (IS_UTF8_LEAD5(s0) || IS_UTF8_LEAD6(s0) || IS_UTF8_INVALID(s0))
 		return (FALSE);
 
-	len = utf_len(ss[0]);
+	len = utf_len(s0);
 	if (len > slen)
 		return (FALSE);
 	if (len == 1)
@@ -904,6 +906,7 @@ public lbool is_composing_char(LWCHAR ch)
 public lbool is_ubin_char(LWCHAR ch)
 {
 	if (is_in_table(ch, &user_prt_table)) return FALSE;
+	if (ch > MAX_UNICODE) return TRUE;
 	return is_in_table(ch, &user_ubin_table) ||
 	       (is_in_table(ch, &ubin_table) ||
 	       (bs_mode == BS_CONTROL && is_in_table(ch, &fmt_table) &&
diff --git a/contrib/less/charset.h b/contrib/less/charset.h
index cf2e02547cb5..dab7474acc73 100644
--- a/contrib/less/charset.h
+++ b/contrib/less/charset.h
@@ -16,3 +16,5 @@
 #define IS_UTF8_LEAD6(c)    (((c) & 0xFE) == 0xFC)
 #define IS_UTF8_INVALID(c)  (((c) & 0xFE) == 0xFE)
 #define IS_UTF8_LEAD(c)     (((c) & 0xC0) == 0xC0 && !IS_UTF8_INVALID(c))
+
+#define MAX_UNICODE         0x10FFFF
diff --git a/contrib/less/cmd.h b/contrib/less/cmd.h
index 945f99719d0c..fb66a6adb99d 100644
--- a/contrib/less/cmd.h
+++ b/contrib/less/cmd.h
@@ -87,6 +87,8 @@
 #define A_START_PASTE          75 /* must not overlap EC_* */
 #define A_END_PASTE            76 /* must not overlap EC_* */
 #define A_F_FOREVER_BELL       77
+#define A_L_MOUSE              78
+#define A_R_MOUSE              79
 
 /* These values must not conflict with any A_* or EC_* value. */
 #define A_INVALID              100
@@ -178,5 +180,6 @@
 #define SK_CTL_END             37
 #define SK_SHIFT_LEFT_ARROW    38
 #define SK_SHIFT_RIGHT_ARROW   39
+#define SK_PAD_ENTER           41
 
 #define SK_CONTROL_K           40
diff --git a/contrib/less/cmdbuf.c b/contrib/less/cmdbuf.c
index 1c3b3d461ad9..9f13473eba03 100644
--- a/contrib/less/cmdbuf.c
+++ b/contrib/less/cmdbuf.c
@@ -113,8 +113,8 @@ static struct mlist *curr_mlist = NULL;
 static int curr_cmdflags;
 
 static char cmd_mbc_buf[MAX_UTF_CHAR_LEN];
-static int cmd_mbc_buf_len;
-static int cmd_mbc_buf_index;
+static size_t cmd_mbc_buf_len;
+static size_t cmd_mbc_buf_index;
 
 
 /*
@@ -1330,7 +1330,7 @@ static int cmd_uchar(char c, size_t *plen)
 			goto retry;
 		}
 
-		*plen = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
+		*plen = cmd_mbc_buf_len;
 		cmd_mbc_buf_len = 0;
 	}
 	return (CC_PASS);
diff --git a/contrib/less/command.c b/contrib/less/command.c
index 1bb8d006f8ec..09eb1614c76d 100644
--- a/contrib/less/command.c
+++ b/contrib/less/command.c
@@ -23,10 +23,11 @@
 extern int erase_char, erase2_char, kill_char;
 extern int sigs;
 extern int quit_if_one_screen;
-extern int one_screen;
+extern lbool one_screen;
 extern int sc_width;
 extern int sc_height;
 extern char *kent;
+extern lbool kent_mapped;
 extern int swindow;
 extern int jump_sline;
 extern lbool quitting;
@@ -48,13 +49,16 @@ extern void *ml_search;
 extern void *ml_examine;
 extern int wheel_lines;
 extern int def_search_type;
+extern int hilite_target;
 extern lbool search_wrapped;
 extern int no_paste;
 extern lbool pasting;
 extern int no_edit_warn;
+extern lbool read_error;
 extern POSITION soft_eof;
 extern POSITION search_incr_start;
 extern char *first_cmd_at_prompt;
+extern lbool prompting;
 #if SHELL_ESCAPE || PIPEC
 extern void *ml_shell;
 #endif
@@ -65,9 +69,9 @@ extern constant char *editproto;
 extern char *osc8_uri;
 #endif
 extern int shift_count;
-extern int forw_prompt;
+extern lbool forw_prompt;
 extern int incr_search;
-extern int full_screen;
+extern lbool full_screen;
 #if MSDOS_COMPILER==WIN32C
 extern int utf_mode;
 extern unsigned less_acp;
@@ -85,6 +89,7 @@ static struct loption *curropt;
 static lbool opt_lower;
 static int optflag;
 static lbool optgetname;
+static POSITION toppos;
 static POSITION bottompos;
 static int save_hshift;
 static int save_bs_mode;
@@ -208,7 +213,7 @@ static void mca_search1(void)
 		cmd_putstr("/");
 	else
 		cmd_putstr("?");
-	forw_prompt = 0;
+	forw_prompt = FALSE;
 }
 
 static void mca_search(void)
@@ -248,7 +253,7 @@ static void mca_opt_toggle(void)
 		cmd_putstr("!");
 		break;
 	}
-	forw_prompt = 0;
+	forw_prompt = FALSE;
 	set_mlist(NULL, CF_OPTION);
 }
 
@@ -850,12 +855,6 @@ public int is_screen_trashed(void)
  */
 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))
-		lclear();
 	/*
 	 * If nothing is displayed yet, display starting from initial_scrpos.
 	 */
@@ -884,12 +883,47 @@ static void make_display(void)
 	}
 }
 
+/*
+ * Display any message that needs to be displayed before the prompt.
+ */
+static void prompt_message(void)
+{
+	if (read_error)
+	{
+		error("read error", NULL_PARG);
+		read_error = FALSE;
+	}
+	if (search_wrapped)
+	{
+		if (search_type & SRCH_BACK)
+			error("Search hit top; continuing at bottom", NULL_PARG);
+		else
+			error("Search hit bottom; continuing at top", NULL_PARG);
+		search_wrapped = FALSE;
+	}
+#if OSC8_LINK
+	if (osc8_uri != NULL)
+	{
+		PARG parg;
+		parg.p_string = osc8_uri;
+		error("Link: %s", &parg);
+		free(osc8_uri);
+		osc8_uri = NULL;
+	}
+#endif
+}
+
 /*
  * Display the appropriate prompt.
  */
 static void prompt(void)
 {
 	constant char *p;
+	int attr;
+#if MSDOS_COMPILER==WIN32C
+	WCHAR w[MAX_PATH*2];
+	char  a[MAX_PATH*2];
+#endif
 
 	if (ungot != NULL && !ungot->ug_end_command)
 	{
@@ -904,6 +938,10 @@ static void prompt(void)
 	 * Make sure the screen is displayed.
 	 */
 	make_display();
+
+	if (hilite_target)
+		draw_target_attn(TRUE); /* Redraw target line for --hilite-target. */
+	toppos = position(TOP);
 	bottompos = position(BOTTOM_PLUS_ONE);
 
 	/*
@@ -921,7 +959,7 @@ static void prompt(void)
 	    entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && 
 	    next_ifile(curr_ifile) == NULL_IFILE)
 		quit(QUIT_OK);
-	quit_if_one_screen = FALSE; /* only get one chance at this */
+	quit_if_one_screen = 0; /* only get one chance at this */
 	if (first_cmd_at_prompt != NULL)
 	{
 		ungetsc(first_cmd_at_prompt);
@@ -932,6 +970,7 @@ static void prompt(void)
 #if MSDOS_COMPILER==WIN32C
 	/* 
 	 * In Win32, display the file name in the window title.
+	 * {{ Seems like this should be done in edit_ifile, not on every prompt. }}
 	 */
 	if (!(ch_getflags() & CH_HELPFILE))
 	{
@@ -958,50 +997,43 @@ static void prompt(void)
 	if (!forw_prompt)
 		clear_bot();
 	clear_cmd();
-	forw_prompt = 0;
+	forw_prompt = FALSE;
+	prompt_message();
+	/* We called make_display above, but if prompt_message displayed
+	 * a message longer than the screen width, we may have trashed
+	 * the screen and need to call make_display again. */
+	if (is_screen_trashed())
+		make_display();
 	p = pr_string();
-#if HILITE_SEARCH
-	if (is_filtering())
-		putstr("& ");
-#endif
-	if (search_wrapped)
-	{
-		if (search_type & SRCH_BACK)
-			error("Search hit top; continuing at bottom", NULL_PARG);
-		else
-			error("Search hit bottom; continuing at top", NULL_PARG);
-		search_wrapped = FALSE;
-	}
-#if OSC8_LINK
-	if (osc8_uri != NULL)
-	{
-		PARG parg;
-		parg.p_string = osc8_uri;
-		error("Link: %s", &parg);
-		free(osc8_uri);
-		osc8_uri = NULL;
-	}
-#endif
 	if (p == NULL || *p == '\0')
 	{
-		at_enter(AT_NORMAL|AT_COLOR_PROMPT);
-		putchr(':');
-		at_exit();
+		p = ":";
+		attr = AT_NORMAL|AT_COLOR_PROMPT;
 	} else
 	{
+		attr = AT_STANDOUT|AT_COLOR_PROMPT;
 #if MSDOS_COMPILER==WIN32C
-		WCHAR w[MAX_PATH*2];
-		char  a[MAX_PATH*2];
 		MultiByteToWideChar(less_acp, 0, p, -1, w, countof(w));
 		WideCharToMultiByte(utf_mode ? CP_UTF8 : GetConsoleOutputCP(),
 		                    0, w, -1, a, sizeof(a), NULL, NULL);
 		p = a;
 #endif
-		load_line(p);
-		put_line(FALSE);
 	}
+#if HILITE_SEARCH
+	if (is_filtering())
+	{
+		constant char *amp = "& ";
+		load_line(p, attr, strlen(amp)+1);
+		putstr(amp);
+	} else
+#endif
+	{
+		load_line(p, attr, 1);
+	}
+	put_line(FALSE);
 	clear_eol();
 	resume_screen();
+	prompting = TRUE;
 }
 
 /*
@@ -1139,8 +1171,9 @@ static char getcc_repl(char constant *orig, char constant *repl, char (*gr_getc)
  */
 public char getcc(void)
 {
-	/* Replace kent (keypad Enter) with a newline. */
-	return getcc_repl(kent, "\n", getccu, ungetcc);
+	/* Replace kent (keypad Enter) with a newline.
+	 * However don't do this if kent is mapped to a command via lesskey. */
+	return getcc_repl(kent_mapped ? NULL : kent, "\n", getccu, ungetcc);
 }
 
 /*
@@ -1291,7 +1324,14 @@ static void multi_search(constant char *pattern, int n, int silent)
 	 * Print an error message if we haven't already.
 	 */
 	if (n > 0 && !silent)
-		error("Pattern not found", NULL_PARG);
+	{
+		PARG parg;
+		parg.p_string = prev_pattern_text();
+		if (parg.p_string == NULL) /* {{ can this happen? }} */
+			error("Pattern not found", NULL_PARG);
+		else
+			error("Pattern not found: %s", &parg);
+	}
 
 	if (changed_file)
 	{
@@ -1348,7 +1388,7 @@ static int forw_loop(int action)
 /*
  * Ignore subsequent (pasted) input chars.
  */
-public void start_ignoring_input()
+public void start_ignoring_input(void)
 {
 	ignoring_input = TRUE;
 #if HAVE_TIME
@@ -1359,7 +1399,7 @@ public void start_ignoring_input()
 /*
  * Stop ignoring input chars.
  */
-public void stop_ignoring_input()
+public void stop_ignoring_input(void)
 {
 	ignoring_input = FALSE;
 	pasting = FALSE;
@@ -1443,6 +1483,8 @@ public void commands(void)
 			c = getcc();
 
 	again:
+		if (c == READ_AGAIN)
+			continue;
 		if (sigs)
 			continue;
 
@@ -1582,12 +1624,13 @@ public void commands(void)
 			if (number <= 0)
 				number = get_swindow();
 			cmd_exec();
+			if (show_attn && toppos != NULL_POSITION && toppos > ch_zero())
+				set_attnpos(toppos-1);
 			backward((int) number, FALSE, TRUE, FALSE);
 			break;
 
 		case A_F_LINE:
 		case A_F_NEWLINE:
-
 			/*
 			 * Forward N (default 1) line.
 			 */
@@ -1607,6 +1650,8 @@ public void commands(void)
 			if (number <= 0)
 				number = 1;
 			cmd_exec();
+			if (show_attn == OPT_ONPLUS && number > 1 && toppos != NULL_POSITION && toppos > ch_zero())
+				set_attnpos(toppos-1);
 			backward((int) number, FALSE, FALSE, action == A_B_NEWLINE && !chopline);
 			break;
 
@@ -1626,6 +1671,29 @@ public void commands(void)
 			backward(wheel_lines, FALSE, FALSE, FALSE);
 			break;
 
+		case A_L_MOUSE:
+			/*
+			 * Left wheel_lines columns.
+			 */
+			cmd_exec();
+			pos_rehead(FALSE);
+			if (wheel_lines > hshift)
+				hshift = 0;
+			else
+				hshift -= wheel_lines;
+			screen_trashed();
+			break;
+
+		case A_R_MOUSE:
+			/*
+			 * Right wheel_lines columns.
+			 */
+			cmd_exec();
+			pos_rehead(FALSE);
+			hshift += wheel_lines;
+			screen_trashed();
+			break;
+
 		case A_FF_LINE:
 			/*
 			 * Force forward N (default 1) line.
@@ -1645,6 +1713,8 @@ public void commands(void)
 			if (number <= 0)
 				number = 1;
 			cmd_exec();
+			if (show_attn == OPT_ONPLUS && number > 1 && toppos != NULL_POSITION && toppos > ch_zero())
+				set_attnpos(toppos-1);
 			backward((int) number, TRUE, FALSE, FALSE);
 			break;
 		
@@ -1667,6 +1737,8 @@ public void commands(void)
 			if (number <= 0)
 				number = get_swindow();
 			cmd_exec();
+			if (show_attn == OPT_ONPLUS && toppos != NULL_POSITION && toppos > ch_zero())
+				set_attnpos(toppos-1);
 			backward((int) number, TRUE, FALSE, FALSE);
 			break;
 
@@ -1704,6 +1776,8 @@ public void commands(void)
 			if (number > 0)
 				wscroll = (int) number;
 			cmd_exec();
+			if (show_attn == OPT_ONPLUS && toppos != NULL_POSITION && toppos > ch_zero())
+				set_attnpos(toppos-1);
 			backward(wscroll, FALSE, FALSE, FALSE);
 			break;
 
@@ -1963,6 +2037,7 @@ public void commands(void)
 			/*
 			 * Clear search string highlighting.
 			 */
+			cmd_exec();
 			undo_search(action == A_CLR_SEARCH);
 			break;
 
@@ -2229,9 +2304,11 @@ public void commands(void)
 			}
 			start_mca(A_SETMARK, "set mark: ", NULL, 0);
 			c = getcc();
+			make_display();
+			cmd_exec();
 			if (is_erase_char(c) || is_newline_char(c))
 				break;
-			setmark(c, action == A_SETMARKBOT ? BOTTOM : TOP);
+			setmark(c, action == A_SETMARKBOT ? BOTTOM : TOP, number);
 			repaint();
 			break;
 
@@ -2241,6 +2318,7 @@ public void commands(void)
 			 */
 			start_mca(A_CLRMARK, "clear mark: ", NULL, 0);
 			c = getcc();
+			cmd_exec();
 			if (is_erase_char(c) || is_newline_char(c))
 				break;
 			clrmark(c);
@@ -2256,7 +2334,7 @@ public void commands(void)
 			if (is_erase_char(c) || is_newline_char(c))
 				break;
 			cmd_exec();
-			gomark(c);
+			gomark(c, number);
 			break;
 
 		case A_PIPE:
@@ -2299,7 +2377,7 @@ public void commands(void)
 				number = (shift_count > 0) ? shift_count : sc_width / 2;
 			if (number > hshift)
 				number = hshift;
-			pos_rehead();
+			pos_rehead(FALSE);
 			hshift -= (int) number;
 			screen_trashed();
 			cmd_exec();
@@ -2313,7 +2391,7 @@ public void commands(void)
 				shift_count = (int) number;
 			else
 				number = (shift_count > 0) ? shift_count : sc_width / 2;
-			pos_rehead();
+			pos_rehead(FALSE);
 			hshift += (int) number;
 			screen_trashed();
 			cmd_exec();
@@ -2323,7 +2401,7 @@ public void commands(void)
 			/*
 			 * Shift view left to margin.
 			 */
-			pos_rehead();
+			pos_rehead(FALSE);
 			hshift = 0;
 			screen_trashed();
 			cmd_exec();
@@ -2333,7 +2411,7 @@ public void commands(void)
 			/*
 			 * Shift view right to view rightmost char on screen.
 			 */
-			pos_rehead();
+			pos_rehead(FALSE);
 			hshift = rrshift();
 			screen_trashed();
 			cmd_exec();
diff --git a/contrib/less/decode.c b/contrib/less/decode.c
index 3615f5b905d7..393082c84097 100644
--- a/contrib/less/decode.c
+++ b/contrib/less/decode.c
@@ -34,12 +34,12 @@
 #include "lesskey.h"
 
 extern int erase_char, erase2_char, kill_char;
-extern int mousecap;
+extern int emouse;
+extern int mouse_reverse;
+extern int hshift;
 extern int sc_height;
 extern char *no_config;
 
-static constant lbool allow_drag = TRUE;
-
 #if USERFILE
 /* "content" is lesskey source, never binary. */
 static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar);
@@ -286,17 +286,19 @@ static unsigned char edittable[] =
 	ESC,'[','2','0','1','~',0,      A_END_PASTE,    /* close paste bracket */
 };
 
-static unsigned char dflt_vartable[] =
+/*
+ * Default environment variables.
+ * Note: "\201" is (A_EXTRA|EV_OK).
+ */
+static char dflt_vartable[] =
 {
-	'L','E','S','S','_','O','S','C','8','_','m','a','n', 0, EV_OK|A_EXTRA,
-		/* echo '%o' | sed -e "s,^man\:\\([^(]*\\)( *\\([^)]*\\)\.*,-man '\\2' '\\1'," -e"t X" -e"s,\.*,-echo Invalid man link," -e"\: X" */
-		'e','c','h','o',' ','\'','%','o','\'',' ','|',' ','s','e','d',' ','-','e',' ','"','s',',','^','m','a','n','\\',':','\\','\\','(','[','^','(',']','*','\\','\\',')','(',' ','*','\\','\\','(','[','^',')',']','*','\\','\\',')','\\','.','*',',','-','m','a','n',' ','\'','\\','\\','2','\'',' ','\'','\\','\\','1','\'',',','"',' ','-','e','"','t',' ','X','"',' ','-','e','"','s',',','\\','.','*',',','-','e','c','h','o',' ','I','n','v','a','l','i','d',' ','m','a','n',' ','l','i','n','k',',','"',' ','-','e','"','\\',':',' ','X','"',
-		0,
-
-	'L','E','S','S','_','O','S','C','8','_','f','i','l','e', 0, EV_OK|A_EXTRA,
-		/* eval `echo '%o' | sed -e "s,^file://\\([^/]*\\)\\(.*\\),_H=\\1;_P=\\2;_E=0," -e"t X" -e"s,.*,_E=1," -e": X"`; if [ "$_E" = 1 ]; then echo -echo Invalid file link; elif [ -z "$_H" -o "$_H" = localhost -o "$_H" = $HOSTNAME ]; then echo ":e $_P"; else echo -echo Cannot open remote file on "$_H"; fi */
-		'e','v','a','l',' ','`','e','c','h','o',' ','\'','%','o','\'',' ','|',' ','s','e','d',' ','-','e',' ','"','s',',','^','f','i','l','e','\\',':','/','/','\\','\\','(','[','^','/',']','*','\\','\\',')','\\','\\','(','\\','.','*','\\','\\',')',',','_','H','=','\\','\\','1',';','_','P','=','\\','\\','2',';','_','E','=','0',',','"',' ','-','e','"','t',' ','X','"',' ','-','e','"','s',',','\\','.','*',',','_','E','=','1',',','"',' ','-','e','"','\\',':',' ','X','"','`',';',' ','i','f',' ','[',' ','"','$','_','E','"',' ','=',' ','1',' ',']',';',' ','t','h','e','n',' ','e','c','h','o',' ','-','e','c','h','o',' ','I','n','v','a','l','i','d',' ','f','i','l','e',' ','l','i','n','k',';',' ','e','l','i','f',' ','[',' ','-','z',' ','"','$','_','H','"',' ','-','o',' ','"','$','_','H','"',' ','=',' ','l'
 ,'o','c','a','l','h','o','s','t',' ','-','o',' ','"','$','_','H','"',' ','=',' ','$','H','O','S','T','N','A','M','E',' ',']',';',' ','t','h','e','n',' ','e','c','h','o',' ','"','\\',':','e'
,' ','$','_','P','"',';',' ','e','l','s','e',' ','e','c','h','o',' ','-','e','c','h','o',' ','C','a','n','n','o','t',' ','o','p','e','n',' ','r','e','m','o','t','e',' ','f','i','l','e',' ','o','n',' ','"','$','_','H','"',';',' ','f','i',
-		0,
+	"LESS_OSC8_OPEN_ANY\0\201"
+#ifdef LIBEXECDIR
+		"-" LIBEXECDIR "/less-osc8-open"
+#else
+		"-less-osc8-open"
+#endif
+		"\0"
 };
 
 /*
@@ -317,6 +319,9 @@ static struct tablelist *list_ecmd_tables = NULL;
 static struct tablelist *list_var_tables = NULL;
 static struct tablelist *list_sysvar_tables = NULL;
 
+#if USERFILE
+static struct tablelist * find_stop_table(struct tablelist *t);
+#endif
 
 /*
  * Expand special key abbreviations in a command table.
@@ -335,7 +340,7 @@ static void expand_special_keys(unsigned char *table, size_t len)
 		 * Rewrite each command in the table with any
 		 * special key abbreviations expanded.
 		 */
-		for (to = fm;  *fm != '\0'; )
+		for (to = fm;  fm < table + len && *fm != '\0'; )
 		{
 			if (*fm != SK_SPECIAL_KEY)
 			{
@@ -352,7 +357,7 @@ static void expand_special_keys(unsigned char *table, size_t len)
 			 * output by the special key on this terminal.
 			 */
 			repl = special_key_str(fm[1]);
-			klen = fm[2] & 0377;
+			klen = fm[2];
 			fm += klen;
 			if (repl == NULL || strlen(repl) > klen)
 				repl = "\377";
@@ -367,10 +372,10 @@ static void expand_special_keys(unsigned char *table, size_t len)
 		while (to <= fm)
 			*to++ = A_SKIP;
 		fm++;
-		a = *fm++ & 0377;
+		a = *fm++;
 		if (a & A_EXTRA)
 		{
-			while (*fm++ != '\0')
+			while (fm < table + len && *fm++ != '\0')
 				continue;
 		}
 	}
@@ -404,12 +409,15 @@ public void expand_cmd_tables(void)
  */
 public void init_cmds(void)
 {
+	struct tablelist *t;
+	unsigned char *udflt_vartable = (unsigned char *) dflt_vartable;
+
 	/*
 	 * Add the default command tables.
 	 */
 	add_fcmd_table(cmdtable, sizeof(cmdtable));
 	add_ecmd_table(edittable, sizeof(edittable));
-	add_sysvar_table(dflt_vartable, sizeof(dflt_vartable));
+	add_sysvar_table(udflt_vartable, sizeof(dflt_vartable));
 #if USERFILE
 #ifdef BINDIR /* For backwards compatibility */
 	/* Try to add tables in the OLD system lesskey file. */
@@ -449,6 +457,16 @@ public void init_cmds(void)
 	
 	add_content_table(lesskey_content, "LESSKEY_CONTENT_SYSTEM", TRUE);
 	add_content_table(lesskey_content, "LESSKEY_CONTENT", FALSE);
+
+	/*
+	 * If any command table contains a #stop directive, discard all other tables.
+	 */
+	t = find_stop_table(list_fcmd_tables);
+	if (t != NULL)
+	{
+		t->t_next = NULL;
+		list_fcmd_tables = t;
+	}
 #endif /* USERFILE */
 }
 
@@ -555,7 +573,9 @@ public void add_sysvar_table(unsigned char *buf, size_t len)
  */
 static int mouse_wheel_down(void)
 {
-	return ((mousecap == OPT_ONPLUS) ? A_B_MOUSE : A_F_MOUSE);
+	if (!(emouse & EMOUSE_VSCROLL))
+		return A_NOACTION;
+	return mouse_reverse ? A_B_MOUSE : A_F_MOUSE;
 }
 
 /*
@@ -563,7 +583,29 @@ static int mouse_wheel_down(void)
  */
 static int mouse_wheel_up(void)
 {
-	return ((mousecap == OPT_ONPLUS) ? A_F_MOUSE : A_B_MOUSE);
+	if (!(emouse & EMOUSE_VSCROLL))
+		return A_NOACTION;
+	return mouse_reverse ? A_F_MOUSE : A_B_MOUSE;
+}
+
+/*
+ * Return action for a mouse wheel left event.
+ */
+static int mouse_wheel_left(void)
+{
+	if (!(emouse & EMOUSE_HSCROLL))
+		return A_NOACTION;
+	return mouse_reverse ? A_R_MOUSE : A_L_MOUSE;
+}
+
+/*
+ * Return action for a mouse wheel right event.
+ */
+static int mouse_wheel_right(void)
+{
+	if (!(emouse & EMOUSE_HSCROLL))
+		return A_NOACTION;
+	return mouse_reverse ? A_L_MOUSE : A_R_MOUSE;
 }
 
 /*
@@ -571,32 +613,48 @@ static int mouse_wheel_up(void)
  */
 static int mouse_button_left(int x, int y, lbool down, lbool drag)
 {
+	static int last_drag_x = -1;
 	static int last_drag_y = -1;
 	static int last_click_y = -1;
 
 	if (down && !drag)
 	{
+		last_drag_x = x;
*** 4359 LINES SKIPPED ***
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.