1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! csh/tcsh source → zsh source translator for `zshrs --csh`.
//!
//! zshrs-original — no zsh C counterpart. csh syntax is not zsh syntax
//! (`set x = 5`, `setenv`, `@ n = 1 + 2`, `if (...) then`/`endif`,
//! `foreach`/`end`, `switch`/`endsw`, `$#x`, `$x[2]`, `>&`, `|&`), so a
//! `--csh` input is rewritten here into zsh text with the same meaning and
//! run by the ordinary engine. The reference is /bin/tcsh (macOS `/bin/csh`
//! is tcsh); every rule here is checked against it.
//!
//! Pure `std`; no crate dependencies, so the tree compiles standalone with
//! `rustc --edition 2021 --test mod.rs`.
//!
//! Layering (each file owns one concern):
//! * [`lex`] — logical lines, quote-aware splitting (shared helpers)
//! * [`words`] — one csh word → zsh word (`$x[2]`, `$#x`, `$?x`, `:h`, …)
//! * [`expr`] — csh expressions (`if`/`while`/`@`) → zsh conditions/arith
//! * [`cmds`] — one command line (lists, pipes, redirections, builtins)
//! * [`ctl`] — control structures with block nesting
//!
//! Whole-script behaviour handled here and in [`lex::script_lines`]:
//! * here-document bodies and their terminators are passed through
//! verbatim (no comment stripping, no continuation joining, blank lines
//! kept); the terminator is the delimiter word exactly as typed, quotes
//! included, as in tcsh;
//! * a line the translator rejects does not discard the lines before it:
//! [`translate`] returns the earlier lines followed by the error as a
//! run-time `print -u2; exit 1`, because tcsh has already executed them
//! when it reports the error;
//! * a quote does not span lines (only `\<newline>` inside `"…"` does);
//! * a script piped on stdin is read whole (`emulation_startup::csh_slurp`)
//! and translated like a file, so `goto`, here-documents and the point
//! where an error ends the script are the same as for a file; only a
//! terminal is read line by line.
/// zsh-side helpers the translated output relies on (`cd`/`pushd`/`popd`
/// with tcsh's error text, `printenv`, the command-not-found handler).
/// Installed once, ahead of the first translated input.
pub const PREAMBLE: &str = include_str!;
/// Set for `zshrs --csh-translate --source`: the text is a sourced file, so
/// `exit` in it only ends that file (`return` in the `source` function).
static SOURCE_MODE: AtomicBool = new;
/// Translate a whole csh script (a file, a `-c` string) to zsh, with tcsh's
/// end-of-input behaviour: a block left open still runs its body, and an
/// error is raised only where tcsh has to skip over the missing closer.
/// Errors carry the csh-side message text real tcsh prints
/// (`if: Expression Syntax.`, `Too many ('s`, …).
/// Translate input that may still be arriving (a prompt, stdin). A block
/// left open is an `Err` whose text ends in `not found.`, which the caller
/// treats as "keep reading lines".