git: 69ce8ed3c650 - stable/13 - MFV: less v632.

From: Xin LI <delphij_at_FreeBSD.org>
Date: Thu, 18 May 2023 06:01:00 UTC
The branch stable/13 has been updated by delphij:

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

commit 69ce8ed3c6500878ec011a779663765a69727342
Author:     Xin LI <delphij@FreeBSD.org>
AuthorDate: 2023-05-02 03:43:57 +0000
Commit:     Xin LI <delphij@FreeBSD.org>
CommitDate: 2023-05-18 06:00:49 +0000

    MFV: less v632.
    
    (cherry picked from commit d713e0891ff9ab8246245c3206851d486ecfdd37)
---
 contrib/less/LICENSE         |   2 +-
 contrib/less/NEWS            |  79 ++++-
 contrib/less/brac.c          |   9 +-
 contrib/less/ch.c            | 321 ++++++++-----------
 contrib/less/charset.c       | 234 +++++++++-----
 contrib/less/charset.h       |   2 +-
 contrib/less/cmd.h           |   3 +-
 contrib/less/cmdbuf.c        | 211 +++---------
 contrib/less/command.c       | 200 ++++++------
 contrib/less/compose.uni     |  14 +-
 contrib/less/cvt.c           |  19 +-
 contrib/less/decode.c        | 144 ++-------
 contrib/less/edit.c          | 357 +++++++++++++++------
 contrib/less/filename.c      | 137 ++++----
 contrib/less/fmt.uni         |   4 +-
 contrib/less/forwback.c      |  64 +---
 contrib/less/funcs.h         | 748 ++++++++++++++++++++++---------------------
 contrib/less/help.c          |  46 ++-
 contrib/less/ifile.c         | 118 ++-----
 contrib/less/input.c         | 203 +++++++++---
 contrib/less/jump.c          |  37 +--
 contrib/less/less.h          |  89 +++--
 contrib/less/less.hlp        |  44 ++-
 contrib/less/less.nro        | 677 ++++++++++++++++++++++++++-------------
 contrib/less/lessecho.c      |  44 +--
 contrib/less/lessecho.nro    |  38 +--
 contrib/less/lesskey.c       |  66 ++--
 contrib/less/lesskey.h       |   2 +-
 contrib/less/lesskey.nro     |  62 ++--
 contrib/less/lesskey_parse.c | 111 ++-----
 contrib/less/lglob.h         |   2 +-
 contrib/less/line.c          | 467 ++++++++++++---------------
 contrib/less/linenum.c       |  53 ++-
 contrib/less/lsystem.c       |  18 +-
 contrib/less/main.c          |  54 ++--
 contrib/less/mark.c          |  84 ++---
 contrib/less/mkutable        |  15 +-
 contrib/less/optfunc.c       | 314 ++++++++----------
 contrib/less/option.c        | 105 ++----
 contrib/less/option.h        |   4 +-
 contrib/less/opttbl.c        | 116 +++++--
 contrib/less/os.c            | 231 +++++++------
 contrib/less/output.c        | 135 ++++----
 contrib/less/pattern.c       | 176 +++++-----
 contrib/less/pattern.h       |  10 +-
 contrib/less/pckeys.h        |   2 +-
 contrib/less/position.c      |  41 +--
 contrib/less/position.h      |   2 +-
 contrib/less/prompt.c        |  78 ++---
 contrib/less/screen.c        | 562 +++++++++++++++-----------------
 contrib/less/scrsize.c       |   2 +-
 contrib/less/search.c        | 370 ++++++++-------------
 contrib/less/signal.c        |  29 +-
 contrib/less/tags.c          |  87 ++---
 contrib/less/ttyin.c         |  52 +--
 contrib/less/ubin.uni        |  16 +-
 contrib/less/version.c       |  31 +-
 contrib/less/wide.uni        |  22 +-
 contrib/less/xbuf.c          | 150 +++++++--
 contrib/less/xbuf.h          |   7 +-
 usr.bin/less/defines.h       |  24 +-
 61 files changed, 3721 insertions(+), 3623 deletions(-)

