Expand description
pattern_data_escape submodule (Rust-only; see the module docs).
Rust-only utility (NOT a port — lives outside src/ported/ by design).
The DATA half of docs/BUGS.md #1090: how a backslash that is a
CHARACTER OF A VALUE has to be spelled before it reaches
ported::pattern::patcompile.
C never needs this transform. Its pattern compiler consumes the
LEXER’s encoding, where a source-level quote already arrived as
Bnull/Bnullkeep + payload (c:Src/zsh.h:195-200), so a RAW
backslash in patcompile’s input can only be data. A substituted
value acquires its pattern meaning in zshtokenize
(c:Src/glob.c:3585-3653), reached from strcatsub’s
if (glbsub) shtokenize(dest) (c:Src/subst.c:822/830) for
${~spec} / GLOB_SUBST, and that function rewrites a backslash
into a quote marker ONLY when the next character reaches its
ztokens scan:
c:Src/glob.c:3597-3605 case Bnull: case Bnullkeep: case '\\':
if (bslash) { s[-1] = … Bnullkeep/Bnull; break; }
bslash = 1; continue;
c:Src/glob.c:3640-3648 for (t = ztokens; *t; t++)
if (*t == *s) {
if (bslash) s[-1] = … Bnullkeep/Bnull;
else *s = (t - ztokens) + Pound;
break;
}
c:Src/glob.c:3651 bslash = 0;Before anything else — a space, a $, a { — no switch arm fires,
c:3651 just clears bslash, and BOTH bytes survive in the string as
ordinary literal data. That is why real zsh answers
p='a\ b'; [[ 'a b' == ${~p} ]] # no match — the pattern holds a backslash
p='a\ b'; [[ 'a\ b' == ${~p} ]] # matchported::pattern’s input normalizer (src/ported/pattern.rs, the \\
arm) reads a lone raw \X as a QUOTE of X — the spelling every
SOURCE-level pattern path in zshrs hands it (the cond/case pattern
builder in extensions::compile_zsh, ${v//\%/%%}’s builder in
ported::subst) — and spells a literal backslash as the pair \\.
So doubling exactly the backslashes zshtokenize declines to consume
is what carries C’s Bnull-vs-raw split into the Rust encoding.
Backslashes the tokenizer WOULD consume are left in place so the
downstream tokenizer/normalizer still folds them into a quote at
their original position.
Callers are the “this pattern text came out of a VALUE” sites:
ported::subst::paramsubst— the search-subscript patterns (${a[(I)…]}/(i)/(r)/(R)/(K)), which reachpatcompilethroughtokenizealone (c:Src/params.c:1727).fusevm_bridge’sBUILTIN_GLOB_SUBST_GUARD/BUILTIN_PAT_DATA_BACKSLASH— the${~spec}andsetopt globsubstlegs of a[[ … == pat ]]RHS and acasearm, thestrcatsubshtokenizeC runs at c:Src/subst.c:822/830.
Functions§
- escape_
data_ backslashes - Rewrite a pattern string that came out of a VALUE so
ported::pattern’s normalizer reads its backslashes the wayzshtokenizedoes — see the module docs.