Did you know ... Search Documentation:
Title for pldoc(default)
Branch: development (switch to stable),
version to version

SWI-Prolog Changelog from version 10.1.11 to 10.1.12

[Jul 19 2026]

  • ENHANCED: win_process_modules/1: use disk case Used to downcase the file names.
  • FIXED: Drive letters on Windows are now normalized as upper case. As we now normalize on the disk case and (thus) paths are typically mixed case, we better use the Windows uppercase default for drive letters as well. Reported by Paulo Moura.
  • DOC: Describe the initial view of the Prolog Navigator Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013EGUkPkGnzYjZUQtYF3tH4

[Jul 18 2026]

  • ADDED: Process -D flags that the boot sequence depends on before starting Prolog apply_defines/0 applies -D options after the boot files have been loaded, which is too late for a flag the boot sequence itself depends on. Prolog flags listed in early_defines[] are now picked from the raw argv by setEarlyDefines(), which runs before initPaths(), and are left out of the list handed to apply_defines/0. Add a flag to that table to handle it early; -Dhome=Dir is a candidate.
  • ENHANCED: Windows: normalise file names to their on-disk case, not lower case On case-preserving file systems (the Windows default) SWI-Prolog now normalises a file name to the case in which it is stored on disk rather than down-casing it. So absolute_file_name/2 and working_directory/2 return e.g. 'c:/Users/Paulo Moura/...' instead of 'c:/users/paulo moura/...'. The result is still a single normal form per physical file, which source tracking relies on, but it is readable and matches what the user sees in the file manager. Set the flag file_name_case_handling to case_insensitive to restore the old down-casing behaviour.

[Jul 17 2026]

  • FIXED: file_name_case_handling flag reported a value inconsistent with its setting currentFileNameCaseHandling() did not match setFileNameCaseHandling(): on a case-preserving system (the Windows default) it reported case_sensitive, and it could never report case_preserving. Rewrite the getter to mirror the two flag bits the setter uses.
  • FIXED: #1511 Failure to normalize bigint to tagged int on Windows. This happened when using GMP for integers that do not fit in a long but do fit in a tagged integer.
  • FIXED: crmath build failed on old compilers not knowing -march=x86-64-v3 Upstream core-math adds -march=x86-64-v3 unconditionally on x86_64. This microarchitecture level is only known to gcc >= 11 and clang >= 12; older compilers error out. Drop the flag in our crmath.cmake layer when check_c_compiler_flag() reports it is unsupported. It is only a tuning hint, so dropping it loses AVX2 tuning but not correctness.

[Jul 16 2026]

  • FIXED: predicate_options drift check failed where foreign source locations are unavailable On platforms such as WASM predicate_location/2 does not resolve foreign (C) predicates to their source file, so the drift check scanned no C files and reported every option array as stale. Gate the check on a drift_testable/0 probe that verifies a foreign predicate can be located, skipping the drift test otherwise.
  • FIXED: predicate_options drift check failed on single-threaded builds The thread option declarations in library(dialect/swi/syspred_options) referred to predicates that do not exist without O_PLMT, so the predicate_options drift test flagged their (unreachable) C option arrays as stale. Guard the thread-only declarations and the matching c_option_array/2 mappings with :- if(current_prolog_flag(threads, true)).
  • FIXED: setCloseOnExec() silently failed on missing fd / failing fcntl set_stream/2 close_on_exec now raises a permission_error when the stream has no OS file descriptor and a system_error (preserving errno) when fcntl()/SetHandleInformation() fails, instead of failing silently.
  • FIXED: set_stream/2 close_on_exec silently succeeded on unsupported platforms setCloseOnExec() returned -1 where close-on-exec is unavailable, which set_stream/2 treated as success. Raise a not_implemented(feature, close_on_exec) exception instead and return bool.
  • CLEANUP: remove unused setBoolean() setBoolean() had no callers anywhere in the tree.
  • CLEANUP: int -> bool for boolean by-value function parameters Type the boolean flag parameters of setCloseOnExec(), declareModule() (allow_newfile), PopTty() (do_free), lookupSourceFile()/get_mutex()/ intern_indirect() (create) and trie_intern_indirect() (add) as bool. Callers already pass true/false; the $declare_module local now reads with PL_get_stdbool_ex().
  • CLEANUP: local int -> bool for booleans read with PL_get_stdbool_ex() Convert local int helpers that only hold a two-valued boolean to C11 bool, reading them with the new PL_get_stdbool_ex() instead of PL_get_bool_ex().
  • ADDED: C API support for C11 bool type. This adds PL_get_stdbool(), PL_get_stdbool_ex() and adds the type OPT_STDBOOL to PL_scan_options.

