MFV: less v685.

MFC after:	3 days
This commit is contained in:
Xin LI
2025-11-10 00:55:06 -08:00
33 changed files with 597 additions and 141 deletions
+39
View File
@@ -9,6 +9,45 @@
Report bugs, suggestions or comments at
https://github.com/gwsw/less/issues.
======================================================================
Major changes between "less" versions 679 and 685
* Add --cmd option (github #624).
* Add LESS_TERMCAP_SUSPEND and LESS_TERMCAP_RESUME (github #654).
* Change --incsearch so that after typing each character of the pattern,
the search begins at the position where the search command was invoked,
not the current position (github #640).
* Allow mixing of option arguments and filename arguments on the
command line unless POSIXLY_CORRECT is set (github #653).
* Don't output U+00AD and U+200D, and fix some bugs handling emoji
modifier characters (github #637).
* Fix hang if a search using ^S modifier matches empty string (github #634).
* Fix bug using -g and -J (github #636).
* Fix bug when pasting a search pattern while --incsearch is active
(github #635).
* Fix bug in Windows build when autorepeating a search pattern (github #639).
* Fix lesskey bug using #stop directive.
* Fix lesskey bug using "invalid" action (github #643).
* Fix bug causing file to appear to end prematurely if an input command
was received during a file read (github #649).
* Fix performance issue in & filtering (github #638). Problem was introduced
in da2a9ecdf16beb642d0c030e35f0351c5f2e5a12 and released in less-673.
* Fix some problems reported by valgrind (github #659, github #660, github #661).
======================================================================
Major changes between "less" versions 678 and 679
-4
View File
@@ -283,11 +283,7 @@ static int ch_get(void)
read_again = FALSE;
if (n == READ_INTR)
{
if (ch_flags & CH_CANSEEK)
ch_fsize = pos;
return (EOI);
}
if (n == READ_AGAIN)
{
read_again = TRUE;
+41 -7
View File
@@ -128,10 +128,12 @@ 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 xbuffer user_omit_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;
static struct wchar_range_table user_omit_table;
/*
* Set a wchar_range_table to the table in an xbuffer.
@@ -179,6 +181,7 @@ static void ichardef_utf(constant char *s)
xbuf_init(&user_ubin_array);
xbuf_init(&user_compose_array);
xbuf_init(&user_prt_array);
xbuf_init(&user_omit_array);
if (s != NULL)
{
@@ -204,6 +207,9 @@ static void ichardef_utf(constant char *s)
case 'c':
xbuf_add_data(&user_compose_array, (unsigned char *) &range, sizeof(range));
break;
case 'd':
xbuf_add_data(&user_omit_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));
@@ -225,6 +231,7 @@ static void ichardef_utf(constant char *s)
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);
wchar_range_table_set(&user_omit_table, &user_omit_array);
}
/*
@@ -554,7 +561,7 @@ public constant char * prutfchar(LWCHAR ch)
SNPRINTF1(buf, sizeof(buf), "^%c", ((char) ch) ^ 0100);
else
SNPRINTF1(buf, sizeof(buf), binfmt, (char) ch);
} else if (is_ubin_char(ch))
} else if (is_ubin_char(ch) || is_omit_char(ch))
{
SNPRINTF1(buf, sizeof(buf), utfbinfmt, ch);
} else
@@ -827,6 +834,10 @@ DECLARE_RANGE_TABLE_START(fmt)
#include "fmt.uni"
DECLARE_RANGE_TABLE_END(fmt)
DECLARE_RANGE_TABLE_START(omit)
#include "omit.uni"
DECLARE_RANGE_TABLE_END(omit)
/* comb_table is special pairs, not ranges. */
static struct wchar_range comb_table[] = {
{0x0644,0x0622}, {0x0644,0x0623}, {0x0644,0x0625}, {0x0644,0x0627},
@@ -856,6 +867,17 @@ static lbool is_in_table(LWCHAR ch, struct wchar_range_table *table)
return FALSE;
}
/*
* Is a character in none of a set of specified user tables?
*/
static lbool not_user_defined(LWCHAR ch, struct wchar_range_table *tbl1, struct wchar_range_table *tbl2, struct wchar_range_table *tbl3)
{
if (is_in_table(ch, tbl1)) return FALSE;
if (is_in_table(ch, tbl2)) return FALSE;
if (is_in_table(ch, tbl3)) return FALSE;
return TRUE;
}
/*
* Is a character a UTF-8 composing character?
* If a composing character follows any char, the two combine into one glyph.
@@ -864,8 +886,9 @@ public lbool is_composing_char(LWCHAR ch)
{
if (is_in_table(ch, &user_prt_table)) return FALSE;
return is_in_table(ch, &user_compose_table) ||
is_in_table(ch, &compose_table) ||
(bs_mode != BS_CONTROL && is_in_table(ch, &fmt_table));
(is_in_table(ch, &compose_table) ||
(bs_mode != BS_CONTROL && is_in_table(ch, &fmt_table) &&
not_user_defined(ch, &user_prt_table, &user_ubin_table, &user_omit_table)));
}
/*
@@ -875,8 +898,9 @@ public lbool is_ubin_char(LWCHAR ch)
{
if (is_in_table(ch, &user_prt_table)) return FALSE;
return is_in_table(ch, &user_ubin_table) ||
is_in_table(ch, &ubin_table) ||
(bs_mode == BS_CONTROL && is_in_table(ch, &fmt_table));
(is_in_table(ch, &ubin_table) ||
(bs_mode == BS_CONTROL && is_in_table(ch, &fmt_table) &&
not_user_defined(ch, &user_prt_table, &user_compose_table, &user_omit_table)));
}
/*
@@ -885,7 +909,18 @@ public lbool is_ubin_char(LWCHAR ch)
public lbool is_wide_char(LWCHAR ch)
{
return is_in_table(ch, &user_wide_table) ||
is_in_table(ch, &wide_table);
(is_in_table(ch, &wide_table) &&
not_user_defined(ch, &user_compose_table, &user_ubin_table, &user_omit_table));
}
/*
* Is this an omittable character?
*/
public lbool is_omit_char(LWCHAR ch)
{
return is_in_table(ch, &user_omit_table) ||
(is_in_table(ch, &omit_table) &&
not_user_defined(ch, &user_prt_table, &user_compose_table, &user_ubin_table));
}
/*
@@ -905,4 +940,3 @@ public lbool is_combining_char(LWCHAR ch1, LWCHAR ch2)
}
return FALSE;
}
+40
View File
@@ -49,10 +49,13 @@ extern void *ml_examine;
extern int wheel_lines;
extern int def_search_type;
extern lbool search_wrapped;
extern lbool no_poll;
extern int no_paste;
extern lbool pasting;
extern int no_edit_warn;
extern POSITION soft_eof;
extern POSITION search_incr_start;
extern char *first_cmd_at_prompt;
#if SHELL_ESCAPE || PIPEC
extern void *ml_shell;
#endif
@@ -90,6 +93,8 @@ static int save_proc_backspace;
static int screen_trashed_value = 0;
static lbool literal_char = FALSE;
static lbool ignoring_input = FALSE;
static struct scrpos search_incr_pos = { NULL_POSITION, 0 };
static int search_incr_hshift;
#if HAVE_TIME
static time_type ignoring_input_time;
#endif
@@ -209,6 +214,13 @@ static void mca_search1(void)
static void mca_search(void)
{
if (incr_search)
{
/* Remember where the incremental search started. */
get_scrpos(&search_incr_pos, TOP);
search_incr_start = search_pos(search_type);
search_incr_hshift = hshift;
}
mca_search1();
set_mlist(ml_search, 0);
}
@@ -747,6 +759,9 @@ static int mca_char(char c)
constant char *pattern = get_cmdbuf();
if (pattern == NULL)
return (MCA_MORE);
/* Defer searching if more chars of the pattern are available. */
if (ttyin_ready())
return (MCA_MORE);
/*
* Must save updown_match because mca_search
* reinits it. That breaks history scrolling.
@@ -758,11 +773,24 @@ static int mca_char(char c)
{
/* User has backspaced to an empty pattern. */
undo_search(1);
hshift = search_incr_hshift;
jump_loc(search_incr_pos.pos, search_incr_pos.ln);
} else
{
/*
* Suppress tty polling while searching.
* This avoids a problem where tty input
* can cause the search to be interrupted.
*/
no_poll = TRUE;
if (search(st | SRCH_INCR, pattern, 1) != 0)
{
/* No match, invalid pattern, etc. */
undo_search(1);
hshift = search_incr_hshift;
jump_loc(search_incr_pos.pos, search_incr_pos.ln);
}
no_poll = FALSE;
}
/* Redraw the search prompt and search string. */
if (is_screen_trashed() || !full_screen)
@@ -795,6 +823,7 @@ static void clear_buffers(void)
#if HILITE_SEARCH
clr_hilite();
#endif
set_line_contig_pos(NULL_POSITION);
}
public void screen_trashed_num(int trashed)
@@ -889,6 +918,12 @@ static void prompt(void)
next_ifile(curr_ifile) == NULL_IFILE)
quit(QUIT_OK);
quit_if_one_screen = FALSE; /* only get one chance at this */
if (first_cmd_at_prompt != NULL)
{
ungetsc(first_cmd_at_prompt);
first_cmd_at_prompt = NULL;
return;
}
#if MSDOS_COMPILER==WIN32C
/*
@@ -962,6 +997,7 @@ static void prompt(void)
put_line(FALSE);
}
clear_eol();
resume_screen();
}
/*
@@ -2261,6 +2297,7 @@ public void commands(void)
pos_rehead();
hshift -= (int) number;
screen_trashed();
cmd_exec();
break;
case A_RSHIFT:
@@ -2274,6 +2311,7 @@ public void commands(void)
pos_rehead();
hshift += (int) number;
screen_trashed();
cmd_exec();
break;
case A_LLSHIFT:
@@ -2283,6 +2321,7 @@ public void commands(void)
pos_rehead();
hshift = 0;
screen_trashed();
cmd_exec();
break;
case A_RRSHIFT:
@@ -2292,6 +2331,7 @@ public void commands(void)
pos_rehead();
hshift = rrshift();
screen_trashed();
cmd_exec();
break;
case A_PREFIX:
+1 -3
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Mn Me -- unicode/UnicodeData.txt" on Oct 1 18:10:07 GMT 2024 */
/* Generated by "./mkutable -f2 Mn Me -- unicode/UnicodeData.txt" on Aug 11 0:27:25 GMT 2025 */
{ 0x0300, 0x036f }, /* Mn */
{ 0x0483, 0x0487 }, /* Mn */
{ 0x0488, 0x0489 }, /* Me */
@@ -217,7 +217,6 @@
{ 0xd7b0, 0xd7c6 }, /* Mn */
{ 0xd7cb, 0xd7fb }, /* Mn */
{ 0xfb1e, 0xfb1e }, /* Mn */
{ 0xfe00, 0xfe0f }, /* Mn */
{ 0xfe20, 0xfe2f }, /* Mn */
{ 0x101fd, 0x101fd }, /* Mn */
{ 0x102e0, 0x102e0 }, /* Mn */
@@ -363,4 +362,3 @@
{ 0x1e5ee, 0x1e5ef }, /* Mn */
{ 0x1e8d0, 0x1e8d6 }, /* Mn */
{ 0x1e944, 0x1e94a }, /* Mn */
{ 0xe0100, 0xe01ef }, /* Mn */
+5 -6
View File
@@ -483,12 +483,12 @@ public void add_ecmd_table(unsigned char *buf, size_t len)
/*
* Add an environment variable table.
*/
static void add_var_table(struct tablelist **tlist, unsigned char *buf, size_t len)
static void add_var_table(struct tablelist **tlist, mutable unsigned char *buf, size_t len)
{
struct xbuffer xbuf;
xbuf_init(&xbuf);
expand_evars((char*)buf, len, &xbuf); /*{{unsigned-issue}}*/
expand_evars((mutable char*)buf, len, &xbuf); /*{{unsigned-issue}}*/
/* {{ We leak the table in buf. expand_evars scribbled in it so it's useless anyway. }} */
if (add_cmd_table(tlist, xbuf.data, xbuf.end) < 0)
error("Warning: environment variables from lesskey file unavailable", NULL_PARG);
@@ -749,7 +749,8 @@ static int cmd_search(constant char *cmd, constant unsigned char *table, constan
if (match == cmdlen) /* (last chars of) cmd matches this table entry */
{
action = taction;
*extra = textra;
if (extra != NULL)
*extra = textra;
} else if (match > 0 && action == A_INVALID) /* cmd is a prefix of this table entry */
{
action = A_PREFIX;
@@ -780,13 +781,11 @@ static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char
for (t = tlist; t != NULL; t = t->t_next)
{
constant unsigned char *tsp;
size_t mlen;
size_t mlen = match_len;
int taction = cmd_search(cmd, t->t_start, t->t_end, &tsp, &mlen);
if (mlen >= match_len)
{
match_len = mlen;
if (taction == A_UINVALID)
taction = A_INVALID;
if (taction != A_INVALID)
{
*sp = (constant char *) tsp;
+6 -4
View File
@@ -113,9 +113,7 @@ public constant char * forw_textlist(struct textlist *tlist, constant char *prev
s = tlist->string;
else
s = prev + strlen(prev);
if (s >= tlist->endstring)
return (NULL);
while (*s == '\0')
while (s < tlist->endstring && *s == '\0')
s++;
if (s >= tlist->endstring)
return (NULL);
@@ -306,7 +304,11 @@ static void close_pipe(FILE *pipefd)
if (WIFSIGNALED(status))
{
int sig = WTERMSIG(status);
if (sig != SIGPIPE || ch_length() != NULL_POSITION)
if (
#ifdef SIGPIPE
sig != SIGPIPE ||
#endif
ch_length() != NULL_POSITION)
{
parg.p_string = signal_message(sig);
error("Input preprocessor terminated: %s", &parg);
+3 -3
View File
@@ -1,5 +1,4 @@
/* Generated by "./mkutable -f2 Cf -- unicode/UnicodeData.txt" on Oct 1 18:10:07 GMT 2024 */
{ 0x00ad, 0x00ad }, /* Cf */
/* Generated by "./mkutable -f2 Cf -- unicode/UnicodeData.txt" on Jul 27 19:38:50 GMT 2025 */
{ 0x0600, 0x0605 }, /* Cf */
{ 0x061c, 0x061c }, /* Cf */
{ 0x06dd, 0x06dd }, /* Cf */
@@ -7,7 +6,8 @@
{ 0x0890, 0x0891 }, /* Cf */
{ 0x08e2, 0x08e2 }, /* Cf */
{ 0x180e, 0x180e }, /* Cf */
{ 0x200b, 0x200f }, /* Cf */
{ 0x200b, 0x200c }, /* Cf */
{ 0x200e, 0x200f }, /* Cf */
{ 0x202a, 0x202e }, /* Cf */
{ 0x2060, 0x2064 }, /* Cf */
{ 0x2066, 0x206f }, /* Cf */
+1 -1
View File
@@ -359,7 +359,7 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
}
if (!first_line)
add_forw_pos(pos, FALSE);
if (nlines == 0 && !ignore_eoi)
if (nlines == 0 && !ignore_eoi && !ABORT_SIGS())
eof_bell();
else if (do_repaint)
repaint();
+10 -2
View File
@@ -14,6 +14,8 @@ public void init_win_colors(void);
public void get_term(void);
public void init_mouse(void);
public void deinit_mouse(void);
public void suspend_screen(void);
public void resume_screen(void);
public void init(void);
public void deinit(void);
public int interactive(void);
@@ -83,6 +85,7 @@ public LWCHAR step_char(char **pp, signed int dir, constant char *limit);
public lbool is_composing_char(LWCHAR ch);
public lbool is_ubin_char(LWCHAR ch);
public lbool is_wide_char(LWCHAR ch);
public lbool is_omit_char(LWCHAR ch);
public lbool is_combining_char(LWCHAR ch1, LWCHAR ch2);
public void cmd_reset(void);
public void clear_cmd(void);
@@ -228,7 +231,9 @@ public void jump_loc(POSITION pos, int sline);
public void init_line(void);
public lbool is_ascii_char(LWCHAR ch);
public POSITION line_position(void);
public void prewind(void);
public lbool is_line_contig_pos(POSITION pos);
public void set_line_contig_pos(POSITION pos);
public void prewind(lbool contig);
public void plinestart(POSITION pos);
public int line_pfx_width(void);
public void pshift_all(void);
@@ -314,6 +319,7 @@ public void opt_wheel_lines(int type, constant char *s);
public void opt_linenum_width(int type, constant char *s);
public void opt_status_col_width(int type, constant char *s);
public void opt_filesize(int type, constant char *s);
public void opt_first_cmd_at_prompt(int type, constant char *s);
public void opt_intr(int type, constant char *s);
public int next_cnum(constant char **sp, constant char *printopt, constant char *errmsg, lbool *errp);
public void opt_header(int type, constant char *s);
@@ -343,6 +349,7 @@ public struct loption * findopt(int c);
public struct loption * findopt_name(constant char **p_optname, constant char **p_oname, lbool *p_ambig);
public char * findopts_name(constant char *pfx);
public void init_poll(void);
public lbool ttyin_ready(void);
public int supports_ctrl_x(void);
public ssize_t iread(int fd, unsigned char *buf, size_t len);
public int iopen(constant char *filename, int flags);
@@ -403,6 +410,7 @@ public lbool is_filtered(POSITION pos);
public POSITION next_unfiltered(POSITION pos);
public int is_hilited_attr(POSITION pos, POSITION epos, int nohide, int *p_matches);
public void chg_hilite(void);
public POSITION search_pos(int search_type);
public void osc8_search(int search_type, constant char *param, int matches);
public lbool osc8_click(int sindex, int col);
public void osc8_open(void);
@@ -439,7 +447,7 @@ public void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b);
public void xbuf_add_char(struct xbuffer *xbuf, char c);
public void xbuf_add_data(struct xbuffer *xbuf, constant unsigned char *data, size_t len);
public int xbuf_pop(struct xbuffer *buf);
public void xbuf_set(struct xbuffer *dst, struct xbuffer *src);
public void xbuf_set(struct xbuffer *dst, constant struct xbuffer *src);
public constant char * xbuf_char_data(constant struct xbuffer *xbuf);
public lbool help_ckd_add(void *r, uintmax a, uintmax b, int rsize, int rsigned);
public lbool help_ckd_mul(void *r, uintmax a, uintmax b, int rsize, int rsigned);
+1 -1
View File
@@ -1,4 +1,4 @@
/* This file was generated by mkhelp.pl from less.hlp at 19:46 on 2025/5/28 */
/* This file was generated by mkhelp.pl from less.hlp at 18:02 on 2025/10/4 */
#include "less.h"
constant char helpdata[] = {
'\n',
+43 -31
View File
@@ -96,6 +96,8 @@ public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, l
if (p_linepos != NULL)
*p_linepos = NULL_POSITION;
if (p_newline != NULL)
*p_newline = TRUE;
get_forw_line:
if (curr_pos == NULL_POSITION)
@@ -104,7 +106,7 @@ public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, l
return (NULL_POSITION);
}
#if HILITE_SEARCH
if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
if (hilite_search == OPT_ONPLUS || is_filtering() || (status_col && hilite_search != OPT_ON))
{
/*
* If we are ignoring EOI (command F), only prepare
@@ -142,39 +144,48 @@ public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, l
/*
* Read forward again to the position we should start at.
*/
prewind();
plinestart(base_pos);
(void) ch_seek(base_pos);
new_pos = base_pos;
while (new_pos < curr_pos)
if (is_line_contig_pos(curr_pos))
{
c = ch_forw_get();
if (c == EOI)
prewind(TRUE);
plinestart(base_pos);
ch_seek(curr_pos);
new_pos = curr_pos;
} else
{
prewind(FALSE);
plinestart(base_pos);
ch_seek(base_pos);
new_pos = base_pos;
while (new_pos < curr_pos)
{
null_line();
return (NULL_POSITION);
}
backchars = pappend((char) c, new_pos);
new_pos++;
if (backchars > 0)
{
pshift_all();
if (wordwrap && (c == ' ' || c == '\t'))
c = ch_forw_get();
if (c == EOI)
{
do
{
new_pos++;
c = ch_forw_get(); /* {{ what if c == EOI? }} */
} while (c == ' ' || c == '\t');
backchars = 1;
null_line();
return (NULL_POSITION);
}
backchars = pappend((char) c, new_pos);
new_pos++;
if (backchars > 0)
{
pshift_all();
if (wordwrap && (c == ' ' || c == '\t'))
{
do
{
new_pos++;
c = ch_forw_get(); /* {{ what if c == EOI? }} */
} while (c == ' ' || c == '\t');
backchars = 1;
}
new_pos -= backchars;
while (--backchars >= 0)
(void) ch_back_get();
}
new_pos -= backchars;
while (--backchars >= 0)
(void) ch_back_get();
}
pshift_all();
}
(void) pflushmbc();
pshift_all();
/*
* Read the first character to display.
@@ -329,6 +340,7 @@ public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, l
*p_linepos = curr_pos;
if (p_newline != NULL)
*p_newline = endline;
set_line_contig_pos(endline ? NULL_POSITION : new_pos);
return (new_pos);
}
@@ -358,6 +370,8 @@ public POSITION back_line(POSITION curr_pos, lbool *p_newline)
lbool skipped_leading;
get_back_line:
if (p_newline != NULL)
*p_newline = TRUE;
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
{
null_line();
@@ -426,7 +440,7 @@ public POSITION back_line(POSITION curr_pos, lbool *p_newline)
}
#if HILITE_SEARCH
if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
if (hilite_search == OPT_ONPLUS || is_filtering() || (status_col && hilite_search != OPT_ON))
prep_hilite(base_pos, NULL_POSITION, 1);
#endif
@@ -446,10 +460,8 @@ public POSITION back_line(POSITION curr_pos, lbool *p_newline)
return (NULL_POSITION);
}
endline = FALSE;
prewind();
prewind(FALSE);
plinestart(new_pos);
if (p_newline != NULL)
*p_newline = TRUE;
loop:
wrap_pos = NULL_POSITION;
skipped_leading = FALSE;
+4 -1
View File
@@ -216,7 +216,7 @@ void free();
* Special types and constants.
*/
typedef unsigned long LWCHAR;
#if defined(MINGW) || (defined(_MSC_VER) && _MSC_VER >= 1500)
#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1500)
typedef long long less_off_t; /* __int64 */
typedef struct _stat64 less_stat_t;
#define less_fstat _fstat64
@@ -435,6 +435,7 @@ typedef enum osc8_state {
#define AT_ANSI (1 << 4) /* Content-supplied "ANSI" escape sequence */
#define AT_BINARY (1 << 5) /* LESS*BINFMT representation */
#define AT_HILITE (1 << 6) /* Internal highlights (e.g., for search) */
#define AT_PLACEHOLDER (1 << 7) /* Placeholder for half of double-wide char */
#define AT_COLOR_SHIFT 8
#define AT_NUM_COLORS 16
@@ -554,6 +555,8 @@ typedef enum {
#define ESC CONTROL('[')
#define ESCS "\33"
#define CSI ((unsigned char)'\233')
#define VARSEL_15 ((LWCHAR)0xFE0E) /* VARIATION SELECTOR 15 */
#define VARSEL_16 ((LWCHAR)0xFE0F) /* VARIATION SELECTOR 16 */
#if _OSK_MWC32
#define LSIGNAL(sig,func) os9_signal(sig,func)
+88 -22
View File
@@ -1,5 +1,5 @@
'\" t
.TH LESS 1 "Version 679: 28 May 2025"
.TH LESS 1 "Version 685: 04 Oct 2025"
.SH NAME
less \- display the contents of a file in a terminal
.SH SYNOPSIS
@@ -203,8 +203,11 @@ Followed by another single quote, returns to the position at
which the last "large" movement command was executed.
Followed by a \(ha or $, jumps to the beginning or end of the
file respectively.
Marks are preserved when a new file is examined,
Marks are preserved when a new file is examined within a single invocation of
.BR less ,
so the \(aq command can be used to switch between input files.
The \-\-save-marks option causes marks to be preserved across different invocations of
.BR less .
.IP "\(haX\(haX"
Same as single quote.
.IP "ESC-m"
@@ -800,8 +803,9 @@ where the first integer specifies the foreground color and
the second specifies the background color.
Each integer is a value between 0 and 255 inclusive which selects
a "CSI 38;5" color value (see
.UR https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
.UE ).
.nh
https://en.wikipedia.org/wiki/ANSI_escape_code#SGR).
.hy
If either integer is a "-" or is omitted,
the corresponding color is set to that of normal text.
.PP
@@ -835,8 +839,9 @@ CHAR_INFO.Attributes
.hy
value, between 0 and 15 inclusive
(see
.UR https://learn.microsoft.com/en-us/windows/console/char-info-str
.UE ).
.nh
https://learn.microsoft.com/en-us/windows/console/char-info-str).
.hy
To avoid confusion, it is recommended that the equivalent letters rather than numbers
be used after a lowercase color selector on MS-DOS/Windows.
@@ -1213,8 +1218,9 @@ the name of a command compatible with
.BR global (1),
and that command is executed to find the tag.
(See
.UR http://www.gnu.org/software/global/global.html
.UE ).
.nh
http://www.gnu.org/software/global/global.html).
.hy
The \-t option may also be specified from within
.B less
(using the \- command) as a way of examining a new file.
@@ -1328,6 +1334,16 @@ of the screen, starting with a decimal point: \&.5 is half of the
screen width, \&.3 is three tenths of the screen width, and so on.
If the number is specified as a fraction, the actual number of
scroll positions is recalculated if the terminal window is resized.
.IP "\-\-cmd=\fIcommands\fP
The specified string is taken to be an initial command to
.BR less .
This is similar to specifying "+\fIcommands\fP", except that
commands specified by \-\-cmd are not executed if
.B less
exits immediately due to the use of the \-E or \-F option, while
commands specified by the \fB+\fP option are executed even if
.B less
exits immediately.
.IP "\-\-exit-follow-on-close"
When using the "F" command on a pipe,
.B less
@@ -1583,8 +1599,9 @@ Enables colored text in various places.
The \-D option can be used to change the colors.
Colored text works only if the terminal supports
ANSI color escape sequences (as defined in
.UR https://www.ecma-international.org/publications-and-standards/standards/ecma-48
.UE ).
.nh
https://www.ecma-international.org/publications-and-standards/standards/ecma-48).
.hy
.IP "\-\-wheel-lines=\fIn\fP"
Set the number of lines to scroll when the mouse wheel is scrolled
and the \-\-mouse or \-\-MOUSE option is in effect.
@@ -1598,6 +1615,9 @@ The default is to wrap at any character.
A command line argument of "\-\-" marks the end of option arguments.
Any arguments following this are interpreted as filenames.
This can be useful when viewing a file whose name begins with a "\-" or "+".
Otherwise, option arguments and filename arguments can be intermixed;
that is, option arguments do not need to appear before filename arguments,
unless the environment variable POSIXLY_CORRECT is set.
.IP +
If a command line option begins with \fB+\fP,
the remainder of that option is taken to be an initial command to
@@ -1613,6 +1633,7 @@ If the option starts with ++, the initial command applies to
every file being viewed, not just the first one.
The + command described previously
may also be used to set (or change) an initial command for every file.
Also see the \-\-cmd option.
.
.SH "LINE EDITING"
When entering a command line at the bottom of the screen
@@ -1913,7 +1934,7 @@ Again, in this case the dash is not considered to be part of
the input pipe command.
.
.SH "NATIONAL CHARACTER SETS"
There are three types of characters in the input file:
There are five types of characters in the input file:
.IP "normal characters"
can be displayed directly to the screen.
.IP "control characters"
@@ -1922,6 +1943,12 @@ in ordinary text files (such as backspace and tab).
.IP "binary characters"
should not be displayed directly and are not expected to be found
in text files.
.IP "composing characters"
are not displayed separately, but modify the display of the
preceding character. (Only when LESSCHARSET is "utf8".)
.IP "deleted characters"
are simply deleted from the input and not displayed.
(Only when LESSCHARSET is "utf8".)
.PP
A "character set" is simply a description of which characters are to
be considered normal, control, and binary.
@@ -2049,7 +2076,7 @@ of how the UTF-8 file is ill-formed.
.PP
When the character set is utf-8, in rare cases it may be desirable to
override the Unicode definition of the type of certain characters.
For example, characters in a Private Use Area are normally treated as control
For example, characters in a Private Use Area are normally treated as binary
characters, but if you are using a custom font with printable characters
in that range, it may be desirable to tell
.B less
@@ -2076,6 +2103,8 @@ A wide (2-space) printable character.
A binary (non-printable) character.
.IP "c"
A composing (zero width) character.
.IP "d"
A deleted character (deleted from the input and not displayed).
.RE
.PP
For example, setting LESSUTFCHARDEF to
@@ -2085,6 +2114,18 @@ For example, setting LESSUTFCHARDEF to
.sp
.fi
would make all Private Use Area characters be treated as printable.
.PP
By default, emoji modifiers, components and variation selectors
are deleted because many terminals do not display them correctly.
If you use a terminal which does display some or all of them correctly,
you can cause to be displayed by setting LESSUTFCHARDEF
to treat them as composing characters.
For example, this sets them all to composing characters:
.nf
.sp
FE00-FE0F:c,1F3FB-1F3FF:c,1F9B0-1F9B3:c,E0100-E01EF:c
.sp
.fi
.SH "PROMPTS"
The \-P option allows you to tailor the prompt to your preference.
The string given to the \-P option replaces the specified prompt string.
@@ -2407,8 +2448,8 @@ end character in an ANSI color escape sequence
(default "0123456789:;[?!"\(aq#%()*+\ ").
.IP LESSANSIOSCALLOW
A comma-separated list of OSC types which are output directly to the
terminal when \-R is in effect.
By default, only OSC 8 sequences are output directly.
terminal when \-R is in effect
(default "8"; that is, only OSC 8 sequences are output directly).
.IP LESSANSIOSCCHARS
Characters which may follow an ESC character to mark the start
of an "OS Command" sequence.
@@ -2480,9 +2521,7 @@ file. (Not used if "$LESSKEYIN_SYSTEM" exists.)
List of characters which are considered "metacharacters" by the shell.
.IP LESSMETAESCAPE
Prefix which less will add before each metacharacter in a
command sent to the shell.
If LESSMETAESCAPE is an empty string, commands containing
metacharacters will not be passed to the shell.
command sent to the shell (default "\\").
.IP LESSOPEN
Command line to invoke the (optional) input-preprocessor.
.IP LESSSECURE
@@ -2492,7 +2531,8 @@ See discussion under SECURITY.
Enables individual features which are normally disabled by LESSSECURE.
See discussion under SECURITY.
.IP LESSSEPARATOR
String to be appended to a directory name in filename completion.
String to be appended to a directory name in filename completion
(default "\\" on MS-DOS, Windows, and OS/2; otherwise "/").
.IP LESSUTFBINFMT
Format for displaying non-printable Unicode code points.
.IP LESSUTFCHARDEF
@@ -2550,6 +2590,24 @@ receives a SIGUSR1 signal.
.IP LESS_TERMCAP_xx
Where "xx" is any two characters, overrides the definition
of the termcap "xx" capability for the terminal.
.IP LESS_TERMCAP_BRACKETED_PASTE_START
Overrides the standard ANSI escape sequence to enable bracketed paste.
This is used when the \-\-no-paste option is in effect.
.IP LESS_TERMCAP_BRACKETED_PASTE_END
Overrides the standard ANSI escape sequence to disable bracketed paste.
.IP LESS_TERMCAP_MOUSE_START
Overrides the standard ANSI escape sequence to enable mouse reporting.
This is used when the \-\-mouse option is in effect.
.IP LESS_TERMCAP_MOUSE_END
Overrides the standard ANSI escape sequence to disable mouse reporting.
.IP LESS_TERMCAP_SUSPEND
Defines an escape sequence to temporarily suspend screen updates.
This is sent to the terminal before clearing the screen.
This can be used to avoid screen tearing when the screen is redrawn
on certain terminals.
.IP LESS_TERMCAP_RESUME
Defines an escape sequence to resume screen updates.
This is sent to the terminal after displaying the prompt.
.IP LESS_UNSUPPORT
A space-separated list of command line options.
These options will be ignored (with no error message) if they appear
@@ -2571,6 +2629,12 @@ automatically when running in
.IP PATH
User's search path (used to find a lesskey file
on MS-DOS, Windows, and OS/2 systems).
.IP POSIXLY_CORRECT
If set to any value, all option arguments on the command line
are expected to appear before any filename arguments.
This must be set as an actual environment variable, not in a
.B lesskey
file.
.IP SHELL
The shell used to execute the !\& command, as well as to expand filenames.
.IP TERM
@@ -2619,10 +2683,12 @@ See the GNU General Public License for more details.
Mark Nudelman
.br
Report bugs at
.UR https://github.com/gwsw/less/issues
.UE .
.nh
https://github.com/gwsw/less/issues.
.hy
.br
For more information, see the less homepage at
.br
.UR https://greenwoodsoftware.com/less
.UE .
.nh
https://greenwoodsoftware.com/less.
.hy
+2 -4
View File
@@ -1,4 +1,4 @@
.TH LESSECHO 1 "Version 679: 28 May 2025"
.TH LESSECHO 1 "Version 685: 04 Oct 2025"
.SH NAME
lessecho \- expand metacharacters
.SH SYNOPSIS
@@ -53,6 +53,4 @@ The default is that only arguments containing metacharacters are quoted.
This manual page was written by Thomas Schoepf <schoepf@debian.org>,
for the Debian GNU/Linux system (but may be used by others).
.PP
Report bugs at
.UR https://github.com/gwsw/less/issues
.UE .
Report bugs at https://github.com/gwsw/less/issues.
+13 -5
View File
@@ -1,5 +1,5 @@
'\" t
.TH LESSKEY 1 "Version 679: 28 May 2025"
.TH LESSKEY 1 "Version 685: 04 Oct 2025"
.SH NAME
lesskey \- customize key bindings for less
.SH "SYNOPSIS (deprecated)"
@@ -83,8 +83,10 @@ l l l.
\er RETURN (0x0D)
\et TAB (0x09)
.TE
.RE
.sp
\ek followed by a single character represents the char(s) produced when one of these keys is pressed:
.RS 5m
.TS
l l.
\ekb BACKSPACE (the BACKSPACE key)
@@ -105,7 +107,7 @@ l l.
\ekX ctrl-DELETE
\ek1 F1
.TE
.RE
.PP
A backslash followed by any other character indicates that character is
to be taken literally.
@@ -121,6 +123,14 @@ string is parsed, just as if it were typed in to
This feature can be used in certain cases to extend
the functionality of a command.
For example, see the "{" and ":t" commands in the example below.
It can also be used to execute more than one command when a key is pressed.
For example, if this line were in a lesskey file, pressing the "B" key
would first set the "b" mark and then search for the string "next":
.sp
.nf
B set-mark b/next\en
.fi
.sp
The extra string has a special meaning for the "quit" action:
when
.B less
@@ -486,6 +496,4 @@ See the GNU General Public License for more details.
.
Mark Nudelman
.br
Report bugs at
.UR https://github.com/gwsw/less/issues
.UE .
Report bugs at https://github.com/gwsw/less/issues.
+1 -1
View File
@@ -56,7 +56,7 @@
char ext[_MAX_EXT]; \
int handle;
#else
#if MSDOS_COMPILER==WIN32C && (defined(_MSC_VER) || defined(MINGW))
#if MSDOS_COMPILER==WIN32C && (defined(_MSC_VER) || defined(__MINGW32__))
#define GLOB_FIRST_NAME(filename,fndp,h) h = _findfirst(filename, fndp)
#define GLOB_FIRST_FAILED(handle) ((handle) == -1)
+95 -11
View File
@@ -28,6 +28,7 @@ static struct {
int *attr; /* Parallel to buf, to hold attributes */
size_t print; /* Index in buf of first printable char */
size_t end; /* Number of chars in buf */
size_t prev_end; /* Number of chars in buf for previous line */
char pfx[MAX_PFX_WIDTH]; /* Holds status column and line number */
int pfx_attr[MAX_PFX_WIDTH];
size_t pfx_end; /* Number of chars in pfx */
@@ -63,6 +64,7 @@ public int ntabstops = 1; /* Number of tabstops */
public int tabdefault = 8; /* Default repeated tabstops */
public POSITION highest_hilite; /* Pos of last hilite in file found so far */
static POSITION line_pos;
static POSITION line_contig_pos = NULL_POSITION; /* One after last byte processed */
static int end_column; /* Printable length, accounting for backspaces, etc. */
static int right_curr;
@@ -254,13 +256,43 @@ public POSITION line_position(void)
return line_pos;
}
/*
* Is this byte the next one after the previous byte processed?
*/
public lbool is_line_contig_pos(POSITION pos)
{
return pos == line_contig_pos;
}
/*
* Set the position of the next byte to be processed.
*/
public void set_line_contig_pos(POSITION pos)
{
line_contig_pos = pos;
}
/*
* Copy any ANSI sequences from line buffer to shifted_ansi.
*/
static void pshift(size_t end)
{
size_t i;
for (i = linebuf.print; i < end; i++)
if (linebuf.attr[i] == AT_ANSI)
xbuf_add_char(&shifted_ansi, linebuf.buf[i]);
}
/*
* Rewind the line buffer.
*/
public void prewind(void)
public void prewind(lbool contig)
{
int ax;
xbuf_reset(&shifted_ansi);
if (contig && linebuf.prev_end != 0)
pshift(linebuf.prev_end);
linebuf.print = 6; /* big enough for longest UTF-8 sequence */
linebuf.pfx_end = 0;
for (linebuf.end = 0; linebuf.end < linebuf.print; linebuf.end++)
@@ -285,7 +317,6 @@ public void prewind(void)
clear_after_line = FALSE;
line_mark_attr = 0;
line_pos = NULL_POSITION;
xbuf_reset(&shifted_ansi);
xbuf_reset(&last_ansi);
for (ax = 0; ax < NUM_LAST_ANSIS; ax++)
xbuf_reset(&last_ansis[ax]);
@@ -431,10 +462,7 @@ public int line_pfx_width(void)
*/
public void pshift_all(void)
{
size_t i;
for (i = linebuf.print; i < linebuf.end; i++)
if (linebuf.attr[i] == AT_ANSI)
xbuf_add_char(&shifted_ansi, linebuf.buf[i]);
pshift(linebuf.end);
linebuf.end = linebuf.print;
end_column = (int) linebuf.pfx_end; /*{{type-issue}}*/
line_pos = NULL_POSITION;
@@ -517,6 +545,12 @@ public int pwidth(LWCHAR ch, int a, LWCHAR prev_ch, int prev_a)
}
} else
{
if (ch == VARSEL_15)
/* If prev char was double width, make it single width. */
return (prev_ch != 0 && pwidth(prev_ch, a, 0, 0) == 2) ? -1 : 0;
if (ch == VARSEL_16)
/* If prev char was single width, make it double width. */
return (prev_ch != 0 && pwidth(prev_ch, a, 0, 0) == 1) ? +1 : 0;
if (is_composing_char(ch) || is_combining_char(prev_ch, ch))
{
/*
@@ -814,6 +848,7 @@ static int store_char(LWCHAR ch, int a, constant char *rep, POSITION pos)
size_t replen;
char cs;
int ov;
lbool need_shift;
ov = (a & (AT_UNDERLINE|AT_BOLD));
if (ov != AT_NORMAL)
@@ -899,14 +934,41 @@ static int store_char(LWCHAR ch, int a, constant char *rep, POSITION pos)
add_linebuf((char) shifted_ansi.data[i], AT_ANSI, 0);
xbuf_reset(&shifted_ansi);
}
if (linebuf.end == linebuf.print+1)
{
/* If first char is a placeholder, the one before it is double-width.
* VS15 changes the double-width char to single-width, so replace the
* placeholder with this VS15. */
if (ch == VARSEL_15 && (linebuf.attr[linebuf.end-1] & AT_PLACEHOLDER))
{
linebuf.end--;
inc_end_column(-1);
}
} else if (linebuf.end == linebuf.print)
{
/* VS16 changes the previous single-width char to double-width.
* Add a placeholder to represent the second half of the
* double-width char. */
if (ch == VARSEL_16)
{
char *p = &linebuf.buf[linebuf.end];
LWCHAR prev_ch = (linebuf.end > 0) ? step_char(&p, -1, linebuf.buf) : 0;
if (prev_ch != 0 && pwidth(prev_ch, a, 0, 0) == 1)
add_linebuf(' ', rscroll_attr|AT_PLACEHOLDER, 0);
}
}
}
/* Add the char to the buf, even if we will left-shift it next. */
need_shift = (cshift < hshift);
if (!need_shift && w <= 0 && linebuf.end <= linebuf.print+1 && is_composing_char(ch) &&
(linebuf.end == linebuf.print || (linebuf.end == linebuf.print+1 && (linebuf.attr[linebuf.end-1] & AT_PLACEHOLDER))))
need_shift = TRUE;
inc_end_column(w);
for (i = 0; i < replen; i++)
add_linebuf(*rep++, a, 0);
if (cshift < hshift)
if (need_shift)
{
/* We haven't left-shifted enough yet. */
if (a == AT_ANSI)
@@ -929,7 +991,7 @@ static int store_char(LWCHAR ch, int a, constant char *rep, POSITION pos)
*/
while (cshift > hshift)
{
add_linebuf(' ', rscroll_attr, 0);
add_linebuf(' ', rscroll_attr|AT_PLACEHOLDER, 0);
cshift--;
}
}
@@ -1267,6 +1329,17 @@ static int do_append(LWCHAR ch, constant char *rep, POSITION pos)
overstrike = 0;
}
if (is_omit_char(ch))
{
if (bs_mode == BS_CONTROL)
{
if (utf_mode)
STORE_STRING(prutfchar(ch), AT_BINARY, pos);
else
STORE_PRCHAR(ch, pos);
}
return (0); /* omit the character. */
}
if (ch == '\t')
{
/*
@@ -1340,6 +1413,7 @@ static void add_attr_normal(void)
public void pdone(lbool endline, lbool chopped, lbool forw)
{
(void) pflushmbc();
linebuf.prev_end = (!endline && !chopped) ? linebuf.end : 0;
if (pendc && (pendc != '\r' || !endline))
/*
@@ -1509,7 +1583,11 @@ static void col_vs_pos(POSITION linepos, mutable struct col_pos *cp, POSITION sa
LWCHAR wch = get_wchar(utf8_buf);
int attr = 0; /* {{ ignoring attribute is not correct for magic cookie terminals }} */
utf8_len = 0;
if (utf_mode && ctldisp != OPT_ON && is_ubin_char(wch))
if (is_omit_char(wch))
{
if (bs_mode == BS_CONTROL)
cw = strlen(utf_mode ? prutfchar(wch) : prchar(wch));
} else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(wch))
cw = (int) strlen(prutfchar(wch));
else
cw = pwidth(wch, attr, prev_ch, attr);
@@ -1638,6 +1716,7 @@ public POSITION forw_raw_line_len(POSITION curr_pos, size_t read_len, constant c
(c = ch_forw_get()) == EOI)
return (NULL_POSITION);
set_line_contig_pos(NULL_POSITION);
n = 0;
for (;;)
{
@@ -1693,6 +1772,7 @@ public POSITION back_raw_line(POSITION curr_pos, constant char **linep, size_t *
ch_seek(curr_pos-1))
return (NULL_POSITION);
set_line_contig_pos(NULL_POSITION);
n = size_linebuf;
linebuf.buf[--n] = '\0';
for (;;)
@@ -1804,11 +1884,14 @@ static int pappstr(constant char *str)
public void load_line(constant char *str)
{
int save_hshift = hshift;
hshift = 0;
/* We're overwriting the line buffer, so what's in it will no longer be contiguous. */
set_line_contig_pos(NULL_POSITION);
for (;;)
{
prewind();
prewind(FALSE);
if (pappstr(str) == 0)
break;
/*
@@ -1819,6 +1902,7 @@ public void load_line(constant char *str)
hshift += 1;
}
set_linebuf(linebuf.end, '\0', AT_NORMAL);
linebuf.prev_end = 0;
/* Color the prompt unless it has ansi sequences in it. */
if (!ansi_in_line)
+1 -1
View File
@@ -19,7 +19,7 @@
#if MSDOS_COMPILER
#include <dos.h>
#if MSDOS_COMPILER==WIN32C && defined(MINGW)
#if MSDOS_COMPILER==WIN32C && defined(__MINGW32__)
#include <direct.h>
#define setdisk(n) _chdrive((n)+1)
#else
+29 -12
View File
@@ -17,7 +17,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if defined(MINGW) || defined(_MSC_VER)
#if defined(__MINGW32__) || defined(_MSC_VER)
#include <locale.h>
#include <shellapi.h>
#endif
@@ -78,7 +78,7 @@ extern int redraw_on_quit;
extern int term_init_done;
extern lbool first_time;
#if MSDOS_COMPILER==WIN32C && (defined(MINGW) || defined(_MSC_VER))
#if MSDOS_COMPILER==WIN32C && (defined(__MINGW32__) || defined(_MSC_VER))
/* malloc'ed 0-terminated utf8 of 0-terminated wide ws, or null on errors */
static char *utf8_from_wide(constant wchar_t *ws)
{
@@ -247,8 +247,14 @@ int main(int argc, constant char *argv[])
{
IFILE ifile;
constant char *s;
int i;
struct xbuffer xfiles;
constant int *files;
size_t num_files;
lbool end_opts = FALSE;
lbool posixly_correct = FALSE;
#if MSDOS_COMPILER==WIN32C && (defined(MINGW) || defined(_MSC_VER))
#if MSDOS_COMPILER==WIN32C && (defined(__MINGW32__) || defined(_MSC_VER))
if (GetACP() != CP_UTF8) /* not using a UTF-8 manifest */
try_utf8_locale(&argc, &argv);
#endif
@@ -318,13 +324,20 @@ int main(int argc, constant char *argv[])
#define isoptstring(s) less_is_more ? (((s)[0] == '-') && (s)[1] != '\0') : \
(((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0')
while (argc > 0 && (isoptstring(*argv) || isoptpending()))
xbuf_init(&xfiles);
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
for (i = 0; i < argc; i++)
{
s = *argv++;
argc--;
if (strcmp(s, "--") == 0)
break;
scan_option(s, FALSE);
if (strcmp(argv[i], "--") == 0)
end_opts = TRUE;
else if (!end_opts && (isoptstring(argv[i]) || isoptpending()))
scan_option(argv[i], FALSE);
else
{
if (posixly_correct)
end_opts = TRUE;
xbuf_add_data(&xfiles, (constant unsigned char *) &i, sizeof(i));
}
}
#undef isoptstring
@@ -364,7 +377,9 @@ int main(int argc, constant char *argv[])
ifile = NULL_IFILE;
if (dohelp)
ifile = get_ifile(FAKE_HELPFILE, ifile);
while (argc-- > 0)
files = (constant int *) xfiles.data;
num_files = xfiles.end / sizeof(int);
for (i = 0; i < num_files; i++)
{
#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
/*
@@ -378,7 +393,7 @@ int main(int argc, constant char *argv[])
char *gfilename;
char *qfilename;
gfilename = lglob(*argv++);
gfilename = lglob(argv[files[i]]);
init_textlist(&tlist, gfilename);
filename = NULL;
while ((filename = forw_textlist(&tlist, filename)) != NULL)
@@ -390,10 +405,12 @@ int main(int argc, constant char *argv[])
}
free(gfilename);
#else
(void) get_ifile(*argv++, ifile);
(void) get_ifile(argv[files[i]], ifile);
ifile = prev_ifile(NULL_IFILE);
#endif
}
xbuf_deinit(&xfiles);
/*
* Set up terminal, etc.
*/
+20 -1
View File
@@ -22,6 +22,17 @@ my %force_space = (
0x0d => 1, # carriage return
);
# Override Unicode tables for certain modifier chars which act differently
# on different terminals. Treat them as omittable.
my @force_omit = (
[0xad, 0xad], # SOFT HYPHEN
[0x200d, 0x200d], # ZERO WIDTH JOINER
[0x1f3fb, 0x1f3ff], # EMOJI MODIFIER FITZPATRICK TYPE-[1-6]
[0x1f9b0, 0x1f9b3], # EMOJI COMPONENT [RED,CURLY,BALD,WHITE] HAIR
[0xfe00, 0xfe0f], # VARIATION SELECTOR-[1-16]
[0xe0100, 0xe01ef], # VARIATION SELECTOR-[17-256]
);
# Hangul Jamo medial vowels and final consonants should be zero width.
my @force_compose = (
[0x1160, 0x11ff],
@@ -51,6 +62,13 @@ sub main {
$force_compose{$ch} = 1;
}
}
my %force_omit;
foreach my $comp (@force_omit) {
my ($lo,$hi) = @$comp;
for (my $ch = $lo; $ch <= $hi; ++$ch) {
$force_omit{$ch} = 1;
}
}
my ($sec,$min,$hour,$mday,$mon,$year) = gmtime($ENV{SOURCE_DATE_EPOCH} // time());
my @month = ( "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" );
@@ -88,7 +106,8 @@ sub main {
$type =~ s/\s//g;
for ($last_code = $lo_code; $last_code <= $hi_code; ++$last_code) {
output(\%out, $last_code,
$force_space{$last_code} ? 'Zs' : $force_compose{$last_code} ? 'Mn' : $type);
$force_space{$last_code} ? 'Zs' : $force_compose{$last_code} ? 'Mn' :
$force_omit{$last_code} ? 'Xx' : $type);
}
}
output(\%out, $last_code);
+7
View File
@@ -0,0 +1,7 @@
/* Generated by "./mkutable -f2 Xx -- unicode/UnicodeData.txt" on Aug 19 1:16:32 GMT 2025 */
{ 0x00ad, 0x00ad }, /* Xx */
{ 0x200d, 0x200d }, /* Xx */
{ 0xfe00, 0xfe0f }, /* Xx */
{ 0x1f3fb, 0x1f3ff }, /* Xx */
{ 0x1f9b0, 0x1f9b3 }, /* Xx */
{ 0xe0100, 0xe01ef }, /* Xx */
+18
View File
@@ -72,6 +72,7 @@ extern int nosearch_header_lines;
extern int nosearch_header_cols;
extern POSITION header_start_pos;
extern char *init_header;
extern char *first_cmd_at_prompt;
#if LOGFILE
extern char *namelogfile;
extern lbool force_logfile;
@@ -973,6 +974,23 @@ public void opt_filesize(int type, constant char *s)
}
}
/*
* Handler for the --cmd option.
*/
/*ARGSUSED*/
public void opt_first_cmd_at_prompt(int type, constant char *s)
{
switch (type)
{
case INIT:
case TOGGLE:
first_cmd_at_prompt = save(s);
break;
case QUERY:
break;
}
}
/*
* Handler for the --intr option.
*/
+6
View File
@@ -86,6 +86,7 @@ public int no_edit_warn; /* Don't warn when editing a LESSOPENed file */
public int stop_on_form_feed; /* Stop scrolling on a line starting with form feed */
public long match_shift_fraction = NUM_FRAC_DENOM/2; /* 1/2 of screen width */
public char intr_char = CONTROL('X'); /* Char to interrupt reads */
public char *first_cmd_at_prompt = NULL; /* Command to exec before first prompt */
#if HILITE_SEARCH
public int hilite_search; /* Highlight matched search patterns? */
#endif
@@ -184,6 +185,7 @@ static struct optname proc_backspace_optname = { "proc-backspace", NULL };
static struct optname proc_tab_optname = { "proc-tab", NULL };
static struct optname proc_return_optname = { "proc-return", NULL };
static struct optname match_shift_optname = { "match-shift", NULL };
static struct optname first_cmd_at_prompt_optname = { "cmd", NULL };
#if LESSTEST
static struct optname ttyin_name_optname = { "tty", NULL };
#endif /*LESSTEST*/
@@ -748,6 +750,10 @@ static struct loption option[] =
"Print carriage return as ^M"
}
},
{ OLETTER_NONE, &first_cmd_at_prompt_optname,
O_STRING|O_NO_TOGGLE|O_NO_QUERY, 0, NULL, opt_first_cmd_at_prompt,
{ NULL, NULL, NULL }
},
{ OLETTER_NONE, &match_shift_optname,
O_STRING|O_INIT_HANDLER, 0, NULL, opt_match_shift,
{
+44 -7
View File
@@ -43,7 +43,7 @@ extern int errno;
#include <sys/utsname.h>
#endif
#if HAVE_POLL && !MSDOS_COMPILER
#if HAVE_POLL && !MSDOS_COMPILER && !defined(__MVS__)
#define USE_POLL 1
static lbool use_poll = TRUE;
#else
@@ -82,6 +82,7 @@ static lbool opening;
public lbool waiting_for_data;
public int consecutive_nulls = 0;
public lbool getting_one_screen = FALSE;
public lbool no_poll = FALSE;
/* Milliseconds to wait for data before displaying "waiting for data" message. */
static int waiting_for_data_delay = 4000;
@@ -163,7 +164,8 @@ static int check_poll(int fd, int tty)
/* Break out of "waiting for data". */
return (READ_INTR);
ungetcc_back((char) ch);
return (READ_INTR);
if (!no_poll)
return (READ_INTR);
}
}
if (ignore_eoi && exit_F_on_close && (poller[0].revents & (POLLHUP|POLLIN)) == POLLHUP)
@@ -177,6 +179,36 @@ static int check_poll(int fd, int tty)
}
#endif /* USE_POLL */
/*
* Is a character available to be read from the tty?
*/
public lbool ttyin_ready(void)
{
#if MSDOS_COMPILER==WIN32C
return win32_kbhit();
#else
#if MSDOS_COMPILER
return kbhit();
#else
#if USE_POLL
#if LESSTEST
if (is_lesstest())
return FALSE;
#endif /*LESSTEST*/
if (!use_poll)
return FALSE;
{
struct pollfd poller[1] = { { tty, POLLIN, 0 } };
poll(poller, 1, 0);
return ((poller[0].revents & POLLIN) != 0);
}
#else
return FALSE;
#endif
#endif
#endif
}
public int supports_ctrl_x(void)
{
#if MSDOS_COMPILER==WIN32C
@@ -282,16 +314,21 @@ public ssize_t iread(int fd, unsigned char *buf, size_t len)
}
#else
#if MSDOS_COMPILER==WIN32C
if (win32_kbhit2(TRUE))
if (!(quit_if_one_screen && one_screen) && win32_kbhit2(TRUE))
{
int c;
lbool intr;
c = WIN32getch();
sigs |= S_SWINTERRUPT;
reading = FALSE;
if (c != CONTROL('C') && c != intr_char)
intr = (c == CONTROL('C') || c == intr_char);
if (!intr)
WIN32ungetch((char) c);
return (READ_INTR);
if (intr || !no_poll)
{
sigs |= S_SWINTERRUPT;
reading = FALSE;
return (READ_INTR);
}
}
#endif
#endif
+6 -1
View File
@@ -469,7 +469,12 @@ public lbool match_pattern(PATTERN_TYPE pattern, constant char *tpattern, consta
lbool matched = match_pattern1(pattern, tpattern, line, line_len, line_off, sp, ep, nsp, notbol, search_type);
if (!matched || subsearch_ok(sp, ep, search_type))
return matched;
mlen = ep[0] - line;
/* We have a match, but it does not satisfy all SUBSEARCH conditions.
* Continue searching after this match. */
mlen = ptr_diff(ep[0], line);
if (mlen == 0)
/* If the match is empty, we can't progress. */
return FALSE;
line += mlen;
line_len -= mlen;
notbol = 1;
+30
View File
@@ -221,6 +221,8 @@ static constant char
*sc_e_mousecap, /* End mouse capture mode */
*sc_s_bracketed_paste, /* Start bracketed paste mode */
*sc_e_bracketed_paste, /* End bracketed paste mode */
*sc_suspend, /* Suspend screen updates */
*sc_resume, /* Resume screen updates */
*sc_init, /* Startup terminal initialization */
*sc_deinit; /* Exit terminal de-initialization */
@@ -1330,6 +1332,13 @@ public void get_term(void)
if (sc_e_bracketed_paste == NULL)
sc_e_bracketed_paste = ESCS"[?2004l";
sc_suspend = ltgetstr("SUSPEND", &sp);
if (sc_suspend == NULL)
sc_suspend = "";
sc_resume = ltgetstr("RESUME", &sp);
if (sc_resume == NULL)
sc_resume = "";
sc_init = ltgetstr("ti", &sp);
if (sc_init == NULL)
sc_init = "";
@@ -1755,6 +1764,26 @@ public void deinit_mouse(void)
#endif
}
/*
* Suspend screen updates.
*/
public void suspend_screen(void)
{
#if !MSDOS_COMPILER
ltputs(sc_suspend, 1, putchr);
#endif
}
/*
* Resume screen updates.
*/
public void resume_screen(void)
{
#if !MSDOS_COMPILER
ltputs(sc_resume, 1, putchr);
#endif
}
/*
* Initialize terminal
*/
@@ -2341,6 +2370,7 @@ public void bell(void)
public void clear(void)
{
assert_interactive();
suspend_screen();
#if !MSDOS_COMPILER
ltputs(sc_clear, sc_height, putchr);
#else
+8 -4
View File
@@ -52,6 +52,7 @@ static POSITION prep_endpos;
public POSITION header_start_pos = NULL_POSITION;
static POSITION header_end_pos;
public lbool search_wrapped = FALSE;
public POSITION search_incr_start = NULL_POSITION;
#if OSC8_LINK
public POSITION osc8_linepos = NULL_POSITION;
public POSITION osc8_match_start = NULL_POSITION;
@@ -1083,7 +1084,7 @@ public void chg_hilite(void)
/*
* Figure out where to start a search.
*/
static POSITION search_pos(int search_type)
public POSITION search_pos(int search_type)
{
POSITION pos;
int sindex;
@@ -1189,6 +1190,7 @@ static lbool matches_filters(POSITION pos, char *cline, size_t line_len, int *ch
struct hilite hl;
hl.hl_startpos = linepos;
hl.hl_endpos = pos;
hl.hl_attr = 0;
add_hilite(&filter_anchor, &hl);
free(cline);
free(chpos);
@@ -2118,7 +2120,8 @@ public int search(int search_type, constant char *pattern, int n)
/*
* Figure out where to start the search.
*/
pos = search_pos(search_type);
pos = ((search_type & SRCH_INCR) && search_incr_start != NULL_POSITION) ?
search_incr_start : search_pos(search_type);
opos = position(sindex_from_sline(jump_sline));
if (pos == NULL_POSITION)
{
@@ -2241,7 +2244,7 @@ public void prep_hilite(POSITION spos, POSITION epos, int maxlines)
*/
clr_hilite();
clr_filter();
nprep_startpos = spos;
nprep_startpos = nprep_endpos = spos;
} else
{
/*
@@ -2282,7 +2285,7 @@ public void prep_hilite(POSITION spos, POSITION epos, int maxlines)
result = search_range(spos, epos, search_type, 0, maxlines, (POSITION*)NULL, &new_epos, (POSITION*)NULL);
if (result < 0)
return;
if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
if (nprep_endpos == NULL_POSITION || new_epos > nprep_endpos)
nprep_endpos = new_epos;
/*
@@ -2300,6 +2303,7 @@ public void prep_hilite(POSITION spos, POSITION epos, int maxlines)
if (epos == NULL_POSITION)
break;
maxlines = 1;
nprep_endpos = epos;
continue;
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Cc Cs Co Zl Zp -- unicode/UnicodeData.txt" on Oct 1 18:10:07 GMT 2024 */
/* Generated by "./mkutable -f2 Cc Cs Co Zl Zp -- unicode/UnicodeData.txt" on Aug 19 1:16:32 GMT 2025 */
{ 0x0000, 0x0007 }, /* Cc */
{ 0x000b, 0x000b }, /* Cc */
{ 0x000e, 0x001f }, /* Cc */
+13 -1
View File
@@ -1049,6 +1049,18 @@ v677 4/27/25 Fix & filtering bug.
v678 5/1/25 Don't change stty tab setting.
v679 5/28/25 Fix lesskey parsing bug when env var is prefix of another;
fix unexpected exit when using -K.
v680 6/25/25 Fix hang if a search using ^S modifier matches empty string.
v681 8/2/25 Fix bug using -g with -J; fix bug when pasting input
with --incsearch; improve performance with long lines;
fix performance with & filtering; change search position when
using --incsearch; treat some composing chars as binary.
v682 8/24/25 Add --cmd; fix lesskey bug using #stop; fix lesskey bug
using "invalid"; fix some emoji bugs.
v683 9/4/25 Fix bug if cmd char received during file read.
v684 9/18/25 Allow mixing of options and filenames on command line;
add LESS_TERMCAP_SUSPEND & LESS_TERMCAP_RESUME.
v685 10/4/25 Make --incsearch return to same column as well as same line;
fix some problems reported by valgrind.
*/
char version[] = "679";
char version[] = "685";
+5 -3
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f1 W F -- unicode/EastAsianWidth.txt" on Sep 23 19:46:51 GMT 2024 */
/* Generated by "./mkutable -f1 W F -- unicode/EastAsianWidth.txt" on Aug 10 20:15:03 GMT 2025 */
{ 0x1100, 0x115f }, /* W */
{ 0x231a, 0x231b }, /* W */
{ 0x2329, 0x232a }, /* W */
@@ -93,7 +93,8 @@
{ 0x1f3cf, 0x1f3d3 }, /* W */
{ 0x1f3e0, 0x1f3f0 }, /* W */
{ 0x1f3f4, 0x1f3f4 }, /* W */
{ 0x1f3f8, 0x1f43e }, /* W */
{ 0x1f3f8, 0x1f3fa }, /* W */
{ 0x1f400, 0x1f43e }, /* W */
{ 0x1f440, 0x1f440 }, /* W */
{ 0x1f442, 0x1f4fc }, /* W */
{ 0x1f4ff, 0x1f53d }, /* W */
@@ -114,7 +115,8 @@
{ 0x1f7f0, 0x1f7f0 }, /* W */
{ 0x1f90c, 0x1f93a }, /* W */
{ 0x1f93c, 0x1f945 }, /* W */
{ 0x1f947, 0x1f9ff }, /* W */
{ 0x1f947, 0x1f9af }, /* W */
{ 0x1f9b4, 0x1f9ff }, /* W */
{ 0x1fa70, 0x1fa7c }, /* W */
{ 0x1fa80, 0x1fa89 }, /* W */
{ 0x1fa8f, 0x1fac6 }, /* W */
+1 -1
View File
@@ -86,7 +86,7 @@ public int xbuf_pop(struct xbuffer *buf)
/*
* Set an xbuf to the contents of another xbuf.
*/
public void xbuf_set(struct xbuffer *dst, struct xbuffer *src)
public void xbuf_set(struct xbuffer *dst, constant struct xbuffer *src)
{
xbuf_reset(dst);
xbuf_add_data(dst, src->data, src->end);