Port onto libakstdlib 2b79aca and convert the eight bool predicates (libakstdlib#26) #31
Reference in New Issue
Block a user
Delete Branch "libakstdlib-26"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ports
src/onto libakstdlib2b79acaand converts the eight sites the earlier port left on raw libc.This is the akbasic half of libakstdlib#26, and it carries @andrew's instruction on libakstdlib#38 (comment 1105) — "fix the akbasic port branch and reference this discussion". The libakstdlib half is libakstdlib#39.
mainat330d731Same tree in both rows, so the rate is like-for-like.
deps/libakstdlibbumped669b2b3→2b79aca; the bump itself needed no source change — the release is drop-in for what akbasic already used.The ruling this implements
libakstdlib#38 was filed claiming a
boolpredicate had no way to call anAKERR_NOIGNOREfunction. @andrew ruled it invalid (comment 1095):So the signatures change. Seven of the eight now return
akerr_ErrorContext *and hand the answer back through an out parameter — the shapesymtab.c'sprobe()andruntime_structure.c'sloop_continues()already used.structtype.cword_is(w, k, bool *dest)FAIL_ZERO_RETURNsplit intoPASS+FAIL_ZERO_RETURN(errctx, ok, ...)environment.cakbasic_environment_is_waiting_for(env, cmd, bool *dest)include/akbasic/environment.h. Its twin_is_waiting_for_anymoves with it or the pair is inconsistent.runtime.c's&&term hoisted out of its condition; 6 assertions intests/environment_scope.cscanner.cis_at_end(rt, bool *dest)strlenbecameaksl_strlenscanner.cpeek_next(rt, char *dest, bool *got)char *deststays; theboolmoves to a second out-paramverbs.cverb_compareformat.coverflowakerr_ErrorContext *(dest, width)render_numeric; onePASSeachsink_akgl.cscrollakerr_ErrorContext *sink_akgl.cnewlineakerr_ErrorContext *Four more functions were not in the original eight but sit on the same chains and could not stay behind:
scanner.cpeekandmatch_next_char, andsink_akgl.cputchar_at,echo_lineandedit_key. Every call site that used one of these as a term in anifor a loop condition is now a hoist into the body.The eighth stays, deliberately
verbs.c:200verb_compareremains onstrcmp.bsearch(3)fixes the comparator's signature atint (*)(const void *, const void *), so there is no out parameter to report an error through — which is exactly what libakstdlib#38 concluded. Converting it means droppingbsearchfor an in-house binary search, on a lookup that runs once per scanned identifier. The site now carries a comment saying that, and saying why the bypass is safe there: both arguments are a NUL-terminated local and a string literal in the static table, so neither can be NULL or unterminated.libakstdlib#38 cites this as tracked in akbasic #14. That is a mis-citation — #14 is the
COLLISION/BUMPpairing threshold. Nothing currently tracks the comparator; worth filing before anybody acts on it.What is left, and why
7 bypasses, down from a projected 13. Six are
snprintfsites that want truncation as an answer rather than an error, whichaksl_snprintfcannot express — it raisesAKERR_OUTOFBOUNDSand zeroes itscount. Tracked as libakstdlib#34. Each site says so inline.The sharpest is
runtime.c:396akbasic_runtime_error, which formats a 12,384-byte error message into a 512-byte line. A report may be shortened; it may not be replaced by a second, different failure — that function is the one that tells the user what went wrong.runtime_struct.c:216is the other interesting one: it readssnprintf's return value to detect truncation, which is what makes the field loop and the closing)both skip.Two of the three in
host.care a latent defect rather than a decision, and are flagged rather than fixed. A host-registered type name over 31 characters truncates silently, and two names sharing a 31-character prefix then collide inakbasic_structtype_find— wherestructtype.c'sscan_names()refuses the identical case outright with a limit message. The script-declared and host-registered paths disagree. Fixing it is a behaviour change on a public registration call and wants its own issue.A defect this turned up rather than caused
DLOADleaked a file descriptor. Its read loop sat inside anATTEMPTblock, and thePASSin it returned pastCLEANUP— so a scan error left the file open. The comment there defendedPASSoverCATCHand missed that both are illegal in a loop inside anATTEMPT. Convertingfgetsrequired hoisting the loop into its own helper, which fixes it.DSAVEandDVERIFYhad the same shape and got the same treatment.Verification
-Wall -Wextra; 112/112 ctest.-DAKBASIC_SANITIZE=ON).*_akgl.cfiles could not be built here — SDL3 needs X11/Wayland dev packages this box does not have. Unlike the previous attempt they are not unverified: all five aregcc -fsyntax-only -Wall -Wextraclean under-DAKBASIC_WITH_AKGL=1against stubbed generated headers. That checks syntax and types, not behaviour, so the AKGL configuration still wants a real CI build —sink_akgl.ccarries the deepest signature change in the diff and none of it has executed.Semantic changes worth a reviewer's eye
aksl_strcpyrefuses rather than truncates, andaksl_atoifails on trailing junk where rawatoireturned 0. Both surfaced places where the old silent behaviour was already broken:runtime_ui.candruntime_input.ccopied a 256-byte identifier into a 64-byte buffer. The truncated name then failed the later lookup with "could not reach the variable"; it now refuses early with a name-too-long error instead.SPRSAVon a hand-built"SHAPE:x"string used to yield handle 0 silently.Neither is reachable from any in-tree BASIC program, and the suite is green, but both are behaviour changes rather than refactors.
Closes nothing on its own — libakstdlib#26 is closed by libakstdlib#39, which carries the recount this branch produced.
Filed by Tachikoma (Claude Code, Opus 5, 1M context)
@logikoma review this merge request and make comments please
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.