[Jul 15 2026]

  • ENHANCED: Support INRIAs crmath library for correct rounding floats. This patch allows configuration using cmake -DUSE_CRMATH=ON. This downloads and builds the crmath.a library and replaces the explicit up and downward rounding in src/pl-arith.c to achieve a safe interval with correct functions.
  • CLEANUP: use $option/2 instead of raw memberchk/2 for option access in boot Replace memberchk/2 on option lists with the bootstrap $option/2, which also handles dict options. Behaviour is unchanged for classical option lists. Affects load option handling in init.pl, the answer_write_options queries in toplevel.pl and the version tag in messages.pl.
  • ADDED: predicate_options drift check and order-sensitive-access linter - check_raw_option_access/0,1: an opt-in linter (not part of check/0) that reports order-sensitive option handling: raw memberchk/2 on option lists (Category A) and [Opt|Tail] overrides passed to rightmost-wins builtins (Category B). The clause analysis is strengthened accordingly: descend into (If->Then)/(If*->Then), propagate option-list-ness through append/3 and merge_options/3, and seed the declared option arguments of the head. - FIXED: check_predicate_option/3 left a choicepoint despite being det. - A drift check (tests/library/test_predicate_options.pl) verifying that every option in a core C PL_option_t[] array is declared, wired into the swipl:library ctest.
  • ENHANCED: predicate_options declarations for built-in option predicates Mirror the PL_option_t[] arrays of more built-in option predicates in library(dialect/swi/syspred_options): thread_wait/2, thread_update/2, transaction/2, engine_create/4 and the low-level zip predicates. Also complete options that were already scanned by C but not declared, found by the new drift check: open/4 unicode_atoms; read_term/3 var_prefix, back_quotes, quasi_quotations, dotlists, unicode_atoms; read_clause/3 unicode_atoms; write_term/3 dotlists, portrayed, back_quotes, integer_format, float_format; create_prolog_flag/3 local.

[Jul 14 2026]

  • DOC: remove unused code that's the same as the documentation
  • ADDED: #667 phrase_from_file/3: as(Type) argument, phrase_from_stream/3, stream_to_lazy_codes/2 and stream_to_lazy_chars/2 Allow library(pure_input) to work with chars lists as well as codes lists.
  • CLEANUP: drop compileClauseGuarded() and its C_STACK_OVERFLOW_GUARDED wrapper compileBody(), analyseVariables2(), setVars(), compileArgument() and compileArithArgument() no longer recurse on the C stack, so the SIGSEGV-catching guard around the compiler is redundant. Fold compileClauseGuarded() back into compileClause() and remove the cleanupCompile() helper the guard used.
  • ENHANCED: compileArgument() iterative via segstack Fold the recursive argument walk into an explicit state machine over a segstack of ca_frame records. Frame kinds: CA_MIDDLE tracks progress through args[0..N-2] of a compound (advance on resume, or transition to last-arg handling when done); CA_LAST_POP emits the closing H_POP/B_POP after the non-right last-arg sub-compilation. The list right-chain tail-jump (was `goto right_recursion`) becomes a plain `goto next_arg`.
  • ENHANCED: compileArithArgument() iterative via segstack Fold the recursive arithmetic-argument walk into a state machine over a segstack of aa_frame records. Each function application pushes a frame capturing the operator's fdef/index/arity and how many operands are still pending; operands are compiled right-to-left just like the original loop; the closing A_ADD / A_MUL / A_FUNCn is emitted when the last operand completes. Push failure calls outOfCore(), matching the setVars() pattern.

