Compare commits

...
Author SHA1 Message Date
Colin Percival 4099b5c828 Update in preparation for 14.5-RELEASE
- Bump BRANCH to RELEASE
- Add the anticipated RELEASE announcement date
- Set a static __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-09-04 00:00:00 +00:00
Mark Johnston 813eb5a497 devstat: Fix a kernel stack disclosure
The 16-byte "device_name" field was not zero-filled, so could contain
uninitialized stack data.  Zero the whole struct, as that's the
prevailing pattern for this kind of conversion code, and it's more
robust in the face of future revisions to struct devstat.

Approved by:	re (cperciva)
Reviewed by:	olce, kib
Reported by:	Reo Shiseki
Fixes:		a11d132f6c ("devstat: Provide 32-bit compatibility")
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D59309

(cherry picked from commit 7cb1a76f88)
(cherry picked from commit 6e94e0734b)
2026-09-03 15:45:57 -07:00
Colin Percival 151d7a8cb1 14.5: Update to RC1
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-08-27 17:07:50 -07:00
Colin Percival b503d9e219 Switch from "quarterly" to "release" pkgs on DVD
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-08-27 16:55:40 -07:00
Colin Percival 1f20ac6a3d Revert "Remove minor version from kmods repo"
We now have kmod repositories built on releng/14.5 for amd64, arm64,
and i386.

This reverts commit 19a1025e1c.

Approved by:	re (cperciva)
2026-08-27 16:28:00 -07:00
Dag-Erling Smørgrav 5805e0ec88 install: Fix two bugs in stdin code
* Fix case where the source is - and the target exists.

* Only call chflags() (to remove flags that might prevent us from
  replacing an existing target) in the exists case; otherwise,
  to_sb.st_flags is uninitialized.

* Rename the source file in the stdin test case.

* Extend null and stdin test cases to cover the case where the
  target already exists.

Approved by:	re (cperciva)
PR:		297681
MFC after:	1 week
Fixes:		d34870708d ("install: Allow installing stdin")
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D59144

(cherry picked from commit a5ff4125cf)
(cherry picked from commit 203438d0a3)
2026-08-27 16:27:54 -07:00
Mark Johnston 9c7f4633c5 posixshm: Fix a TOCTOU race in the FIOSSHMLPGCNF handler
The check for whether shm_lp_psind was assigned was unlocked.  This race
can be exploited to create an object with psind==2 but with only
pagesizes[1] worth of pages populated.  This in turn can be used to
escalate privileges.

Fix this by acquiring the rangelock earlier.  In shm_mmap_large(),
assert that we hold the rangelock.  In shm_write(), annotate an unlocked
load of shm_lp_psind.

Approved by:	re (cperciva)
Approved by:	so
Security:	FreeBSD-SA-26:63.posixshm
Security:	CVE-2026-58094
Reported by:	tsune of GMO Cybersecurity by Ierae, Inc. working with TrendAI Zero Day Initiative
Reviewed by:	kib
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D59104
2026-08-24 19:04:38 +00:00
Mark Johnston 1aefa1fab9 tty: Revalidate after dropping the tty lock in ioctl handlers
The TIOCSCTTY ioctl handler drops the tty lock in order to acquire the
proctree relock.  After relocking the tty, it did not revalidate the
tty state, and it could end up linking a doomed tty to the calling
process' session.  This race can be exploited to escalate privileges.

TIOCSPGRP has a similar race, fix that too.

Approved by:	re (cperciva)
Approved by:	so
Security:	FreeBSD-SA-26:62.tty
Security:	CVE-2026-58093
Reported by:	tsune of GMO Cybersecurity by Ierae, Inc. working with TrendAI Zero Day Initiative
Reviewed by:	kib
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D59126
2026-08-24 19:04:32 +00:00
Gordon Tetlow b9cac4b178 openssl: Fix multiple vulnerabilities
This is a rollup commit from upstream to fix:
  Avoid full read buffer allocation when buffering DTLS records
  ssl/record: lower the DTLS unprocessed_rcds queue limit
  Fix heap buffer overflow (8-byte OOB write) in AES-WRAP-PAD unwrap
  Add a test for restricting growth in cmp cert cache
  Fix unbounded cert cache growth in cmp
  Fix Remote NULL deref in ossl_cmp_calc_protection() via crafted protectionAlg

Approved by:	re (cperciva)
Approved by:	so
Obtained from:	OpenSSL
Security:	FreeBSD-SA-26:61.openssl
Security:	CVE-2026-54874
Security:	CVE-2026-63072
Security:	CVE-2026-63074
Security:	CVE-2026-63076
2026-08-24 19:04:13 +00:00
Mark Johnston c086ed0cc5 ppp: Fix a buffer overflow in the endpoint discriminator set command
Approved by:	re (cperciva)
Reported by:	Reo Shiseki
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D59054

(cherry picked from commit 6cb7e368da)
(cherry picked from commit 55ee29bf35)
2026-08-24 19:03:48 +00:00
Mark Johnston 514ef2fdfc dsp: Fix a potential use-after-free in dsp_oss_syncstart()
This function has a loop where it attempts to lock all channels in a
group.  If doing so would block, it releases all locks, sleeps for a
bit, and tries again.  However, once the syncgroup lock is dropped,
nothing prevents the syncgroup structure from being freed.

Fix the inner loop: after waking up, break out of it unconditionally and
start everything again.  I think the old code was also buggy and not
well-exercised: after waking up we'd continue to try and continue
locking channels.  Then we'd try again from the beginning and fail to
lock the channels we had already locked.

Approved by:	re (cperciva)
Approved by:	so
Security:	FreeBSD-SA-26:58.sound
Security:	CVE-2026-58091
Reported by:	Hazley Samsudin of GovTech CSG
Reviewed by:	christos
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58912
2026-08-24 19:03:06 +00:00
Mark Johnston 77528485e8 hwpmc: Fix the execve handler
When a process execve()s, pmc_process_exec() is supposed to evaluate
whether the new image is setuid/setgid and if so, whether to detach
PMCs.  This was handled by pmc_can_attach(), which is effectively an
open-coded copy of cr_xids_subset().

Unfortunately, the test of the result of this function was inverted,
with the result that we'd detach PMCs only if the predicate said it was
okay to do so.  It appears the bug has always been there; it seems the
intent was to return 0 on "success", i.e., it is okay to attach the
PMCs, much like p_candebug().  Commits 1c3c698ba4 and 1c40b15971
obscured this a bit.

I think this check is trying to be too clever.  Let's make it simpler:
simply do not attach PMCs unless the owner is privileged.  This is how,
e.g., ktrace works.  I do not think it's worth trying to be more
sophisticated than this unless we can generalize the policy in a way
that's applicable to other subsystems.

Also fix a bug at the end of pmc_process_exec():
pmc_detach_one_process() will call pmc_remove_process_descriptor() for
us.

Approved by:	re (cperciva)
Approved by:	so
Security:	FreeBSD-SA-26:56.hwpmc
Security:	CVE-2026-58089
Reported by:	netchild
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D59102
2026-08-24 19:02:58 +00:00
Colin Percival 03c50e6573 15.1: Update to BETA3
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-08-20 17:01:48 -07:00
Mark Johnston bdfae0fed8 epoch: Fix epoch_drain_callbacks()
This function is supposed to wait until all pending callbacks have been
executed.  This is useful in some contexts where we tear down some
context (like a VNET jail and its associated UMA zones) synchronously,
and we want to make sure that all pending asynchronous callbacks (which
may free objects to said UMA zones) have run first.

The implementation schedules a callback on each CPU and waits for them
all to run.  This assumes that, on a given CPU, callbacks are executed
in the order that they are pushed.  This assumption depends on the
implementation of epoch_call_task() and ck_epoch_poll_deferred(), and it
is not true in general.

Callbacks are pushed onto a per-CPU stack in LIFO order.
ck_epoch_poll_deferred() first pulls out the callbacks from epoch - 2,
which are always safe to execute, and in so doing reorders them such
that the oldest callback as at the top of the stack, so in this case,
epoch_call_task() will execute them in order.  However,
ck_epoch_poll_deferred() may determine that it is safe to execute
callbacks from epoch - 1 (or even from the current epoch if there are
no active readers), and in this case it will push those callbacks onto
the returned stack.  This means that epoch_call_task() will invoke those
newer destructors before the older ones, which means that
epoch_drain_callbacks() may return early.

Fix the correctness problem by simply doing all of this twice: once the
first callback is invoked, we know that all of the callbacks that were
pending at the time that epoch_drain_callbacks() was called are
scheduled to be executed, so when the second callback is executed we
know that they must be finished.  This is slow, but it is already slow,
and the slowness is less noticeable after commit dce5659499.

I note that in an ideal world, this function would not exist, and all of
the teardown would happen asynchronously, rather than the current
mismash of synchronous and asynchronous cleanup.

Approved by:	re (cperciva)
PR:		290201
Reviewed by:	glebius
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D58030

(cherry picked from commit 7bf11a2f0c)
(cherry picked from commit 8eef466432)
2026-08-20 10:53:07 -07:00
Mark Johnston eddae793c8 ctl.4: Document the assumption that CTL HA runs only on trusted networks
The CTL High Availablity clustering feature allows a pair of hosts to
implement transparent failover.  The implementation uses a TCP
connection to exchange messages.  There is no authentication mechanism
and the protocol itself embeds kernel pointers in the messages exchanged
between HA hosts.  This property (of CTL_MSG_DATAMOVE messages
specifically), as well as insufficient validation of inbound messages,
mean that anyone able to access a CTL HA port is able to remotely
execute code on that host.

Provide a warning to this effect in the CTL man page.

Approved by:	re (cperciva)
Reported by:	Ryan of Calif.io
Reviewed by:	ziaee, ken, mav
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58622

(cherry picked from commit 3c8f8432b6)
(cherry picked from commit 43a34002f6)
2026-08-20 10:53:04 -07:00
Mark Johnston 10dd09ca4c ppp: Reject invalid endpoint discriminator options
Per RFC1717 section 5.1.3, the option length must be at least three.
Processing an undersized option would trigger a large out-of-bounds
write.

Approved by:	re (cperciva)
PR:		271910
Reported by:	Robert Morris
Reported by:	Décio Brandão (0xDBJ)
Reviewed by:	emaste
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58554

(cherry picked from commit b9d07a4308)
(cherry picked from commit 30b4bdd451)
2026-08-20 10:53:01 -07:00
Mark Johnston 281fb7d8a2 ppp: Avoid overflow when formatting endpoint discriminator options
Each byte of the address is represented by a pair of characters, so we
should be multiplying len by 2 when figuring out how much buffer space
we have.  Previously, a sufficiently large option could cause an
overflow of the global "result" buffer.

Approved by:	re (cperciva)
Reported by:	Joshua Rogers <[email protected]>
Tested by:	Décio Brandão (0xDBJ)
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58555

(cherry picked from commit e004ff15f8)
(cherry picked from commit 607c41d8f8)
2026-08-20 10:52:58 -07:00
Mark Johnston 43bbea2cc8 proc: Copy the p_reapsubtree field explicitly during fork
p_reapsubtree lives in the p_startcopy/p_endcopy block of struct proc,
which is copied during fork without any synchronization.  However, the
field is not stable except when the proctree lock is held, and indeed
may change if p1's reaper exits or explicitly releases its reaper
status.  This state change can race with fork() and leave the child with
an incorrect p_reapsubtree field.

Close the race: explicitly copy the field under the proctree lock during
fork.

Approved by:	re (cperciva)
Reported by:	syzkaller
Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58482

(cherry picked from commit 8616b7dc38)
(cherry picked from commit fb0af871db)
2026-08-20 10:52:55 -07:00
Mark Johnston dde557209a rawip: Fix handling of checksums in rip6_input()
A v6 raw socket may ask the kernel to validate the checksum of an
inbound packet.  If it does, and the validation fails, we discard the
packet, but this isn't really right: other raw sockets may wish to
receive a copy of the packet anyway.

Rework checksum handling to address this problem, and use a flag to
avoid computing the checksum more than once for a given packet.

Approved by:	re (cperciva)
Fixes:		de2d47842e ("SMR protection for inpcbs")
Reviewed by:	pouria, glebius
Reported by:	Yunzhi Ke
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D58559

(cherry picked from commit 196874ce2e)
(cherry picked from commit 1fe3a2897b)
2026-08-20 10:52:51 -07:00
Mark Johnston 9c5f81332b in_mcast: Fix uninitialized variable usage in inm_merge()
When the first loop in inm_merge() hits an error, generally because it
hit some limit on the number of source filters for a multicast group,
inm_merge() tries to atomically roll back changes to the group source
filter list.

To roll back, it iterates over the global source filter list for the
multicast group, starting at the last entry that we updated ("nims").
But, if we have not yet updated any entries, this variable is
uninitialized.  Initialize it to NULL, so that RB_FOREACH_REVERSE_FROM
doesn't visit any source filters in this case.

All of the above applies to the v6 case.

Approved by:	re (cperciva)
Reported by:	Daniel Birtwhistle
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit b9db5a5b16)
(cherry picked from commit 843ef89615)
2026-08-20 10:52:45 -07:00
Xin LI 7cc6a5d464 MFV: less v704.
(cherry picked from commit fa0dc4f0f9)
(cherry picked from commit 86aea5b4db)

Approved by:	re (cperciva)
2026-08-18 13:17:56 -07:00
Xin LI 3a1396af29 MFV less v691
Relnotes:	yes

(cherry picked from commit dafba19e42)

MFV: less v692.

(cherry picked from commit e2abec625b)
(cherry picked from commit 6330c2f5fb)

Approved by:	re (cperciva)
2026-08-18 13:17:45 -07:00
Eric van Gyzen 31c2290fc1 if_vmx: fix panic during kldload
Just like vmxnet3_intr_disable_all, iflib may invoke this routine
before vmxnet3_attach_post() has run, which is before the top-level
shared data area is initialized and the device made aware of it.

Approved by:	re (cperciva)
PR:		294312
Sponsored by:	Dell Inc.

(cherry picked from commit 01b0690c49)
(cherry picked from commit 065396e09e)
2026-08-17 18:27:46 -07:00
Konstantin Belousov 2f580cc4c2 netipsec/xform_ipcomp.c: fix sockaddr type set in ipcomp6_nonexp_encapcheck()
Approved by:	re (cperciva)

(cherry picked from commit 01d4e3c1d3)
(cherry picked from commit 3626363aae)
2026-08-17 18:27:43 -07:00
Konstantin Belousov feecef8df3 PF_KEY socket: limit the length of copied socket address
Approved by:	re (cperciva)
PR:	297264

(cherry picked from commit cba481a7bf)
(cherry picked from commit 022f935a1f)
2026-08-17 18:27:38 -07:00
Konstantin Belousov 8ca6be06ee netipsec/key.c::key_checksockaddrs(): constify src/dst address buffer pointers
Approved by:	re (cperciva)

(cherry picked from commit fbe9aa7ebf)
(cherry picked from commit af11a69e53)
2026-08-17 18:26:43 -07:00
Colin Percival 19a1025e1c Remove minor version from kmods repo
We don't have a kmods_quarterly_5 repo for releng/14.5 so don't point
users at it.

Direct commit to releng/14.5, hopefully to be reverted once the repo
exists.

Approved by:	re (cperciva)
Sponsored by:	OpenSats Initiative
2026-08-13 17:02:24 -07:00
Colin Percival 8bca5d0c0d 14.5: Update to BETA2
Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-08-14 00:00:00 +00:00
Colin Percival c33f8dd282 Revert "sys/socket.h: Fix AF_MAX"
Back out this change for 14.5-BETA2.  It might come back with
changes, but in its current form it breaks ABI.

This reverts commit f77a60a27a.

Approved by:	re (cperciva)
2026-08-13 16:44:33 -07:00
Dag-Erling Smørgrav 2cc2d2f64f pseudofs: Don't purge the cache on shutdown
This is a waste of time and results in a use-after-free if linsysfs is
loaded and a USB network interface is in use, since USB devices are
disconnected at shutdown, which triggers a call into linsysfs, which
then tries to destroy a pseudofs node which has already been purged.

Approved by:	re (cperciva)
MFC after:	1 week
Reviewed by:	glebius
Differential Revision:	https://reviews.freebsd.org/D58359

(cherry picked from commit 4ebcdb8dd9)
(cherry picked from commit ea65604407)
2026-08-13 16:44:11 -07:00
Dag-Erling Smørgrav c555236ec7 unbound: Update to 1.26.0
Release notes at
        https://community.nlnetlabs.nl/t/unbound-1-26-0-released

Merge commit '84ffc29dc8ddb0c946db5cb3b3c1310bec6a9e6c'

Approved by:	re (cperciva)

(cherry picked from commit 7a789145f8)
(cherry picked from commit ceb764f65d)
2026-08-13 16:44:00 -07:00
Enji Cooper a9a5c96f55 crypto/openssl: correct version numbers for pkg-config files
The files were incorrectly reporting 3.5.1 instead of 3.0.21.

This is a direct commit to stable/14 as stable/15 and later are on
OpenSSL 3.5.

Approved by:	re (cperciva)
PR:	297144
Fixes:	d03be8cf ("crypto/openssl: make vendor imports easier/less error prone")
(cherry picked from commit 2e04d98688)
2026-08-12 17:08:42 -07:00
Dag-Erling Smørgrav fbe0d8aa64 mbuf: Parenthesize macro arguments
Approved by:	re (cperciva)
MFC after:	1 week
Sponsored by:	Klara, Inc.
Sponsored by:	NetApp, Inc.

(cherry picked from commit 744cc51456)
(cherry picked from commit 7d8fc2a82b)
2026-08-12 17:08:37 -07:00
Dag-Erling Smørgrav f77a60a27a sys/socket.h: Fix AF_MAX
AF_MAX was always intended to be one more than the greatest allocated
value.  Jeff broke this in 2013.  Unfortunately, a bunch of people then
decided to adapt to the mistake instead of correcting it.

Approved by:	re (cperciva)
Fixes:          863c7e4562 (" - Reserve a special AF for SDP.  The one we were incorrectly using before    was taken by another AF.")
MFC after:	3 days
Sponsored by:	Klara, Inc.
Sponsored by:	NetApp, Inc.
Reviewed by:	kevans, glebius
Differential Revision:	https://reviews.freebsd.org/D58597

(cherry picked from commit ddd850aa77)
(cherry picked from commit 2d25276471)
2026-08-12 17:08:29 -07:00
Konstantin Belousov ce139f7da0 geom_zero(4): reset the uio vector on each uiomove()
PR:	297062

Approved by:	re (cperciva)

(cherry picked from commit 34ca5a9e73)
(cherry picked from commit 51f5623874)
2026-08-12 17:08:18 -07:00
Colin Percival f68ca7c41d Revert "release: Ship firmware from kmods repo on DVD"
This was a good idea, but we don't build metapackages in the kmods
repo so it ends up breaking the release build.  I might resurrect this
change if/when the kmods repo includes the wifi-firmware-kmod
metapackage.

This reverts commit bda8028146.

MFC after:	1 second
Approved by:	re (cperciva)

(cherry picked from commit ca0cff7932)
(cherry picked from commit daf81f32f8)
2026-08-07 08:55:00 -07:00
Colin Percival 187da1388d 14.5: create releng/14.5 branch
Update from PRERELEASE to BETA1
Switch pkg(8) configuration to use the quarterly repositories
Bump __FreeBSD_version to 1405000

Approved by:	re (implicit)
Sponsored by:	OpenSats Initiative
2026-08-07 00:00:00 +00:00
225 changed files with 18186 additions and 11648 deletions

No files matched your search

+3
View File
@@ -12,6 +12,9 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
20260908:
14.5-RELEASE.
20260727:
The wait_for_pids() function in rc.subr, used by rc scripts
when stopping or restarting a service, has been modified to
+1 -1
View File
@@ -2,7 +2,7 @@
------------
Less
Copyright (C) 1984-2025 Mark Nudelman
Copyright (C) 1984-2026 Mark Nudelman
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
+209
View File
@@ -9,6 +9,215 @@
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
* Revert HOME key to scroll to beginning of file and END key
to scroll to end of file (github #658).
* Configure tty to leave CR and NL unmodified (github #703).
* Add commands to lesskey parser (forw-bell-hilite, goto-pos and osc8-jump).
* Add key sequences to lesskey parser (\kE, \kF, \kH, \kI, \kM, and \kS).
* Fix bug using negative value with -z option (github #709).
* Fix bug handling empty terminfo capabilties (github #710).
* Fix memory leak in setupterm (github #707).
* Make lesstest ignore system locale (nl_langinfo) (github #708).
======================================================================
Major changes between "less" versions 685 and 691
* Add --autosave option (github #678).
* Add ESC-f command (github #680).
* Add column number to long prompt and = message.
* Add prompt prototype sequences %C, %W, %Q and ?Q (github #685).
* Map keypad keys, and use terminfo rather than termcap since keypad
definitions don't exist in termcap (github #650).
* Change HOME key to scroll fully left and END key to scroll fully right.
Add shift-HOME and ctrl-HOME to scroll left and jump to top, and
add shift-END and ctrl-END to scroll right and jump to end (github #658).
* Add LESSNOCONFIG environment variable.
* Add --without-termlib to configure (github #701).
* When setting line number colors (-DN), don't force bold attribute.
To set bold, you must append "d" or "*" to the color string (github #684).
* While waiting for file data, only ^C or ^X will interrupt, not any command.
This reverts to behavior that existed before less-670 (github #700).
* When --save-marks is not used, retain any marks saved in the history file
(github #662).
* Defer sending the terminal init string until the first char is read
from the input file (github #682).
* Make SIGHUP do an orderly exit like SIGTERM.
* Implement modeline handling in Windows build.
* Fix bugs and improve behavior of screen resize on Windows.
* Fix bug when entering search modifier key at start of non-empty
search string (github #668).
* Fix bug repainting screen with --form-feed (github #672).
* Fix bugs passing invalid negative values to some command line
options (github #675).
* Fix incorrect display of Lit indicator (github #670).
* Fix incorrect display when returning to a mark after resizeing window
(github #681).
* Fix bug using --pattern with --incsearch (github #696).
* Disallow mouse click to open OSC8 link in SECURE mode (github #676).
* Add SECURE_COMPILE environment variable for Windows builds.
* Update Unicode tables.
======================================================================
Major changes between "less" versions 679 and 685
+21 -41
View File
@@ -84,7 +84,7 @@ INSTALLATION (Unix & Linux systems only):
Makefile now. Take particular notice of the list of "terminal"
libraries in the LIBS definition in the Makefile; these may need
to be edited. The terminal libraries will be some subset of
-lncurses -lcurses -ltermcap -ltermlib
-ltinfo -ltinfow -lxcurses -lncursesw -lncurses -lcurses -ltermcap -ltermlib
If you wish, you may edit defines.h to remove some optional features.
If you choose not to include some features in your version, you may
@@ -108,12 +108,27 @@ 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,
with Microsoft Visual C++, mingw, or Borland C)
1. Move the distributed source to its own directory.
2. If you wish, you may edit defines.wn to remove some optional features.
If you choose not to include some features in your version, you may
wish to edit the manual page less.man and the help page help.c
to remove the descriptions of the features which you are removing.
3. If you are using Microsoft Visual C++, run "nmake -f Makefile.wnm".
If you are using mingw, run "make -f Makefile.wng".
If you are using Borland C, run "make -f Makefile.wnb".
If the environment variable SECURE_COMPILE is to 1 during the make,
a "secure" version of less is built, with some features disabled.
4. If the make succeeds, it will generate the programs "less.exe" and
"lesskey.exe" in your current directory. Test the generated programs.
@@ -156,34 +171,6 @@ INSTALLATION (MS-DOS systems only,
=======================================================================
INSTALLATION (Windows-95, Windows-98 and Windows-NT systems only,
with Borland C or Microsoft Visual C++)
1. Move the distributed source to its own directory.
2. If you are using Borland C, rename Makefile.wnb to Makefile.
If you are using Microsoft Visual C++, rename Makefile.wnm to Makefile.
3. Check the Makefile to make sure the definitions look ok.
4. If you wish, you may edit defines.wn to remove some optional features.
If you choose not to include some features in your version, you may
wish to edit the manual page less.man and the help page help.c
to remove the descriptions of the features which you are removing.
5. Type "make" and watch the fun.
6. If the make succeeds, it will generate the programs "less.exe" and
"lesskey.exe" in your current directory. Test the generated programs.
7. When satisfied that it works, if you wish to install it
in a public place, type "make install".
See step 6 of the Unix installation instructions for details
on how to change the default installation directories.
=======================================================================
INSTALLATION (OS/2 systems only,
with EMX C)
@@ -245,10 +232,3 @@ INSTALLATION (OS-9 systems only,
See step 6 of the Unix installation instructions for details
on how to change the default installation directories.
=======================================================================
ACKNOWLEDGMENTS:
Some versions of the less distribution are packaged using
Info-ZIP's compression utility.
Info-ZIP's software is free and can be obtained as source
code or executables from various anonymous-ftp sites,
including ftp.uu.net:/pub/archiving/zip.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+13 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -22,7 +22,8 @@
typedef POSITION BLOCKNUM;
public int ignore_eoi;
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
@@ -883,13 +885,13 @@ public void ch_init(int f, int flags, ssize_t nread)
*/
ch_fsize = (flags & CH_HELPFILE) ? size_helpdata : filesize(ch_file);
/*
* This is a kludge to workaround a Linux kernel bug: files in some
* pseudo filesystems like /proc and tracefs have a size of 0 according
* to fstat() but have readable data.
*/
if (ch_fsize == 0 && nread > 0)
{
/*
* This is a kludge to workaround a Linux kernel bug: files in some
* pseudo filesystems like /proc and tracefs have a size of 0 according
* to fstat() but have readable data.
*/
ch_flags |= CH_NOTRUSTSIZE;
}
+33 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -202,20 +202,20 @@ static void ichardef_utf(constant char *s)
switch (*s++)
{
case 'b':
xbuf_add_data(&user_ubin_array, (unsigned char *) &range, sizeof(range));
xbuf_add_data(&user_ubin_array, &range, sizeof(range));
break;
case 'c':
xbuf_add_data(&user_compose_array, (unsigned char *) &range, sizeof(range));
xbuf_add_data(&user_compose_array, &range, sizeof(range));
break;
case 'd':
xbuf_add_data(&user_omit_array, (unsigned char *) &range, sizeof(range));
xbuf_add_data(&user_omit_array, &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));
xbuf_add_data(&user_wide_array, &range, sizeof(range));
xbuf_add_data(&user_prt_array, &range, sizeof(range));
break;
case 'p': case '.':
xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
xbuf_add_data(&user_prt_array, &range, sizeof(range));
break;
case '\0':
s--;
@@ -429,13 +429,21 @@ static void set_charset(void)
/*
* Try using the codeset name as the charset name.
*/
s = nl_langinfo(CODESET);
if (icharset(s, 1))
return;
#if LESSTEST
/*
* Don't check nl_langinfo in lesstest mode; charset should come
* only from environment variables, not from the system locale.
*/
if (0) /* {{ unfortunately it's too early to use is_lesstest }} */
#endif
{
s = nl_langinfo(CODESET);
if (icharset(s, 1))
return;
}
#endif
#endif
#if HAVE_STRSTR
/*
* Check whether LC_ALL, LC_CTYPE or LANG look like UTF-8 is used.
*/
@@ -448,7 +456,6 @@ static void set_charset(void)
if (icharset("utf-8", 1))
return;
}
#endif
#if HAVE_LOCALE
/*
@@ -578,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. */
@@ -601,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)
@@ -897,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) &&
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -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
+28 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -86,6 +86,9 @@
#define A_OSC8_JUMP 74
#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
@@ -155,4 +158,28 @@
#define SK_BACKTAB 15
#define SK_CTL_BACKSPACE 16
#define SK_BACKSPACE 17
#define SK_PAD_U 18
#define SK_PAD_D 19
#define SK_PAD_R 20
#define SK_PAD_L 21
#define SK_PAD_UR 22
#define SK_PAD_UL 23
#define SK_PAD_DR 24
#define SK_PAD_DL 25
#define SK_PAD_CENTER 26
#define SK_PAD_STAR 27
#define SK_PAD_SLASH 28
#define SK_PAD_DASH 29
#define SK_PAD_PLUS 30
#define SK_PAD_DOT 31
#define SK_PAD_COMMA 32
#define SK_PAD_ZERO 33
#define SK_SHIFT_HOME 34
#define SK_SHIFT_END 35
#define SK_CTL_HOME 36
#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
+84 -60
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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,7 +23,7 @@
extern int sc_width;
extern int utf_mode;
extern int no_hist_dups;
extern int marks_modified;
extern lbool marks_modified;
extern int no_paste;
public lbool pasting = FALSE;
@@ -35,6 +35,9 @@ static int cmd_offset; /* Index into cmdbuf of first displayed char */
static lbool literal; /* Next input char should not be interpreted */
static size_t updown_match; /* Prefix length in up/down movement */
static lbool have_updown_match = FALSE;
#if LESS_INSERT_MODE
static lbool insert_mode = TRUE;
#endif
static int cmd_complete(int action);
/*
@@ -110,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;
/*
@@ -189,7 +192,7 @@ public int len_cmdbuf(void)
*/
public lbool cmdbuf_empty(void)
{
return cp == cmdbuf && cmd_mbc_buf_len == 0;
return cmdbuf[0] == '\0' && cmd_mbc_buf_len == 0;
}
/*
@@ -454,39 +457,6 @@ static int cmd_left(void)
return (CC_OK);
}
/*
* Insert a char into the command buffer, at the current position.
*/
static int cmd_ichar(constant char *cs, size_t clen)
{
char *s;
if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1)
{
/* No room in the command buffer for another char. */
bell();
return (CC_ERROR);
}
/*
* Make room for the new character (shift the tail of the buffer right).
*/
for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--)
s[clen] = s[0];
/*
* Insert the character into the buffer.
*/
for (s = cp; s < cp + clen; s++)
*s = *cs++;
/*
* Reprint the tail of the line from the inserted char.
*/
have_updown_match = FALSE;
cmd_repaint(cp);
cmd_right();
return (CC_OK);
}
/*
* Backspace in the command buffer.
* Delete the char to the left of the cursor.
@@ -502,7 +472,7 @@ static int cmd_erase(void)
* Backspace past beginning of the buffer:
* this usually means abort the command.
*/
return (CC_QUIT);
return CC_QUIT;
}
/*
* Move cursor left (to the char being erased).
@@ -532,7 +502,7 @@ static int cmd_erase(void)
* to abort the current command, if CF_QUIT_ON_ERASE is set.
*/
if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0')
return (CC_QUIT);
return CC_QUIT;
return (CC_OK);
}
@@ -554,6 +524,43 @@ static int cmd_delete(void)
return (CC_OK);
}
/*
* Insert a char into the command buffer, at the current position.
*/
static int cmd_ichar(constant char *cs, size_t clen)
{
char *s;
if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1)
{
/* No room in the command buffer for another char. */
lbell();
return (CC_ERROR);
}
#if LESS_INSERT_MODE
if (!insert_mode)
cmd_delete();
#endif
/*
* Make room for the new character (shift the tail of the buffer right).
*/
for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--)
s[clen] = s[0];
/*
* Insert the character into the buffer.
*/
for (s = cp; s < cp + clen; s++)
*s = *cs++;
/*
* Reprint the tail of the line from the inserted char.
*/
have_updown_match = FALSE;
cmd_repaint(cp);
cmd_right();
return (CC_OK);
}
/*
* Delete the "word" to the left of the cursor.
*/
@@ -612,7 +619,7 @@ static int cmd_kill(void)
if (cmdbuf[0] == '\0')
{
/* Buffer is already empty; abort the current command. */
return (CC_QUIT);
return CC_QUIT;
}
cmd_offset = 0;
cmd_home();
@@ -625,7 +632,7 @@ static int cmd_kill(void)
* to abort the current command, if CF_QUIT_ON_ERASE is set.
*/
if (curr_cmdflags & CF_QUIT_ON_ERASE)
return (CC_QUIT);
return CC_QUIT;
return (CC_OK);
}
@@ -660,7 +667,7 @@ static int cmd_updown(int action)
/*
* The current command has no history list.
*/
bell();
lbell();
return (CC_OK);
}
@@ -705,7 +712,7 @@ static int cmd_updown(int action)
/*
* We didn't find a history entry that matches.
*/
bell();
lbell();
return (CC_OK);
}
@@ -796,6 +803,15 @@ public void cmd_addhist(struct mlist *mlist, constant char *cmd, lbool modified)
* Thus, an UPARROW will always retrieve the previous command.
*/
mlist->curr_mp = ml->next;
if (modified)
{
if (mlist == &mlist_search && autosave_action('/'))
save_cmdhist();
#if SHELL_ESCAPE || PIPEC
else if (mlist == &mlist_shell && autosave_action('!'))
save_cmdhist();
#endif
}
#endif
}
@@ -904,6 +920,9 @@ static int cmd_edit(char c, lbool stay_in_completion)
return (CC_OK);
case EC_INSERT:
not_in_completion();
#if LESS_INSERT_MODE
insert_mode = !insert_mode;
#endif
return (CC_OK);
case EC_BACKSPACE:
not_in_completion();
@@ -914,7 +933,7 @@ static int cmd_edit(char c, lbool stay_in_completion)
case EC_ABORT:
not_in_completion();
(void) cmd_kill();
return (CC_QUIT);
return CC_QUIT;
case EC_W_BACKSPACE:
not_in_completion();
return (cmd_werase());
@@ -950,17 +969,23 @@ static int cmd_istr(constant char *str)
{
constant char *endline = str + strlen(str);
constant char *s;
int action;
int action = CC_OK;
#if LESS_INSERT_MODE
lbool save_insert_mode = insert_mode;
insert_mode = TRUE;
#endif
for (s = str; *s != '\0'; )
{
constant char *os = s;
step_charc(&s, +1, endline);
action = cmd_ichar(os, ptr_diff(s, os));
if (action != CC_OK)
return (action);
break;
}
return (CC_OK);
#if LESS_INSERT_MODE
insert_mode = save_insert_mode;
#endif
return (action);
}
/*
@@ -1171,7 +1196,7 @@ static int cmd_complete(int action)
#endif /* TAB_COMPLETE_FILENAME */
if (tk_text == NULL)
{
bell();
lbell();
return (CC_OK);
}
if (action == EC_EXPAND)
@@ -1239,7 +1264,7 @@ static int cmd_complete(int action)
fail:
in_completion = FALSE;
bell();
lbell();
return (CC_OK);
}
@@ -1281,7 +1306,7 @@ static int cmd_uchar(char c, size_t *plen)
} else
{
/* UTF8_INVALID or stray UTF8_TRAIL */
bell();
lbell();
return (CC_ERROR);
}
} else if (IS_UTF8_TRAIL(c))
@@ -1293,19 +1318,19 @@ static int cmd_uchar(char c, size_t *plen)
{
/* complete, but not well formed (non-shortest form), sequence */
cmd_mbc_buf_len = 0;
bell();
lbell();
return (CC_ERROR);
}
} else
{
/* Flush incomplete (truncated) sequence. */
cmd_mbc_buf_len = 0;
bell();
lbell();
/* Handle new char. */
goto retry;
}
*plen = (size_t) cmd_mbc_buf_len; /*{{type-issue}}*/
*plen = cmd_mbc_buf_len;
cmd_mbc_buf_len = 0;
}
return (CC_PASS);
@@ -1388,7 +1413,6 @@ public LINENUM cmd_int(mutable long *frac)
{
constant char *p;
LINENUM n = 0;
lbool err;
for (p = cmdbuf; *p >= '0' && *p <= '9'; p++)
{
@@ -1401,8 +1425,8 @@ public LINENUM cmd_int(mutable long *frac)
*frac = 0;
if (*p++ == '.')
{
*frac = getfraction(&p, NULL, &err);
/* {{ do something if err is set? }} */
/* {{ Just ignore error in fractional part. }} */
(void) getfraction(&p, frac);
}
return (n);
}
@@ -1447,7 +1471,7 @@ static int mlist_size(struct mlist *ml)
static char * histfile_find(lbool must_exist)
{
constant char *home = lgetenv("HOME");
char *name = NULL;
char *name;
/* Try in $XDG_STATE_HOME, then in $HOME/.local/state, then in $XDG_DATA_HOME, then in $HOME. */
#if OS2
@@ -1738,7 +1762,7 @@ public void save_cmdhist(void)
int skip_shell;
struct save_ctx ctx;
constant char *s;
FILE *fout = NULL;
FILE *fout;
int histsize = 0;
if (!secure_allow(SF_HISTORY) || !histfile_modified())
+177 -94
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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,16 +23,17 @@
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;
extern int wscroll;
extern int top_scroll;
extern int ignore_eoi;
extern lbool ignore_eoi;
extern int hshift;
extern int bs_mode;
extern int proc_backspace;
@@ -48,14 +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 lbool no_poll;
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
@@ -66,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;
@@ -86,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;
@@ -154,7 +158,7 @@ static void start_mca(int action, constant char *prompt, void *mlist, int cmdfla
set_mlist(mlist, cmdflags);
}
public int in_mca(void)
public lbool in_mca(void)
{
return (mca != 0 && mca != A_PREFIX);
}
@@ -209,7 +213,7 @@ static void mca_search1(void)
cmd_putstr("/");
else
cmd_putstr("?");
forw_prompt = 0;
forw_prompt = FALSE;
}
static void mca_search(void)
@@ -249,7 +253,7 @@ static void mca_opt_toggle(void)
cmd_putstr("!");
break;
}
forw_prompt = 0;
forw_prompt = FALSE;
set_mlist(NULL, CF_OPTION);
}
@@ -476,7 +480,7 @@ static int mca_opt_nonfirst_char(char c)
}
} else if (!ambig)
{
bell();
lbell();
}
return (MCA_MORE);
}
@@ -575,7 +579,10 @@ static int mca_search_char(char c)
*/
if (!cmdbuf_empty() || literal_char)
{
lbool was_literal_char = literal_char;
literal_char = FALSE;
if (was_literal_char)
mca_search1();
return (NO_MCA);
}
@@ -639,6 +646,17 @@ static int mca_search_char(char c)
return (NO_MCA);
}
/*
* Jump back to the starting position of an incremental search.
*/
static void jump_search_incr_pos(void)
{
if (search_incr_pos.pos == NULL_POSITION)
return;
hshift = search_incr_hshift;
jump_loc(search_incr_pos.pos, search_incr_pos.ln);
}
/*
* Handle a character of a multi-character command.
*/
@@ -772,30 +790,21 @@ static int mca_char(char c)
if (*pattern == '\0')
{
/* User has backspaced to an empty pattern. */
undo_search(1);
hshift = search_incr_hshift;
jump_loc(search_incr_pos.pos, search_incr_pos.ln);
undo_search(TRUE);
jump_search_incr_pos();
} 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);
undo_search(TRUE);
jump_search_incr_pos();
}
no_poll = FALSE;
}
/* Redraw the search prompt and search string. */
if (is_screen_trashed() || !full_screen)
{
clear();
lclear();
repaint();
}
mca_search1();
@@ -846,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))
clear();
/*
* If nothing is displayed yet, display starting from initial_scrpos.
*/
@@ -864,9 +867,9 @@ static void make_display(void)
} else if (is_screen_trashed() || !full_screen)
{
int save_top_scroll = top_scroll;
int save_ignore_eoi = ignore_eoi;
lbool save_ignore_eoi = ignore_eoi;
top_scroll = 1;
ignore_eoi = 0;
ignore_eoi = FALSE;
if (is_screen_trashed() == 2)
{
/* Special case used by ignore_eoi: re-open the input file
@@ -880,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)
{
@@ -900,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);
/*
@@ -917,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);
@@ -928,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))
{
@@ -954,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;
}
/*
@@ -1135,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);
}
/*
@@ -1287,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)
{
@@ -1304,29 +1348,31 @@ static void multi_search(constant char *pattern, int n, int silent)
/*
* Forward forever, or until a highlighted line appears.
*/
static int forw_loop(int until_hilite)
static int forw_loop(int action)
{
POSITION curr_len;
POSITION prev_hilite;
if (ch_getflags() & CH_HELPFILE)
return (A_NOACTION);
cmd_exec();
jump_forw_buffered();
curr_len = ch_length();
highest_hilite = until_hilite ? curr_len : NULL_POSITION;
ignore_eoi = 1;
highest_hilite = prev_hilite = 0;
ignore_eoi = TRUE;
while (!sigs)
{
if (until_hilite && highest_hilite > curr_len)
if (action != A_F_FOREVER && highest_hilite > prev_hilite)
{
bell();
break;
lbell();
if (action == A_F_UNTIL_HILITE)
break;
prev_hilite = highest_hilite;
}
make_display();
forward(1, FALSE, FALSE, FALSE);
}
ignore_eoi = 0;
highest_hilite = NULL_POSITION;
ignore_eoi = FALSE;
ch_set_eof();
/*
@@ -1334,7 +1380,7 @@ static int forw_loop(int until_hilite)
* a non-abort signal (e.g. window-change).
*/
if (sigs && !ABORT_SIGS())
return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER);
return (action);
return (A_NOACTION);
}
@@ -1342,7 +1388,7 @@ static int forw_loop(int until_hilite)
/*
* Ignore subsequent (pasted) input chars.
*/
public void start_ignoring_input()
public void start_ignoring_input(void)
{
ignoring_input = TRUE;
#if HAVE_TIME
@@ -1353,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;
@@ -1401,7 +1447,6 @@ public void commands(void)
#endif
search_type = SRCH_FORW;
wscroll = (sc_height + 1) / 2;
newaction = A_NOACTION;
for (;;)
@@ -1438,6 +1483,8 @@ public void commands(void)
c = getcc();
again:
if (c == READ_AGAIN)
continue;
if (sigs)
continue;
@@ -1507,7 +1554,9 @@ public void commands(void)
* want erase_char/kill_char to be treated
* as line editing characters.
*/
constant char tbuf[2] = { c, '\0' };
char tbuf[2];
tbuf[0] = c;
tbuf[1] = '\0';
action = fcmd_decode(tbuf, &extra);
}
/*
@@ -1575,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.
*/
@@ -1600,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;
@@ -1619,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.
@@ -1638,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;
@@ -1660,10 +1737,14 @@ 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;
case A_F_FOREVER:
case A_F_FOREVER_BELL:
case A_F_UNTIL_HILITE:
/*
* Forward forever, ignoring EOF.
*/
@@ -1671,11 +1752,7 @@ public void commands(void)
error("Warning: command may not work correctly when file is viewed via LESSOPEN", NULL_PARG);
if (show_attn)
set_attnpos(bottompos);
newaction = forw_loop(0);
break;
case A_F_UNTIL_HILITE:
newaction = forw_loop(1);
newaction = forw_loop(action);
break;
case A_F_SCROLL:
@@ -1699,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;
@@ -1958,6 +2037,7 @@ public void commands(void)
/*
* Clear search string highlighting.
*/
cmd_exec();
undo_search(action == A_CLR_SEARCH);
break;
@@ -2143,7 +2223,7 @@ public void commands(void)
cmd_exec();
if (new_ifile == NULL_IFILE)
{
bell();
lbell();
break;
}
if (edit_ifile(new_ifile) != 0)
@@ -2224,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;
@@ -2236,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);
@@ -2251,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:
@@ -2294,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();
@@ -2308,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();
@@ -2318,7 +2401,7 @@ public void commands(void)
/*
* Shift view left to margin.
*/
pos_rehead();
pos_rehead(FALSE);
hshift = 0;
screen_trashed();
cmd_exec();
@@ -2328,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();
@@ -2353,7 +2436,7 @@ public void commands(void)
break;
default:
bell();
lbell();
break;
}
}
+11 -3
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Mn Me -- unicode/UnicodeData.txt" on Aug 11 0:27:25 GMT 2025 */
/* Generated by "./mkutable -f2 Mn Me -- unicode/UnicodeData.txt" on Nov 28 1:30:11 GMT 2025 */
{ 0x0300, 0x036f }, /* Mn */
{ 0x0483, 0x0487 }, /* Mn */
{ 0x0488, 0x0489 }, /* Me */
@@ -144,7 +144,8 @@
{ 0x1a7f, 0x1a7f }, /* Mn */
{ 0x1ab0, 0x1abd }, /* Mn */
{ 0x1abe, 0x1abe }, /* Me */
{ 0x1abf, 0x1ace }, /* Mn */
{ 0x1abf, 0x1add }, /* Mn */
{ 0x1ae0, 0x1aeb }, /* Mn */
{ 0x1b00, 0x1b03 }, /* Mn */
{ 0x1b34, 0x1b34 }, /* Mn */
{ 0x1b36, 0x1b3a }, /* Mn */
@@ -230,7 +231,7 @@
{ 0x10d24, 0x10d27 }, /* Mn */
{ 0x10d69, 0x10d6d }, /* Mn */
{ 0x10eab, 0x10eac }, /* Mn */
{ 0x10efc, 0x10eff }, /* Mn */
{ 0x10efa, 0x10eff }, /* Mn */
{ 0x10f46, 0x10f50 }, /* Mn */
{ 0x10f82, 0x10f85 }, /* Mn */
{ 0x11001, 0x11001 }, /* Mn */
@@ -305,6 +306,9 @@
{ 0x11a59, 0x11a5b }, /* Mn */
{ 0x11a8a, 0x11a96 }, /* Mn */
{ 0x11a98, 0x11a99 }, /* Mn */
{ 0x11b60, 0x11b60 }, /* Mn */
{ 0x11b62, 0x11b64 }, /* Mn */
{ 0x11b66, 0x11b66 }, /* Mn */
{ 0x11c30, 0x11c36 }, /* Mn */
{ 0x11c38, 0x11c3d }, /* Mn */
{ 0x11c3f, 0x11c3f }, /* Mn */
@@ -360,5 +364,9 @@
{ 0x1e2ec, 0x1e2ef }, /* Mn */
{ 0x1e4ec, 0x1e4ef }, /* Mn */
{ 0x1e5ee, 0x1e5ef }, /* Mn */
{ 0x1e6e3, 0x1e6e3 }, /* Mn */
{ 0x1e6e6, 0x1e6e6 }, /* Mn */
{ 0x1e6ee, 0x1e6ef }, /* Mn */
{ 0x1e6f5, 0x1e6f5 }, /* Mn */
{ 0x1e8d0, 0x1e8d6 }, /* Mn */
{ 0x1e944, 0x1e94a }, /* Mn */
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+344 -97
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -34,10 +34,11 @@
#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;
static constant lbool allow_drag = TRUE;
extern char *no_config;
#if USERFILE
/* "content" is lesskey source, never binary. */
@@ -92,6 +93,7 @@ static unsigned char cmdtable[] =
ESC,'j',0, A_F_NEWLINE,
ESC,'k',0, A_B_NEWLINE,
'F',0, A_F_FOREVER,
ESC,'f',0, A_F_FOREVER_BELL,
ESC,'F',0, A_F_UNTIL_HILITE,
'R',0, A_FREPAINT,
'r',0, A_REPAINT,
@@ -101,6 +103,11 @@ static unsigned char cmdtable[] =
ESC,'U',0, A_CLR_SEARCH,
'g',0, A_GOLINE,
SK(SK_HOME),0, A_GOLINE,
SK(SK_SHIFT_HOME),0, A_GOLINE|A_EXTRA, ESC,'{',0,
SK(SK_CTL_HOME),0, A_GOLINE|A_EXTRA, ESC,'{',0,
SK(SK_END),0, A_GOEND,
SK(SK_SHIFT_END),0, A_GOEND|A_EXTRA, ESC,'}',0,
SK(SK_CTL_END),0, A_GOEND|A_EXTRA, ESC,'}',0,
'<',0, A_GOLINE,
ESC,'<',0, A_GOLINE,
'p',0, A_PERCENT,
@@ -113,6 +120,8 @@ static unsigned char cmdtable[] =
SK(SK_LEFT_ARROW),0, A_LSHIFT,
SK(SK_CTL_RIGHT_ARROW),0, A_RRSHIFT,
SK(SK_CTL_LEFT_ARROW),0, A_LLSHIFT,
SK(SK_SHIFT_RIGHT_ARROW),0, A_RRSHIFT,
SK(SK_SHIFT_LEFT_ARROW),0, A_LLSHIFT,
'{',0, A_F_BRACKET|A_EXTRA, '{','}',0,
'}',0, A_B_BRACKET|A_EXTRA, '{','}',0,
'(',0, A_F_BRACKET|A_EXTRA, '(',')',0,
@@ -125,7 +134,6 @@ static unsigned char cmdtable[] =
ESC,'G',0, A_GOEND_BUF,
ESC,'>',0, A_GOEND,
'>',0, A_GOEND,
SK(SK_END),0, A_GOEND,
'P',0, A_GOPOS,
'0',0, A_DIGIT,
@@ -183,6 +191,24 @@ static unsigned char cmdtable[] =
'!',0, A_SHELL,
'#',0, A_PSHELL,
'+',0, A_FIRSTCMD,
SK(SK_PAD_U),0, A_B_LINE,
SK(SK_PAD_D),0, A_F_LINE,
SK(SK_PAD_R),0, A_RSHIFT,
SK(SK_PAD_L),0, A_LSHIFT,
SK(SK_PAD_UR),0, A_B_SCREEN,
SK(SK_PAD_UL),0, A_GOLINE,
SK(SK_PAD_DR),0, A_F_SCREEN,
SK(SK_PAD_DL),0, A_GOEND,
SK(SK_PAD_STAR),0, A_NOACTION|A_EXTRA, '*',0,
SK(SK_PAD_SLASH),0, A_NOACTION|A_EXTRA, '/',0,
SK(SK_PAD_DASH),0, A_NOACTION|A_EXTRA, '-',0,
SK(SK_PAD_PLUS),0, A_NOACTION|A_EXTRA, '+',0,
SK(SK_PAD_DOT),0, A_NOACTION|A_EXTRA, '.',0,
SK(SK_PAD_COMMA),0, A_NOACTION,
SK(SK_PAD_ZERO),0, A_NOACTION|A_EXTRA, '0',0,
SK(SK_PAD_CENTER),0, A_NOACTION,
ESC,'[','2','0','0','~',0, A_START_PASTE,
ESC,'[','2','0','1','~',0, A_END_PASTE,
@@ -227,30 +253,52 @@ static unsigned char edittable[] =
ESC,SK(SK_BACKSPACE),0, EC_W_BACKSPACE, /* ESC BACKSPACE */
ESC,'0',0, EC_HOME, /* ESC 0 */
SK(SK_HOME),0, EC_HOME, /* HOME */
SK(SK_SHIFT_HOME),0, EC_HOME, /* SHIFT-HOME */
SK(SK_CTL_HOME),0, EC_HOME, /* CTRL-HOME */
ESC,'$',0, EC_END, /* ESC $ */
SK(SK_END),0, EC_END, /* END */
SK(SK_SHIFT_END),0, EC_END, /* SHIFT-END */
SK(SK_CTL_END),0, EC_END, /* CTRL-END */
ESC,'k',0, EC_UP, /* ESC k */
SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */
ESC,'j',0, EC_DOWN, /* ESC j */
SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */
CONTROL('G'),0, EC_ABORT, /* CTRL-G */
SK(SK_PAD_U),0, EC_UP,
SK(SK_PAD_D),0, EC_DOWN,
SK(SK_PAD_R),0, EC_RIGHT,
SK(SK_PAD_L),0, EC_LEFT,
SK(SK_PAD_UR),0, A_NOACTION,
SK(SK_PAD_UL),0, EC_HOME,
SK(SK_PAD_DR),0, A_NOACTION,
SK(SK_PAD_DL),0, EC_END,
SK(SK_PAD_STAR),0, A_NOACTION|A_EXTRA, '*',0,
SK(SK_PAD_SLASH),0, A_NOACTION|A_EXTRA, '/',0,
SK(SK_PAD_DASH),0, A_NOACTION|A_EXTRA, '-',0,
SK(SK_PAD_PLUS),0, A_NOACTION|A_EXTRA, '+',0,
SK(SK_PAD_DOT),0, A_NOACTION|A_EXTRA, '.',0,
SK(SK_PAD_COMMA),0, A_NOACTION|A_EXTRA, ',',0,
SK(SK_PAD_ZERO),0, A_NOACTION|A_EXTRA, '0',0,
SK(SK_PAD_CENTER),0, A_NOACTION,
ESC,'[','M',0, EC_X11MOUSE, /* X11 mouse report */
ESC,'[','<',0, EC_X116MOUSE, /* X11 1006 mouse report */
ESC,'[','2','0','0','~',0, A_START_PASTE, /* open paste bracket */
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"
};
/*
@@ -271,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.
@@ -289,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)
{
@@ -306,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";
@@ -321,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;
}
}
@@ -358,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. */
@@ -403,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 */
}
@@ -509,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;
}
/*
@@ -517,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;
}
/*
@@ -525,38 +613,58 @@ 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;
last_drag_y = last_click_y = y;
}
if (allow_drag && drag && last_drag_y >= 0)
if (drag)
{
/* Drag text up/down */
if (y > last_drag_y)
{
if ((emouse & EMOUSE_HDRAG) && last_drag_x >= 0 && x != last_drag_x) {
/* Drag text left/right */
pos_rehead(FALSE);
if (hshift < x - last_drag_x)
hshift = 0;
else
hshift -= x - last_drag_x;
screen_trashed();
cmd_exec();
backward(y - last_drag_y, FALSE, FALSE, FALSE);
last_drag_y = y;
} else if (y < last_drag_y)
{
cmd_exec();
forward(last_drag_y - y, FALSE, FALSE, FALSE);
last_drag_y = y;
last_drag_x = x;
}
} else if (!down)
if ((emouse & EMOUSE_VDRAG) && last_drag_y >= 0) {
/* Drag text up/down */
if (y > last_drag_y)
{
cmd_exec();
backward(y - last_drag_y, FALSE, FALSE, FALSE);
last_drag_y = y;
} else if (y < last_drag_y)
{
cmd_exec();
forward(last_drag_y - y, FALSE, FALSE, FALSE);
last_drag_y = y;
}
}
} else if ((emouse & EMOUSE_LCLICK) && !down)
{
#if OSC8_LINK
if (osc8_click(y, x))
return (A_NOACTION);
if (secure_allow(SF_OSC8_OPEN))
{
cmd_exec();
if (osc8_click(y, x))
return (A_NOACTION);
}
#else
(void) x;
#endif /* OSC8_LINK */
if (y < sc_height-1 && y == last_click_y)
{
setmark('#', y);
cmd_exec();
setmark('#', y, 0);
screen_trashed();
}
}
@@ -573,9 +681,11 @@ static int mouse_button_right(int x, int y, lbool down, lbool drag)
* {{ unlike mouse_button_left, we could return an action,
* but keep it near mouse_button_left for readability. }}
*/
if (!(emouse & EMOUSE_RCLICK))
return (A_NOACTION);
if (!down && y < sc_height-1)
{
gomark('#');
gomark('#', 0);
screen_trashed();
}
return (A_NOACTION);
@@ -637,6 +747,10 @@ static int x11mouse_action(lbool skip)
return mouse_wheel_down();
case X11MOUSE_WHEEL_UP:
return mouse_wheel_up();
case X11MOUSE_WHEEL_LEFT:
return mouse_wheel_left();
case X11MOUSE_WHEEL_RIGHT:
return mouse_wheel_right();
case X11MOUSE_BUTTON1:
case X11MOUSE_BUTTON2:
case X11MOUSE_BUTTON3:
@@ -671,6 +785,10 @@ static int x116mouse_action(lbool skip)
return mouse_wheel_down();
case X11MOUSE_WHEEL_UP:
return mouse_wheel_up();
case X11MOUSE_WHEEL_LEFT:
return mouse_wheel_left();
case X11MOUSE_WHEEL_RIGHT:
return mouse_wheel_right();
case X11MOUSE_BUTTON1:
case X11MOUSE_BUTTON2:
case X11MOUSE_BUTTON3: {
@@ -727,82 +845,95 @@ static constant unsigned char * cmd_next_entry(constant unsigned char *entry, mu
}
/*
* Search a single command table for the command string in cmd.
* Does a command table contain a #stop directive?
*/
static int cmd_search(constant char *cmd, constant unsigned char *table, constant unsigned char *endtable, constant unsigned char **extra, size_t *mlen)
static lbool table_has_stop(struct tablelist *t)
{
int action = A_INVALID;
size_t match_len = 0;
if (extra != NULL)
*extra = NULL;
while (table < endtable)
constant unsigned char *entry = t->t_start;
while (entry < t->t_end)
{
int taction;
const unsigned char *textra;
size_t cmdlen;
size_t match = cmd_match((constant char *) table, cmd);
table = cmd_next_entry(table, &taction, &textra, &cmdlen);
if (taction == A_END_LIST)
return (-action);
if (match >= match_len)
{
if (match == cmdlen) /* (last chars of) cmd matches this table entry */
{
action = taction;
if (extra != NULL)
*extra = textra;
} else if (match > 0 && action == A_INVALID) /* cmd is a prefix of this table entry */
{
action = A_PREFIX;
}
match_len = match;
}
int action;
entry = cmd_next_entry(entry, &action, NULL, NULL);
if (action == A_END_LIST)
return TRUE;
}
if (mlen != NULL)
*mlen = match_len;
return (action);
return FALSE;
}
/*
* Decode a command character and return the associated action.
* The "extra" string, if any, is returned in sp.
* Find the first command table with a #stop directive, if any.
*/
static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char **sp)
static struct tablelist * find_stop_table(struct tablelist *t)
{
for (; t != NULL; t = t->t_next)
{
if (table_has_stop(t))
return t;
}
return NULL;
}
/*
* Search a single command table for the command string in cmd.
*/
static int cmd_decode(struct tablelist *tlist, constant char *cmd, lbool anchored, constant char **extra)
{
struct tablelist *t;
int action = A_INVALID;
size_t match_len = 0;
constant unsigned char *table = NULL;
constant unsigned char *endtable;
/*
* Search for the cmd thru all the command tables.
* If we find it more than once, take the last one.
*/
*sp = NULL;
for (t = tlist; t != NULL; t = t->t_next)
if (extra != NULL)
*extra = NULL;
while (tlist != NULL)
{
constant unsigned char *tsp;
size_t mlen = match_len;
int taction = cmd_search(cmd, t->t_start, t->t_end, &tsp, &mlen);
if (mlen >= match_len)
int taction;
constant unsigned char *textra;
size_t tcmdlen;
size_t tmatch;
if (table == NULL)
{
match_len = mlen;
if (taction != A_INVALID)
/* Beginning of table: set start/end pointers. */
table = tlist->t_start;
endtable = tlist->t_end;
}
if (anchored)
tmatch = (strcmp((constant char *) table, cmd) == 0) ? strlen(cmd) : 0;
else
tmatch = cmd_match((constant char *) table, cmd);
table = cmd_next_entry(table, &taction, &textra, &tcmdlen);
if (table >= endtable)
{
/* End of table; move to next table. */
tlist = tlist->t_next;
table = NULL;
}
if (taction == A_END_LIST)
break;
if (tmatch >= match_len)
{
if (tmatch == tcmdlen)
{
*sp = (constant char *) tsp;
if (taction < 0)
{
action = -taction;
break;
}
/* (Last chars of) cmd matches this table entry. */
action = taction;
if (extra != NULL)
*extra = (constant char *) textra;
} else if (tmatch > 0 && (tmatch > match_len || action == A_INVALID))
{
/* cmd is a prefix of this table entry */
action = A_PREFIX;
if (extra != NULL)
*extra = NULL;
}
match_len = tmatch;
}
}
if (action == A_X11MOUSE_IN)
action = x11mouse_action(FALSE);
else if (action == A_X116MOUSE_IN)
action = x116mouse_action(FALSE);
return (action);
return action;
}
/*
@@ -810,7 +941,7 @@ static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char
*/
public int fcmd_decode(constant char *cmd, constant char **sp)
{
return (cmd_decode(list_fcmd_tables, cmd, sp));
return (cmd_decode(list_fcmd_tables, cmd, FALSE, sp));
}
/*
@@ -818,9 +949,119 @@ public int fcmd_decode(constant char *cmd, constant char **sp)
*/
public int ecmd_decode(constant char *cmd, constant char **sp)
{
return (cmd_decode(list_ecmd_tables, cmd, sp));
return (cmd_decode(list_ecmd_tables, cmd, FALSE, sp));
}
/*
* Parse a comma-separated list.
* Call func repeatedly, passing each item in the list.
* Stop and return FALSE if func ever returns FALSE,
* otherwise parse the entire list and return TRUE.
*/
public lbool parse_csl(lbool (*func)(constant char *word, size_t wlen, void *arg), constant char *str, void *arg)
{
for (;;)
{
constant char *estr;
while (*str == ' ' || *str == ',') ++str; /* skip leading spaces/commas */
if (*str == '\0') break;
estr = strchr(str, ',');
if (estr == NULL) estr = str + strlen(str);
while (estr > str && estr[-1] == ' ') --estr; /* trim trailing spaces */
if (!(*func)(str, ptr_diff(estr, str), arg))
return FALSE;
str = estr;
}
return TRUE;
}
/*
* Display error message for parse_csl_bitmap.
*/
static int csl_bitmap_error(constant char *pfx, constant char *type, size_t len, constant char *name)
{
PARG parg;
size_t msglen = len + strlen(pfx) + strlen(type) + 32;
char *msg = ecalloc(msglen, sizeof(char));
SNPRINTF4(msg, msglen, "%s: %s name \"%.*s\"", pfx, type, (int) len, name);
parg.p_string = msg;
error("%s", &parg);
free(msg);
return 0;
}
/*
* Return the bit value of a csl_bitmap name.
*/
public int csl_bitmap_bit(constant char *name, size_t len, struct csl_bitmap_def *defs, int num_defs, constant char *pfx)
{
int i;
int match = -1;
for (i = 0; i < num_defs; i++)
{
if (strncmp(defs[i].bit_name, name, len) == 0)
{
if (match >= 0) /* name is ambiguous */
return csl_bitmap_error(pfx, "ambiguous", len, name);
match = i;
}
}
if (match < 0)
return csl_bitmap_error(pfx, "invalid", len, name);
return defs[match].bit_value;
}
/* State for parse_csl_bitmap. */
struct csl_bitmap_info
{
int bitmap; /* bitmap being constructed */
struct csl_bitmap_def *def; /* array of name/value pairs */
int num_defs; /* length of def array */
constant char *pfx; /* prefix for error messages */
};
/*
* Set a bit in a csl_bitmap_info based on a csl_bitmap name.
*/
static lbool csl_bitmap_set(constant char *word, size_t wlen, void *arg)
{
struct csl_bitmap_info *info = (struct csl_bitmap_info *) arg;
info->bitmap |= csl_bitmap_bit(word, wlen, info->def, info->num_defs, info->pfx);
return TRUE;
}
/*
* Parse a comma-separated list of csl_bitmap names and return
* the combined bitmap value.
*/
public int parse_csl_bitmap(constant char *str, struct csl_bitmap_def *defs, int num_defs, constant char *pfx)
{
struct csl_bitmap_info info;
info.bitmap = 0;
info.def = defs;
info.num_defs = num_defs;
info.pfx = pfx;
if (!parse_csl(csl_bitmap_set, str, &info))
return -1;
return info.bitmap;
}
/*
* Should we ignore the setting of an environment variable?
*/
static lbool word_no_match(constant char *word, size_t wlen, void *arg)
{
constant char *var = (constant char *) arg;
return !(wlen == strlen(var) && strncmp(var, word, wlen) == 0);
}
static lbool ignore_env(constant char *var)
{
if (isnullenv(no_config))
return FALSE; /* no_config is not set; don't ignore anything */
/* no_config is set; ignore any var that does not appear in no_config */
return parse_csl(word_no_match, no_config, (void*) var);
}
/*
* Get the value of an environment variable.
@@ -831,13 +1072,15 @@ public constant char * lgetenv(constant char *var)
int a;
constant char *s;
a = cmd_decode(list_var_tables, var, &s);
if (ignore_env(var))
return (NULL);
a = cmd_decode(list_var_tables, var, TRUE, &s);
if (a == EV_OK)
return (s);
s = getenv(var);
if (s != NULL && *s != '\0')
return (s);
a = cmd_decode(list_sysvar_tables, var, &s);
a = cmd_decode(list_sysvar_tables, var, TRUE, &s);
if (a == EV_OK)
return (s);
return (NULL);
@@ -986,7 +1229,7 @@ public int lesskey(constant char *filename, lbool sysvar)
ssize_t n;
int f;
if (!secure_allow(SF_LESSKEY))
if (!secure_allow(SF_LESSKEY) || !isnullenv(no_config))
return (1);
/*
* Try to open the lesskey file.
@@ -1048,7 +1291,7 @@ static int lesskey_text(constant char *filename, lbool sysvar, lbool content)
int r;
static struct lesskey_tables tables;
if (!secure_allow(SF_LESSKEY))
if (!secure_allow(SF_LESSKEY) || !isnullenv(no_config))
return (1);
r = content ? parse_lesskey_content(filename, &tables) : parse_lesskey(filename, &tables);
if (r != 0)
@@ -1089,6 +1332,10 @@ static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant c
constant char *efilename;
int r;
#if LESSTEST
if (is_lesstest()) /* Don't use lesskey files in lesstest */
return -1;
#endif
if (envname != NULL && (efilename = lgetenv(envname)) != NULL)
filename = save(efilename);
else if (sysvar) /* def_filename is full path */
+37 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -25,13 +25,13 @@ public int fd0 = 0;
extern lbool new_file;
extern char *every_first_cmd;
extern int force_open;
extern int is_tty;
extern lbool is_tty;
extern int sigs;
extern int hshift;
extern int want_filesize;
extern int consecutive_nulls;
extern int modelines;
extern int show_preproc_error;
extern lbool read_error;
extern IFILE curr_ifile;
extern IFILE old_ifile;
extern struct scrpos initial_scrpos;
@@ -77,20 +77,20 @@ public void init_textlist(struct textlist *tlist, mutable char *str)
#if SPACES_IN_FILENAMES
if (meta_quoted)
{
meta_quoted = 0;
meta_quoted = FALSE;
} else if (esclen > 0 && s + esclen < tlist->endstring &&
strncmp(s, esc, esclen) == 0)
{
meta_quoted = 1;
meta_quoted = TRUE;
s += esclen - 1;
} else if (delim_quoted)
{
if (*s == closequote)
delim_quoted = 0;
delim_quoted = FALSE;
} else /* (!delim_quoted) */
{
if (*s == openquote)
delim_quoted = 1;
delim_quoted = TRUE;
else if (*s == ' ')
*s = '\0';
}
@@ -101,7 +101,7 @@ public void init_textlist(struct textlist *tlist, mutable char *str)
}
}
public constant char * forw_textlist(struct textlist *tlist, constant char *prev)
public constant char * forw_textlist(constant struct textlist *tlist, constant char *prev)
{
constant char *s;
@@ -120,7 +120,7 @@ public constant char * forw_textlist(struct textlist *tlist, constant char *prev
return (s);
}
public constant char * back_textlist(struct textlist *tlist, constant char *prev)
public constant char * back_textlist(constant struct textlist *tlist, constant char *prev)
{
constant char *s;
@@ -210,7 +210,6 @@ static void modeline_options(constant char *str, char end_char)
*/
static void check_modeline(constant char *line)
{
#if HAVE_STRSTR
static constant char *pgms[] = { "less:", "vim:", "vi:", "ex:", NULL };
constant char **pgm;
for (pgm = pgms; *pgm != NULL; ++pgm)
@@ -235,7 +234,6 @@ static void check_modeline(constant char *line)
pline = str;
}
}
#endif /* HAVE_STRSTR */
}
/*
@@ -266,6 +264,7 @@ static void close_pipe(FILE *pipefd)
int status;
char *p;
PARG parg;
int sig = 0;
if (pipefd == NULL)
return;
@@ -292,18 +291,33 @@ static void close_pipe(FILE *pipefd)
if (WIFEXITED(status))
{
int s = WEXITSTATUS(status);
if (s != 0)
if (s == 0)
return;
if (s <= 128)
{
parg.p_int = s;
error("Input preprocessor failed (status %d)", &parg);
return;
}
return;
/*
* popen invoked the shell, which likely last ran a
* program that terminated due to a signal.
* Assume the longstanding tradition (allowed but not
* required by POSIX) of adding 128 to the signal.
* Many shells use last command optimization, i.e.,
* they exec the last command instead of forking and
* waiting for it, and in that case the more-reliable
* WIFSIGNALED code below will be used.
*/
sig = s - 128;
}
#endif
#if defined WIFSIGNALED && defined WTERMSIG
if (WIFSIGNALED(status))
sig = WTERMSIG(status);
#endif
if (sig != 0)
{
int sig = WTERMSIG(status);
if (
#ifdef SIGPIPE
sig != SIGPIPE ||
@@ -315,7 +329,6 @@ static void close_pipe(FILE *pipefd)
}
return;
}
#endif
if (status != 0)
{
parg.p_int = status;
@@ -363,11 +376,14 @@ static void close_file(void)
* Save the current position so that we can return to
* the same position if we edit this file again.
*/
get_scrpos(&scrpos, TOP);
if (scrpos.pos != NULL_POSITION)
if (is_tty)
{
store_pos(curr_ifile, &scrpos);
lastmark();
get_scrpos(&scrpos, TOP);
if (scrpos.pos != NULL_POSITION)
{
store_pos(curr_ifile, &scrpos);
lastmark();
}
}
/*
* Close the file descriptor, unless it is a pipe.
@@ -547,7 +563,7 @@ public int edit_ifile(IFILE ifile)
} else
{
chflags |= CH_CANSEEK;
if (bin_file(f, &nread) && !force_open && !opened(ifile))
if (bin_file(f, &nread) && is_tty && !force_open && !opened(ifile))
{
/*
* Looks like a binary file.
@@ -613,7 +629,6 @@ public int edit_ifile(IFILE ifile)
set_open(curr_ifile); /* File has been opened */
get_pos(curr_ifile, &initial_scrpos);
ch_init(f, chflags, nread);
consecutive_nulls = 0;
check_modelines();
if (!(chflags & CH_HELPFILE))
@@ -662,6 +677,7 @@ public int edit_ifile(IFILE ifile)
#endif
undo_osc8();
hshift = 0;
read_error = FALSE;
if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE))
{
char *qfilename = shell_quote(filename);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+22 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -319,15 +319,13 @@ static void xcpy_char(xcpy *xp, char ch)
static void xcpy_filename(xcpy *xp, constant char *str)
{
/* If filename contains spaces, quote it
* to prevent edit_list from splitting it. */
lbool quote = (strchr(str, ' ') != NULL);
if (quote)
xcpy_char(xp, openquote);
for (; *str != '\0'; str++)
xcpy_char(xp, *str);
if (quote)
xcpy_char(xp, closequote);
char *qstr = shell_quote(str);
char *s;
if (qstr == NULL)
return;
for (s = qstr; *s != '\0'; s++)
xcpy_char(xp, *s);
free(qstr);
}
static size_t fexpand_copy(constant char *fr, char *to)
@@ -469,22 +467,23 @@ public char * fcomplete(constant char *s)
* be used later to compare to st_size from stat(2) to see if the file
* is lying about its size.
*/
public int bin_file(int f, ssize_t *n)
public lbool bin_file(int f, ssize_t *n)
{
int bin_count = 0;
char data[256];
constant char* p;
constant char* edata;
constant int umax = 4;
if (!seekable(f))
return (0);
return FALSE;
if (less_lseek(f, (less_off_t)0, SEEK_SET) == BAD_LSEEK)
return (0);
return FALSE;
*n = read(f, data, sizeof(data));
if (*n <= 0)
return (0);
if (*n <= umax)
return FALSE;
edata = &data[*n];
for (p = data; p < edata; )
for (p = data; p+umax < edata; )
{
if (utf_mode && !is_utf8_well_formed(p, (int) ptr_diff(edata,p)))
{
@@ -569,9 +568,10 @@ static FILE * shellcmd(constant char *cmd)
fd = popen(cmd, "r");
} else
{
size_t len = strlen(shell) + strlen(esccmd) + 5;
constant char *copt = shell_coption();
size_t len = strlen(shell) + strlen(esccmd) + strlen(copt) + 3;
scmd = (char *) ecalloc(len, sizeof(char));
SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd);
SNPRINTF3(scmd, len, "%s %s %s", shell, copt, esccmd);
free(esccmd);
fd = popen(scmd, "r");
free(scmd);
@@ -731,7 +731,11 @@ public char * lglob(constant char *afilename)
}
lessecho = lgetenv("LESSECHO");
if (isnullenv(lessecho))
#ifdef LIBEXECDIR
lessecho = LIBEXECDIR "/lessecho";
#else
lessecho = "lessecho";
#endif
/*
* Invoke lessecho, and read its output (a globbed list of filenames).
*/
+1 -1
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Cf -- unicode/UnicodeData.txt" on Jul 27 19:38:50 GMT 2025 */
/* Generated by "./mkutable -f2 Cf -- unicode/UnicodeData.txt" on Nov 28 1:30:12 GMT 2025 */
{ 0x0600, 0x0605 }, /* Cf */
{ 0x061c, 0x061c }, /* Cf */
{ 0x06dd, 0x06dd }, /* Cf */
+60 -30
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -19,8 +19,8 @@
extern int less_is_more;
public lbool squished;
public int no_back_scroll = 0;
public int forw_prompt;
public lbool no_back_scroll = FALSE;
public lbool forw_prompt;
public lbool first_time = TRUE; /* We're printing the first screen of output */
public int shell_lines = 1;
/* soft_eof is set as end-of-file when a read attempt returns EOF. This can
@@ -36,11 +36,12 @@ extern int auto_wrap;
extern lbool plusoption;
extern int forw_scroll;
extern int back_scroll;
extern int ignore_eoi;
extern lbool ignore_eoi;
extern int header_lines;
extern int header_cols;
extern int full_screen;
extern lbool full_screen;
extern int stop_on_form_feed;
extern int past_eof;
extern POSITION header_start_pos;
extern lbool getting_one_screen;
#if HILITE_SEARCH
@@ -66,7 +67,7 @@ public void eof_bell(void)
}
#endif
if (quiet == NOT_QUIET)
bell();
lbell();
else
vbell();
}
@@ -140,7 +141,7 @@ static POSITION forw_line_pfx(POSITION pos, int pfx, int skipeol)
sc_width = pfx + line_pfx_width();
auto_wrap = 0;
hshift = 0;
pos = forw_line_seg(pos, skipeol, FALSE, FALSE, NULL, NULL);
pos = forw_line_seg(pos, skipeol, FALSE, FALSE, FALSE, TRUE, NULL, NULL);
sc_width = save_sc_width;
auto_wrap = save_auto_wrap;
hshift = save_hshift;
@@ -218,15 +219,18 @@ public int overlay_header(void)
* The first real line after the blanks will start at ch_zero().
* "to_newline" means count file lines rather than screen lines.
*/
public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, int nblank)
public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, lbool do_stop_on_form_feed, int nblank)
{
int nlines = 0;
lbool do_repaint;
lbool newline;
lbool first_line = TRUE;
lbool need_home = FALSE;
if (pos != NULL_POSITION)
pos = after_header_pos(pos);
if (past_eof)
force = TRUE;
squish_check();
/*
@@ -242,7 +246,7 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
(forw_scroll >= 0 && n > forw_scroll && n != sc_height-1);
if (!do_repaint)
{
if (top_scroll && n >= sc_height - 1 && pos != ch_length())
if (top_scroll && n >= sc_height - 1 && pos != NULL_POSITION && pos != ch_length())
{
/*
* Start a new screen.
@@ -252,10 +256,7 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
*/
pos_clear();
force = TRUE;
if (less_is_more == 0) {
clear();
home();
}
need_home = (less_is_more == 0) ? TRUE : FALSE;
}
if (pos != position(BOTTOM_PLUS_ONE) || empty_screen())
@@ -269,8 +270,7 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
force = TRUE;
if (top_scroll)
{
clear();
home();
need_home = TRUE;
} else if (!first_time && !is_filtering() && full_screen)
{
putstr("...skipping...\n");
@@ -308,18 +308,25 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
/*
* End of file: stop here unless the top line
* is still empty, or "force" is true.
* Even if force is true, stop when the last
* line in the file reaches the top of screen.
*/
soft_eof = opos;
linepos = opos;
if (ABORT_SIGS() ||
(!force && position(TOP) != NULL_POSITION) ||
(!empty_lines(0, 0) && !empty_lines(1, 1) && empty_lines(2, sc_height-1)))
linepos = (opos == ch_zero()) ? NULL_POSITION : opos;
if (ABORT_SIGS() || !force)
{
pos = opos;
break;
}
/*
* Even if force is true, stop when the last
* line in the file reaches the top of screen.
* Check for 3 non-empty lines at top of screen.
* The first will be shifted away by the add_forw_pos()
* after this loop; the other two are the start and end of
* the single line that we want to retain at top of screen.
*/
if (!first_line && sc_height >= 3 && empty_lines(3, sc_height-1) &&
!empty_lines(0, 0) && !empty_lines(1, 1) && !empty_lines(2, 2))
break;
}
}
/*
@@ -331,6 +338,12 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
nlines++;
if (do_repaint)
continue;
if (need_home)
{
lclear();
home();
need_home = FALSE;
}
/*
* If this is the first screen displayed and
* we hit an early EOF (i.e. before the requested
@@ -353,13 +366,13 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
continue;
}
put_line(TRUE);
if (stop_on_form_feed && !do_repaint && line_is_ff() && position(TOP) != NULL_POSITION)
if (do_stop_on_form_feed && !do_repaint && line_is_ff() && position(TOP) != NULL_POSITION)
break;
forw_prompt = 1;
forw_prompt = TRUE;
}
if (!first_line)
add_forw_pos(pos, FALSE);
if (nlines == 0 && !ignore_eoi && !ABORT_SIGS())
if (nlines == 0 && !ignore_eoi)
eof_bell();
else if (do_repaint)
repaint();
@@ -375,13 +388,15 @@ public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
/*
* Display n lines, scrolling backward.
*/
public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline)
public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, lbool do_stop_on_form_feed)
{
int nlines = 0;
lbool do_repaint;
lbool newline;
squish_check();
if (past_eof)
force = TRUE;
do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1) || header_lines > 0);
while (--n >= 0)
@@ -397,7 +412,18 @@ public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
/*
* Beginning of file: stop here unless "force" is true.
*/
if (!force)
if (ABORT_SIGS() || !force)
break;
/*
* Even if force is true, stop when the first
* line in the file reaches the bottom of the screen.
* Check for 2 non-empty lines at bottom of screen.
* These are the start and end of the single line that
* we want to retain at bottom of screen.
*/
if (sc_height >= 3 && empty_lines(0, sc_height-3) &&
!empty_lines(sc_height-1, sc_height-1) &&
!empty_lines(sc_height-2, sc_height-2))
break;
}
if (pos != after_header_pos(pos))
@@ -418,7 +444,7 @@ public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_new
home();
add_line();
put_line(FALSE);
if (stop_on_form_feed && line_is_ff())
if (do_stop_on_form_feed && line_is_ff())
break;
}
}
@@ -453,6 +479,8 @@ public void forward(int n, lbool force, lbool only_last, lbool to_newline)
return;
}
if (past_eof)
force = TRUE;
pos = position(BOTTOM_PLUS_ONE);
if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1)))
{
@@ -469,7 +497,7 @@ public void forward(int n, lbool force, lbool only_last, lbool to_newline)
{
do
{
back(1, position(TOP), TRUE, FALSE, FALSE);
back(1, position(TOP), TRUE, FALSE, FALSE, stop_on_form_feed);
pos = position(BOTTOM_PLUS_ONE);
} while (pos == NULL_POSITION && !ABORT_SIGS());
}
@@ -479,7 +507,7 @@ public void forward(int n, lbool force, lbool only_last, lbool to_newline)
return;
}
}
forw(n, pos, force, only_last, to_newline, 0);
forw(n, pos, force, only_last, to_newline, stop_on_form_feed, 0);
}
/*
@@ -490,13 +518,15 @@ public void backward(int n, lbool force, lbool only_last, lbool to_newline)
{
POSITION pos;
if (past_eof)
force = TRUE;
pos = position(TOP);
if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0))
{
eof_bell();
return;
}
back(n, pos, force, only_last, to_newline);
back(n, pos, force, only_last, to_newline, stop_on_form_feed);
}
/*
+65 -47
View File
@@ -8,6 +8,7 @@ public size_t sprefix(constant char *ps, constant char *s, int uppercase);
public void quit(int status);
public int secure_allow(int features);
public void raw_mode(int on);
public void scrsize(void);
public void screen_size_changed(void);
public constant char * special_key_str(int key);
public void init_win_colors(void);
@@ -16,9 +17,9 @@ 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);
public void term_init(void);
public void term_deinit(void);
public lbool interactive(void);
public void home(void);
public void dump_screen(void);
public void add_line(void);
@@ -29,8 +30,8 @@ public void line_left(void);
public void check_winch(void);
public void goto_line(int sindex);
public void vbell(void);
public void bell(void);
public void clear(void);
public void lbell(void);
public void lclear(void);
public void clear_eol(void);
public void clear_bot(void);
public void init_bracketed_paste(void);
@@ -42,10 +43,12 @@ public void at_switch(int attr);
public lbool is_at_equiv(int attr1, int attr2);
public int apply_at_specials(int attr);
public void putbs(void);
public void win32_enqueue(int ch);
public void WIN32ungetch(int ch);
public lbool win32_kbhit2(lbool no_queued);
public void win32_clear_queue(void);
public lbool win32_kbhit2(char *pch);
public lbool win32_kbhit(void);
public char WIN32getch(void);
public int WIN32getch(void);
public void win32_getch_clear(void);
public void WIN32setcolors(int fg, int bg);
public void WIN32textout(constant char *text, size_t len);
@@ -75,8 +78,8 @@ public lbool binary_char(LWCHAR c);
public lbool control_char(LWCHAR c);
public constant char * prchar(LWCHAR c);
public constant char * prutfchar(LWCHAR ch);
public int utf_len(char ch);
public lbool is_utf8_well_formed(constant char *ss, int slen);
public int utf_len(char ach);
public lbool is_utf8_well_formed(constant char *ssa, int slen);
public void utf_skip_to_lead(constant char **pp, constant char *limit);
public LWCHAR get_wchar(constant char *sp);
public void put_wchar(mutable char **pp, LWCHAR ch);
@@ -106,7 +109,7 @@ public constant char * cmd_lastpattern(void);
public void init_cmdhist(void);
public void save_cmdhist(void);
public void cmd_exec(void);
public int in_mca(void);
public lbool in_mca(void);
public int norm_search_type(int st);
public void screen_trashed_num(int trashed);
public void screen_trashed(void);
@@ -119,8 +122,8 @@ public void ungetcc_back(char c);
public void ungetcc_end_command(void);
public void ungetsc(constant char *s);
public char peekcc(void);
public void start_ignoring_input();
public void stop_ignoring_input();
public void start_ignoring_input(void);
public void stop_ignoring_input(void);
public lbool is_ignoring_input(int action);
public void commands(void);
public size_t cvt_length(size_t len, int ops);
@@ -134,6 +137,9 @@ public void add_uvar_table(unsigned char *buf, size_t len);
public void add_sysvar_table(unsigned char *buf, size_t len);
public int fcmd_decode(constant char *cmd, constant char **sp);
public int ecmd_decode(constant char *cmd, constant char **sp);
public lbool parse_csl(lbool (*func)(constant char *word, size_t wlen, void *arg), constant char *str, void *arg);
public int csl_bitmap_bit(constant char *name, size_t len, struct csl_bitmap_def *defs, int num_defs, constant char *pfx);
public int parse_csl_bitmap(constant char *str, struct csl_bitmap_def *defs, int num_defs, constant char *pfx);
public constant char * lgetenv(constant char *var);
public constant char * lgetenv_ext(constant char *var, unsigned char *env_buf, size_t env_buf_len);
public lbool isnullenv(constant char *s);
@@ -142,8 +148,8 @@ public int lesskey_src(constant char *filename, lbool sysvar);
public int lesskey_content(constant char *content, lbool sysvar);
public int editchar(char c, int flags);
public void init_textlist(struct textlist *tlist, mutable char *str);
public constant char * forw_textlist(struct textlist *tlist, constant char *prev);
public constant char * back_textlist(struct textlist *tlist, constant char *prev);
public constant char * forw_textlist(constant struct textlist *tlist, constant char *prev);
public constant char * back_textlist(constant struct textlist *tlist, constant char *prev);
public void close_altpipe(IFILE ifile);
public void check_altpipe_error(void);
public int edit(constant char *filename);
@@ -170,7 +176,7 @@ public char * dirfile(constant char *dirname, constant char *filename, int must_
public char * homefile(constant char *filename);
public char * fexpand(constant char *s);
public char * fcomplete(constant char *s);
public int bin_file(int f, ssize_t *n);
public lbool bin_file(int f, ssize_t *n);
public char * readfd(FILE *fd);
public char * lglob(constant char *afilename);
public lbool is_fake_pathname(constant char *path);
@@ -188,8 +194,8 @@ public lbool eof_displayed(lbool offset);
public lbool entire_file_displayed(void);
public void squish_check(void);
public int overlay_header(void);
public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, int nblank);
public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline);
public void forw(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, lbool do_stop_on_form_feed, int nblank);
public void back(int n, POSITION pos, lbool force, lbool only_last, lbool to_newline, lbool do_stop_on_form_feed);
public void forward(int n, lbool force, lbool only_last, lbool to_newline);
public void backward(int n, lbool force, lbool only_last, lbool to_newline);
public int get_back_scroll(void);
@@ -203,10 +209,10 @@ public IFILE get_ifile(constant char *filename, IFILE prev);
public constant char * get_filename(IFILE ifile);
public constant char * get_real_filename(IFILE ifile);
public int get_index(IFILE ifile);
public void store_pos(IFILE ifile, struct scrpos *scrpos);
public void store_pos(IFILE ifile, constant struct scrpos *scrpos);
public void get_pos(IFILE ifile, struct scrpos *scrpos);
public void set_open(IFILE ifile);
public int opened(IFILE ifile);
public lbool opened(IFILE ifile);
public void hold_ifile(IFILE ifile, int incr);
public int held_ifile(IFILE ifile);
public void * get_filestate(IFILE ifile);
@@ -216,7 +222,7 @@ public void *get_altpipe(IFILE ifile);
public void set_altfilename(IFILE ifile, char *altfilename);
public char * get_altfilename(IFILE ifile);
public void if_dump(void);
public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop, POSITION *p_linepos, lbool *p_newline);
public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop, lbool full_pad, lbool rforw, POSITION *p_linepos, lbool *p_newline);
public POSITION forw_line(POSITION curr_pos, POSITION *p_linepos, lbool *p_newline);
public POSITION back_line(POSITION curr_pos, lbool *p_newline);
public void set_attnpos(POSITION pos);
@@ -235,7 +241,7 @@ 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 unsigned line_pfx_width(void);
public void pshift_all(void);
public int pwidth(LWCHAR ch, int a, LWCHAR prev_ch, int prev_a);
public void savec(void);
@@ -251,7 +257,7 @@ public int pappend_b(char c, POSITION pos, lbool before_pendc);
public int pappend(char c, POSITION pos);
public lbool line_is_ff(void);
public int pflushmbc(void);
public void pdone(lbool endline, lbool chopped, lbool forw);
public void pdone(lbool endline, lbool chopped, lbool forw, lbool full_pad);
public int col_from_pos(POSITION linepos, POSITION spos, POSITION saved_pos, int saved_col);
public POSITION pos_from_col(POSITION linepos, int col, POSITION saved_pos, int saved_col);
public void set_attr_line(int a);
@@ -263,7 +269,8 @@ public POSITION forw_raw_line_len(POSITION curr_pos, size_t read_len, constant c
public POSITION forw_raw_line(POSITION curr_pos, constant char **linep, size_t *line_lenp);
public POSITION back_raw_line(POSITION curr_pos, constant char **linep, size_t *line_lenp);
public int skip_columns(int cols, constant char **linep, size_t *line_lenp);
public void load_line(constant char *str);
public void load_line(constant char *str, int attr, int reserve);
public int longest_line_width(void);
public int rrshift(void);
public int set_color_map(int attr, constant char *colorstr);
public constant char * get_color_map(int attr);
@@ -278,11 +285,11 @@ public void lsystem(constant char *cmd, constant char *donemsg);
public int pipe_mark(char c, constant char *cmd);
public int pipe_data(constant char *cmd, POSITION spos, POSITION epos);
public void init_mark(void);
public int badmark(char c);
public void setmark(char c, int where);
public lbool badmark(char c);
public void setmark(char c, int where, LINENUM linenum);
public void clrmark(char c);
public void lastmark(void);
public void gomark(char c);
public void gomark(char c, int sline);
public POSITION markpos(char c);
public char posmark(POSITION pos);
public void unmark(IFILE ifile);
@@ -303,6 +310,8 @@ public void opt_t(int type, constant char *s);
public void opt__T(int type, constant char *s);
public void opt_p(int type, constant char *s);
public void opt__P(int type, constant char *s);
public void opt_end_prompt(int type, constant char *s);
public void opt_autosave(int type, constant char *s);
public void opt_b(int type, constant char *s);
public void opt_i(int type, constant char *s);
public void opt__V(int type, constant char *s);
@@ -314,15 +323,16 @@ public void opt_rscroll(int type, constant char *s);
public void opt_query(int type, constant char *s);
public void opt_match_shift(int type, constant char *s);
public void calc_match_shift(void);
public void opt_mousecap(int type, constant char *s);
public void opt_emouse(int type, constant char *s);
public void opt_mouse(int type, constant char *s);
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);
public void opt_hilite_target(int type, constant char *s);
public void opt_search_type(int type, constant char *s);
public void opt_nosearch_headers(int type, constant char *s);
public void opt_nosearch_header_lines(int type, constant char *s);
@@ -331,17 +341,18 @@ public void opt_no_paste(int type, constant char *s);
public void opt_ttyin_name(int type, constant char *s);
public int chop_line(void);
public int get_swindow(void);
public lbool autosave_action(char act);
public constant char * propt(char c);
public void scan_option(constant char *s, lbool is_env);
public void toggle_option(struct loption *o, lbool lower, constant char *s, int how_toggle);
public int opt_has_param(struct loption *o);
public constant char * opt_prompt(struct loption *o);
public lbool toggle_option(struct loption *o, lbool lower, constant char *s, int how_toggle);
public lbool opt_has_param(constant struct loption *o);
public constant char * opt_prompt(constant struct loption *o);
public constant char * opt_toggle_disallowed(int c);
public lbool isoptpending(void);
public void nopendopt(void);
public int getnumc(constant char **sp, constant char *printopt, lbool *errp);
public int getnum(char **sp, constant char *printopt, lbool *errp);
public long getfraction(constant char **sp, constant char *printopt, lbool *errp);
public lbool getnumc(constant char **sp, constant char *printopt, lbool neg_ok, mutable int *p_num);
public lbool getnum(char **sp, constant char *printopt, lbool neg_ok, mutable int *p_num);
public lbool getfraction(constant char **sp, mutable long *p_frac);
public void init_unsupport(void);
public int get_quit_at_eof(void);
public void init_option(void);
@@ -350,10 +361,11 @@ public struct loption * findopt_name(constant char **p_optname, constant char **
public char * findopts_name(constant char *pfx);
public void init_poll(void);
public lbool ttyin_ready(void);
public int supports_ctrl_x(void);
public lbool supports_ctrl_x(void);
public ssize_t iread(int fd, unsigned char *buf, size_t len);
public int iopen(constant char *filename, int flags);
public void intio(void);
public void polling_ok(void);
public time_type get_time(void);
public char * errno_message(constant char *filename);
public constant char * signal_message(int sig);
@@ -362,18 +374,19 @@ public int percentage(POSITION num, POSITION den);
public POSITION percent_pos(POSITION pos, int percent, long fraction);
public int os9_signal(int type, RETSIGTYPE (*handler)());
public void sleep_ms(int ms);
public void put_line_hilite(lbool forw_scroll, lbool target);
public void put_line(lbool forw_scroll);
public void flush(void);
public void set_output(int fd);
public void set_output(int fd, lbool no_term_init);
public int putchr(int ch);
public void clear_bot_if_needed(void);
public void putstr(constant char *s);
public int less_printf(constant char *fmt, PARG *parg);
public int less_printf(constant char *fmt, constant PARG *parg);
public void get_return(void);
public void error(constant char *fmt, PARG *parg);
public void ierror(constant char *fmt, PARG *parg);
public void ixerror(constant char *fmt, PARG *parg);
public int query(constant char *fmt, PARG *parg);
public void error(constant char *fmt, constant PARG *parg);
public void ierror(constant char *fmt, constant PARG *parg);
public void ixerror(constant char *fmt, constant PARG *parg);
public int query(constant char *fmt, constant PARG *parg);
public int compile_pattern(constant char *pattern, int search_type, int show_error, PATTERN_TYPE *comp_pattern);
public void uncompile_pattern(PATTERN_TYPE *pattern);
public int valid_pattern(char *pattern);
@@ -386,22 +399,27 @@ public void add_back_pos(POSITION pos);
public void pos_clear(void);
public void pos_init(void);
public int onscreen(POSITION pos);
public int empty_screen(void);
public int empty_lines(int s, int e);
public lbool empty_screen(void);
public lbool empty_lines(int s, int e);
public void get_scrpos_pos(struct scrpos *scrpos, int where, POSITION pos);
public void get_scrpos(struct scrpos *scrpos, int where);
public int sindex_from_sline(int sline);
public void pos_rehead(void);
public POSITION beginning_of_line(POSITION tpos);
public void pos_rehead(lbool adj_hshift);
public void init_prompt(void);
public constant char * pr_expand(constant char *proto);
public constant char * eq_message(void);
public constant char * pr_string(void);
public constant char * end_pr_string(void);
public constant char * wait_message(void);
public void init_search(void);
public int get_cvt_ops(int search_type);
public constant char* prev_pattern_text(void);
public void repaint_hilite(lbool on);
public void draw_target_attn(lbool hilite);
public void clear_attn(void);
public void undo_search(lbool clear);
public void undo_osc8(void);
public lbool undo_osc8(void);
public void clr_hlist(struct hilite_tree *anchor);
public void clr_hilite(void);
public void clr_filter(void);
@@ -420,7 +438,7 @@ public int search(int search_type, constant char *pattern, int n);
public void prep_hilite(POSITION spos, POSITION epos, int maxlines);
public void set_filter_pattern(constant char *pattern, int search_type);
public lbool is_filtering(void);
public RETSIGTYPE winch(int type);
public RETSIGTYPE lwinch(int type);
public void init_signals(int on);
public void psignals(void);
public void cleantags(void);
@@ -445,7 +463,7 @@ public void xbuf_deinit(struct xbuffer *xbuf);
public void xbuf_reset(struct xbuffer *xbuf);
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 void xbuf_add_data(struct xbuffer *xbuf, constant void *vdata, size_t len);
public int xbuf_pop(struct xbuffer *buf);
public void xbuf_set(struct xbuffer *dst, constant struct xbuffer *src);
public constant char * xbuf_char_data(constant struct xbuffer *xbuf);
+23 -12
View File
@@ -1,4 +1,4 @@
/* This file was generated by mkhelp.pl from less.hlp at 18:02 on 2025/10/4 */
/* This file was generated by mkhelp.pl from less.hlp at 23:54 on 2026/5/30 */
#include "less.h"
constant char helpdata[] = {
'\n',
@@ -32,6 +32,7 @@ constant char helpdata[] = {
' ',' ','E','S','C','-','{',' ',' ','^','L','e','f','t','A','r','r','o','w',' ',' ',' ',' ','L','e','f','t',' ',' ','t','o',' ','f','i','r','s','t',' ','c','o','l','u','m','n','.','\n',
' ',' ','F',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','o','r','w','a','r','d',' ','f','o','r','e','v','e','r',';',' ','l','i','k','e',' ','"','t','a','i','l',' ','-','f','"','.','\n',
' ',' ','E','S','C','-','F',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','L','i','k','e',' ','F',' ','b','u','t',' ','s','t','o','p',' ','w','h','e','n',' ','s','e','a','r','c','h',' ','p','a','t','t','e','r','n',' ','i','s',' ','f','o','u','n','d','.','\n',
' ',' ','E','S','C','-','f',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','L','i','k','e',' ','F',' ','b','u','t',' ','r','i','n','g',' ','t','h','e',' ','b','e','l','l',' ','w','h','e','n',' ','s','e','a','r','c','h',' ','p','a','t','t','e','r','n',' ','i','s',' ','f','o','u','n','d','.','\n',
' ',' ','r',' ',' ','^','R',' ',' ','^','L',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','p','a','i','n','t',' ','s','c','r','e','e','n','.','\n',
' ',' ','R',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','p','a','i','n','t',' ','s','c','r','e','e','n',',',' ','d','i','s','c','a','r','d','i','n','g',' ','b','u','f','f','e','r','e','d',' ','i','n','p','u','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
@@ -54,7 +55,7 @@ constant char helpdata[] = {
' ',' ','E','S','C','-','U',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','l','e','a','r',' ','s','e','a','r','c','h',' ','h','i','g','h','l','i','g','h','t','i','n','g','.','\n',
' ',' ','&','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','D','i','s','p','l','a','y',' ','o','n','l','y',' ','m','a','t','c','h','i','n','g',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\t','\t','S','e','a','r','c','h',' ','i','s',' ','c','a','s','e','-','s','e','n','s','i','t','i','v','e',' ','u','n','l','e','s','s',' ','c','h','a','n','g','e','d',' ','w','i','t','h',' ','-','i',' ','o','r',' ','-','I','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','i','s',' ','c','a','s','e','-','s','e','n','s','i','t','i','v','e',' ','u','n','l','e','s','s',' ','c','h','a','n','g','e','d',' ','w','i','t','h',' ','-','i',' ','o','r',' ','-','I','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','A',' ','s','e','a','r','c','h',' ','p','a','t','t','e','r','n',' ','m','a','y',' ','b','e','g','i','n',' ','w','i','t','h',' ','o','n','e',' ','o','r',' ','m','o','r','e',' ','o','f',':','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','N',' ','o','r',' ','!',' ',' ','S','e','a','r','c','h',' ','f','o','r',' ','N','O','N','-','m','a','t','c','h','i','n','g',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','E',' ','o','r',' ','*',' ',' ','S','e','a','r','c','h',' ','m','u','l','t','i','p','l','e',' ','f','i','l','e','s',' ','(','p','a','s','s',' ','t','h','r','u',' ','E','N','D',' ','O','F',' ','F','I','L','E',')','.','\n',
@@ -68,8 +69,8 @@ constant char helpdata[] = {
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','J','\b','J','U','\b','U','M','\b','M','P','\b','P','I','\b','I','N','\b','N','G','\b','G','\n',
'\n',
' ',' ','g',' ',' ','<',' ',' ','E','S','C','-','<',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','f','i','r','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','G',' ',' ','>',' ',' ','E','S','C','-','>',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','l','a','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','g',' ',' ','<',' ',' ','E','S','C','-','<',' ',' ','H','O','M','E',' ','*',' ',' ','G','o',' ','t','o',' ','f','i','r','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','G',' ',' ','>',' ',' ','E','S','C','-','>',' ',' ','E','N','D',' ',' ','*',' ',' ','G','o',' ','t','o',' ','l','a','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','p',' ',' ','%',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','b','e','g','i','n','n','i','n','g',' ','o','f',' ','f','i','l','e',' ','(','o','r',' ','_','\b','N',' ','p','e','r','c','e','n','t',' ','i','n','t','o',' ','f','i','l','e',')','.','\n',
' ',' ','t',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','n','e','x','t',' ','t','a','g','.','\n',
' ',' ','T',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','p','r','e','v','i','o','u','s',' ','t','a','g','.','\n',
@@ -83,11 +84,11 @@ constant char helpdata[] = {
' ',' ',' ',' ',' ',' ',' ',' ','E','a','c','h',' ','"','f','i','n','d',' ','o','p','e','n',' ','b','r','a','c','k','e','t','"',' ','c','o','m','m','a','n','d',' ','g','o','e','s',' ','b','a','c','k','w','a','r','d',' ','t','o',' ','t','h','e',' ','o','p','e','n',' ','b','r','a','c','k','e','t',' ','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','m','a','t','c','h','i','n','g',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t',' ','i','n',' ','t','h','e',' ','b','o','t','t','o','m',' ','l','i','n','e','.','\n',
'\n',
' ',' ','m','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','a','r','k',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','t','o','p',' ','l','i','n','e',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','M','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','a','r','k',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','b','o','t','t','o','m',' ','l','i','n','e',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','\'','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','G','o',' ','t','o',' ','a',' ','p','r','e','v','i','o','u','s','l','y',' ','m','a','r','k','e','d',' ','p','o','s','i','t','i','o','n','.','\n',
' ',' ','\'','\'',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','p','r','e','v','i','o','u','s',' ','p','o','s','i','t','i','o','n','.','\n',
' ',' ','^','X','^','X',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','a','m','e',' ','a','s',' ','\'','.','\n',
' ',' ','m','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','M','a','r','k',' ','t','h','e',' ','t','o','p',' ','l','i','n','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','M','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','M','a','r','k',' ','t','h','e',' ','b','o','t','t','o','m',' ','l','i','n','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','\'','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','a',' ','p','r','e','v','i','o','u','s','l','y',' ','m','a','r','k','e','d',' ','p','o','s','i','t','i','o','n',' ','(','p','u','t',' ','o','n',' ','p','o','s','i','t','i','o','n',' ','_','\b','N',')','.','\n',
' ',' ','\'','\'',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','p','r','e','v','i','o','u','s',' ','p','o','s','i','t','i','o','n','.','\n',
' ',' ','^','X','^','X',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','S','a','m','e',' ','a','s',' ','\'','.','\n',
' ',' ','E','S','C','-','m','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ','C','l','e','a','r',' ','a',' ','m','a','r','k','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
' ',' ',' ',' ',' ',' ',' ',' ','A',' ','m','a','r','k',' ','i','s',' ','a','n','y',' ','u','p','p','e','r','-','c','a','s','e',' ','o','r',' ','l','o','w','e','r','-','c','a','s','e',' ','l','e','t','t','e','r','.','\n',
@@ -204,9 +205,9 @@ constant char helpdata[] = {
' ',' ','-','V',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','v','e','r','s','i','o','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','t','h','e',' ','v','e','r','s','i','o','n',' ','n','u','m','b','e','r',' ','o','f',' ','"','l','e','s','s','"','.','\n',
' ',' ','-','w',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','h','i','l','i','t','e','-','u','n','r','e','a','d','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','f','o','r','w','a','r','d','-','s','c','r','e','e','n','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','f','u','l','l',' ','s','c','r','e','e','n',' ','m','o','v','e','m','e','n','t','.','\n',
' ',' ','-','W',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','H','I','L','I','T','E','-','U','N','R','E','A','D','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','a','n','y',' ','f','o','r','w','a','r','d',' ','m','o','v','e','m','e','n','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','a','n','y',' ','m','o','v','e','m','e','n','t','.','\n',
' ',' ','-','x',' ','[','_','\b','N','[',',','.','.','.',']',']',' ',' ','-','-','t','a','b','s','=','[','_','\b','N','[',',','.','.','.',']',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','t','a','b',' ','s','t','o','p','s','.','\n',
' ',' ','-','X',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','n','o','-','i','n','i','t','\n',
@@ -222,6 +223,12 @@ constant char helpdata[] = {
' ',' ','-','#',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','s','h','i','f','t','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','h','o','r','i','z','o','n','t','a','l',' ','s','c','r','o','l','l',' ','a','m','o','u','n','t',' ','(','0',' ','=',' ','o','n','e',' ','h','a','l','f',' ','s','c','r','e','e','n',' ','w','i','d','t','h',')','.','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','a','u','t','o','s','a','v','e','=','[','_','\b','m','_','\b','/','_','\b','!','_','\b','*',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','A','c','t','i','o','n','s',' ','w','h','i','c','h',' ','c','a','u','s','e',' ','t','h','e',' ','h','i','s','t','o','r','y',' ','f','i','l','e',' ','t','o',' ','b','e',' ','s','a','v','e','d','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','e','m','o','u','s','e','=','[','_','\b','v','_','\b','s','_','\b','c','_','\b','r','_','\b','o','_','\b','l','_','\b','l',',','_','\b','v','_','\b','d','_','\b','r','_','\b','a','_','\b','g',',','_','\b','h','_','\b','s','_','\b','c','_','\b','r','_','\b','o','_','\b','l','_','\b','l',',','_','\b','h','_','\b','d','_','\b','r','_','\b','a','_','\b','g',',','_','\b','l','_','\b','c','_','\b','l','_','\b','i','_','\b','c','_','\b','k',',','_','\b','r','_','\b','c','_','\b','l','_','\b','i','_','\b','c','_','\b','k',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','n','a','b','l','e',' ','m','o','u','s','e',' ','f','e','a','t','u','r','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','e','n','d','-','p','r','o','m','p','t','=','[','_','\b','s','_','\b','t','_','\b','r','_','\b','i','_','\b','n','_','\b','g',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','t','r','i','n','g',' ','t','o',' ','b','e',' ','p','r','i','n','t','e','d',' ','a','f','t','e','r',' ','e','r','a','s','i','n','g',' ','t','h','e',' ','p','r','o','m','p','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','e','x','i','t','-','f','o','l','l','o','w','-','o','n','-','c','l','o','s','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','i','t',' ','F',' ','c','o','m','m','a','n','d',' ','o','n',' ','a',' ','p','i','p','e',' ','w','h','e','n',' ','w','r','i','t','e','r',' ','c','l','o','s','e','s',' ','p','i','p','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','f','i','l','e','-','s','i','z','e','\n',
@@ -232,6 +239,8 @@ constant char helpdata[] = {
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','t','o','p',' ','s','c','r','o','l','l','i','n','g',' ','w','h','e','n',' ','a',' ','f','o','r','m',' ','f','e','e','d',' ','c','h','a','r','a','c','t','e','r',' ','i','s',' ','r','e','a','c','h','e','d','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','h','e','a','d','e','r','=','[','_','\b','L','[',',','_','\b','C','[',',','_','\b','N',']',']',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','s','e',' ','_','\b','L',' ','l','i','n','e','s',' ','(','s','t','a','r','t','i','n','g',' ','a','t',' ','l','i','n','e',' ','_','\b','N',')',' ','a','n','d',' ','_','\b','C',' ','c','o','l','u','m','n','s',' ','a','s',' ','h','e','a','d','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','h','i','l','i','t','e','-','t','a','r','g','e','t','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','t','h','e',' ','t','a','r','g','e','t',' ','l','i','n','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','i','n','c','s','e','a','r','c','h','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','f','i','l','e',' ','a','s',' ','e','a','c','h',' ','p','a','t','t','e','r','n',' ','c','h','a','r','a','c','t','e','r',' ','i','s',' ','t','y','p','e','d',' ','i','n','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','i','n','t','r','=','[','_','\b','C',']','\n',
@@ -247,7 +256,7 @@ constant char helpdata[] = {
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','m','o','d','e','l','i','n','e','s','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','a','d',' ','_','\b','N',' ','l','i','n','e','s',' ','f','r','o','m',' ','t','h','e',' ','i','n','p','u','t',' ','f','i','l','e',' ','a','n','d',' ','l','o','o','k',' ','f','o','r',' ','v','i','m',' ','m','o','d','e','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','m','o','u','s','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','n','a','b','l','e',' ','m','o','u','s','e',' ','i','n','p','u','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','n','a','b','l','e',' ','m','o','u','s','e',' ','c','l','i','c','k','i','n','g',' ','a','n','d',' ','v','e','r','t','i','c','a','l',' ','s','c','r','o','l','l','i','n','g','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','e','d','i','t','-','w','a','r','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','w','a','r','n',' ','w','h','e','n',' ','u','s','i','n','g',' ','v',' ','c','o','m','m','a','n','d',' ','o','n',' ','a',' ','f','i','l','e',' ','o','p','e','n','e','d',' ','v','i','a',' ','L','E','S','S','O','P','E','N','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','k','e','y','p','a','d','\n',
@@ -276,6 +285,8 @@ constant char helpdata[] = {
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','d','e','f','a','u','l','t',' ','o','p','t','i','o','n','s',' ','f','o','r',' ','e','v','e','r','y',' ','s','e','a','r','c','h','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','h','o','w','-','p','r','e','p','r','o','c','-','e','r','r','o','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','a',' ','m','e','s','s','a','g','e',' ','i','f',' ','p','r','e','p','r','o','c','e','s','s','o','r',' ','e','x','i','t','s',' ','w','i','t','h',' ','a','n',' ','e','r','r','o','r',' ','s','t','a','t','u','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','p','a','s','t','-','e','o','f','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','c','r','o','l','l','i','n','g',' ','c','o','m','m','a','n','d','s',' ','c','o','n','t','i','n','u','e',' ','p','a','s','t',' ','e','n','d',' ','o','f',' ','f','i','l','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','p','r','o','c','-','b','a','c','k','s','p','a','c','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','P','r','o','c','e','s','s',' ','b','a','c','k','s','p','a','c','e','s',' ','f','o','r',' ','b','o','l','d','/','u','n','d','e','r','l','i','n','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','P','R','O','C','-','B','A','C','K','S','P','A','C','E','\n',
+6 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -31,7 +31,7 @@ struct ifile {
void *h_filestate; /* File state (used in ch.c) */
int h_index; /* Index within command line list */
int h_hold; /* Hold count */
char h_opened; /* Has this ifile been opened? */
lbool h_opened; /* Has this ifile been opened? */
struct scrpos h_scrpos; /* Saved position within the file */
void *h_altpipe; /* Alt pipe */
char *h_altfilename; /* Alt filename */
@@ -108,7 +108,7 @@ static struct ifile * new_ifile(constant char *filename, struct ifile *prev)
p->h_filename = save(filename);
p->h_rfilename = lrealpath(filename);
p->h_scrpos.pos = NULL_POSITION;
p->h_opened = 0;
p->h_opened = FALSE;
p->h_hold = 0;
p->h_filestate = NULL;
p->h_altfilename = NULL;
@@ -269,7 +269,7 @@ public int get_index(IFILE ifile)
/*
* Save the file position to be associated with a given file.
*/
public void store_pos(IFILE ifile, struct scrpos *scrpos)
public void store_pos(IFILE ifile, constant struct scrpos *scrpos)
{
int_ifile(ifile)->h_scrpos = *scrpos;
}
@@ -288,13 +288,13 @@ public void get_pos(IFILE ifile, struct scrpos *scrpos)
*/
public void set_open(IFILE ifile)
{
int_ifile(ifile)->h_opened = 1;
int_ifile(ifile)->h_opened = TRUE;
}
/*
* Return whether the ifile has been opened previously.
*/
public int opened(IFILE ifile)
public lbool opened(IFILE ifile)
{
return (int_ifile(ifile)->h_opened);
}
+7 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -22,7 +22,6 @@
extern int squeeze;
extern int hshift;
extern int quit_if_one_screen;
extern int ignore_eoi;
extern int status_col;
extern int wordwrap;
extern POSITION start_attnpos;
@@ -81,7 +80,7 @@ static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp
* a line. The new position is the position of the first character
* of the NEXT line. The line obtained is the line starting at curr_pos.
*/
public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop, POSITION *p_linepos, lbool *p_newline)
public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop, lbool full_pad, lbool rforw, POSITION *p_linepos, lbool *p_newline)
{
POSITION base_pos;
POSITION new_pos;
@@ -246,7 +245,7 @@ get_forw_line:
} while (c != '\n' && c != EOI);
new_pos = ch_tell();
endline = TRUE;
quit_if_one_screen = FALSE;
quit_if_one_screen = 0;
chopped = TRUE;
} else
{
@@ -307,7 +306,7 @@ get_forw_line:
pappend_b(' ', ch_tell()-1, TRUE);
}
#endif
pdone(endline, rscroll && chopped, TRUE);
pdone(endline, rscroll && chopped, rforw, full_pad);
#if HILITE_SEARCH
if (is_filtered(base_pos))
@@ -346,7 +345,7 @@ get_forw_line:
public POSITION forw_line(POSITION curr_pos, POSITION *p_linepos, lbool *p_newline)
{
return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE, p_linepos, p_newline);
return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE, FALSE, TRUE, p_linepos, p_newline);
}
/*
@@ -502,7 +501,7 @@ get_back_line:
{
endline = TRUE;
chopped = TRUE;
quit_if_one_screen = FALSE;
quit_if_one_screen = 0;
edisp_pos = new_pos;
break;
}
@@ -569,7 +568,7 @@ get_back_line:
}
}
pdone(endline, chopped, FALSE);
pdone(endline, chopped, FALSE, FALSE);
#if HILITE_SEARCH
if (is_filtered(base_pos))
+29 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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,6 +20,9 @@ extern lbool squished;
extern int sc_width, sc_height;
extern int show_attn;
extern int top_scroll;
extern int quit_if_one_screen;
extern lbool one_screen;
extern lbool full_screen;
extern POSITION header_start_pos;
/*
@@ -188,15 +191,15 @@ static void after_header_message(void)
{
#if HAVE_TIME
#define MSG_FREQ 1 /* seconds */
static time_type last_msg = (time_type) 0;
time_type now = get_time();
if (now < last_msg + MSG_FREQ)
return;
last_msg = now;
static time_type last_msg = (time_type) 0;
time_type now = get_time();
if (now < last_msg + MSG_FREQ)
return;
last_msg = now;
#endif
bell();
/* {{ This message displays before the file text is updated, which is not a good UX. }} */
/** error("Cannot display text before header; use --header=- to disable header", NULL_PARG); */
lbell();
/* {{ This message displays before the file text is updated, which is not a good UX. }} */
/** error("Cannot display text before header; use --header=- to disable header", NULL_PARG); */
}
/*
@@ -210,8 +213,8 @@ public POSITION after_header_pos(POSITION pos)
{
if (header_start_pos != NULL_POSITION && pos < header_start_pos)
{
after_header_message();
pos = header_start_pos;
after_header_message();
pos = header_start_pos;
}
return pos;
}
@@ -235,6 +238,14 @@ public void jump_loc(POSITION pos, int sline)
pos = next_unfiltered(pos);
sindex = sindex_from_sline(sline);
if (!full_screen && !(quit_if_one_screen && one_screen))
{
/* If not full screen, can't rely on scrolling logic below, since
* "scrolling" may just print lines in the unused part of the screen. */
pos_clear();
lclear();
}
if ((nline = onscreen(pos)) >= 0)
{
/*
@@ -243,9 +254,9 @@ public void jump_loc(POSITION pos, int sline)
*/
nline -= sindex;
if (nline > 0)
forw(nline, position(BOTTOM_PLUS_ONE), TRUE, FALSE, FALSE, 0);
forw(nline, position(BOTTOM_PLUS_ONE), TRUE, FALSE, FALSE, FALSE, 0);
else
back(-nline, position(TOP), TRUE, FALSE, FALSE);
back(-nline, position(TOP), TRUE, FALSE, FALSE, FALSE);
#if HILITE_SEARCH
if (show_attn)
repaint_hilite(TRUE);
@@ -286,7 +297,7 @@ public void jump_loc(POSITION pos, int sline)
* close enough to the current screen
* that we can just scroll there after all.
*/
forw(sc_height-sindex+nline-1, bpos, TRUE, FALSE, FALSE, 0);
forw(sc_height-sindex+nline-1, bpos, TRUE, FALSE, FALSE, FALSE, 0);
#if HILITE_SEARCH
if (show_attn)
repaint_hilite(TRUE);
@@ -308,7 +319,7 @@ public void jump_loc(POSITION pos, int sline)
lastmark();
squished = FALSE;
screen_trashed_num(0);
forw(sc_height-1, pos, TRUE, FALSE, FALSE, sindex-nline);
forw(sc_height-1, pos, TRUE, FALSE, FALSE, FALSE, sindex-nline);
} else
{
/*
@@ -337,7 +348,7 @@ public void jump_loc(POSITION pos, int sline)
* close enough to the current screen
* that we can just scroll there after all.
*/
back(nline, tpos, TRUE, FALSE, FALSE);
back(nline, tpos, TRUE, FALSE, FALSE, FALSE);
#if HILITE_SEARCH
if (show_attn)
repaint_hilite(TRUE);
@@ -347,11 +358,11 @@ public void jump_loc(POSITION pos, int sline)
}
lastmark();
if (!top_scroll)
clear();
lclear();
else
home();
screen_trashed_num(0);
add_back_pos(pos);
back(sc_height-1, pos, TRUE, FALSE, FALSE);
back(sc_height-1, pos, TRUE, FALSE, FALSE, FALSE);
}
}
+4 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -53,5 +53,8 @@ typedef __int64 ssize_t;
typedef __int32 ssize_t;
#endif
#endif
#ifdef __BORLANDC__
typedef long ssize_t;
#endif
#endif // LESS_LANG_H_
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
# Less OSC 8 handler.
echo() { printf %s\\n "$*"; }
# Open a link of the form "file://HOST/PATH" or "file:///PATH"
open_file() {
case $1 in
file:///* | file://localhost/*)
less -- "/${1#file://*/}"
;;
file://*/*)
linkhost=${1#file://}; linkhost=${linkhost%%/*}
localhost=${HOSTNAME:-$(bash -c 'printf %s "$HOSTNAME"' || uname -n)} 2>/dev/null
case $localhost in
*/* | '')
echo "unable to detect local hostname: $localhost"
exit 1
;;
"$linkhost")
less -- "/${1#file://*/}"
;;
*)
echo "cannot open remote file: $1"
exit 1
;;
esac
;;
*)
echo "invalid file link: $1"
exit 1
;;
esac
}
# Open a link of the form "man:NAME" or "man:NAME(SECTION)".
open_man() {
case $1 in
man:?*\(*\) )
sect=${1#*\(}; sect=${sect%?}
name=${1#man:}; name=${name%%\(*}
man -- ${sect:+"$sect"} "$name"
;;
man:?*)
man -- "${1#man:}"
;;
*)
echo "invalid man link: $1"
exit 1
;;
esac
}
case $1 in
file:*) open_file "$1" ;;
man:*) open_man "$1" ;;
*) echo "unsupported link type: $1"; exit 1 ;;
esac
+47 -16
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -52,9 +52,6 @@
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_WCTYPE_H
#include <wctype.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
@@ -266,6 +263,11 @@ typedef off_t LINENUM;
#endif
#endif
/* Use iread() to read tty? */
#if !MSDOS_COMPILER || MSDOS_COMPILER == DJGPPC
#define LESS_IREAD_TTY 1
#endif
/*
* Flags for creat()
*/
@@ -336,6 +338,12 @@ struct wchar_range_table
unsigned int count;
};
struct csl_bitmap_def
{
constant char *bit_name;
int bit_value;
};
#if HAVE_POLL
typedef short POLL_EVENTS;
#endif
@@ -438,8 +446,7 @@ typedef enum osc8_state {
#define AT_PLACEHOLDER (1 << 7) /* Placeholder for half of double-wide char */
#define AT_COLOR_SHIFT 8
#define AT_NUM_COLORS 16
#define AT_COLOR ((AT_NUM_COLORS-1) << AT_COLOR_SHIFT)
#define AT_COLOR ((~(unsigned)0) << AT_COLOR_SHIFT)
#define AT_COLOR_ATTN (1 << AT_COLOR_SHIFT)
#define AT_COLOR_BIN (2 << AT_COLOR_SHIFT)
#define AT_COLOR_CTRL (3 << AT_COLOR_SHIFT)
@@ -450,8 +457,12 @@ typedef enum osc8_state {
#define AT_COLOR_RSCROLL (8 << AT_COLOR_SHIFT)
#define AT_COLOR_HEADER (9 << AT_COLOR_SHIFT)
#define AT_COLOR_SEARCH (10 << AT_COLOR_SHIFT)
#define AT_COLOR_SUBSEARCH(i) ((10+(i)) << AT_COLOR_SHIFT)
#define NUM_SEARCH_COLORS (AT_NUM_COLORS-10-1)
#define AT_COLOR_TILDE (11 << AT_COLOR_SHIFT)
#define AT_COLOR_TARGET (12 << AT_COLOR_SHIFT)
#define AT_COLOR_SS_OFFSET 13 /* largest AT_COLOR_* value + 1 */
#define NUM_SEARCH_COLORS 5
#define AT_NUM_COLORS (AT_COLOR_SS_OFFSET + NUM_SEARCH_COLORS)
#define AT_COLOR_SUBSEARCH(i) ((AT_COLOR_SS_OFFSET+(i)-1) << AT_COLOR_SHIFT)
typedef enum { CT_NULL, CT_4BIT, CT_6BIT } COLOR_TYPE;
@@ -627,14 +638,25 @@ typedef enum {
#endif
/* X11 mouse reporting definitions */
#define X11MOUSE_BUTTON1 0 /* Left button press */
#define X11MOUSE_BUTTON2 1 /* Middle button press */
#define X11MOUSE_BUTTON3 2 /* Right button press */
#define X11MOUSE_BUTTON_REL 3 /* Button release */
#define X11MOUSE_DRAG 0x20 /* Drag with button down */
#define X11MOUSE_WHEEL_UP 0x40 /* Wheel scroll up */
#define X11MOUSE_WHEEL_DOWN 0x41 /* Wheel scroll down */
#define X11MOUSE_OFFSET 0x20 /* Added to button & pos bytes to create a char */
#define X11MOUSE_BUTTON1 0 /* Left button press */
#define X11MOUSE_BUTTON2 1 /* Middle button press */
#define X11MOUSE_BUTTON3 2 /* Right button press */
#define X11MOUSE_BUTTON_REL 3 /* Button release */
#define X11MOUSE_DRAG 0x20 /* Drag with button down */
#define X11MOUSE_WHEEL_UP 0x40 /* Wheel scroll up */
#define X11MOUSE_WHEEL_DOWN 0x41 /* Wheel scroll down */
#define X11MOUSE_WHEEL_LEFT 0x42 /* Wheel scroll left */
#define X11MOUSE_WHEEL_RIGHT 0x43 /* Wheel scroll right */
#define X11MOUSE_OFFSET 0x20 /* Added to button & pos bytes to create a char */
/* Mouse features */
#define EMOUSE_HSCROLL (1<<0) /* Horizontal scroll */
#define EMOUSE_VSCROLL (1<<1) /* Vertical scroll */
#define EMOUSE_HDRAG (1<<2) /* Horizontal drag */
#define EMOUSE_VDRAG (1<<3) /* Vertical drag */
#define EMOUSE_LCLICK (1<<4) /* Left click */
#define EMOUSE_RCLICK (1<<5) /* Right click */
#define EMOUSE_COUNT 6
/* Security features. */
#define SF_EDIT (1<<1) /* Edit file (v) */
@@ -675,3 +697,12 @@ unsigned long lstrtoulc(constant char*, constant char**, int);
#if MSDOS_COMPILER==WIN32C
int pclose(FILE*);
#endif
#if !HAVE_STRCHR
char * strchr(char *s, char c);
#endif
#if !HAVE_MEMCPY
void * memcpy(void *dst, constant void *src, size_t len);
#endif
#if !HAVE_STRSTR
char * strstr(constant char *haystack, constant char *needle);
#endif
+22 -11
View File
@@ -29,6 +29,7 @@
ESC-{ ^LeftArrow Left to first column.
F Forward forever; like "tail -f".
ESC-F Like F but stop when search pattern is found.
ESC-f Like F but ring the bell when search pattern is found.
r ^R ^L Repaint screen.
R Repaint screen, discarding buffered input.
---------------------------------------------------
@@ -51,7 +52,7 @@
ESC-U Clear search highlighting.
&_p_a_t_t_e_r_n * Display only matching lines.
---------------------------------------------------
Search is case-sensitive unless changed with -i or -I.
Search is case-sensitive unless changed with -i or -I.
A search pattern may begin with one or more of:
^N or ! Search for NON-matching lines.
^E or * Search multiple files (pass thru END OF FILE).
@@ -65,8 +66,8 @@
JJUUMMPPIINNGG
g < ESC-< * Go to first line in file (or line _N).
G > ESC-> * Go to last line in file (or line _N).
g < ESC-< HOME * Go to first line in file (or line _N).
G > ESC-> END * Go to last line in file (or line _N).
p % * Go to beginning of file (or _N percent into file).
t * Go to the (_N-th) next tag.
T * Go to the (_N-th) previous tag.
@@ -80,11 +81,11 @@
Each "find open bracket" command goes backward to the open bracket
matching the (_N-th) close bracket in the bottom line.
m_<_l_e_t_t_e_r_> Mark the current top line with <letter>.
M_<_l_e_t_t_e_r_> Mark the current bottom line with <letter>.
'_<_l_e_t_t_e_r_> Go to a previously marked position.
'' Go to the previous position.
^X^X Same as '.
m_<_l_e_t_t_e_r_> * Mark the top line (or line _N) with <letter>.
M_<_l_e_t_t_e_r_> * Mark the bottom line (or line _N) with <letter>.
'_<_l_e_t_t_e_r_> * Go to a previously marked position (put on position _N).
'' * Go to the previous position.
^X^X * Same as '.
ESC-m_<_l_e_t_t_e_r_> Clear a mark.
---------------------------------------------------
A mark is any upper-case or lower-case letter.
@@ -201,9 +202,9 @@
-V ........ --version
Display the version number of "less".
-w ........ --hilite-unread
Highlight first new line after forward-screen.
Highlight first new line after full screen movement.
-W ........ --HILITE-UNREAD
Highlight first new line after any forward movement.
Highlight first new line after any movement.
-x [_N[,...]] --tabs=[_N[,...]]
Set tab stops.
-X ........ --no-init
@@ -219,6 +220,12 @@
-# [_N] .... --shift=[_N]
Set horizontal scroll amount (0 = one half screen width).
--autosave=[_m_/_!_*]
Actions which cause the history file to be saved.
--emouse=[_v_s_c_r_o_l_l,_v_d_r_a_g,_h_s_c_r_o_l_l,_h_d_r_a_g,_l_c_l_i_c_k,_r_c_l_i_c_k]
Enable mouse features.
--end-prompt=[_s_t_r_i_n_g]
String to be printed after erasing the prompt.
--exit-follow-on-close
Exit F command on a pipe when writer closes pipe.
--file-size
@@ -229,6 +236,8 @@
Stop scrolling when a form feed character is reached.
--header=[_L[,_C[,_N]]]
Use _L lines (starting at line _N) and _C columns as headers.
--hilite-target
Highlight the target line.
--incsearch
Search file as each pattern character is typed in.
--intr=[_C]
@@ -244,7 +253,7 @@
--modelines=[_N]
Read _N lines from the input file and look for vim modelines.
--mouse
Enable mouse input.
Enable mouse clicking and vertical scrolling.
--no-edit-warn
Don't warn when using v command on a file opened via LESSOPEN.
--no-keypad
@@ -273,6 +282,8 @@
Set default options for every search.
--show-preproc-errors
Display a message if preprocessor exits with an error status.
--past-eof
Scrolling commands continue past end of file.
--proc-backspace
Process backspaces for bold/underline.
--PROC-BACKSPACE
+1212 -572
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+32 -5
View File
@@ -1,9 +1,33 @@
.TH LESSECHO 1 "Version 685: 04 Oct 2025"
.TH LESSECHO 1 "30 May 2026" "less 704"
.\" Define a string to interpolate the hyphenless break point escape
.\" sequence (for URLs and similar) if the formatter claims groff
.\" compatibility, else interpolate nothing.
.ie \n(.g .ds : \:
.el .ds : \" empty
.SH NAME
lessecho \- expand metacharacters
.SH SYNOPSIS
.HP
.B lessecho
.I "[-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-a] file ..."
.RB [ \-a ]
.RB [ \-o\c
.IR x ]
.RB [ \-c\c
.IR x ]
.RB [ \-p\c
.IR n ]
.RB [ \-d\c
.IR n ]
.RB [ \-m\c
.IR x ]
.RB [ \-n\c
.IR n ]
.RB [ \-e\c
.IR x ]
.I file
\&.\|.\|.
.PP
.B "lessecho \-\-version"
.SH "DESCRIPTION"
.B lessecho
is a program that simply echos its arguments on standard output.
@@ -18,12 +42,12 @@ A summary of options is included below.
.TP
.B \-e\fIx\fP
Specifies "\fIx\fP", rather than backslash, to be the escape char for metachars.
If \fIx\fP is "-", no escape char is used and arguments containing metachars
If \fIx\fP is "\-", no escape char is used and arguments containing metachars
are surrounded by quotes instead.
.TP
.B \-o\fIx\fP
Specifies "\fIx\fP", rather than double-quote, to be the open quote character,
which is used if the \-e- option is specified.
which is used if the \-e\- option is specified.
.TP
.B \-c\fIx\fP
Specifies "\fIx\fP" to be the close quote character.
@@ -53,4 +77,7 @@ The default is that only arguments containing metacharacters are quoted.
This manual page was written by Thomas Schoepf <[email protected]>,
for the Debian GNU/Linux system (but may be used by others).
.PP
Report bugs at https://github.com/gwsw/less/issues.
Report bugs at
.nh
https://\*:github\*:.com/\*:gwsw/\*:less/\*:issues.
.hy
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+246 -144
View File
@@ -1,12 +1,31 @@
'\" t
.TH LESSKEY 1 "Version 685: 04 Oct 2025"
.TH LESSKEY 1 "30 May 2026" "less 704"
.\" Define a string for the caret ("hat") as portably as possible.
.ie \n(.g .ds ^ \(ha
.el .ds ^ ^
.\" Define a string for the neutral apostrophe as portably as possible.
.ie \n(.g .ds ' \(aq
.el .ds ' '
.\" Define a string to interpolate the hyphenless break point escape
.\" sequence (for URLs and similar) if the formatter claims groff
.\" compatibility, else interpolate nothing.
.ie \n(.g .ds : \:
.el .ds : \" empty
.SH NAME
lesskey \- customize key bindings for less
.SH "SYNOPSIS (deprecated)"
.B "lesskey [\-o output] [\-\-] [input]"
.br
.B "lesskey [\-\-output=output] [\-\-] [input]"
.B lesskey
.RB [ \-o
.IR output ]
.B \-\-
.I input
.br
.B lesskey
.RB [ \-\-output=\c
.IR output ]
.B \-\-
.I input
.PP
.B "lesskey \-V"
.br
.B "lesskey \-\-version"
@@ -43,7 +62,7 @@ Each section starts with a line that identifies the type of section.
Possible sections are:
.IP #command
Customizes command key bindings.
.IP #line-edit
.IP #line\-edit
Customizes line-editing key bindings.
.IP #env
Defines environment variables.
@@ -54,15 +73,15 @@ except as noted below.
.
.SH "COMMAND SECTION"
The command section begins with the line
.sp
.PP
#command
.sp
.PP
If the command section is the first section in the file,
this line may be omitted.
The command section consists of lines of the form:
.sp
.PP
\fIstring\fP <whitespace> \fIaction\fP <whitespace> [extra-string] <newline>
.sp
.PP
Whitespace is any sequence of one or more spaces and/or tabs.
The \fIstring\fP is the command key(s) which invoke the action.
The \fIstring\fP may be a single command key, or a sequence of up to 15 keys.
@@ -84,28 +103,52 @@ l l l.
\et TAB (0x09)
.TE
.RE
.sp
\ek followed by a single character represents the char(s) produced when one of these keys is pressed:
.PP
\ek followed by one or two characters represents the char(s) produced
when one of these keys is pressed:
.RS 5m
.TS
l l.
\ekb BACKSPACE (the BACKSPACE key)
\ekb BACKSPACE (the BACKSPACE key; may be different than \eb)
\ekB ctrl-BACKSPACE
\ekd DOWN ARROW
\ekD PAGE DOWN
\eke END
\ekE ctrl-END
\ekF shift-END
\ekh HOME
\ekH ctrl-HOME
\ekI shift-HOME
\eki INSERT
\ekl LEFT ARROW
\ekL ctrl-LEFT ARROW
\ekM shift-LEFT ARROW
\ekr RIGHT ARROW
\ekR ctrl-RIGHT ARROW
\ekS shift-RIGHT ARROW
\ekt BACKTAB
\eku UP ARROW
\ekU PAGE UP
\ekx DELETE
\ekX ctrl-DELETE
\ek1 F1
\ekp1 lower left key on the numeric keypad
\ekp2 lower center key on the numeric keypad
\ekp3 lower right key on the numeric keypad
\ekp4 center left key on the numeric keypad
\ekp5 center key on the numeric keypad
\ekp6 center right key on the numeric keypad
\ekp7 upper left key on the numeric keypad
\ekp8 upper center key on the numeric keypad
\ekp9 upper right key on the numeric keypad
\ekp0 0 on the numeric keypad
\ekp* * on the numeric keypad
\ekp/ / on the numeric keypad
\ekp\- \- on the numeric keypad
\ekp+ + on the numeric keypad
\ekp. . on the numeric keypad
\ekp, , on the numeric keypad
\ekpe ENTER on the numeric keypad
.TE
.RE
.PP
@@ -126,11 +169,13 @@ 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
.PP
.EX
.nf
B set-mark b/next\en
B set\-mark b/next\en
.fi
.sp
.EE
.PP
The extra string has a special meaning for the "quit" action:
when
.B less
@@ -144,116 +189,130 @@ default command keys used by
Documentation on each command can be found in the
.B less
man page, under the key sequence which invokes the command.
.sp
.PP
.RS 5m
.TS
l l.
#command
\er forw-line
\en forw-line
e forw-line
j forw-line
\ekd forw-line
^E forw-line
^N forw-line
k back-line
y back-line
^Y back-line
^K back-line
^P back-line
J forw-line-force
K back-line-force
Y back-line-force
\eej forw-newline
\eek back-newline
d forw-scroll
^D forw-scroll
u back-scroll
^U back-scroll
\e40 forw-screen
f forw-screen
^F forw-screen
^V forw-screen
\ekD forw-screen
b back-screen
^B back-screen
\eev back-screen
\ekU back-screen
z forw-window
w back-window
\ee\e40 forw-screen-force
\eeb back-screen-force
F forw-forever
\eeF forw-until-hilite
R repaint-flush
\er forw\-line
\en forw\-line
e forw\-line
j forw\-line
\ekd forw\-line
\*^E forw\-line
\*^N forw\-line
k back\-line
y back\-line
\*^Y back\-line
\*^K back\-line
\*^P back\-line
\eku back\-line
J forw\-line\-force
K back\-line\-force
Y back\-line\-force
d forw\-scroll
\*^D forw\-scroll
u back\-scroll
\*^U back\-scroll
\e40 forw\-screen
f forw\-screen
\*^F forw\-screen
\*^V forw\-screen
\ekD forw\-screen
b back\-screen
\*^B back\-screen
\eev back\-screen
\ekU back\-screen
z forw\-window
w back\-window
\ee\e40 forw\-screen\-force
\eeb back\-screen\-force
\eej forw\-newline
\eek back\-newline
F forw\-forever
\eeF forw\-until\-hilite
\eef forw\-bell\-hilite
R repaint\-flush
r repaint
^R repaint
^L repaint
\eeu undo-hilite
\eeU clear-search
g goto-line
\ekh goto-line
< goto-line
\ee< goto-line
\*^R repaint
\*^L repaint
\eeu undo\-hilite
\eeU clear\-search
g goto\-line
\ekh goto\-line
\ekH goto\-line \ee{
\ekI goto\-line \ee{
\eke goto\-end
\ekE goto\-end \ee}
\ekF goto\-end \ee}
< goto\-line
\ee< goto\-line
p percent
% percent
\ee( left-scroll
\ee) right-scroll
\ekl left-scroll
\ekr right-scroll
\ee{ no-scroll
\ee} end-scroll
{ forw-bracket {}
} back-bracket {}
( forw-bracket ()
) back-bracket ()
[ forw-bracket []
] back-bracket []
\ee^F forw-bracket
\ee^B back-bracket
G goto-end
\ee> goto-end
> goto-end
\eke goto-end
\eeG goto-end-buffered
\ee( left\-scroll
\ee) right\-scroll
\ee{ no\-scroll
\ee} end\-scroll
\ekl left\-scroll
\ekr right\-scroll
\ekL no\-scroll
\ekM no\-scroll
\ekR end\-scroll
\ekS end\-scroll
{ forw\-bracket {}
} back\-bracket {}
( forw\-bracket ()
) back\-bracket ()
[ forw\-bracket []
] back\-bracket []
\ee\*^F forw\-bracket
\ee\*^B back\-bracket
G goto\-end
\ee> goto\-end
> goto\-end
P goto\-pos
\eeG goto\-end\-buffered
\&= status
^G status
\*^G status
:f status
/ forw-search
? back-search
\ee/ forw-search *
\ee? back-search *
n repeat-search
\een repeat-search-all
N reverse-search
\eeN reverse-search-all
^O^N osc8-forw-search
^On osc8-forw-search
^O^P osc8-back-search
^Op osc8-back-search
^O^O osc8-open
/ forw\-search
? back\-search
\ee/ forw\-search *
\ee? back\-search *
n repeat\-search
\een repeat\-search\-all
N reverse\-search
\eeN reverse\-search\-all
& filter
m set-mark
M set-mark-bottom
\eem clear-mark
\&' goto-mark
^X^X goto-mark
m set\-mark
M set\-mark\-bottom
\eem clear\-mark
\&\*' goto\-mark
\*^X\*^X goto\-mark
E examine
:e examine
^X^V examine
:n next-file
:p prev-file
t next-tag
T prev-tag
:x index-file
:d remove-file
- toggle-option
:t toggle-option t
s toggle-option o
\*^X\*^V examine
:n next\-file
:p prev\-file
\*^O\*^N osc8\-forw\-search
\*^On osc8\-forw\-search
\*^O\*^P osc8\-back\-search
\*^Op osc8\-back\-search
\*^O\*^O osc8\-open
\*^Oo osc8\-open
\*^O\*^L osc8\-jump
\*^Ol osc8\-jump
t next\-tag
T prev\-tag
:x index\-file
:d remove\-file
\- toggle\-option
:t toggle\-option t
s toggle\-option o
## Use a long option name by starting the
## extra string with ONE dash; eg:
## s toggle-option -log-file\en
\&_ display-option
## s toggle\-option \-log\-file\en
\&_ display\-option
| pipe
v visual
! shell
@@ -261,8 +320,24 @@ v visual
+ firstcmd
\ee[M mouse
\ee[< mouse6
\ekp1 goto\-end
\ekp2 forw\-line
\ekp3 forw\-screen
\ekp4 left\-scroll
\ekp6 right\-scroll
\ekp7 goto\-line
\ekp8 back\-line
\ekp9 back\-screen
\ekp0 noaction 0
\ekp* noaction *
\ekp/ noaction /
\ekp\- noaction \-
\ekp+ noaction +
\ekp. noaction .
\ekp, noaction ,
H help
h help
\ek1 help
V version
0 digit
1 digit
@@ -281,7 +356,6 @@ Q quit
ZZ quit
.TE
.RE
.sp
.SH PRECEDENCE
Commands specified by
.B lesskey
@@ -296,9 +370,9 @@ will give an error beep for an "invalid" command,
but not for a "noaction" command.
In addition, ALL default commands may be disabled by
adding this control line to the input file:
.sp
.PP
#stop
.sp
.PP
This will cause all default commands to be ignored.
The #stop line should be the last line in that section of the file.
.PP
@@ -310,9 +384,11 @@ For example, failure to provide a "quit" command can lead to frustration.
.
.SH "LINE EDITING SECTION"
The line-editing section begins with the line:
.sp
#line-edit
.sp
.PP
.EX
#line\-edit
.EE
.PP
This section specifies new key bindings for the line editing commands,
in a manner similar to the way key bindings for
ordinary commands are specified in the #command section.
@@ -323,14 +399,15 @@ one per line as in the example below.
The following input file describes the set of
default line-editing keys used by
.BR less :
.sp
.PP
.RS 5m
.TS
l l.
#line-edit
\et forw-complete
\e17 back-complete
\ee\et back-complete
#line\-edit
\et forw\-complete
\e17 back\-complete
\eekt back\-complete
\ee\et back\-complete
^L expand
^V literal
^A literal
@@ -338,16 +415,21 @@ l l.
\ekr right
\eeh left
\ekl left
\eeb word-left
\ee\ekl word-left
\eew word-right
\ee\ekr word-right
\eeb word\-left
\ee\ekl word\-left
\ee\ekL word\-left
\eew word\-right
\ee\ekr word\-right
\ee\ekR word\-right
\eei insert
\eki insert
\eex delete
\ekx delete
\eeX word-delete
\eekx word-delete
\ee\eb word-backspace
\eeX word\-delete
\eekx word\-delete
\ekX word\-delete
\ee\eb word\-backspace
\ekB word\-backspace
\ee0 home
\ekh home
\ee$ end
@@ -355,18 +437,31 @@ l l.
\eek up
\eku up
\eej down
\ekd down
^G abort
\ekp1 end
\ekp2 down
\ekp4 left
\ekp6 right
\ekp7 home
\ekp8 up
\ekp0 noaction 0
\ekp* noaction *
\ekp/ noaction /
\ekp\- noaction \-
\ekp+ noaction +
\ekp. noaction .
\ekp, noaction ,
\ee[M mouse
\ee[< mouse6
.TE
.RE
.sp
.
.SH "LESS ENVIRONMENT VARIABLES"
The environment variable section begins with the line
.sp
.PP
#env
.sp
.PP
Following this line is a list of environment variable assignments.
Each line consists of an environment variable name, an equals sign (=)
and the value to be assigned to the environment variable.
@@ -376,7 +471,7 @@ Variables assigned in this way are visible only to
If a variable is specified in the system environment and also in a
lesskey file, the value in the lesskey file takes precedence.
.
.sp
.PP
If the variable name is followed by += rather than =,
the string is appended to the variable's existing value.
This currently works only if any += lines immediately follow
@@ -390,7 +485,7 @@ it should be appended to the end of the preceding line.
(It cannot be added to the beginning of the += string because space after
the equals sign is ignored, as noted above.)
.
.sp
.PP
In the string after the = sign, a substring of the form ${NAME}
is replaced with the value of the environment variable "NAME".
The value of the variable may come from either the system environment,
@@ -417,18 +512,20 @@ the remainder of the line is parsed if and only if the running version of
matches the operator.
This can be helpful if a lesskey file is used by different versions of
.BR less .
.sp
For example, suppose that a new command named 'sideways-search' is added in
.PP
For example, suppose that a new command named 'sideways\-search' is added in
.B less
version 777.
Then the following line would assign the command to the Q key, but only in versions of
.B less
which support it. The line would be ignored by versions earlier than 777.
.sp
.PP
.EX
.nf
#version >= 777 Q sideways-search
#version >= 777 Q sideways\-search
.fi
.sp
.EE
.PP
These six operators are supported:
.RS 5m
.TS
@@ -441,7 +538,7 @@ l l.
!= Not equal to
.TE
.RE
.sp
.PP
The #version feature is not supported in
.B less
and
@@ -453,14 +550,16 @@ In those older versions, all #version lines are ignored.
The following input file sets the \-i and \-S options when
.B less
is run and, on version 595 and higher, adds a \-\-color option.
.sp
.PP
.EX
.nf
#env
## (Note that there must be a space at the end of the next line,
## to separate the --color option from the -S option.)
## to separate the \-\-color option from the \-S option.)
LESS = \-i\ \-S\
#version\ >=\ 595\ \ LESS\ +=\ \-\-color=Hkc
.fi
.EE
.
.SH "SEE ALSO"
.BR less (1)
@@ -471,7 +570,7 @@ which start with a NUL character (0).
This NUL character should be represented as \e340 in a lesskey file.
.
.SH COPYRIGHT
Copyright (C) 1984-2025 Mark Nudelman
Copyright (C) 1984-2026 Mark Nudelman
.PP
less is part of the GNU project and is free software.
You can redistribute it and/or modify it
@@ -496,4 +595,7 @@ See the GNU General Public License for more details.
.
Mark Nudelman
.br
Report bugs at https://github.com/gwsw/less/issues.
Report bugs at
.nh
https://\*:github\*:.com/\*:gwsw/\*:less/\*:issues.
.hy
+37 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -53,6 +53,7 @@ static constant struct lesskey_cmdname cmdnames[] =
{ "first-cmd", A_FIRSTCMD },
{ "firstcmd", A_FIRSTCMD },
{ "flush-repaint", A_FREPAINT },
{ "forw-bell-hilite", A_F_FOREVER_BELL },
{ "forw-bracket", A_F_BRACKET },
{ "forw-forever", A_F_FOREVER },
{ "forw-line", A_F_LINE },
@@ -68,6 +69,7 @@ static constant struct lesskey_cmdname cmdnames[] =
{ "goto-end-buffered", A_GOEND_BUF },
{ "goto-line", A_GOLINE },
{ "goto-mark", A_GOMARK },
{ "goto-pos", A_GOPOS },
{ "help", A_HELP },
{ "index-file", A_INDEX_FILE },
{ "invalid", A_UINVALID },
@@ -80,6 +82,7 @@ static constant struct lesskey_cmdname cmdnames[] =
{ "noaction", A_NOACTION },
{ "osc8-forw-search", A_OSC8_F_SEARCH },
{ "osc8-back-search", A_OSC8_B_SEARCH },
{ "osc8-jump", A_OSC8_JUMP },
{ "osc8-open", A_OSC8_OPEN },
{ "percent", A_PERCENT },
{ "pipe", A_PIPE },
@@ -125,6 +128,7 @@ static constant struct lesskey_cmdname editnames[] =
{ "literal", EC_LITERAL },
{ "mouse", EC_X11MOUSE },
{ "mouse6", EC_X116MOUSE },
{ "noaction", A_NOACTION },
{ "right", EC_RIGHT },
{ "up", EC_UP },
{ "word-backspace", EC_W_BACKSPACE },
@@ -247,6 +251,7 @@ static constant char * tstr(char **pp, int xlate)
case 'k':
if (xlate)
{
ch = 0;
switch (*++p)
{
case 'b': ch = SK_BACKSPACE; break;
@@ -254,19 +259,49 @@ static constant char * tstr(char **pp, int xlate)
case 'd': ch = SK_DOWN_ARROW; break;
case 'D': ch = SK_PAGE_DOWN; break;
case 'e': ch = SK_END; break;
case 'E': ch = SK_CTL_END; break;
case 'F': ch = SK_SHIFT_END; break;
case 'h': ch = SK_HOME; break;
case 'H': ch = SK_CTL_HOME; break;
case 'I': ch = SK_SHIFT_HOME; break;
case 'i': ch = SK_INSERT; break;
case 'l': ch = SK_LEFT_ARROW; break;
case 'L': ch = SK_CTL_LEFT_ARROW; break;
case 'M': ch = SK_SHIFT_LEFT_ARROW; break;
case 'r': ch = SK_RIGHT_ARROW; break;
case 'R': ch = SK_CTL_RIGHT_ARROW; break;
case 'S': ch = SK_SHIFT_RIGHT_ARROW; break;
case 't': ch = SK_BACKTAB; break;
case 'u': ch = SK_UP_ARROW; break;
case 'U': ch = SK_PAGE_UP; break;
case 'x': ch = SK_DELETE; break;
case 'X': ch = SK_CTL_DELETE; break;
case '1': ch = SK_F1; break;
default:
case 'p':
switch (*++p)
{
case '1': ch = SK_PAD_DL; break;
case '2': ch = SK_PAD_D; break;
case '3': ch = SK_PAD_DR; break;
case '4': ch = SK_PAD_L; break;
case '5': ch = SK_PAD_CENTER; break;
case '6': ch = SK_PAD_R; break;
case '7': ch = SK_PAD_UL; break;
case '8': ch = SK_PAD_U; break;
case '9': ch = SK_PAD_UR; break;
case '0': ch = SK_PAD_ZERO; break;
case '*': ch = SK_PAD_STAR; break;
case '/': ch = SK_PAD_SLASH; break;
case '-': ch = SK_PAD_DASH; break;
case '+': ch = SK_PAD_PLUS; break;
case '.': ch = SK_PAD_DOT; break;
case ',': ch = SK_PAD_COMMA; break;
case 'e': ch = SK_PAD_ENTER; break;
}
break;
}
if (ch == 0)
{
parse_error("invalid escape sequence \"\\k%s\"", char_string(buf, *p, 0));
*pp = increment_pointer(p);
return ("");
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+70 -53
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -97,7 +97,7 @@ extern int twiddle;
extern int status_col;
extern int status_col_width;
extern int linenum_width;
extern int auto_wrap, ignaw;
extern int auto_wrap, defer_wrap;
extern int bo_s_width, bo_e_width;
extern int ul_s_width, ul_e_width;
extern int bl_s_width, bl_e_width;
@@ -129,12 +129,14 @@ static struct color_map color_map[] = {
{ AT_COLOR_BIN, "kR" },
{ AT_COLOR_CTRL, "kR" },
{ AT_COLOR_ERROR, "kY" },
{ AT_COLOR_LINENUM, "c" },
{ AT_COLOR_LINENUM, "c*" },
{ AT_COLOR_MARK, "Wb" },
{ AT_COLOR_PROMPT, "kC" },
{ AT_COLOR_RSCROLL, "kc" },
{ AT_COLOR_HEADER, "" },
{ AT_COLOR_SEARCH, "kG" },
{ AT_COLOR_TILDE, "-d" },
{ AT_COLOR_TARGET, "-u" },
{ AT_COLOR_SUBSEARCH(1), "ky" },
{ AT_COLOR_SUBSEARCH(2), "wb" },
{ AT_COLOR_SUBSEARCH(3), "YM" },
@@ -185,7 +187,7 @@ public void init_line(void)
s = skipspc(s);
if (*s == ',')
++s;
xbuf_add_data(&xbuf, (constant void *) &num, sizeof(num));
xbuf_add_data(&xbuf, &num, sizeof(num));
++osc_ansi_allow_count;
}
osc_ansi_allow = (long *) xbuf.data;
@@ -436,7 +438,7 @@ public void plinestart(POSITION pos)
for (i = 0; i + len < (size_t) linenum_width; i++)
add_pfx(' ', AT_NORMAL);
for (i = 0; i < len; i++)
add_pfx(buf[i], AT_BOLD|AT_COLOR_LINENUM);
add_pfx(buf[i], use_color ? AT_COLOR_LINENUM : AT_BOLD);
add_pfx(' ', AT_NORMAL);
}
end_column = (int) linebuf.pfx_end; /*{{type-issue}}*/
@@ -446,7 +448,7 @@ public void plinestart(POSITION pos)
* Return the width of the line prefix (status column and line number).
* {{ Actual line number can be wider than linenum_width. }}
*/
public int line_pfx_width(void)
public unsigned line_pfx_width(void)
{
int width = 0;
if (status_col)
@@ -1077,7 +1079,7 @@ static int flush_mbc_buf(POSITION pos)
*/
public int pappend_b(char c, POSITION pos, lbool before_pendc)
{
LWCHAR ch = c & 0377;
LWCHAR ch = (unsigned char) c;
int r;
if (pendc && !before_pendc)
@@ -1192,6 +1194,22 @@ static int store_control_char(LWCHAR ch, constant char *rep, POSITION pos)
return (0);
}
/*
* Remove invalid ANSI sequence.
*/
static void remove_ansi(void)
{
constant char *start = (cshift < hshift) ? xbuf_char_data(&shifted_ansi): linebuf.buf;
size_t *end = (cshift < hshift) ? &shifted_ansi.end : &linebuf.end;
constant char *p = start + *end;
LWCHAR bch;
do {
bch = step_charc(&p, -1, start);
} while (p > start && (!IS_CSI_START(bch) || line_ansi->escs_in_seq-- > 0));
*end = ptr_diff(p, start);
xbuf_reset(&last_ansi);
}
static int store_ansi(LWCHAR ch, constant char *rep, POSITION pos)
{
switch (ansi_step2(line_ansi, ch, pos != NULL_POSITION))
@@ -1215,18 +1233,7 @@ static int store_ansi(LWCHAR ch, constant char *rep, POSITION pos)
curr_last_ansi = (curr_last_ansi + 1) % NUM_LAST_ANSIS;
break;
case ANSI_ERR:
{
/* Remove whole unrecognized sequence. */
constant char *start = (cshift < hshift) ? xbuf_char_data(&shifted_ansi): linebuf.buf;
size_t *end = (cshift < hshift) ? &shifted_ansi.end : &linebuf.end;
constant char *p = start + *end;
LWCHAR bch;
do {
bch = step_charc(&p, -1, start);
} while (p > start && (!IS_CSI_START(bch) || line_ansi->escs_in_seq-- > 0));
*end = ptr_diff(p, start);
}
xbuf_reset(&last_ansi);
remove_ansi();
ansi_done(line_ansi);
line_ansi = NULL;
break;
@@ -1388,13 +1395,12 @@ static void add_attr_normal(void)
{
switch (line_ansi->ostate)
{
case OSC_TYPENUM:
case OSC8_PARAMS:
case OSC8_URI:
case OSC_STRING:
addstr_linebuf("\033\\", AT_ANSI, 0);
case OSC_START:
case OSC_END:
break;
default:
/* We're in an unterminated OSC sequence; remove it. */
remove_ansi();
break;
}
ansi_done(line_ansi);
@@ -1410,7 +1416,7 @@ static void add_attr_normal(void)
/*
* Terminate the line in the line buffer.
*/
public void pdone(lbool endline, lbool chopped, lbool forw)
public void pdone(lbool endline, lbool chopped, lbool forw, lbool full_pad)
{
(void) pflushmbc();
linebuf.prev_end = (!endline && !chopped) ? linebuf.end : 0;
@@ -1462,8 +1468,8 @@ public void pdone(lbool endline, lbool chopped, lbool forw)
/*
* If we're coloring a status line, fill out the line with spaces.
*/
if (status_line && line_mark_attr != 0) {
while (end_column +1 < sc_width + cshift)
if (status_line && (line_mark_attr != 0 || full_pad)) {
while (end_column < sc_width + cshift)
add_linebuf(' ', line_mark_attr, 1);
}
@@ -1480,14 +1486,14 @@ public void pdone(lbool endline, lbool chopped, lbool forw)
* the next line is blank. In that case the single newline output for
* that blank line would be ignored!)
*/
if (end_column < sc_width + cshift || !auto_wrap || (endline && ignaw) || ctldisp == OPT_ON)
if (end_column < sc_width + cshift || !auto_wrap || (endline && defer_wrap) || ctldisp == OPT_ON)
{
add_linebuf('\n', AT_NORMAL, 0);
}
else if (ignaw && end_column >= sc_width + cshift && forw)
else if (defer_wrap && end_column >= sc_width + cshift && forw)
{
/*
* Terminals with "ignaw" don't wrap until they *really* need
* Terminals with "defer_wrap" don't wrap until they *really* need
* to, i.e. when the character *after* the last one to fit on a
* line is output. But they are too hard to deal with when they
* get in the state where a full screen width of characters
@@ -1509,7 +1515,7 @@ public void pdone(lbool endline, lbool chopped, lbool forw)
* colored with the last char's background color before the color
* reset sequence is sent. Clear the line to reset the background color.
*/
if (auto_wrap && !ignaw && end_column >= sc_width + cshift)
if (auto_wrap && !defer_wrap && end_column >= sc_width + cshift)
clear_after_line = TRUE;
set_linebuf(linebuf.end, '\0', AT_NORMAL);
}
@@ -1664,7 +1670,7 @@ public int gline(size_t i, int *ap)
{
if (i == 0)
{
*ap = AT_BOLD;
*ap = use_color ? AT_COLOR_TILDE : AT_BOLD;
return '~';
}
--i;
@@ -1681,7 +1687,7 @@ public int gline(size_t i, int *ap)
}
i += linebuf.print - linebuf.pfx_end;
*ap = linebuf.attr[i];
return (linebuf.buf[i] & 0xFF);
return (unsigned char) linebuf.buf[i];
}
/*
@@ -1878,10 +1884,10 @@ static int pappstr(constant char *str)
/*
* Load a string into the line buffer.
* If the string is too long to fit on the screen,
* If the string is too long to fit on the screen (minus reserve chars),
* truncate the beginning of the string to fit.
*/
public void load_line(constant char *str)
public void load_line(constant char *str, int attr, int reserve)
{
int save_hshift = hshift;
hshift = 0;
@@ -1889,6 +1895,7 @@ public void load_line(constant char *str)
/* We're overwriting the line buffer, so what's in it will no longer be contiguous. */
set_line_contig_pos(NULL_POSITION);
sc_width -= reserve;
for (;;)
{
prewind(FALSE);
@@ -1903,39 +1910,49 @@ public void load_line(constant char *str)
}
set_linebuf(linebuf.end, '\0', AT_NORMAL);
linebuf.prev_end = 0;
sc_width += reserve;
/* Color the prompt unless it has ansi sequences in it. */
if (!ansi_in_line)
{
size_t i;
for (i = linebuf.print; i < linebuf.end; i++)
set_linebuf(i, linebuf.buf[i], AT_STANDOUT|AT_COLOR_PROMPT);
set_linebuf(i, linebuf.buf[i], attr);
}
hshift = save_hshift;
}
/*
* Find the length of the longest displayed line on the screen.
*/
public int longest_line_width(void)
{
POSITION pos;
int save_width;
int sindex;
int longest = 0;
save_width = sc_width;
sc_width = INT_MAX; /* so forw_line() won't chop */
for (sindex = TOP; sindex < sc_height-1; sindex++)
if ((pos = position(sindex)) != NULL_POSITION)
break;
for (; sindex < sc_height-1 && pos != NULL_POSITION; sindex++)
{
pos = forw_line(pos, NULL, NULL);
if (end_column > longest)
longest = end_column;
}
sc_width = save_width;
return longest;
}
/*
* Find the shift necessary to show the end of the longest displayed line.
*/
public int rrshift(void)
{
POSITION pos;
int save_width;
int sline;
int longest = 0;
save_width = sc_width;
sc_width = INT_MAX; /* so forw_line() won't chop */
for (sline = TOP; sline < sc_height; sline++)
if ((pos = position(sline)) != NULL_POSITION)
break;
for (; sline < sc_height && pos != NULL_POSITION; sline++)
{
pos = forw_line(pos, NULL, NULL);
if (end_column > longest)
longest = end_column;
}
sc_width = save_width;
int longest = longest_line_width();
if (longest < sc_width)
return 0;
return longest - sc_width;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+12 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -32,6 +32,7 @@
#endif
#endif
extern int sigs;
extern IFILE curr_ifile;
@@ -92,7 +93,7 @@ public void lsystem(constant char *cmd, constant char *donemsg)
/*
* De-initialize the terminal and take out of raw mode.
*/
deinit();
term_deinit();
flush(); /* Make sure the deinit chars get out */
raw_mode(0);
#if MSDOS_COMPILER==WIN32C
@@ -135,9 +136,10 @@ public void lsystem(constant char *cmd, constant char *donemsg)
char *esccmd = shell_quote(cmd);
if (esccmd != NULL)
{
size_t len = strlen(shell) + strlen(esccmd) + 5;
constant char *copt = shell_coption();
size_t len = strlen(shell) + strlen(esccmd) + strlen(copt) + 3;
p = (char *) ecalloc(len, sizeof(char));
SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd);
SNPRINTF3(p, len, "%s %s %s", shell, copt, esccmd);
free(esccmd);
}
}
@@ -191,7 +193,7 @@ public void lsystem(constant char *cmd, constant char *donemsg)
putchr('\n');
flush();
}
init();
term_init();
screen_trashed();
#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
@@ -220,15 +222,13 @@ public void lsystem(constant char *cmd, constant char *donemsg)
*/
reedit_ifile(save_ifile);
#if defined(SIGWINCH) || defined(SIGWIND)
/*
* Since we were ignoring window change signals while we executed
* the system command, we must assume the window changed.
* Warning: this leaves a signal pending (in "sigs"),
* so psignals() should be called soon after lsystem().
*/
winch(0);
#endif
sigs |= S_WINCH;
}
#endif
@@ -266,7 +266,7 @@ public int pipe_mark(char c, constant char *cmd)
if (c == '.')
return (pipe_data(cmd, tpos, bpos));
else if (mpos <= tpos)
else if (mpos < tpos)
return (pipe_data(cmd, mpos, bpos));
else if (bpos == NULL_POSITION)
return (pipe_data(cmd, tpos, bpos));
@@ -305,7 +305,7 @@ public int pipe_data(constant char *cmd, POSITION spos, POSITION epos)
putstr(cmd);
putstr("\n");
deinit();
term_deinit();
flush();
raw_mode(0);
init_signals(0);
@@ -351,11 +351,11 @@ public int pipe_data(constant char *cmd, POSITION spos, POSITION epos)
#endif
init_signals(1);
raw_mode(1);
init();
term_init();
screen_trashed();
#if defined(SIGWINCH) || defined(SIGWIND)
/* {{ Probably don't need this here. }} */
winch(0);
lwinch(0);
#endif
return (0);
}
+36 -76
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -29,7 +29,7 @@ public unsigned less_acp = CP_ACP;
public char * every_first_cmd = NULL;
public lbool new_file;
public int is_tty;
public lbool is_tty;
public IFILE curr_ifile = NULL_IFILE;
public IFILE old_ifile = NULL_IFILE;
public struct scrpos initial_scrpos;
@@ -38,8 +38,9 @@ public POSITION end_attnpos = NULL_POSITION;
public int wscroll;
public constant char *progname;
public lbool quitting = FALSE;
public int dohelp;
public lbool dohelp = FALSE;
public char * init_header = NULL;
public char * no_config = NULL;
static int secure_allow_features;
#if LOGFILE
@@ -67,7 +68,7 @@ public time_type less_start_time;
static wchar_t consoleTitle[256];
#endif
public int one_screen;
public lbool one_screen;
extern int less_is_more;
extern lbool missing_cap;
extern int know_dumb;
@@ -75,8 +76,9 @@ extern int quit_if_one_screen;
extern int no_init;
extern int errmsgs;
extern int redraw_on_quit;
extern int term_init_done;
extern int term_addrs;
extern lbool first_time;
extern lbool term_init_ever;
#if MSDOS_COMPILER==WIN32C && (defined(__MINGW32__) || defined(_MSC_VER))
/* malloc'ed 0-terminated utf8 of 0-terminated wide ws, or null on errors */
@@ -156,26 +158,16 @@ cleanup:
}
#endif
#if !SECURE
static int security_feature_error(constant char *type, size_t len, constant char *name)
{
PARG parg;
size_t msglen = len + strlen(type) + 64;
char *msg = ecalloc(msglen, sizeof(char));
SNPRINTF3(msg, msglen, "LESSSECURE_ALLOW: %s feature name \"%.*s\"", type, (int) len, name);
parg.p_string = msg;
error("%s", &parg);
free(msg);
return 0;
}
/*
* Return the SF_xxx value of a secure feature given the name of the feature.
* Set the secure_allow_features bitmask, which controls
* whether certain secure features are allowed.
*/
static int security_feature(constant char *name, size_t len)
static void init_secure(void)
{
struct secure_feature { constant char *name; int sf_value; };
static struct secure_feature features[] = {
#if SECURE
secure_allow_features = 0;
#else
static struct csl_bitmap_def security_features[] = {
{ "edit", SF_EDIT },
{ "examine", SF_EXAMINE },
{ "glob", SF_GLOB },
@@ -189,33 +181,6 @@ static int security_feature(constant char *name, size_t len)
{ "stop", SF_STOP },
{ "tags", SF_TAGS },
};
int i;
int match = -1;
for (i = 0; i < countof(features); i++)
{
if (strncmp(features[i].name, name, len) == 0)
{
if (match >= 0) /* name is ambiguous */
return security_feature_error("ambiguous", len, name);
match = i;
}
}
if (match < 0)
return security_feature_error("invalid", len, name);
return features[match].sf_value;
}
#endif /* !SECURE */
/*
* Set the secure_allow_features bitmask, which controls
* whether certain secure features are allowed.
*/
static void init_secure(void)
{
#if SECURE
secure_allow_features = 0;
#else
constant char *str = lgetenv("LESSSECURE");
if (isnullenv(str))
secure_allow_features = ~0; /* allow everything */
@@ -224,19 +189,8 @@ static void init_secure(void)
str = lgetenv("LESSSECURE_ALLOW");
if (!isnullenv(str))
{
for (;;)
{
constant char *estr;
while (*str == ' ' || *str == ',') ++str; /* skip leading spaces/commas */
if (*str == '\0') break;
estr = strchr(str, ',');
if (estr == NULL) estr = str + strlen(str);
while (estr > str && estr[-1] == ' ') --estr; /* trim trailing spaces */
secure_allow_features |= security_feature(str, ptr_diff(estr, str));
str = estr;
}
}
secure_allow_features = parse_csl_bitmap(str,
security_features, countof(security_features), "LESSSECURE_ALLOW");
#endif
}
@@ -251,8 +205,11 @@ int main(int argc, constant char *argv[])
struct xbuffer xfiles;
constant int *files;
size_t num_files;
size_t f;
lbool end_opts = FALSE;
lbool posixly_correct = FALSE;
lbool posixly_correct;
no_config = getenv("LESSNOCONFIG");
#if MSDOS_COMPILER==WIN32C && (defined(__MINGW32__) || defined(_MSC_VER))
if (GetACP() != CP_UTF8) /* not using a UTF-8 manifest */
@@ -295,7 +252,7 @@ int main(int argc, constant char *argv[])
* Process command line arguments and LESS environment arguments.
* Command line arguments override environment arguments.
*/
is_tty = isatty(1);
is_tty = (isatty(1) != 0);
init_mark();
init_cmds();
init_poll();
@@ -325,7 +282,7 @@ 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')
xbuf_init(&xfiles);
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
posixly_correct = (lgetenv("POSIXLY_CORRECT") != NULL);
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "--") == 0)
@@ -336,7 +293,7 @@ int main(int argc, constant char *argv[])
{
if (posixly_correct)
end_opts = TRUE;
xbuf_add_data(&xfiles, (constant unsigned char *) &i, sizeof(i));
xbuf_add_data(&xfiles, &i, sizeof(i));
}
}
#undef isoptstring
@@ -354,7 +311,8 @@ int main(int argc, constant char *argv[])
if (less_is_more)
no_init = TRUE;
get_term();
if (is_tty)
get_term();
expand_cmd_tables();
#if EDITOR
@@ -379,7 +337,7 @@ int main(int argc, constant char *argv[])
ifile = get_ifile(FAKE_HELPFILE, ifile);
files = (constant int *) xfiles.data;
num_files = xfiles.end / sizeof(int);
for (i = 0; i < num_files; i++)
for (f = 0; f < num_files; f++)
{
#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC)
/*
@@ -393,7 +351,7 @@ int main(int argc, constant char *argv[])
char *gfilename;
char *qfilename;
gfilename = lglob(argv[files[i]]);
gfilename = lglob(argv[files[f]]);
init_textlist(&tlist, gfilename);
filename = NULL;
while ((filename = forw_textlist(&tlist, filename)) != NULL)
@@ -405,7 +363,7 @@ int main(int argc, constant char *argv[])
}
free(gfilename);
#else
(void) get_ifile(argv[files[i]], ifile);
(void) get_ifile(argv[files[f]], ifile);
ifile = prev_ifile(NULL_IFILE);
#endif
}
@@ -420,10 +378,10 @@ int main(int argc, constant char *argv[])
* Output is not a tty.
* Just copy the input file(s) to output.
*/
set_output(1); /* write to stdout */
SET_BINARY(1);
if (edit_first() == 0)
{
set_output(1, TRUE); /* write to stdout */
do {
cat_file();
} while (edit_next(1) == 0);
@@ -476,7 +434,7 @@ int main(int argc, constant char *argv[])
/*
* See if file fits on one screen to decide whether
* to send terminal init. But don't need this
* if -X (no_init) overrides this (see init()).
* if -X (no_init) overrides this (see term_init()).
*/
if (quit_if_one_screen)
{
@@ -504,8 +462,10 @@ int main(int argc, constant char *argv[])
get_return();
putchr('\n');
}
set_output(1);
init();
set_output(1, FALSE);
#if MSDOS_COMPILER
term_init();
#endif
commands();
quit(QUIT_OK);
/*NOTREACHED*/
@@ -617,9 +577,9 @@ public void quit(int status)
check_altpipe_error();
if (interactive())
clear_bot();
deinit();
term_deinit();
flush();
if (redraw_on_quit && term_init_done)
if (redraw_on_quit && term_addrs)
{
/*
* The last file text displayed might have been on an
+144 -62
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -27,7 +27,6 @@ struct mark
* because we don't want to create an ifile until the
* user explicitly requests the file (by name or mark).
*/
char m_letter; /* Associated character */
IFILE m_ifile; /* Input file being marked */
char *m_filename; /* Name of the input file */
struct scrpos m_scrpos; /* Position of the mark */
@@ -39,12 +38,14 @@ struct mark
* The final one is lmark, for the "last mark"; addressed by the apostrophe.
*/
#define NMARKS ((2*26)+2) /* a-z, A-Z, mousemark, lastmark */
#define NUMARKS ((2*26)+1) /* user marks (not lastmark) */
#define MOUSEMARK (NMARKS-2)
#define NUMARKS (NMARKS-1) /* user marks (not lastmark) */
#define LASTMARK (NMARKS-1)
#define MOUSEMARK (LASTMARK-1)
static struct mark marks[NMARKS];
public int marks_modified = 0;
public lbool marks_modified = FALSE;
#if CMD_HISTORY
static struct mark file_marks[NMARKS];
#endif
/*
* Initialize a mark struct.
@@ -69,17 +70,23 @@ public void init_mark(void)
for (i = 0; i < NMARKS; i++)
{
char letter;
switch (i) {
case MOUSEMARK: letter = '#'; break;
case LASTMARK: letter = '\''; break;
default: letter = (char) ((i < 26) ? 'a'+i : 'A'+i-26); break;
}
marks[i].m_letter = letter;
cmark(&marks[i], NULL_IFILE, NULL_POSITION, -1);
#if CMD_HISTORY
cmark(&file_marks[i], NULL_IFILE, NULL_POSITION, -1);
#endif
}
}
static void mark_clear(struct mark *m)
{
m->m_scrpos.pos = NULL_POSITION;
}
static lbool mark_is_set(struct mark *m)
{
return m->m_scrpos.pos != NULL_POSITION;
}
/*
* Set m_ifile and clear m_filename.
*/
@@ -101,23 +108,48 @@ static void mark_get_ifile(struct mark *m)
mark_set_ifile(m, get_ifile(m->m_filename, prev_ifile(NULL_IFILE)));
}
/*
* Return the letter associated with a mark index.
*/
static char mark_letter(int index)
{
switch (index) {
case LASTMARK: return '\'';
case MOUSEMARK: return '#';
default: return (char) ((index < 26) ? 'a'+index : 'A'+index-26);
}
}
/*
* Return the mark table index identified by a character.
*/
static int mark_index(char c)
{
if (c >= 'a' && c <= 'z')
return c-'a';
if (c >= 'A' && c <= 'Z')
return c-'A'+26;
if (c == '\'')
return LASTMARK;
if (c == '#')
return MOUSEMARK;
return -1;
}
/*
* Return the user mark struct identified by a character.
*/
static struct mark * getumark(char c)
{
PARG parg;
if (c >= 'a' && c <= 'z')
return (&marks[c-'a']);
if (c >= 'A' && c <= 'Z')
return (&marks[c-'A'+26]);
if (c == '\'')
return (&marks[LASTMARK]);
if (c == '#')
return (&marks[MOUSEMARK]);
parg.p_char = (char) c;
error("Invalid mark letter %c", &parg);
return (NULL);
int index = mark_index(c);
if (index < 0 || index >= NUMARKS)
{
PARG parg;
parg.p_char = (char) c;
error("Invalid mark letter %c", &parg);
return NULL;
}
return &marks[index];
}
/*
@@ -129,6 +161,7 @@ static struct mark * getmark(char c)
{
struct mark *m;
static struct mark sm;
POSITION pos;
switch (c)
{
@@ -149,7 +182,13 @@ static struct mark * getmark(char c)
return (NULL);
}
m = &sm;
cmark(m, curr_ifile, ch_tell(), sc_height);
pos = ch_tell();
if (pos == NULL_POSITION)
return (NULL);
pos = back_line(pos, NULL);
if (pos == NULL_POSITION)
return (NULL);
cmark(m, curr_ifile, pos, sc_height-1);
break;
case '.':
/*
@@ -172,7 +211,7 @@ static struct mark * getmark(char c)
m = getumark(c);
if (m == NULL)
break;
if (m->m_scrpos.pos == NULL_POSITION)
if (!mark_is_set(m))
{
error("Mark not set", NULL_PARG);
return (NULL);
@@ -185,7 +224,7 @@ static struct mark * getmark(char c)
/*
* Is a mark letter invalid?
*/
public int badmark(char c)
public lbool badmark(char c)
{
return (getmark(c) == NULL);
}
@@ -193,22 +232,40 @@ public int badmark(char c)
/*
* Set a user-defined mark.
*/
public void setmark(char c, int where)
public void setmark(char c, int where, LINENUM linenum)
{
struct mark *m;
struct scrpos scrpos;
POSITION pos;
m = getumark(c);
if (m == NULL)
return;
get_scrpos(&scrpos, where);
if (scrpos.pos == NULL_POSITION)
if (linenum == 0)
{
bell();
return;
get_scrpos(&scrpos, where);
if (scrpos.pos == NULL_POSITION)
{
lbell();
return;
}
} else
{
pos = find_pos(linenum);
if (pos == NULL_POSITION)
{
PARG parg;
parg.p_linenum = linenum;
error("Cannot find line number %n", &parg);
return;
}
get_scrpos_pos(&scrpos, where, pos);
}
cmark(m, curr_ifile, scrpos.pos, scrpos.ln);
marks_modified = 1;
marks_modified = TRUE;
if (perma_marks && autosave_action('m'))
save_cmdhist();
}
/*
@@ -223,11 +280,18 @@ public void clrmark(char c)
return;
if (m->m_scrpos.pos == NULL_POSITION)
{
bell();
lbell();
return;
}
m->m_scrpos.pos = NULL_POSITION;
marks_modified = 1;
mark_clear(m);
#if CMD_HISTORY
/* Also clear in file_marks, so save_marks doesn't save it to history file. */
m = &file_marks[mark_index(c)];
mark_clear(m);
#endif
marks_modified = TRUE;
if (perma_marks && autosave_action('m'))
save_cmdhist();
}
/*
@@ -243,13 +307,13 @@ public void lastmark(void)
if (scrpos.pos == NULL_POSITION)
return;
cmark(&marks[LASTMARK], curr_ifile, scrpos.pos, scrpos.ln);
marks_modified = 1;
marks_modified = TRUE;
}
/*
* Go to a mark.
*/
public void gomark(char c)
public void gomark(char c, int sline)
{
struct mark *m;
struct scrpos scrpos;
@@ -257,6 +321,8 @@ public void gomark(char c)
m = getmark(c);
if (m == NULL)
return;
if (sline != 0)
m->m_scrpos.ln = sline;
/*
* If we're trying to go to the lastmark and
@@ -264,7 +330,7 @@ public void gomark(char c)
* set it to the beginning of the current file.
* {{ Couldn't we instead set marks[LASTMARK] in edit()? }}
*/
if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
if (m == &marks[LASTMARK] && !mark_is_set(m))
cmark(m, curr_ifile, ch_zero(), jump_sline);
mark_get_ifile(m);
@@ -316,14 +382,11 @@ public char posmark(POSITION pos)
/* Only user marks */
for (i = 0; i < NUMARKS; i++)
{
if (marks[i].m_ifile == curr_ifile && marks[i].m_scrpos.pos == pos)
{
if (i < 26) return (char) ('a' + i);
if (i < 26*2) return (char) ('A' + (i - 26));
return '#';
}
struct mark *m = &marks[i];
if (m->m_ifile == curr_ifile && m->m_scrpos.pos == pos)
return mark_letter(i);
}
return 0;
return '\0';
}
/*
@@ -335,7 +398,7 @@ public void unmark(IFILE ifile)
for (i = 0; i < NMARKS; i++)
if (marks[i].m_ifile == ifile)
marks[i].m_scrpos.pos = NULL_POSITION;
mark_clear(&marks[i]);
}
/*
@@ -363,6 +426,15 @@ public void mark_check_ifile(IFILE ifile)
#if CMD_HISTORY
/*
* Initialize a mark struct, including the filename.
*/
static void cmarkf(struct mark *m, IFILE ifile, POSITION pos, int ln, constant char *filename)
{
cmark(m, ifile, pos, ln);
m->m_filename = (filename == NULL) ? NULL : save(filename);
}
/*
* Save marks to history file.
*/
@@ -370,16 +442,29 @@ public void save_marks(FILE *fout, constant char *hdr)
{
int i;
if (!perma_marks)
return;
if (perma_marks)
{
/* Copy active marks to file_marks. */
for (i = 0; i < NMARKS; i++)
{
struct mark *m = &marks[i];
if (mark_is_set(m))
cmarkf(&file_marks[i], m->m_ifile, m->m_scrpos.pos, m->m_scrpos.ln, m->m_filename);
}
}
/*
* Save file_marks to the history file.
* These may have been read from the history file at startup
* (in restore_mark), or copied from the active marks above.
*/
fprintf(fout, "%s\n", hdr);
for (i = 0; i < NMARKS; i++)
{
constant char *filename;
struct mark *m = &marks[i];
struct mark *m = &file_marks[i];
char pos_str[INT_STRLEN_BOUND(m->m_scrpos.pos) + 2];
if (m->m_scrpos.pos == NULL_POSITION)
if (!mark_is_set(m))
continue;
postoa(m->m_scrpos.pos, pos_str, 10);
filename = m->m_filename;
@@ -387,7 +472,7 @@ public void save_marks(FILE *fout, constant char *hdr)
filename = get_real_filename(m->m_ifile);
if (strcmp(filename, "-") != 0)
fprintf(fout, "m %c %d %s %s\n",
m->m_letter, m->m_scrpos.ln, pos_str, filename);
mark_letter(i), m->m_scrpos.ln, pos_str, filename);
}
}
@@ -396,7 +481,7 @@ public void save_marks(FILE *fout, constant char *hdr)
*/
public void restore_mark(constant char *line)
{
struct mark *m;
int index;
int ln;
POSITION pos;
@@ -404,24 +489,21 @@ public void restore_mark(constant char *line)
if (*line++ != 'm')
return;
skip_whitespace;
m = getumark(*line++);
if (m == NULL)
index = mark_index(*line++);
if (index < 0)
return;
skip_whitespace;
ln = lstrtoic(line, &line, 10);
if (ln < 0)
return;
if (ln < 1)
ln = 1;
if (ln > sc_height)
ln = sc_height;
skip_whitespace;
pos = lstrtoposc(line, &line, 10);
if (pos < 0)
return;
skip_whitespace;
cmark(m, NULL_IFILE, pos, ln);
m->m_filename = save(line);
/* Save in both active marks table and file_marks table. */
cmarkf(&marks[index], NULL_IFILE, pos, ln, line);
cmarkf(&file_marks[index], NULL_IFILE, pos, ln, line);
}
#endif /* CMD_HISTORY */
+1 -1
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Xx -- unicode/UnicodeData.txt" on Aug 19 1:16:32 GMT 2025 */
/* Generated by "./mkutable -f2 Xx -- unicode/UnicodeData.txt" on Nov 28 1:30:12 GMT 2025 */
{ 0x00ad, 0x00ad }, /* Xx */
{ 0x200d, 0x200d }, /* Xx */
{ 0xfe00, 0xfe0f }, /* Xx */
+251 -83
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -34,16 +34,18 @@ extern lbool plusoption;
extern int swindow;
extern int sc_width;
extern int sc_height;
extern int dohelp;
extern lbool dohelp;
extern char openquote;
extern char closequote;
extern char *prproto[];
extern char *eprproto[];
extern char *eqproto;
extern char *hproto;
extern char *wproto;
extern char *every_first_cmd;
extern IFILE curr_ifile;
extern char version[];
extern int jump_sline_arg;
extern int jump_sline;
extern long jump_sline_fraction;
extern int shift_count;
@@ -52,7 +54,9 @@ extern int match_shift;
extern long match_shift_fraction;
extern LWCHAR rscroll_char;
extern int rscroll_attr;
extern int mousecap;
extern int emouse;
extern int mouse_reverse;
extern int xmouse;
extern int wheel_lines;
extern int less_is_more;
extern int linenum_width;
@@ -67,12 +71,14 @@ extern int tabstops[];
extern int ntabstops;
extern int tabdefault;
extern int no_paste;
extern int hilite_target;
extern char intr_char;
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;
extern char *autosave;
#if LOGFILE
extern char *namelogfile;
extern lbool force_logfile;
@@ -85,7 +91,7 @@ extern char ztags[];
#endif
#if LESSTEST
extern constant char *ttyin_name;
extern int is_tty;
extern lbool is_tty;
#endif /*LESSTEST*/
#if MSDOS_COMPILER
extern int nm_fg_color, nm_bg_color, nm_attr;
@@ -166,36 +172,27 @@ public void opt__O(int type, constant char *s)
}
#endif
static int toggle_fraction(int *num, long *frac, constant char *s, constant char *printopt, void (*calc)(void))
static void toggle_fraction(int *num, long *frac, constant char *s, constant char *printopt, lbool neg_ok, void (*calc)(void))
{
lbool err;
if (s == NULL)
{
(*calc)();
} else if (*s == '.')
{
long tfrac;
s++;
tfrac = getfraction(&s, printopt, &err);
if (err)
if (!getfraction(&s, frac))
{
error("Invalid fraction", NULL_PARG);
return -1;
PARG parg;
parg.p_string = printopt;
error("Invalid fraction in %s", &parg);
return;
}
*frac = tfrac;
(*calc)();
} else
{
int tnum = getnumc(&s, printopt, &err);
if (err)
{
error("Invalid number", NULL_PARG);
return -1;
}
if (!getnumc(&s, printopt, neg_ok, num))
return;
*frac = -1;
*num = tnum;
}
return 0;
(*calc)();
}
static void query_fraction(int value, long fraction, constant char *int_msg, constant char *frac_msg)
@@ -229,11 +226,11 @@ public void opt_j(int type, constant char *s)
{
case INIT:
case TOGGLE:
toggle_fraction(&jump_sline, &jump_sline_fraction,
s, "j", calc_jump_sline);
toggle_fraction(&jump_sline_arg, &jump_sline_fraction,
s, "-j", TRUE, calc_jump_sline);
break;
case QUERY:
query_fraction(jump_sline, jump_sline_fraction,
query_fraction(jump_sline_arg, jump_sline_fraction,
"Position target at screen line %d", "Position target at screen position %s");
break;
}
@@ -241,10 +238,19 @@ public void opt_j(int type, constant char *s)
public void calc_jump_sline(void)
{
jump_sline = jump_sline_arg;
/* If jump_sline_fraction is set, calculate jump_sline from it. */
if (jump_sline_fraction >= 0)
jump_sline = (int) muldiv(sc_height, jump_sline_fraction, NUM_FRAC_DENOM);
/* Negative jump_sline means relative to bottom of screen. */
if (jump_sline < 0)
jump_sline += sc_height;
/* If jump_sline is obscured by header, move it after the header. */
if (jump_sline <= header_lines)
jump_sline = header_lines + 1;
/* If jump_sline is past bottom of screen, move it to the bottom. */
if (jump_sline >= sc_height)
jump_sline = sc_height - 1;
}
/*
@@ -257,7 +263,7 @@ public void opt_shift(int type, constant char *s)
case INIT:
case TOGGLE:
toggle_fraction(&shift_count, &shift_count_fraction,
s, "#", calc_shift_count);
s, "-#", FALSE, calc_shift_count);
break;
case QUERY:
query_fraction(shift_count, shift_count_fraction,
@@ -331,7 +337,7 @@ public void opt__S(int type, constant char *s)
switch (type)
{
case TOGGLE:
pos_rehead();
pos_rehead(TRUE);
break;
}
}
@@ -467,7 +473,73 @@ public void opt__P(int type, constant char *s)
break;
case QUERY:
parg.p_string = prproto[pr_type];
error("%s", &parg);
switch (pr_type)
{
case PR_MEDIUM: error("Prompt (medium): %s", &parg); break;
case PR_LONG: error("Prompt (long): %s", &parg); break;
default: error("Prompt (short): %s", &parg); break;
}
break;
}
}
/*
* Handler for --end-prompt option.
*/
public void opt_end_prompt(int type, constant char *s)
{
char **pend;
PARG parg;
switch (type)
{
case INIT:
case TOGGLE:
switch (*s)
{
case 's': pend = &eprproto[PR_SHORT]; s++; break;
case 'm': pend = &eprproto[PR_MEDIUM]; s++; break;
case 'M': pend = &eprproto[PR_LONG]; s++; break;
default: pend = &eprproto[PR_SHORT]; break;
}
if (*pend != NULL)
free(*pend);
*pend = (strcmp(s, "-") == 0) ? NULL : save(s);
break;
case QUERY:
parg.p_string = eprproto[pr_type];
if (parg.p_string == NULL)
parg.p_string = "(nothing)";
switch (pr_type)
{
case PR_MEDIUM: error("Print after medium prompt: %s", &parg); break;
case PR_LONG: error("Print after long prompt: %s", &parg); break;
default: error("Print after short prompt: %s", &parg); break;
}
break;
}
}
/*
* Handler for --autosave option.
*/
public void opt_autosave(int type, constant char *s)
{
PARG parg;
switch (type)
{
case INIT:
case TOGGLE:
if (s == NULL)
s = "-";
if (autosave != NULL)
free(autosave);
autosave = save(s);
break;
case QUERY:
parg.p_string = (autosave != NULL) ? autosave : "-";
error("Autosave actions: %s", &parg);
break;
}
}
@@ -522,7 +594,7 @@ public void opt__V(int type, constant char *s)
dispversion();
break;
case INIT:
set_output(1); /* Force output to stdout per GNU standard for --version output. */
set_output(1, TRUE); /* Force output to stdout per GNU standard for --version output. */
putstr("less ");
putstr(version);
putstr(" (");
@@ -530,7 +602,7 @@ public void opt__V(int type, constant char *s)
putstr(" regular expressions)\n");
{
char constant *copyright =
"Copyright (C) 1984-2025 Mark Nudelman\n\n";
"Copyright (C) 1984-2026 Mark Nudelman\n\n";
putstr(copyright);
}
if (version[strlen(version)-1] == 'x')
@@ -587,11 +659,13 @@ static int color_from_namechar(char namechar)
case 'C': return AT_COLOR_CTRL;
case 'E': return AT_COLOR_ERROR;
case 'H': return AT_COLOR_HEADER;
case 'J': return AT_COLOR_TARGET;
case 'M': return AT_COLOR_MARK;
case 'N': return AT_COLOR_LINENUM;
case 'P': return AT_COLOR_PROMPT;
case 'R': return AT_COLOR_RSCROLL;
case 'S': return AT_COLOR_SEARCH;
case 'T': return AT_COLOR_TILDE;
case 'W': case 'A': return AT_COLOR_ATTN;
case 'n': return AT_NORMAL;
case 's': return AT_STANDOUT;
@@ -622,6 +696,11 @@ public void opt_D(int type, constant char *s)
if (*s == 'a')
{
sgr_mode = !sgr_mode;
if (type == TOGGLE)
{
p.p_string = (sgr_mode) ? "on" : "off";
error("SGR mode is %s", &p);
}
break;
}
#endif
@@ -674,12 +753,6 @@ public void opt_D(int type, constant char *s)
return;
}
break;
#if MSDOS_COMPILER
case QUERY:
p.p_string = (sgr_mode) ? "on" : "off";
error("SGR mode is %s", &p);
break;
#endif
}
}
@@ -842,7 +915,7 @@ public void opt_query(int type, constant char *s)
error("Use \"h\" for help", NULL_PARG);
break;
case INIT:
dohelp = 1;
dohelp = TRUE;
}
}
@@ -854,7 +927,7 @@ public void opt_match_shift(int type, constant char *s)
case INIT:
case TOGGLE:
toggle_fraction(&match_shift, &match_shift_fraction,
s, "--match-shift", calc_match_shift);
s, "--match-shift", FALSE, calc_match_shift);
break;
case QUERY:
query_fraction(match_shift, match_shift_fraction,
@@ -870,21 +943,100 @@ public void calc_match_shift(void)
match_shift = (int) muldiv(sc_width, match_shift_fraction, NUM_FRAC_DENOM);
}
/*
* Handler for the --emouse option.
*/
/*ARGSUSED*/
public void opt_emouse(int type, constant char *s)
{
/* Order of entries matters for QUERY.
* Combinations must come after their components. */
static struct csl_bitmap_def emouse_defs[] = {
{ "hscroll", EMOUSE_HSCROLL },
{ "vscroll", EMOUSE_VSCROLL },
{ "hdrag", EMOUSE_HDRAG },
{ "vdrag", EMOUSE_VDRAG },
{ "lclick", EMOUSE_LCLICK },
{ "rclick", EMOUSE_RCLICK },
{ "scroll", EMOUSE_HSCROLL|EMOUSE_VSCROLL },
{ "drag", EMOUSE_HDRAG|EMOUSE_VDRAG },
{ "hmove", EMOUSE_HSCROLL|EMOUSE_HDRAG },
{ "vmove", EMOUSE_VSCROLL|EMOUSE_VDRAG },
{ "move", EMOUSE_VSCROLL|EMOUSE_VDRAG|EMOUSE_HSCROLL|EMOUSE_HDRAG },
{ "click", EMOUSE_LCLICK|EMOUSE_RCLICK },
{ "all", EMOUSE_VSCROLL|EMOUSE_VDRAG|EMOUSE_HSCROLL|EMOUSE_HDRAG|EMOUSE_LCLICK|EMOUSE_RCLICK },
};
switch (type)
{
case INIT:
case TOGGLE: {
lbool was_mouse_enabled = (emouse != 0);
if (s == NULL || strcmp(s, "-") == 0)
emouse = 0;
else
emouse = parse_csl_bitmap(s,
emouse_defs, countof(emouse_defs), "--emouse");
if (type == TOGGLE && was_mouse_enabled != (emouse != 0))
{
if (emouse == 0)
deinit_mouse();
else
init_mouse();
}
break; }
case QUERY: {
char buf[128];
char *bp = buf;
char *ebuf = buf + sizeof(buf);
int qmouse = emouse;
PARG parg;
int i;
for (i = countof(emouse_defs)-1; i >= 0; i--)
{
int bit = emouse_defs[i].bit_value;
if ((qmouse & bit) == bit)
{
if (bp > buf && bp+1 < ebuf)
*bp++ = ',';
strncpy(bp, emouse_defs[i].bit_name, ptr_diff(ebuf, bp));
bp += strlen(bp);
qmouse &= ~bit;
}
}
*bp = '\0';
parg.p_string = buf;
if (buf[0] == '\0')
error("Ignore mouse input", NULL_PARG);
else
error("Mouse features enabled: %s", &parg);
break; }
}
}
/*
* Handler for the --mouse option.
*/
/*ARGSUSED*/
public void opt_mousecap(int type, constant char *s)
public void opt_mouse(int type, constant char *s)
{
switch (type)
{
case TOGGLE:
if (mousecap == OPT_OFF)
deinit_mouse();
else
init_mouse();
break;
case INIT:
case TOGGLE:
switch (xmouse)
{
case OPT_OFF:
opt_emouse(type, "-");
break;
case OPT_ON:
case OPT_ONPLUS:
opt_emouse(type, "vmove,click");
mouse_reverse = (xmouse == OPT_ONPLUS);
break;
}
break;
case QUERY:
break;
}
@@ -1019,28 +1171,24 @@ public void opt_intr(int type, constant char *s)
* Return -1 if the list entry is missing or empty.
* Updates *sp to point to the first char of the next number in the list.
*/
public int next_cnum(constant char **sp, constant char *printopt, constant char *errmsg, lbool *errp)
static lbool next_cnum(constant char **sp, constant char *printopt, mutable int *p_num)
{
int n;
*errp = FALSE;
if (**sp == '\0') /* at end of line */
return -1;
{
*p_num = -1;
return TRUE;
}
if (**sp == ',') /* that's the next comma; we have an empty string */
{
++(*sp);
return -1;
}
n = getnumc(sp, printopt, errp);
if (*errp)
{
PARG parg;
parg.p_string = errmsg;
error("invalid %s", &parg);
return -1;
*p_num = -1;
return TRUE;
}
if (!getnumc(sp, printopt, FALSE, p_num))
return FALSE;
if (**sp == ',')
++(*sp);
return n;
return TRUE;
}
/*
@@ -1050,26 +1198,21 @@ public int next_cnum(constant char **sp, constant char *printopt, constant char
static lbool parse_header(constant char *s, int *lines, int *cols, POSITION *start_pos)
{
int n;
lbool err;
if (*s == '-')
s = "0,0";
n = next_cnum(&s, "header", "number of lines", &err);
if (err) return FALSE;
if (!next_cnum(&s, "--header", &n))
return FALSE;
if (n >= 0) *lines = n;
n = next_cnum(&s, "header", "number of columns", &err);
if (err) return FALSE;
if (!next_cnum(&s, "--header", &n))
return FALSE;
if (n >= 0) *cols = n;
n = next_cnum(&s, "header", "line number", &err);
if (err) return FALSE;
if (n > 0)
if (!next_cnum(&s, "--header", &n))
return FALSE;
if (n > 0)
{
LINENUM lnum = (LINENUM) n;
if (lnum < 1) lnum = 1;
*start_pos = find_pos(lnum);
if (n < 1) n = 1;
*start_pos = find_pos((LINENUM)n);
}
return TRUE;
}
@@ -1099,13 +1242,31 @@ public void opt_header(int type, constant char *s)
set_header(start_pos);
calc_jump_sline();
break; }
case QUERY: {
char buf[3*INT_STRLEN_BOUND(long)+3];
PARG parg;
SNPRINTF3(buf, sizeof(buf), "%ld,%ld,%ld", (long) header_lines, (long) header_cols, (long) find_linenum(header_start_pos));
parg.p_string = buf;
error("Header (lines,columns,line-number) is %s", &parg);
break; }
case QUERY: {
char buf[3*INT_STRLEN_BOUND(long)+3];
PARG parg;
SNPRINTF3(buf, sizeof(buf), "%ld,%ld,%ld", (long) header_lines, (long) header_cols, (long) find_linenum(header_start_pos));
parg.p_string = buf;
error("Header (lines,columns,line-number) is %s", &parg);
break; }
}
}
/*
* Handler for the --hilite-target option.
*/
/*ARGSUSED*/
public void opt_hilite_target(int type, constant char *s)
{
switch (type)
{
case INIT:
break;
case TOGGLE:
draw_target_attn(hilite_target != OPT_OFF);
break;
case QUERY:
break;
}
}
@@ -1225,11 +1386,11 @@ public void opt_no_paste(int type, constant char *s)
init_bracketed_paste();
else
deinit_bracketed_paste();
break;
break;
case INIT:
case QUERY:
break;
}
}
}
#if LESSTEST
@@ -1243,7 +1404,7 @@ public void opt_ttyin_name(int type, constant char *s)
{
case INIT:
ttyin_name = s;
is_tty = 1;
is_tty = TRUE;
break;
}
}
@@ -1264,3 +1425,10 @@ public int get_swindow(void)
return (sc_height - header_lines + swindow);
}
/*
* Should an action initiate an autosave?
*/
public lbool autosave_action(char act)
{
return strchr(autosave, act) != NULL || strchr(autosave, '*') != NULL;
}
+70 -68
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -70,7 +70,6 @@ public void scan_option(constant char *s, lbool is_env)
char *str;
lbool set_default;
lbool lc;
lbool ambig;
PARG parg;
if (s == NULL)
@@ -94,7 +93,7 @@ public void scan_option(constant char *s, lbool is_env)
break;
case O_NUMBER:
printopt = opt_desc(pendopt);
*(pendopt->ovar) = getnumc(&s, printopt, NULL);
getnumc(&s, printopt, (pendopt->otype & O_NEGOK) != 0, pendopt->ovar);
break;
}
}
@@ -179,14 +178,20 @@ public void scan_option(constant char *s, lbool is_env)
* Not a special case.
* Look up the option letter in the option table.
*/
ambig = FALSE;
if (optname == NULL)
{
printopt = propt(optc);
lc = ASCII_IS_LOWER(optc);
o = findopt(optc);
if (o == NULL)
{
parg.p_string = printopt;
error("There is no %s option (\"less --help\" for help)", &parg);
return;
}
} else
{
lbool ambig = FALSE;
printopt = optname;
lc = ASCII_IS_LOWER(optname[0]);
o = findopt_name(&optname, NULL, &ambig);
@@ -208,7 +213,7 @@ public void scan_option(constant char *s, lbool is_env)
(o->otype & OTYPE) != O_NUMBER)
{
parg.p_string = printopt;
error("The %s option should not be followed by =",
error("The --%s option should not be followed by =",
&parg);
return;
}
@@ -221,17 +226,15 @@ public void scan_option(constant char *s, lbool is_env)
*/
o = NULL;
}
}
if (o == NULL)
{
parg.p_string = printopt;
if (ambig)
error("%s is an ambiguous abbreviation (\"less --help\" for help)",
&parg);
else
error("There is no %s option (\"less --help\" for help)",
&parg);
return;
if (o == NULL)
{
parg.p_string = printopt;
if (ambig)
error("--%s is an ambiguous abbreviation (\"less --help\" for help)", &parg);
else
error("There is no --%s option (\"less --help\" for help)", &parg);
return;
}
}
str = NULL;
@@ -292,7 +295,7 @@ public void scan_option(constant char *s, lbool is_env)
}
if (o->otype & O_UNSUPPORTED)
break;
*(o->ovar) = getnumc(&s, printopt, NULL);
getnumc(&s, printopt, (o->otype & O_NEGOK) != 0, o->ovar);
break;
}
/*
@@ -314,11 +317,9 @@ public void scan_option(constant char *s, lbool is_env)
* OPT_UNSET set to the default value
* OPT_SET set to the inverse of the default value
*/
public void toggle_option(struct loption *o, lbool lower, constant char *s, int how_toggle)
public lbool toggle_option(struct loption *o, lbool lower, constant char *s, int how_toggle)
{
int num;
int no_prompt;
lbool err;
PARG parg;
no_prompt = (how_toggle & OPT_NO_PROMPT);
@@ -327,21 +328,21 @@ public void toggle_option(struct loption *o, lbool lower, constant char *s, int
if (o == NULL)
{
error("No such option", NULL_PARG);
return;
return FALSE;
}
if (how_toggle == OPT_TOGGLE && (o->otype & O_NO_TOGGLE))
{
parg.p_string = opt_desc(o);
error("Cannot change the %s option", &parg);
return;
return FALSE;
}
if (how_toggle == OPT_NO_TOGGLE && (o->otype & O_NO_QUERY))
{
parg.p_string = opt_desc(o);
error("Cannot query the %s option", &parg);
return;
return FALSE;
}
/*
@@ -426,7 +427,7 @@ public void toggle_option(struct loption *o, lbool lower, constant char *s, int
case OPT_UNSET:
error("Cannot use \"-+\" or \"-!\" for a string option",
NULL_PARG);
return;
return FALSE;
}
break;
case O_NUMBER:
@@ -436,9 +437,8 @@ public void toggle_option(struct loption *o, lbool lower, constant char *s, int
switch (how_toggle)
{
case OPT_TOGGLE:
num = getnumc(&s, NULL, &err);
if (!err)
*(o->ovar) = num;
if (!getnumc(&s, opt_desc(o), (o->otype & O_NEGOK) != 0, o->ovar))
return FALSE;
break;
case OPT_UNSET:
*(o->ovar) = o->odefault;
@@ -446,7 +446,7 @@ public void toggle_option(struct loption *o, lbool lower, constant char *s, int
case OPT_SET:
error("Can't use \"-!\" for a numeric option",
NULL_PARG);
return;
return FALSE;
}
break;
}
@@ -488,15 +488,15 @@ public void toggle_option(struct loption *o, lbool lower, constant char *s, int
error(o->odesc[1], &parg);
break;
case O_STRING:
/*
* Message was already printed by the handling function.
*/
if (how_toggle != OPT_NO_TOGGLE && o->ofunc != NULL)
(*o->ofunc)(QUERY, NULL);
break;
}
}
if (how_toggle != OPT_NO_TOGGLE && (o->otype & O_REPAINT))
screen_trashed();
return TRUE;
}
/*
@@ -513,20 +513,20 @@ static int flip_triple(int val, lbool lc)
/*
* Determine if an option takes a parameter.
*/
public int opt_has_param(struct loption *o)
public lbool opt_has_param(constant struct loption *o)
{
if (o == NULL)
return (0);
return FALSE;
if (o->otype & (O_BOOL|O_TRIPLE|O_NOVAR|O_NO_TOGGLE))
return (0);
return (1);
return FALSE;
return TRUE;
}
/*
* Return the prompt to be used for a given option letter.
* Only string and number valued options have prompts.
*/
public constant char * opt_prompt(struct loption *o)
public constant char * opt_prompt(constant struct loption *o)
{
if (o == NULL || (o->otype & (O_STRING|O_NUMBER)) == 0)
return ("?");
@@ -653,26 +653,29 @@ static constant char * optstring(constant char *s, char **p_str, constant char *
return (p);
}
/*
*/
static int num_error(constant char *printopt, lbool *errp, lbool overflow)
{
PARG parg;
typedef enum {
NUM_ERR_NONE, NUM_ERR_OVERFLOW, NUM_ERR_NEG, NUM_ERR_MISSING
} num_error_type;
if (errp != NULL)
{
*errp = TRUE;
return (-1);
}
/*
* Display error message for invalid number.
*/
static lbool num_error(constant char *printopt, num_error_type error_type)
{
if (printopt != NULL)
{
constant char *msg;
PARG parg;
switch (error_type)
{
case NUM_ERR_OVERFLOW: msg = "Number too large in %s"; break;
case NUM_ERR_NEG: msg = "Negative number not allowed in %s"; break;
default: msg = "Number is required after %s"; break;
}
parg.p_string = printopt;
error((overflow
? "Number too large in '%s'"
: "Number is required after %s"),
&parg);
error(msg, &parg);
}
return (-1);
return FALSE;
}
/*
@@ -680,38 +683,38 @@ static int num_error(constant char *printopt, lbool *errp, lbool overflow)
* Like atoi(), but takes a pointer to a char *, and updates
* the char * to point after the translated number.
*/
public int getnumc(constant char **sp, constant char *printopt, lbool *errp)
public lbool getnumc(constant char **sp, constant char *printopt, lbool neg_ok, mutable int *p_num)
{
constant char *s = *sp;
int n;
lbool neg;
lbool neg = FALSE;
s = skipspc(s);
neg = FALSE;
if (*s == '-')
{
if (!neg_ok)
return num_error(printopt, NUM_ERR_NEG);
neg = TRUE;
s++;
}
if (*s < '0' || *s > '9')
return (num_error(printopt, errp, FALSE));
return num_error(printopt, NUM_ERR_MISSING);
n = lstrtoic(s, sp, 10);
if (n < 0)
return (num_error(printopt, errp, TRUE));
if (errp != NULL)
*errp = FALSE;
return num_error(printopt, NUM_ERR_OVERFLOW);
if (neg)
n = -n;
return (n);
*p_num = n;
return TRUE;
}
public int getnum(char **sp, constant char *printopt, lbool *errp)
public lbool getnum(char **sp, constant char *printopt, lbool neg_ok, mutable int *p_num)
{
constant char *cs = *sp;
int r = getnumc(&cs, printopt, errp);
if (!getnumc(&cs, printopt, neg_ok, p_num))
return FALSE;
*sp = (char *) cs;
return r;
return TRUE;
}
/*
@@ -720,7 +723,7 @@ public int getnum(char **sp, constant char *printopt, lbool *errp)
* The value of the fraction is returned as parts per NUM_FRAC_DENOM.
* That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM.
*/
public long getfraction(constant char **sp, constant char *printopt, lbool *errp)
public lbool getfraction(constant char **sp, mutable long *p_frac)
{
constant char *s;
long frac = 0;
@@ -728,7 +731,7 @@ public long getfraction(constant char **sp, constant char *printopt, lbool *errp
s = skipspc(*sp);
if (*s < '0' || *s > '9')
return (num_error(printopt, errp, FALSE));
return FALSE;
for ( ; *s >= '0' && *s <= '9'; s++)
{
@@ -740,9 +743,8 @@ public long getfraction(constant char **sp, constant char *printopt, lbool *errp
while (fraclen++ < NUM_LOG_FRAC_DENOM)
frac *= 10;
*sp = s;
if (errp != NULL)
*errp = FALSE;
return (frac);
*p_frac = frac;
return TRUE;
}
/*
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -24,6 +24,7 @@
#define O_NO_QUERY 0400 /* Option cannot be queried with "_" cmd */
#define O_INIT_HANDLER 01000 /* Call option handler function at startup */
#define O_UNSUPPORTED 02000 /* Option is unsupported via LESS_UNSUPPORT */
#define O_NEGOK 04000 /* O_NUMBER parameter may be negative */
#define OTYPE (O_BOOL|O_TRIPLE|O_NUMBER|O_STRING|O_NOVAR)
+60 -11
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -40,6 +40,7 @@ public int ctldisp; /* Send control chars to screen untranslated */
public int force_open; /* Open the file even if not regular file */
public int swindow; /* Size of scrolling window */
public int jump_sline; /* Screen line of "jump target" */
public int jump_sline_arg;
public long jump_sline_fraction = -1;
public int shift_count; /* Number of positions to shift horizontally */
public long shift_count_fraction = -1;
@@ -49,6 +50,7 @@ public int no_init; /* Disable sending ti/te termcap strings */
public int no_keypad; /* Disable sending ks/ke termcap strings */
public int twiddle; /* Show tildes after EOF */
public int show_attn; /* Hilite first unread line */
public int hilite_target; /* Hilite target line */
public int status_col; /* Display a status column */
public int use_lessopen; /* Use the LESSOPEN filter */
public int quit_on_intr; /* Quit on interrupt */
@@ -58,7 +60,9 @@ public int opt_use_backslash; /* Use backslash escaping in option parsing */
public LWCHAR rscroll_char; /* Char which marks chopped lines with -S */
public int rscroll_attr; /* Attribute of rscroll_char */
public int no_hist_dups; /* Remove dups from history list */
public int mousecap; /* Allow mouse for scrolling */
public int emouse; /* Enabled mouse features */
public int mouse_reverse; /* Reverse mouse wheel scrolling direction */
public int xmouse; /* Old --mouse option, replaced by --emouse */
public int wheel_lines; /* Number of lines to scroll on mouse wheel scroll */
public int perma_marks; /* Save marks in history file */
public int linenum_width; /* Width of line numbers */
@@ -84,9 +88,12 @@ public int match_shift; /* Extra horizontal shift on search match */
public int no_paste; /* Don't accept pasted input */
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 int past_eof; /* Continue scrolling past EOF */
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 */
public char *autosave; /* Actions which do autosave of history file */
public char *end_prompt; /* Printed after clearing the prompt */
#if HILITE_SEARCH
public int hilite_search; /* Highlight matched search patterns? */
#endif
@@ -155,7 +162,9 @@ static struct optname follow_optname = { "follow-name", NULL };
static struct optname use_backslash_optname = { "use-backslash", NULL };
static struct optname rscroll_optname = { "rscroll", NULL };
static struct optname nohistdups_optname = { "no-histdups", NULL };
static struct optname mousecap_optname = { "mouse", NULL };
static struct optname mouse_optname = { "mouse", NULL };
static struct optname emouse_optname = { "emouse", NULL };
static struct optname mouse_reverse_optname = { "rmouse", NULL };
static struct optname wheel_lines_optname = { "wheel-lines", NULL };
static struct optname perma_marks_optname = { "save-marks", NULL };
static struct optname linenum_width_optname = { "line-num-width", NULL };
@@ -167,6 +176,7 @@ static struct optname status_line_optname = { "status-line", NULL };
static struct optname header_optname = { "header", NULL };
static struct optname no_paste_optname = { "no-paste", NULL };
static struct optname form_feed_optname = { "form-feed", NULL };
static struct optname past_eof_optname = { "past-eof", NULL };
static struct optname no_edit_warn_optname2 = { "no-warn-edit", NULL };
static struct optname no_edit_warn_optname = { "no-edit-warn", &no_edit_warn_optname2 };
static struct optname nonum_headers_optname = { "no-number-headers", NULL };
@@ -186,6 +196,9 @@ 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 };
static struct optname autosave_optname = { "autosave", NULL };
static struct optname hilite_target_optname = { "hilite-target", NULL };
static struct optname end_prompt_optname = { "end-prompt", NULL };
#if LESSTEST
static struct optname ttyin_name_optname = { "tty", NULL };
#endif /*LESSTEST*/
@@ -436,6 +449,14 @@ static struct loption option[] =
O_NOVAR, 0, NULL, opt__V,
{ NULL, NULL, NULL }
},
{ OLETTER_NONE, &hilite_target_optname,
O_BOOL, OPT_OFF, &hilite_target, opt_hilite_target,
{
"Don't highlight target line",
"Highlight target line",
NULL
}
},
{ 'w', &w_optname,
O_TRIPLE|O_REPAINT, OPT_OFF, &show_attn, NULL,
{
@@ -469,7 +490,7 @@ static struct loption option[] =
}
},
{ 'z', &z_optname,
O_NUMBER, -1, &swindow, NULL,
O_NUMBER|O_NEGOK, -1, &swindow, NULL,
{
"Scroll window size: ",
"Scroll window size is %d lines",
@@ -527,8 +548,8 @@ static struct loption option[] =
{ OLETTER_NONE, &use_backslash_optname,
O_BOOL, OPT_OFF, &opt_use_backslash, NULL,
{
"Use backslash escaping in command line parameters",
"Don't use backslash escaping in command line parameters",
"Use backslash escaping in command line parameters",
NULL
}
},
@@ -544,12 +565,24 @@ static struct loption option[] =
NULL
}
},
{ OLETTER_NONE, &mousecap_optname,
O_TRIPLE, OPT_OFF, &mousecap, opt_mousecap,
{ OLETTER_NONE, &mouse_optname,
O_TRIPLE, OPT_OFF, &xmouse, opt_mouse,
{
"Ignore mouse input",
"Use the mouse for scrolling",
"Use the mouse for scrolling (reverse)"
"Use the mouse for scrolling vertically",
"Use the mouse for scrolling vertically (reverse)"
}
},
{ OLETTER_NONE, &emouse_optname,
O_STRING, 0, NULL, opt_emouse,
{ "Mouse features: ", "s", NULL }
},
{ OLETTER_NONE, &mouse_reverse_optname,
O_BOOL, OPT_OFF, &mouse_reverse, NULL,
{
"Normal mouse scroll direction",
"Reverse mouse scroll direction",
NULL
}
},
{ OLETTER_NONE, &wheel_lines_optname,
@@ -611,8 +644,8 @@ static struct loption option[] =
{ OLETTER_NONE, &status_line_optname,
O_BOOL|O_REPAINT, OPT_OFF, &status_line, NULL,
{
"Don't color each line with its status column color",
"Color each line with its status column color",
"Line highlight applies to text only",
"Line highlight applies to entire width of screen",
NULL
}
},
@@ -636,6 +669,14 @@ static struct loption option[] =
NULL
}
},
{ OLETTER_NONE, &past_eof_optname,
O_BOOL, OPT_OFF, &past_eof, NULL,
{
"Stop scrolling at end of file",
"Don't stop scrolling at end of file",
NULL
}
},
{ OLETTER_NONE, &no_edit_warn_optname,
O_BOOL, OPT_OFF, &no_edit_warn, NULL,
{
@@ -762,6 +803,14 @@ static struct loption option[] =
NULL
}
},
{ OLETTER_NONE, &autosave_optname,
O_STRING|O_INIT_HANDLER, 0, NULL, opt_autosave,
{ "Autosave actions: ", "s", NULL }
},
{ OLETTER_NONE, &end_prompt_optname,
O_STRING, 0, NULL, opt_end_prompt,
{ "Print after prompt: ", "s", NULL }
},
#if LESSTEST
{ OLETTER_NONE, &ttyin_name_optname,
O_STRING|O_NO_TOGGLE, 0, NULL, opt_ttyin_name,
+59 -45
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -80,9 +80,7 @@ static lbool any_data = FALSE;
static lbool reading;
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;
@@ -93,18 +91,18 @@ static JUMP_BUF read_label;
static JUMP_BUF open_label;
extern int sigs;
extern int ignore_eoi;
extern lbool ignore_eoi;
extern int exit_F_on_close;
extern int follow_mode;
extern int scanning_eof;
extern char intr_char;
extern int is_tty;
extern lbool is_tty;
extern int quit_if_one_screen;
extern int one_screen;
extern lbool one_screen;
#if HAVE_TIME
extern time_type less_start_time;
#endif
#if !MSDOS_COMPILER
#if LESS_IREAD_TTY
extern int tty;
#endif
@@ -164,8 +162,6 @@ static int check_poll(int fd, int tty)
/* Break out of "waiting for data". */
return (READ_INTR);
ungetcc_back((char) ch);
if (!no_poll)
return (READ_INTR);
}
}
if (ignore_eoi && exit_F_on_close && (poller[0].revents & (POLLHUP|POLLIN)) == POLLHUP)
@@ -198,6 +194,7 @@ public lbool ttyin_ready(void)
if (!use_poll)
return FALSE;
{
/* {{ assert LESS_IREAD_TTY }} */
struct pollfd poller[1] = { { tty, POLLIN, 0 } };
poll(poller, 1, 0);
return ((poller[0].revents & POLLIN) != 0);
@@ -209,7 +206,7 @@ public lbool ttyin_ready(void)
#endif
}
public int supports_ctrl_x(void)
public lbool supports_ctrl_x(void)
{
#if MSDOS_COMPILER==WIN32C
return (TRUE);
@@ -269,7 +266,7 @@ start:
#endif
#endif
#endif
#if !MSDOS_COMPILER
#if !MSDOS_COMPILER /* {{ LESS_IREAD_TTY? }} */
if (fd != tty && !ABORT_SIGS())
/* Non-interrupt signal like SIGWINCH. */
return (READ_AGAIN);
@@ -307,51 +304,36 @@ start:
if (ret != 0)
{
if (ret == READ_INTR)
{
sigs |= S_SWINTERRUPT;
getcc_clear();
}
reading = FALSE;
return (ret);
}
}
#else
#if MSDOS_COMPILER==WIN32C
if (!(quit_if_one_screen && one_screen) && win32_kbhit2(TRUE))
if (!(quit_if_one_screen && one_screen))
{
int c;
lbool intr;
c = WIN32getch();
intr = (c == CONTROL('C') || c == intr_char);
if (!intr)
WIN32ungetch((char) c);
if (intr || !no_poll)
char c;
if (win32_kbhit2(&c))
{
sigs |= S_SWINTERRUPT;
reading = FALSE;
return (READ_INTR);
if (c == CONTROL('C') || c == intr_char)
{
sigs |= S_SWINTERRUPT;
reading = FALSE;
win32_clear_queue();
return (READ_INTR);
}
win32_enqueue((int) c);
}
}
#endif
#endif
n = read(fd, buf, len);
reading = FALSE;
#if 0
/*
* This is a kludge to workaround a problem on some systems
* where terminating a remote tty connection causes read() to
* start returning 0 forever, instead of -1.
*/
{
if (!ignore_eoi)
{
if (n == 0)
consecutive_nulls++;
else
consecutive_nulls = 0;
if (consecutive_nulls > 20)
quit(QUIT_ERROR);
}
}
#endif
if (n < 0)
{
#if HAVE_ERRNO
@@ -369,10 +351,13 @@ start:
#endif
return (READ_ERR);
}
#if USE_POLL
if (fd != tty && n > 0)
any_data = TRUE;
#if LESS_IREAD_TTY
if (fd != tty)
#endif
{
if (n > 0)
polling_ok();
}
return (n);
}
@@ -418,6 +403,16 @@ public void intio(void)
}
}
/*
* We can start polling the input file.
*/
public void polling_ok(void)
{
#if USE_POLL
any_data = TRUE;
#endif
}
/*
* Return the current time.
*/
@@ -548,7 +543,7 @@ char * strchr(char *s, char c)
#endif
#if !HAVE_MEMCPY
void * memcpy(void *dst, void *src, size_t len)
void * memcpy(void *dst, constant void *src, size_t len)
{
char *dstp = (char *) dst;
char *srcp = (char *) src;
@@ -560,6 +555,25 @@ void * memcpy(void *dst, void *src, size_t len)
}
#endif
#if !HAVE_STRSTR
char * strstr(constant char *haystack, constant char *needle)
{
if (*needle == '\0')
return (char *) haystack;
for (; *haystack; haystack++) {
constant char *h = haystack;
constant char *n = needle;
while (*h != '\0' && *n != '\0' && *h == *n) {
h++;
n++;
}
if (*n == '\0')
return (char *) haystack;
}
return NULL;
}
#endif
#ifdef _OSK_MWC32
/*
+65 -39
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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,17 +21,22 @@
#endif
public int errmsgs; /* Count of messages displayed by error() */
public int need_clr;
public int final_attr;
public int at_prompt;
public lbool prompting = FALSE;
static lbool need_clr = FALSE;
extern int sigs;
extern int sc_width;
extern int so_s_width, so_e_width;
extern int is_tty;
extern lbool is_tty;
extern int oldbot;
extern int utf_mode;
extern int status_col;
extern int status_line;
extern int hilite_target;
extern int use_color;
extern char intr_char;
extern lbool term_init_ever;
extern int pr_type;
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
extern int ctldisp;
@@ -49,11 +54,13 @@ extern int vt_enabled;
/*
* Display the line which is in the line buffer.
*/
public void put_line(lbool forw_scroll)
public void put_line_hilite(lbool forw_scroll, lbool target)
{
int c;
size_t i;
int a;
lbool empty_line = TRUE;
constant int target_attr = use_color ? AT_COLOR_TARGET : AT_UNDERLINE;
if (ABORT_SIGS())
{
@@ -64,12 +71,27 @@ public void put_line(lbool forw_scroll)
return;
}
final_attr = AT_NORMAL;
for (i = 0; (c = gline(i, &a)) != '\0'; i++)
{
if (target && a == AT_NORMAL)
{
/* We're highlighting this line as the target line. Highlight
* this char if it's not already highlighted, and either we're
* highlighting the whole line or we're highlighting only the
* status column and this is the status column. */
if ((status_col && i == 0) ||
(i >= line_pfx_width() && (status_line || !status_col)))
a = target_attr;
}
if (target && (c == '\n' || c == '\r') && empty_line)
{
/* Line is empty; add a space to carry the target hilite. */
at_switch(target_attr);
putchr(' ');
}
if (!(a & AT_ANSI))
empty_line = FALSE;
at_switch(a);
final_attr = a;
if (c == '\b')
putbs();
else
@@ -81,10 +103,15 @@ public void put_line(lbool forw_scroll)
clear_eol();
}
public void put_line(lbool forw_scroll)
{
put_line_hilite(forw_scroll, FALSE);
}
/*
* win_flush has at least one non-critical issue when an escape sequence
* begins at the last char of the buffer, and possibly more issues.
* as a temporary measure to reduce likelyhood of encountering end-of-buffer
* as a temporary measure to reduce likelihood of encountering end-of-buffer
* issues till the SGR parser is replaced, OUTBUF_SIZE is 8K on Windows.
*/
static char obuf[OUTBUF_SIZE];
@@ -435,17 +462,19 @@ public void flush(void)
#endif
#endif
if (write(outfd, obuf, n) != n)
if (write(outfd, obuf, n) != (ssize_t) n)
screen_trashed();
}
/*
* Set the output file descriptor (1=stdout or 2=stderr).
*/
public void set_output(int fd)
public void set_output(int fd, lbool no_term_init)
{
flush();
outfd = fd;
if (no_term_init)
term_init_ever = TRUE; /* don't init terminal in putchr */
}
/*
@@ -455,25 +484,23 @@ public void set_output(int fd)
public int putchr(int ch)
{
char c = (char) ch;
#if 0 /* fake UTF-8 output for testing */
extern int utf_mode;
if (utf_mode)
/*
* Init the terminal if this is the first byte written to stdout
* (rather than stderr), and the terminal has never been initted.
* If it has previously been initted, it will be reinitted explicitly
* as part of a term_deinit/term_init pair, so we shouldn't do it here.
*/
if (!term_init_ever && outfd == 1)
term_init();
if (prompting)
{
static char ubuf[MAX_UTF_CHAR_LEN];
static int ubuf_len = 0;
static int ubuf_index = 0;
if (ubuf_len == 0)
{
ubuf_len = utf_len(c);
ubuf_index = 0;
}
ubuf[ubuf_index++] = c;
if (ubuf_index < ubuf_len)
return c;
c = get_wchar(ubuf) & 0xFF;
ubuf_len = 0;
constant char *epr = end_pr_string();
prompting = FALSE;
if (epr != NULL)
putstr(epr);
}
#endif
clear_bot_if_needed();
#if MSDOS_COMPILER
if (c == '\n' && is_tty)
@@ -494,7 +521,6 @@ public int putchr(int ch)
if (ob >= &obuf[sizeof(obuf)-1])
flush();
*ob++ = c;
at_prompt = 0;
return (c);
}
@@ -502,7 +528,7 @@ public void clear_bot_if_needed(void)
{
if (!need_clr)
return;
need_clr = 0;
need_clr = FALSE;
clear_bot();
}
@@ -590,7 +616,7 @@ IPRINT_FUNC(iprint_linenum, LINENUM, linenumtoa)
* {{ This paranoia about the portability of printf dates from experiences
* with systems in the 1980s and is of course no longer necessary. }}
*/
public int less_printf(constant char *fmt, PARG *parg)
public int less_printf(constant char *fmt, constant PARG *parg)
{
constant char *s;
constant char *es;
@@ -664,7 +690,7 @@ public void get_return(void)
#if ONLY_RETURN
while ((c = getchr()) != '\n' && c != '\r')
bell();
lbell();
#else
c = getchr();
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
@@ -676,7 +702,7 @@ public void get_return(void)
* Output a message in the lower left corner of the screen
* and wait for carriage return.
*/
public void error(constant char *fmt, PARG *parg)
public void error(constant char *fmt, constant PARG *parg)
{
int col = 0;
static char return_to_continue[] = " (press RETURN)";
@@ -722,7 +748,7 @@ public void error(constant char *fmt, PARG *parg)
* Usually used to warn that we are beginning a potentially
* time-consuming operation.
*/
static void ierror_suffix(constant char *fmt, PARG *parg, constant char *suffix1, constant char *suffix2, constant char *suffix3)
static void ierror_suffix(constant char *fmt, constant PARG *parg, constant char *suffix1, constant char *suffix2, constant char *suffix3)
{
at_exit();
clear_bot();
@@ -733,15 +759,15 @@ static void ierror_suffix(constant char *fmt, PARG *parg, constant char *suffix1
putstr(suffix3);
at_exit();
flush();
need_clr = 1;
need_clr = TRUE;
}
public void ierror(constant char *fmt, PARG *parg)
public void ierror(constant char *fmt, constant PARG *parg)
{
ierror_suffix(fmt, parg, "... (interrupt to abort)", "", "");
}
public void ixerror(constant char *fmt, PARG *parg)
public void ixerror(constant char *fmt, constant PARG *parg)
{
if (!supports_ctrl_x())
ierror(fmt, parg);
@@ -757,7 +783,7 @@ public void ixerror(constant char *fmt, PARG *parg)
* Output a message in the lower left corner of the screen
* and return a single-character response.
*/
public int query(constant char *fmt, PARG *parg)
public int query(constant char *fmt, constant PARG *parg)
{
int c;
int col = 0;
+7 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -147,7 +147,11 @@ public int compile_pattern(constant char *pattern, int search_type, int show_err
{
int result;
if (caseless != OPT_ONPLUS || (re_handles_caseless && !(search_type & SRCH_NO_REGEX)))
#if RE_HANDLES_CASELESS
if (caseless != OPT_ONPLUS || (!(search_type & SRCH_NO_REGEX)))
#else
if (caseless != OPT_ONPLUS)
#endif
{
result = compile_pattern2(pattern, search_type, comp_pattern, show_error);
} else
@@ -391,7 +395,7 @@ static lbool match_pattern1(PATTERN_TYPE pattern, constant char *tpattern, const
#if HAVE_PCRE2
{
int flags = (notbol) ? PCRE2_NOTBOL : 0;
pcre2_match_data *md = pcre2_match_data_create(nsp-1, NULL);
pcre2_match_data *md = pcre2_match_data_create_from_pattern(pattern, NULL);
int mcount = pcre2_match(pattern, (PCRE2_SPTR)line, line_len,
line_off, flags, md, NULL);
matched = (mcount > 0);
+6 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -25,7 +25,7 @@ extern int less_is_more;
#endif
#define PATTERN_TYPE regex_t *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#define RE_HANDLES_CASELESS 1
#endif
/* ---- PCRE ---- */
@@ -33,7 +33,7 @@ extern int less_is_more;
#include <pcre.h>
#define PATTERN_TYPE pcre *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#define RE_HANDLES_CASELESS 1
#endif
/* ---- PCRE2 ---- */
@@ -42,7 +42,7 @@ extern int less_is_more;
#include <pcre2.h>
#define PATTERN_TYPE pcre2_code *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#define RE_HANDLES_CASELESS 1
#endif
/* ---- RE_COMP ---- */
@@ -76,6 +76,6 @@ extern int reg_show_error;
#define SET_NULL_PATTERN(name)
#endif
#ifndef re_handles_caseless
#define re_handles_caseless FALSE
#ifndef RE_HANDLES_CASELESS
#define RE_HANDLES_CASELESS 0
#endif
+26 -19
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -13,21 +13,28 @@
* Special (non-ASCII) keys on the PC send a two-byte sequence,
* where the first byte is 0 and the second is as defined below.
*/
#define PCK_SHIFT_TAB '\017'
#define PCK_ALT_E '\022'
#define PCK_CAPS_LOCK '\072'
#define PCK_F1 '\073'
#define PCK_NUM_LOCK '\105'
#define PCK_HOME '\107'
#define PCK_UP '\110'
#define PCK_PAGEUP '\111'
#define PCK_LEFT '\113'
#define PCK_RIGHT '\115'
#define PCK_END '\117'
#define PCK_DOWN '\120'
#define PCK_PAGEDOWN '\121'
#define PCK_INSERT '\122'
#define PCK_DELETE '\123'
#define PCK_CTL_LEFT '\163'
#define PCK_CTL_RIGHT '\164'
#define PCK_CTL_DELETE '\223'
#define PCK_SHIFT_TAB '\x0f'
#define PCK_ALT_E '\x12'
#define PCK_CAPS_LOCK '\x3a'
#define PCK_F1 '\x3b'
#define PCK_NUM_LOCK '\x45'
#define PCK_HOME '\x47'
#define PCK_UP '\x48'
#define PCK_PAGEUP '\x49'
#define PCK_LEFT '\x4b'
#define PCK_RIGHT '\x4d'
#define PCK_END '\x4f'
#define PCK_DOWN '\x50'
#define PCK_PAGEDOWN '\x51'
#define PCK_INSERT '\x52'
#define PCK_DELETE '\x53'
/* The following are nonstandard and internal to less. */
#define PCK_SHIFT_END '\x61'
#define PCK_CTL_DELETE '\x62'
#define PCK_CTL_LEFT '\x63'
#define PCK_CTL_RIGHT '\x74'
#define PCK_CTL_HOME '\x7a'
#define PCK_CTL_END '\x7c'
#define PCK_SHIFT_HOME '\x7d'
#define PCK_SHIFT_LEFT '\x73'
#define PCK_SHIFT_RIGHT '\x7f'
+57 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -147,19 +147,19 @@ public int onscreen(POSITION pos)
/*
* See if the entire screen is empty.
*/
public int empty_screen(void)
public lbool empty_screen(void)
{
return (empty_lines(0, sc_height-1));
}
public int empty_lines(int s, int e)
public lbool empty_lines(int s, int e)
{
int i;
for (i = s; i <= e; i++)
if (table[i] != NULL_POSITION && table[i] != 0)
return (0);
return (1);
if (table[i] != NULL_POSITION)
return FALSE;
return TRUE;
}
/*
@@ -170,7 +170,7 @@ public int empty_lines(int s, int e)
* such that the top few lines are empty, we may have to set
* the screen line to a number > 0.
*/
public void get_scrpos(struct scrpos *scrpos, int where)
public void get_scrpos_pos(struct scrpos *scrpos, int where, POSITION pos)
{
int i;
int dir;
@@ -194,24 +194,52 @@ public void get_scrpos(struct scrpos *scrpos, int where)
break;
}
/*
* Find the first line on the screen which has something on it,
* and return the screen line number and the file position.
*/
for (;; i += dir)
if (pos != NULL_POSITION)
{
if (table[i] != NULL_POSITION)
scrpos->ln = i+1;
scrpos->pos = pos;
} else
{
/*
* Find the first line on the screen which has something on it,
* and return the screen line number and the file position.
*/
for (;; i += dir)
{
scrpos->ln = i+1;
scrpos->pos = table[i];
return;
if (table[i] != NULL_POSITION)
{
scrpos->ln = i+1;
scrpos->pos = table[i];
return;
}
if (i == last) break;
}
if (i == last) break;
/* The screen is empty. */
scrpos->pos = NULL_POSITION;
}
}
public void get_scrpos(struct scrpos *scrpos, int where)
{
get_scrpos_pos(scrpos, where, NULL_POSITION);
}
/*
* Convert sline to sindex and clip to screen size.
*/
static int sindex_from_sline_clipped(int sline)
{
/*
* The screen is empty.
* Can't be less than 1 or greater than sc_height-1.
*/
scrpos->pos = NULL_POSITION;
if (sline <= 0)
sline = 1;
if (sline >= sc_height)
sline = sc_height-1;
/*
* Return zero-based line number, not one-based.
*/
return (sline-1);
}
/*
@@ -231,17 +259,7 @@ public int sindex_from_sline(int sline)
*/
if (sline < 0)
sline += sc_height;
/*
* Can't be less than 1 or greater than sc_height.
*/
if (sline <= 0)
sline = 1;
if (sline > sc_height)
sline = sc_height;
/*
* Return zero-based line number, not one-based.
*/
return (sline-1);
return sindex_from_sline_clipped(sline);
}
/*
@@ -273,12 +291,14 @@ static int pos_shift(POSITION linepos, size_t choff)
* Return the position of the first char of the line containing tpos.
* Thus if tpos is the first char of its line, just return tpos.
*/
static POSITION beginning_of_line(POSITION tpos)
public POSITION beginning_of_line(POSITION tpos)
{
ch_seek(tpos);
while (ch_tell() != ch_zero())
{
int ch = ch_back_get();
if (ch == EOI)
break; /* {{ probably unnecessary due to ch_zero() check }} */
if (ch == '\n')
{
(void) ch_forw_get();
@@ -291,10 +311,11 @@ static POSITION beginning_of_line(POSITION tpos)
/*
* When viewing long lines, it may be that the first char in the top screen
* line is not the first char in its (file) line (the table is "beheaded").
* This function sets that entry to the position of the first char in the line,
* and sets hshift so that the first char in the first line is unchanged.
* This function sets that entry to the position of the first char in the
* line, and optionally sets hshift so that the first char in the first line
* is unchanged.
*/
public void pos_rehead(void)
public void pos_rehead(lbool adj_hshift)
{
POSITION linepos;
POSITION tpos = table[TOP];
@@ -304,6 +325,7 @@ public void pos_rehead(void)
if (linepos == tpos)
return;
table[TOP] = linepos;
hshift = pos_shift(linepos, (size_t) (tpos - linepos));
if (adj_hshift)
hshift = pos_shift(linepos, (size_t) (tpos - linepos));
screen_trashed();
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+56 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -24,6 +24,7 @@ extern int pr_type;
extern lbool new_file;
extern int linenums;
extern int hshift;
extern int sc_width;
extern int sc_height;
extern int jump_sline;
extern int less_is_more;
@@ -31,7 +32,7 @@ extern int header_lines;
extern int utf_mode;
extern IFILE curr_ifile;
#if OSC8_LINK
extern char *osc8_path;
extern POSITION osc8_linepos;
#endif
#if EDITOR
extern constant char *editor;
@@ -47,9 +48,9 @@ static constant char s_proto[] =
static constant char m_proto[] =
"?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t";
static constant char M_proto[] =
"?f%f .?n?m(%T %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t";
"?f%f .?n?m(%T %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..?c (column %c).%t";
static constant char e_proto[] =
"?f%f .?m(%T %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t";
"?f%f .?m(%T %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..?c (column %c).%t";
static constant char h_proto[] =
"HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done";
static constant char w_proto[] =
@@ -58,12 +59,14 @@ static constant char more_proto[] =
"--More--(?eEND ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t)";
public char *prproto[3];
public char *eprproto[3];
public char constant *eqproto = e_proto;
public char constant *hproto = h_proto;
public char constant *wproto = w_proto;
static char message[PROMPT_SIZE];
static char *mp;
static int longest_line;
/*
* Initialize the prompt prototype strings.
@@ -73,11 +76,24 @@ public void init_prompt(void)
prproto[0] = save(s_proto);
prproto[1] = save(less_is_more ? more_proto : m_proto);
prproto[2] = save(M_proto);
eprproto[0] = eprproto[1] = eprproto[2] = NULL;
eqproto = save(e_proto);
hproto = save(h_proto);
wproto = save(w_proto);
}
/*
* Get width of longest line currently on screen.
* Calling longest_line_width() is expensive, so we cache its value here
* in case it is called more than once per prompt expansion.
*/
static int pr_longest_line(void)
{
if (longest_line < 0)
longest_line = longest_line_width();
return longest_line;
}
/*
* Append a string to the end of the message.
* nprt means the character *may* be nonprintable
@@ -226,6 +242,12 @@ static lbool cond(char c, int where)
return (ntags() ? TRUE : new_file ? TRUE : FALSE);
#else
return (new_file ? TRUE : FALSE);
#endif
case 'O': /* OSC 8 link selected? */
#if OSC8_LINK
return (osc8_linepos != NULL_POSITION);
#else
return FALSE;
#endif
case 'p': /* Percent into file (bytes) known? */
return (curr_byte(where) != NULL_POSITION && ch_length() > 0);
@@ -233,6 +255,8 @@ static lbool cond(char c, int where)
return (currline(where) != 0 &&
(len = ch_length()) > 0 &&
find_linenum(len) != 0);
case 'Q': /* Any on-screen line truncated? */
return (hshift + sc_width < pr_longest_line());
case 's': /* Size of file known? */
case 'B':
return (ch_length() != NULL_POSITION);
@@ -275,7 +299,10 @@ static void protochar(char c, int where)
ap_quest();
break;
case 'c':
ap_int(hshift);
ap_int(hshift+1);
break;
case 'C':
ap_int(hshift + sc_width);
break;
case 'd': /* Current page number */
linenum = currline(where);
@@ -349,14 +376,6 @@ static void protochar(char c, int where)
#endif
ap_int(nifile());
break; }
case 'o': /* path (URI without protocol) of selected OSC8 link */
#if OSC8_LINK
if (osc8_path != NULL)
ap_str(osc8_path);
else
#endif
ap_quest();
break;
case 'p': /* Percent into file (bytes) */
pos = curr_byte(where);
len = ch_length();
@@ -374,6 +393,9 @@ static void protochar(char c, int where)
else
ap_int(percentage(linenum, last_linenum));
break;
case 'Q': /* Percent shifted horizontally */
ap_int(percentage(hshift + sc_width, pr_longest_line()));
break;
case 's': /* Size of file */
case 'B':
len = ch_length();
@@ -395,6 +417,9 @@ static void protochar(char c, int where)
#endif
ap_str("file");
break;
case 'W': /* Width of longest line on screen */
ap_int(pr_longest_line());
break;
case 'x': /* Name of next file */
h = next_ifile(curr_ifile);
if (h != NULL_IFILE)
@@ -496,11 +521,12 @@ public constant char * pr_expand(constant char *proto)
char c;
int where;
mp = message;
if (*proto == '\0')
return ("");
mp = message;
longest_line = -1;
for (p = proto; *p != '\0'; p++)
{
switch (*p)
@@ -572,6 +598,21 @@ public constant char * pr_string(void)
return (prompt);
}
/*
* Return the end prompt string.
*/
public constant char * end_pr_string(void)
{
int type;
if (ch_getflags() & CH_HELPFILE)
return NULL;
type = (!less_is_more) ? pr_type : pr_type ? 0 : 1;
if (eprproto[type] == NULL)
return NULL;
return pr_expand(eprproto[type]);
}
/*
* Return a message suitable for printing while waiting in the F command.
*/
+147 -59
View File
@@ -25,6 +25,8 @@
* *** NOTE: this code has been altered slightly for use in Tcl. ***
* Slightly modified by David MacKenzie to undo most of the changes for TCL.
* Added regexec2 with notbol parameter. -- 4/19/99 Mark Nudelman
* Change functions style from K&R to C89 -- 2023-09 Avi Halachmi
* Add support for character classes [:NAME:] -- 2026-02 Avi Halachmi
*/
#include "less.h"
@@ -47,16 +49,13 @@
* regstart char that must begin a match; '\0' if none obvious
* reganch is the match anchored (at beginning-of-line only)?
* regmust string (pointer into program) that match must include, or NULL
* regmlen length of regmust string
*
* Regstart and reganch permit very fast decisions on suitable starting points
* for a match, cutting down the work a lot. Regmust permits fast rejection
* of lines that cannot possibly match. The regmust tests are costly enough
* that regcomp() supplies a regmust only if the r.e. contains something
* potentially expensive (at present, the only such thing detected is * or +
* at the start of the r.e., which can involve a lot of backup). Regmlen is
* supplied because the test in regexec() needs it and regcomp() is
* computing it anyway.
* at the start of the r.e., which can involve a lot of backup).
*/
/*
@@ -251,7 +250,6 @@ regcomp(constant char *exp)
r->regstart = '\0'; /* Worst-case defaults. */
r->reganch = 0;
r->regmust = NULL;
r->regmlen = 0;
scan = r->program+1; /* First BRANCH. */
if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
scan = OPERAND(scan);
@@ -276,10 +274,10 @@ regcomp(constant char *exp)
for (; scan != NULL; scan = regnext(scan))
if (OP(scan) == EXACTLY && ((int) strlen(OPERAND(scan))) >= len) {
longest = OPERAND(scan);
/* redundant strlen, not critical in regcomp */
len = (int) strlen(OPERAND(scan));
}
r->regmust = longest;
r->regmlen = len;
}
}
@@ -458,6 +456,126 @@ regpiece(int *flagp)
return(ret);
}
/*
* Handling of character classes [:NAME:]
*
* - We only cover C/POSIX locale (ASCII).
* - We identify the 12 POSIX classes.
* - We error on unknown [:THING:].
* - [=EQUIV=] or [.COLLATE.] are NOT detected, and considered non-special.
* - [:NAME:] errors on either side of '-' range (but not if the '-' is
* literal - at the beginning or end of the [...]).
* - The logic is confined to regbracket(), and only used during regcomp.
*
* POSIX regex, classes, collation, etc:
* https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap09.html
* https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap07.html
*/
typedef struct cclass {
constant size_t len; /* of id */
constant char *id;
constant char *chars;
} cclass;
static constant cclass cclasses[] = {
/* first two chars of id are ignored, and expected to be "[:" */
{9, "[:alnum:]", "0-9A-Za-z"},
{9, "[:alpha:]", "A-Za-z"},
{9, "[:blank:]", "\t "},
{9, "[:cntrl:]", "\x01-\x1f\x7f"},
{9, "[:digit:]", "0-9"},
{9, "[:graph:]", "\x21-\x7e"},
{9, "[:lower:]", "a-z"},
{9, "[:print:]", "\x20-\x7e"},
{9, "[:punct:]", "!-/:-@[-`{|}~"},
{9, "[:space:]", "\t\n\v\f\r "},
{9, "[:upper:]", "A-Z"},
{10, "[:xdigit:]", "0-9A-Fa-f"},
};
/* returns index>=0 in cclasses if s starts with known [:NAME:],
* else -2 on error (s starts with unknown [:THING:]),
* else -1 (not-special).
*
* we could create a wrapper macro which tests '[' and ':' before
* calling cclass_idx(s) - to avoid a function call on early abort,
* and/or replace the string search in cclass_idx with binary search
* or something else, but this is not hot code, so keep it simple.
*/
static int
cclass_idx(constant char *s)
{
int i;
constant char *p;
if (*s++ != '[' || *s++ != ':')
return -1;
/* s is past the "[:" prefix */
for (i = 0; i < countof(cclasses); ++i)
if (strncmp(s, cclasses[i].id + 2, cclasses[i].len - 2) == 0)
return i; /* found */
p = strchr(s, ']');
if (p && p != s && p[-1] == ':')
return -2; /* unrecognized [:THING:] */
return -1; /* not special as far as we can tell */
}
/* Calls regc(c) for each char which a bracket expression matches,
* without touching the global regparse.
*
* The caller should ensure that ANYOF or ANYBUT node was already added
* (depending on whether it starts with "[" or "[^"), and "in" should
* point to the first data char after this prefix.
*
* calls FAIL(...) and returns NULL on failure,
* or returns a pointer to the first unprocessed char (']' or '\0').
* the caller may then update the global regparse, and add final regc(0).
*/
static constant char *
regbracket(constant char *in)
{
register int clss;
register int classend;
int idx;
if (*in == ']' || *in == '-')
regc(*in++);
while (*in != '\0' && *in != ']') {
if (*in == '-') {
in++;
if (cclass_idx(in) != -1)
FAIL("invalid [] range end"); /* X-[:NAME:] */
if (*in == ']' || *in == '\0')
regc('-');
else {
clss = UCHARAT(in-2)+1;
classend = UCHARAT(in);
if (clss > classend+1)
FAIL("invalid [] range");
for (; clss <= classend; clss++)
regc(clss);
in++;
}
} else if ((idx = cclass_idx(in)) == -1) {
regc(*in++);
} else if (idx == -2) {
FAIL("unknown [:CLASS:] name");
} else { /* idx is a valid index, add class chars */
if (regbracket(cclasses[idx].chars) == NULL)
return(NULL); /* should be unreachable */
in += cclasses[idx].len;
if (*in == '-' && in[1] != '\0' && in[1] != ']')
FAIL("invalid [] range start"); /* [:NAME:]-X */
}
}
return in;
}
/*
- regatom - the lowest level
*
@@ -485,40 +603,22 @@ regatom(int *flagp)
ret = regnode(ANY);
*flagp |= HASWIDTH|SIMPLE;
break;
case '[': {
register int clss;
register int classend;
if (*regparse == '^') { /* Complement of range. */
ret = regnode(ANYBUT);
regparse++;
} else
ret = regnode(ANYOF);
if (*regparse == ']' || *regparse == '-')
regc(*regparse++);
while (*regparse != '\0' && *regparse != ']') {
if (*regparse == '-') {
regparse++;
if (*regparse == ']' || *regparse == '\0')
regc('-');
else {
clss = UCHARAT(regparse-2)+1;
classend = UCHARAT(regparse);
if (clss > classend+1)
FAIL("invalid [] range");
for (; clss <= classend; clss++)
regc(clss);
regparse++;
}
} else
regc(*regparse++);
}
regc('\0');
if (*regparse != ']')
FAIL("unmatched []");
case '[':
if (*regparse == '^') { /* Complement of range. */
ret = regnode(ANYBUT);
regparse++;
*flagp |= HASWIDTH|SIMPLE;
}
} else
ret = regnode(ANYOF);
regparse = regbracket(regparse);
if (regparse == NULL)
return(NULL);
regc('\0');
if (*regparse != ']')
FAIL("unmatched []");
regparse++;
*flagp |= HASWIDTH|SIMPLE;
break;
case '(':
ret = reg(1, &flags);
@@ -701,8 +801,7 @@ STATIC int regrepeat(char *);
#ifdef DEBUG
int regnarrate = 0;
void regdump();
STATIC char *regprop();
STATIC constant char *regprop(constant char *);
#endif
/*
@@ -726,16 +825,8 @@ regexec2(register regexp *prog, register constant char *string, int notbol)
}
/* If there is a "must appear" string, look for it. */
if (prog->regmust != NULL) {
s = string;
while ((s = strchr(s, prog->regmust[0])) != NULL) {
if (strncmp(s, prog->regmust, prog->regmlen) == 0)
break; /* Found it. */
s++;
}
if (s == NULL) /* Not present. */
return(0);
}
if (prog->regmust != NULL && strstr(string, prog->regmust) == NULL)
return(0); /* Not present. */
/* Mark beginning of line for ^ . */
if (notbol)
@@ -1068,14 +1159,11 @@ regnext(register char *p)
#ifdef DEBUG
STATIC char *regprop();
/*
- regdump - dump a regexp onto stdout in vaguely comprehensible form
*/
void
regdump(r)
regexp *r;
regdump(regexp *r)
{
register char *s;
register char op = EXACTLY; /* Arbitrary non-END op. */
@@ -1085,12 +1173,13 @@ regexp *r;
s = r->program + 1;
while (op != END) { /* While that wasn't END last time... */
op = OP(s);
printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
/* prints ADDRESS:... where the ":..." is from regprop(s) */
printf("%2ld%s", (long)(s - r->program), regprop(s));
next = regnext(s);
if (next == NULL) /* Next ptr. */
printf("(0)");
else
printf("(%d)", (s-r->program)+(next-s));
printf("(%ld)", (long)((s - r->program)+(next-s)));
s += 3;
if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
/* Literal string, where present. */
@@ -1117,8 +1206,7 @@ regexp *r;
- regprop - printable representation of opcode
*/
static constant char *
regprop(op)
constant char *op;
regprop(constant char *op)
{
register char *p;
static char buf[50];
+4 -1
View File
@@ -15,7 +15,6 @@ typedef struct regexp {
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
int regmlen; /* Internal use only. */
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
@@ -31,4 +30,8 @@ extern int regexec2 _ANSI_ARGS_((regexp *prog, constant char *string, int notbol
extern void regsub _ANSI_ARGS_((regexp *prog, constant char *source, char *dest));
extern void regerror _ANSI_ARGS_((constant char *msg));
#ifdef DEBUG
extern void regdump _ANSI_ARGS_((regexp *r));
#endif
#endif /* REGEXP */
+446 -172
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
+97 -64
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -29,6 +29,8 @@ extern int proc_backspace;
extern int proc_return;
extern int ctldisp;
extern int status_col;
extern int status_line;
extern int hilite_target;
extern void *ml_search;
extern POSITION start_attnpos;
extern POSITION end_attnpos;
@@ -63,7 +65,6 @@ public POSITION osc8_uri_start = NULL_POSITION;
public POSITION osc8_uri_end = NULL_POSITION;
public POSITION osc8_text_start = NULL_POSITION;
public POSITION osc8_text_end = NULL_POSITION;
char *osc8_path = NULL;
char *osc8_uri = NULL;
constant char *osc8_search_param = NULL;
#endif
@@ -230,8 +231,13 @@ public int get_cvt_ops(int search_type)
{
int ops = 0;
if (is_caseless && (!re_handles_caseless || (search_type & SRCH_NO_REGEX)))
#if RE_HANDLES_CASELESS
if (is_caseless && (search_type & SRCH_NO_REGEX))
ops |= CVT_TO_LC;
#else
if (is_caseless)
ops |= CVT_TO_LC;
#endif
if (proc_backspace == OPT_ON || (bs_mode == BS_SPECIAL && proc_backspace == OPT_OFF))
ops |= CVT_BS;
if (proc_return == OPT_ON || (bs_mode != BS_CONTROL && proc_backspace == OPT_OFF))
@@ -253,6 +259,14 @@ static lbool prev_pattern(struct pattern_info *info)
return (info->text != NULL);
}
/*
* Return text of previous search pattern.
*/
public constant char* prev_pattern_text(void)
{
return search_info.text;
}
#if HILITE_SEARCH
/*
* Repaint the hilites currently displayed on the screen.
@@ -299,6 +313,27 @@ public void repaint_hilite(lbool on)
}
#endif
/*
* Redraw the jump target line with the attn hilite on or off.
*/
public void draw_target_attn(lbool hilite)
{
int sindex;
POSITION pos;
if (!can_goto_line) /* {{ Are there any such terminals any more? }} */
return;
if (squished)
return;
sindex = sindex_from_sline(jump_sline);
pos = position(sindex);
forw_line_seg(pos, chop_line() || hshift > 0, TRUE, FALSE, hilite && status_line, FALSE, NULL, NULL);
goto_line(sindex);
clear_eol();
put_line_hilite(TRUE, hilite);
lower_left();
}
/*
* Clear the attn hilite.
*/
@@ -312,6 +347,9 @@ public void clear_attn(void)
POSITION epos;
int moved = 0;
if (hilite_target)
draw_target_attn(FALSE);
if (start_attnpos == NULL_POSITION)
return;
old_start_attnpos = start_attnpos;
@@ -354,32 +392,37 @@ public void clear_attn(void)
*/
public void undo_search(lbool clear)
{
clear_pattern(&search_info);
undo_osc8();
#if HILITE_SEARCH
lbool osc8_active = undo_osc8();
lbool has_pattern = prev_pattern(&search_info);
if (clear)
{
clear_pattern(&search_info);
clr_hilite();
} else
{
if (hilite_anchor.first == NULL)
{
if (has_pattern)
hide_hilite = !hide_hilite;
else if (!osc8_active)
error("No previous regular expression", NULL_PARG);
return;
}
hide_hilite = !hide_hilite;
}
repaint_hilite(TRUE);
#else
undo_osc8();
clear_pattern(&search_info);
#endif
}
/*
*/
public void undo_osc8(void)
public lbool undo_osc8(void)
{
lbool was_active = FALSE;
#if OSC8_LINK
was_active = (osc8_linepos != NULL_POSITION);
osc8_linepos = NULL_POSITION;
#endif
return was_active;
}
#if HILITE_SEARCH
@@ -957,7 +1000,7 @@ static void add_hilite(struct hilite_tree *anchor, struct hilite *hl)
*/
static void create_hilites(POSITION linepos, constant char *line, constant char *sp, constant char *ep, int attr, int *chpos)
{
size_t start_index = ptr_diff(sp, line); /*{{type-issue}}*/
size_t start_index = ptr_diff(sp, line);
size_t end_index = ptr_diff(ep, line);
struct hilite hl;
size_t i;
@@ -1813,6 +1856,7 @@ public lbool osc8_click(int sindex, int col)
clickpos = pos_from_col(linepos, col, NULL_POSITION, -1);
if (clickpos == NULL_POSITION)
return FALSE;
linepos = beginning_of_line(linepos);
if (forw_raw_line(linepos, &line, &line_len) == NULL_POSITION)
return FALSE;
r = osc8_search_line(SRCH_FORW|SRCH_OSC8, linepos, line, line_len, NULL, clickpos, &matches);
@@ -1843,18 +1887,6 @@ static size_t scheme_length(constant char *uri, size_t uri_len)
return 0;
}
/*
* Does a URI contain any dangerous characters?
*/
static lbool bad_uri(constant char *uri, size_t uri_len)
{
size_t i;
for (i = 0; i < uri_len; i++)
if (strchr("'\"", uri[i]) != NULL)
return TRUE;
return FALSE;
}
/*
* Re-read the line containing the selected OSC8 link.
*/
@@ -1885,10 +1917,11 @@ public void osc8_open(void)
char env_name[64];
size_t scheme_len;
constant char *handler;
char *open_cmd;
char *cmd;
char *uri_q;
size_t uri_len;
FILE *hf;
static constant char *env_name_pfx = "LESS_OSC8_";
char *p;
static constant char *env_name_pfx = "LESS_OSC8_OPEN_";
if (osc8_linepos == NULL_POSITION)
{
@@ -1901,9 +1934,8 @@ public void osc8_open(void)
return;
}
/*
* Read a "handler" shell cmd from environment variable "LESS_OSC8_scheme".
* pr_expand the handler cmd (to expand %o -> osc8_path) and execute it.
* Handler's stdout is an "opener" shell cmd; execute opener to open the link.
* Read a "handler" shell cmd from environment variable "LESS_OSC8_OPEN_scheme".
* Append the URI to the handler as an argument, and execute it.
*/
uri_len = ptr_diff(op.uri_end, op.uri_start);
scheme_len = scheme_length(op.uri_start, uri_len);
@@ -1918,16 +1950,19 @@ public void osc8_open(void)
free(param);
return;
}
#if HAVE_POPEN
if (bad_uri(op.uri_start, uri_len))
if (scheme_len == 0)
{
error("Cannot open link containing quote characters", NULL_PARG);
return;
SNPRINTF1(env_name, sizeof(env_name), "%sNONE", env_name_pfx);
} else
{
SNPRINTF3(env_name, sizeof(env_name), "%s%.*s", env_name_pfx, (int) scheme_len, op.uri_start);
for (p = &env_name[strlen(env_name_pfx)]; *p != '\0'; p++)
if (ASCII_IS_UPPER(*p))
*p = ASCII_TO_LOWER(*p);
}
SNPRINTF3(env_name, sizeof(env_name), "%s%.*s", env_name_pfx, (int) scheme_len, op.uri_start);
handler = lgetenv(env_name);
if (isnullenv(handler) || strcmp(handler, "-") == 0)
handler = lgetenv("LESS_OSC8_ANY");
handler = lgetenv("LESS_OSC8_OPEN_ANY");
if (isnullenv(handler))
{
PARG parg;
@@ -1935,31 +1970,25 @@ public void osc8_open(void)
error("No handler for \"%s\" link type", &parg);
return;
}
/* {{ ugly global osc8_path }} */
osc8_path = saven(op.uri_start, uri_len);
hf = popen(pr_expand(handler), "r");
free(osc8_path);
osc8_path = NULL;
if (hf == NULL)
uri_q = shell_quoten(op.uri_start, uri_len);
cmd = ecalloc(strlen(handler) + strlen(uri_q) + 2, sizeof(char));
sprintf(cmd, "%s %s", handler, uri_q);
free(uri_q);
{
PARG parg;
parg.p_string = env_name;
error("Cannot execute protocol handler in %s", &parg);
return;
constant char *exec_cmd = cmd;
constant char *done_msg = "link done";
POSITION save_osc8_linepos = osc8_linepos;
if (*exec_cmd == CONTROL('P'))
{
done_msg = NULL;
exec_cmd++;
}
lsystem(exec_cmd, done_msg);
/* lsystem reedits the input file which clears the selected
* OSC8 link, so restore it. */
osc8_linepos = save_osc8_linepos;
}
open_cmd = readfd(hf);
pclose(hf);
if (strncmp(open_cmd, ":e", 2) == 0)
{
edit(skipsp(&open_cmd[2]));
} else
{
lsystem(open_cmd, "link done");
}
free(open_cmd);
#else
error("Cannot open link because your system does not support popen", NULL_PARG);
#endif /* HAVE_POPEN */
free(cmd);
}
/*
@@ -2021,15 +2050,19 @@ public void chg_caseless(void)
* If regex handles caseless, we need to discard
* the pattern which was compiled with the old caseless.
*/
if (!re_handles_caseless)
/* We handle caseless, so the pattern doesn't change. */
return;
#if !RE_HANDLES_CASELESS
/* Less handles caseless, so the pattern doesn't change. */
return;
#endif
}
/*
* Regenerate the pattern using the new state.
*/
clear_pattern(&search_info);
(void) hist_pattern(search_info.search_type);
if (prev_pattern(&search_info))
{
clear_pattern(&search_info);
(void) hist_pattern(search_info.search_type);
}
}
/*
+19 -11
View File
@@ -1,6 +1,6 @@
#include <errno.h>
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -44,7 +44,7 @@ extern int less_is_more;
static RETSIGTYPE u_interrupt(int type)
{
(void) type;
bell();
lbell();
#if OS2
LSIGNAL(SIGINT, SIG_ACK);
#endif
@@ -64,6 +64,7 @@ static RETSIGTYPE u_interrupt(int type)
#if HILITE_SEARCH
set_filter_pattern(NULL, 0);
#endif
polling_ok();
intio();
}
#endif
@@ -96,10 +97,10 @@ static RETSIGTYPE stop(int type)
* "Window" change handler
*/
/* ARGSUSED*/
public RETSIGTYPE winch(int type)
public RETSIGTYPE lwinch(int type)
{
(void) type;
LSIGNAL(SIG_LESSWINDOW, winch);
LSIGNAL(SIG_LESSWINDOW, lwinch);
#if LESSTEST
/*
* Ignore window changes during lesstest.
@@ -185,10 +186,10 @@ public void init_signals(int on)
(void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : stop);
#endif
#ifdef SIGWINCH
(void) LSIGNAL(SIGWINCH, winch);
(void) LSIGNAL(SIGWINCH, lwinch);
#endif
#ifdef SIGWIND
(void) LSIGNAL(SIGWIND, winch);
(void) LSIGNAL(SIGWIND, lwinch);
#endif
#ifdef SIGQUIT
(void) LSIGNAL(SIGQUIT, SIG_IGN);
@@ -196,6 +197,9 @@ public void init_signals(int on)
#ifdef SIGTERM
(void) LSIGNAL(SIGTERM, terminate);
#endif
#ifdef SIGHUP
(void) LSIGNAL(SIGHUP, terminate);
#endif
#ifdef SIGUSR1
(void) LSIGNAL(SIGUSR1, sigusr1);
#endif
@@ -224,6 +228,9 @@ public void init_signals(int on)
#ifdef SIGTERM
(void) LSIGNAL(SIGTERM, SIG_DFL);
#endif
#ifdef SIGHUP
(void) LSIGNAL(SIGHUP, SIG_DFL);
#endif
#ifdef SIGUSR1
(void) LSIGNAL(SIGUSR1, SIG_DFL);
#endif
@@ -252,7 +259,7 @@ public void psignals(void)
LSIGNAL(SIGTTOU, SIG_IGN);
#endif
clear_bot();
deinit();
term_deinit();
flush();
raw_mode(0);
#ifdef SIGTTOU
@@ -268,7 +275,7 @@ public void psignals(void)
*/
LSIGNAL(SIGTSTP, stop);
raw_mode(1);
init();
term_init();
screen_trashed();
tsignals |= S_WINCH;
}
@@ -284,10 +291,7 @@ public void psignals(void)
old_height = sc_height;
get_term();
if (sc_width != old_width || sc_height != old_height)
{
wscroll = (sc_height + 1) / 2;
screen_size_changed();
}
screen_trashed();
}
#endif
@@ -295,5 +299,9 @@ public void psignals(void)
{
if (quit_on_intr)
quit(QUIT_INTERRUPT);
getcc_clear();
#if MSDOS_COMPILER==WIN32C
win32_getch_clear();
#endif
}
}
+11 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -256,12 +256,12 @@ static enum tag_result findctag(constant char *tag)
char *q;
FILE *f;
size_t taglen;
int n;
LINENUM taglinenum;
char *tagfile;
char *tagpattern;
lbool tagendline;
int search_char;
lbool err;
char tline[TAGLINE_SIZE];
struct tag *tp;
@@ -321,8 +321,15 @@ static enum tag_result findctag(constant char *tag)
* First see if it is a line number.
*/
tagendline = FALSE;
taglinenum = getnum(&p, 0, &err);
if (err)
if (getnum(&p, NULL, FALSE, &n)) {
/*
* Line numbers start from 1.
*/
if (n == 0)
continue;
taglinenum = n;
}
else
{
/*
* No, it must be a pattern.
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -192,7 +192,7 @@ public int getchr(void)
do
{
flush();
#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
#if !LESS_IREAD_TTY
/*
* In raw read, we don't see ^C so look here for it.
*/
@@ -208,7 +208,7 @@ public int getchr(void)
result = 1;
if (c == '\003')
return (READ_INTR);
#else
#else /* LESS_IREAD_TTY */
{
unsigned char uc;
result = iread(tty, &uc, sizeof(char));
@@ -274,5 +274,5 @@ public int getchr(void)
c = '\340';
} while (result != 1);
return (c & 0xFF);
return (unsigned char) c;
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f2 Cc Cs Co Zl Zp -- unicode/UnicodeData.txt" on Aug 19 1:16:32 GMT 2025 */
/* Generated by "./mkutable -f2 Cc Cs Co Zl Zp -- unicode/UnicodeData.txt" on Nov 28 1:30:13 GMT 2025 */
{ 0x0000, 0x0007 }, /* Cc */
{ 0x000b, 0x000b }, /* Cc */
{ 0x000e, 0x001f }, /* Cc */
+52 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 1984-2025 Mark Nudelman
* Copyright (C) 1984-2026 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.
@@ -1061,6 +1061,56 @@ 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.
v686 10/30/25 Map keypad keys; make HOME/END scroll horizontally;
retain saved marks even if --save-marks is not specified;
fix repaint bug with --form-feed; fix bugs passing negative
values to cmd line options.
v687 11/17/25 Disallow opening OSC8 link via mouse in secure mode;
add --autosave; make SIGHUP act like SIGTERM; add ESC-f.
v688 11/28/25 Add LESSNOCONFIG; defer "ti" until first char received;
don't auto-bold line numbers.
v689 12/27/25 Add prompt seqs %C, %W, %Q, ?Q; don't allow any command to
interrupt waiting for data; fix screen resize on Windows;
add --without-termlib.
v690 12/31/25 Cleanup.
v691 1/10/26 Fix mingw build.
v692 1/29/26 Fix memory leak in setupterm; clear termio ICRNL|INLCR;
fix bug with negative value in -z; fix bug with empty
terminfo caps; make lesstest ignore nl_langinfo;
revert HOME/END to g/G; add keys & cmds to lesskey parser.
v693 2/14/26 Fix binary file with redirected stdout; fix error messages
with redirected stdout; fix buffer overrun with malformed
lesskey file; fix bad scrolling past EOF; fix command
parser bugs; fix -D bug when no color specified; add -DT;
make -w/-W hilite on backward movement; show pattern in
"not found" message.
v694 3/24/26 | cmd pipes 1 line if mark is top line; allow numeric arg
on m/M cmds; support POSIX char classes with built-in regex;
don't retry read after error; fix crash with bad tags file;
add --past-eof; add --emouse; fix restore mark if not at top;
don't save cleared marks.
v695 4/3/26 Fix build if tparm doesn't use varargs; fix prompt overflow
with & filtering; fix hilite when change -i with & filtering;
add --end-prompt; install lessecho in libexecdir; change mark
cmds to take file line number not screen line; add numeric
arg to ' cmd; add %O and ?o to prompts; fix
--show-preproc-error with some shells.
v696 4/3/26 Doc.
v697 4/19/26 Fix bug using PCRE2 with more than 5 parentheses; discard
pending keys when interrupt with ^X; fix bad display with
LESS_LINES.
v698 4/23/26 Fix bad display after message in narrow terminal; replace
LESS_OSC8_xxx with LESS_OSC8_OPEN_xxx; add \kpe to lesskey.
v699 4/23/26 Add less-osc8-*.bash files to distribution.
v700 4/30/26 Add \kpe to lesskey; improve less-osc8-* scripts.
v701 5/13/26 Replace less-osc-*.bash with less-osc8-open.sh; don't init
terminal if stdout is not tty; fix bug clicking OSC 8 link
in a long line; fix misread chars on Windows; remove %O.
v702 5/22/26 Doc.
v703 5/30/26 Fix handling unsafe man options in OSC 8 link; fix unsafe
handling of unterminated OSC seq; shell-escape expansion
of % and #.
v704 5/30/26 Fix uninstall target in Makefile.
*/
char version[] = "685";
char version[] = "704";
+12 -11
View File
@@ -1,4 +1,4 @@
/* Generated by "./mkutable -f1 W F -- unicode/EastAsianWidth.txt" on Aug 10 20:15:03 GMT 2025 */
/* Generated by "./mkutable -f1 W F -- unicode/EastAsianWidth.txt" on Nov 28 1:30:13 GMT 2025 */
{ 0x1100, 0x115f }, /* W */
{ 0x231a, 0x231b }, /* W */
{ 0x2329, 0x232a }, /* W */
@@ -61,10 +61,10 @@
{ 0xff01, 0xff60 }, /* F */
{ 0xffe0, 0xffe6 }, /* F */
{ 0x16fe0, 0x16fe4 }, /* W */
{ 0x16ff0, 0x16ff1 }, /* W */
{ 0x17000, 0x187f7 }, /* W */
{ 0x18800, 0x18cd5 }, /* W */
{ 0x18cff, 0x18d08 }, /* W */
{ 0x16ff0, 0x16ff6 }, /* W */
{ 0x17000, 0x18cd5 }, /* W */
{ 0x18cff, 0x18d1e }, /* W */
{ 0x18d80, 0x18df2 }, /* W */
{ 0x1aff0, 0x1aff3 }, /* W */
{ 0x1aff5, 0x1affb }, /* W */
{ 0x1affd, 0x1affe }, /* W */
@@ -107,7 +107,7 @@
{ 0x1f680, 0x1f6c5 }, /* W */
{ 0x1f6cc, 0x1f6cc }, /* W */
{ 0x1f6d0, 0x1f6d2 }, /* W */
{ 0x1f6d5, 0x1f6d7 }, /* W */
{ 0x1f6d5, 0x1f6d8 }, /* W */
{ 0x1f6dc, 0x1f6df }, /* W */
{ 0x1f6eb, 0x1f6ec }, /* W */
{ 0x1f6f4, 0x1f6fc }, /* W */
@@ -118,10 +118,11 @@
{ 0x1f947, 0x1f9af }, /* W */
{ 0x1f9b4, 0x1f9ff }, /* W */
{ 0x1fa70, 0x1fa7c }, /* W */
{ 0x1fa80, 0x1fa89 }, /* W */
{ 0x1fa8f, 0x1fac6 }, /* W */
{ 0x1face, 0x1fadc }, /* W */
{ 0x1fadf, 0x1fae9 }, /* W */
{ 0x1faf0, 0x1faf8 }, /* W */
{ 0x1fa80, 0x1fa8a }, /* W */
{ 0x1fa8e, 0x1fac6 }, /* W */
{ 0x1fac8, 0x1fac8 }, /* W */
{ 0x1facd, 0x1fadc }, /* W */
{ 0x1fadf, 0x1faea }, /* W */
{ 0x1faef, 0x1faf8 }, /* W */
{ 0x20000, 0x2fffd }, /* W */
{ 0x30000, 0x3fffd }, /* W */
+11 -1
View File
@@ -1,3 +1,12 @@
/*
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
*
* For more information, see the README file.
*/
#include "less.h"
#include "xbuf.h"
@@ -66,8 +75,9 @@ public void xbuf_add_char(struct xbuffer *xbuf, char c)
/*
* Add arbitrary data to an xbuf.
*/
public void xbuf_add_data(struct xbuffer *xbuf, constant unsigned char *data, size_t len)
public void xbuf_add_data(struct xbuffer *xbuf, constant void *vdata, size_t len)
{
constant unsigned char *data = (constant unsigned char *) vdata;
size_t i;
for (i = 0; i < len; i++)
xbuf_add_byte(xbuf, data[i]);
+10 -1
View File
@@ -1,3 +1,12 @@
/*
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
*
* For more information, see the README file.
*/
#ifndef XBUF_H_
#define XBUF_H_
@@ -17,7 +26,7 @@ void xbuf_deinit(struct xbuffer *xbuf);
void xbuf_reset(struct xbuffer *xbuf);
void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b);
void xbuf_add_char(struct xbuffer *xbuf, char c);
void xbuf_add_data(struct xbuffer *xbuf, constant unsigned char *data, size_t len);
void xbuf_add_data(struct xbuffer *xbuf, constant void *data, size_t len);
int xbuf_pop(struct xbuffer *xbuf);
constant char *xbuf_char_data(constant struct xbuffer *xbuf);
+1 -1
View File
@@ -10,7 +10,7 @@ Unbound is a validating, recursive, caching DNS resolver. It is designed to be
fast and lean and incorporates modern features based on open standards. If you
have any feedback, we would love to hear from you. Don’t hesitate to
[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
or post a message on our [community forum](https://community.nlnetlabs.nl/).
You can learn more about Unbound by reading our
[documentation](https://unbound.docs.nlnetlabs.nl/).
+17 -2
View File
@@ -87,7 +87,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 31
#serial 32
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
@@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes"],
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
solaris*)
# Solaris 11.4 introduced XPG7 support and did away with the need for
# _REENTRANT.
AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT],
[
# undef _XOPEN_SOURCE
# include <sys/feature_tests.h>
# if _XOPEN_VERSION < 700
AX_PTHREAD_SOLARIS__REENTRANT
# endif
],
[ax_pthread_check_macro="_REENTRANT"],
[ax_pthread_check_macro="--"])
;;
darwin* | hpux* | linux* | osf*)
ax_pthread_check_macro="_REENTRANT"
;;
+11
View File
@@ -401,6 +401,12 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
LDNS_RCODE_YXDOMAIN)
return 0;
/* Do not persist data the validator has not yet seen, or has rejected.
* Otherwise an expired blob could maybe reach clients via
* serve-expired. */
if(qstate->env->need_to_validate &&
qstate->return_msg->rep->security == sec_status_bogus)
return 0;
/* We don't store the reply if its TTL is 0. This is probably coming
* from upstream and it is not meant to be stored. */
if(qstate->return_msg->rep->ttl == 0)
@@ -863,6 +869,11 @@ cachedb_handle_query(struct module_qstate* qstate,
return;
}
/* No 0TTL answers escaping from external cache. */
if(qstate->return_msg->rep->ttl == 0) {
qstate->return_msg = NULL;
qstate->ext_state[id] = module_wait_module;
return;
}
log_assert(qstate->return_msg->rep->ttl > 0);
qstate->is_cachedb_answer = 1;
/* we are done with the query */
+9 -382
View File
@@ -20,398 +20,25 @@
* http://man.openbsd.org/getentropy.2
*/
#include <TargetConditionals.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/statvfs.h>
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
/* Modified to use SecRandomCopyBytes. It is from macOS 10.7 (2011) and
* iOS 2.0 (2008), and is the primary API for cryptographic random numbers. */
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <mach/mach_time.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#if TARGET_OS_OSX
#include <sys/socketvar.h>
#include <sys/vmmeter.h>
#endif
#include <netinet/in.h>
#include <netinet/tcp.h>
#if TARGET_OS_OSX
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp_var.h>
#include <netinet/udp_var.h>
#endif
#include <CommonCrypto/CommonDigest.h>
#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c)))
#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
#define SHA512_CTX CC_SHA512_CTX
#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
#define REPEAT 5
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define HX(a, b) \
do { \
if ((a)) \
HD(errno); \
else \
HD(b); \
} while (0)
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
#include <Security/SecRandom.h>
int getentropy(void *buf, size_t len);
static int getentropy_urandom(void *buf, size_t len);
static int getentropy_fallback(void *buf, size_t len);
int
getentropy(void *buf, size_t len)
{
int ret = -1;
if (len > 256) {
errno = EIO;
return (-1);
goto error;
}
/*
* Try to get entropy with /dev/urandom
*
* This can fail if the process is inside a chroot or if file
* descriptors are exhausted.
*/
ret = getentropy_urandom(buf, len);
if (ret != -1)
return (ret);
/*
* Entropy collection via /dev/urandom and sysctl have failed.
*
* No other API exists for collecting entropy, and we have
* no failsafe way to get it on OSX that is not sensitive
* to resource exhaustion.
*
* We have very few options:
* - Even syslog_r is unsafe to call at this low level, so
* there is no way to alert the user or program.
* - Cannot call abort() because some systems have unsafe
* corefiles.
* - Could raise(SIGKILL) resulting in silent program termination.
* - Return EIO, to hint that arc4random's stir function
* should raise(SIGKILL)
* - Do the best under the circumstances....
*
* This code path exists to bring light to the issue that OSX
* does not provide a failsafe API for entropy collection.
*
* We hope this demonstrates that OSX should consider
* providing a new failsafe API which works in a chroot or
* when file descriptors are exhausted.
*/
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
raise(SIGKILL);
#endif
ret = getentropy_fallback(buf, len);
if (ret != -1)
return (ret);
if (SecRandomCopyBytes(kSecRandomDefault, len, buf) == errSecSuccess) {
return 0;
}
error:
errno = EIO;
return (ret);
}
static int
getentropy_urandom(void *buf, size_t len)
{
struct stat st;
size_t i;
int fd, flags;
int save_errno = errno;
start:
flags = O_RDONLY;
#ifdef O_NOFOLLOW
flags |= O_NOFOLLOW;
#endif
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
fd = open("/dev/urandom", flags, 0);
if (fd == -1) {
if (errno == EINTR)
goto start;
goto nodevrandom;
}
#ifndef O_CLOEXEC
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
#endif
/* Lightly verify that the device node looks sane */
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
close(fd);
goto nodevrandom;
}
for (i = 0; i < len; ) {
size_t wanted = len - i;
ssize_t ret = read(fd, (char *)buf + i, wanted);
if (ret == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
close(fd);
goto nodevrandom;
}
i += ret;
}
close(fd);
errno = save_errno;
return (0); /* satisfied */
nodevrandom:
errno = EIO;
return (-1);
}
#if TARGET_OS_OSX
static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
#endif
static int kmib[] = { CTL_KERN, KERN_USRSTACK };
static int hwmib[] = { CTL_HW, HW_USERMEM };
static int
getentropy_fallback(void *buf, size_t len)
{
uint8_t results[SHA512_DIGEST_LENGTH];
int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
static int cnt;
struct timespec ts;
struct timeval tv;
struct rusage ru;
sigset_t sigset;
struct stat st;
SHA512_CTX ctx;
static pid_t lastpid;
pid_t pid;
size_t i, ii, m;
char *p;
#if TARGET_OS_OSX
struct tcpstat tcpstat;
struct udpstat udpstat;
struct ipstat ipstat;
#endif
u_int64_t mach_time;
unsigned int idata;
void *addr;
pid = getpid();
if (lastpid == pid) {
faster = 1;
repeat = 2;
} else {
faster = 0;
lastpid = pid;
repeat = REPEAT;
}
for (i = 0; i < len; ) {
int j;
SHA512_Init(&ctx);
for (j = 0; j < repeat; j++) {
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
if (e != -1) {
cnt += (int)tv.tv_sec;
cnt += (int)tv.tv_usec;
}
mach_time = mach_absolute_time();
HD(mach_time);
ii = sizeof(addr);
HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
&addr, &ii, NULL, 0) == -1, addr);
ii = sizeof(idata);
HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
&idata, &ii, NULL, 0) == -1, idata);
#if TARGET_OS_OSX
ii = sizeof(tcpstat);
HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
&tcpstat, &ii, NULL, 0) == -1, tcpstat);
ii = sizeof(udpstat);
HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
&udpstat, &ii, NULL, 0) == -1, udpstat);
ii = sizeof(ipstat);
HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
&ipstat, &ii, NULL, 0) == -1, ipstat);
#endif
HX((pid = getpid()) == -1, pid);
HX((pid = getsid(pid)) == -1, pid);
HX((pid = getppid()) == -1, pid);
HX((pid = getpgid(0)) == -1, pid);
HX((e = getpriority(0, 0)) == -1, e);
if (!faster) {
ts.tv_sec = 0;
ts.tv_nsec = 1;
(void) nanosleep(&ts, NULL);
}
HX(sigpending(&sigset) == -1, sigset);
HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
sigset);
HF(getentropy); /* an addr in this library */
HF(printf); /* an addr in libc */
p = (char *)&p;
HD(p); /* an addr on stack */
p = (char *)&errno;
HD(p); /* the addr of errno */
if (i == 0) {
struct sockaddr_storage ss;
struct statvfs stvfs;
struct termios tios;
struct statfs stfs;
socklen_t ssl;
off_t off;
/*
* Prime-sized mappings encourage fragmentation;
* thus exposing some address entropy.
*/
struct mm {
size_t npg;
void *p;
} mm[] = {
{ 17, MAP_FAILED }, { 3, MAP_FAILED },
{ 11, MAP_FAILED }, { 2, MAP_FAILED },
{ 5, MAP_FAILED }, { 3, MAP_FAILED },
{ 7, MAP_FAILED }, { 1, MAP_FAILED },
{ 57, MAP_FAILED }, { 3, MAP_FAILED },
{ 131, MAP_FAILED }, { 1, MAP_FAILED },
};
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
HX(mm[m].p = mmap(NULL,
mm[m].npg * pgs,
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANON, -1,
(off_t)0), mm[m].p);
if (mm[m].p != MAP_FAILED) {
size_t mo;
/* Touch some memory... */
p = mm[m].p;
mo = cnt %
(mm[m].npg * pgs - 1);
p[mo] = 1;
cnt += (int)((long)(mm[m].p)
/ pgs);
}
/* Check cnts and times... */
mach_time = mach_absolute_time();
HD(mach_time);
cnt += (int)mach_time;
HX((e = getrusage(RUSAGE_SELF,
&ru)) == -1, ru);
if (e != -1) {
cnt += (int)ru.ru_utime.tv_sec;
cnt += (int)ru.ru_utime.tv_usec;
}
}
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
if (mm[m].p != MAP_FAILED)
munmap(mm[m].p, mm[m].npg * pgs);
mm[m].p = MAP_FAILED;
}
HX(stat(".", &st) == -1, st);
HX(statvfs(".", &stvfs) == -1, stvfs);
HX(statfs(".", &stfs) == -1, stfs);
HX(stat("/", &st) == -1, st);
HX(statvfs("/", &stvfs) == -1, stvfs);
HX(statfs("/", &stfs) == -1, stfs);
HX((e = fstat(0, &st)) == -1, st);
if (e == -1) {
if (S_ISREG(st.st_mode) ||
S_ISFIFO(st.st_mode) ||
S_ISSOCK(st.st_mode)) {
HX(fstatvfs(0, &stvfs) == -1,
stvfs);
HX(fstatfs(0, &stfs) == -1,
stfs);
HX((off = lseek(0, (off_t)0,
SEEK_CUR)) < 0, off);
}
if (S_ISCHR(st.st_mode)) {
HX(tcgetattr(0, &tios) == -1,
tios);
} else if (S_ISSOCK(st.st_mode)) {
memset(&ss, 0, sizeof ss);
ssl = sizeof(ss);
HX(getpeername(0,
(void *)&ss, &ssl) == -1,
ss);
}
}
HX((e = getrusage(RUSAGE_CHILDREN,
&ru)) == -1, ru);
if (e != -1) {
cnt += (int)ru.ru_utime.tv_sec;
cnt += (int)ru.ru_utime.tv_usec;
}
} else {
/* Subsequent hashes absorb previous result */
HD(results);
}
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
if (e != -1) {
cnt += (int)tv.tv_sec;
cnt += (int)tv.tv_usec;
}
HD(cnt);
}
SHA512_Final(results, &ctx);
memcpy((char *)buf + i, results, min(sizeof(results), len - i));
i += min(sizeof(results), len - i);
}
explicit_bzero(&ctx, sizeof ctx);
explicit_bzero(results, sizeof results);
errno = save_errno;
return (0); /* satisfied */
return -1;
}
+3 -10
View File
@@ -59,10 +59,7 @@ static int inet_pton6 (const char *src, uint8_t *dst);
* Paul Vixie, 1996.
*/
int
inet_pton(af, src, dst)
int af;
const char *src;
void *dst;
inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
@@ -91,9 +88,7 @@ inet_pton(af, src, dst)
* Paul Vixie, 1996.
*/
static int
inet_pton4(src, dst)
const char *src;
uint8_t *dst;
inet_pton4(const char *src, uint8_t *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
@@ -145,9 +140,7 @@ inet_pton4(src, dst)
* Paul Vixie, 1996.
*/
static int
inet_pton6(src, dst)
const char *src;
uint8_t *dst;
inet_pton6(const char *src, uint8_t *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
+9 -17
View File
@@ -1,10 +1,10 @@
#! /bin/sh
#!/usr/bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2026 Free Software Foundation, Inc.
# Copyright 1992-2024 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2026-05-17'
timestamp='2024-07-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2026 Free Software Foundation, Inc.
Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -150,7 +150,7 @@ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case $UNAME_SYSTEM in
Ironclad|Linux|GNU|GNU/*)
Linux|GNU|GNU/*)
LIBC=unknown
set_cc_for_build
@@ -167,8 +167,6 @@ Ironclad|Linux|GNU|GNU/*)
LIBC=gnu
#elif defined(__LLVM_LIBC__)
LIBC=llvm
#elif defined(__mlibc__)
LIBC=mlibc
#else
#include <stdarg.h>
/* First heuristic to detect musl libc. */
@@ -1188,9 +1186,6 @@ EOF
sparc:Linux:*:* | sparc64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
sw_64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
tile*:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
@@ -1602,11 +1597,8 @@ EOF
*:Unleashed:*:*)
GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
;;
x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*)
GUESS=$UNAME_MACHINE-pc-ironclad-$LIBC
;;
*:[Ii]ronclad:*:*)
GUESS=$UNAME_MACHINE-unknown-ironclad-$LIBC
*:Ironclad:*:*)
GUESS=$UNAME_MACHINE-unknown-ironclad
;;
esac
@@ -1816,8 +1808,8 @@ fi
exit 1
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%Y-%02m-%02d"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
+220 -178
View File
@@ -31,6 +31,9 @@
/* Whether daemon is deprecated */
#undef DEPRECATED_DAEMON
/* Whether X509_NAME_get_text_by_NID is deprecated */
#undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID
/* Deprecate RSA 1024 bit length, makes that an unsupported key */
#undef DEPRECATE_RSA_1024
@@ -48,18 +51,21 @@
internal symbols */
#undef EXPORT_ALL_SYMBOLS
/* Define to 1 if you have the `accept4' function. */
/* Define to 1 if you have the 'accept4' function. */
#undef HAVE_ACCEPT4
/* Define to 1 if you have the `arc4random' function. */
/* Define to 1 if you have the 'arc4random' function. */
#undef HAVE_ARC4RANDOM
/* Define to 1 if you have the `arc4random_uniform' function. */
/* Define to 1 if you have the 'arc4random_uniform' function. */
#undef HAVE_ARC4RANDOM_UNIFORM
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if you have the 'ASN1_STRING_get0_data' function. */
#undef HAVE_ASN1_STRING_GET0_DATA
/* Whether the C compiler accepts the "fallthrough" attribute */
#undef HAVE_ATTR_FALLTHROUGH
@@ -81,7 +87,7 @@
/* If we have be64toh */
#undef HAVE_BE64TOH
/* Define to 1 if you have the `BIO_set_callback_ex' function. */
/* Define to 1 if you have the 'BIO_set_callback_ex' function. */
#undef HAVE_BIO_SET_CALLBACK_EX
/* Define to 1 if you have the <bsd/stdlib.h> header file. */
@@ -90,245 +96,255 @@
/* Define to 1 if you have the <bsd/string.h> header file. */
#undef HAVE_BSD_STRING_H
/* Define to 1 if you have the `chown' function. */
/* Define to 1 if you have the 'chown' function. */
#undef HAVE_CHOWN
/* Define to 1 if you have the `chroot' function. */
/* Define to 1 if you have the 'chroot' function. */
#undef HAVE_CHROOT
/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
/* Define to 1 if you have the 'CRYPTO_cleanup_all_ex_data' function. */
#undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
/* Define to 1 if you have the `CRYPTO_THREADID_set_callback' function. */
/* Define to 1 if you have the 'CRYPTO_THREADID_set_callback' function. */
#undef HAVE_CRYPTO_THREADID_SET_CALLBACK
/* Define to 1 if you have the `ctime_r' function. */
/* Define to 1 if you have the 'ctime_r' function. */
#undef HAVE_CTIME_R
/* Define to 1 if you have the `daemon' function. */
/* Define to 1 if you have the 'daemon' function. */
#undef HAVE_DAEMON
/* Define to 1 if you have the declaration of `arc4random', and to 0 if you
/* Define to 1 if you have the declaration of 'arc4random', and to 0 if you
don't. */
#undef HAVE_DECL_ARC4RANDOM
/* Define to 1 if you have the declaration of `arc4random_uniform', and to 0
/* Define to 1 if you have the declaration of 'arc4random_uniform', and to 0
if you don't. */
#undef HAVE_DECL_ARC4RANDOM_UNIFORM
/* Define to 1 if you have the declaration of `evsignal_assign', and to 0 if
/* Define to 1 if you have the declaration of 'evsignal_assign', and to 0 if
you don't. */
#undef HAVE_DECL_EVSIGNAL_ASSIGN
/* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you
/* Define to 1 if you have the declaration of 'inet_ntop', and to 0 if you
don't. */
#undef HAVE_DECL_INET_NTOP
/* Define to 1 if you have the declaration of `inet_pton', and to 0 if you
/* Define to 1 if you have the declaration of 'inet_pton', and to 0 if you
don't. */
#undef HAVE_DECL_INET_PTON
/* Define to 1 if you have the declaration of `nghttp2_session_server_new',
/* Define to 1 if you have the declaration of 'nghttp2_session_server_new',
and to 0 if you don't. */
#undef HAVE_DECL_NGHTTP2_SESSION_SERVER_NEW
/* Define to 1 if you have the declaration of `ngtcp2_conn_server_new', and to
/* Define to 1 if you have the declaration of 'ngtcp2_conn_server_new', and to
0 if you don't. */
#undef HAVE_DECL_NGTCP2_CONN_SERVER_NEW
/* Define to 1 if you have the declaration of `ngtcp2_crypto_encrypt_cb', and
/* Define to 1 if you have the declaration of 'ngtcp2_crypto_encrypt_cb', and
to 0 if you don't. */
#undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB
/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
/* Define to 1 if you have the declaration of 'ngtcp2_crypto_ossl_ctx_new',
and to 0 if you don't. */
#undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW
/* Define to 1 if you have the declaration of 'NID_ED25519', and to 0 if you
don't. */
#undef HAVE_DECL_NID_ED25519
/* Define to 1 if you have the declaration of `NID_ED448', and to 0 if you
/* Define to 1 if you have the declaration of 'NID_ED448', and to 0 if you
don't. */
#undef HAVE_DECL_NID_ED448
/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you
/* Define to 1 if you have the declaration of 'NID_secp384r1', and to 0 if you
don't. */
#undef HAVE_DECL_NID_SECP384R1
/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0
/* Define to 1 if you have the declaration of 'NID_X9_62_prime256v1', and to 0
if you don't. */
#undef HAVE_DECL_NID_X9_62_PRIME256V1
/* Define to 1 if you have the declaration of `reallocarray', and to 0 if you
/* Define to 1 if you have the declaration of 'reallocarray', and to 0 if you
don't. */
#undef HAVE_DECL_REALLOCARRAY
/* Define to 1 if you have the declaration of `redisConnect', and to 0 if you
/* Define to 1 if you have the declaration of 'redisConnect', and to 0 if you
don't. */
#undef HAVE_DECL_REDISCONNECT
/* Define to 1 if you have the declaration of `sk_SSL_COMP_pop_free', and to 0
/* Define to 1 if you have the declaration of 'sk_SSL_COMP_pop_free', and to 0
if you don't. */
#undef HAVE_DECL_SK_SSL_COMP_POP_FREE
/* Define to 1 if you have the declaration of
`SSL_COMP_get_compression_methods', and to 0 if you don't. */
'SSL_COMP_get_compression_methods', and to 0 if you don't. */
#undef HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
/* Define to 1 if you have the declaration of `SSL_CTX_set_ecdh_auto', and to
/* Define to 1 if you have the declaration of 'SSL_CTX_set_ecdh_auto', and to
0 if you don't. */
#undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
/* Define to 1 if you have the declaration of `SSL_CTX_set_tmp_ecdh', and to 0
/* Define to 1 if you have the declaration of 'SSL_CTX_set_tmp_ecdh', and to 0
if you don't. */
#undef HAVE_DECL_SSL_CTX_SET_TMP_ECDH
/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
/* Define to 1 if you have the declaration of 'strlcat', and to 0 if you
don't. */
#undef HAVE_DECL_STRLCAT
/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
/* Define to 1 if you have the declaration of 'strlcpy', and to 0 if you
don't. */
#undef HAVE_DECL_STRLCPY
/* Define to 1 if you have the declaration of `XML_StopParser', and to 0 if
/* Define to 1 if you have the declaration of 'XML_StopParser', and to 0 if
you don't. */
#undef HAVE_DECL_XML_STOPPARSER
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the `DSA_SIG_set0' function. */
/* Define to 1 if you have the 'DSA_SIG_set0' function. */
#undef HAVE_DSA_SIG_SET0
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 if you have the `endprotoent' function. */
/* Define to 1 if you have the 'endprotoent' function. */
#undef HAVE_ENDPROTOENT
/* Define to 1 if you have the `endpwent' function. */
/* Define to 1 if you have the 'endpwent' function. */
#undef HAVE_ENDPWENT
/* Define to 1 if you have the `endservent' function. */
/* Define to 1 if you have the 'endservent' function. */
#undef HAVE_ENDSERVENT
/* Define to 1 if you have the `ENGINE_cleanup' function. */
/* Define to 1 if you have the 'ENGINE_cleanup' function. */
#undef HAVE_ENGINE_CLEANUP
/* Define to 1 if you have the `ERR_free_strings' function. */
/* Define to 1 if you have the 'ERR_free_strings' function. */
#undef HAVE_ERR_FREE_STRINGS
/* Define to 1 if you have the `ERR_load_crypto_strings' function. */
/* Define to 1 if you have the 'ERR_load_crypto_strings' function. */
#undef HAVE_ERR_LOAD_CRYPTO_STRINGS
/* Define to 1 if you have the `event_assign' function. */
/* Define to 1 if you have the 'event_assign' function. */
#undef HAVE_EVENT_ASSIGN
/* Define to 1 if you have the `event_base_free' function. */
/* Define to 1 if you have the 'event_base_free' function. */
#undef HAVE_EVENT_BASE_FREE
/* Define to 1 if you have the `event_base_get_method' function. */
/* Define to 1 if you have the 'event_base_get_method' function. */
#undef HAVE_EVENT_BASE_GET_METHOD
/* Define to 1 if you have the `event_base_new' function. */
/* Define to 1 if you have the 'event_base_new' function. */
#undef HAVE_EVENT_BASE_NEW
/* Define to 1 if you have the `event_base_once' function. */
/* Define to 1 if you have the 'event_base_once' function. */
#undef HAVE_EVENT_BASE_ONCE
/* Define to 1 if you have the <event.h> header file. */
#undef HAVE_EVENT_H
/* Define to 1 if you have the `EVP_aes_256_cbc' function. */
/* Define to 1 if you have the 'EVP_aes_256_cbc' function. */
#undef HAVE_EVP_AES_256_CBC
/* Define to 1 if you have the `EVP_cleanup' function. */
/* Define to 1 if you have the 'EVP_cleanup' function. */
#undef HAVE_EVP_CLEANUP
/* Define to 1 if you have the `EVP_default_properties_is_fips_enabled'
/* Define to 1 if you have the 'EVP_default_properties_is_fips_enabled'
function. */
#undef HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED
/* Define to 1 if you have the `EVP_DigestVerify' function. */
/* Define to 1 if you have the 'EVP_DigestVerify' function. */
#undef HAVE_EVP_DIGESTVERIFY
/* Define to 1 if you have the `EVP_dss1' function. */
/* Define to 1 if you have the 'EVP_dss1' function. */
#undef HAVE_EVP_DSS1
/* Define to 1 if you have the `EVP_EncryptInit_ex' function. */
/* Define to 1 if you have the 'EVP_EncryptInit_ex' function. */
#undef HAVE_EVP_ENCRYPTINIT_EX
/* Define to 1 if you have the `EVP_MAC_CTX_set_params' function. */
/* Define to 1 if you have the 'EVP_MAC_CTX_set_params' function. */
#undef HAVE_EVP_MAC_CTX_SET_PARAMS
/* Define to 1 if you have the `EVP_MD_CTX_new' function. */
/* Define to 1 if you have the 'EVP_MD_CTX_new' function. */
#undef HAVE_EVP_MD_CTX_NEW
/* Define to 1 if you have the `EVP_sha1' function. */
/* Define to 1 if you have the 'EVP_sha1' function. */
#undef HAVE_EVP_SHA1
/* Define to 1 if you have the `EVP_sha256' function. */
/* Define to 1 if you have the 'EVP_sha256' function. */
#undef HAVE_EVP_SHA256
/* Define to 1 if you have the `EVP_sha512' function. */
/* Define to 1 if you have the 'EVP_sha512' function. */
#undef HAVE_EVP_SHA512
/* Define to 1 if you have the `ev_default_loop' function. */
/* Define to 1 if you have the 'ev_default_loop' function. */
#undef HAVE_EV_DEFAULT_LOOP
/* Define to 1 if you have the `ev_loop' function. */
/* Define to 1 if you have the 'ev_loop' function. */
#undef HAVE_EV_LOOP
/* Define to 1 if you have the <expat.h> header file. */
#undef HAVE_EXPAT_H
/* Define to 1 if you have the `explicit_bzero' function. */
/* Define to 1 if you have the 'explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `fcntl' function. */
/* Define to 1 if you have the 'fcntl' function. */
#undef HAVE_FCNTL
/* Define to 1 if you have the `FIPS_mode' function. */
/* Define to 1 if you have the 'FIPS_mode' function. */
#undef HAVE_FIPS_MODE
/* Define to 1 if you have the `fork' function. */
/* Define to 1 if you have the 'fnmatch' function. */
#undef HAVE_FNMATCH
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the 'fork' function. */
#undef HAVE_FORK
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
/* Define to 1 if fseeko (and ftello) are declared in stdio.h. */
#undef HAVE_FSEEKO
/* Define to 1 if you have the `fsync' function. */
/* Define to 1 if you have the 'fsync' function. */
#undef HAVE_FSYNC
/* Whether getaddrinfo is available */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getauxval' function. */
/* Define to 1 if you have the 'getauxval' function. */
#undef HAVE_GETAUXVAL
/* Define to 1 if you have the `getentropy' function. */
/* Define to 1 if you have the 'getentropy' function. */
#undef HAVE_GETENTROPY
/* Define to 1 if you have the `getifaddrs' function. */
/* Define to 1 if you have the 'getifaddrs' function. */
#undef HAVE_GETIFADDRS
/* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H
/* Define to 1 if you have the `getpwnam' function. */
/* Define to 1 if you have the 'getpwnam' function. */
#undef HAVE_GETPWNAM
/* Define to 1 if you have the `getrlimit' function. */
/* Define to 1 if you have the 'getrlimit' function. */
#undef HAVE_GETRLIMIT
/* Define to 1 if you have the `gettid' function. */
/* Define to 1 if you have the 'gettid' function. */
#undef HAVE_GETTID
/* Define to 1 if you have the `glob' function. */
/* Define to 1 if you have the 'glob' function. */
#undef HAVE_GLOB
/* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H
/* Define to 1 if you have the `gmtime_r' function. */
/* Define to 1 if you have the 'gmtime_r' function. */
#undef HAVE_GMTIME_R
/* Define to 1 if you have the <grp.h> header file. */
@@ -337,7 +353,7 @@
/* Define to 1 if you have the <hiredis/hiredis.h> header file. */
#undef HAVE_HIREDIS_HIREDIS_H
/* Define to 1 if you have the `HMAC_Init_ex' function. */
/* Define to 1 if you have the 'HMAC_Init_ex' function. */
#undef HAVE_HMAC_INIT_EX
/* If we have htobe64 */
@@ -346,19 +362,19 @@
/* Define to 1 if you have the <ifaddrs.h> header file. */
#undef HAVE_IFADDRS_H
/* Define to 1 if you have the `if_nametoindex' function. */
/* Define to 1 if you have the 'if_nametoindex' function. */
#undef HAVE_IF_NAMETOINDEX
/* Define to 1 if you have the `inet_aton' function. */
/* Define to 1 if you have the 'inet_aton' function. */
#undef HAVE_INET_ATON
/* Define to 1 if you have the `inet_ntop' function. */
/* Define to 1 if you have the 'inet_ntop' function. */
#undef HAVE_INET_NTOP
/* Define to 1 if you have the `inet_pton' function. */
/* Define to 1 if you have the 'inet_pton' function. */
#undef HAVE_INET_PTON
/* Define to 1 if you have the `initgroups' function. */
/* Define to 1 if you have the 'initgroups' function. */
#undef HAVE_INITGROUPS
/* Define to 1 if you have the <inttypes.h> header file. */
@@ -370,10 +386,10 @@
/* Define to 1 if you have the <iphlpapi.h> header file. */
#undef HAVE_IPHLPAPI_H
/* Define to 1 if you have the `isblank' function. */
/* Define to 1 if you have the 'isblank' function. */
#undef HAVE_ISBLANK
/* Define to 1 if you have the `kill' function. */
/* Define to 1 if you have the 'kill' function. */
#undef HAVE_KILL
/* Use portable libbsd functions */
@@ -391,7 +407,7 @@
/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
#undef HAVE_LINUX_NET_TSTAMP_H
/* Define to 1 if you have the `localtime_r' function. */
/* Define to 1 if you have the 'localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define to 1 if you have the <login_cap.h> header file. */
@@ -400,7 +416,7 @@
/* If have GNU libc compatible malloc */
#undef HAVE_MALLOC
/* Define to 1 if you have the `memmove' function. */
/* Define to 1 if you have the 'memmove' function. */
#undef HAVE_MEMMOVE
/* Define to 1 if you have the <minix/config.h> header file. */
@@ -442,52 +458,52 @@
/* Define this to use ngtcp2. */
#undef HAVE_NGTCP2
/* Define to 1 if you have the `ngtcp2_ccerr_default' function. */
/* Define to 1 if you have the 'ngtcp2_ccerr_default' function. */
#undef HAVE_NGTCP2_CCERR_DEFAULT
/* Define to 1 if you have the `ngtcp2_conn_encode_0rtt_transport_params'
/* Define to 1 if you have the 'ngtcp2_conn_encode_0rtt_transport_params'
function. */
#undef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS
/* Define to 1 if you have the `ngtcp2_conn_get_max_local_streams_uni'
/* Define to 1 if you have the 'ngtcp2_conn_get_max_local_streams_uni'
function. */
#undef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI
/* Define to 1 if you have the `ngtcp2_conn_get_num_scid' function. */
/* Define to 1 if you have the 'ngtcp2_conn_get_num_scid' function. */
#undef HAVE_NGTCP2_CONN_GET_NUM_SCID
/* Define to 1 if you have the `ngtcp2_conn_in_closing_period' function. */
/* Define to 1 if you have the 'ngtcp2_conn_in_closing_period' function. */
#undef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
/* Define to 1 if you have the `ngtcp2_conn_in_draining_period' function. */
/* Define to 1 if you have the 'ngtcp2_conn_in_draining_period' function. */
#undef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD
/* Define if ngtcp2_conn_shutdown_stream has 4 arguments. */
#undef HAVE_NGTCP2_CONN_SHUTDOWN_STREAM4
/* Define to 1 if you have the `ngtcp2_conn_tls_early_data_rejected' function.
/* Define to 1 if you have the 'ngtcp2_conn_tls_early_data_rejected' function.
*/
#undef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED
/* Define to 1 if you have the `ngtcp2_crypto_encrypt_cb' function. */
/* Define to 1 if you have the 'ngtcp2_crypto_encrypt_cb' function. */
#undef HAVE_NGTCP2_CRYPTO_ENCRYPT_CB
/* Define to 1 if you have the
`ngtcp2_crypto_quictls_configure_client_context' function. */
'ngtcp2_crypto_quictls_configure_client_context' function. */
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
/* Define to 1 if you have the
`ngtcp2_crypto_quictls_configure_server_context' function. */
'ngtcp2_crypto_quictls_configure_server_context' function. */
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT
/* Define to 1 if you have the
`ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */
'ngtcp2_crypto_quictls_from_ossl_encryption_level' function. */
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL
/* Define to 1 if you have the `ngtcp2_crypto_quictls_init' function. */
/* Define to 1 if you have the 'ngtcp2_crypto_quictls_init' function. */
#undef HAVE_NGTCP2_CRYPTO_QUICTLS_INIT
/* Define to 1 if the system has the type `ngtcp2_encryption_level'. */
/* Define to 1 if the system has the type 'ngtcp2_encryption_level'. */
#undef HAVE_NGTCP2_ENCRYPTION_LEVEL
/* Define to 1 if you have the <ngtcp2/ngtcp2_crypto_openssl.h> header file.
@@ -507,13 +523,16 @@
/* Use libnss for crypto */
#undef HAVE_NSS
/* Define to 1 if you have the `OpenSSL_add_all_digests' function. */
/* Define to 1 if you have the 'OpenSSL_add_all_digests' function. */
#undef HAVE_OPENSSL_ADD_ALL_DIGESTS
/* Define to 1 if you have the <openssl/bn.h> header file. */
#undef HAVE_OPENSSL_BN_H
/* Define to 1 if you have the `OPENSSL_config' function. */
/* Define to 1 if you have the 'OPENSSL_cleanup' function. */
#undef HAVE_OPENSSL_CLEANUP
/* Define to 1 if you have the 'OPENSSL_config' function. */
#undef HAVE_OPENSSL_CONFIG
/* Define to 1 if you have the <openssl/conf.h> header file. */
@@ -534,10 +553,10 @@
/* Define to 1 if you have the <openssl/err.h> header file. */
#undef HAVE_OPENSSL_ERR_H
/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
/* Define to 1 if you have the 'OPENSSL_init_crypto' function. */
#undef HAVE_OPENSSL_INIT_CRYPTO
/* Define to 1 if you have the `OPENSSL_init_ssl' function. */
/* Define to 1 if you have the 'OPENSSL_init_ssl' function. */
#undef HAVE_OPENSSL_INIT_SSL
/* Define to 1 if you have the <openssl/param_build.h> header file. */
@@ -552,10 +571,10 @@
/* Define to 1 if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H
/* Define to 1 if you have the `OSSL_PARAM_BLD_new' function. */
/* Define to 1 if you have the 'OSSL_PARAM_BLD_new' function. */
#undef HAVE_OSSL_PARAM_BLD_NEW
/* Define to 1 if you have the `poll' function. */
/* Define to 1 if you have the 'poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
@@ -570,7 +589,7 @@
/* Have PTHREAD_PRIO_INHERIT. */
#undef HAVE_PTHREAD_PRIO_INHERIT
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
/* Define to 1 if the system has the type 'pthread_rwlock_t'. */
#undef HAVE_PTHREAD_RWLOCK_T
/* Define if pthread_setname_np has the common 2 arguments. */
@@ -585,7 +604,7 @@
/* Define if pthread_setname_np exists as pthread_set_name_np instead. */
#undef HAVE_PTHREAD_SET_NAME_NP
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
/* Define to 1 if the system has the type 'pthread_spinlock_t'. */
#undef HAVE_PTHREAD_SPINLOCK_T
/* Define to 1 if you have the <pwd.h> header file. */
@@ -594,100 +613,107 @@
/* Define if you have Python libraries and header files. */
#undef HAVE_PYTHON
/* Define to 1 if you have the `random' function. */
/* Define to 1 if you have the 'random' function. */
#undef HAVE_RANDOM
/* Define to 1 if you have the `RAND_cleanup' function. */
/* Define to 1 if you have the 'RAND_cleanup' function. */
#undef HAVE_RAND_CLEANUP
/* If we have reallocarray(3) */
#undef HAVE_REALLOCARRAY
/* Define to 1 if you have the `recvmsg' function. */
/* Define to 1 if you have the 'recvmsg' function. */
#undef HAVE_RECVMSG
/* Define to 1 if you have the `sendmsg' function. */
/* Define to 1 if you have the 'sendmsg' function. */
#undef HAVE_SENDMSG
/* Define to 1 if you have the `setregid' function. */
/* Define to 1 if you have the 'setregid' function. */
#undef HAVE_SETREGID
/* Define to 1 if you have the `setresgid' function. */
/* Define to 1 if you have the 'setresgid' function. */
#undef HAVE_SETRESGID
/* Define to 1 if you have the `setresuid' function. */
/* Define to 1 if you have the 'setresuid' function. */
#undef HAVE_SETRESUID
/* Define to 1 if you have the `setreuid' function. */
/* Define to 1 if you have the 'setreuid' function. */
#undef HAVE_SETREUID
/* Define to 1 if you have the `setrlimit' function. */
/* Define to 1 if you have the 'setrlimit' function. */
#undef HAVE_SETRLIMIT
/* Define to 1 if you have the `setsid' function. */
/* Define to 1 if you have the 'setsid' function. */
#undef HAVE_SETSID
/* Define to 1 if you have the `setusercontext' function. */
/* Define to 1 if you have the 'setusercontext' function. */
#undef HAVE_SETUSERCONTEXT
/* Define to 1 if you have the `SHA512_Update' function. */
/* Define to 1 if you have the 'SHA512_Update' function. */
#undef HAVE_SHA512_UPDATE
/* Define to 1 if you have the `shmget' function. */
/* Define to 1 if you have the 'shmget' function. */
#undef HAVE_SHMGET
/* Define to 1 if you have the `sigprocmask' function. */
/* Define to 1 if you have the 'sigprocmask' function. */
#undef HAVE_SIGPROCMASK
/* Define to 1 if you have the `sleep' function. */
/* Define to 1 if you have the 'sleep' function. */
#undef HAVE_SLEEP
/* Define to 1 if you have the `snprintf' function. */
/* Define to 1 if you have the 'snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the `socketpair' function. */
/* Define to 1 if you have the 'socketpair' function. */
#undef HAVE_SOCKETPAIR
/* Using Solaris threads */
#undef HAVE_SOLARIS_THREADS
/* Define to 1 if you have the `srandom' function. */
/* Define to 1 if you have the 'srandom' function. */
#undef HAVE_SRANDOM
/* Define if you have the SSL libraries installed. */
#undef HAVE_SSL
/* Define to 1 if you have the `SSL_CTX_set_alpn_protos' function. */
/* Define to 1 if you have the 'SSL_CTX_set_alpn_protos' function. */
#undef HAVE_SSL_CTX_SET_ALPN_PROTOS
/* Define to 1 if you have the `SSL_CTX_set_alpn_select_cb' function. */
/* Define to 1 if you have the 'SSL_CTX_set_alpn_select_cb' function. */
#undef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
/* Define to 1 if you have the `SSL_CTX_set_ciphersuites' function. */
/* Define to 1 if you have the 'SSL_CTX_set_ciphersuites' function. */
#undef HAVE_SSL_CTX_SET_CIPHERSUITES
/* Define to 1 if you have the `SSL_CTX_set_security_level' function. */
/* Define to 1 if you have the 'SSL_CTX_set_security_level' function. */
#undef HAVE_SSL_CTX_SET_SECURITY_LEVEL
/* Define to 1 if you have the `SSL_CTX_set_tlsext_ticket_key_evp_cb'
/* Define to 1 if you have the 'SSL_CTX_set_tlsext_ticket_key_evp_cb'
function. */
#undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
/* Define to 1 if you have the `SSL_get0_alpn_selected' function. */
/* Define to 1 if you have the 'SSL_get0_alpn_selected' function. */
#undef HAVE_SSL_GET0_ALPN_SELECTED
/* Define to 1 if you have the `SSL_get0_peername' function. */
/* Define to 1 if you have the 'SSL_get0_peername' function. */
#undef HAVE_SSL_GET0_PEERNAME
/* Define to 1 if you have the `SSL_get1_peer_certificate' function. */
/* Define to 1 if you have the 'SSL_get1_peer_certificate' function. */
#undef HAVE_SSL_GET1_PEER_CERTIFICATE
/* Define to 1 if you have the `SSL_is_quic' function. */
/* Define to 1 if you have the 'SSL_is_quic' function. */
#undef HAVE_SSL_IS_QUIC
/* Define to 1 if you have the `SSL_set1_host' function. */
/* Define to 1 if you have the 'SSL_set1_dnsname' function. */
#undef HAVE_SSL_SET1_DNSNAME
/* Define to 1 if you have the 'SSL_set1_host' function. */
#undef HAVE_SSL_SET1_HOST
/* Define to 1 if you have the 'SSL_set_quic_tls_early_data_enabled' function.
*/
#undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
@@ -706,7 +732,7 @@
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strftime' function. */
/* Define to 1 if you have the 'strftime' function. */
#undef HAVE_STRFTIME
/* Define to 1 if you have the <strings.h> header file. */
@@ -715,45 +741,45 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
/* Define to 1 if you have the 'strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
/* Define to 1 if you have the 'strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strptime' function. */
/* Define to 1 if you have the 'strptime' function. */
#undef HAVE_STRPTIME
/* Define to 1 if you have the `strsep' function. */
/* Define to 1 if you have the 'strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */
/* Define to 1 if 'ipi_spec_dst' is a member of 'struct in_pktinfo'. */
#undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
/* Define to 1 if `tokenlen' is a member of `struct ngtcp2_pkt_hd'. */
/* Define to 1 if 'tokenlen' is a member of 'struct ngtcp2_pkt_hd'. */
#undef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
/* Define to 1 if `max_tx_udp_payload_size' is a member of `struct
/* Define to 1 if 'max_tx_udp_payload_size' is a member of 'struct
ngtcp2_settings'. */
#undef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE
/* Define to 1 if `tokenlen' is a member of `struct ngtcp2_settings'. */
/* Define to 1 if 'tokenlen' is a member of 'struct ngtcp2_settings'. */
#undef HAVE_STRUCT_NGTCP2_SETTINGS_TOKENLEN
/* Define to 1 if `original_dcid_present' is a member of `struct
/* Define to 1 if 'original_dcid_present' is a member of 'struct
ngtcp2_transport_params'. */
#undef HAVE_STRUCT_NGTCP2_TRANSPORT_PARAMS_ORIGINAL_DCID_PRESENT
/* Define to 1 if the system has the type `struct ngtcp2_version_cid'. */
/* Define to 1 if the system has the type 'struct ngtcp2_version_cid'. */
#undef HAVE_STRUCT_NGTCP2_VERSION_CID
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
/* Define to 1 if 'sun_len' is a member of 'struct sockaddr_un'. */
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */
/* Define to 1 if 'st_mtimensec' is a member of 'struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIMENSEC
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
/* Define to 1 if 'st_mtim.tv_nsec' is a member of 'struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
/* Define if you have Swig libraries and header files. */
@@ -813,16 +839,16 @@
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the `tzset' function. */
/* Define to 1 if you have the 'tzset' function. */
#undef HAVE_TZSET
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `usleep' function. */
/* Define to 1 if you have the 'usleep' function. */
#undef HAVE_USLEEP
/* Define to 1 if you have the `vfork' function. */
/* Define to 1 if you have the 'vfork' function. */
#undef HAVE_VFORK
/* Define to 1 if you have the <vfork.h> header file. */
@@ -840,22 +866,28 @@
/* Define to 1 if you have the <winsock2.h> header file. */
#undef HAVE_WINSOCK2_H
/* Define to 1 if `fork' works. */
/* Define to 1 if 'fork' works. */
#undef HAVE_WORKING_FORK
/* Define to 1 if `vfork' works. */
/* Define to 1 if 'vfork' works. */
#undef HAVE_WORKING_VFORK
/* Define to 1 if you have the `writev' function. */
/* Define to 1 if you have the 'writev' function. */
#undef HAVE_WRITEV
/* Define to 1 if you have the <ws2tcpip.h> header file. */
#undef HAVE_WS2TCPIP_H
/* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */
/* Define to 1 if you have the 'X509_get_key_usage' function. */
#undef HAVE_X509_GET_KEY_USAGE
/* Define to 1 if you have the 'X509_NAME_get_text_by_NID' function. */
#undef HAVE_X509_NAME_GET_TEXT_BY_NID
/* Define to 1 if you have the 'X509_VERIFY_PARAM_set1_host' function. */
#undef HAVE_X509_VERIFY_PARAM_SET1_HOST
/* Define to 1 if you have the `_beginthreadex' function. */
/* Define to 1 if you have the '_beginthreadex' function. */
#undef HAVE__BEGINTHREADEX
/* If HMAC_Init_ex() returns void */
@@ -954,16 +986,16 @@
/* Shared data */
#undef SHARE_DIR
/* The size of `pthread_t', as computed by sizeof. */
/* The size of 'pthread_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_T
/* The size of `size_t', as computed by sizeof. */
/* The size of 'size_t', as computed by sizeof. */
#undef SIZEOF_SIZE_T
/* The size of `time_t', as computed by sizeof. */
/* The size of 'time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* The size of `unsigned long', as computed by sizeof. */
/* The size of 'unsigned long', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_LONG
/* define if (v)snprintf does not return length needed, (but length used) */
@@ -972,7 +1004,7 @@
/* Define to 1 if libsodium supports sodium_set_misuse_handler */
#undef SODIUM_MISUSE_HANDLER
/* Define to 1 if all of the C90 standard headers exist (not just the ones
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
@@ -1069,7 +1101,7 @@
/* Define this to enable SHA256 and SHA512 support. */
#undef USE_SHA2
/* Enable extensions on AIX 3, Interix. */
/* Enable extensions on AIX, Interix, z/OS. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
@@ -1130,11 +1162,15 @@
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# undef __STDC_WANT_IEC_60559_DFP_EXT__
#endif
/* Enable extensions specified by C23 Annex F. */
#ifndef __STDC_WANT_IEC_60559_EXT__
# undef __STDC_WANT_IEC_60559_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
@@ -1175,30 +1211,36 @@
/* Define if you want PyUnbound. */
#undef WITH_PYUNBOUND
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
/* Define to 1 if 'lex' declares 'yytext' as a 'char *' by default, not a
'char[]'. */
#undef YYTEXT_POINTER
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
/* Define to 1 if necessary to make fseeko visible. */
#undef _LARGEFILE_SOURCE
/* Define for large files, on AIX-style hosts. */
/* Define to 1 on platforms where this makes off_t a 64-bit type. */
#undef _LARGE_FILES
/* Enable for compile on Minix */
#undef _NETBSD_SOURCE
/* Number of bits in time_t, on hosts where this is settable. */
#undef _TIME_BITS
/* Define to 1 on platforms where this makes time_t a 64-bit type. */
#undef __MINGW_USE_VC2005_COMPAT
/* defined to use gcc ansi snprintf and sscanf that understands %lld when
compiled for windows. */
#undef __USE_MINGW_ANSI_STDIO
/* Define to empty if `const' does not conform to ANSI C. */
/* Define to empty if 'const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> doesn't define. */
/* Define as 'int' if <sys/types.h> doesn't define. */
#undef gid_t
/* in_addr_t */
@@ -1207,28 +1249,28 @@
/* in_port_t */
#undef in_port_t
/* Define to `__inline__' or `__inline' if that's what the C compiler
/* Define to '__inline__' or '__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `short' if <sys/types.h> does not define. */
/* Define to 'short' if <sys/types.h> does not define. */
#undef int16_t
/* Define to `int' if <sys/types.h> does not define. */
/* Define to 'int' if <sys/types.h> does not define. */
#undef int32_t
/* Define to `long long' if <sys/types.h> does not define. */
/* Define to 'long long' if <sys/types.h> does not define. */
#undef int64_t
/* Define to `signed char' if <sys/types.h> does not define. */
/* Define to 'signed char' if <sys/types.h> does not define. */
#undef int8_t
/* Define if replacement function should be used. */
#undef malloc
/* Define to `long int' if <sys/types.h> does not define. */
/* Define to 'long int' if <sys/types.h> does not define. */
#undef off_t
/* Define as a signed integer type capable of holding a process identifier. */
@@ -1237,34 +1279,34 @@
/* Define to 'int' if not defined */
#undef rlim_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* Define as 'unsigned int' if <stddef.h> doesn't define. */
#undef size_t
/* Define to 'int' if not defined */
#undef socklen_t
/* Define to `int' if <sys/types.h> does not define. */
/* Define to 'int' if <sys/types.h> does not define. */
#undef ssize_t
/* Define to 'unsigned char if not defined */
#undef u_char
/* Define to `int' if <sys/types.h> doesn't define. */
/* Define as 'int' if <sys/types.h> doesn't define. */
#undef uid_t
/* Define to `unsigned short' if <sys/types.h> does not define. */
/* Define to 'unsigned short' if <sys/types.h> does not define. */
#undef uint16_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* Define to 'unsigned int' if <sys/types.h> does not define. */
#undef uint32_t
/* Define to `unsigned long long' if <sys/types.h> does not define. */
/* Define to 'unsigned long long' if <sys/types.h> does not define. */
#undef uint64_t
/* Define to `unsigned char' if <sys/types.h> does not define. */
/* Define to 'unsigned char' if <sys/types.h> does not define. */
#undef uint8_t
/* Define as `fork' if `vfork' does not work. */
/* Define as 'fork' if 'vfork' does not work. */
#undef vfork
#if defined(OMITTED__D_GNU_SOURCE) && !defined(_GNU_SOURCE)
+10 -21
View File
@@ -1,10 +1,10 @@
#! /bin/sh
#!/usr/bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2026 Free Software Foundation, Inc.
# Copyright 1992-2024 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
timestamp='2026-05-17'
timestamp='2024-05-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ Report bugs and patches to <[email protected]>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2026 Free Software Foundation, Inc.
Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -145,7 +145,6 @@ case $1 in
| kfreebsd*-gnu* \
| knetbsd*-gnu* \
| kopensolaris*-gnu* \
| ironclad-* \
| linux-* \
| managarm-* \
| netbsd*-eabi* \
@@ -243,6 +242,7 @@ case $1 in
| rombug \
| semi \
| sequent* \
| siemens \
| sgi* \
| siemens \
| sim \
@@ -261,7 +261,7 @@ case $1 in
basic_machine=$field1-$field2
basic_os=
;;
tock* | zephyr*)
zephyr*)
basic_machine=$field1-unknown
basic_os=$field2
;;
@@ -1194,7 +1194,7 @@ case $cpu-$vendor in
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
arm64-* | aarch64le-* | arm64_32-*)
arm64-* | aarch64le-*)
cpu=aarch64
;;
@@ -1321,7 +1321,6 @@ case $cpu-$vendor in
| i960 \
| ia16 \
| ia64 \
| intelgt \
| ip2k \
| iq2000 \
| javascript \
@@ -1432,7 +1431,6 @@ case $cpu-$vendor in
| sparcv9v \
| spu \
| sv1 \
| sw_64 \
| sx* \
| tahoe \
| thumbv7* \
@@ -1524,10 +1522,6 @@ EOF
kernel=nto
os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
;;
ironclad*)
kernel=ironclad
os=`echo "$basic_os" | sed -e 's|ironclad|gnu|'`
;;
linux*)
kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
@@ -1982,7 +1976,6 @@ case $os in
| atheos* \
| auroraux* \
| aux* \
| banan_os* \
| beos* \
| bitrig* \
| bme* \
@@ -2029,6 +2022,7 @@ case $os in
| ios* \
| iris* \
| irix* \
| ironclad* \
| isc* \
| its* \
| l4re* \
@@ -2124,7 +2118,6 @@ case $os in
| sysv* \
| tenex* \
| tirtos* \
| tock* \
| toppers* \
| tops10* \
| tops20* \
@@ -2221,8 +2214,6 @@ case $kernel-$os-$obj in
;;
uclinux-uclibc*- | uclinux-gnu*- )
;;
ironclad-gnu*- | ironclad-mlibc*- )
;;
managarm-mlibc*- | managarm-kernel*- )
;;
windows*-msvc*-)
@@ -2258,8 +2249,6 @@ case $kernel-$os-$obj in
;;
*-eabi*- | *-gnueabi*-)
;;
ios*-simulator- | tvos*-simulator- | watchos*-simulator- )
;;
none--*)
# None (no kernel, i.e. freestanding / bare metal),
# can be paired with an machine code file format
@@ -2358,8 +2347,8 @@ echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%Y-%02m-%02d"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
+2874 -1942
View File
File diff suppressed because it is too large. Load diff
+19 -7
View File
@@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[25])
m4_define([VERSION_MICRO],[2])
m4_define([VERSION_MINOR],[26])
m4_define([VERSION_MICRO],[0])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[[email protected] or https://github.com/NLnetLabs/unbound/issues],[unbound])
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=38
LIBUNBOUND_REVISION=39
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -125,6 +125,7 @@ LIBUNBOUND_AGE=1
# 1.25.0 had 9:36:1
# 1.25.1 had 9:37:1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -483,7 +484,7 @@ PKG_PROG_PKG_CONFIG
fi
# Checks for header files.
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h fnmatch.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
# net/if.h portability for Darwin see:
# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
AC_CHECK_HEADERS([net/if.h],,, [
@@ -1080,12 +1081,19 @@ else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup])
# these check_funcs need -lssl
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername SSL_set1_dnsname X509_get_key_usage ASN1_STRING_get0_data X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
AC_CHECK_FUNCS([X509_NAME_get_text_by_NID])
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
ACX_FUNC_DEPRECATED([X509_NAME_get_text_by_NID], [
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0);], [
#include "openssl/x509.h"
])
fi
LIBS="$BAKLIBS"
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [
@@ -1704,6 +1712,9 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
AC_CHECK_LIB([ngtcp2_crypto_ossl], [ngtcp2_crypto_encrypt_cb], [
LIBS="$LIBS -lngtcp2_crypto_ossl"
AC_DEFINE(USE_NGTCP2_CRYPTO_OSSL, 1, [Define this to use ngtcp2_crypto_ossl.])
AC_CHECK_DECLS([ngtcp2_crypto_ossl_ctx_new], [], [AC_MSG_ERROR([No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed.])], [AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2_crypto_ossl.h>
])
], [
AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ], [
AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ])
@@ -1715,6 +1726,7 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])])
AC_CHECK_FUNCS([SSL_set_quic_tls_early_data_enabled])
LIBS="$BAKLIBS"
AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT
@@ -1928,7 +1940,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
AC_MSG_RESULT(no))
AC_SEARCH_LIBS([setusercontext], [util])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
+2 -2
View File
@@ -99,7 +99,7 @@ static void
dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
time_t now, size_t i)
{
char s[65535];
char s[65535*4+2048];
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
spool_txt_string(txt, "BADRR\n");
return;
@@ -455,7 +455,7 @@ load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
/* read the line */
if(!ssl_read_buf(ssl, buf))
return 0;
if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) {
*go_on = 0;
return 1;
}
+29 -11
View File
@@ -217,7 +217,8 @@ setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0),
is_dot, is_doh, cfg->tls_protocols))) {
fatal_exit("could not set up listen SSL_CTX");
log_err("could not set up listen SSL_CTX");
*ctx = NULL;
}
}
#endif /* HAVE_SSL */
@@ -259,7 +260,8 @@ void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
pem += strlen(chroot);
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
fatal_exit("could not set up quic SSL_CTX");
log_err("could not set up quic SSL_CTX");
return NULL;
}
return ctx;
}
@@ -277,8 +279,10 @@ void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
bundle += strlen(chroot);
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
cfg->tls_win_cert)))
fatal_exit("could not set up connect SSL_CTX");
cfg->tls_win_cert))) {
log_err("could not set up connect SSL_CTX");
return NULL;
}
return ctx;
}
#endif /* HAVE_SSL */
@@ -308,16 +312,22 @@ daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
}
daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(
daemon, cfg);
if(!daemon->listen_dot_sslctx)
fatal_exit("Could not set up listen dot sslctx");
#ifdef HAVE_NGHTTP2_NGHTTP2_H
if(cfg_has_https(cfg)) {
daemon->listen_doh_sslctx =
daemon_setup_listen_doh_sslctx(daemon, cfg);
if(!daemon->listen_doh_sslctx)
fatal_exit("Could not set up listen doh sslctx");
}
#endif
#ifdef HAVE_NGTCP2
if(cfg_has_quic(cfg)) {
daemon->listen_quic_sslctx =
daemon_setup_listen_quic_sslctx(daemon, cfg);
if(!daemon->listen_quic_sslctx)
fatal_exit("Could not set up listen quic sslctx");
}
#endif /* HAVE_NGTCP2 */
@@ -350,6 +360,8 @@ daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
}
daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
daemon, cfg);
if(!daemon->connect_dot_sslctx)
fatal_exit("could not setup connect dot sslctx");
#else /* HAVE_SSL */
(void)daemon;(void)cfg;
#endif /* HAVE_SSL */
@@ -921,13 +933,14 @@ thread_start(void* arg)
{
struct worker* worker = (struct worker*)arg;
int port_num = 0;
log_assert(worker->thr_id);
set_log_thread_id(worker, worker->daemon->cfg);
{
char name[16]; /* seems to be the safest size between
different OSes */
snprintf(name, sizeof(name), "unbound/%u", worker->thread_num);
ub_thread_setname(worker->thr_id, name);
/* worker->thr_id can be written to after the thread was made
* by the creating thread, so this uses pthread_self. */
ub_thread_setname(ub_thread_self(), name);
}
ub_thread_blocksigs();
#ifdef THREADS_DISABLED
@@ -942,8 +955,9 @@ thread_start(void* arg)
port_num = 0;
#endif
if(!worker_init(worker, worker->daemon->cfg,
worker->daemon->ports[port_num], 0))
worker->daemon->ports[port_num], 0)) {
fatal_exit("Could not initialize thread");
}
worker_work(worker);
return NULL;
@@ -1105,8 +1119,9 @@ daemon_fork(struct daemon* daemon)
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
/* in libev the first inited base gets signals */
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
fatal_exit("Could not initialize main thread");
}
#endif
/* Now create the threads and init the workers.
@@ -1119,8 +1134,9 @@ daemon_fork(struct daemon* daemon)
*/
#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
/* libevent has the last inited base get signals (or any base) */
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
fatal_exit("Could not initialize main thread");
}
#endif
signal_handling_playback(daemon->workers[0]);
@@ -1164,7 +1180,6 @@ daemon_cleanup(struct daemon* daemon)
/* before stopping main worker, handle signals ourselves, so we
don't die on multiple reload signals for example. */
signal_handling_record();
log_thread_set(NULL);
/* clean up caches because
* a) RRset IDs will be recycled after a reload, causing collisions
* b) validation config can change, thus rrset, msg, keycache clear
@@ -1270,7 +1285,7 @@ daemon_delete(struct daemon* daemon)
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE
# ifndef S_SPLINT_S
# if OPENSSL_VERSION_NUMBER < 0x10100000
sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free);
sk_SSL_COMP_pop_free(comp_meth, (void(*)(SSL_COMP*))CRYPTO_free);
# endif
# endif
# endif
@@ -1293,6 +1308,9 @@ daemon_delete(struct daemon* daemon)
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
ub_openssl_lock_delete();
# endif
#ifdef HAVE_OPENSSL_CLEANUP
OPENSSL_cleanup();
#endif
#ifndef HAVE_ARC4RANDOM
_ARC4_LOCK_DESTROY();
#endif
+249 -14
View File
@@ -307,7 +307,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
#endif
}
} else {
char* s = strchr(ip, '@');
const char* s = strchr(ip, '@');
char newif[128];
if(s) {
/* override port with ifspec@port */
@@ -1533,18 +1533,95 @@ do_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
(void)ssl_printf(ssl, "added %d datas\n", num);
}
static int
perform_data_remove_rr(RES* ssl, struct local_zones* local_zones,
uint8_t* rr, size_t len, size_t dname_len, char *arg)
{
uint16_t rr_class, rr_type;
int labs;
struct local_zone* z;
struct local_data* ld;
uint8_t *rdata;
size_t rdata_len, index;
struct packed_rrset_data* d;
struct local_rrset* p;
rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len);
rdata_len = ((size_t)sldns_wirerr_get_rdatalen(rr, len, dname_len))+2;
labs = dname_count_labels(rr);
rr_class = sldns_wirerr_get_class(rr, len, dname_len);
rr_type = sldns_wirerr_get_type(rr, len, dname_len);
z = local_zones_lookup(local_zones, rr, dname_len,
labs, rr_class, rr_type, 1);
if (!z) {
ssl_printf(ssl, "error no zone for rr %s\n", arg);
return 0;
}
ld = local_zone_find_data(z, rr, dname_len, labs);
if (!ld) {
ssl_printf(ssl, "error no local data for rr %s\n", arg);
return 0;
}
p = ld->rrsets;
while (p && ntohs(p->rrset->rk.type) != rr_type) {
p = p->next;
}
if (!p) {
ssl_printf(ssl, "error no rrset for rr %s\n", arg);
return 0;
}
d = (struct packed_rrset_data*)p->rrset->entry.data;
if (!packed_rrset_find_rr(d, rdata, rdata_len, &index)) {
ssl_printf(ssl, "error rr %s not found in rrset\n", arg);
return 0;
}
if (!local_rrset_remove_rr(d, index)) {
ssl_printf(ssl, "error unable to delete rr %s\n", arg);
return 0;
}
return 1;
}
/** Remove RR data */
static int
perform_data_remove(RES* ssl, struct local_zones* zones, char* arg)
{
uint8_t* nm;
int nmlabs;
size_t nmlen;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
uint8_t rr[LDNS_RR_BUF_SIZE], *nm;
size_t len = sizeof(rr);
int status, nmlabs;
size_t nmlen, dname_len;
/* try to parse as a rr first */
status = sldns_str2wire_rr_buf(arg, rr, &len, &dname_len, 3600,
NULL, 0, NULL, 0);
/* try to parse as a domain name second */
if (status != 0) {
if (parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) {
local_zones_del_data(zones, nm,
nmlen, nmlabs, LDNS_RR_CLASS_IN);
free(nm);
return 1;
}
ssl_printf(ssl, "error cannot parse rr %s at %d: %s\n", arg,
LDNS_WIREPARSE_OFFSET(status),
sldns_get_errorstr_parse(status));
return 0;
local_zones_del_data(zones, nm,
nmlen, nmlabs, LDNS_RR_CLASS_IN);
free(nm);
}
/* handle the rr case */
if (!perform_data_remove_rr(ssl, zones, rr, len, dname_len, arg))
return 0;
return 1;
}
@@ -2315,6 +2392,9 @@ zone_del_rrset(struct lruhash_entry* e, void* arg)
(struct packed_rrset_data*)e->data;
if(d->ttl > inf->expired) {
d->ttl = inf->expired;
if(d->ttl_add > inf->expired)
d->ttl_add = inf->expired; /* for 0TTL rrsets,
means that d->ttl_add <= d->ttl */
inf->num_rrsets++;
}
}
@@ -3238,6 +3318,10 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
return;
}
if(!auth_zone_read_zonefile(z, worker->env.cfg)) {
/* The old tree was already cleared. Do not answer from the
* failed load. */
z->zone_expired = 1;
auth_zone_clear_data(z);
lock_rw_unlock(&z->lock);
if(xfr) {
lock_basic_unlock(&xfr->lock);
@@ -3249,6 +3333,7 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
z->zone_expired = 0;
if(xfr) {
xfr->zone_expired = 0;
xfr->num_ixfrs = 0;
if(!xfr_find_soa(z, xfr)) {
if(z->data.count == 0) {
lock_rw_unlock(&z->lock);
@@ -4941,6 +5026,74 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1,
}
}
/** fast reload thread, check if config str3list has changed. */
#define FR_CHECK_CHANGED_CFG_STR3LIST(desc, var, buff) do { \
fr_check_changed_cfg_str3list(cfg->var, newcfg->var, desc, buff,\
sizeof(buff)); \
} while(0);
static void
fr_check_changed_cfg_str3list(struct config_str3list* cmp1,
struct config_str3list* cmp2, const char* desc, char* str, size_t len)
{
struct config_str3list* p1 = cmp1, *p2 = cmp2;
while(p1 && p2) {
if((!p1->str && p2->str) ||
(p1->str && !p2->str) ||
(p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
if((!p1->str2 && p2->str2) ||
(p1->str2 && !p2->str2) ||
(p1->str2 && p2->str2 &&
strcmp(p1->str2, p2->str2) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
if((!p1->str3 && p2->str3) ||
(p1->str3 && !p2->str3) ||
(p1->str3 && p2->str3 &&
strcmp(p1->str3, p2->str3) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
p1 = p1->next;
p2 = p2->next;
}
if((!p1 && p2) || (p1 && !p2)) {
fr_add_incompatible_option(desc, str, len);
}
}
/** fast reload thread, check tag datas. */
static int
fr_check_tag_datas(struct fast_reload_thread* fr, struct config_file* newcfg)
{
char changed_str[1024];
struct config_file* cfg = fr->worker->env.cfg;
changed_str[0]=0;
/* Check for tag_datas in acl_addr. */
FR_CHECK_CHANGED_CFG_STR3LIST("interface-tag-data", interface_tag_datas, changed_str);
FR_CHECK_CHANGED_CFG_STR3LIST("access-control-tag-data", acl_tag_datas, changed_str);
if(changed_str[0] != 0) {
if(fr->fr_drop_mesh)
return 1; /* already dropping queries */
fr->fr_drop_mesh = 1;
fr->worker->daemon->fast_reload_drop_mesh = fr->fr_drop_mesh;
if(!fr_output_printf(fr, "recursion referenced data has changed, with: '%s"
"', and the queries have to be dropped"
", setting '+d'\n", changed_str))
return 0;
fr_send_notification(fr, fast_reload_notification_printout);
}
return 1;
}
/** fast reload thread, check compatible config items */
static int
fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg)
@@ -5477,6 +5630,23 @@ xfr_masterlist_equal(struct auth_master* list1, struct auth_master* list2)
return 0;
}
/** See if configuration has changed. */
static int
xfr_config_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
{
if(xfr1 == NULL && xfr2 == NULL)
return 1;
if(xfr1 == NULL && xfr2 != NULL)
return 0;
if(xfr1 != NULL && xfr2 == NULL)
return 0;
if(xfr1->max_transfer_size != xfr2->max_transfer_size)
return 0;
if(xfr1->max_transfer_time != xfr2->max_transfer_time)
return 0;
return 1;
}
/** See if the list of masters has changed. */
static int
xfr_masters_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
@@ -5565,8 +5735,31 @@ auth_zones_check_changes(struct fast_reload_thread* fr,
&old_serial)!=0);
have_new = (auth_zone_get_serial(new_z,
&new_serial)!=0);
/* A change in primaries, also means it is different
* and the change makes it fire new transfers, from
* the new primaries. */
/* Treat as changed when the old zone has an
* outstanding ZONEMD DS/DNSKEY mesh callback.
* This will make the worker pickup change code
* remove the mesh callback, before the old zone is
* deleted. Also it makes a new zonemd lookup.
* The new lookup is needed, because the new zone
* entry needs to have a valid zonemd result,
* and if that is bad, needs to be invalidated.
* Also if there is a race event where the
* outstanding callback makes the zone invalid,
* before fast-reload completes, the change makes
* the new zone entry have a new zonemd lookup,
* to then invalidate that new zone.
* There is also a brief operational window at
* program start when a zonemd has to be looked
* up on-line, where the zone is operational.
* And this copies that for such a race event.
*/
if(have_old != have_new || old_serial != new_serial
|| !xfr_masters_equal(old_xfr, new_xfr)) {
|| !xfr_masters_equal(old_xfr, new_xfr)
|| !xfr_config_equal(old_xfr, new_xfr)
|| old_z->zonemd_callback_env != NULL) {
/* The zone has been changed. */
if(!fr_add_auth_zone_change(fr, old_z, new_z,
0, 0, 1)) {
@@ -5639,6 +5832,8 @@ ct_create_sslctxs(struct fast_reload_construct* ct,
/* Leave listen ctxs and file str at NULL */
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
daemon, newcfg);
if(!ct->connect_dot_sslctx)
return 0;
return 1;
}
@@ -5648,20 +5843,28 @@ ct_create_sslctxs(struct fast_reload_construct* ct,
pem += strlen(chroot);
ct->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(daemon, newcfg);
if(!ct->listen_dot_sslctx)
return 0;
#ifdef HAVE_NGHTTP2_NGHTTP2_H
if(cfg_has_https(newcfg)) {
ct->listen_doh_sslctx = daemon_setup_listen_doh_sslctx(
daemon, newcfg);
if(!ct->listen_doh_sslctx)
return 0;
}
#endif
#ifdef HAVE_NGTCP2
if(cfg_has_quic(newcfg)) {
ct->listen_quic_sslctx = daemon_setup_listen_quic_sslctx(
daemon, newcfg);
if(!ct->listen_quic_sslctx)
return 0;
}
#endif /* HAVE_NGTCP2 */
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(daemon,
newcfg);
if(!ct->connect_dot_sslctx)
return 0;
/* Store mtime and names */
ct->ssl_service_key = strdup(newcfg->ssl_service_key);
@@ -6631,9 +6834,12 @@ fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg,
}
#ifdef USE_DNSTAP
if(env->cfg->dnstap) {
if(!fr->fr_nopause)
dt_apply_cfg(daemon->dtenv, env->cfg);
else dt_apply_logcfg(daemon->dtenv, env->cfg);
if(!fr->fr_nopause) {
if(!dt_apply_cfg(daemon->dtenv, env->cfg))
log_warn("fast_reload: dnstap identity/version metadata not updated due to allocation failure");
} else {
dt_apply_logcfg(daemon->dtenv, env->cfg);
}
}
#endif
fr_adjust_cache(env, ct->oldcfg);
@@ -6773,6 +6979,10 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read,
config_delete(newcfg);
return 0;
}
if(!fr_check_tag_datas(fr, newcfg)) {
config_delete(newcfg);
return 0;
}
if(!fr_check_compat_cfg(fr, newcfg)) {
config_delete(newcfg);
return 0;
@@ -6864,7 +7074,7 @@ static void* fast_reload_thread_main(void* arg)
#endif
log_thread_set(&fast_reload_thread->threadnum);
ub_thread_setname(fast_reload_thread->tid, name);
ub_thread_setname(ub_thread_self(), name);
(void)name; /* When setname is not defined, ignore the name variable. */
verbose(VERB_ALGO, "start fast reload thread");
@@ -7587,7 +7797,8 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
qinfo.local_alias = NULL;
mesh_remove_callback(mesh, &qinfo, qflags,
&auth_zonemd_dnskey_lookup_callback, z);
&auth_zonemd_dnskey_lookup_callback, z,
z->zonemd_callback_unique_info);
}
/** Pick up the auth zone locks. */
@@ -7696,6 +7907,9 @@ auth_xfr_pickup_config(struct auth_xfer* loadxfr, struct auth_xfer* xfr)
log_assert(loadxfr->namelabs == xfr->namelabs);
log_assert(loadxfr->dclass == xfr->dclass);
xfr->max_transfer_size = loadxfr->max_transfer_size;
xfr->max_transfer_time = loadxfr->max_transfer_time;
/* The lists can be swapped in, the other xfr struct will be deleted
* afterwards. */
probe_masters = xfr->task_probe->masters;
@@ -7720,6 +7934,16 @@ fr_worker_auth_add(struct worker* worker, struct fast_reload_auth_change* item,
/* The xfr item needs to be created. The auth zones lock
* is held to make this possible. */
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
if(!xfr) {
log_err("out of memory in fr_worker_auth_add");
lock_rw_unlock(&item->new_z->lock);
lock_rw_unlock(&worker->env.auth_zones->lock);
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
if(loadxfr) {
lock_basic_unlock(&loadxfr->lock);
}
return;
}
auth_xfr_pickup_config(loadxfr, xfr);
/* Serial information is copied into the xfr struct. */
if(!xfr_find_soa(item->new_z, xfr)) {
@@ -7789,6 +8013,17 @@ fr_worker_auth_cha(struct worker* worker, struct fast_reload_auth_change* item)
} else if(loadxfr && !xfr) {
/* Create the xfr. */
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
if(!xfr) {
log_err("out of memory in fr_worker_auth_cha");
lock_rw_unlock(&item->new_z->lock);
lock_rw_unlock(&item->old_z->lock);
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
lock_rw_unlock(&worker->env.auth_zones->lock);
if(loadxfr) {
lock_basic_unlock(&loadxfr->lock);
}
return;
}
auth_xfr_pickup_config(loadxfr, xfr);
item->new_z->zone_is_slave = 1;
}
+1 -7
View File
@@ -49,6 +49,7 @@
#include <openssl/ssl.h>
#endif
#include "util/locks.h"
#include "libunbound/remote.h"
struct config_file;
struct listen_list;
struct listen_port;
@@ -365,13 +366,6 @@ void fast_reload_thread_start(RES* ssl, struct worker* worker,
*/
void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread);
/** fast reload thread commands to remote service thread event callback */
void fast_reload_service_cb(int fd, short bits, void* arg);
/** fast reload callback for the remote control client connection */
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
struct comm_reply* rep);
/** fast reload printq delete list */
void fast_reload_printq_list_delete(struct fast_reload_printq* list);
+22 -6
View File
@@ -422,12 +422,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
# endif
#endif
);
log_err("server_stats_obtain: no response from worker %d "
"(stats timeout); returning zero stats for this worker",
who->thread_num);
/* A later reply from the worker, would be sizeof stats reply,
* and the worker_handle_control_cmd routine discards if
* it is not a 4byte command, when that is received here. */
memset(s, 0, sizeof(*s));
return;
}
if(!tube_read_msg(worker->cmd, &reply, &len, 0)) {
log_err("server_stats_obtain: failed to read stats from worker "
"(tube read error); returning zero stats for this worker");
memset(s, 0, sizeof(*s));
return;
}
if(len != (uint32_t)sizeof(*s)) {
log_err("server_stats_obtain: wrong stats length %d (expected %d); "
"discarding", (int)len, (int)sizeof(*s));
free(reply);
memset(s, 0, sizeof(*s));
return;
}
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
fatal_exit("failed to read stats over cmd channel");
if(len != (uint32_t)sizeof(*s))
fatal_exit("stats on cmd channel wrong length %d %d",
(int)len, (int)sizeof(*s));
memcpy(s, reply, (size_t)len);
free(reply);
}
@@ -439,7 +455,7 @@ void server_stats_reply(struct worker* worker, int reset)
verbose(VERB_ALGO, "write stats replymsg");
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
(uint8_t*)&s, sizeof(s), 0))
fatal_exit("could not write stat values over cmd channel");
log_err("could not write stat values over cmd channel");
}
void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
+28 -13
View File
@@ -501,7 +501,9 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
return;
}
if(len != sizeof(uint32_t)) {
fatal_exit("bad control msg length %d", (int)len);
verbose(VERB_ALGO, "bad control msg length %d", (int)len);
free(msg);
return;
}
cmd = sldns_read_uint32(msg);
free(msg);
@@ -714,7 +716,8 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
struct sockaddr_storage* addr, socklen_t addrlen,
struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
struct reply_info** encode_repp, struct auth_zones* az,
int* rpz_passthru)
{
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
actinfo.action = respip_none;
@@ -725,7 +728,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
alias_rrset, 0, worker->scratchpad, az, NULL,
alias_rrset, 0, worker->scratchpad, az, rpz_passthru,
worker->env.views, worker->env.respip_set))
return 0;
@@ -772,7 +775,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** partial_repp,
struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns)
struct comm_reply* repinfo, struct edns_data* edns, int* rpz_passthru)
{
time_t timenow = *worker->env.now;
uint16_t udpsize = edns->udp_size;
@@ -882,7 +885,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
&encode_rep, worker->env.auth_zones, rpz_passthru)) {
goto bail_out;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
@@ -1494,6 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct reply_info* partial_rep = NULL;
struct query_info* lookup_qinfo = &qinfo;
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
uint8_t* alias_orig_qname = NULL; /* original qname for logs, if
a local_alias is used to change the qname. */
struct respip_client_info* cinfo = NULL, cinfo_tmp;
struct timeval wait_time;
struct check_request_result check_result = {0,0};
@@ -1511,7 +1516,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if (worker->stats.max_query_time_us < wait_queue_time)
worker->stats.max_query_time_us = wait_queue_time;
if(wait_queue_time >
(long long)(worker->env.cfg->sock_queue_timeout * 1000000)) {
(long long)worker->env.cfg->sock_queue_timeout * 1000000) {
/* count and drop queries that were sitting in the socket queue too long */
worker->stats.num_queries_timed_out++;
return 0;
@@ -1936,6 +1941,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* If we've found a local alias, replace the qname with the alias
* target before resolving it. */
if(qinfo.local_alias) {
if(qinfo.local_alias->rrset &&
qinfo.local_alias->rrset->rk.dname)
/* Store the original qname, used for logs, since
* local_alias can be removed by region_free_all. */
alias_orig_qname = qinfo.local_alias->rrset->rk.dname;
if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname,
&qinfo.qname_len)) {
regional_free_all(worker->scratchpad);
@@ -1983,7 +1993,7 @@ lookup_cache:
&alias_rrset, &partial_rep, rep,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
&edns, &rpz_passthru)) {
/* prefetch it if the prefetch TTL expired.
* Note that if there is more than one pass
* its qname must be that used for cache
@@ -2101,11 +2111,10 @@ send_reply_rc:
{
struct timeval tv;
memset(&tv, 0, sizeof(tv));
if(qinfo.local_alias && qinfo.local_alias->rrset &&
qinfo.local_alias->rrset->rk.dname) {
if(alias_orig_qname) {
/* log original qname, before the local alias was
* used to resolve that CNAME to something else */
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
qinfo.qname = alias_orig_qname;
log_reply_info(NO_VERBOSE, &qinfo,
&repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer,
@@ -2374,6 +2383,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker_stat_timer_cb, worker);
if(!worker->stat_timer) {
log_err("could not create statistics timer");
worker_delete(worker);
return 0;
}
/* we use the msg_buffer_size as a good estimate for what the
@@ -2526,6 +2537,8 @@ worker_delete(struct worker* worker)
/* don't touch worker->alloc, as it's maintained in daemon */
regional_destroy(worker->env.scratch);
regional_destroy(worker->scratchpad);
/* The thread id can reference this worker's id value, so clear it. */
log_thread_set(NULL);
free(worker);
}
@@ -2534,7 +2547,8 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q, int* was_ratelimited)
struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -2546,7 +2560,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
want_dnssec, nocaps, check_ratelimit, tcp_upstream,
ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
worker_handle_service_reply, e, worker->back->udp_buff, q->env,
was_ratelimited);
was_ratelimited, ratelimit_incremented);
if(!e->qsent) {
return NULL;
}
@@ -2595,7 +2609,8 @@ struct outbound_entry* libworker_send_query(
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
+59 -8
View File
@@ -643,6 +643,12 @@ handle_event_moddone(struct module_qstate* qstate, int id)
qstate->return_msg->rep &&
reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep);
int synth_qname = 0;
if(could_synth && !has_data && qstate->env->need_to_validate &&
qstate->return_msg && qstate->return_msg->rep &&
qstate->return_msg->rep->security == sec_status_bogus) {
verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized");
could_synth = 0;
}
if(could_synth &&
(!has_data ||
@@ -654,8 +660,11 @@ handle_event_moddone(struct module_qstate* qstate, int id)
/* Store the response in cache. */
if( (!iq || !iq->started_no_cache_store) &&
!qstate->rpz_applied && !qstate->rpz_passthru &&
!qstate->is_subnet_answer &&
qstate->return_msg &&
qstate->return_msg->rep &&
!qstate->fwd_stub_no_cache &&
!dns_cache_store(
qstate->env, &qstate->qinfo, qstate->return_msg->rep,
0, qstate->prefetch_leeway, 0, NULL,
@@ -717,8 +726,15 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
}
if(qstate->ext_state[id] == module_finished) {
iq = (struct dns64_qstate*)qstate->minfo[id];
if(iq && iq->state != DNS64_INTERNAL_QUERY)
qstate->no_cache_store = iq->started_no_cache_store;
if(iq && iq->state != DNS64_INTERNAL_QUERY) {
if(qstate->fwd_stub_no_cache) {
/* If the forward/stub has no cache, then
* continue with the query with no cache. */
qstate->no_cache_store = qstate->fwd_stub_no_cache;
} else {
qstate->no_cache_store = iq->started_no_cache_store;
}
}
}
}
@@ -825,6 +841,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
size_t i, s;
struct packed_rrset_data* fd, *dd;
struct ub_packed_rrset_key* fk, *dk;
int allocated_return_msg = 0;
verbose(VERB_ALGO, "converting A answers to AAAA answers");
@@ -840,6 +857,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
return;
memset(super->return_msg, 0, sizeof(*super->return_msg));
super->return_msg->qinfo = super->qinfo;
allocated_return_msg = 1;
}
rep = qstate->return_msg->rep;
@@ -852,11 +870,14 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
rep->serve_expired_norec_ttl,
rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
rep->rrset_count, rep->security, LDNS_EDE_NONE);
if(!cp)
if(!cp) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
/* allocate ub_key structures special or not */
if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
@@ -871,8 +892,10 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) {
/* also sets dk->entry.hash */
dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env);
if(!dd)
if(!dd) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
/* Delete negative AAAA record from cache stored by
* the iterator module */
rrset_cache_remove(super->env->rrset_cache, dk->rk.dname,
@@ -889,15 +912,19 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
fk->rk.dname, fk->rk.dname_len);
if(!dk->rk.dname)
if(!dk->rk.dname) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
s = packed_rrset_sizeof(fd);
dd = (struct packed_rrset_data*)regional_alloc_init(
super->region, fd, s);
if(!dd)
if(!dd) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
}
packed_rrset_ptr_fixup(dd);
@@ -928,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
return;
super->return_msg->qinfo = super->qinfo;
if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
NULL, super->region)))
NULL, super->region))) {
super->return_msg = NULL;
return;
}
/*
* Adjust the domain name of the answer RR set so that it matches the
@@ -998,6 +1027,21 @@ dns64_inform_super(struct module_qstate* qstate, int id,
/* Use return code from A query in response to client. */
if (super->return_rcode != LDNS_RCODE_NOERROR)
super->return_rcode = qstate->return_rcode;
/* RPZ applied to the subquery need to then change (not cache)
* the super query. With the super query not cached, it is
* going to run the state machine modules on incoming queries,
* that fetch the subquery (cache) response, and modify it
* according to the rpz policy. That makes the synthesized
* super query also adjusted by rpz policies. But loses cache
* hits. Even though the subquery likely is answered from cache,
* internally in its state machine process. */
if(qstate->rpz_applied)
super->rpz_applied = 1;
if(qstate->rpz_passthru)
super->rpz_passthru = 1;
/* Since the super qstate has a new response, its errinf is removed. */
super->errinf = NULL;
/* Generate a response suitable for the original query. */
if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) {
@@ -1006,9 +1050,16 @@ dns64_inform_super(struct module_qstate* qstate, int id,
log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR);
dns64_adjust_ptr(qstate, super);
}
/* If the sub-query has no cache store, then also the super query. */
if(qstate->fwd_stub_no_cache)
super->fwd_stub_no_cache = 1;
/* Store the generated response in cache. */
if ( (!super_dq || !super_dq->started_no_cache_store) &&
if ( super->return_msg && super->return_msg->rep &&
(!super_dq || !super_dq->started_no_cache_store) &&
!qstate->fwd_stub_no_cache &&
!super->rpz_applied && !super->rpz_passthru &&
!super->is_subnet_answer &&
!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
0, super->prefetch_leeway, 0, NULL, super->query_flags,
qstate->qstarttime, qstate->is_valrec))
+8 -1
View File
@@ -842,7 +842,14 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
if(memcmp(current_keypair->crypt_publickey,
env->signed_certs[c].server_publickey,
crypto_box_PUBLICKEYBYTES) == 0) {
dnsccert *current_cert = &env->certs[cert_id++];
dnsccert* current_cert;
if(cert_id >= env->signed_certs_count) {
log_err("dnscrypt: secret key %s matches a cert that "
"is already bound to another key (duplicate "
"dnscrypt-secret-key?)", head->str);
return -1;
}
current_cert = &env->certs[cert_id++];
found_cert = 1;
current_cert->keypair = current_keypair;
memcpy(current_cert->magic_query,
+36 -17
View File
@@ -176,26 +176,29 @@ dt_create(struct config_file* cfg)
env->dtio = dt_io_thread_create();
if(!env->dtio) {
log_err("malloc failure");
free(env);
dt_delete(env);
return NULL;
}
if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
dt_io_thread_delete(env->dtio);
free(env);
dt_delete(env);
return NULL;
}
if(!dt_apply_cfg(env, cfg)) {
dt_delete(env);
return NULL;
}
dt_apply_cfg(env, cfg);
return env;
}
static void
static int
dt_apply_identity(struct dt_env *env, struct config_file *cfg)
{
char buf[MAXHOSTNAMELEN+1];
if (!cfg->dnstap_send_identity) {
free(env->identity);
env->identity = NULL;
return;
env->len_identity = 0;
return 1;
}
free(env->identity);
if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
@@ -203,36 +206,49 @@ dt_apply_identity(struct dt_env *env, struct config_file *cfg)
buf[MAXHOSTNAMELEN] = 0;
env->identity = strdup(buf);
} else {
fatal_exit("dt_apply_identity: gethostname() failed");
log_err("dt_apply_identity: gethostname() failed: %s",
strerror(errno));
env->identity = NULL;
env->len_identity = 0;
return 0;
}
} else {
env->identity = strdup(cfg->dnstap_identity);
}
if (env->identity == NULL)
fatal_exit("dt_apply_identity: strdup() failed");
if (env->identity == NULL) {
log_err("dt_apply_identity: strdup() failed");
env->len_identity = 0;
return 0;
}
env->len_identity = (unsigned int)strlen(env->identity);
verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
env->identity);
return 1;
}
static void
static int
dt_apply_version(struct dt_env *env, struct config_file *cfg)
{
if (!cfg->dnstap_send_version) {
free(env->version);
env->version = NULL;
return;
env->len_version = 0;
return 1;
}
free(env->version);
if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
env->version = strdup(PACKAGE_STRING);
else
env->version = strdup(cfg->dnstap_version);
if (env->version == NULL)
fatal_exit("dt_apply_version: strdup() failed");
if (env->version == NULL) {
log_err("dt_apply_version: strdup() failed");
env->len_version = 0;
return 0;
}
env->len_version = (unsigned int)strlen(env->version);
verbose(VERB_OPS, "dnstap version field set to \"%s\"",
env->version);
return 1;
}
void
@@ -276,15 +292,18 @@ dt_apply_logcfg(struct dt_env *env, struct config_file *cfg)
lock_basic_unlock(&env->sample_lock);
}
void
int
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
{
if (!cfg->dnstap)
return;
return 1;
dt_apply_identity(env, cfg);
dt_apply_version(env, cfg);
dt_apply_logcfg(env, cfg);
if(!dt_apply_identity(env, cfg))
return 0;
if(!dt_apply_version(env, cfg))
return 0;
return 1;
}
int
+2 -2
View File
@@ -102,9 +102,9 @@ dt_create(struct config_file* cfg);
* Apply config settings.
* @param env: dnstap environment object.
* @param cfg: new config settings.
* @return false on failure.
*/
void
dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
int dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
/**
* Apply config settings for log enable for message types.
+1 -1
View File
@@ -2144,7 +2144,7 @@ static void* dnstap_io(void* arg)
#endif
log_thread_set(&dtio->threadnum);
ub_thread_setname(dtio->tid, name);
ub_thread_setname(ub_thread_self(), name);
/* setup */
verbose(VERB_ALGO, "start dnstap io thread");
@@ -1659,7 +1659,8 @@ struct outbound_entry* worker_send_query(
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
@@ -1693,7 +1694,8 @@ struct outbound_entry* libworker_send_query(
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
+577
View File
@@ -1,3 +1,507 @@
24 July 2026: Wouter
- Merge #1433 from jisakiel: Add new static zone type
block_aaaa to suppress AAAA queries.
- Unit test for block_a and block_aaaa.
- Fix #1477: respip + dns64: dns64 uses A records modified by
respip instead of original A records. Adds local-zone types
block_a_wdata and block_aaaa_wdata, that are like block_a
and block_aaaa, and uses local-data if present.
- set code repository version to 1.26.0.
- Update generated man pages.
- Fix to allow test fake sha1 on systems with possible sha1
support.
- Fix to use sha256 for unbound-anchor unit test.
- Fix unbound-anchor check for return value of
X509_NAME_get_text_by_NID of the emailaddress.
- Fix lock test protect for auth zone change.
- Fix to lock shared_ports structure during initialisation.
- Fix to lock anchor structure when file is set for it in
parse of the header.
- Merge #1480 from petrvaganoff: authzone: fix memory leak in
xfer_set_masters() error path.
- Fix unused variable warnings in shared_ports_fetch_random
and shared_ports_return_port when compiled without threads.
- Fix to guard access to shared ports interface array during
set up, for analyzer.
- Fix sign of comparison warning in shared ports setup.
- Fix #1481: Fix to use tls-port after referral if
tls-upstream is set.
- Merge #1479 from psumbera: Fix pthread detection on
Solaris 11.4.
- Fix to call OPENSSL_cleanup on exit when that is defined.
23 July 2026: Wouter
- Updated credits for Xuanchao Xie in 22 july changelog.
- Merge #1478 from petrvaganoff: pythonmod: add check return
value after ftell().
- Fix that for NSEC3 proofs the NSEC3 zone, as the b32.name is
checked to be the same as the signer name. Also RRSIGs are
not considered valid when an NSEC3 is not b32.signerzone.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that the aggressive negative cache does not insert NSEC
records with overreaching next owner name. Also the result
is not above the trust anchor's bailiwick. Also RRSIGS are
not considered valid when an NSEC next owner name is not
under the signer zone name. Thanks to Qifan Zhang, Palo
Alto Networks, for the report.
- Fix mesh cycle detection for configuration with respip CNAME
loop and tagged clients. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
22 July 2026: Wouter
- Release tag for 1.25.2, with the security commits:
- Fix CVE-2026-14586, Assertion in libngtcp2 when under pressure
in high concurrency DNS-over-QUIC environments. Thanks to Kunta
Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
for the report.
- Fix CVE-2026-32665, Remote DNS-over-QUIC denial of
service due to `quic-size` budget bypass. Thanks to N0zoM1z0
(https://github.com/N0zoM1z0) for the report. In addition, thanks to
Kunta Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
for also reporting this issue. In addition, thanks to Qifan Zhang,
Palo Alto Networks, for also reporting this issue. In addition,
thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue of the
University of Science and Technology of China (USTC), for also
reporting this issue.
- Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks
to Qifan Zhang, Palo Alto Networks, for the report. In addition,
thanks to Trung Nguyen (@everping) of CyStack, for also reporting
this issue.
- Fix CVE-2026-41637, Degradation of resolution service from
improperly accounted client-terminated DNS-over-QUIC queries. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-42955, Extra fix for CVE-2026-40622 to also clamp
the TTL of A/AAAA records disallowing a one-time 'ghost domain'
delegation renewal via glue records. Thanks to Qifan Zhang, Palo
Alto Networks, for the report.
- Fix CVE-2026-44621, Libunbound applications configured with
'unwanted-reply-threshold' could eventually be abruptly
terminated. Thanks to Qifan Zhang, Palo Alto Networks, for the
report.
- Fix CVE-2026-44687, Off-by-one error in 'harden-below-nxdomain'
logic can shadow a stub/forward zone by a legitimate parent's
NXDOMAIN. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via
RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix CVE-2026-46582, A wildcard replay, as another piece of data,
triggers poisoning in the serve expired reply path. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-50045, 'max-global-quota' reset by DNSSEC validation
restarts. Thanks to Kunjie Shang, University of Science and
Technology of China, for the report.
- Fix CVE-2026-50046, Possible heap use-after-free in an error path
when a DoT forwarded query is jostled out. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix CVE-2026-50243, 'response-ip'/'rpz' can rewrite BOGUS answers
instead of returning SERVFAIL. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix CVE-2026-50248, BOGUS configured primary hostname accepted for
XFR in auth/rpz zones. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix CVE-2026-50251, Attacker supplied `0.0.0.0`/`::` glue triggers
defensive full-cache flush. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix CVE-2026-50252, Possible cache poisoning attack by mapping
source port population per thread. Thanks to Inbal Schussheim and
Amit Klein, Hebrew University, for the report.
- Fix CVE-2026-52863, Memory corruption could lead to crash and
denial of service. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix CVE-2026-54478, DNS Cookie bypass when combined with
proxy-protocol use. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix CVE-2026-55708, Privacy/configuration issue when adding local
data in views through 'unbound-control'. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix CVE-2026-55717, 'serve-expired-client-timeout' and 'response-ip'
CNAME redirect could lead to a crash. Thanks to Qifan Zhang, Palo
Alto Networks, for the report. In addition, thanks to Xin Wang,
Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University,
for also reporting this issue.
- Fix CVE-2026-55973, 'dns-error-reporting: yes' leads to stack buffer
overflow. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-55990, Packet of death for a DNSCrypt misconfigured
Unbound. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-55991, Remote DNS-over-QUIC (DoQ) flow-control
assertion failure in libngtcp2. Thanks to Qifan Zhang, Palo Alto
Networks, for the report. In addition, thanks to Xuanchao Xie,
Lutong Chen, and Kaiping Xue of the University of Science and
Technology of China (USTC), for also reporting this issue.
- Fix CVE-2026-56416, Possible heap buffer overflow when validator
canonicalizes RDATA that contains domain name. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
- Fix CVE-2026-56444, Degradation of resolution service when
'discard-timeout' and 'serve-expired-client-timeout' are combined in
unusual configuration. Thanks to Qifan Zhang, Palo Alto Networks,
for the report. In addition, thanks to Xin Wang, Jiapeng Li,
and Jiajia Liu, Northwestern Polytechnical University, for also
reporting this issue. In addition, thanks to Haruki Oyama (Waseda
University), for also reporting this issue.
- Set the repository to 1.25.3, it continues with the previous
changes.
- Unit test for CVE-2026-42955.
- Unit test for CVE-2026-44687.
- Unit test for CVE-2026-44690.
- Unit test for CVE-2026-46582.
- Unit test for CVE-2026-50045.
- Unit test for CVE-2026-50243.
- Unit test for CVE-2026-50248.
- Unit test for CVE-2026-55717.
- Unit test for CVE-2026-55973.
- Unit test for CVE-2026-56416.
- Fix error in log printout in fix for CVE-2026-50248, when the
primary name is bogus.
- iana portlist update.
21 July 2026: Wouter
- Merge #1476 from petrvaganoff: ipsecmod: fix possible deref
on null after reply_find_answer_rrset().
20 July 2026: Wouter
- Merge #1475 from petrvaganoff: ipsecmod: fix deref on null
in ipsecmod-whitelist after OOM.
- Fix #1474: DoQ responses are never padded - pad-responses
does not apply to comm_doq (RFC 9250 §5.4 MUST).
9 July 2026: Wouter
- Merge #1383 from jdek: Fix randomness generation on
macOS/iOS under chroot.
- Fix unit test for malformed svcb for test on Windows.
2 July 2026: Wouter
- Merge #1087: Overload `local_data_remove` to support removing
specific records.
30 June 2026: Wouter
- Fix #1469: dohclient: DoH POST missing content-length → :status
400 from strict resolvers (Cloudflare, Mullvad).
- iana portlist updated.
26 June 2026: Wouter
- Merge #1467: daemon: fix DEREF_AFTER_NULL.EX.COND on
worker_init. This fixes error handling if the worker
stat_timer allocation has an out of memory error. That
makes the server not crash later, attempting to use it.
24 June 2026: Wouter
- Merge #1465 from dag-erling: Add libunbound/remote.h. Add
a shared header containing prototypes for functions that
both ends of a remote control connection need to implement.
19 June 2026: Wouter
- Fix for #1457: fix thread setname for thread start of
dnstap, and fast_reload.
- Fix to update github ci actions/checkout to v7.
- Fix warning about file_string_matches in unbound-checkconf.
17 June 2026: Wouter
- Fix that after fast_reload the disown of the auth zone
transfer task cleans the chunk list. Also fix the
auth_transfer_limit test to use a forwarder for each type
of failure, so the one is not blocked by the other waiting.
- Fix to remove debug from auth_transfer_limit test.
- Fix that unbound-checkconf checks if an auth-zone download
can overwrite another file, by filename collision.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that malloc failure in auth-zone insert rr does
not create an empty node and does not cause an infinite
loop. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix that unbound-control auth_zone_reload stops the
server answering from the zone after a failure to read.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that malloc failure in dns64_inform_super does
not set up a half-built reply for cache store, that could
lead to a crash. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix that malloc failure for new_local_rrset for RPZ qname
trigger RR insert does not crash. It does not link a
partial RRset, and logs an error on failure, and cleans
up the dname allocation. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that malloc failure in doq connection setup, does
not crash in doq connection delete later. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
- Fix that malloc failure for ngtcp2_conn_server_new
cleans up reference that older ngtcp2 versions can leave.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that on malloc failure during accept of TCP, the
socket is not left to cause a read event loop. It uses
slow-accept to delay accepting new connections, if
that fails it drops the new connections. When the tcp
connection usage is full, it waits for 50msec, to allow
existing queries to be resolved. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix that malloc failure for rpz_strip_nsdname is
checked and handled, so that it does not crash later.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that malloc failure during edns subnet addrtree
insert is checked, so it does not crash later. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
- Fix to check the return value of auth_xfer_create
during fast_reload auth-zone add and change processing.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix to check for malloc failure in rpz response create,
for nodata and nxdomain, so it does not crash later.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that fast_reload does not terminate the server
on malloc failure for dnstap, or if gethostname fails.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix after malloc failure for stats, then it drains the pipe
so the internal messaging stays correct. Also it does
not exit the server if stats pipe communication fails.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that fast_reload does not terminate the server
on config read failure after malloc failure. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
- Fix that fast_reload does not terminate the server if
random init for DNS cookies fails. The data is only random
generated if cookies are enabled, and the random data
is necessary. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
17 June 2026: Yorgos
- Fix memory leak on DNAME 0TTL records.
16 June 2026: Wouter
- Fix to disallow $INCLUDE for secondary zones. Start up
of server continues if a secondary zone fails to load.
Failed loads clear the zone data, so there is no partial
zone. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix that when SVCB records cannot be written out, and
are written in unknown format, that the zone read allows
such unknown format SVCB records. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix that a half-written trust anchor file does not crash
the server at runtime. It unlinks a wrong file from the list.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that auth-zone, and RPZ zones, do not allow out-of-zone
records. These are records that are not under the zone apex.
The out-of-zone records are dropped from the zone contents.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that dns64 does not ignore the `forward-no-cache` and
`stub-no-cache` options. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that a signed wildcard NSEC, is checked before use,
so it does not allow insecure DS proofs inappropriately.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that after malloc failure a half-built local_alias does
not crash the server. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that for a zonefile only zone, if that file does not
exist on server start, the server continues to start with
a warning log message. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that after malloc failure in RPZ load a half built
list does not crash later. The newly created RRset is
linked after creation has succeeded. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix that dnscrypt configuration does not crash, due to
inconsistency between secret and public keys. Also
duplicate files are skipped. Thanks to Qifan Zhang, Palo
Alto Networks, for the report.
- Fix locking in libunbound ub_ctx_set_event call.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that libunbound pipe functions fail with error after
an event base is set. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix for neater solution to clear log thread id after
worker init failure. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix incorrect cleanup after an allocation failure for
a delegation point. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that after malloc failure in find_tag_datas, the
local_alias is cleaned up. Thanks to Qifan Zhang, Palo
Alto Networks, for the report.
- Fix that after shared memory cannot be created, from
`shm-enable`, the server does not crash. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
- Fix incorrect cleanup after an allocation failure for
a delegation point in a region. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix after malloc failure the rrset_insert_rr in
localzone processing, during RPZ qname trigger processing,
the RRset retains its previous data correcly. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
- Fix for #1462: Fix that auth primary host name lookup
allows CNAMEs.
15 June 2026: Wouter
- Fix to add `max-transfer-size` and `max-transfer-time` that
limit auth-zone and rpz transfer amount and time taken.
Default is disabled. This hardens against unbounded
transfers. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix perform a full transfer every number of incremental
transfers, to stop increasing memory usage, for rpz
zones. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix assertion failure for long HTTP header that fills
buffer. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix buffer overflow when configured with lower than
default size and http transfer. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix that misconfigured `iter-scrub-ns: 0` causes request
failures. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix that fast_reload when a zonemd verification lookup
it in progress with subnet loaded, deregisters the
callback. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix for fast_reload that removes an auth zone while its
lookups are in progress, for a primary name. Also after the
change, it no longer picks up the old results. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
- Fix integer overflow in infra-cache-max-rtt calculation.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix erroneous DNS error report values after bogus AAAA
query caused error information that was not cleared by
a successful A subquery. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix integer overflow for very high values of
`sock-queue-timeout`. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix that fast_reload does not terminate the server for
errors in config, for key files. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix log of an aliased qname, to not use freed region
memory. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix DNAME synthesis from cache that keeps use of 0TTL
entries in a sliding window. It did not surpass RRSIG
expiry. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix misconfigured ipsecmod hook causing path name
similarity with other file. The ipsecmod is changed for
exec of the hook. The ipsecmod hook, if a script, has to
start now with a line like `#!/bin/sh`. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
- Fix that dns64 bypasses rpz-passthru rule during
synthesis. This restricted more than necessary. Thanks to
Qifan Zhang, Palo Alto Networks, for the report.
12 June 2026: Wouter
- Fix that for auth-zone and rpz zones the allow-notify
addresses and netblocks are available from start, and
fix the probe step skip.
11 June 2026: Wouter
- Fix for #1306: configure detects specifically the call to
SSL_set_quic_tls_early_data_enabled and
SSL_set_quic_early_data_enabled, so the correct one is used.
- Fix for #1306: configure checks if the ngtcp2_crypto_ossl
header file is available, and prints an error otherwise.
- Fix #1437: Fix compile with OpenSSL 4.0.1.
- Fix compile for OpenSSL 1.0.2 and before in server cleanup.
10 June 2026: Wouter
- Fix pythonmod script read for numeric overflow.
- Fix warnings with gcc in compat/inet_pton.c.
9 June 2026: Wouter
- Fix unit test for ecs to check for malloc success.
3 June 2026: Wouter
- Fix that the processing of class responses does not have
a heap use-after-free. That could happen if at least two
distinct classes are configured for resolution. Thanks
to Qifan Zhang, Palo Alto Networks for the report.
In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia
Liu, Northwestern Polytechnical University, for also
reporting this.
- Fix negative cache to work with NSEC3 records without salt.
Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
Polytechnical University, for the report.
- Fix parse of svcbparam ech, it had incorrect length. Thanks
to Qifan Zhang, Palo Alto Networks for the report.
- Fix that quotation and escaping works the same in auth-zone
url content, as in the zonefile read. Thanks to Qifan Zhang,
Palo Alto Networks for the report.
- Fix ipset module to use larger domain name buffers, and
check buffer lengths. Thanks to Qifan Zhang, Palo Alto
Networks for the report.
- Fix PROXYv2 header read and consume, it checks the header
size. Thanks to Qifan Zhang, Palo Alto Networks for
the report.
- Fix negative cache NSEC3 nodata proof, to use the correct
message size. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix fast_reload for when a ZONEMD lookup is in progress.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that validation canonicalization of domain names
in rdata checks for buffer bounds. Thanks to Qifan Zhang,
Palo Alto Networks, for the report.
- Fix that dump_cache has a larger buffer for records,
and it checks that an owner name does not collide with BADRR
on the input, and changes verbosity on the log of failure in
rrset to string. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix that dns64 cleans up the allocated message if the adjust
routines fail, and checks if there is a reply before cache
store, also unbound checks if A and AAAA are malformed
for auth-zones. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
3 June 2026: Yorgos
- Fix const as reported by newest compiler warnings.
29 May 2026: Wouter
- Fix header_seen detection for trust anchor files, so that it
detects the id line.
- iana portlist updated.
- Update icannbundle.pem certificates in unbound-anchor. It
has the public keys for 2009 to 2029 and for 2025 to 2045.
- Fix unit test to check for new icannbundle.pem.
28 May 2026: Wouter
- Fix #1457: race condition causes segfault when starting
threads.
27 May 2026: Wouter
- Fix for autotrust state-file line overflow, that can give
hold-down bypass. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix to limit the DSNS per-label walk in the iterator. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that the ratelimit is decremented on successful
referrals. Thanks to Qifan Zhang, Palo Alto Networks, for
the report.
- Fix that msgencode insert_query has the correct assertion,
for a local_alias. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix to reset the tcp-timeout before applying a load based
reduction. Thanks to Qifan Zhang, Palo Alto Networks, for the
report.
- Fix to decrement the per-netblock tcp connection limits, so
it keeps usable. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix manual to document ratelimit, that it is for target
nameservers for a domain, and keeps queries limited. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
- Fix, in depth, for respip rewrite of dns64 responses. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that dns64 with subnetcache does not write ECS scoped
answers to global cache. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
- Fix ipset module for name too long checks, race conditions
on local name buffer, and for socket close race condition.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that validator caps number of ANY RRsets it can
validate, and the wait timer is shortened. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
- Fix analyzer warning in mesh_new_client.
26 May 2026: Wouter
- Fix for mesh new client and mesh new callback to rollback the
added address, tcp mesh state and callback when there is a failure
to initialize. This fixes the mesh accounting of reply addresses.
Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
Polytechnical University, for the report
20 May 2026: Wouter
- Fix CVE-2026-33278, Possible remote code execution during DNSSEC
validation. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
@@ -27,6 +531,79 @@
Networks, for the report.
- Fix CVE-2026-44608, Use after free and crash in RPZ code. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
- Tag for 1.25.1 release, it contains the security fixes on 1.25.0.
the code repository continues with in addition the previous fixes,
for 1.25.2.
- Unit test for CVE-2026-33278.
- Unit test for CVE-2026-42944.
- Unit test for CVE-2026-42959.
- Unit test for CVE-2026-40622.
- Unit test for CVE-2026-42960.
- Fix in depth for serve-expired responses from cachedb, that it
does not store bogus. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix lame server detection, for selfpointed glue records.
Thanks to Shuhan Zhang, Dan Li, and Baojun Liu from Tsinghua
University for the report.
- Fix cleaning up DoH session. The same query can be on multiple
streams in a session. Thanks to Qifan Zhang, Palo Alto Networks,
for the report.
- Fix for signed same-owner CNAME and ordinary RRset responses.
Thanks to Xin Wang and Jiajia Liu, Northwestern Polytechnical
University, for the report.
18 May 2026: Wouter
- Fix for mixed class referrals, the resolver uses the query
class. Thanks to Xin Wang and Jiajia Liu, Northwestern
Polytechnical University, for the report.
15 May 2026: Wouter
- Fix man page entry for so-sndbuf, it is for responses sent out.
- Fix val_find_DS for robustness, to check the result of
packet_rrset_copy_region before using it. Thanks to Xin Wang
and Jiajia Liu, Northwestern Polytechnical University, for
the report.
- Fix that for dns64 answers, the AAAA query is checked to be
DNSSEC validated, when DNSSEC is enabled. This improves
the RFC6147 conformance of Unbound. Thanks to Xin Wang
and Jiajia Liu, Northwestern Polytechnical University, for
the report. In addition, thanks to Qifan Zhang, Palo Alto
Networks, for reporting it.
- Fix for allocation-failure hardening of rrset cache wildcard
storage and canonical NSEC owner replacement. Thanks to Xin
Wang and Jiajia Liu, Northwestern Polytechnical University,
for the report.
- Fix DNSSEC validation with libnettle for noncanonical RSA
DNSKEYs with leading zeroes for n. Thanks to Xin Wang and
Jiajia Liu, Northwestern Polytechnical University, for
the report.
- Fix DNSKEY size calculation for noncanonical RSA DNSKEYs
with leading zeroes for n. Thanks to Xin Wang and Jiajia Liu,
Northwestern Polytechnical University, for the report.
11 May 2026: Yorgos
- Fix comment and verbose logging for EDNS fallback buffer size.
8 May 2026: Wouter
- Fix to relax assertions after the TTL 0 handling change.
This relaxes an assertion in cachedb (it fails instead),
and for packet_rrset_copy_region.
7 May 2026: Wouter
- Fix for Heap Out-of-Bounds Write via size_t-to-int Truncation
in setup_if() - outside_network_create(). This fixes that
large values for num_ports do not overflow and create
invalid references after integer truncation. Thanks
to Karnakar Reddy (@karnakarreddi) for the report.
- Fix to clean up log ids after a failure to start a worker thread.
1 May 2026: Wouter
- iana portlist updated.
29 April 2026: Wouter
- tag for 1.25.0. The code repository continues with 1.25.1 in
development.
- Fix windows 64bit build for libssp dependency.
23 April 2026: Wouter
- Merge #1441: Fix buffer overrun in
+1 -1
View File
@@ -1,4 +1,4 @@
README for Unbound 1.25.2
README for Unbound 1.26.0
Copyright 2007 NLnet Labs
http://unbound.net
+10 -1
View File
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
# See unbound.conf(5) man page, version 1.25.2.
# See unbound.conf(5) man page, version 1.26.0.
#
# this is a comment.
@@ -899,6 +899,10 @@ server:
# that name
# o block_a resolves all records normally but returns
# NODATA for A queries and ignores local data for that name
# o block_aaaa similarly to block_a, resolves all records normally but
# returns NODATA for AAAA queries and ignores local data for that name
# o block_a_wdata like block_a but uses local data if present.
# o block_aaaa_wdata like block_aaaa but uses local data if present.
# o always_null returns 0.0.0.0 or ::0 for any name in the zone.
# o noview breaks out of that view towards global local-zones.
#
@@ -1287,6 +1291,9 @@ remote-control:
# zonemd-check: no
# zonemd-reject-absence: no
# zonefile: "example.org.zone"
# max-transfer-size: 0
# max-transfer-time: 0
# Views
# Create named views. Name must be unique.
@@ -1453,3 +1460,5 @@ remote-control:
# rpz-signal-nxdomain-ra: no
# for-downstream: no
# tags: "example"
# max-transfer-size: 0
# max-transfer-time: 0
+10 -1
View File
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
# See unbound.conf(5) man page, version 1.25.2.
# See unbound.conf(5) man page, version 1.26.0.
#
# this is a comment.
@@ -899,6 +899,10 @@ server:
# that name
# o block_a resolves all records normally but returns
# NODATA for A queries and ignores local data for that name
# o block_aaaa similarly to block_a, resolves all records normally but
# returns NODATA for AAAA queries and ignores local data for that name
# o block_a_wdata like block_a but uses local data if present.
# o block_aaaa_wdata like block_aaaa but uses local data if present.
# o always_null returns 0.0.0.0 or ::0 for any name in the zone.
# o noview breaks out of that view towards global local-zones.
#
@@ -1287,6 +1291,9 @@ remote-control:
# zonemd-check: no
# zonemd-reject-absence: no
# zonefile: "example.org.zone"
# max-transfer-size: 0
# max-transfer-time: 0
# Views
# Create named views. Name must be unique.
@@ -1453,3 +1460,5 @@ remote-control:
# rpz-signal-nxdomain-ra: no
# for-downstream: no
# tags: "example"
# max-transfer-size: 0
# max-transfer-time: 0
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "LIBUNBOUND" "3" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "LIBUNBOUND" "3" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
libunbound \- Unbound DNS validating resolver 1.25.2 functions.
libunbound \- Unbound DNS validating resolver 1.26.0 functions.
.SH SYNOPSIS
.sp
\fB#include <unbound.h>\fP
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "LIBUNBOUND" "3" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "LIBUNBOUND" "3" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
libunbound \- Unbound DNS validating resolver 1.25.2 functions.
libunbound \- Unbound DNS validating resolver 1.26.0 functions.
.SH SYNOPSIS
.sp
\fB#include <unbound.h>\fP
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-ANCHOR" "8" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "UNBOUND-ANCHOR" "8" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
unbound-anchor \- Unbound 1.25.2 anchor utility.
unbound-anchor \- Unbound 1.26.0 anchor utility.
.SH SYNOPSIS
.sp
\fBunbound\-anchor\fP [\fBopts\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-ANCHOR" "8" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "UNBOUND-ANCHOR" "8" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
unbound-anchor \- Unbound 1.25.2 anchor utility.
unbound-anchor \- Unbound 1.26.0 anchor utility.
.SH SYNOPSIS
.sp
\fBunbound\-anchor\fP [\fBopts\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CHECKCONF" "8" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "UNBOUND-CHECKCONF" "8" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
unbound-checkconf \- Check Unbound 1.25.2 configuration file for errors.
unbound-checkconf \- Check Unbound 1.26.0 configuration file for errors.
.SH SYNOPSIS
.sp
\fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CHECKCONF" "8" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "UNBOUND-CHECKCONF" "8" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
unbound-checkconf \- Check Unbound 1.25.2 configuration file for errors.
unbound-checkconf \- Check Unbound 1.26.0 configuration file for errors.
.SH SYNOPSIS
.sp
\fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile]
+4 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CONTROL" "8" "Jul 22, 2026" "1.25.2" "Unbound"
.TH "UNBOUND-CONTROL" "8" "Aug 4, 2026" "1.26.0" "Unbound"
.SH NAME
unbound-control \- Unbound 1.25.2 remote server control utility.
unbound-control \- Unbound 1.26.0 remote server control utility.
.SH SYNOPSIS
.sp
\fBunbound\-control\fP [\fB\-hq\fP] [\fB\-c cfgfile\fP] [\fB\-s server\fP] command
@@ -354,6 +354,8 @@ If the name already has no items, nothing happens.
Often results in NXDOMAIN for the name (in a static zone), but if the name
has become an empty nonterminal (there is still data in domain names below
the removed name), NOERROR nodata answers are the result for that name.
With a specific RR instead of a domain name, that specific record is
removed from the local data, and not all the RR data.
.UNINDENT
.INDENT 0.0
.TP
Loaded 100 of 225 files, more files were not shown because too many files have changed in this diff. Show more