document.bash: point at docs/hacking/bash-pitfalls.md where code relies on its rules.
commit 764825d0a731929c05d42f89cc9d19a63c33e72c · parent 8d0fe9cfbc
· browse this tree
Ximianth, 2026-10-23 23:35:12 UTC
Each pointer names a section heading, replacing a restatement where there was one: the storage comment's rule for name-keyed elements, the assoc declares before the commit's namerefs, the NUL check, and the body loop (a slice there would be quadratic over a whole dump). The read already points at its section, from the commit that changed it.
diff --git a/lib/testmark/document.bash b/lib/testmark/document.bash index 0a66374..d40ad71 100644 --- a/lib/testmark/document.bash +++ b/lib/testmark/document.bash @@ -10,8 +10,7 @@ # pid $BASHPID at parse, for refusing state changes from a subshell # So forgetting a handle is one `unset` per kind, and nothing else needs cleaning up. # Variable names are built only from handles that pass _testmark_handle, and kinds have no "_", so two handles' variables never meet. -# Hunk names come from documents and may contain shell syntax: on some bash versions, arithmetic, `[[ -v ]]`, `unset`, and `printf -v` on an element run `$(...)` from inside its key. -# So touch name-keyed elements only as `a[$k]=v`, `"${a[$k]}"`, `"${a[$k]-}"`, `${a[$k]+set}`, and `"${!a[@]}"`. +# Hunk names come from documents and may contain shell syntax, so name-keyed elements are touched only as "Using assoc arrays safely" in docs/hacking/bash-pitfalls.md allows. _testmark_kinds=(lines start end info names pid) _testmark_err() { @@ -46,7 +45,7 @@ _testmark_parse() { local i line name names='' open='' k='' at='' for ((i = 0; i < ${#lines[@]}; i++)); do line=${lines[i]} - # mapfile ends a line at a NUL, dropping its "\n". So a line without one is the last line, or has a NUL; read -d '' tells which. + # A line without its "\n" is the last line, or was cut at a NUL; read -d '' tells which. See "NUL bytes vanish unless you check for them" in docs/hacking/bash-pitfalls.md. if [[ $line != *$'\n' ]] && IFS= read -r -d '' _ <"$file"; then _testmark_err "$file:$((i + 1)): contains a NUL byte" return 1 @@ -105,7 +104,7 @@ _testmark_parse() { } # Parsed without error; only now are globals written. - # Assoc kinds are declared first, since a nameref to an undeclared name makes an indexed array. + # Assoc kinds are declared first; see "assoc arrays must be declared as such" in docs/hacking/bash-pitfalls.md. declare -gA "_testmark_start_$h" "_testmark_end_$h" "_testmark_info_$h" local -n g_lines=_testmark_lines_$h g_start=_testmark_start_$h g_end=_testmark_end_$h g_info=_testmark_info_$h local -n g_names=_testmark_names_$h g_pid=_testmark_pid_$h @@ -151,7 +150,7 @@ _testmark_body() { _testmark_hunk "$1" "$2" || return 1 local -n lines=_testmark_lines_$1 start=_testmark_start_$1 end=_testmark_end_$1 local i=${start[$2]} last=${end[$2]} body= - for (( ; i < last; i++)); do body+=${lines[i]}; done + for (( ; i < last; i++)); do body+=${lines[i]}; done # not a slice; see "Quadratic operations" in docs/hacking/bash-pitfalls.md printf '%s' "$body" }