Compare commits

...

3 Commits

Author SHA1 Message Date
Julian Noble faa459f572 punkzip PROVENANCE.md: relative sibling-checkout convention replaces the dev-machine absolute path 2 days ago
Julian Noble 2c1dec100e CRLF hygiene ahead of the fossil catch-up: glob the vendored sdx patches, LF two strays 3 days ago
Julian Noble 03306be068 argparsingtest 1.3.0: opt, cmdline and tepam are optional, not module-level requires 3 days ago
  1. 5
      .fossil-settings/crlf-glob
  2. 8
      src/buildsuites/suite_tcl86/src/main.zig
  3. 334
      src/modules/argparsingtest-999999.0a1.0.tm
  4. 5
      src/modules/argparsingtest-buildversion.txt
  5. 6
      src/modules/oolib-buildversion.txt
  6. 88
      src/tests/modules/argparsingtest/testsuites/argparsingtest/argparsingtest.test
  7. 29
      src/tools/punkzip/PROVENANCE.md

5
.fossil-settings/crlf-glob

@ -3,8 +3,11 @@
#kit payloads, and vendored-tool test fixtures (vendor/payload files keep their #kit payloads, and vendored-tool test fixtures (vendor/payload files keep their
#upstream endings; the LF preference in root AGENTS.md governs authored text #upstream endings; the LF preference in root AGENTS.md governs authored text
#files, not these trees). punkzip's hamlet.txt fixture is CRLF byte-exact test #files, not these trees). punkzip's hamlet.txt fixture is CRLF byte-exact test
#data - its compression tests pin sizes against it. #data - its compression tests pin sizes against it. suite_tcl86's patches/ holds
#vendored sdx sources (Matt Newman / Jean-Claude Wippler) plus the patch file
#derived from them - upstream CRLF, kept byte-exact so the patch applies.
src/embedded/* src/embedded/*
src/vendorlib/* src/vendorlib/*
src/vfs/* src/vfs/*
src/tools/punkzip/src/fixtures/* src/tools/punkzip/src/fixtures/*
src/buildsuites/suite_tcl86/patches/*

8
src/buildsuites/suite_tcl86/src/main.zig

@ -1,4 +1,4 @@
const std = @import("std"); const std = @import("std");
pub const _start = void; pub const _start = void;
pub const WinMainCRTStartup = void; pub const WinMainCRTStartup = void;

334
src/modules/argparsingtest-999999.0a1.0.tm

@ -50,15 +50,28 @@
package require Tcl 8.6- package require Tcl 8.6-
package require punk::args package require punk::args
package require opt
package require cmdline # Every parser package this module compares is OPTIONAL, including the tcllib ones.
package require tepam # A comparison harness that cannot load at all because one of the libraries it
# compares is absent is useless on exactly the runtime you most want to measure -
# and punkshell builds do ship without tcllib. A missing library must degrade to a
# not_loaded row (see the {optional <pkg>} roster markers), never to a load failure.
# Guarded here rather than at the call sites because the guard needed differs:
# cmdline - used only INSIDE proc bodies, so the requires below are the whole story
# opt - tcl::OptProc DEFINES the wrapper procs, so each definition site is
# tepam additionally guarded by an 'is the package present' test. Those sites
# test presence rather than catching, so a genuine error in a spec still
# surfaces loudly on a runtime that does have the package.
# argp, parse_args and argparse are required further down, at their own sites.
catch {package require opt}
catch {package require cmdline}
catch {package require tepam}
#*** !doctools #*** !doctools
#[item] [package {Tcl 8.6}] #[item] [package {Tcl 8.6}]
#[item] [package {punk::args}] #[item] [package {punk::args}]
#[item] [package {opt}] #[item] [package {opt}] (optional - parser under test)
#[item] [package {cmdline}] #[item] [package {cmdline}] (optional - parser under test)
#[item] [package {tepam}] #[item] [package {tepam}] (optional - parser under test)
# #package require frobz # #package require frobz
# #*** !doctools # #*** !doctools
@ -163,13 +176,13 @@ namespace eval argparsingtest {
punkargs_by_id always punkargs_by_id always
punkargs_parsecache always punkargs_parsecache always
punkargs_validate_ansistripped always punkargs_validate_ansistripped always
opt always opt {optional opt}
cmdline_untyped always cmdline_untyped {optional cmdline}
cmdline_typed always cmdline_typed {optional cmdline}
argp {optional argp} argp {optional argp}
parse_args {optional parse_args} parse_args {optional parse_args}
argparse {optional argparse} argparse {optional argparse}
tepam always tepam {optional tepam}
} }
} }
tkstyle { tkstyle {
@ -180,8 +193,8 @@ namespace eval argparsingtest {
punkargs always punkargs always
punkargs_by_id always punkargs_by_id always
punkargs_parsecache always punkargs_parsecache always
opt always opt {optional opt}
tepam always tepam {optional tepam}
argparse {optional argparse} argparse {optional argparse}
cmdline_untyped unsupported cmdline_untyped unsupported
cmdline_typed unsupported cmdline_typed unsupported
@ -197,10 +210,10 @@ namespace eval argparsingtest {
punkargs always punkargs always
punkargs_by_id always punkargs_by_id always
punkargs_parsecache always punkargs_parsecache always
opt always opt {optional opt}
cmdline_untyped always cmdline_untyped {optional cmdline}
cmdline_typed always cmdline_typed {optional cmdline}
tepam always tepam {optional tepam}
parse_args {optional parse_args} parse_args {optional parse_args}
argparse {optional argparse} argparse {optional argparse}
argp unsupported argp unsupported
@ -214,7 +227,7 @@ namespace eval argparsingtest {
punkargs always punkargs always
punkargs_by_id always punkargs_by_id always
punkargs_parsecache always punkargs_parsecache always
opt always opt {optional opt}
argparse {optional argparse} argparse {optional argparse}
cmdline_untyped unsupported cmdline_untyped unsupported
cmdline_typed unsupported cmdline_typed unsupported
@ -1494,24 +1507,27 @@ namespace eval argparsingtest::opts {
-join -type none -multiple 1 -join -type none -multiple 1
}] }]
} }
tcl::OptProc opt { #tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
{-return string "return type"} if {![catch {package present opt}]} {
{-frametype \uFFEF "type of frame"} tcl::OptProc opt {
{-show_edge \uFFEF "show table outer borders"} {-return string "return type"}
{-show_seps \uFFEF "show separators"} {-frametype \uFFEF "type of frame"}
{-join "solo option"} {-show_edge \uFFEF "show table outer borders"}
{-x "" "x val"} {-show_seps \uFFEF "show separators"}
{-y b "y val"} {-join "solo option"}
{-z c "z val"} {-x "" "x val"}
{-1 1 "1val"} {-y b "y val"}
{-2 -int 2 "2val"} {-z c "z val"}
{-3 -int 3 "3val"} {-1 1 "1val"}
} { {-2 -int 2 "2val"}
set opts [dict create] {-3 -int 3 "3val"}
foreach v [info locals] { } {
dict set opts $v [set $v] set opts [dict create]
foreach v [info locals] {
dict set opts $v [set $v]
}
return $opts
} }
return $opts
} }
#cmdline::getoptions is much faster than typedGetoptions #cmdline::getoptions is much faster than typedGetoptions
@ -1736,22 +1752,25 @@ namespace eval argparsingtest::opts {
-join -type none -multiple 1 -join -type none -multiple 1
}] }]
} }
tepam::procedure {tepam} { #tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
-args { if {![catch {package present tepam}]} {
{-return -type string -default string} tepam::procedure {tepam} {
{-frametype -type string -default \uFFEF} -args {
{-show_edge -type string -default \uFFEF} {-return -type string -default string}
{-show_seps -type string -default \uFFEF} {-frametype -type string -default \uFFEF}
{-join -type none -multiple} {-show_edge -type string -default \uFFEF}
{-x -type string -default ""} {-show_seps -type string -default \uFFEF}
{-y -type string -default b} {-join -type none -multiple}
{-z -type string -default c} {-x -type string -default ""}
{-1 -type boolean -default 1} {-y -type string -default b}
{-2 -type integer -default 2} {-z -type string -default c}
{-3 -type integer -default 3} {-1 -type boolean -default 1}
} {-2 -type integer -default 2}
} { {-3 -type integer -default 3}
return [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join] }
} {
return [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]
}
} }
#*** !doctools #*** !doctools
@ -1967,28 +1986,31 @@ namespace eval argparsingtest::tkstyle {
-join -type none -multiple 1 -join -type none -multiple 1
}] }]
} }
tcl::OptProc opt { #tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
{p1 -string "first positional argument"} if {![catch {package present opt}]} {
{p2 -string "second positional argument"} tcl::OptProc opt {
{-return string "return type"} {p1 -string "first positional argument"}
{-frametype \uFFEF "type of frame"} {p2 -string "second positional argument"}
{-show_edge \uFFEF "show table outer borders"} {-return string "return type"}
{-show_seps \uFFEF "show separators"} {-frametype \uFFEF "type of frame"}
{-join "solo option"} {-show_edge \uFFEF "show table outer borders"}
{-x "" "x val"} {-show_seps \uFFEF "show separators"}
{-y b "y val"} {-join "solo option"}
{-z c "z val"} {-x "" "x val"}
{-1 1 "1val"} {-y b "y val"}
{-2 -int 2 "2val"} {-z c "z val"}
{-3 -int 3 "3val"} {-1 1 "1val"}
} { {-2 -int 2 "2val"}
set opts [dict create] {-3 -int 3 "3val"}
foreach v [info locals] { } {
if {$v ni {p1 p2 opts args Args}} { set opts [dict create]
dict set opts $v [set $v] foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
}
} }
return [list $p1 $p2 $opts]
} }
return [list $p1 $p2 $opts]
} }
namespace eval argdoc { namespace eval argdoc {
@ -2015,25 +2037,28 @@ namespace eval argparsingtest::tkstyle {
-join -type none -multiple 1 -join -type none -multiple 1
}] }]
} }
tepam::procedure {tepam} { #tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
-named_arguments_first 0 if {![catch {package present tepam}]} {
-args { tepam::procedure {tepam} {
{p1 -type string} -named_arguments_first 0
{p2 -type string} -args {
{-return -type string -default string} {p1 -type string}
{-frametype -type string -default \uFFEF} {p2 -type string}
{-show_edge -type string -default \uFFEF} {-return -type string -default string}
{-show_seps -type string -default \uFFEF} {-frametype -type string -default \uFFEF}
{-join -type none -multiple} {-show_edge -type string -default \uFFEF}
{-x -type string -default ""} {-show_seps -type string -default \uFFEF}
{-y -type string -default b} {-join -type none -multiple}
{-z -type string -default c} {-x -type string -default ""}
{-1 -type boolean -default 1} {-y -type string -default b}
{-2 -type integer -default 2} {-z -type string -default c}
{-3 -type integer -default 3} {-1 -type boolean -default 1}
} {-2 -type integer -default 2}
} { {-3 -type integer -default 3}
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]] }
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
}
} }
namespace eval argdoc { namespace eval argdoc {
@ -2296,28 +2321,31 @@ namespace eval argparsingtest::tclstyle {
p2 -type string -optional 0 p2 -type string -optional 0
}] }]
} }
tcl::OptProc opt { #tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
{-return string "return type"} if {![catch {package present opt}]} {
{-frametype \uFFEF "type of frame"} tcl::OptProc opt {
{-show_edge \uFFEF "show table outer borders"} {-return string "return type"}
{-show_seps \uFFEF "show separators"} {-frametype \uFFEF "type of frame"}
{-join "solo option"} {-show_edge \uFFEF "show table outer borders"}
{-x "" "x val"} {-show_seps \uFFEF "show separators"}
{-y b "y val"} {-join "solo option"}
{-z c "z val"} {-x "" "x val"}
{-1 1 "1val"} {-y b "y val"}
{-2 -int 2 "2val"} {-z c "z val"}
{-3 -int 3 "3val"} {-1 1 "1val"}
{p1 -string "first positional argument"} {-2 -int 2 "2val"}
{p2 -string "second positional argument"} {-3 -int 3 "3val"}
} { {p1 -string "first positional argument"}
set opts [dict create] {p2 -string "second positional argument"}
foreach v [info locals] { } {
if {$v ni {p1 p2 opts args Args}} { set opts [dict create]
dict set opts $v [set $v] foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
}
} }
return [list $p1 $p2 $opts]
} }
return [list $p1 $p2 $opts]
} }
namespace eval argdoc { namespace eval argdoc {
@ -2439,24 +2467,27 @@ namespace eval argparsingtest::tclstyle {
p2 -type string -optional 0 p2 -type string -optional 0
}] }]
} }
tepam::procedure {tepam} { #tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
-args { if {![catch {package present tepam}]} {
{-return -type string -default string} tepam::procedure {tepam} {
{-frametype -type string -default \uFFEF} -args {
{-show_edge -type string -default \uFFEF} {-return -type string -default string}
{-show_seps -type string -default \uFFEF} {-frametype -type string -default \uFFEF}
{-join -type none -multiple} {-show_edge -type string -default \uFFEF}
{-x -type string -default ""} {-show_seps -type string -default \uFFEF}
{-y -type string -default b} {-join -type none -multiple}
{-z -type string -default c} {-x -type string -default ""}
{-1 -type boolean -default 1} {-y -type string -default b}
{-2 -type integer -default 2} {-z -type string -default c}
{-3 -type integer -default 3} {-1 -type boolean -default 1}
{p1 -type string} {-2 -type integer -default 2}
{p2 -type string} {-3 -type integer -default 3}
} {p1 -type string}
} { {p2 -type string}
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]] }
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
}
} }
namespace eval argdoc { namespace eval argdoc {
@ -2848,31 +2879,34 @@ namespace eval argparsingtest::sandwich {
p5 -type string -optional 0 p5 -type string -optional 0
}] }]
} }
tcl::OptProc opt { #tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
{p1 -string "first leading positional argument"} if {![catch {package present opt}]} {
{p2 -string "second leading positional argument"} tcl::OptProc opt {
{-return string "return type"} {p1 -string "first leading positional argument"}
{-frametype \uFFEF "type of frame"} {p2 -string "second leading positional argument"}
{-show_edge \uFFEF "show table outer borders"} {-return string "return type"}
{-show_seps \uFFEF "show separators"} {-frametype \uFFEF "type of frame"}
{-join "solo option"} {-show_edge \uFFEF "show table outer borders"}
{-x "" "x val"} {-show_seps \uFFEF "show separators"}
{-y b "y val"} {-join "solo option"}
{-z c "z val"} {-x "" "x val"}
{-1 1 "1val"} {-y b "y val"}
{-2 -int 2 "2val"} {-z c "z val"}
{-3 -int 3 "3val"} {-1 1 "1val"}
{p3 -string "first trailing positional argument"} {-2 -int 2 "2val"}
{p4 -string "second trailing positional argument"} {-3 -int 3 "3val"}
{p5 -string "third trailing positional argument"} {p3 -string "first trailing positional argument"}
} { {p4 -string "second trailing positional argument"}
set opts [dict create] {p5 -string "third trailing positional argument"}
foreach v [info locals] { } {
if {$v ni {p1 p2 p3 p4 p5 opts args Args}} { set opts [dict create]
dict set opts $v [set $v] foreach v [info locals] {
if {$v ni {p1 p2 p3 p4 p5 opts args Args}} {
dict set opts $v [set $v]
}
} }
return [list [list $p1 $p2] [list $p3 $p4 $p5] $opts]
} }
return [list [list $p1 $p2] [list $p3 $p4 $p5] $opts]
} }
namespace eval argdoc { namespace eval argdoc {

5
src/modules/argparsingtest-buildversion.txt

@ -1,6 +1,9 @@
1.2.0 1.3.0
#First line must be a semantic version number #First line must be a semantic version number
#all other lines are ignored. #all other lines are ignored.
#1.3.0 - opt, cmdline and tepam are no longer module-level hard requires. A punkshell build without tcllib could not load the module at all ("can't find package opt"), which is useless on exactly the runtime you wanted to measure: every parser this module compares is now optional and a missing one degrades to a not_loaded row like argp/parse_args/argparse already did. Their roster entries become {optional opt} / {optional cmdline} / {optional tepam}
#1.3.0 - the guard differs by package because the dependency does: cmdline is only called inside proc bodies, so the catch-guarded require is the whole story, whereas tcl::OptProc and tepam::procedure DEFINE their wrapper procs - those 7 definition sites are additionally guarded by a 'package present' test, so the proc simply does not exist when the package is absent (and discover_parsers then never calls it). Presence test rather than catch, so a genuine spec error still raises loudly on a runtime that does have the package
#1.3.0 - regression pinned by module_loads_without_optional_parser_packages (child interp with an emptied auto_path); tests that name parsers explicitly now filter through a loaded_parsers helper
#1.2.0 - fourth calling style 'sandwich': 2 mandatory leading positionals, THEN the 10 keyed options (argvec now exercises the valueless -join flag alongside -flag value pairs), THEN 3 mandatory trailing positionals. The 2/3 split is asymmetric on purpose - an even split could be satisfied by a parser that just halves the positional block. New namespace argparsingtest::sandwich with manual_switch, punkargs, punkargs_by_id, punkargs_parsecache, opt and argparse wrappers; return contract is {{p1 p2} {p3 p4 p5} optsdict} (grouped rather than the flat {p1 p2 opts} of the other positional styles, since positionals sit on both sides of the options) #1.2.0 - fourth calling style 'sandwich': 2 mandatory leading positionals, THEN the 10 keyed options (argvec now exercises the valueless -join flag alongside -flag value pairs), THEN 3 mandatory trailing positionals. The 2/3 split is asymmetric on purpose - an even split could be satisfied by a parser that just halves the positional block. New namespace argparsingtest::sandwich with manual_switch, punkargs, punkargs_by_id, punkargs_parsecache, opt and argparse wrappers; return contract is {{p1 p2} {p3 p4 p5} optsdict} (grouped rather than the flat {p1 p2 opts} of the other positional styles, since positionals sit on both sides of the options)
#1.2.0 - sandwich style: cmdline, tepam, argp and parse_args are 'unsupported' (N/A rows) - each verified to fail on the style's argvec. cmdline is the notable one: cmdline::getoptions returns WITHOUT error having parsed nothing, leaving every option at its default and the argument list untouched #1.2.0 - sandwich style: cmdline, tepam, argp and parse_args are 'unsupported' (N/A rows) - each verified to fail on the style's argvec. cmdline is the notable one: cmdline::getoptions returns WITHOUT error having parsed nothing, leaving every option at its default and the argument list untouched
#1.2.0 - sandwich style: punk::args, opt and the manual baseline model the arrangement and reject options ahead of the leaders; argparse reaches the style only via -mixed, which permits switches anywhere and therefore parses the argvec correctly WITHOUT enforcing the arrangement (pinned by the sandwich_strictness / sandwich_argparse_is_permissive tests) #1.2.0 - sandwich style: punk::args, opt and the manual baseline model the arrangement and reject options ahead of the leaders; argparse reaches the style only via -mixed, which permits switches anywhere and therefore parses the argvec correctly WITHOUT enforcing the arrangement (pinned by the sandwich_strictness / sandwich_argparse_is_permissive tests)

6
src/modules/oolib-buildversion.txt

@ -1,4 +1,4 @@
0.1.4 0.1.4
#First line must be a tm version number #First line must be a tm version number
#all other lines are ignored. #all other lines are ignored.
#0.1.4 - collection add duplicate-key error message no longer misnames the object as 'col_processors' (stray copy-paste in the generic collection class) #0.1.4 - collection add duplicate-key error message no longer misnames the object as 'col_processors' (stray copy-paste in the generic collection class)

88
src/tests/modules/argparsingtest/testsuites/argparsingtest/argparsingtest.test

@ -15,6 +15,20 @@ namespace eval ::testspace {
testConstraint parse_args_loaded [expr {![catch {package present parse_args}]}] testConstraint parse_args_loaded [expr {![catch {package present parse_args}]}]
testConstraint argparse_loaded [expr {![catch {package present argparse}]}] testConstraint argparse_loaded [expr {![catch {package present argparse}]}]
#added 2026-07-28 (agent) - opt, cmdline and tepam are optional too (module 1.3.0 stopped
#hard-requiring them: a comparison harness must still load on a build without tcllib), so any
#test naming parsers explicitly has to drop the ones this runtime cannot load
proc loaded_parsers {style names} {
set disco [dict get [argparsingtest::discover_parsers -style $style] $style]
set out {}
foreach n $names {
if {[dict exists $disco $n] && [dict get $disco $n] eq "loaded"} {
lappend out $n
}
}
return $out
}
#added 2026-07-18 (agent) - suite rewritten for the argparsingtest 1.0.0 restructure: #added 2026-07-18 (agent) - suite rewritten for the argparsingtest 1.0.0 restructure:
#parser procs live in per-style namespaces (opts/tkstyle/tclstyle), harness results are keyed by style #parser procs live in per-style namespaces (opts/tkstyle/tclstyle), harness results are keyed by style
#Split 2026-07-19 (G-092 - parallel-floor reduction, tests moved verbatim): this file holds #Split 2026-07-19 (G-092 - parallel-floor reduction, tests moved verbatim): this file holds
@ -91,7 +105,9 @@ namespace eval ::testspace {
if {$ok eq 1 && [dict get $r opts manual_switch] ne "loaded"} { set ok "opts manual_switch status" } if {$ok eq 1 && [dict get $r opts manual_switch] ne "loaded"} { set ok "opts manual_switch status" }
if {$ok eq 1 && [dict get $r tkstyle cmdline_typed] ne "unsupported"} { set ok "tkstyle cmdline_typed status" } if {$ok eq 1 && [dict get $r tkstyle cmdline_typed] ne "unsupported"} { set ok "tkstyle cmdline_typed status" }
if {$ok eq 1 && [dict get $r tkstyle argp] ne "unsupported"} { set ok "tkstyle argp status" } if {$ok eq 1 && [dict get $r tkstyle argp] ne "unsupported"} { set ok "tkstyle argp status" }
if {$ok eq 1 && [dict get $r tclstyle cmdline_typed] ne "loaded"} { set ok "tclstyle cmdline_typed status" } #tclstyle CAN express cmdline, so there the status tracks whether the package is installed
set expect_cmdline [expr {[catch {package present cmdline}] ? "not_loaded" : "loaded"}]
if {$ok eq 1 && [dict get $r tclstyle cmdline_typed] ne $expect_cmdline} { set ok "tclstyle cmdline_typed status" }
if {$ok eq 1 && [dict get $r tclstyle argp] ne "unsupported"} { set ok "tclstyle argp status" } if {$ok eq 1 && [dict get $r tclstyle argp] ne "unsupported"} { set ok "tclstyle argp status" }
if {$ok eq 1 && [dict exists $r opts test1_switch]} { set ok "stale test1_switch key present" } if {$ok eq 1 && [dict exists $r opts test1_switch]} { set ok "stale test1_switch key present" }
set ok set ok
@ -105,6 +121,10 @@ namespace eval ::testspace {
foreach {pkg pname styles} { foreach {pkg pname styles} {
parse_args parse_args {opts tclstyle} parse_args parse_args {opts tclstyle}
argparse argparse {opts tkstyle tclstyle sandwich} argparse argparse {opts tkstyle tclstyle sandwich}
opt opt {opts tkstyle tclstyle sandwich}
cmdline cmdline_untyped {opts tclstyle}
cmdline cmdline_typed {opts tclstyle}
tepam tepam {opts tkstyle tclstyle}
} { } {
set expected [expr {[catch {package present $pkg}] ? "not_loaded" : "loaded"}] set expected [expr {[catch {package present $pkg}] ? "not_loaded" : "loaded"}]
foreach s $styles { foreach s $styles {
@ -128,6 +148,66 @@ namespace eval ::testspace {
set ok set ok
} -result 1 } -result 1
#added 2026-07-28 (agent) - regression pin for the 1.3.0 change: the module used to hard-require
#opt, cmdline and tepam, so 'package require argparsingtest' died outright with "can't find
#package opt" on a punkshell build without tcllib - a comparison harness unloadable on exactly
#the runtime you wanted to measure. Exercised in a child interp with an emptied auto_path, which
#is where tcllib's pkgIndex-based packages come from. If a runtime provides any of the three as a
#.tm on a module path this degrades to asserting the module still loads, which is the main claim.
test module_loads_without_optional_parser_packages {Test that the module loads when opt, cmdline and tepam are unavailable} -body {
set tm_paths [tcl::tm::list]
#pin to the parent's versions - a plain require prefers a stable copy over the 999999.0a1.0 source module
set pinned ""
foreach pkg {punk::args punk::lib argparsingtest} {
if {![catch {package present $pkg} ver]} {
append pinned "package require -exact [list $pkg] [list $ver]\n"
}
}
set child [interp create]
try {
set child_tm [interp eval $child {tcl::tm::list}]
if {[llength $child_tm]} {
interp eval $child [list tcl::tm::path remove {*}$child_tm]
}
if {[llength $tm_paths]} {
interp eval $child [list tcl::tm::path add {*}$tm_paths]
}
interp eval $child [list set ::auto_path [list]]
set result [interp eval $child [string cat $pinned {
set absent {}
foreach p {opt cmdline tepam} {
if {[catch {package present $p}]} { lappend absent $p }
}
set disco [dict get [argparsingtest::discover_parsers -style opts] opts]
set statuses {}
set stillcommands {}
foreach {pname pkg} {opt opt cmdline_untyped cmdline cmdline_typed cmdline tepam tepam} {
if {$pkg in $absent} {
lappend statuses $pname [dict get $disco $pname]
}
}
#opt and tepam DEFINE their wrapper procs, so those must not exist when absent
foreach {pname pkg} {opt opt tepam tepam} {
if {$pkg in $absent && [llength [info commands ::argparsingtest::opts::$pname]]} {
lappend stillcommands $pname
}
}
list loaded [package present argparsingtest] absent $absent statuses $statuses stillcommands $stillcommands
}]]
} finally {
interp delete $child
}
set ok 1
if {[dict get $result loaded] eq ""} { set ok "child did not load argparsingtest" }
if {$ok eq 1 && [llength [dict get $result stillcommands]] } { set ok "wrapper procs defined without their package: [dict get $result stillcommands]" }
if {$ok eq 1} {
foreach {pname status} [dict get $result statuses] {
if {$status ne "not_loaded"} { set ok "$pname reported $status with its package absent" ; break }
}
}
set ok
} -result 1
#added 2026-07-26 (agent) - opts-style external wrappers agree with the hand-rolled baseline's option values #added 2026-07-26 (agent) - opts-style external wrappers agree with the hand-rolled baseline's option values
test parse_args_opts_values {Test that the parse_args opts wrapper returns the declared option values} -constraints parse_args_loaded -body { test parse_args_opts_values {Test that the parse_args opts wrapper returns the declared option values} -constraints parse_args_loaded -body {
set r [argparsingtest::opts::parse_args -return object -x hello -y world -1 1 -2 2 -3 3] set r [argparsingtest::opts::parse_args -return object -x hello -y world -1 1 -2 2 -3 3]
@ -204,7 +284,7 @@ namespace eval ::testspace {
test sandwich_strictness {Test that the modelling sandwich parsers reject options before the leaders} -body { test sandwich_strictness {Test that the modelling sandwich parsers reject options before the leaders} -body {
set badvec {-x hello -join alpha beta gamma delta epsilon} set badvec {-x hello -join alpha beta gamma delta epsilon}
set ok 1 set ok 1
foreach pname {manual_switch punkargs punkargs_by_id punkargs_parsecache opt} { foreach pname [loaded_parsers sandwich {manual_switch punkargs punkargs_by_id punkargs_parsecache opt}] {
if {![catch {argparsingtest::sandwich::$pname {*}$badvec} r]} { if {![catch {argparsingtest::sandwich::$pname {*}$badvec} r]} {
set ok "$pname accepted options-before-leaders: $r" set ok "$pname accepted options-before-leaders: $r"
break break
@ -237,7 +317,7 @@ namespace eval ::testspace {
#added 2026-07-17 (agent) #added 2026-07-17 (agent)
test first_call_library_backed {Test that first_call returns cold and warm float timings for library-backed parsers (warm-up scripts must run cleanly)} -body { test first_call_library_backed {Test that first_call returns cold and warm float timings for library-backed parsers (warm-up scripts must run cleanly)} -body {
set r [argparsingtest::first_call -style opts -parsers {punkargs punkargs_by_id opt cmdline_untyped cmdline_typed tepam}] set r [argparsingtest::first_call -style opts -parsers [loaded_parsers opts {punkargs punkargs_by_id opt cmdline_untyped cmdline_typed tepam}]]
set ok 1 set ok 1
foreach {pname sub} [dict get $r opts] { foreach {pname sub} [dict get $r opts] {
foreach mode {cold warm} { foreach mode {cold warm} {
@ -254,7 +334,7 @@ namespace eval ::testspace {
test first_call_positional_styles {Test first_call cold and warm for tkstyle, tclstyle and sandwich parsers} -body { test first_call_positional_styles {Test first_call cold and warm for tkstyle, tclstyle and sandwich parsers} -body {
set ok 1 set ok 1
foreach {s plist} {tkstyle {punkargs_by_id tepam} tclstyle {cmdline_untyped} sandwich {manual_switch punkargs_by_id opt}} { foreach {s plist} {tkstyle {punkargs_by_id tepam} tclstyle {cmdline_untyped} sandwich {manual_switch punkargs_by_id opt}} {
set r [argparsingtest::first_call -style $s -parsers $plist] set r [argparsingtest::first_call -style $s -parsers [loaded_parsers $s $plist]]
foreach {pname sub} [dict get $r $s] { foreach {pname sub} [dict get $r $s] {
foreach mode {cold warm} { foreach mode {cold warm} {
if {![dict exists $sub $mode]} { set ok "missing $mode for $s $pname" ; break } if {![dict exists $sub $mode]} { set ok "missing $mode for $s $pname" ; break }

29
src/tools/punkzip/PROVENANCE.md

@ -2,8 +2,12 @@
## Origin ## Origin
- Upstream repository: `c:/repo/jn/zig/punkzip` (git; remote - Upstream repository: punkzip (git; remote
`https://www.gitea1.intx.com.au/jn/punkzip`) `https://www.gitea1.intx.com.au/jn/punkzip`). The working checkout is expected as
a sibling of this repository, at `../zig/punkzip` relative to the punkshell repo
root. That is a layout convention, not a requirement - if no checkout is present
there, clone the remote to that location; the Vendored state commit below
identifies the exact upstream state in any clone.
- Vendored state: commit `0882f0373eb2c983142e713c814b91aa82cfcea7` (punkzip v2.3.1, - Vendored state: commit `0882f0373eb2c983142e713c814b91aa82cfcea7` (punkzip v2.3.1,
2026-07-27; upstream working tree clean at copy time) 2026-07-27; upstream working tree clean at copy time)
- Vendored: 2026-07-27 for goal G-126 (see `goals/G-126-punkzip-accelerator.md`) - Vendored: 2026-07-27 for goal G-126 (see `goals/G-126-punkzip-accelerator.md`)
@ -35,20 +39,19 @@ fork boundary stays clean and every vendored state corresponds to an upstream co
## Re-vendor procedure ## Re-vendor procedure
From a CLEAN upstream checkout (commit upstream first; a dirty copy has no committed From a CLEAN upstream checkout (commit upstream first; a dirty copy has no committed
provenance): provenance). All commands run from the punkshell repo root, with the upstream
checkout at its expected sibling location `../zig/punkzip` (see Origin):
cd c:/repo/jn/zig/punkzip git -C ../zig/punkzip status --short # must be empty
git status --short # must be empty git -C ../zig/punkzip rev-parse HEAD # record as the new Vendored state above
git rev-parse HEAD # record as the new Vendored state above
# from the punkshell repo root:
rm -rf src/tools/punkzip/src rm -rf src/tools/punkzip/src
cp c:/repo/jn/zig/punkzip/build.zig src/tools/punkzip/ cp ../zig/punkzip/build.zig src/tools/punkzip/
cp c:/repo/jn/zig/punkzip/build.zig.zon src/tools/punkzip/ cp ../zig/punkzip/build.zig.zon src/tools/punkzip/
cp c:/repo/jn/zig/punkzip/LICENSE src/tools/punkzip/ cp ../zig/punkzip/LICENSE src/tools/punkzip/
cp c:/repo/jn/zig/punkzip/LICENSE-time-dot-zig src/tools/punkzip/ cp ../zig/punkzip/LICENSE-time-dot-zig src/tools/punkzip/
cp c:/repo/jn/zig/punkzip/README.md src/tools/punkzip/ cp ../zig/punkzip/README.md src/tools/punkzip/
cp -r c:/repo/jn/zig/punkzip/src src/tools/punkzip/src cp -r ../zig/punkzip/src src/tools/punkzip/src
# verify with the pinned toolchain (zig build test must pass; the gate is the # verify with the pinned toolchain (zig build test must pass; the gate is the
# exit code - the zip suite's negative tests print EOCD warnings while passing): # exit code - the zip suite's negative tests print EOCD warnings while passing):

Loading…
Cancel
Save