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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! !!! WARNING: RUST-ONLY MODULE — NO C COUNTERPART !!!
//!
//! Lossless decode of RAW SCRIPT BYTES into the shell pipeline's
//! `String` form.
//!
//! C zsh has no encoding requirement on script input. `Src/input.c`
//! reads bytes (`shingetchar`, c:229) and `Src/utils.c:4856 metafy`
//! escapes only the reserved IMETA bytes (`Src/utils.c:4195-4201` —
//! `'\0'`, `Meta` 0x83, `Marker` 0xa2 and the token range
//! `Pound`..`Nularg`); every other byte, including a lone ISO-8859-1
//! `0xe9`, travels through the lexer untouched and is written back
//! out verbatim. That is why a legacy byte in a completion file has
//! never bothered zsh.
//!
//! Rust `String` is UTF-8, so a raw non-UTF-8 byte cannot be stored
//! directly. zshrs already has one encoding for exactly this, used by
//! the `$'\xNN'` decoders (`src/ported/lex.rs` `getkeystring_dollar_quote`,
//! `src/extensions/compile_zsh.rs` `meta_encode_byte`) and decoded at
//! every write/exec boundary by `crate::ported::utils::unmetafy_str`:
//! a byte `>= 0x80` becomes the two chars `U+0083` (Meta) and
//! `U+00(b ^ 32)`. This module applies that same encoding to the
//! bytes a script file or SHIN hands us.
//!
//! The transform is the byte-level twin of `Src/input.c:267
//! shingetline`, which the interactive/stdin path already performs
//! inline: valid UTF-8 stays real `char`s (the lexer is Unicode-based
//! — `src/ported/lex.rs:6171` "zshrs does not metafy, it keeps UTF-8
//! `str`"), and only bytes that cannot be part of a UTF-8 sequence
//! are Meta-encoded. Clean-ASCII and valid-UTF-8 input therefore
//! decode to exactly the same `String` `read_to_string` produced, so
//! the common path is unchanged; the difference is that an invalid
//! byte no longer kills the read.
use io;
use Path;
/// Meta-encode ONE raw byte into the pipeline's `String` form.
///
/// Mirrors the metafy step of `Src/utils.c:4856`
/// (`if (imeta(c)) { *p++ = Meta; *p++ = c ^ 32; }`) transposed onto
/// zshrs's char-level encoding, and is the exact inverse of
/// `crate::ported::utils::unmetafy_str`.
/// Decode raw script bytes into the pipeline's `String` form without
/// losing a single byte.
///
/// Valid UTF-8 runs are copied verbatim; every byte that is not part
/// of a valid UTF-8 sequence is Meta-encoded so
/// `crate::ported::utils::unmetafy_str` reproduces it exactly at the
/// output boundary.
///
/// A literal `U+0083` that was validly UTF-8 encoded in the source
/// (bytes `c2 83`) is copied through as the `char` `U+0083`, matching
/// what `Src/input.c:267 shingetline` already does on the stdin path;
/// it then reads as a Meta marker, which is the pre-existing ambiguity
/// of the char-level encoding and is not introduced here.
/// Read a script file as raw bytes and decode it losslessly.
///
/// Replaces `fs::read_to_string` on every path that loads shell CODE
/// (`zshrs FILE`, `source`/`.`, `autoload`, `stuff`, `$(< FILE)`).
/// `read_to_string` rejected the ENTIRE file on the first invalid
/// byte, which surfaced as a hard error for a script argument and as
/// a SILENT no-op for `source` and `autoload`.