Ann: SWI-Prolog 10.1.12

Dear SWI-Prolog users,

SWI-Prolog 10.1.12 is ready for download. The list of changes is
extensive. Please test as some regression is not unlikely, notably
on Windows. Highlights:

Core

  • Windows file name case handling has been changed from downcase
    to use disk case (case preserving). You can restore the old
    behaviour using swipl -Dfile_name_case_handling=case_insensitive.

  • Fixed Windows arithmetic flaw: expressions that contains big
    numbers and whose result fits in a tagged integer, but not
    in a 32-bit Windows long remained big integers. Numerically,
    these are the same as their canonical tagged counterpart, but
    they fail on unification and ==/2.

  • Support INRIAs crmath library for correct rounding floats.
    This patch allows configuration using cmake -DUSE_CRMATH=ON.

  • Option processing now uses library(option) or the C API
    consistently. This allows for using dicts for options everywhere.
    This patch also completes the predicate_options/1 declarations and
    extends the linter to find suspicious operations on options lists.
    These are preparing steps to resolve the ordering issue with
    option lists.

  • The compiler (also assert/1, etc.) now avoids C stack recursion.
    This allows it to compile much deeper nested structures and raise
    a proper resource_error(memory) exception when running out of
    memory.

  • phrase_from_file/3 got as(chars) option to call DCGs compiled to
    process literals as character lists.

  • Fixed crash in debugger on using d as command (set print depth).

  • Fixed (hopefully) dif/2 on (some) cyclic terms as well as avoid
    non-termination on some unifications.

  • Added push_prolog_flag/2 and pop_prolog_flag/1 (Ciao compatible).

  • Added library(random_terms) to generate complex terms with
    controlled properties and probabilities.

  • Fixed auto-loading Janus (py_*) predicates.

  • Added code-signing for Windows. Actual signing waits for approval
    of the current process by SignPath. Hopefully next release.

Packages

  • archive_open/4 now uses a filters(+List) and formats(+List) option
    instead of repeating filter(+Filter) and format(+Format). Backward
    compatibility is implemented.

  • library(crypto) got support for Ed25519 signatures. Fixed compilation
    using modern OpenSSL for single threading.

  • Janus now provides access to built-in classes as builtins:<class>.
    Fix for lost exception in invalid py_call/3.

GUI

  • Added library(xdot) and demo. This uses Graphviz (dot) for
    rendering graphs and display them in an xpce window. Provides
    panning and zooming as well as clicking and menus on nodes and
    edges.

  • To support the above, library(pan_zoom) got a fix and several
    graphical classes now have more precise event hit testing. Also
    added support for colour gradient filling.

  • Fixed transferring rational numbers to xpce (as floats).

  • Cleanup relaying printing from the xpce thread (main) to the
    first Epilog console. Simpler and also handles normal write to
    these streams.

  • Improve handling of BMP symbol glyphs (dingbats, misc symbols)
    in Epilog.

  • Prettier scroll bars on Windows.

    Enjoy — Jan

SWI-Prolog Changelog since version 10.1.11

  • 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

  • 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.

  • 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.

  • 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.

  • 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.

  • 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.

  • 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.

  • 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.

  • 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.

  • 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.

  • FIXED: single-threaded build of push_prolog_flag/2 and pop_prolog_flag/1
    copy_prolog_flag() was defined only under O_PLMT but is called
    unconditionally by push_prolog_flag/2. Move the guard so it is
    compiled in all configurations. Also move the now-unused in_local
    tracking in pop_prolog_flag/1 inside the O_PLMT block.

  • ENHANCED: use push_prolog_flag/2 for xref-flag scoping
    boot/autoload.pl exports/5, library/prolog_xref.pl with_xref/1 and
    library/prolog_source.pl read_directives. Drops the fallback for
    “xref flag might not exist” and the state term threading OldXref,
    both handled by push/pop.

  • ADDED: push_prolog_flag/2 and pop_prolog_flag/1 Thread-local, nestable
    save/restore of Prolog flag values. Both go through the existing
    set_prolog_flag/2 code path, so type checks, read-only checks,
    thread-local COW, and side effects (character escapes, module bits,
    boolean fast mask, …) stay consistent. The push stack lives
    inside the prolog_flag struct as a linked list of snapshot frames.
    A FF_PUSH_ABSENT sentinel records that the flag did not exist at push
    time; pop then removes the local entry.

  • 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:

  • 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

  • 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

  • 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.

  • 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

  • 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.
  • 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

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

  • ENHANCED: use push_prolog_flag/2 for stack_limit save/restore in
    with_small_stacks/2 Depends on push_prolog_flag/2 and pop_prolog_flag/1
    in swipl-devel.