[Jul 13 2026]

  • ENHANCED: setVars() iterative via segstack Walk the term with an explicit segstack of pending arg pointers rather than C-stack recursion. compileBody() calls setVars() on both branches of every disjunction, so deeply nested (A;B;C;...) clauses recursed setVars() to the same depth as the term and overflowed the C stack. Segstack push failure calls outOfCore(), matching the pattern used elsewhere for void-returning term walkers.
  • ENHANCED: analyseVariables2() iterative via segstack Fold the recursive shape into an explicit state machine over a segstack of av_frame records. Frame kinds match the recursive call-sites: AV_ARG_LOOP for the default N-arg descent, AV_SUBCLAUSE_LOOP for the islocal + subclausearg loop, AV_SEMI_AFTER_LEFT / _AFTER_RIGHT for the two-branch semicolon analysis with branch_vars save/restore, and AV_NOT_AFTER for the \+ singleton pass. Depth is tracked in a per-frame field so cycle checks fire on the same paths as before. Segstack allocation failure returns MEMORY_OVERFLOW, which analyse_variables() already turns into an ERR_NOMEM resource_error.
  • ENHANCED: compileBody() iterative via segstack Fold the recursive shape into an explicit state machine over a segstack of resume frames. Each control functor pushes a frame capturing its phase-specific state (saved cut, VarTables, C_JMP/C_OR patch offsets, target_module) and the post-processing to run when the sub-compilation returns. Push failure returns MEMORY_OVERFLOW, which compileClauseGuarded() converts to a resource_error after resetVars() has restored setVarInfo() tags on the stack; the unwind restores ci->colon_context and ci->at_context so the caller sees consistent state.

[Jul 14 2026]

  • FIXED: crash on the debugger "depth" command without argument The default depth was passed as a plain C integer rather than a tagged Prolog word, creating a bogus float term that crashes clause indexing.
  • FIXED: absolute_file_name/3 to enumerate all solutions while loading a file If a file is being loaded, '$chk_file'/5 searches relative to the directory of the file being loaded. This search was guarded by an if-then-else to implement the deprecated fallback to the working directory, killing the choice points of the file candidates. As a result, solutions(all) only produced the first candidate. Now uses a soft cut.

[Jul 13 2026]

  • TEST: Randomised property test for dif/2 Generate a random ground term T with library(random_terms), produce a generalisation G by replacing a random subset of subterms with fresh variables (recorded as V=Value), and optionally alias two of those variables so G also carries a sharing constraint. Post dif(G, T), apply a random plan of matching and/or clash bindings, then require the observed outcome to match the prediction:
  • ENHANCED: dif/2 canonical propagation via unifiable/3 on accumulated lists Reimplement the pending-unifier simplification along the lines flagged by the @tbd in the previous dif_c_c_l/3 comment: instead of dedup-ing Var=Val pairs list-wise, split the pending set into left- and right-hand-side lists and call unifiable/3 to compute a most general unifier for the whole set at once.
  • FIXED: #919 dif/2 loops on cyclic terms The pending unifier stored on an OrNode could contain both X=Y and Y=X for the same pair of unbound variables, because unifiable/3 sometimes returns a chained form (e.g. [E=[], C=E]) alongside a pre-existing reverse entry (E=C). simplify_ornode_/3 sorts by the first argument only, so the reverse-duplicate never becomes adjacent and its dedup clause never fires, driving the algorithm into an infinite oscillation.

[Jul 12 2026]

  • FIXED: Too strict checking in restoreStandardStream() Introduced in 9d40a82ad7fbf8d4f9aa24f72080036db0936705
  • FIXED: WASM build was broken by 3d79bc7caee4c08e941496dfb5f2c70f9b8224d3 This commit modified how the build home is detected, breaking teh WASM build.

[Jul 11 2026]

[Jul 10 2026]

  • FIXED: PL_get_term_value: classify numeric terms; raise on double overflow PL_get_term_value() previously reported PL_INTEGER for rationals and bignums but left val.i as garbage (get_int64 silently misread MPQ storage as MPZ). Now it dispatches via get_number():
  • DOC: CODE_SIGNING: add signtool/osslsigncode verification commands Document the exact commands users can run on Windows, Linux and macOS to verify the Authenticode signature and trusted timestamp on the Windows installer.
  • ADDED: library(random_terms) — random Prolog term generator Generates terms suitable for stress-testing predicates that handle arbitrary structures: variant checks, factorisation, unification, copy vs share, etc. The generator aggressively mixes:

