Conversation
The "param" class glued a long option's value onto its short form without checking it. A value that is not a number converts to nothing, so the option keeps its default, and the leftover characters reach the cluster loop as more short options: --long-names=yes writes DOS 8.3 names and --sockets=8I0 mirrors with no top index, both exit 0. A param value is now a bounded digit run, the on/off mapping the class already had, or the extra character a given parser reads (-m takes N,N2, -%c a rate with a decimal point). Anything else draws the same refusal the other classes have used since #1195. --structure is left out, being the one param row that also reads a user template. Also fixes --cache's help string, which was --retries', so the new message quoted the wrong option. Closes #1426 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
The gate admitted the comma and the dot anywhere in the value, so --connection-per-second=1.2.3 passed it and reached maxconn as 1.2, the silent-wrong-value class this change is about. Both are now one occurrence with a digit after it, which also refuses --max-files=100, and --max-files=,,,5 at the gate instead of downstream. 362's --structure case asserted a falsehood: the glued template exits 0 because the word is swallowed as a URL, not because it applied. The exemption is now pinned in the optalias self-test, which sees the expansion, and 362 asserts only that the rule does not refuse it. Renamed the test into the *_engine-* glob so the Windows suite runs it; it has no skip path, so the suite's expected-skip set is unchanged. --cache=off/on now discriminates on the cache directory, so an inverted on/off mapping reds 362 on its own terms. 19 param rows carry no help string, whose dangling tab read as a truncated message; the four syntax errors now drop the line when there is nothing to put on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
#1418 gave --structure its own "paramn" class, so the -N guard this branch carried to spare it is gone: the rule is scoped to "param", which is now exactly the 27 rows the issue lists. Both sides' helpers sit side by side, and #1418's own refusal drops its dangling help tab the way the other four syntax errors here do. 362 tests the class boundary where it is real: --structure=1L0 is a preset trailed by more short options, which the param rule would refuse, and whose -L0 tail shows on disk. The self-test's --structure assertions are dropped as duplicates of #1418's own block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Xavier Roche <roche@httrack.com>
xroche
enabled auto-merge (squash)
August 25, 2026 06:43
This was referenced Aug 25, 2026
xroche
added a commit
that referenced
this pull request
Aug 25, 2026
Two of the three spellings in #1434 mirrored the wrong thing at exit 0, both because the value mapped onto the bare short form. `--structure=on` expanded to a bare `-N`, which reads the next word as a user template, so `--structure=on <URL>` swallowed the URL and mirrored nothing. "on" now names the default preset (`-N0`), the layout "off" already selected; #1418's glue rules are otherwise untouched. `--long-names=` expanded to a bare `-L`, whose `sscanf` converted nothing and left the switch to re-map the value already stored, landing on DOS 8.3 names (`-L1 -L` did the same). Rather than refuse the empty value I fixed the short form: a bare `-L` now selects L1, the default the help and man page already star. Refusing would have taken `sockets=` and the config-file `long-names=` spelling with it, and this way the empty value means the option's own default. `-L0`, `--long-names=off` and `--long-names=2` are unchanged. Rewriting that parse surfaced a third bug, pre-existing and folded in here: the digit-run bound #1418 added counts digits rather than reading the value, so a zero-padded run falls off it. `-L0000000001` selected ISO9660, `-N0000000001` lost its preset, and `--structure=0000000001` was refused. `optalias_digits_fit` skips the leading zeros first, shared by the four sites that read such a run. The 27 `param` rows keep #1427's 16-character cap: its bound is a magnitude, not a run length, so `optalias_digits_fit` does not fit there — 9 significant digits would refuse `--advanced-maxlinks=2000000000`, and it cannot see the second operand of `-m N,N2`. Filed as #1437. The third spelling in the issue, `--structure=I0`, has been refused since #1418 landed after the issue was measured, and test 368 pins that. What survives is `--structure=8I0`: the digits-then-cluster form #1418 glues on purpose, and the same shape as the `--structure=1L0` that #1427's test pins as accepted. No rule separates the two, so that one wants a decision rather than a patch. Closes #1434 --------- Signed-off-by: Xavier Roche <roche@httrack.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
xroche
added a commit
that referenced
this pull request
Aug 25, 2026
#1439) `optalias_param_takes()` (#1427) bounded a `param` row's value at 16 characters, which is a length where a magnitude is meant. It refused `--depth=0000000000000000001` for its padding alone, and accepted `--sockets=1234567890123456`, sixteen digits that `sscanf("%d")` then read as 1015724736 simultaneous connections. Each digit run is now converted with `strtoll` and range-checked against what the option's own parser holds: `INT_MAX` for the rows reading an `int`, `INT64_MAX` for `-m`, `-M` and `-G` on their `LLint` and for `-%c`, whose float takes any run `strtoll` converts. The check runs per operand, so the second half of `-m N,N2` and `-%c 0.5` is covered too. `optalias_suffix()` carried a copy of the same bare 16, so the six `level` rows get the same treatment. The behaviour change is the fix rather than a side effect of it, and it goes both ways. Refused from now on: a value on an int-valued long form whose digit run exceeds 2147483647 and which the old cap let through, so no longer than 16 characters. `--sockets=1234567890123456`, `--max-rate=3000000000`, `--depth=2147483648`, `--timeout=99999999999`, `--generate-errors=3000000000`, and every value of that shape on the other int rows. All of them were undefined at `sscanf("%d")` and wrapped in practice: 1015724736 sockets, a rate of -1294967296, a depth of -2147483648, a timeout of 1215752191 seconds. None landed on a sane value by accident either, since `-c` clamps its wrapped negative back to one socket, which is still not what was asked for. Accepted from now on: a zero-padded value wherever its magnitude fits, and on `-m`, `-M`, `-G` and `-%c` any 17-to-19-digit run up to `INT64_MAX`. `--max-size=9223372036854775807` is refused on master and taken here, which is right, because that is what the `LLint` behind it holds. The old cap was also the only thing keeping a value short enough to glue into the 1024-byte expansion buffer, where `strlcatbuff` aborts rather than clips. So a length bound stays, at the glue site and sized to the room the short form leaves: without it `httrack --depth $(printf '0%.0s' $(seq 1022))` exits 134 with a backtrace where master printed a syntax error. It now also reaches a class the old cap never covered, the `param0` rows, where `httrack --allow <1023 chars>` aborts on master and draws the same syntax error here. 369 asserts both directions, through the engine's own expansion and on disk, and reds on six mutants: the length cap put back, `optalias_run_fits` forced true or stripped of its `max`, the `LLint` arm narrowed to `-M` and `-%c`, a leading sign accepted, the capacity guard removed, and `optalias_suffix` reverted. `st_optalias`'s table-wide loop carries the padding, `INT_MAX` and sign probes across all 27 `param` rows. Closes #1437 --------- Signed-off-by: Xavier Roche <roche@httrack.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
paramclass glued a long option's value onto its short form without looking at it. A value the short form cannot read converts short or not at all, so the option keeps a value nobody asked for, and the tail spills into the cluster loop as more short options.--long-names=yesand--long-names=nonemirror in DOS 8.3 names, which is what--long-names=0means, and--sockets=8I0mirrors with no topindex.htmlbecause theI0reached-I0. Both exit 0. Aparamvalue is now a bounded digit run, theon/offmapping the class already had, or one separator with a digit after it where the parser reads one (-mtakesN,N2,-%ca rate with a decimal point). Anything else draws the refusal the other classes have used since #1195, across all 27paramrows, asserted table-wide in theoptaliasself-test so a new row is covered the day it is added.Refusal rather than a warning, because carrying on does not preserve the run: the value's characters turn other options on, so the warning would be followed by a wrong mirror under exit 0, which a script cannot see. Refusal is not a new outcome here either, since an uppercase junk value already exits 255 on every one of these rows,
OFFreaching-O, with a message naming an option nobody typed.--cache=OFFnow saysOption --cache does not take the value OFF. Along the way:--cache's help string was--retries's, and 19 of these rows carry no help string at all, whose dangling tab read as a truncated message.--structureis out of scope, having its ownparamnclass since #1418, which this branch is merged onto. Three gaps stay open behind that class, all pre-existing and all surviving #1418, which keeps8I0-shaped gluing by design:--structure=I0is byte-identical to-I0, exit 0 withindex.htmland the two GIFs silently missing;--structure=on <URL>maps to a bare-N, which eats the next argument, so the crawl mirrors nothing and still exits 0; and--long-names=with an empty value is the bare-L, which is 8.3, so the headline symptom stays reachable by that spelling.Closes #1426