Package cql

  • 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

  • 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.
  • CLEANUP: use PL_scan_options() in http stream filters; drop http_error.c
    Convert the hand-rolled option loops of http_chunked_open/3,
    multipart_open/3 and ws_open/3 to PL_scan_options(). Remove
    http_error.c: its type/domain/existence/permission/instantiation_error
    and get_int_ex helpers are replaced by the public
    PL_*_error()/PL_get_integer_ex() API, and the debug hook
    (http_stream_debug/1) moves into http_stream.c.

  • CLEANUP: use option/2 for option access in http predicates Replace
    raw memberchk/2 (and a member/2 *-> idiom) on option lists with
    option/2, which also accepts Name=Value and dict options. Files:
    http_parameters.pl, http_dispatch.pl, thread_httpd.pl, ax.pl and
    http_pwp.pl. Sites that inspect non-option lists, multi-argument
    options or backtrack over repeated terms are left on memberchk/2
    and member/2.

  • 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.

  • TEST: proxy: factor shared shutdown into stop_control_thread/4
    Both stop_http_proxy_server/0 and stop_socks_server/1 do the same
    close(ControlWrite) / tcp_connect wake / thread_join dance to shut
    down their worker thread. Extract it into stop_control_thread/4.

Package json

  • 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

  • ENHANCED: use push_prolog_flag/2 in with_quote_flags/3 Depends on
    push_prolog_flag/2 and pop_prolog_flag/1 in swipl-devel.

Package mqi

  • 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.

  • ENHANCED: use push_prolog_flag/2 for tmp_dir save/restore Also fixes
    the case where tmp_dir is not currently set: the previous code would
    fail on current_prolog_flag/2. push_prolog_flag/2 handles the absent
    case and pop_prolog_flag/1 removes the flag again.

Package odbc

  • 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

  • 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

  • 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

  • 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.

  • FIXED: #45 doc_htmlsrc source view leaking / into rendered
    structured comments In source_to_html/3, /
    * … */ fragments
    produced by colour_fragments/2 include the trailing newline after /.
    end_of_comment//1 in doc_wiki.pl matched "
    /" but did not consume
    trailing whitespace, so phrase/2 failed and split_lines//2 backtracked
    to render */ as an ordinary content line at the end of the rendered
    comment block.

Package plunit

  • 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.

  • ENHANCED: use push_prolog_flag/2 for occurs_check in run_test_once/6
    Depends on push_prolog_flag/2 and pop_prolog_flag/1 in swipl-devel.

Package semweb

  • 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.
  • 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.

  • ENHANCED: use push_prolog_flag/2 for agc_margin save/restore rdf_load/2
    and no_agc/1 (rdf_persistency).

Package sgml

  • 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

  • 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).
  • MODIFIED: ed25519_sign/4 and ed25519_verify/4 default to encoding(utf8)
    This matches Scryer Prolog. Unlike ecdsa_sign/4 and rsa_sign/4,
    which default to hex because they are typically applied to a hash
    of the data, Ed25519 signs the data itself.

  • TEST: Ed25519 and X25519 against the RFC 8032 and RFC 7748 test
    vectors Also documents the new predicates in the crypto library manual.

  • ADDED: load_private_key/3 and load_public_key/2 support
    Ed25519 and X25519 Ed25519 private keys are unified as
    private_key(ed25519(KeyPair)), where KeyPair is the hexadecimal PKCS#8
    v2 key pair that ed25519_sign/4 of library(crypto) accepts. X25519 keys
    are unified as x25519(Hex), which curve25519_scalar_mult/3 accepts.
    This allows using keys created with openssl genpkey -algorithm ed25519
    (or x25519).

  • ADDED: #156 Ed25519 signatures and X25519 key exchange library(crypto)
    now provides ed25519_new_keypair/1, ed25519_seed_keypair/2,
    ed25519_keypair_public_key/2, ed25519_sign/4, ed25519_verify/4,
    curve25519_generator/1 and curve25519_scalar_mult/3. The API is
    that of Scryer Prolog’s library(crypto). Key pairs are PKCS#8 v2
    (RFC 8410), the format used by openssl genpkey -algorithm ed25519.

  • 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

  • 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

  • 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

  • BUILD: doc generation racing ahead of foreign plugin builds

  • 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

  • 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.

  • 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.

  • 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).

  • 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.

  • FIXED: Non-functioning Epilog Help/GUI demos menu. The code behind
    this item was broken and a functioning entry is in the GUI menu.

  • ADDED: xdot->load to accept either a file or a string. Instead, we
    pipe the string through graphviz, This now used by random_terms_demo.pl
    to avoid the need for temporary files.

  • ENHANCED: use push_prolog_flag/2 for flag scoping with_hyperlink_term/1
    (epilog.pl) and auto_call/1 (swi_compatibility.pl, autoload flag).

  • 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.

  • 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:

  • 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

  • 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

  • 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.
1 Like