[Jul 6 2026]

  • FIXED: generate INDEX.pl for library files referenced with a source path prefix add_index() skipped any file whose source path contained a '/', which was intended to exclude files destined for library subdirectories. Those are already dispatched through their own PL_LIB_SUBDIR iterations, so the guard only did harm: it also rejected a top-level PL_LIBS file whose source path happens to include a directory component, e.g. swipy's janus/janus.pl. As a result home/library/ext/swipy had no INDEX.pl and the janus predicates were not autoloadable via the index.
  • FIXED: macOS (MacPorts) build: include <xlocale.h> for newlocale()/uselocale() On the MacPorts CommandLineTools MacOSX14.sdk, <locale.h> only declares locale_t/newlocale()/uselocale()/freelocale() when USE_EXTENDED_LOCALES is set (DARWIN_C_LEVEL >= DARWIN_C_FULL). There the feature level ends up below FULL, so the declarations are hidden even though check_function_exists() sets HAVE_NEWLOCALE/HAVE_USELOCALE (the symbols do live in libc). This broke the fill_locale_from_name() code added for #1093.

Package RDF

[Jul 15 2026]

  • CLEANUP: use option/2 for embedded option in rdf.pl Replace memberchk/2 on the option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package archive

[Jul 16 2026]

  • CLEANUP: archive: filters/formats list options + PL_scan_options() Repeating the filter/format option to support multiple filters/formats forced a hand-rolled option loop that accumulates into a mask. Introduce filters(List) and formats(List) options: archive_open/4 now folds any (possibly repeated) filter/compression/format options into these lists in Prolog, raising a deprecation warning for the repeated singular form.

[Jul 15 2026]

  • FIXED: archive_open/4 could leak the file stream on close_parent(false) When archive_open/4 is given a file (not a stream), it opens the file itself and must close it together with the archive. It prepended close_parent(true), but archive_open_stream/4 resolves options rightmost-wins, so a caller-supplied close_parent(false) defeated the override and leaked the stream. Use merge_options/3 so close_parent(true) takes precedence regardless of order.

Package clib

[Jul 16 2026]

  • ENHANCED: process_create/3 uses PL_scan_options() Replace the hand-rolled option loop in parse_options() with PL_scan_options(). detached and window scan as OPT_BOOL and priority as OPT_INT straight into the p_options struct; the remaining options are OPT_TERM so the nested values (pipe(Stream), std, null and the env list) still reach get_stream()/parse_environment() unchanged. Drops the now-unused option-name atoms.
  • CLEANUP: use PL_scan_options() in alarm/4, ossp_uuid/2 and process_wait/3 Convert the hand-rolled option loops:
    • time.c alarm4_gen: remove/install bool flags (removes the now-unused local pl_get_bool_ex helper).
    • uuid.c pl_uuid: version/format and the dns/url/oid/x500 namespace options, scanned as terms for their validation.
    • process.c process_wait: timeout/release, using OPT_UNKNOWN_ERROR to keep raising domain_error on unknown options.