diff --git a/contrib/less/LICENSE b/contrib/less/LICENSE
index 65bce4288972..d22cc6070c51 100644
--- a/contrib/less/LICENSE
+++ b/contrib/less/LICENSE
@@ -2,7 +2,7 @@
                           ------------
 
 Less
-Copyright (C) 1984-2022  Mark Nudelman
+Copyright (C) 1984-2023  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 bcfe4c6c9e38..468f59441b28 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -9,6 +9,77 @@
   Report bugs, suggestions or comments at 
   https://github.com/gwsw/less/issues.
 
+======================================================================
+
+	Major changes between "less" versions 608 and 632
+
+* Add LESSUTFCHARDEF environment variable (github #275).
+
+* Add # command (github #330).
+
+* Add ^S search modifier (github #196).
+
+* Add --wordwrap option (github #113).
+
+* Add --no-vbell option (github #304).
+
+* Add --no-search-headers option (github #44).
+
+* Add --modelines option (github #89).
+
+* Add --intr option (github #224).
+
+* Add --proc-backspace, --proc-tab and --proc-return options (github #335).
+
+* Add --show-preproc-errors option (github #258).
+
+* Add LESS_LINES and LESS_COLUMNS environment variables (github #84).
+
+* Add LESS_DATA_DELAY environment variable (github #337).
+
+* Allow empty "lines" field in --header option.
+
+* Update Unicode tables.
+
+* Improve ability of ^X to interrupt F command (github #49).
+
+* Status column (-J) shows off-screen matches.
+
+* Parenthesized sub-patterns in searches are colored with unique colors,
+  if supported by the regular expression library (github #196).
+
+* Don't allow opening a tty as file input unless -f is set (github #309).
+
+* Don't require newline input after +&... option (github #339).
+
+* Fix incorrect handling of some Private Use Unicode characters.
+
+* Fix ANSI color bug when overstriking with colored chars (github #276).
+
+* Fix compiler const warning (github #279).
+
+* Fix signal race in iread (github #280).
+
+* Fix reading procfs files on Linux (github #282).
+
+* Fix --ignore-case with ctrl-R (no regex) search (github #300).
+
+* Fix bug doing repeat search after setting & filter (github #299).
+
+* Fix bug doing repeat search before non-repeat search.
+
+* Fix crash with -R and certain line lengths (github #338).
+
+* Fix input of Windows dead keys (github #352).
+
+* Don't retain search options from a cancelled search (github #302).
+
+* Don't call realpath on fake filenames like "-" (github #289).
+
+* Implement lesstest test suite.
+
+* Convert function parameter definitions from K&R to C89 (github #316).
+
 ======================================================================
 
 	Major changes between "less" versions 590 and 608
@@ -241,7 +312,7 @@
 
 * Update Unicode tables to 2017-03-08.
 
-* Pass-thru Unicode formating chars (Cf type) instead of treating them
+* Pass-thru Unicode formatting chars (Cf type) instead of treating them
   as binary chars. But treat them as binary if -U is set.
 
 * Fix erroneous binary file warning when UTF-8 file contains ANSI SGR sequences.
@@ -433,7 +504,7 @@
 
 * Fix problem interrupting the line number calculation for initial prompt.
 
-* Fix SGR emulation when dealing with multiple attributes (eg. bold+underline).
+* Fix SGR emulation when dealing with multiple attributes (e.g. bold+underline).
 
 * Fix highlight bug when searching for underlined/overstruck text.
 
@@ -515,7 +586,7 @@
 
 * The -c option has been made identical with the -C option.
 
-* Allow "/dev/null" as synomym for "-" in LESSHISTFILE to indicate
+* Allow "/dev/null" as synonym for "-" in LESSHISTFILE to indicate
   that no history file should be used.
 
 * Search can now find text which follows a null byte, if the PCRE
@@ -665,7 +736,7 @@
 
 * Improved performance in reading very large pipes.
 
-* Eliminated some dependencies on file offets being 32 bits.
+* Eliminated some dependencies on file offsets being 32 bits.
 
 * Fixed problems when viewing files with very long lines.
 
diff --git a/contrib/less/brac.c b/contrib/less/brac.c
index 58ecf172ae4e..da4efab8605e 100644
--- a/contrib/less/brac.c
+++ b/contrib/less/brac.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2022  Mark Nudelman
+ * Copyright (C) 1984-2023  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.
@@ -23,12 +23,7 @@
  * The characters which serve as "open bracket" and 
  * "close bracket" are given.
  */
-	public void
-match_brac(obrac, cbrac, forwdir, n)
-	int obrac;
-	int cbrac;
-	int forwdir;
-	int n;
+public void match_brac(char obrac, char cbrac, int forwdir, int n)
 {
 	int c;
 	int nest;
diff --git a/contrib/less/ch.c b/contrib/less/ch.c
index bfad09c719f6..b297e7483e7b 100644
--- a/contrib/less/ch.c
+++ b/contrib/less/ch.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2022  Mark Nudelman
+ * Copyright (C) 1984-2023  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.
@@ -20,14 +20,11 @@
 #include <windows.h>
 #endif
 
-#if HAVE_STAT_INO
-#include <sys/stat.h>
-extern dev_t curr_dev;
-extern ino_t curr_ino;
-#endif
-
 #if HAVE_PROCFS
 #include <sys/statfs.h>
+#if HAVE_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
 #endif
 
 typedef POSITION BLOCKNUM;
@@ -133,6 +130,7 @@ extern int sigs;
 extern int secure;
 extern int screen_trashed;
 extern int follow_mode;
+extern int waiting_for_data;
 extern constant char helpdata[];
 extern constant int size_helpdata;
 extern IFILE curr_ifile;
@@ -147,13 +145,12 @@ static int ch_addbuf();
 /*
  * Get the character pointed to by the read pointer.
  */
-	int
-ch_get(VOID_PARAM)
+static int ch_get(void)
 {
 	struct buf *bp;
 	struct bufnode *bn;
 	int n;
-	int slept;
+	int read_again;
 	int h;
 	POSITION pos;
 	POSITION len;
@@ -172,11 +169,10 @@ ch_get(VOID_PARAM)
 			return bp->data[ch_offset];
 	}
 
-	slept = FALSE;
-
 	/*
 	 * Look for a buffer holding the desired block.
 	 */
+	waiting_for_data = FALSE;
 	h = BUFHASH(ch_block);
 	FOR_BUFS_IN_CHAIN(h, bn)
 	{
@@ -225,149 +221,139 @@ ch_get(VOID_PARAM)
 		BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
 	}
 
-    read_more:
-	pos = (ch_block * LBUFSIZE) + bp->datasize;
-	if ((len = ch_length()) != NULL_POSITION && pos >= len)
-		/*
-		 * At end of file.
-		 */
-		return (EOI);
-
-	if (pos != ch_fpos)
+	for (;;)
 	{
+		pos = (ch_block * LBUFSIZE) + bp->datasize;
+		if ((len = ch_length()) != NULL_POSITION && pos >= len)
+			/*
+			 * At end of file.
+			 */
+			return (EOI);
+
+		if (pos != ch_fpos)
+		{
+			/*
+			 * Not at the correct position: must seek.
+			 * If input is a pipe, we're in trouble (can't seek on a pipe).
+			 * Some data has been lost: just return "?".
+			 */
+			if (!(ch_flags & CH_CANSEEK))
+				return ('?');
+			if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)
+			{
+				error("seek error", NULL_PARG);
+				clear_eol();
+				return (EOI);
+			}
+			ch_fpos = pos;
+		}
+
 		/*
-		 * Not at the correct position: must seek.
-		 * If input is a pipe, we're in trouble (can't seek on a pipe).
-		 * Some data has been lost: just return "?".
+		 * Read the block.
+		 * If we read less than a full block, that's ok.
+		 * We use partial block and pick up the rest next time.
 		 */
-		if (!(ch_flags & CH_CANSEEK))
-			return ('?');
-		if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)
+		if (ch_ungotchar != -1)
 		{
-			error("seek error", NULL_PARG);
-			clear_eol();
-			return (EOI);
+			bp->data[bp->datasize] = ch_ungotchar;
+			n = 1;
+			ch_ungotchar = -1;
+		} else if (ch_flags & CH_HELPFILE)
+		{
+			bp->data[bp->datasize] = helpdata[ch_fpos];
+			n = 1;
+		} else
+		{
+			n = iread(ch_file, &bp->data[bp->datasize], 
+				(unsigned int)(LBUFSIZE - bp->datasize));
 		}
-		ch_fpos = pos;
-	}
-
-	/*
-	 * Read the block.
-	 * If we read less than a full block, that's ok.
-	 * We use partial block and pick up the rest next time.
-	 */
-	if (ch_ungotchar != -1)
-	{
-		bp->data[bp->datasize] = ch_ungotchar;
-		n = 1;
-		ch_ungotchar = -1;
-	} else if (ch_flags & CH_HELPFILE)
-	{
-		bp->data[bp->datasize] = helpdata[ch_fpos];
-		n = 1;
-	} else
-	{
-		n = iread(ch_file, &bp->data[bp->datasize], 
-			(unsigned int)(LBUFSIZE - bp->datasize));
-	}
 
-	if (n == READ_INTR)
-		return (EOI);
-	if (n < 0)
-	{
+		read_again = FALSE;
+		if (n == READ_INTR)
+		{
+			ch_fsize = pos;
+			return (EOI);
+		}
+		if (n == READ_AGAIN)
+		{
+			read_again = TRUE;
+			n = 0;
+		}
+		if (n < 0)
+		{
 #if MSDOS_COMPILER==WIN32C
-		if (errno != EPIPE)
+			if (errno != EPIPE)
 #endif
-		{
-			error("read error", NULL_PARG);
-			clear_eol();
+			{
+				error("read error", NULL_PARG);
+				clear_eol();
+			}
+			n = 0;
 		}
-		n = 0;
-	}
 
 #if LOGFILE
-	/*
-	 * If we have a log file, write the new data to it.
-	 */
-	if (!secure && logfile >= 0 && n > 0)
-		write(logfile, (char *) &bp->data[bp->datasize], n);
+		/*
+		 * If we have a log file, write the new data to it.
+		 */
+		if (!secure && logfile >= 0 && n > 0)
+			write(logfile, (char *) &bp->data[bp->datasize], n);
 #endif
 
-	ch_fpos += n;
-	bp->datasize += n;
+		ch_fpos += n;
+		bp->datasize += n;
 
-	/*
-	 * If we have read to end of file, set ch_fsize to indicate
-	 * the position of the end of file.
-	 */
-	if (n == 0)
-	{
-		ch_fsize = pos;
-		if (ignore_eoi)
+		if (n == 0)
 		{
-			/*
-			 * We are ignoring EOF.
-			 * Wait a while, then try again.
-			 */
-			if (!slept)
-			{
-				PARG parg;
-				parg.p_string = wait_message();
-				ierror("%s", &parg);
-			}
-			sleep_ms(2); /* Reduce system load */
-			slept = TRUE;
-
-#if HAVE_STAT_INO
-			if (follow_mode == FOLLOW_NAME)
+			/* Either end of file or no data available.
+			 * read_again indicates the latter. */
+			if (!read_again)
+				ch_fsize = pos;
+			if (ignore_eoi || read_again)
 			{
-				/* See whether the file's i-number has changed,
-				 * or the file has shrunk.
-				 * If so, force the file to be closed and
-				 * reopened. */
-				struct stat st;
-				POSITION curr_pos = ch_tell();
-				int r = stat(get_filename(curr_ifile), &st);
-				if (r == 0 && (st.st_ino != curr_ino ||
-					st.st_dev != curr_dev ||
-					(curr_pos != NULL_POSITION && st.st_size < curr_pos)))
+				/* Wait a while, then try again. */
+				if (!waiting_for_data)
 				{
-					/* screen_trashed=2 causes
-					 * make_display to reopen the file. */
-					screen_trashed = 2;
-					return (EOI);
+					PARG parg;
+					parg.p_string = wait_message();
+					ixerror("%s", &parg);
+					waiting_for_data = TRUE;
 				}
+				sleep_ms(50); /* Reduce system load */
 			}
-#endif
+			if (ignore_eoi && follow_mode == FOLLOW_NAME && curr_ifile_changed())
+			{
+				/* screen_trashed=2 causes make_display to reopen the file. */
+				screen_trashed = 2;
+				return (EOI);
+			}
+			if (sigs)
+				return (EOI);
 		}
-		if (sigs)
-			return (EOI);
-	}
 
-    found:
-	if (ch_bufhead != bn)
-	{
-		/*
-		 * Move the buffer to the head of the buffer chain.
-		 * This orders the buffer chain, most- to least-recently used.
-		 */
-		BUF_RM(bn);
-		BUF_INS_HEAD(bn);
+		found:
+		if (ch_bufhead != bn)
+		{
+			/*
+			 * Move the buffer to the head of the buffer chain.
+			 * This orders the buffer chain, most- to least-recently used.
+			 */
+			BUF_RM(bn);
+			BUF_INS_HEAD(bn);
 
-		/*
-		 * Move to head of hash chain too.
-		 */
-		BUF_HASH_RM(bn);
-		BUF_HASH_INS(bn, h);
-	}
+			/*
+			 * Move to head of hash chain too.
+			 */
+			BUF_HASH_RM(bn);
+			BUF_HASH_INS(bn, h);
+		}
 
-	if (ch_offset >= bp->datasize)
+		if (ch_offset < bp->datasize)
+			break;
 		/*
 		 * After all that, we still don't have enough data.
 		 * Go back and try again.
 		 */
-		goto read_more;
-
+	}
 	return (bp->data[ch_offset]);
 }
 
@@ -375,9 +361,7 @@ ch_get(VOID_PARAM)
  * ch_ungetchar is a rather kludgy and limited way to push 
  * a single char onto an input file descriptor.
  */
-	public void
-ch_ungetchar(c)
-	int c;
+public void ch_ungetchar(int c)
 {
 	if (c != -1 && ch_ungotchar != -1)
 		error("ch_ungetchar overrun", NULL_PARG);
@@ -389,8 +373,7 @@ ch_ungetchar(c)
  * Close the logfile.
  * If we haven't read all of standard input into it, do that now.
  */
-	public void
-end_logfile(VOID_PARAM)
+public void end_logfile(void)
 {
 	static int tried = FALSE;
 
@@ -415,8 +398,7 @@ end_logfile(VOID_PARAM)
  * Invoked from the - command; see toggle_option().
  * Write all the existing buffered data to the log file.
  */
-	public void
-sync_logfile(VOID_PARAM)
+public void sync_logfile(void)
 {
 	struct buf *bp;
 	struct bufnode *bn;
@@ -452,9 +434,7 @@ sync_logfile(VOID_PARAM)
 /*
  * Determine if a specific block is currently in one of the buffers.
  */
-	static int
-buffered(block)
-	BLOCKNUM block;
+static int buffered(BLOCKNUM block)
 {
 	struct buf *bp;
 	struct bufnode *bn;
@@ -474,9 +454,7 @@ buffered(block)
  * Seek to a specified position in the file.
  * Return 0 if successful, non-zero if can't seek there.
  */
-	public int
-ch_seek(pos)
-	POSITION pos;
+public int ch_seek(POSITION pos)
 {
 	BLOCKNUM new_block;
 	POSITION len;
@@ -513,8 +491,7 @@ ch_seek(pos)
 /*
  * Seek to the end of the file.
  */
-	public int
-ch_end_seek(VOID_PARAM)
+public int ch_end_seek(void)
 {
 	POSITION len;
 
@@ -540,8 +517,7 @@ ch_end_seek(VOID_PARAM)
 /*
  * Seek to the last position in the file that is currently buffered.
  */
-	public int
-ch_end_buffer_seek(VOID_PARAM)
+public int ch_end_buffer_seek(void)
 {
 	struct buf *bp;
 	struct bufnode *bn;
@@ -568,8 +544,7 @@ ch_end_buffer_seek(VOID_PARAM)
  * We may not be able to seek there if input is a pipe and the
  * beginning of the pipe is no longer buffered.
  */
-	public int
-ch_beg_seek(VOID_PARAM)
+public int ch_beg_seek(void)
 {
 	struct bufnode *bn;
 	struct bufnode *firstbn;
@@ -600,8 +575,7 @@ ch_beg_seek(VOID_PARAM)
 /*
  * Return the length of the file, if known.
  */
-	public POSITION
-ch_length(VOID_PARAM)
+public POSITION ch_length(void)
 {
 	if (thisfile == NULL)
 		return (NULL_POSITION);
@@ -617,8 +591,7 @@ ch_length(VOID_PARAM)
 /*
  * Return the current position in the file.
  */
-	public POSITION
-ch_tell(VOID_PARAM)
+public POSITION ch_tell(void)
 {
 	if (thisfile == NULL)
 		return (NULL_POSITION);
@@ -628,8 +601,7 @@ ch_tell(VOID_PARAM)
 /*
  * Get the current char and post-increment the read pointer.
  */
-	public int
-ch_forw_get(VOID_PARAM)
+public int ch_forw_get(void)
 {
 	int c;
 
@@ -651,8 +623,7 @@ ch_forw_get(VOID_PARAM)
 /*
  * Pre-decrement the read pointer and get the new current char.
  */
-	public int
-ch_back_get(VOID_PARAM)
+public int ch_back_get(void)
 {
 	if (thisfile == NULL)
 		return (EOI);
@@ -674,15 +645,14 @@ ch_back_get(VOID_PARAM)
  * Set max amount of buffer space.
  * bufspace is in units of 1024 bytes.  -1 mean no limit.
  */
-	public void
-ch_setbufspace(bufspace)
-	int bufspace;
+public void ch_setbufspace(int bufspace)
 {
 	if (bufspace < 0)
 		maxbufs = -1;
 	else
 	{
-		maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
+		int lbufk = LBUFSIZE / 1024;
+		maxbufs = bufspace / lbufk + (bufspace % lbufk != 0);
 		if (maxbufs < 1)
 			maxbufs = 1;
 	}
@@ -691,8 +661,7 @@ ch_setbufspace(bufspace)
 /*
  * Flush (discard) any saved file state, including buffer contents.
  */
-	public void
-ch_flush(VOID_PARAM)
+public void ch_flush(void)
 {
 	struct bufnode *bn;
 
@@ -765,8 +734,7 @@ ch_flush(VOID_PARAM)
  * Allocate a new buffer.
  * The buffer is added to the tail of the buffer chain.
  */
-	static int
-ch_addbuf(VOID_PARAM)
+static int ch_addbuf(void)
 {
 	struct buf *bp;
 	struct bufnode *bn;
@@ -790,8 +758,7 @@ ch_addbuf(VOID_PARAM)
 /*
  *
  */
-	static void
-init_hashtbl(VOID_PARAM)
+static void init_hashtbl(void)
 {
 	int h;
 
@@ -805,8 +772,7 @@ init_hashtbl(VOID_PARAM)
 /*
  * Delete all buffers for this file.
  */
-	static void
-ch_delbufs(VOID_PARAM)
+static void ch_delbufs(void)
 {
 	struct bufnode *bn;
 
@@ -823,9 +789,7 @@ ch_delbufs(VOID_PARAM)
 /*
  * Is it possible to seek on a file descriptor?
  */
-	public int
-seekable(f)
-	int f;
+public int seekable(int f)
 {
 #if MSDOS_COMPILER
 	extern int fd0;
@@ -845,8 +809,7 @@ seekable(f)
  * Force EOF to be at the current read position.
  * This is used after an ignore_eof read, during which the EOF may change.
  */
-	public void
-ch_set_eof(VOID_PARAM)
+public void ch_set_eof(void)
 {
 	if (ch_fsize != NULL_POSITION && ch_fsize < ch_fpos)
 		ch_fsize = ch_fpos;
@@ -856,10 +819,7 @@ ch_set_eof(VOID_PARAM)
 /*
  * Initialize file state for a new file.
  */
-	public void
-ch_init(f, flags)
-	int f;
-	int flags;
+public void ch_init(int f, int flags)
 {
 	/*
 	 * See if we already have a filestate for this file.
@@ -896,8 +856,7 @@ ch_init(f, flags)
 /*
  * Close a filestate.
  */
-	public void
-ch_close(VOID_PARAM)
+public void ch_close(void)
 {
 	int keepstate = FALSE;
 
@@ -939,8 +898,7 @@ ch_close(VOID_PARAM)
 /*
  * Return ch_flags for the current file.
  */
-	public int
-ch_getflags(VOID_PARAM)
+public int ch_getflags(void)
 {
 	if (thisfile == NULL)
 		return (0);
@@ -948,8 +906,7 @@ ch_getflags(VOID_PARAM)
 }
 
 #if 0
-	public void
-ch_dump(struct filestate *fs)
+static void ch_dump(struct filestate *fs)
 {
 	struct buf *bp;
 	struct bufnode *bn;
diff --git a/contrib/less/charset.c b/contrib/less/charset.c
index 5e9a2d6427b8..881ebafd02cf 100644
--- a/contrib/less/charset.c
+++ b/contrib/less/charset.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1984-2022  Mark Nudelman
+ * Copyright (C) 1984-2023  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.
@@ -21,6 +21,7 @@
 #endif
 
 #include "charset.h"
+#include "xbuf.h"
 
 #if MSDOS_COMPILER==WIN32C
 #define WIN32_LEAN_AND_MEAN
@@ -123,6 +124,108 @@ static char *binfmt = NULL;
 static char *utfbinfmt = NULL;
 public int binattr = AT_STANDOUT|AT_COLOR_BIN;
 
+static struct xbuffer user_wide_array;
+static struct xbuffer user_ubin_array;
+static struct xbuffer user_compose_array;
+static struct xbuffer user_prt_array;
+static struct wchar_range_table user_wide_table;
+static struct wchar_range_table user_ubin_table;
+static struct wchar_range_table user_compose_table;
+static struct wchar_range_table user_prt_table;
+
+/*
+ * Set a wchar_range_table to the table in an xbuffer.
+ */
+static void wchar_range_table_set(struct wchar_range_table *tbl, struct xbuffer *arr)
+{
+	tbl->table = (struct wchar_range *) arr->data;
+	tbl->count = arr->end / sizeof(struct wchar_range);
+}
+
+/*
+ * Skip over a "U" or "U+" prefix before a hex codepoint.
+ */
+static char * skip_uprefix(char *s)
+{
+	if (*s == 'U' || *s == 'u')
+		if (*++s == '+') ++s;
+	return s;
+}
+
+/*
+ * Parse a dash-separated range of hex values.
+ */
+static void wchar_range_get(char **ss, struct wchar_range *range)
+{
+	char *s = skip_uprefix(*ss);
+	range->first = lstrtoul(s, &s, 16);
+	if (s[0] == '-')
+	{
+		s = skip_uprefix(&s[1]);
+		range->last = lstrtoul(s, &s, 16);
+	} else 
+	{
+		range->last = range->first;
+	}
+	*ss = s;
+}
+
+/*
+ * Parse the LESSUTFCHARDEF variable.
+ */
+static void ichardef_utf(char *s)
+{
+	xbuf_init(&user_wide_array);
+	xbuf_init(&user_ubin_array);
+	xbuf_init(&user_compose_array);
+	xbuf_init(&user_prt_array);
+
+	if (s != NULL)
+	{
+		while (s[0] != '\0')
+		{
+			struct wchar_range range;
+			wchar_range_get(&s, &range);
+			if (range.last == 0)
+			{
+				error("invalid hex number(s) in LESSUTFCHARDEF", NULL_PARG);
+				quit(QUIT_ERROR);
+			}
+			if (*s++ != ':')
+			{
+				error("missing colon in LESSUTFCHARDEF", NULL_PARG);
+				quit(QUIT_ERROR);
+			}
+			switch (*s++)
+			{
+			case 'b':
+				xbuf_add_data(&user_ubin_array, (unsigned char *) &range, sizeof(range));
+				break;
+			case 'c':
+				xbuf_add_data(&user_compose_array, (unsigned char *) &range, sizeof(range));
+				break;
+			case 'w':
+				xbuf_add_data(&user_wide_array, (unsigned char *) &range, sizeof(range));
+				xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
+				break;
+			case 'p': case '.':
+				xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
+				break;
+			case '\0':
+				s--;
+				break;
+			default:
+				/* Ignore unknown character attribute. */
+				break;
+			}
+			if (s[0] == ',') ++s;
+		}
+	}
+	wchar_range_table_set(&user_wide_table, &user_wide_array);
+	wchar_range_table_set(&user_ubin_table, &user_ubin_array);
+	wchar_range_table_set(&user_compose_table, &user_compose_array);
+	wchar_range_table_set(&user_prt_table, &user_prt_array);
+}
 
 /*
  * Define a charset, given a description string.
@@ -138,9 +241,7 @@ public int binattr = AT_STANDOUT|AT_COLOR_BIN;
  *      b binary character
  *      c control character
  */
-	static void
-ichardef(s)
-	char *s;
+static void ichardef(char *s)
 {
 	char *cp;
 	int n;
@@ -165,10 +266,12 @@ ichardef(s)
 
 		case '0': case '1': case '2': case '3': case '4':
 		case '5': case '6': case '7': case '8': case '9':
-			n = (10 * n) + (s[-1] - '0');
+			if (ckd_mul(&n, n, 10) || ckd_add(&n, n, s[-1] - '0'))
+				goto invalid_chardef;
 			continue;
 
 		default:
+		invalid_chardef:
 			error("invalid chardef", NULL_PARG);
 			quit(QUIT_ERROR);
 			/*NOTREACHED*/
@@ -195,10 +298,7 @@ ichardef(s)
  * Define a charset, given a charset name.
  * The valid charset names are listed in the "charsets" array.
  */
-	static int
-icharset(name, no_error)
-	char *name;
-	int no_error;
+static int icharset(char *name, int no_error)
 {
 	struct charset *p;
 	struct cs_alias *a;
@@ -244,8 +344,7 @@ icharset(name, no_error)
 /*
  * Define a charset, given a locale name.
  */
-	static void
-ilocale(VOID_PARAM)
+static void ilocale(void)
 {
 	int c;
 
@@ -264,12 +363,7 @@ ilocale(VOID_PARAM)
 /*
  * Define the printing format for control (or binary utf) chars.
  */
-	public void
-setfmt(s, fmtvarptr, attrptr, default_fmt)
-	char *s;
-	char **fmtvarptr;
-	int *attrptr;
-	char *default_fmt;
+public void setfmt(char *s, char **fmtvarptr, int *attrptr, char *default_fmt, int for_printf)
 {
*** 14546 LINES SKIPPED ***