BATsh
view release on metacpan or search on metacpan
directly and does not re-enter cmd.exe, so the original
quote-re-wrapping failure mode cannot recur. _bg_tempfile()'s
temp-directory selection already accounts for %TEMP%/%TMP% and
backslash path separators. No logic defects found in review;
confirmation on an actual Windows host (locale, path-length,
%TEMP% permission variables that cannot be reviewed statically)
remains pending.
- CP932 (Shift_JIS) multibyte-safe execution: NEW MODULE BATsh::MB.
A .batsh script written in CP932 -- the encoding of Japanese
Windows -- now runs correctly even when its characters contain
trail bytes that collide with ASCII shell metacharacters (the
classic "dame-moji" / 0x5C problem). Affected characters are
extremely common: SO (0x835C), HYOU (0x955C), NOH (0x945C) end
in a backslash; PO (0x837C) in a pipe; CHI (0x8360) in a
backtick; DA (0x835E) in the cmd.exe caret escape; and many
trail bytes fall in a-z/A-Z where uc()/lc() corrupt them.
Design: instead of teaching every byte-oriented scanner in
BATsh::CMD / BATsh::SH about lead and trail bytes, the script
text passes through a reversible GUARD TRANSFORM on input. Each
two-byte character LEAD+TRAIL whose TRAIL is in the dangerous
ASCII range 0x40-0x7E is rewritten to the three-byte form
\x01 LEAD (TRAIL+0x80), which contains no ASCII bytes; a literal
\x01 becomes \x01\x01, making the transform bijective. All
existing parsing (caret escapes, pipelines, quotes, redirects,
globs, case patterns, uc/lc variable handling, SETLOCAL
snapshots, ...) is then automatically DBCS-safe with no scanner
changes. The inverse transform is applied at the output
boundaries only:
print sinks ECHO/echo/printf/SET display, prompts, _warn
exec sinks system() for external commands, background jobs,
FOR /F ('command') input pipes
file sinks redirect targets, CD/DIR/COPY/DEL/MOVE/MKDIR/
RMDIR/REN/TYPE paths, IF EXIST, test -e/-f/-d...,
glob patterns, here-document bodies, CALL/source
script filenames
env sink BATsh::Env::sync_to_env (raw bytes into %ENV)
and input re-entry points guard incoming raw bytes again:
SET /P and read line input, FOR /F file/command lines, $(...)
and `...` captured output, glob results, Cwd for %CD%/PWD.
- Encoding selection (BATsh::MB): 'auto' is the default -- a
non-UTF-8 source containing bytes >= 0x80 is detected as CP932
and the guard switches on (and then stays on for the process,
because Env may hold guarded values; only an explicit
set_encoding deactivates it). Pure-ASCII and well-formed UTF-8
sources need no guarding and are byte-for-byte unaffected, so
existing behaviour is preserved exactly. Explicit selection:
BATsh->run($file, encoding => 'cp932');
BATsh->run_string($src, encoding => 'sjis');
BATsh->set_encoding('cp932');
set BATSH_ENCODING=cp932 (environment variable)
perl lib/BATsh.pm --encoding=cp932 script.batsh
Supported: cp932/sjis, gbk/cp936, uhc/cp949, big5/cp950 (all
sharing the same trail-byte hazard), utf8, none, auto. A UTF-8
BOM on the first line is stripped.
- Character semantics for substring/length operators under the
guard: ${#VAR}, ${VAR:N:L}, ${VAR:N} (SH) and %VAR:~n,m% (CMD)
now count CP932 CHARACTERS, not bytes, via BATsh::MB::mb_length
/ mb_substr. Byte semantics are unchanged while the guard is
inactive (ASCII/UTF-8 operation identical to 0.06).
- Modulino command line (perl lib/BATsh.pm ...): new options
--encoding=ENC and --version; script arguments after the script
name are now passed through as %1..%9 / %* (previously they
were dropped).
- BATsh::Env::sync_to_env no longer copies the batch-parameter
pseudo keys (%0..%9, %*, %%V FOR variables) into %ENV; they are
not legal environment variable names and polluted the child
environment of external commands.
- t/0015-cp932.t: new regression suite (20 checks, US-ASCII
source with \xNN escapes) covering echo/ECHO of dame-moji,
%VAR% and Env-bridge round-trips, pipeline/backtick/caret
false-positive protection, uc() safety, character-based
${#VAR} / ${VAR:N:L} / %VAR:~n,m%, case patterns, redirects,
CP932 filenames (test -f, IF EXIST), FOR /F over a CP932 file,
${VAR^^}, IF string comparison, %ENV export, auto-detection,
UTF-8 pass-through, and enc/dec bijectivity.
- eg/13_cp932_demo.pl: runnable demonstration (US-ASCII source)
of a CP932 mixed CMD/SH script.
- t/9010-encoding.t: BATsh::MB added to the US-ASCII source
check list.
- Fixed a pre-existing echo bug: the SH "echo" builtin decided
whether to apply filename globbing by testing the already
variable-expanded $rest for * ? [ characters. This meant a
variable whose *value* happened to be a glob metacharacter
(e.g. getopts setting $opt to "?" on an unknown option, or ":"
on a missing argument) could be silently glob-matched against
the current directory and replaced by whatever single-character
filename happened to match, instead of being echoed literally.
The glob-or-not decision is now made from the raw, pre-expansion
source text instead, so only a glob metacharacter actually
written in the script (e.g. "echo *.txt") triggers globbing;
a variable's expanded value is never re-subject to globbing,
matching the same "expansion results are not re-expanded"
principle already used for tilde expansion. (t/0021:
EF25/EF26 regression tests.)
- Practical-level fixes to the pure-Perl SH and CMD interpreters
(bugs found by exercising real scripts; all covered by the new
t/0022-sh-compound-fixes.t regression suite, 16 checks):
* A simple-command prefix followed on the SAME physical line by
a control structure introduced with ';' now dispatches the
control structure through its block parser instead of handing
the pieces to /bin/sh -- e.g. x=""; if [ -z "$x" ]; then ...;
fi, i=0; while ...; done, v=cat; case ...; esac
(_run_lines/_find_control_split).
* Inline "if COND; then A; else B; fi" (and elif) now honours
the else/elif branch; the old single-line parser dropped it
(_parse_if via _inline_has_terminator/_inline_expand).
( run in 3.810 seconds using v1.01-cache-2.11-cpan-364913b4093 )