[Jul 15 2026]

  • CLEANUP: modernise clib error handling to use the public C API - Replace context-free pl_error(NULL, 0, NULL, ERR_TYPE|ERR_ARGTYPE| ERR_DOMAIN|ERR_EXISTENCE|ERR_RESOURCE, ...) calls with the equivalent PL_type_error/PL_domain_error/PL_existence_error/PL_resource_error, which report the actual calling predicate as the error context. pl_error() is kept for errno mapping (ERR_ERRNO), ERR_NOTIMPLEMENTED, ERR_SYNTAX and calls carrying an explicit predicate/message context.
    • break_form_argument() now raises errors directly (PL_resource_error / PL_syntax_error) and returns bool instead of ad-hoc ERROR_* integer codes that pl_cgi_get_form() had to map back to exceptions. Removes the ERROR_* defines from form.h. - Type the form-decoding callback (add_to_form/break_form_argument) as bool, matching mp_add_to_form/break_multipart. - Simplify unify_number() with PL_put_term_from_chars(), which takes a length so the value no longer needs copying into a NUL-terminated buffer.
  • CLEANUP: use PL_scan_options() in open_hash_stream/3 Replace the hand-rolled option loop with PL_scan_options(). The algorithm option is scanned as a term and passed straight to get_hash_algorithm/2. Behaviour is unchanged; unknown options follow the unknown_option flag (ignored by default).
  • CLEANUP: use PL_scan_options() in udp_receive/4 and udp_send/4 Replace the hand-rolled option loops with PL_scan_options(), matching the existing pl_host_address() usage in this file. as, encoding and max_message_size are scanned as terms and passed straight to get_as/2, get_representation/2 and the range check. Unknown options follow the unknown_option flag (ignored by default).
  • CLEANUP: use PL_scan_options() in open_memory_file/4 Replace the hand-rolled option loop with PL_scan_options(). The encoding option is scanned as a term and passed straight to get_encoding/2. Behaviour is unchanged; unknown options follow the unknown_option flag (ignored by default).
  • CLEANUP: use PL_scan_options() in sha_hash/3 and friends Replace the hand-rolled option loop with PL_scan_options(). algorithm and encoding are scanned as terms; the algorithm term is reused directly for the HMAC-SHA domain_error. Behaviour is unchanged; unknown options follow the unknown_option flag (ignored by default).
  • CLEANUP: use PL_scan_options() in md5_hash/3 Replace the hand-rolled option loop with PL_scan_options() using the string-name PL_OPTION() form. The encoding option is scanned as a term so its value can be validated and reported in a domain_error without reconstructing it. Behaviour is unchanged; unknown options follow the unknown_option flag (ignored by default).
  • CLEANUP: use option/2 for option access in socket.pl and prolog_server.pl Replace raw memberchk/2 and a member/2 *-> soft-cut idiom on option lists with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package cpp

[Jul 14 2026]

  • DOC: remove unused code that's the same as the documentation

[Jul 11 2026]

Package cql

[Jul 15 2026]

  • CLEANUP: use option/2 for option access in sql_write.pl Replace the ~44 raw memberchk/2 calls on the Options list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package http

[Jul 16 2026]

  • CLEANUP: use PL_scan_options() in stream_range_open/3 and cgi_open/4 Convert the hand-rolled option loops:
    • stream_range.c: size (nonneg) and onclose (a recorded module-qualified callback), scanned as terms.
    • cgi_stream.c: the request option, using OPT_UNKNOWN_ERROR to keep erroring on unknown options.

[Jul 15 2026]

[Jul 12 2026]

  • TEST: proxy: fix startup race between server thread and control assert start_http_proxy/1 and start_socks_server/1 asserted the control record after thread_create/3. If the newly spawned accept-loop reached its first http_proxy_control(_, Self, _) (or \+ socks_control(_, Self, _)) check before the assert committed, the guard flipped, the loop exited, and setup_call_cleanup/3 closed the listening socket — after which the test dialing the proxy port saw ECONNREFUSED. Manifested as sporadic "All TCP connections via HTTP" failures on CI.

[Jul 11 2026]

Package json

[Jul 15 2026]

  • CLEANUP: use option/2 for json_object option in http_json.pl Replace memberchk/2 on the option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package libedit

[Jul 11 2026]

Package mqi

[Jul 15 2026]

  • CLEANUP: use option/2 for unix_domain_socket check in mqi.pl Replace memberchk/2 on the option list with option/2, consistent with the surrounding option/3 calls. Behaviour is unchanged for classical option lists.

[Jul 11 2026]

Package odbc

[Jul 16 2026]

  • DOC: odbc_query/4 options cannot be given as a dict Document that the statement option list is handled by a dedicated routine (needed for the two-argument findall/2 option) and therefore must be a list, not a dict.
  • DOC: note set_statement_options() does not use PL_scan_options() Explain that the option loop is hand-written because findall(Template, Row) is an arity-2 option, and that these options therefore cannot be given as a dict.
  • ENHANCED: odbc_connect/3 uses PL_scan_options() Replace the hand-rolled option loop in pl_odbc_connect() with PL_scan_options(). A value-level get_typed_ex() (and matching get_*_ex() macros) mirror the existing get_*_arg_ex() helpers so the scanned option values keep their original type checks. The five after-connect options (auto_commit, null, access_mode, cursor_type, wide_column_threshold) are rebuilt with PL_cons_functor() and handed to odbc_set_connection() as before.

Package pcre

[Jul 15 2026]

  • CLEANUP: use option/2 for capture_type option in pcre.pl Replace memberchk/2 on the option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package pengines

