Branch: development (switch to
stable),
SWI-Prolog Changelog from version 10.1.7 to 10.1.8
[May 28 2026]
- DOC: macOS .pkg installer build, signing, notarization and cert
renewal Add doc/MacOSXInstaller.md: an end-to-end, reproducible
guide to building the signed and notarized macOS .pkg --- one-time
keychain and Developer-ID/notarytool setup, the build invocation,
result verification, certificate renewal, and the failure modes hit
on the Apple-Silicon + macOS 26 host.
- ADDED: macOS: `ninja pkg' builds a signed, notarized split-layout .pkg
installer Add a `pkg' target producing a single Developer-ID-signed
and Apple-notarized .pkg that delivers swipl-win.app to /Applications
and swipl.framework to /Library/Frameworks.
- ADDED: macOS: swipl.framework and the split swipl-win.app bundle
layout Package the macOS runtime as a standalone swipl.framework and
arrange the split bundle layout the installer ships: swipl-win.app
in /Applications, swipl.framework in /Library/Frameworks.
[May 25 2026]
- FIXED: Reset cached JIT index decisions when the supervisor changes.
The per-argument
assessed flags, jiti_tried, pindex_verified,
fixed_indexes and unindexed memoize index decisions for the current
clause shape. A supervisor change is the signal that this shape has
changed enough that those verdicts may be stale. Without a reset,
a "not indexable" verdict made on a transient state (e.g., while an
autoload triggered through trapUndefined() re-enters Prolog) could
stick and disable JIT indexing for the eventual stable clause set.
[May 18 2026]
- MODIFIED: PL_predicate() now takes UTF-8 strings as argument.
- DOC: Modernized calc.c, cacl.pl example. Replaceing PR 1493
[May 17 2026]
- DOC: Unicode bracket-pair atoms are consistent with {} Document
that an empty Unicode bracket pair (optionally layout-only) reads
as the two-character atom, that atom before '(' is a functor, and
'<open><close>'(X) writes as <open>X<close> with the bare atom
unquoted, all governed by the brace_terms write option.
- TEST: Unicode bracket-pair atoms (read/write consistency with {})
Covers empty/layout pair reading as the atom, '<o><c>'(X) as a
compound, unquoted bare-atom output, write_canonical functor form,
round-tripping and that {} is unchanged.
- ENHANCED: Make Unicode bracket-pair atoms consistent with {} A matching
Unicode bracket pair (Ps/Pe) now behaves like {}: an empty pair,
optionally with layout in between, reads as the atom '<open><close>'
(and as a functor when followed by '('), while '<open><close>'(X)
writes as <open>X<close> and the bare atom is written unquoted.
E.g. ⟨⟩ reads as '⟨⟩', ⟨⟩(x) as '⟨⟩'(x), and
'⟨⟩'(hello) writes as ⟨hello⟩.
[May 15 2026]
- FIXED: Avoid crash trying to destroy a running engine from another
thread.
[May 13 2026]
- ADDED: code_type/2 and char_type/2 property pattern_syntax Exposes
Unicode UAX #31 Pattern_Syntax membership through the standard ctype
dispatch. Useful for libraries that want to align tokenisation
or quoting with the immutable syntax set, and for inspecting which
code points the write_term/2 pattern_syntax_solo option will treat
as stable.
- ADDED: write_term/2 option pattern_syntax_solo, used by
write_canonical/1 A new boolean write_term/2 option quotes
single-character atoms whose code point is not in the immutable UAX
#31 Pattern_Syntax set, so atoms like '€', '·', '🎉' round-trip
safely across Unicode versions instead of relying on classifications
that may shift in future releases. write_canonical/1 enables the
option by default; plain write/1 and writeq/1 are unchanged.
- FIXED: compare/3 on wide atoms must order by code point, not code
unit On platforms with 16-bit wchar_t (Windows), a supplementary
character is stored as a UTF-16 surrogate pair whose lead unit lives
in U+D800..U+DBFF.
compareUCSAtom() compared raw wchar_t values, so
a non-BMP atom like '\U0001D11E' wrongly ordered below BMP atoms in
U+DC00..U+FFFF — e.g. compare(C, '\U0001D11E', '豈') (with U+F900)
returned < on Windows where Linux (32-bit wchar_t) gave the correct
>.
- FIXED: Reject surrogate code points in UTF-8 and UTF-16 stream
decoders. A well-formed UTF-8 sequence never encodes a surrogate
(RFC 3629), and a well-formed UTF-16 sequence never produces a
lone trail surrogate. Both decoders previously let such malformed
input through, so a file containing the bytes ED A0 80 read with
encoding(utf8) would deliver U+D800 as a code point — leaking an
invalid Unicode value into atoms and strings even though the new
PL_get_char / Sputcode checks reject surrogates everywhere else.
- FIXED: Reject UTF-16 surrogate code points at every Prolog API surface.
Extends the recent fix to atom_codes/2 to put_code/1,2, put_char/1,2,
put/1,2 and the format/2,3 ~c directive: PL_get_char() and the ~c
argument check now use VALID_CODE_POINT(), so a lone surrogate is
rejected with
type_error(character_code, Code) (or format_argument_type
for ~c) before it can reach the stream layer. As defence in depth,
Sputcode() in pl-stream.c now calls reperror() on a surrogate before
encoding-specific handling, preventing foreign callers from emitting
invalid UTF-8 or raw-wchar bytes via Sputcode(0xD800, s).
- FIXED: Do not allow surrogate pair code points in atom_codes/2.
[May 12 2026]
- FIXED: Solo characters do not needs quotes
- MODIFIED: Code walker not to track below call/1. This allows using
call(Goal) in places that are false possitives for the detection of
undefined predicates.
[May 11 2026]
- FIXED: Confusable detection when using zero-arity compounds.
- ENHANCED: char_type/2 and code_type/2 accept prolog_solo The kernel has
a
f_is_prolog_solo helper (and a corresponding SOLO category in the
syntax map) but did not expose it through the char_type/2 catalogue.
Register prolog_solo alongside prolog_symbol, prolog_atom_start
and friends in src/os/pl-ctype.c, with a new atom in src/ATOMS,
and document the class in the char_type/2 reference (man/builtin.plx).
- ENHANCED: library(check) gets list_confusable_identifiers/{0,1}
A new consistency check that walks every clause in the modules in
module_class (default [user]) and warns on atoms whose written
form is a UTS #39 spoof:
- ENHANCED: '\''$needs_quotes'\''/1 + fix unquoted_atom for
UCS atoms Exposes the kernel's own quote decision as a semidet
'\''$needs_quotes'\''/1 so library code (notably library(check)'s
confusable-identifier linter) can ask "would writeq quote this
atom?" without re-parsing the name.
Package clib
[May 28 2026]
- FIXED: bsd-crypt.c: unconditional include of "crypt.h" breaks build
when no system crypt.h is available On glibc >= 2.39 the
crypt()
function is no longer in libc; when libcrypt-dev is also absent
(e.g. some PPA build chroots), CMake's HAVE_CRYPT and HAVE_LIBCRYPT
both fail and the build falls back to the bsd-crypt.c implementation,
which then failed because it unconditionally included "crypt.h".
The DES_ONLY define already excludes the only consumers of anything
declared there, so guard the include with HAVE_CRYPT_H, matching the
pattern in crypt.c.
Package cpp
[May 19 2026]
- DOC: document the PlEncoding API in pl2cpp.plx Document the
PlEncoding enum and the ENC_INPUT/ENC_OUTPUT defaults, the
trailing-PlEncoding constructor/method forms and the deprecated
argument-order constructors. Add a PlFunctor section and state that
PlModule/PlPredicate/PlFunctor/PlCompound functor names are UTF-8.
Replace the stale EncLatin1/EncUTF8/EncLocale enumerators, correct
the unify_*() wrapper descriptions and escape & for the PDF build.
Package http
[May 28 2026]
- TEST: proxy: reserve the `unused' port by holding a bound (unlistened)
socket Concurrent ctest jobs that allocate ports dynamically (bind to
port 0) could grab the port the proxy tests had pre-allocated for the
`unused' role, causing connections that should be refused to instead
succeed against an unrelated test server. Keeping a bound socket
on that port for the duration of the suite reserves the port number
while still producing ECONNREFUSED on
connect(), since no tcp_listen/2
is called. SO_REUSEADDR is intentionally omitted on the held socket.
Package libedit
[May 20 2026]
- ADDED: Bind Ctrl+Left/Right to word motion Maps the xterm sequences
ESC[1;5D and ESC[1;5C, sent by the Epilog terminal, to ed-prev-word
and em-next-word. In vi mode the same sequences are also bound in
the command (alternative) keymap to vi-prev-word and vi-next-word.
Package ltx2htm
[May 12 2026]
- FIXED: #8 Handling e.g.,
\\const{\%h}
Package pldoc
[May 18 2026]
- CLEANUP: As we go through luatex, we no longer need utf8proc as
dependency
Package utf8proc
[May 17 2026]
- ADDED: library(uniname) exporting unicode_name/2 Wraps the compact
name table in a SWI plugin (uniname4pl.c) and a library (uniname.pl).
unicode_name(?CodePoint, ?Name) is nondet: (+,-) is the semidet forward
name, (-,+) the semidet reverse lookup, and (-,-) enumerates every
named code point on backtracking via a stateful foreign iterator
(no quadratic blow-up; >100k solutions in ~50 ms). Registered as
the utf8proc:uniname ctest.
- ADDED: Prototype compact Unicode code-point -> name table Adds
etc/gen_uniname.pl, the generated uniname_data.{c,h} and a small
decoder (uniname.c) implementing the ICU / GNU libunistring scheme:
algorithmic ranges (Hangul synthesised from Jamo; CJK/Tangut and every
PREFIX-<cphex> family derived from the code point) carry no per-code-
point data, and the remaining ~34.6k names are stored as a flat LEB128
stream of a code-point delta plus frequency-ordered word ids into a
shared word table.
[May 11 2026]
- TEST: extend confusable_demo.pl with non-predicate-name cases
Adds clauses that put confusable atoms in argument positions, in
nested compound functors, in list elements, and in clause bodies,
so list_confusable_identifiers/0 exercises every code path of its
sub_term/2 walk:
- CHANGE: move list_confusable_identifiers/0 into library(check)
The hook was duplicated from library(check)'s existing list_*
checkers and didn't share their per-atom source-location walking.
Move the predicate to library(check) directly, guarded by
:-
if(exists_source(library(unicode_security))), so it uses the
same prolog_program_clause/2 + message_context/4 infrastructure as
list_strings/0 and friends.
- ENHANCED: hook list_confusable_identifiers/0 into library(check)
Adds a linter that walks predicates of every user-class module and
flags two UTS #39 concerns:
- DOC: fix PlDoc Markdown conventions in unicode_security.pl PlDoc
Markdown is not LaTeX:
- CHANGE: unicode_script_extensions/2 and unicode_identifier_status/2
are semidet Follow-up to commit 8f00f14, applying the same "no info ->
fail" rule to the remaining per-code-point predicates:
- CHANGE: unicode_script/2 and unicode_identifier_type/2 are now semidet
Previously both predicates absorbed missing entries with a default:
unicode_script/2 fell through to 'common' for unassigned code points,
and unicode_identifier_type/2 returned [] for code points without a
listing in IdentifierType.txt. Both also raised a domain_error for
code points outside U+0000..U+10FFFF.
- CHANGE: don't vendor UCD source files; add fetch instructions The
generator etc/gen_uts39.pl runs only on demand (regen-uts39 target)
and the checked-in uts39_data.{c,h} are authoritative for default
builds, so keeping the .txt inputs in the repo just bloats history.
Remove them, add data/*.txt to .gitignore, and add a data/README.md
that says where to obtain them.
- ENHANCED: unify range tables as (start, len, value) All UTS #39 / UAX
#24 range tables (script, scx, idstatus, idtype) now share one type:
- DOC: predicate docstrings and README paragraph for unicode_security
PlDoc comments for each exported predicate in unicode_security.pl,
plus a one-paragraph README pointer to library(unicode_security)
and the regen-uts39 workflow.
- TEST: add PLUnit suite for library(unicode_security) Covers all
eight predicates: unicode_script/2, unicode_script_extensions/2,
unicode_identifier_status/2, unicode_identifier_type/2,
unicode_skeleton/2, unicode_confusable/{2,3},
unicode_resolved_scripts/2 and unicode_restriction_level/2.
- ENHANCED: implement UTS #39 runtime in library(unicode_security)
Implements the runtime algorithms over the generated tables and
exports the public Prolog API:
- ENHANCED: add UTS #39 / UAX #24 generator and generated tables
etc/gen_uts39.pl reads the vendored UCD files under data/ and writes
uts39_data.{c,h}. The output is deterministic, so re-running the
generator on unchanged inputs produces a zero diff.
- ENHANCED: scaffold library(unicode_security) plugin Adds an empty
second plugin alongside unicode4pl in the same package. The plugin
compiles, the Prolog module loads, the doc section is generated and
linked into utf8proc.tex. No predicates yet; this is the integration
scaffold for the upcoming UTS #39 implementation.
- ENHANCED: vendor UTS #39 and UAX #24 data files for unicode_security
Source files for the upcoming library(unicode_security) generator:
Package xpce
[May 25 2026]
- FIXED: Hold a code reference on Frame across the FLASH_END SDL event
flash_end_callback() pushes MY_EVENT_FLASH_END carrying a raw FrameObj
pointer. Same UAF shape as the Timer case: if the frame is destroyed
and reused before the consumer in CtoEvent() runs, the F_FREED check
reads stale memory. Take a code reference around the queue and skip
the push entirely when the frame is already being freed.
- FIXED: Hold a code reference on Timer across the SDL event queue
tm_callback() pushes MY_EVENT_TIMER carrying a raw Timer pointer.
If the Timer is destroyed and its memory freed/reused before the
main thread consumes the event, the F_FREEING|F_FREED check in
sdl_timer_event() reads stale memory. Mirror the FDWatch pattern:
addCodeReference() before SDL_PushEvent(), delCodeReference() in the
consumer so the object stays in F_FREEING (memory alive) until the
queued event is drained.
- FIXED: Register Epilog pty slave_fd as a drainable console (POSIX) So
that
ws_discard_input() drops keystrokes the user typed at an Epilog
terminal window while a modal confirmer is up. Uses tcflush(TCIFLUSH)
on the slave fd, which drops kernel-buffered bytes without consuming
them and therefore does not race with the Prolog engine reading the
same fd.
- FIXED: Register stdin as a drainable console when it is a terminal So
that
ws_discard_input() drops pending bytes typed at the terminal while
a modal confirmer is up. Skipped silently when stdin is redirected
(e.g. Epilog spawning swipl with stdin closed).
- FIXED:
ws_discard_input() reads stale fd after socket-based dispatch
hook Replace the static dispatch_fd cache with a small console
registry, populated by the host on init (stdin) and by terminal.c for
Epilog ptys. ws_dispatch() now only watches an fd transiently for the
duration of one call, never caching it as a global; ws_discard_input()
iterates the registry and uses tcflush()/FlushConsoleInputBuffer()
instead of read(), avoiding races with engines reading the same fd.
[May 20 2026]
- ADDED: Send xterm Ctrl+Left/Right escape sequences from the terminal
Ctrl modifier on cursorLeft/cursorRight now produces ESC[1;5D /
ESC[1;5C so libedit (or any xterm-compatible reader) can bind these
to word motion.
[May 17 2026]
- ADDED: PceEmacs: normalize_region/normalize_buffer M-x commands to
apply a Unicode normalization form (nfc, nfd, nfkc, nfkd) to the region
or the whole buffer. Conditional on the optional library(unicode).
- ADDED: PceEmacs/epilog: insert_symbol command (C-x 8 RET / C-x 8 s)
C-x 8 is a prefix in PceEmacs and the epilog terminal; it opens the
symbol picker targeting the invoking editor/terminal.
- ADDED:
library(pce_symbol_picker) for picking Unicode symbols A
non-modal singleton (and modal pick_symbol/1) to browse Unicode blocks
and curated code ranges, type the picked symbol into the focused
window, and remember recents. Supports code_range/3 user ranges,
matching pairs, and a filter that searches either block names or
Unicode character names.
- FIXED: man class hierarchy: correct builtin/user class icons
- ADDED: display_manager <->focus_message: hook on keyboard-focus change
Fires the given message when a frame gains or loses the keyboard focus,
so tools can track the active application window.
- ENHANCED: text<-pointed: add round option (caret vs hit-test)
<-pointed takes an extra argument selecting caret-style rounding
(snap to nearest gap) versus exact hit-testing.
- ENHANCED: text_item: optional clear-field image Add a ->clear_image
slot to class text_item. When set (use @default for the standard
clear-text.svg icon), a clickable image appears at the right of the
entry field while it is non-empty; clicking it clears the field.
The space is reserved as soon as the image is set so the field does
not reflow when the icon appears. Restricted to style `normal'.
[May 15 2026]
- ADDED: window->pdf: print the full window contents Graphical->pdf
saves <-area, i.e. only the visible part of a window. Override it on
window to use <-bounding_box (the union of all graphicals) so scrolled
or oversized content is printed in full, with the page offset so the
bounding box maps onto the page.
- FIXED: graphical->pdf: negate the page offset
pdfGraphical() created
a page sized to <-area but set d_offset() to +area->x,+area->y.
Since drawing primitives add the offset, a graphical at a non-zero
position was shifted off the page, producing a blank PDF. Negate the
offset so the graphical's area maps onto the page origin.
- FIXED: text<-pointed: hit-test with Pango layout, not per-char c_width
get_pointed_text() summed c_width() per character to map a click to
a character index. For proportional fonts and strings needing font
fallback (e.g. the symbol picker showing emoji/Greek/math), that sum
drifts from the actual rendered glyph positions, so clicks selected
the wrong symbol.
[May 14 2026]
- FIXED: xpce printf %c: handle non-ASCII code points Routed %c through
snprintf which collapses the int argument to a single byte and produced
invalid UTF-8 for any code point above 0x7F. Handle %c separately:
Put() takes a uchar_t (uint32_t) which already carries a full code
point, and put_void_str promotes the target string to wide as needed.
Width and left-align flags from the format spec are still honoured.