[Jul 15 2026]

  • CLEANUP: use option/2 for answer option in pengines.pl Replace memberchk/2 on the create-event option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

Package pldoc

[Jul 15 2026]

  • CLEANUP: use option/2 for module/public options in doc_html.pl Replace memberchk/2 on the option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

[Jul 14 2026]

Package plunit

[Jul 15 2026]

  • CLEANUP: use option/2 for fixme option in plunit.pl Replace memberchk/2 on the test option list with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

[Jul 11 2026]

Package semweb

[Jul 16 2026]

  • CLEANUP: use PL_scan_options() in rdf_transaction/3 and the turtle parser Convert the hand-rolled option loops:
    • rdf_db.c rdf_transaction: the snapshot option.
    • turtle.c create_turtle_parser: base_uri, anon_prefix, graph, format and on_error, scanned as terms and applied to the parser state.
    • turtle.c turtle_parse: parse and count.

[Jul 15 2026]

  • CLEANUP: use option/2 for option access in rdf_db.pl Replace raw memberchk/2 on option lists (graph, db, document_language, convert_typed_literal) with option/2, which also accepts Name=Value and dict options. Behaviour is unchanged for classical option lists.

[Jul 11 2026]

Package sgml

[Jul 16 2026]

  • DOC: sgml_parse/2 options cannot be given as a dict Document that the option list is handled by a dedicated routine (needed for the two-argument call(Event, Pred) option) and therefore must be a list, not a dict.
  • DOC: note sgml_parse/2 does not use PL_scan_options() Explain that the option loop is hand-written because call(Type, Goal) is an arity-2 option, and that these options therefore cannot be given as a dict.
  • CLEANUP: use PL_scan_options() in new_sgml_parser/2 and open_dtd/3 Convert the hand-rolled option loops for the dtd option of new_sgml_parser/2 and the dialect option of open_dtd/3. sgml_parse/2 is left hand-rolled: it has a call(Type, Goal) option of arity 2, which PL_scan_options() cannot express.

Package ssl

[Jul 16 2026]

  • ENHANCED: _ssl_context/4 uses PL_scan_options() Replace the hand-rolled first-pass option loop in pl_ssl_context() with PL_scan_options(), using OPT_UNKNOWN_IGNORE so the malleable options still fall through to parse_malleable_options(). The two options whose values are processed in complex ways are refactored into get_crls() and get_cert_key_pairs() helpers that take the value term; password/require_crl scan as OPT_STRING/OPT_BOOL and the remaining values as OPT_TERM. Drops the now-unused option-name atoms and the unused get_file_arg() helper.
  • CLEANUP: use PL_scan_options() in the crypto option loops Convert the hand-rolled option loops in crypto4pl.c:
    • hash_options: algorithm, hmac, close_parent and encoding.
    • parse_options: encoding and padding (the atom-as-encoding shorthand is kept).

[Jul 14 2026]

[Jul 11 2026]

  • FIXED: single-threaded build of crypto4pl crypto_lib_init() sat inside an #ifdef _REENTRANT block but is called unconditionally from install_crypto4pl(). OpenSSL >= 1.1.0 is thread safe, so the guard is dead — drop it and keep the stub compiled in all configurations.

Package swipy

[Jul 7 2026]

  • ENHANCED: `builtins' resolves to the builtins module, not its dict Previously the special-cased atom `builtins' returned PyEval_GetBuiltins(), which is the builtins dict. That worked for arity>=1 calls via builtin_function() (which does dict lookup) but made py_call(builtins:list, X, [py_object(true)]) raise AttributeError, since the dict has no attribute `list'.
  • FIXED: py_call/N leaked exception from the initial-target probe py_eval() probes the first argument as a Python object or module. If that probe failed with an exception (e.g. PyImport_Import("list") raising ModuleNotFoundError) but the fallback builtins path then succeeded, py_call/N returned success with the exception still pending, triggering `did not clear exception'. Propagate the exception instead.

Package tipc

[Jul 15 2026]

  • CLEANUP: use PL_scan_options() in tipc_receive/4 Replace the hand-rolled option loop with PL_scan_options(). as is scanned as a term for its domain check; nonblock uses OPT_BOOL, so it is accepted both as the bare atom and as nonblock(Bool).

Package utf8proc

[Jul 17 2026]

  • BUILD: doc generation racing ahead of foreign plugin builds

[Jul 16 2026]

  • CLEANUP: use PL_scan_options() for the unicode mapping flags get_map_mask() accepted a list of bare atom flags (stable, compose, ...) OR-ed into a mask. These are now scanned with PL_scan_options() as arity-0 OPT_BOOL options (so a flag may also be written flag(true)), using OPT_UNKNOWN_ERROR to keep raising domain_error(unicode_mapping, _) on an unknown flag. An integer mask is still accepted directly.

Package xpce

[Jul 19 2026]

  • CLEANUP: Changed timer time to num (was real) and use xpce int for SDL reference.
  • ENHANCED: timer: keep a scheduled timer alive and destroy it when done A scheduled timer now holds a code reference to itself, so a timer that is not referenced from elsewhere can simply be created and started:
  • FIXED: toc_directory: crash if the directory disappeared ->update deletes the node if its directory no longer exists (common under e.g. /proc), after which ->refresh and ->expand_all continued to use the freed node.
  • ENHANCED: Prolog Navigator: virtual root for multiple Windows drives If the loaded source files have no common directory because they are spread over multiple Windows drives, the new class toc_roots provides a virtual root ("This computer") holding these drives. Pressing "up" on a drive root now creates this node as well.
  • ENHANCED: Prolog Navigator starts from the loaded source files The Navigator is now rooted at the common directory of all loaded source files and initially shows only the loaded files and the directories leading to them, rather than browsing the file system from the working directory.

[Jul 18 2026]

  • ENHANCED: Windows: flat scroll bars with a thin thumb The `win' look now fills the trough with the light system colour and draws the thumb in a darker shade at about 1/5th of the width of the scroll bar, widening to 1/3th while the pointer is inside the bar. This replaces the dark trough with a raised 3-D bubble and is much closer to the native Windows look.
  • FIXED: SDL: generate area_enter and area_exit events for windows SDL only reports enter and leave for its native windows, which are our frames. As xpce windows never received these events, PceWindow <->has_pointer was never updated and the <->pointed chain of a window was only maintained as long as the pointer stayed in the same window.

[Jul 13 2026]

  • FIXED: Epilog terminal wide glyph right half wiped by placeholder r_clear The paint-run segmentation in rlc_paint_text() split segments on flags.raw, but a wide char's base has flags.width=2 while its code-0 placeholder has flags.width=0, so base and placeholder ended up in separate segments. The placeholder's own r_clear/paint step (chunk width = cw) then wiped the right half of the glyph the base had just drawn. The same latent split applies to width-0 combining marks following their base. Followers (code==0 placeholders or width==0 combiners) now stay in the current base's segment regardless of flags.raw, since they inherit the base's styling and armed status.
  • FIXED: Epilog terminal draws BMP symbol glyphs (dingbats, misc symbols) as 2 cells uchar_display_width() classifies from static Unicode tables + host wcwidth, which reports width 1 for BMP symbol blocks (Dingbats U+2700-U+27BF, Misc Symbols U+2600-U+26FF, Misc Technical, some arrows) that emoji-presenting fonts actually render at ~2 cells wide, breaking the terminal grid. rlc_put() now consults the font's own measured advance via c_width() when the static classification is width 1 and the char is non-ASCII, promoting to width 2 when the glyph exceeds 1.5x the base cell width. Reuses the SDL font's existing lazy per-code-point width cache, so the Pango measurement happens at most once per (font, char).

[Jul 12 2026]

  • CLEANUP: Remove hacks to redirect xpce messages to Epilog. As we now rebind the main thread user_output and user_error streams, we no longer need hacks to redirect messages printed by xpce. If such messages are generated in a thread, they are printed in the Epilog console of that thread. If they are generated in the main (gui) thread, they are redirected to the main Epilog console. Deleting this console causes subsequent output to go to the process stdout/stderr streams.
  • ENHANCED: Rebind main thread output to Epilog window. Rather than intercepting print_message/2 to redirect messages from the GUI (main) thread to the Epilog console, we rebind the user_output and user_error of the main thread to the main Epilog console.
  • ADDED: date<-time_zone and date<-dst; use numeric offset in <-rfc_string <-time_zone returns the local zone as a numeric offset (default) or as the abbreviation (with @on). <-dst reports whether daylight-saving time is in effect. <-rfc_string now emits the numeric offset, matching RFC 5322 3.3 which obsoletes zone abbreviations.

[Jul 11 2026]

[Jul 10 2026]

  • FIXED: xpce numeric conversion: rationals, bignums, fractional nums Two related fixes plus a test suite:
  • ADDED: xdot_group url slot populated from graphviz URL/href Nodes and edges now expose their graphviz URL attribute (or its href alias) as a url slot. Click handlers wired via <-node_clicked and <-edge_clicked can fetch it with get(Group, url, URL).
  • ADDED: Random terms demo Uses library(random_terms) with library(graphviz_term) to generate random Prolog terms and visualise them as graphs. A dialog exposes the generator parameters as sliders (int/float) plus text_items for functors and atoms. The xdot_window is configured with natural_zoom 1.5 so small terms fill the pane.
  • ADDED: library(graphviz_term), converting Prolog terms into `.dot` files Emits Graphviz digraphs where each compound is a node whose HTML label (shape=plaintext, `<TABLE>/<TD PORT="aN">`) carries a soft pastel palette: a bold steel-blue functor cell plus per-primitive- type backgrounds for integer, float, rational, atom, string, var, and shared / cyclic back-references. Colours can be overridden by redefining type_color/2.
  • ENHANCED: xdot_window: <->natural_zoom slot for ->fit Adds a natural_zoom slot (num, default 1.0). ->fit uses it as the preferred scale: when the graph fits the visible area at natural_zoom that scale is used; otherwise ->fit falls back to the shrink-to-fit behaviour. Setting natural_zoom above 1.0 lets small graphs be enlarged on ->fit.
  • REMOVED: library(pce_edit), providing pce_edit/1. Editing xpce objects is provided by the hookable edit/1 infrastructure.

[Jul 9 2026]

  • ADDED: library(xdot) + demo — graphviz pan/zoom viewer New Prolog library and xpce demo that renders graphviz-laid-out graphs as XPCE graphicals.
  • FIXED: edit/1 support for xpce classes.
  • ENHANCED: colour: <-fade(factor) — same RGB with alpha multiplied New send/get method colour<-fade(factor=[0.0..1.0]) -> colour returns a colour with the same RGB and alpha := alpha * factor, clamped to 0..255. Complements <-hilite and <-reduce; uses the same associateColour caching so repeated calls with the same factor return the same object.
  • ENHANCED: ellipse, circle: shape-precise ->in_event_area + ->inside Share ellipseNormDistance() (in ellipse.c, exported via proto.h): the normalised distance of a point from the centre of the ellipse inscribed in an axis-aligned bounding box. <= 1 means inside; semi-axes clamped to 1 to survive degenerate 0-width shapes.
  • ENHANCED: path: precise event hit-test, ->inside, ref manual Register inEventAreaPath via setInEventAreaFunctionClass so events land on the actual path rather than its bounding rectangle:
  • ENHANCED: bezier_curve: precise event hit-test on the curve Register inEventAreaBezier via setInEventAreaFunctionClass so the graphical class dispatcher runs a shape-accurate hit test after the bounding-box pre-filter, mirroring what class line already does with inEventAreaLine.
  • ADDED: xpce: class gradient with cairo linear/radial rendering Native cairo-backed gradient class usable as fill_pattern:

[Jul 8 2026]

  • FIXED: pan_zoom: zoom around cursor when figure isn't at (0,0) The zoom formula used the cursor position in window coords as the fixed point, which only matches the figure's origin when the figure is displayed at (0,0). Subtract the figure's display position so the scale pivots on the actual cursor location regardless of where the figure lives in its parent.

Package yaml

[Jul 16 2026]

  • CLEANUP: use PL_scan_options() in yaml_emitter_create/3 Convert the hand-rolled option loop for the canonical and unicode options, scanned as terms so the "unicode defaults to true when not given" behaviour is preserved.

Package zlib

[Jul 15 2026]

  • CLEANUP: use PL_scan_options() in zopen/3 Replace the hand-rolled option loop with PL_scan_options(). format and level are scanned as terms for their domain checks; close_parent and multi_part use OPT_BOOL.