zsh/ported/zsh_h.rs
1//! `zsh.h` port — comprehensive umbrella header for the Rust port.
2//!
3//! Port of `Src/zsh.h` (3,375 lines). zsh.h is the umbrella header
4//! every C file `#include`s. Defines: integer types, tokenized
5//! character constants, ~50 typedef pointer aliases, ~64 structs,
6//! and hundreds of `#define` constants for parameters, builtins,
7//! redirections, jobs, pattern matching, options, terminal control,
8//! prompts, signals, history, completion, etc.
9//!
10//! Per the macro casing rule: UPPERCASE C macros stay UPPERCASE in
11//! Rust with `#[allow(non_snake_case)]`. Struct names use C casing
12//! verbatim with `#[allow(non_camel_case_types)]`. Reserved-keyword
13//! field names get a `_` suffix (`type` → `typ`, `str` → `str`,
14//! `match` → `match_`, `new` → `new_`, `loop` → `loop_`,
15//! `mod` → `mod_`, `fn` → `fn_`, `ref` → `ref_`).
16//!
17//! Many of the `typedef struct foo *Foo;` pointer aliases (c:510-549)
18//! reference structs whose canonical home is the matching `.c` file
19//! (e.g. `struct param` definition is in zsh.h:1829, but the live
20//! Rust storage is in `params.rs`). We define those structs here as
21//! the canonical port of zsh.h; consumers `use` them from here.
22
23use std::sync::atomic::{AtomicI32, Ordering};
24
25// =============================================================================
26// 1. Integer type aliases (zsh.h:30-92).
27// =============================================================================
28
29/// Port of `#define minimum(a,b)` from `Src/zsh.h:31`.
30#[inline]
31#[allow(non_snake_case)]
32pub fn minimum<T: PartialOrd>(a: T, b: T) -> T {
33 // c:31
34 if a < b {
35 a
36 } else {
37 b
38 }
39}
40
41/// Port of `typedef ZSH_64_BIT_TYPE zlong;` from `Src/zsh.h:38`.
42/// On every modern platform this is `int64_t` / `i64`.
43#[allow(non_camel_case_types)]
44pub type zlong = i64; // c:38
45
46/// Port of `typedef ZSH_64_BIT_UTYPE zulong;` from `Src/zsh.h:50`.
47#[allow(non_camel_case_types)]
48pub type zulong = u64; // c:50
49
50/// Port of `#define ZLONG_MAX` from `Src/zsh.h:40-57`.
51pub const ZLONG_MAX: zlong = i64::MAX; // c:40-57
52
53// =============================================================================
54// 2. mnumber + math-fn types (zsh.h:94-136).
55// =============================================================================
56
57/// Port of `mnumber` from `Src/zsh.h:95-101`. C definition:
58///
59/// ```c
60/// typedef struct {
61/// union { zlong l; double d; } u;
62/// int type;
63/// } mnumber;
64/// ```
65///
66/// The C union is represented here with both alternatives held as
67/// sibling fields plus a discriminant — `type_` selects which side
68/// of the prior `u` union is live. Read `l` when
69/// `type_ == MN_INTEGER`, read `d` when `type_ == MN_FLOAT`.
70#[allow(non_camel_case_types)]
71#[derive(Debug, Clone, Copy)] // c:95
72pub struct mnumber {
73 // c:95
74 pub l: i64, // c:97 (u.l)
75 pub d: f64, // c:98 (u.d)
76 pub type_: u32, // c:100 (type)
77}
78/// `MN_INTEGER` from `Src/zsh.h:103`.
79pub const MN_INTEGER: u32 = 1; // c:103
80/// `MN_FLOAT` from `Src/zsh.h:104`.
81pub const MN_FLOAT: u32 = 2; // c:104
82/// `MN_UNSET` from `Src/zsh.h:105` — `mnumber not yet retrieved`.
83pub const MN_UNSET: u32 = 4; // c:105
84
85/// Port of `typedef struct mathfunc *MathFunc;` from `Src/zsh.h:107`.
86pub type MathFunc = Box<mathfunc>; // c:107
87
88/// Port of `typedef mnumber (*NumMathFunc)(...)` from `Src/zsh.h:108`.
89pub type NumMathFunc = fn(name: &str, argc: i32, argv: &[mnumber], id: i32) -> mnumber;
90
91/// Port of `typedef mnumber (*StrMathFunc)(...)` from `Src/zsh.h:109`.
92pub type StrMathFunc = fn(name: &str, arg: &str, id: i32) -> mnumber;
93
94/// Port of `struct mathfunc` from `Src/zsh.h:111-121`.
95#[allow(non_camel_case_types)]
96pub struct mathfunc {
97 // c:111
98 pub next: Option<Box<mathfunc>>, // c:112
99 pub name: String, // c:113
100 pub flags: i32, // c:114
101 pub nfunc: Option<NumMathFunc>, // c:115
102 pub sfunc: Option<StrMathFunc>, // c:116
103 pub module: Option<String>, // c:117
104 pub minargs: i32, // c:118
105 pub maxargs: i32, // c:119
106 pub funcid: i32, // c:120
107}
108/// `MFF_STR` constant.
109pub const MFF_STR: i32 = 1; // c:124
110/// `MFF_ADDED` constant.
111pub const MFF_ADDED: i32 = 2; // c:126
112/// `MFF_USERFUNC` constant.
113pub const MFF_USERFUNC: i32 = 4; // c:128
114/// `MFF_AUTOALL` constant.
115pub const MFF_AUTOALL: i32 = 8; // c:130
116
117// =============================================================================
118// 3. Meta byte + parser tokens (zsh.h:144-224).
119// =============================================================================
120
121// c:144 — `#define Meta ((char) 0x83)`. C `char` is one byte; every
122// use site in zsh compares against / writes raw bytes (`bytes[i] ==
123// Meta`, `out.push(Meta)`, `t[Meta]` ITOK-table indexing). The
124// previous `Meta: char = '\u{83}'` typing was the bot fakery —
125// Rust `char` is a 4-byte Unicode scalar, forcing 32+ `as u8` casts
126// across the tree. `u8` is the faithful byte type matching C's
127// `char` (which on every zsh build is a 1-byte type).
128pub const Meta: u8 = 0x83; // c:144
129/// `DEFAULT_IFS` constant.
130pub const DEFAULT_IFS: &str = " \t\n\u{83} "; // c:149
131/// `DEFAULT_IFS_SH` constant.
132pub const DEFAULT_IFS_SH: &str = " \t\n"; // c:153
133
134// `DEFAULT_FCEDIT` / `DEFAULT_HISTSIZE` belong to `config.h`, not
135// `zsh.h` — they live in `src/ported/config_h.rs` (per PORT.md
136// Rule C). Callers use `crate::ported::config_h::DEFAULT_FCEDIT` /
137// `crate::ported::config_h::DEFAULT_HISTSIZE` (cast `as i64` where
138// the destination is `histsiz: AtomicI64`).
139
140// Byte-token constants — names match C `Src/zsh.h:159-224` exactly
141// (PascalCase). One exception: C `String` (`0x85`) would shadow Rust's
142// `std::string::String`, so we use `Stringg` for that single token.
143#[allow(non_upper_case_globals)]
144pub const Pound: char = '\u{84}'; // c:159 #
145pub const Stringg: char = '\u{85}'; // c:160 $ — C `String` (renamed: collides with std::string::String)
146#[allow(non_upper_case_globals)]
147pub const Hat: char = '\u{86}'; // c:161 ^
148#[allow(non_upper_case_globals)]
149pub const Star: char = '\u{87}'; // c:162 *
150#[allow(non_upper_case_globals)]
151pub const Inpar: char = '\u{88}'; // c:163 (
152#[allow(non_upper_case_globals)]
153pub const Inparmath: char = '\u{89}'; // c:164 ((
154#[allow(non_upper_case_globals)]
155pub const Outpar: char = '\u{8a}'; // c:165 )
156#[allow(non_upper_case_globals)]
157pub const Outparmath: char = '\u{8b}'; // c:166 ))
158#[allow(non_upper_case_globals)]
159pub const Qstring: char = '\u{8c}'; // c:167 "$"
160#[allow(non_upper_case_globals)]
161pub const Equals: char = '\u{8d}'; // c:168 =
162#[allow(non_upper_case_globals)]
163pub const Bar: char = '\u{8e}'; // c:169 |
164#[allow(non_upper_case_globals)]
165pub const Inbrace: char = '\u{8f}'; // c:170 {
166#[allow(non_upper_case_globals)]
167pub const Outbrace: char = '\u{90}'; // c:171 }
168#[allow(non_upper_case_globals)]
169pub const Inbrack: char = '\u{91}'; // c:172 [
170#[allow(non_upper_case_globals)]
171pub const Outbrack: char = '\u{92}'; // c:173 ]
172#[allow(non_upper_case_globals)]
173pub const Tick: char = '\u{93}'; // c:174 `
174#[allow(non_upper_case_globals)]
175pub const Inang: char = '\u{94}'; // c:175 <
176#[allow(non_upper_case_globals)]
177pub const Outang: char = '\u{95}'; // c:176 >
178#[allow(non_upper_case_globals)]
179pub const OutangProc: char = '\u{96}'; // c:177 >(...)
180#[allow(non_upper_case_globals)]
181pub const Quest: char = '\u{97}'; // c:178 ?
182#[allow(non_upper_case_globals)]
183pub const Tilde: char = '\u{98}'; // c:179 ~
184#[allow(non_upper_case_globals)]
185pub const Qtick: char = '\u{99}'; // c:180 "`"
186#[allow(non_upper_case_globals)]
187pub const Comma: char = '\u{9a}'; // c:181 ,
188#[allow(non_upper_case_globals)]
189pub const Dash: char = '\u{9b}'; // c:182 -
190#[allow(non_upper_case_globals)]
191pub const Bang: char = '\u{9c}'; // c:183 !
192/// `LAST_NORMAL_TOK` constant.
193pub const LAST_NORMAL_TOK: char = Bang; // c:188
194
195#[allow(non_upper_case_globals)]
196pub const Snull: char = '\u{9d}'; // c:193
197#[allow(non_upper_case_globals)]
198pub const Dnull: char = '\u{9e}'; // c:194
199#[allow(non_upper_case_globals)]
200pub const Bnull: char = '\u{9f}'; // c:195
201#[allow(non_upper_case_globals)]
202pub const Bnullkeep: char = '\u{a0}'; // c:200
203#[allow(non_upper_case_globals)]
204pub const Nularg: char = '\u{a1}'; // c:206
205#[allow(non_upper_case_globals)]
206pub const Marker: char = '\u{a2}'; // c:224
207/// `SPECCHARS` constant.
208pub const SPECCHARS: &str = "#$^*()=|{}[]`<>?~;&\n\t \\\'\""; // c:228
209/// `PATCHARS` constant.
210pub const PATCHARS: &str = "#^*()|[]<>?~\\"; // c:232
211
212/// Port of `#define IS_DASH(x)` from `Src/zsh.h:242`.
213#[inline]
214#[allow(non_snake_case)]
215pub fn IS_DASH(x: char) -> bool {
216 x == '-' || x == Dash
217} // c:242
218
219// =============================================================================
220// 4. Quote types (zsh.h:252-294).
221// =============================================================================
222/// `QT_NONE` constant.
223pub const QT_NONE: i32 = 0; // c:257
224/// `QT_BACKSLASH` constant.
225pub const QT_BACKSLASH: i32 = 1; // c:259
226/// `QT_SINGLE` constant.
227pub const QT_SINGLE: i32 = 2; // c:261
228/// `QT_DOUBLE` constant.
229pub const QT_DOUBLE: i32 = 3; // c:263
230/// `QT_DOLLARS` constant.
231pub const QT_DOLLARS: i32 = 4; // c:265
232/// `QT_BACKTICK` constant.
233pub const QT_BACKTICK: i32 = 5; // c:271
234/// `QT_SINGLE_OPTIONAL` constant.
235pub const QT_SINGLE_OPTIONAL: i32 = 6; // c:276
236/// `QT_BACKSLASH_PATTERN` constant.
237pub const QT_BACKSLASH_PATTERN: i32 = 7; // c:282
238/// `QT_BACKSLASH_SHOWNULL` constant.
239pub const QT_BACKSLASH_SHOWNULL: i32 = 8; // c:286
240/// `QT_QUOTEDZPUTS` constant.
241pub const QT_QUOTEDZPUTS: i32 = 9; // c:291
242
243/// Port of `#define QT_IS_SINGLE(x)` from `Src/zsh.h:294`.
244#[inline]
245#[allow(non_snake_case)]
246pub fn QT_IS_SINGLE(x: i32) -> bool {
247 x == QT_SINGLE || x == QT_SINGLE_OPTIONAL
248}
249
250// =============================================================================
251// 5. Lexical tokens (zsh.h:304-371).
252// =============================================================================
253/// `lextok` type alias.
254#[allow(non_camel_case_types)]
255pub type lextok = i32;
256/// `NULLTOK` constant.
257pub const NULLTOK: lextok = 0; // c:305
258/// `SEPER` constant.
259pub const SEPER: lextok = 1;
260/// `NEWLIN` constant.
261pub const NEWLIN: lextok = 2;
262/// `SEMI` constant.
263pub const SEMI: lextok = 3;
264/// `DSEMI` constant.
265pub const DSEMI: lextok = 4;
266/// `AMPER` constant.
267pub const AMPER: lextok = 5;
268/// `INPAR_TOK` constant.
269pub const INPAR_TOK: lextok = 6; // collision with char INPAR; suffix
270/// `OUTPAR_TOK` constant.
271pub const OUTPAR_TOK: lextok = 7;
272/// `DBAR` constant.
273pub const DBAR: lextok = 8;
274/// `DAMPER` constant.
275pub const DAMPER: lextok = 9;
276/// `OUTANG_TOK` constant.
277pub const OUTANG_TOK: lextok = 10; // collision with char OUTANG
278/// `OUTANGBANG` constant.
279pub const OUTANGBANG: lextok = 11;
280/// `DOUTANG` constant.
281pub const DOUTANG: lextok = 12;
282/// `DOUTANGBANG` constant.
283pub const DOUTANGBANG: lextok = 13;
284/// `INANG_TOK` constant.
285pub const INANG_TOK: lextok = 14;
286/// `INOUTANG` constant.
287pub const INOUTANG: lextok = 15;
288/// `DINANG` constant.
289pub const DINANG: lextok = 16;
290/// `DINANGDASH` constant.
291pub const DINANGDASH: lextok = 17;
292/// `INANGAMP` constant.
293pub const INANGAMP: lextok = 18;
294/// `OUTANGAMP` constant.
295pub const OUTANGAMP: lextok = 19;
296/// `AMPOUTANG` constant.
297pub const AMPOUTANG: lextok = 20;
298/// `OUTANGAMPBANG` constant.
299pub const OUTANGAMPBANG: lextok = 21;
300/// `DOUTANGAMP` constant.
301pub const DOUTANGAMP: lextok = 22;
302/// `DOUTANGAMPBANG` constant.
303pub const DOUTANGAMPBANG: lextok = 23;
304/// `TRINANG` constant.
305pub const TRINANG: lextok = 24;
306/// `BAR_TOK` constant.
307pub const BAR_TOK: lextok = 25;
308/// `BARAMP` constant.
309pub const BARAMP: lextok = 26;
310/// `INOUTPAR` constant.
311pub const INOUTPAR: lextok = 27;
312/// `DINPAR` constant.
313pub const DINPAR: lextok = 28;
314/// `DOUTPAR` constant.
315pub const DOUTPAR: lextok = 29;
316/// `AMPERBANG` constant.
317pub const AMPERBANG: lextok = 30;
318/// `SEMIAMP` constant.
319pub const SEMIAMP: lextok = 31;
320/// `SEMIBAR` constant.
321pub const SEMIBAR: lextok = 32;
322/// `DOUTBRACK` constant.
323pub const DOUTBRACK: lextok = 33;
324/// `STRING_LEX` constant.
325pub const STRING_LEX: lextok = 34;
326/// `ENVSTRING` constant.
327pub const ENVSTRING: lextok = 35;
328/// `ENVARRAY` constant.
329pub const ENVARRAY: lextok = 36;
330/// `ENDINPUT` constant.
331pub const ENDINPUT: lextok = 37;
332/// `LEXERR` constant.
333pub const LEXERR: lextok = 38;
334/// `BANG_TOK` constant.
335pub const BANG_TOK: lextok = 39; // c:346
336/// `DINBRACK` constant.
337pub const DINBRACK: lextok = 40;
338/// `INBRACE_TOK` constant.
339pub const INBRACE_TOK: lextok = 41;
340/// `OUTBRACE_TOK` constant.
341pub const OUTBRACE_TOK: lextok = 42;
342/// `CASE` constant.
343pub const CASE: lextok = 43;
344/// `COPROC` constant.
345pub const COPROC: lextok = 44;
346/// `DOLOOP` constant.
347pub const DOLOOP: lextok = 45;
348/// `DONE` constant.
349pub const DONE: lextok = 46;
350/// `ELIF` constant.
351pub const ELIF: lextok = 47;
352/// `ELSE` constant.
353pub const ELSE: lextok = 48;
354/// `ZEND` constant.
355pub const ZEND: lextok = 49;
356/// `ESAC` constant.
357pub const ESAC: lextok = 50;
358/// `FI` constant.
359pub const FI: lextok = 51;
360/// `FOR` constant.
361pub const FOR: lextok = 52;
362/// `FOREACH` constant.
363pub const FOREACH: lextok = 53;
364/// `FUNC` constant.
365pub const FUNC: lextok = 54;
366/// `IF` constant.
367pub const IF: lextok = 55;
368/// `NOCORRECT` constant.
369pub const NOCORRECT: lextok = 56;
370/// `REPEAT` constant.
371pub const REPEAT: lextok = 57;
372/// `SELECT` constant.
373pub const SELECT: lextok = 58;
374/// `THEN` constant.
375pub const THEN: lextok = 59;
376/// `TIME` constant.
377pub const TIME: lextok = 60;
378/// `UNTIL` constant.
379pub const UNTIL: lextok = 61;
380/// `WHILE` constant.
381pub const WHILE: lextok = 62;
382/// `TYPESET` constant.
383pub const TYPESET: lextok = 63; // c:370
384
385// =============================================================================
386// 6. Redirection types (zsh.h:377-408).
387// =============================================================================
388/// `REDIR_WRITE` constant.
389pub const REDIR_WRITE: i32 = 0;
390/// `REDIR_WRITENOW` constant.
391pub const REDIR_WRITENOW: i32 = 1;
392/// `REDIR_APP` constant.
393pub const REDIR_APP: i32 = 2;
394/// `REDIR_APPNOW` constant.
395pub const REDIR_APPNOW: i32 = 3;
396/// `REDIR_ERRWRITE` constant.
397pub const REDIR_ERRWRITE: i32 = 4;
398/// `REDIR_ERRWRITENOW` constant.
399pub const REDIR_ERRWRITENOW: i32 = 5;
400/// `REDIR_ERRAPP` constant.
401pub const REDIR_ERRAPP: i32 = 6;
402/// `REDIR_ERRAPPNOW` constant.
403pub const REDIR_ERRAPPNOW: i32 = 7;
404/// `REDIR_READWRITE` constant.
405pub const REDIR_READWRITE: i32 = 8;
406/// `REDIR_READ` constant.
407pub const REDIR_READ: i32 = 9;
408/// `REDIR_HEREDOC` constant.
409pub const REDIR_HEREDOC: i32 = 10;
410/// `REDIR_HEREDOCDASH` constant.
411pub const REDIR_HEREDOCDASH: i32 = 11;
412/// `REDIR_HERESTR` constant.
413pub const REDIR_HERESTR: i32 = 12;
414/// `REDIR_MERGEIN` constant.
415pub const REDIR_MERGEIN: i32 = 13;
416/// `REDIR_MERGEOUT` constant.
417pub const REDIR_MERGEOUT: i32 = 14;
418/// `REDIR_CLOSE` constant.
419pub const REDIR_CLOSE: i32 = 15;
420/// `REDIR_INPIPE` constant.
421pub const REDIR_INPIPE: i32 = 16;
422/// `REDIR_OUTPIPE` constant.
423pub const REDIR_OUTPIPE: i32 = 17;
424/// `REDIR_TYPE_MASK` constant.
425pub const REDIR_TYPE_MASK: i32 = 0x1f; // c:397
426/// `REDIR_VARID_MASK` constant.
427pub const REDIR_VARID_MASK: i32 = 0x20; // c:399
428/// `REDIR_FROM_HEREDOC_MASK` constant.
429pub const REDIR_FROM_HEREDOC_MASK: i32 = 0x40; // c:401
430/// `IS_WRITE_FILE` — see implementation.
431#[inline]
432#[allow(non_snake_case)]
433pub fn IS_WRITE_FILE(x: i32) -> bool {
434 x >= REDIR_WRITE && x <= REDIR_READWRITE
435}
436/// `IS_APPEND_REDIR` — see implementation.
437#[inline]
438#[allow(non_snake_case)]
439pub fn IS_APPEND_REDIR(x: i32) -> bool {
440 IS_WRITE_FILE(x) && (x & 2) != 0
441}
442/// `IS_CLOBBER_REDIR` — see implementation.
443#[inline]
444#[allow(non_snake_case)]
445pub fn IS_CLOBBER_REDIR(x: i32) -> bool {
446 IS_WRITE_FILE(x) && (x & 1) != 0
447}
448/// `IS_ERROR_REDIR` — see implementation.
449#[inline]
450#[allow(non_snake_case)]
451pub fn IS_ERROR_REDIR(x: i32) -> bool {
452 x >= REDIR_ERRWRITE && x <= REDIR_ERRAPPNOW
453}
454/// `IS_READFD` — see implementation.
455#[inline]
456#[allow(non_snake_case)]
457pub fn IS_READFD(x: i32) -> bool {
458 (x >= REDIR_READWRITE && x <= REDIR_MERGEIN) || x == REDIR_INPIPE
459}
460/// `IS_REDIROP` — see implementation.
461#[inline]
462#[allow(non_snake_case)]
463pub fn IS_REDIROP(x: lextok) -> bool {
464 x >= OUTANG_TOK && x <= TRINANG
465}
466
467// =============================================================================
468// 7. fdtable values (zsh.h:415-465).
469// =============================================================================
470/// `FDT_UNUSED` constant.
471pub const FDT_UNUSED: i32 = 0; // c:416
472/// `FDT_INTERNAL` constant.
473pub const FDT_INTERNAL: i32 = 1; // c:421
474/// `FDT_EXTERNAL` constant.
475pub const FDT_EXTERNAL: i32 = 2; // c:426
476/// `FDT_MODULE` constant.
477pub const FDT_MODULE: i32 = 3; // c:433
478/// `FDT_XTRACE` constant.
479pub const FDT_XTRACE: i32 = 4; // c:437
480/// `FDT_FLOCK` constant.
481pub const FDT_FLOCK: i32 = 5; // c:441
482/// `FDT_FLOCK_EXEC` constant.
483pub const FDT_FLOCK_EXEC: i32 = 6; // c:446
484/// `FDT_PROC_SUBST` constant.
485pub const FDT_PROC_SUBST: i32 = 7; // c:454
486/// `FDT_TYPE_MASK` constant.
487pub const FDT_TYPE_MASK: i32 = 15; // c:458
488/// `FDT_SAVED_MASK` constant.
489pub const FDT_SAVED_MASK: i32 = 16; // c:465
490
491// =============================================================================
492// 8. Input-stack flags (zsh.h:468-476).
493// =============================================================================
494/// `INP_FREE` constant.
495pub const INP_FREE: i32 = 1 << 0; // c:468
496/// `INP_ALIAS` constant.
497pub const INP_ALIAS: i32 = 1 << 1; // c:469
498/// `INP_HIST` constant.
499pub const INP_HIST: i32 = 1 << 2; // c:470
500/// `INP_CONT` constant.
501pub const INP_CONT: i32 = 1 << 3; // c:471
502/// `INP_ALCONT` constant.
503pub const INP_ALCONT: i32 = 1 << 4; // c:472
504/// `INP_HISTCONT` constant.
505pub const INP_HISTCONT: i32 = 1 << 5; // c:473
506/// `INP_LINENO` constant.
507pub const INP_LINENO: i32 = 1 << 6; // c:474
508/// `INP_APPEND` constant.
509pub const INP_APPEND: i32 = 1 << 7; // c:475
510/// `INP_RAW_KEEP` constant.
511pub const INP_RAW_KEEP: i32 = 1 << 8; // c:476
512
513// =============================================================================
514// 9. metafy flags (zsh.h:479-486).
515// =============================================================================
516/// `META_REALLOC` constant.
517pub const META_REALLOC: i32 = 0; // c:479
518/// `META_USEHEAP` constant.
519pub const META_USEHEAP: i32 = 1;
520/// `META_STATIC` constant.
521pub const META_STATIC: i32 = 2;
522/// `META_DUP` constant.
523pub const META_DUP: i32 = 3;
524/// `META_ALLOC` constant.
525pub const META_ALLOC: i32 = 4;
526/// `META_NOALLOC` constant.
527pub const META_NOALLOC: i32 = 5;
528/// `META_HEAPDUP` constant.
529pub const META_HEAPDUP: i32 = 6;
530/// `META_HREALLOC` constant.
531pub const META_HREALLOC: i32 = 7;
532
533// =============================================================================
534// 10. ZCONTEXT_* (zsh.h:489-496) + entersubsh_ret (c:499-504).
535// =============================================================================
536/// `ZCONTEXT_HIST` constant.
537pub const ZCONTEXT_HIST: i32 = 1 << 0; // c:491
538/// `ZCONTEXT_LEX` constant.
539pub const ZCONTEXT_LEX: i32 = 1 << 1; // c:493
540/// `ZCONTEXT_PARSE` constant.
541pub const ZCONTEXT_PARSE: i32 = 1 << 2; // c:495
542/// `entersubsh_ret` — see fields for layout.
543#[derive(Default)]
544#[allow(non_camel_case_types)]
545pub struct entersubsh_ret {
546 // c:499
547 pub gleader: i32, // c:501
548 pub list_pipe_job: i32, // c:503
549}
550
551// =============================================================================
552// 11. Linknode/linklist (zsh.h:557-572) + opaque pointer typedefs (c:510-549).
553// =============================================================================
554/// `linknode` — see fields for layout.
555#[allow(non_camel_case_types)]
556pub struct linknode {
557 // c:557
558 /// `next` field.
559 pub next: Option<Box<linknode>>,
560 /// `prev` field.
561 pub prev: Option<Box<linknode>>,
562 /// `dat` field.
563 pub dat: usize,
564}
565/// `linklist` — see fields for layout.
566#[allow(non_camel_case_types)]
567pub struct linklist {
568 // c:563
569 /// `first` field.
570 pub first: Option<Box<linknode>>,
571 /// `last` field.
572 pub last: Option<Box<linknode>>,
573 /// `flags` field.
574 pub flags: i32,
575}
576/// `LinkNode` type alias.
577pub type LinkNode = Box<linknode>; // c:533
578/// `LinkList` type alias.
579pub type LinkList = Box<linklist>; // c:534
580
581// Pointer typedefs for the ~50 struct types declared at c:510-549.
582// Each maps to a Box of the matching struct, with full field-by-field
583// body ports below (organized by C source line). Forward typedefs
584// here so structs that reference each other (e.g. param.old: Param)
585// can compile.
586/// `Alias` type alias.
587pub type Alias = Box<alias>; // c:510
588/// `Asgment` type alias.
589pub type Asgment = Box<asgment>; // c:511
590/// `Builtin` type alias.
591pub type Builtin = Box<builtin>; // c:512
592/// `Cmdnam` type alias.
593pub type Cmdnam = Box<cmdnam>; // c:513
594 // `struct complist` body lives in `crate::ported::glob` (mirrors
595 // C: declared in zsh.h via typedef alias, body defined in glob.c).
596 // The `Complist` alias here resolves to that struct.
597/// `Complist` type alias.
598pub type Complist = Box<crate::ported::glob::complist>; // c:514
599/// `Conddef` type alias.
600pub type Conddef = Box<conddef>; // c:515
601/// `Dirsav` type alias.
602pub type Dirsav = Box<dirsav>; // c:516
603/// `Emulation_options` type alias.
604pub type Emulation_options = Box<emulation_options>; // c:517
605/// `Execcmd_params` type alias.
606pub type Execcmd_params = Box<execcmd_params>; // c:518
607/// `Features` type alias.
608pub type Features = Box<features>; // c:519
609/// `Feature_enables` type alias.
610pub type Feature_enables = Box<feature_enables>; // c:520
611/// `Funcstack` type alias.
612pub type Funcstack = Box<funcstack>; // c:521
613/// `FuncWrap` type alias.
614pub type FuncWrap = Box<funcwrap>; // c:522
615/// `HashNode` type alias.
616pub type HashNode = Box<hashnode>; // c:523
617/// `HashTable` type alias.
618pub type HashTable = Box<hashtable>; // c:524
619/// `Heap` type alias.
620pub type Heap = Box<heap>; // c:525
621/// `Heapstack` type alias.
622pub type Heapstack = Box<heapstack>; // c:526
623/// `Histent` type alias.
624pub type Histent = Box<histent>; // c:527
625/// `Hookdef` type alias.
626pub type Hookdef = Box<hookdef>; // c:528
627/// `Imatchdata` type alias.
628pub type Imatchdata = Box<imatchdata>; // c:529
629/// `Job` type alias.
630pub type Job = Box<job>; // c:531
631/// `Jobfile` type alias.
632pub type Jobfile = Box<jobfile>; // c:530
633/// `Linkedmod` type alias.
634pub type Linkedmod = Box<linkedmod>; // c:532
635/// `Module` type alias.
636pub type Module = Box<module>; // c:535
637/// `Nameddir` type alias.
638pub type Nameddir = Box<nameddir>; // c:536
639/// `Options` type alias.
640pub type Options = Box<options>; // c:537
641/// `Optname` type alias.
642pub type Optname = Box<optname>; // c:538
643/// `Param` type alias.
644pub type Param = Box<param>; // c:539
645/// `Paramdef` type alias.
646pub type Paramdef = Box<paramdef>; // c:540
647/// `Patstralloc` type alias.
648pub type Patstralloc = Box<patstralloc>; // c:541
649/// `Patprog` type alias.
650pub type Patprog = Box<patprog>; // c:542
651/// `Prepromptfn` type alias.
652pub type Prepromptfn = Box<prepromptfn>; // c:543
653/// `Process` type alias.
654pub type Process = Box<process>; // c:544
655/// `Redir` type alias.
656pub type Redir = Box<redir>; // c:545
657/// `Reswd` type alias.
658pub type Reswd = Box<reswd>; // c:546
659/// `Shfunc` type alias.
660pub type Shfunc = Box<shfunc>; // c:547
661/// `Timedfn` type alias.
662pub type Timedfn = Box<timedfn>; // c:548
663/// `Value` type alias.
664pub type Value = Box<value>; // c:549
665/// `voidvoidfnptr_t` type alias.
666pub type voidvoidfnptr_t = fn(); // c:621
667
668// Body-by-body struct definitions (C source order, fields verbatim
669// from zsh.h). Reserved-keyword Rust fields renamed minimally
670// (type→typ, str→str, match→match_, new→new_, loop→loop_,
671// mod→mod_, fn→fn_, ref→ref_, in→in_, where→where_).
672
673/// Port of `struct prepromptfn` from `Src/zsh.h:626-628`.
674#[allow(non_camel_case_types)]
675pub struct prepromptfn {
676 // c:626
677 /// `func` field.
678 pub func: voidvoidfnptr_t,
679}
680
681/// Port of `struct timedfn` from `Src/zsh.h:634-637`.
682#[allow(non_camel_case_types)]
683pub struct timedfn {
684 // c:634
685 /// `func` field.
686 pub func: voidvoidfnptr_t,
687 pub when: i64, // time_t
688}
689
690/// Port of `typedef int (*CondHandler)(...)` from `Src/zsh.h:681`.
691pub type CondHandler = fn(args: &[String], id: i32) -> i32;
692
693/// Port of `struct conddef` from `Src/zsh.h:683-692`.
694#[allow(non_camel_case_types)]
695pub struct conddef {
696 // c:683
697 pub next: Option<Conddef>, // c:684
698 pub name: String, // c:685
699 pub flags: i32, // c:686 CONDF_*
700 pub handler: Option<CondHandler>, // c:687
701 pub min: i32, // c:688
702 pub max: i32, // c:689
703 pub condid: i32, // c:690
704 pub module: Option<String>, // c:691
705}
706
707/// Port of `struct dirsav` from `Src/zsh.h:1159-1164`.
708#[allow(non_camel_case_types)]
709pub struct dirsav {
710 // c:1159
711 pub dirfd: i32, // c:1160
712 pub level: i32, // c:1160
713 pub dirname: Option<String>, // c:1161
714 pub dev: u64, // c:1162 dev_t
715 pub ino: u64, // c:1163 ino_t
716}
717
718/// Port of `struct hashnode` from `Src/zsh.h:1226-1230`.
719#[allow(non_camel_case_types)]
720#[derive(Debug, Clone, Default)]
721pub struct hashnode {
722 // c:1226
723 pub next: Option<HashNode>, // c:1227
724 pub nam: String, // c:1228
725 pub flags: i32, // c:1229
726}
727
728// hashtable function-pointer typedefs (zsh.h:1175-1193).
729/// `VFunc` type alias.
730pub type VFunc = fn(usize) -> usize; // c:1172
731/// `FreeFunc` type alias.
732pub type FreeFunc = fn(usize); // c:1173
733/// `HashFunc` type alias.
734pub type HashFunc = fn(name: &str) -> u32; // c:1175
735/// `TableFunc` type alias.
736pub type TableFunc = fn(table: &mut hashtable); // c:1176
737/// `AddNodeFunc` type alias.
738pub type AddNodeFunc = fn(table: &mut hashtable, name: String, val: usize);
739/// `GetNodeFunc` type alias.
740pub type GetNodeFunc = fn(table: &hashtable, name: &str) -> Option<HashNode>;
741/// `RemoveNodeFunc` type alias.
742pub type RemoveNodeFunc = fn(table: &mut hashtable, name: &str) -> Option<HashNode>;
743/// `FreeNodeFunc` type alias.
744pub type FreeNodeFunc = fn(node: HashNode);
745/// `CompareFunc` type alias.
746pub type CompareFunc = fn(a: &str, b: &str) -> i32;
747/// `ScanFunc` type alias.
748pub type ScanFunc = fn(node: &HashNode, flags: i32);
749/// `ScanTabFunc` type alias.
750pub type ScanTabFunc = fn(table: &hashtable, func: ScanFunc, flags: i32);
751/// `PrintTableStats` type alias.
752pub type PrintTableStats = fn(table: &hashtable);
753
754/// Port of `struct hashtable` from `Src/zsh.h:1200-1222`.
755#[allow(non_camel_case_types)]
756#[derive(Clone)]
757pub struct hashtable {
758 // c:1200
759 pub hsize: i32, // c:1202
760 pub ct: i32, // c:1203
761 pub nodes: Vec<Option<HashNode>>, // c:1204
762 pub tmpdata: usize, // c:1205
763 pub hash: Option<HashFunc>, // c:1208
764 pub emptytable: Option<TableFunc>, // c:1209
765 pub filltable: Option<TableFunc>, // c:1210
766 pub cmpnodes: Option<CompareFunc>, // c:1211
767 pub addnode: Option<AddNodeFunc>, // c:1212
768 pub getnode: Option<GetNodeFunc>, // c:1213
769 pub getnode2: Option<GetNodeFunc>, // c:1214
770 pub removenode: Option<RemoveNodeFunc>, // c:1216
771 pub disablenode: Option<ScanFunc>, // c:1217
772 pub enablenode: Option<ScanFunc>, // c:1218
773 pub freenode: Option<FreeNodeFunc>, // c:1219
774 pub printnode: Option<ScanFunc>, // c:1220
775 pub scantab: Option<ScanTabFunc>, // c:1221
776}
777
778/// Port of `struct optname` from `Src/zsh.h:1239-1242`.
779#[allow(non_camel_case_types)]
780pub struct optname {
781 // c:1239
782 pub node: hashnode, // c:1240
783 pub optno: i32, // c:1241
784}
785
786/// Port of `struct reswd` from `Src/zsh.h:1246-1249`.
787#[allow(non_camel_case_types)]
788#[derive(Debug, Clone)]
789pub struct reswd {
790 // c:1246
791 pub node: hashnode, // c:1247
792 pub token: i32, // c:1248
793}
794
795/// Port of `struct alias` from `Src/zsh.h:1253-1257`.
796#[allow(non_camel_case_types)]
797#[derive(Debug, Clone)]
798pub struct alias {
799 // c:1253
800 pub node: hashnode, // c:1254
801 pub text: String, // c:1255
802 pub inuse: i32, // c:1256
803}
804
805/// Port of `struct asgment` from `Src/zsh.h:1267-1275`. Note the C
806/// union is split into two Option<…> fields here; only one is set
807/// per asgment (dispatched by `flags & ASG_ARRAY`).
808///
809/// `array` is typed `LinkList<String>` (the generic port in
810/// `src/ported/linklist.rs`) rather than the bare `LinkList` type
811/// alias above — C stores `char *` payload in the list, so the
812/// typed form is what `firstnode`/`getdata`/`nextnode` traversal
813/// expects at every assign-printing site (e.g. `Src/builtin.c:476-482`).
814#[allow(non_camel_case_types)]
815pub struct asgment {
816 // c:1267
817 pub node: linknode, // c:1268
818 pub name: String, // c:1269
819 pub flags: i32, // c:1270 ASG_*
820 pub scalar: Option<String>, // c:1272 union value.scalar
821 pub array: Option<crate::ported::linklist::LinkList<String>>, // c:1273 union value.array (LinkList of char *)
822}
823
824/// Port of `struct cmdnam` from `Src/zsh.h:1301-1308`. The C union
825/// `{ char **name; char *cmd; }` becomes two Option fields; only
826/// one is set per cmdnam (dispatched by `flags & HASHED`).
827#[allow(non_camel_case_types)]
828#[derive(Debug, Clone)]
829pub struct cmdnam {
830 // c:1301
831 pub node: hashnode, // c:1302
832 pub name: Option<Vec<String>>, // c:1304 union u.name
833 pub cmd: Option<String>, // c:1305 union u.cmd
834}
835
836/// Port of `struct shfunc` from `Src/zsh.h:1316-1325`.
837#[allow(non_camel_case_types)]
838#[derive(Debug, Clone)]
839pub struct shfunc {
840 // c:1316
841 pub node: hashnode, // c:1317
842 pub filename: Option<String>, // c:1318
843 pub lineno: i64, // c:1321 zlong
844 pub funcdef: Option<Eprog>, // c:1322
845 pub redir: Option<Eprog>, // c:1323
846 pub sticky: Option<Emulation_options>, // c:1324
847 /// **RUST-ONLY EXTENSION (no C counterpart).** Raw source text
848 /// for deferred-compile path: zshrs stores the function body
849 /// as-typed and parses on first invocation, vs C eagerly
850 /// compiling into `funcdef: Eprog` at definition time. When
851 /// the fusevm bytecode cache lands, this field gets retired in
852 /// favor of populating `funcdef` directly (matching C). Until
853 /// then, both fields can be set: `funcdef` for compiled
854 /// callers, `body` for the lazy-compile path.
855 pub body: Option<String>,
856}
857
858/// Port of `struct funcstack` from `Src/zsh.h:1348-1356`.
859#[allow(non_camel_case_types)]
860#[derive(Clone, Default)]
861pub struct funcstack {
862 // c:1348
863 pub prev: Option<Funcstack>, // c:1349
864 pub name: String, // c:1350
865 pub filename: Option<String>, // c:1351
866 pub caller: Option<String>, // c:1352
867 pub flineno: i64, // c:1353
868 pub lineno: i64, // c:1354
869 pub tp: i32, // c:1355 FS_*
870}
871
872/// Port of `typedef int (*WrapFunc)(...)` from `Src/zsh.h:1360`.
873pub type WrapFunc = fn(prog: Eprog, w: FuncWrap, name: &str) -> i32;
874
875/// Port of `struct funcwrap` from `Src/zsh.h:1362-1367`.
876#[allow(non_camel_case_types)]
877pub struct funcwrap {
878 // c:1362
879 pub next: Option<FuncWrap>, // c:1363
880 pub flags: i32, // c:1364
881 pub handler: Option<WrapFunc>, // c:1365
882 pub module: Option<Module>, // c:1366
883}
884
885/// Port of `struct builtin` from `Src/zsh.h:1440-1448`.
886#[allow(non_camel_case_types)]
887pub struct builtin {
888 // c:1440
889 pub node: hashnode, // c:1441
890 pub handlerfunc: Option<HandlerFunc>, // c:1442
891 pub minargs: i32, // c:1443
892 pub maxargs: i32, // c:1444
893 pub funcid: i32, // c:1445
894 pub optstr: Option<String>, // c:1446
895 pub defopts: Option<String>, // c:1447
896}
897
898/// Port of `struct execcmd_params` from `Src/zsh.h:1492-1501`.
899///
900/// C's `Wordcode beg/varspc/assignspc` are `wordcode *` — raw pointers
901/// into the running wordcode stream owned by `state->prog`. Rust's
902/// safe analog is `usize` (index into `state.prog.prog`); `None`
903/// stands in for C's `NULL`. The wordcode bytes themselves stay in
904/// `state.prog` — eparams just records start offsets.
905#[allow(non_camel_case_types)]
906#[derive(Default)]
907pub struct execcmd_params {
908 // c:1492
909 pub args: Option<Vec<String>>, // c:1493 LinkList args
910 pub redir: Option<Vec<redir>>, // c:1494 LinkList redir
911 pub beg: usize, // c:1495 Wordcode beg (pc index)
912 pub varspc: Option<usize>, // c:1496 Wordcode varspc (NULL → None)
913 pub assignspc: Option<usize>, // c:1497 Wordcode assignspc
914 pub typ: i32, // c:1498 (Rust keyword `type`)
915 pub postassigns: i32, // c:1499
916 pub htok: i32, // c:1500
917}
918
919/// Port of `struct module` from `Src/zsh.h:1503-1513`. C uses a union
920/// for handle/linked/alias dispatched implicitly by load type; Rust
921/// port keeps three Options.
922///
923/// `autoloads`/`deps` are `LinkList<String>` because C's untyped
924/// `LinkList` carries `char *` payload for these fields (see
925/// `Src/module.c:2392` `zaddlinknode(m->deps, dep)` etc.).
926#[allow(non_camel_case_types)]
927#[derive(Debug)]
928pub struct module {
929 // c:1503
930 pub node: hashnode, // c:1504
931 pub handle: Option<usize>, // c:1506 union.handle (void *)
932 pub linked: Option<Linkedmod>, // c:1507 union.linked
933 pub alias: Option<String>, // c:1508 union.alias
934 pub autoloads: Option<crate::ported::linklist::LinkList<String>>, // c:1510
935 pub deps: Option<crate::ported::linklist::LinkList<String>>, // c:1511
936 pub wrapper: i32, // c:1512
937}
938
939impl module {
940 /// Construct a fresh statically-linked module entry. Mirrors C's
941 /// `zshcalloc(sizeof(*m))` + `m->node.nam = ztrdup(name)` pattern
942 /// at `Src/module.c:361` (`register_module`).
943 pub fn new(name: &str) -> Self {
944 Self {
945 node: hashnode {
946 next: None,
947 nam: name.to_string(),
948 flags: MOD_LINKED,
949 },
950 handle: None,
951 linked: None,
952 alias: None,
953 autoloads: None,
954 deps: None,
955 wrapper: 0,
956 }
957 }
958
959 /// True if the module is currently usable.
960 /// Mirrors C's `MOD_BUSY`/`MOD_UNLOAD` checks at `Src/module.c:1703`
961 /// (`module_loaded`): the module exists and `MOD_UNLOAD` is clear.
962 pub fn is_loaded(&self) -> bool {
963 (self.node.flags & MOD_LINKED) != 0 && (self.node.flags & MOD_UNLOAD) == 0
964 }
965}
966
967/// Port of module fn-pointer typedefs from `Src/zsh.h:1534-1537`.
968pub type Module_generic_func = fn() -> i32;
969/// `Module_void_func` type alias.
970pub type Module_void_func = fn(m: &module) -> i32;
971/// `Module_features_func` type alias.
972pub type Module_features_func = fn(m: &module, features: &mut Vec<String>) -> i32;
973/// `Module_enables_func` type alias.
974pub type Module_enables_func = fn(m: &module, enables: &mut Vec<i32>) -> i32;
975
976/// Port of `struct linkedmod` from `Src/zsh.h:1539-1547`.
977#[allow(non_camel_case_types)]
978#[derive(Debug)]
979pub struct linkedmod {
980 // c:1539
981 pub name: String, // c:1540
982 pub setup: Option<Module_void_func>, // c:1541
983 pub features: Option<Module_features_func>, // c:1542
984 pub enables: Option<Module_enables_func>, // c:1543
985 pub boot: Option<Module_void_func>, // c:1544
986 pub cleanup: Option<Module_void_func>, // c:1545
987 pub finish: Option<Module_void_func>, // c:1546
988}
989
990/// Port of `struct features` from `Src/zsh.h:1553-1568`.
991#[allow(non_camel_case_types)]
992pub struct features {
993 // c:1553
994 pub bn_list: Option<Builtin>, // c:1555
995 pub bn_size: i32, // c:1556
996 pub cd_list: Option<Conddef>, // c:1558
997 pub cd_size: i32, // c:1559
998 pub mf_list: Option<MathFunc>, // c:1561
999 pub mf_size: i32, // c:1562
1000 pub pd_list: Option<Paramdef>, // c:1564
1001 pub pd_size: i32, // c:1565
1002 pub n_abstract: i32, // c:1567
1003}
1004
1005/// Port of `struct feature_enables` from `Src/zsh.h:1573-1578`.
1006#[allow(non_camel_case_types)]
1007pub struct feature_enables {
1008 // c:1573
1009 pub str: String, // c:1575 (Rust keyword `str`)
1010 pub pat: Option<Patprog>, // c:1577
1011}
1012
1013/// Port of `typedef int (*Hookfn)(Hookdef, void *)` from `Src/zsh.h:1582`.
1014/// Real Rust fn-pointer matching the C ABI of a hook callback.
1015pub type Hookfn = fn(h: *mut hookdef, d: *mut std::ffi::c_void) -> i32;
1016
1017/// Port of `struct hookdef` from `Src/zsh.h:1584-1590`.
1018/// `next` and `funcs` are raw pointers matching the C
1019/// `Hookdef next` / `LinkList funcs` types exactly. NULL is represented
1020/// by `std::ptr::null_mut()`. Backing storage for hookdef nodes is
1021/// expected to be `Box::leak`'d (mirroring C's static-storage
1022/// `zshhooks[]` array and module-side `struct hookdef foo[] = { ... }`
1023/// constants).
1024#[allow(non_camel_case_types)]
1025pub struct hookdef {
1026 // c:1584
1027 pub next: *mut hookdef, // c:1585 — struct hookdef *
1028 pub name: String, // c:1586 — char *
1029 pub def: Option<Hookfn>, // c:1587 — Hookfn (NULL = None)
1030 pub flags: i32, // c:1588
1031 pub funcs: *mut linklist, // c:1589 — LinkList (struct linklist *)
1032}
1033// SAFETY: hookdef contains raw pointers. C zsh is single-threaded;
1034// zshrs serializes hook operations via the module-level `hooktab`
1035// AtomicPtr + the global_state_lock used by tests. Marking explicitly
1036// because raw pointers default to !Send/!Sync.
1037unsafe impl Send for hookdef {}
1038unsafe impl Sync for hookdef {}
1039
1040/// Port of `struct patprog` from `Src/zsh.h:1601-1611`.
1041///
1042/// C layout uses a trailing byte buffer accessed via
1043/// `(char *)prog + prog->startoff`; the Rust port stores it inline
1044/// as a `code: Vec<u8>` field. The opcode stream layout is preserved
1045/// byte-for-byte — `startoff` and `size` index into `code`.
1046///
1047#[derive(Debug, Clone)]
1048#[allow(non_camel_case_types)]
1049pub struct patprog {
1050 // c:1601
1051 pub startoff: i64, // c:1602
1052 pub size: i64, // c:1603
1053 pub mustoff: i64, // c:1604
1054 pub patmlen: i64, // c:1605
1055 pub globflags: i32, // c:1606
1056 pub globend: i32, // c:1607
1057 pub flags: i32, // c:1608 PAT_*
1058 pub patnpar: i32, // c:1609
1059 pub patstartch: u8, // c:1610 (last field per zsh.h)
1060}
1061
1062/// Port of `struct patstralloc` from `Src/zsh.h:1613-1620`.
1063#[allow(non_camel_case_types)]
1064pub struct patstralloc {
1065 // c:1613
1066 pub unmetalen: i32, // c:1614
1067 pub unmetalenp: i32, // c:1615
1068 pub alloced: Option<String>, // c:1617
1069 pub progstrunmeta: Option<String>, // c:1618
1070 pub progstrunmetalen: i32, // c:1619
1071}
1072
1073/// Port of `struct zpc_disables_save` from `Src/zsh.h:1681-1689`.
1074#[allow(non_camel_case_types)]
1075pub struct zpc_disables_save {
1076 // c:1681
1077 pub next: Option<Box<zpc_disables_save>>, // c:1682
1078 pub disables: u32, // c:1688
1079}
1080/// `Zpc_disables_save` type alias.
1081pub type Zpc_disables_save = Box<zpc_disables_save>; // c:1691
1082
1083/// Port of `struct imatchdata` from `Src/zsh.h:1740-1760`.
1084#[allow(non_camel_case_types)]
1085pub struct imatchdata {
1086 // c:1740
1087 pub mstr: Option<String>, // c:1742
1088 pub mlen: i32, // c:1744
1089 pub ustr: Option<String>, // c:1746
1090 pub ulen: i32, // c:1748
1091 pub flags: i32, // c:1750 SUB_*
1092 pub replstr: Option<String>, // c:1752
1093 // c:1759 — C `LinkList repllist` is a heterogeneous void* list of
1094 // `struct repldata`. The Rust `LinkList`/`linklist` substrate stores
1095 // a placeholder `dat: usize` and can't hold `repldata`, so the
1096 // faithful representation of "a list of repldata nodes" is a typed
1097 // Vec<repldata>. get_match_ret pushes onto it; the assembler reads it.
1098 pub repllist: Option<Vec<repldata>>, // c:1759
1099}
1100
1101// gsu_* function-pointer typedefs (zsh.h:1790-1794) + structs.
1102/// `GsuScalar` type alias.
1103pub type GsuScalar = Box<gsu_scalar>; // c:1790
1104/// `GsuInteger` type alias.
1105pub type GsuInteger = Box<gsu_integer>; // c:1791
1106/// `GsuFloat` type alias.
1107pub type GsuFloat = Box<gsu_float>; // c:1792
1108/// `GsuArray` type alias.
1109pub type GsuArray = Box<gsu_array>; // c:1793
1110/// `GsuHash` type alias.
1111pub type GsuHash = Box<gsu_hash>; // c:1794
1112/// `gsu_scalar` — see fields for layout.
1113#[allow(non_camel_case_types)]
1114#[derive(Clone)]
1115pub struct gsu_scalar {
1116 // c:1796
1117 pub getfn: fn(pm: ¶m) -> String, // c:1797
1118 pub setfn: fn(pm: &mut param, val: String), // c:1798
1119 pub unsetfn: fn(pm: &mut param, exp: i32), // c:1799
1120}
1121/// `gsu_integer` — see fields for layout.
1122#[allow(non_camel_case_types)]
1123#[derive(Clone)]
1124pub struct gsu_integer {
1125 // c:1802
1126 pub getfn: fn(pm: ¶m) -> i64,
1127 /// `setfn` field.
1128 pub setfn: fn(pm: &mut param, val: i64),
1129 /// `unsetfn` field.
1130 pub unsetfn: fn(pm: &mut param, exp: i32),
1131}
1132/// `gsu_float` — see fields for layout.
1133#[allow(non_camel_case_types)]
1134#[derive(Clone)]
1135pub struct gsu_float {
1136 // c:1808
1137 pub getfn: fn(pm: ¶m) -> f64,
1138 /// `setfn` field.
1139 pub setfn: fn(pm: &mut param, val: f64),
1140 /// `unsetfn` field.
1141 pub unsetfn: fn(pm: &mut param, exp: i32),
1142}
1143/// `gsu_array` — see fields for layout.
1144#[allow(non_camel_case_types)]
1145#[derive(Clone)]
1146pub struct gsu_array {
1147 // c:1814
1148 pub getfn: fn(pm: ¶m) -> Vec<String>,
1149 /// `setfn` field.
1150 pub setfn: fn(pm: &mut param, val: Vec<String>),
1151 /// `unsetfn` field.
1152 pub unsetfn: fn(pm: &mut param, exp: i32),
1153}
1154/// `gsu_hash` — see fields for layout.
1155#[allow(non_camel_case_types)]
1156#[derive(Clone)]
1157pub struct gsu_hash {
1158 // c:1820
1159 pub getfn: fn(pm: ¶m) -> Option<&HashTable>,
1160 /// `setfn` field.
1161 pub setfn: fn(pm: &mut param, val: HashTable),
1162 /// `unsetfn` field.
1163 pub unsetfn: fn(pm: &mut param, exp: i32),
1164}
1165
1166/// Port of `struct param` from `Src/zsh.h:1829-1867`. The C unions
1167/// `u` (data) and `gsu` (vtable) are flattened into per-variant
1168/// fields; the dispatcher looks at `node.flags & PM_TYPE` and reads
1169/// the matching field.
1170#[allow(non_camel_case_types)]
1171#[derive(Clone, Default)]
1172pub struct param {
1173 // c:1829
1174 pub node: hashnode, // c:1830
1175 // u union (c:1833-1842):
1176 pub u_data: usize, // c:1834 void *data
1177 // c:1834 — typed view of `u.data` for PM_TIED scalars, where C
1178 // stores a `struct tieddata *` (Src/zsh.h:1870-1873) carrying the
1179 // partner-array pointer and the joinchar from `typeset -T s a SEP`.
1180 pub u_tied: Option<Box<tieddata>>,
1181 pub u_arr: Option<Vec<String>>, // c:1835 char **arr
1182 pub u_str: Option<String>, // c:1836 char *str
1183 pub u_val: i64, // c:1837 zlong val
1184 pub u_dval: f64, // c:1839 double dval
1185 pub u_hash: Option<HashTable>, // c:1841 HashTable hash
1186 // gsu vtable union (c:1852-1858):
1187 pub gsu_s: Option<GsuScalar>, // c:1853
1188 pub gsu_i: Option<GsuInteger>, // c:1854
1189 pub gsu_f: Option<GsuFloat>, // c:1855
1190 pub gsu_a: Option<GsuArray>, // c:1856
1191 pub gsu_h: Option<GsuHash>, // c:1857
1192 pub base: i32, // c:1860
1193 pub width: i32, // c:1862
1194 pub env: Option<String>, // c:1863
1195 pub ename: Option<String>, // c:1864
1196 pub old: Option<Param>, // c:1865
1197 pub level: i32, // c:1866
1198}
1199
1200/// Port of `struct tieddata` from `Src/zsh.h:1870-1873`.
1201#[allow(non_camel_case_types)]
1202#[derive(Clone)]
1203pub struct tieddata {
1204 // c:1870
1205 pub arrptr: Option<Vec<String>>, // c:1871 char ***arrptr
1206 pub joinchar: i32, // c:1872
1207}
1208
1209/// Port of `struct repldata` from `Src/zsh.h:2003-2006`.
1210#[allow(non_camel_case_types)]
1211pub struct repldata {
1212 // c:2003
1213 pub b: i32, // c:2004
1214 pub e: i32, // c:2004
1215 pub replstr: Option<String>, // c:2005
1216}
1217/// `Repldata` type alias.
1218pub type Repldata = Box<repldata>; // c:2007
1219
1220/// Port of `struct paramdef` from `Src/zsh.h:2082-2090`.
1221#[allow(non_camel_case_types)]
1222#[derive(Default)]
1223pub struct paramdef {
1224 // c:2082
1225 pub name: String, // c:2083
1226 pub flags: i32, // c:2084
1227 pub var: usize, // c:2085 void *
1228 pub gsu: usize, // c:2086 const void *
1229 pub getnfn: Option<GetNodeFunc>, // c:2087
1230 pub scantfn: Option<ScanTabFunc>, // c:2088
1231 pub pm: Option<Param>, // c:2089
1232}
1233
1234/// Port of `struct nameddir` from `Src/zsh.h:2149-2153`.
1235#[allow(non_camel_case_types)]
1236#[derive(Clone)]
1237pub struct nameddir {
1238 // c:2149
1239 pub node: hashnode, // c:2150
1240 pub dir: String, // c:2151
1241 pub diff: i32, // c:2152
1242}
1243
1244/// Port of `groupmap` from `Src/zsh.h:2161-2166`.
1245#[allow(non_camel_case_types)]
1246pub struct groupmap {
1247 // c:2161
1248 pub name: String, // c:2163
1249 pub gid: u32, // c:2165 gid_t
1250}
1251/// `Groupmap` type alias.
1252pub type Groupmap = Box<groupmap>; // c:2167
1253
1254/// Port of `groupset` from `Src/zsh.h:2170-2175`.
1255#[allow(non_camel_case_types)]
1256pub struct groupset {
1257 // c:2170
1258 pub array: Vec<groupmap>, // c:2172
1259 pub num: i32, // c:2174
1260}
1261/// `Groupset` type alias.
1262pub type Groupset = Box<groupset>; // c:2176
1263
1264/// Port of `struct histent` from `Src/zsh.h:2234-2250`.
1265#[allow(non_camel_case_types)]
1266pub struct histent {
1267 // c:2234
1268 pub node: hashnode, // c:2235
1269 pub up: Option<Histent>, // c:2237
1270 pub down: Option<Histent>, // c:2238
1271 pub zle_text: Option<String>, // c:2239
1272 pub stim: i64, // c:2244 time_t
1273 pub ftim: i64, // c:2245
1274 pub words: Vec<i16>, // c:2246
1275 pub nwords: i32, // c:2248
1276 pub histnum: i64, // c:2249 zlong
1277}
1278
1279/// Port of `struct emulation_options` from `Src/zsh.h:2570-2585`.
1280#[allow(non_camel_case_types)]
1281#[derive(Debug, Clone)]
1282pub struct emulation_options {
1283 // c:2570
1284 pub emulation: i32, // c:2572
1285 pub n_on_opts: i32, // c:2574
1286 pub n_off_opts: i32, // c:2576
1287 pub on_opts: Vec<OptIndex>, // c:2582
1288 pub off_opts: Vec<OptIndex>, // c:2584
1289}
1290
1291/// Port of `struct ttyinfo` from `Src/zsh.h:2593-2609`. The C
1292/// definition `#ifdef`-selects between `termios` / `termio` / sgtty.
1293/// Rust port stores the raw libc `termios` (the path taken on every
1294/// modern host).
1295#[allow(non_camel_case_types)]
1296#[derive(Debug, Clone)]
1297pub struct ttyinfo {
1298 // c:2593
1299 #[cfg(unix)]
1300 pub tio: libc::termios, // c:2595
1301 #[cfg(unix)]
1302 pub winsize: libc::winsize, // c:2607
1303}
1304
1305/// Port of `struct heapstack` from `Src/zsh.h:2871-2877`.
1306#[allow(non_camel_case_types)]
1307pub struct heapstack {
1308 // c:2871
1309 pub next: Option<Heapstack>, // c:2872
1310 pub used: usize, // c:2873
1311}
1312
1313/// Port of `struct heap` from `Src/zsh.h:2881-2898`.
1314#[allow(non_camel_case_types)]
1315pub struct heap {
1316 // c:2881
1317 pub next: Option<Heap>, // c:2882
1318 pub size: usize, // c:2883
1319 pub used: usize, // c:2884
1320 pub sp: Option<Heapstack>, // c:2885
1321}
1322
1323/// Port of `struct sortelt` from `Src/zsh.h:3013-3028`.
1324#[allow(non_camel_case_types)]
1325pub struct sortelt {
1326 // c:3013
1327 pub orig: String, // c:3015
1328 pub cmp: String, // c:3017
1329 pub origlen: i32, // c:3022
1330 pub len: i32, // c:3027
1331}
1332/// `SortElt` type alias.
1333pub type SortElt = Box<sortelt>; // c:3030
1334
1335/// Port of `struct hist_stack` from `Src/zsh.h:3037-3058`.
1336#[allow(non_camel_case_types)]
1337pub struct hist_stack {
1338 // c:3037
1339 pub histactive: i32, // c:3038
1340 pub histdone: i32, // c:3039
1341 pub stophist: i32, // c:3040
1342 pub hlinesz: i32, // c:3041
1343 pub defev: i64, // c:3042 zlong
1344 pub hline: Option<String>, // c:3043
1345 pub hptr: Option<String>, // c:3044
1346 pub chwords: Vec<i16>, // c:3045
1347 pub chwordlen: i32, // c:3046
1348 pub chwordpos: i32, // c:3047
1349 pub csp: i32, // c:3056
1350 pub hist_keep_comment: i32, // c:3057
1351}
1352
1353/// Port of `struct lexbufstate` from `Src/zsh.h:3069-3079`.
1354#[allow(non_camel_case_types)]
1355#[derive(Debug, Clone, Default)]
1356pub struct lexbufstate {
1357 // c:3069
1358 pub ptr: Option<String>, // c:3074
1359 pub siz: i32, // c:3076
1360 pub len: i32, // c:3078
1361}
1362
1363/// Port of `struct lex_stack` from `Src/zsh.h:3082-3096`.
1364#[allow(non_camel_case_types)]
1365#[derive(Debug, Clone, Default)]
1366pub struct lex_stack {
1367 // c:3082
1368 pub dbparens: i32, // c:3083
1369 pub isfirstln: i32, // c:3084
1370 pub isfirstch: i32, // c:3085
1371 pub lexflags: i32, // c:3086
1372 pub tok: lextok, // c:3087
1373 pub tokstr: Option<String>, // c:3088
1374 pub zshlextext: Option<String>, // c:3089
1375 pub lexbuf: lexbufstate, // c:3090
1376 pub lex_add_raw: i32, // c:3091
1377 pub tokstr_raw: Option<String>, // c:3092
1378 pub lexbuf_raw: lexbufstate, // c:3093
1379 pub lexstop: i32, // c:3094
1380 pub toklineno: i64, // c:3095
1381}
1382
1383/// Port of `struct parse_stack` from `Src/zsh.h:3099-3116`.
1384#[allow(non_camel_case_types)]
1385pub struct parse_stack {
1386 // c:3099
1387 pub hdocs: Option<Box<heredocs>>, // c:3100
1388 pub incmdpos: i32, // c:3102
1389 pub aliasspaceflag: i32, // c:3103
1390 pub incond: i32, // c:3104
1391 pub inredir: i32, // c:3105
1392 pub incasepat: i32, // c:3106
1393 pub isnewlin: i32, // c:3107
1394 pub infor: i32, // c:3108
1395 pub inrepeat_: i32, // c:3109
1396 pub intypeset: i32, // c:3110
1397 pub eclen: i32, // c:3112
1398 pub ecused: i32, // c:3112
1399 pub ecnpats: i32, // c:3112
1400 pub ecbuf: Wordcode, // c:3113
1401 pub ecstrs: Option<Eccstr>, // c:3114
1402 pub ecsoffs: i32, // c:3115
1403 pub ecssub: i32, // c:3115
1404 pub ecnfunc: i32, // c:3115
1405}
1406
1407/// Port of `struct heredocs` from `Src/zsh.h:1152-1157`. Used by
1408/// parse_stack above.
1409#[allow(non_camel_case_types)]
1410#[derive(Debug, Clone)]
1411pub struct heredocs {
1412 // c:1152
1413 pub next: Option<Box<heredocs>>, // c:1153
1414 pub typ: i32, // c:1154 (Rust keyword `type`)
1415 pub pc: i32, // c:1155
1416 pub str: Option<String>, // c:1156
1417}
1418
1419/// Port of `struct execstack` from `Src/zsh.h:1127-1150`.
1420#[allow(non_camel_case_types)]
1421pub struct execstack {
1422 // c:1127
1423 pub next: Option<Box<execstack>>, // c:1128
1424 pub list_pipe_pid: i32, // c:1130 pid_t
1425 pub nowait: i32, // c:1131
1426 pub pline_level: i32, // c:1132
1427 pub list_pipe_child: i32, // c:1133
1428 pub list_pipe_job: i32, // c:1134
1429 pub list_pipe_text: [u8; JOBTEXTSIZE], // c:1135
1430 pub lastval: i32, // c:1136
1431 pub noeval: i32, // c:1137
1432 pub badcshglob: i32, // c:1138
1433 pub cmdoutpid: i32, // c:1139
1434 pub cmdoutval: i32, // c:1140
1435 pub use_cmdoutval: i32, // c:1141
1436 pub procsubstpid: i32, // c:1142
1437 pub trap_return: i32, // c:1143
1438 pub trap_state: i32, // c:1144
1439 pub trapisfunc: i32, // c:1145
1440 pub traplocallevel: i32, // c:1146
1441 pub noerrs: i32, // c:1147
1442 pub this_noerrexit: i32, // c:1148
1443 pub underscore: Option<String>, // c:1149
1444}
1445
1446/// Port of `struct process` from `Src/zsh.h:1117-1125`.
1447///
1448/// Field-shape deviations from the C struct (documented for the
1449/// `zsh.h ↔ zsh_h.rs` audit):
1450/// - `text`: `String` instead of `char text[JOBTEXTSIZE]`. The
1451/// `JOBTEXTSIZE` cap in C is a buffer-overflow guard; Rust's owned
1452/// String removes the cap without losing the field's semantic.
1453/// - `bgtime` / `endtime`: `Option<std::time::Instant>` instead of
1454/// `struct timespec`. C uses timespec for monotonic-clock points;
1455/// Rust's `Instant` is the equivalent abstraction.
1456/// - `next` removed: C threads `struct process *next` for the
1457/// in-job singly-linked list; Rust port owns the list externally
1458/// via `job.procs: Vec<process>` so callers don't carry the chain
1459/// pointer per node.
1460#[allow(non_camel_case_types)]
1461#[derive(Debug, Clone)]
1462pub struct process {
1463 // c:1117
1464 pub pid: i32, // c:1119 pid_t
1465 pub text: String, // c:1120 char text[JOBTEXTSIZE]
1466 pub status: i32, // c:1121
1467 pub ti: timeinfo, // c:1122 child_times_t ti
1468 pub bgtime: Option<std::time::Instant>, // c:1123 struct timespec bgtime
1469 pub endtime: Option<std::time::Instant>, // c:1124 struct timespec endtime
1470}
1471
1472/// Port of `struct job` from `Src/zsh.h:1058-1071`.
1473///
1474/// Field-shape deviations from the C struct:
1475/// - `procs` / `auxprocs`: `Vec<process>` instead of singly-linked
1476/// `struct process *procs`. Equivalent semantics; Rust owns the
1477/// list ergonomically rather than threading `next` pointers.
1478/// - `filelist`: `Vec<String>` instead of `LinkList` of `char *`.
1479/// Same reasoning.
1480/// - `text`: added (Rust extension). C reconstructs job-display text
1481/// on demand by walking `procs->text`; the Rust port caches the
1482/// composed text here so display paths don't re-walk per call.
1483#[allow(non_camel_case_types)]
1484#[derive(Debug, Clone, Default)]
1485pub struct job {
1486 // c:1058
1487 pub gleader: i32, // c:1059 pid_t
1488 pub other: i32, // c:1060
1489 pub stat: i32, // c:1062 STAT_*
1490 pub pwd: Option<String>, // c:1063
1491 pub procs: Vec<process>, // c:1065 struct process *procs
1492 pub auxprocs: Vec<process>, // c:1066 struct process *auxprocs
1493 pub filelist: Vec<jobfile>, // c:1067 LinkList filelist (elements are struct jobfile)
1494 pub stty_in_env: i32, // c:1069
1495 pub ty: Option<Box<ttyinfo>>, // c:1070
1496 /// Rust extension: cached job-display text. C re-derives via
1497 /// `procs` walks in `printjob()` (`Src/jobs.c:1244+`).
1498 pub text: String,
1499}
1500
1501/// Port of `struct funcdump` from `Src/zsh.h:776-786`.
1502#[allow(non_camel_case_types)]
1503#[derive(Debug, Clone)]
1504pub struct funcdump {
1505 // c:776
1506 pub next: Option<FuncDump>, // c:777
1507 pub dev: u64, // c:778 dev_t
1508 pub ino: u64, // c:779 ino_t
1509 pub fd: i32, // c:780
1510 pub map: Wordcode, // c:781
1511 pub addr: Wordcode, // c:782
1512 pub len: i32, // c:783
1513 pub count: i32, // c:784
1514 pub filename: Option<String>, // c:785
1515}
1516
1517/// Port of `struct eprog` from `Src/zsh.h:805-815`.
1518#[allow(non_camel_case_types)]
1519#[derive(Debug, Clone, Default)]
1520pub struct eprog {
1521 // c:805
1522 pub flags: i32, // c:806 EF_*
1523 pub len: i32, // c:807
1524 pub npats: i32, // c:808
1525 pub nref: i32, // c:809
1526 pub pats: Vec<Patprog>, // c:810
1527 pub prog: Wordcode, // c:811
1528 pub strs: Option<String>, // c:812
1529 pub shf: Option<Shfunc>, // c:813
1530 pub dump: Option<FuncDump>, // c:814
1531 // !!! WARNING: RUST-ONLY FIELD — NO C COUNTERPART !!!
1532 // C keeps EVERY internal string metafied, so a .zwc string pool
1533 // needs no marker. zshrs's native eprogs carry clean UTF-8 pools;
1534 // only pools read verbatim from a C-zsh-written .zwc dump
1535 // (check_dump_file) still contain Meta (0x83) escapes. ecgetstr /
1536 // ecrawstr unmetafy per-string when this is set — whole-pool
1537 // unmetafy is impossible because wordcode words bake in byte
1538 // offsets. Without this, sourcing a .zwc-shadowed file rendered
1539 // every multibyte glyph as tofu (█ = E2 96 88 stored metafied as
1540 // E2 83 B6 88 → decoded U+20F6 + stray byte).
1541 pub strs_metafied: bool,
1542}
1543
1544/// Port of `struct estate` from `Src/zsh.h:824-828`.
1545#[allow(non_camel_case_types)]
1546pub struct estate {
1547 // c:824
1548 pub prog: Eprog, // c:825
1549 pub pc: usize, // c:826 Wordcode pc — index into prog.prog (C is wordcode *)
1550 pub strs: Option<String>, // c:827 copy of prog.strs at estate creation
1551 pub strs_offset: usize, // c:827 byte offset into strs — mirrors C `strs` pointer movement
1552}
1553
1554/// Port of `struct eccstr` from `Src/zsh.h:836-858`.
1555#[allow(non_camel_case_types)]
1556pub struct eccstr {
1557 // c:836
1558 pub left: Option<Eccstr>, // c:838
1559 pub right: Option<Eccstr>, // c:838
1560 pub str: Option<String>, // c:841
1561 pub offs: wordcode, // c:844
1562 pub aoffs: wordcode, // c:847
1563 pub nfunc: i32, // c:854
1564 pub hashval: u32, // c:857
1565}
1566
1567// =============================================================================
1568// 12. Z_* sublist flags (zsh.h:645-648).
1569// =============================================================================
1570/// `Z_TIMED` constant.
1571pub const Z_TIMED: i32 = 1 << 0; // c:645
1572/// `Z_SYNC` constant.
1573pub const Z_SYNC: i32 = 1 << 1; // c:646
1574/// `Z_ASYNC` constant.
1575pub const Z_ASYNC: i32 = 1 << 2; // c:647
1576/// `Z_DISOWN` constant.
1577pub const Z_DISOWN: i32 = 1 << 3; // c:648
1578
1579// =============================================================================
1580// 13. COND_* condition types (zsh.h:660-679).
1581// =============================================================================
1582/// `COND_NOT` constant.
1583pub const COND_NOT: i32 = 0;
1584/// `COND_AND` constant.
1585pub const COND_AND: i32 = 1;
1586/// `COND_OR` constant.
1587pub const COND_OR: i32 = 2;
1588/// `COND_STREQ` constant.
1589pub const COND_STREQ: i32 = 3;
1590/// `COND_STRDEQ` constant.
1591pub const COND_STRDEQ: i32 = 4;
1592/// `COND_STRNEQ` constant.
1593pub const COND_STRNEQ: i32 = 5;
1594/// `COND_STRLT` constant.
1595pub const COND_STRLT: i32 = 6;
1596/// `COND_STRGTR` constant.
1597pub const COND_STRGTR: i32 = 7;
1598/// `COND_NT` constant.
1599pub const COND_NT: i32 = 8;
1600/// `COND_OT` constant.
1601pub const COND_OT: i32 = 9;
1602/// `COND_EF` constant.
1603pub const COND_EF: i32 = 10;
1604/// `COND_EQ` constant.
1605pub const COND_EQ: i32 = 11;
1606/// `COND_NE` constant.
1607pub const COND_NE: i32 = 12;
1608/// `COND_LT` constant.
1609pub const COND_LT: i32 = 13;
1610/// `COND_GT` constant.
1611pub const COND_GT: i32 = 14;
1612/// `COND_LE` constant.
1613pub const COND_LE: i32 = 15;
1614/// `COND_GE` constant.
1615pub const COND_GE: i32 = 16;
1616/// `COND_REGEX` constant.
1617pub const COND_REGEX: i32 = 17;
1618/// `COND_MOD` constant.
1619pub const COND_MOD: i32 = 18;
1620/// `COND_MODI` constant.
1621pub const COND_MODI: i32 = 19;
1622/// `CONDF_INFIX` constant.
1623pub const CONDF_INFIX: i32 = 1; // c:695
1624/// `CONDF_ADDED` constant.
1625pub const CONDF_ADDED: i32 = 2; // c:697
1626/// `CONDF_AUTOALL` constant.
1627pub const CONDF_AUTOALL: i32 = 4; // c:699
1628
1629// =============================================================================
1630// 14. Redirection structures (zsh.h:706-740) + MULTIOUNIT.
1631// =============================================================================
1632/// `REDIRF_FROM_HEREDOC` constant.
1633pub const REDIRF_FROM_HEREDOC: i32 = 1; // c:708
1634/// `redir` — see fields for layout.
1635#[allow(non_camel_case_types)]
1636#[derive(Clone)]
1637pub struct redir {
1638 // c:713
1639 /// `typ` field.
1640 pub typ: i32,
1641 /// `flags` field.
1642 pub flags: i32,
1643 /// `fd1` field.
1644 pub fd1: i32,
1645 /// `fd2` field.
1646 pub fd2: i32,
1647 /// `name` field.
1648 pub name: Option<String>,
1649 /// `varid` field.
1650 pub varid: Option<String>,
1651 /// `here_terminator` field.
1652 pub here_terminator: Option<String>,
1653 /// `munged_here_terminator` field.
1654 pub munged_here_terminator: Option<String>,
1655}
1656/// `MULTIOUNIT` constant.
1657pub const MULTIOUNIT: usize = 8; // c:725
1658/// `multio` — see fields for layout.
1659#[allow(non_camel_case_types)]
1660pub struct multio {
1661 // c:735
1662 /// `ct` field.
1663 pub ct: i32,
1664 /// `rflag` field.
1665 pub rflag: i32,
1666 /// `pipe` field.
1667 pub pipe: i32,
1668 /// C `int fds[1]` with `VARLENARRAY` trailing-element realloc via
1669 /// `hrealloc(mn, sizeof + ct*sizeof(int))`. Rust uses a growable
1670 /// `Vec<i32>` (no MULTIOUNIT cap). Initial slot stamped on
1671 /// construction (c:2449).
1672 pub fds: Vec<i32>,
1673}
1674
1675// =============================================================================
1676// 15. value struct (zsh.h:744-755) + VALFLAG_* + MAX_ARRLEN.
1677// =============================================================================
1678/// `value` — see fields for layout.
1679#[allow(non_camel_case_types)]
1680pub struct value {
1681 // c:744
1682 /// `pm` field.
1683 pub pm: Option<Param>,
1684 /// `arr` field.
1685 pub arr: Vec<String>,
1686 /// `scanflags` field.
1687 pub scanflags: i32,
1688 /// `valflags` field.
1689 pub valflags: i32,
1690 /// `start` field.
1691 pub start: i32,
1692 /// `end` field.
1693 pub end: i32,
1694}
1695/// `VALFLAG_INV` constant.
1696pub const VALFLAG_INV: i32 = 0x0001; // c:758
1697/// `VALFLAG_EMPTY` constant.
1698pub const VALFLAG_EMPTY: i32 = 0x0002;
1699/// `VALFLAG_SUBST` constant.
1700pub const VALFLAG_SUBST: i32 = 0x0004;
1701/// `VALFLAG_REFSLICE` constant.
1702pub const VALFLAG_REFSLICE: i32 = 0x0008;
1703/// `MAX_ARRLEN` constant.
1704pub const MAX_ARRLEN: i32 = 262144; // c:764
1705
1706// =============================================================================
1707// 16. Word code types (zsh.h:770-1038).
1708// =============================================================================
1709/// `wordcode` type alias.
1710#[allow(non_camel_case_types)]
1711pub type wordcode = u32; // c:770
1712/// `Wordcode` type alias.
1713pub type Wordcode = Vec<wordcode>; // c:771
1714/// `FuncDump` type alias.
1715pub type FuncDump = Box<funcdump>; // c:773
1716/// `Eprog` type alias.
1717pub type Eprog = Box<eprog>; // c:774
1718/// `EF_REAL` constant.
1719pub const EF_REAL: i32 = 1; // c:817
1720/// `EF_HEAP` constant.
1721pub const EF_HEAP: i32 = 2;
1722/// `EF_MAP` constant.
1723pub const EF_MAP: i32 = 4;
1724/// `EF_RUN` constant.
1725pub const EF_RUN: i32 = 8;
1726/// `Estate` type alias.
1727pub type Estate = Box<estate>; // c:822
1728/// `Eccstr` type alias.
1729pub type Eccstr = Box<eccstr>; // c:835
1730/// `EC_NODUP` constant.
1731pub const EC_NODUP: i32 = 0; // c:869
1732/// `EC_DUP` constant.
1733pub const EC_DUP: i32 = 1; // c:872
1734/// `EC_DUPTOK` constant.
1735pub const EC_DUPTOK: i32 = 2; // c:878
1736/// `WC_CODEBITS` constant.
1737pub const WC_CODEBITS: u32 = 5; // c:882
1738/// `wc_code` — see implementation.
1739#[inline]
1740#[allow(non_snake_case)]
1741pub fn wc_code(c: wordcode) -> wordcode {
1742 c & ((1 << WC_CODEBITS) - 1)
1743}
1744/// `wc_data` — see implementation.
1745#[inline]
1746#[allow(non_snake_case)]
1747pub fn wc_data(c: wordcode) -> wordcode {
1748 c >> WC_CODEBITS
1749}
1750/// `wc_bdata` — see implementation.
1751#[inline]
1752#[allow(non_snake_case)]
1753pub fn wc_bdata(d: wordcode) -> wordcode {
1754 d << WC_CODEBITS
1755}
1756/// `wc_bld` — see implementation.
1757#[inline]
1758#[allow(non_snake_case)]
1759pub fn wc_bld(c: wordcode, d: wordcode) -> wordcode {
1760 c | (d << WC_CODEBITS)
1761}
1762/// `WC_END` constant.
1763pub const WC_END: wordcode = 0;
1764/// `WC_LIST` constant.
1765pub const WC_LIST: wordcode = 1;
1766/// `WC_SUBLIST` constant.
1767pub const WC_SUBLIST: wordcode = 2;
1768/// `WC_PIPE` constant.
1769pub const WC_PIPE: wordcode = 3;
1770/// `WC_REDIR` constant.
1771pub const WC_REDIR: wordcode = 4;
1772/// `WC_ASSIGN` constant.
1773pub const WC_ASSIGN: wordcode = 5;
1774/// `WC_SIMPLE` constant.
1775pub const WC_SIMPLE: wordcode = 6;
1776/// `WC_TYPESET` constant.
1777pub const WC_TYPESET: wordcode = 7;
1778/// `WC_SUBSH` constant.
1779pub const WC_SUBSH: wordcode = 8;
1780/// `WC_CURSH` constant.
1781pub const WC_CURSH: wordcode = 9;
1782/// `WC_TIMED` constant.
1783pub const WC_TIMED: wordcode = 10;
1784/// `WC_FUNCDEF` constant.
1785pub const WC_FUNCDEF: wordcode = 11;
1786/// `WC_FOR` constant.
1787pub const WC_FOR: wordcode = 12;
1788/// `WC_SELECT` constant.
1789pub const WC_SELECT: wordcode = 13;
1790/// `WC_WHILE` constant.
1791pub const WC_WHILE: wordcode = 14;
1792/// `WC_REPEAT` constant.
1793pub const WC_REPEAT: wordcode = 15;
1794/// `WC_CASE` constant.
1795pub const WC_CASE: wordcode = 16;
1796/// `WC_IF` constant.
1797pub const WC_IF: wordcode = 17;
1798/// `WC_COND` constant.
1799pub const WC_COND: wordcode = 18;
1800/// `WC_ARITH` constant.
1801pub const WC_ARITH: wordcode = 19;
1802/// `WC_AUTOFN` constant.
1803pub const WC_AUTOFN: wordcode = 20;
1804/// `WC_TRY` constant.
1805pub const WC_TRY: wordcode = 21;
1806/// `WC_COUNT` constant.
1807pub const WC_COUNT: wordcode = 22;
1808/// `Z_END` constant.
1809pub const Z_END: i32 = 1 << 4; // c:921
1810/// `Z_SIMPLE` constant.
1811pub const Z_SIMPLE: i32 = 1 << 5; // c:922
1812/// `WC_LIST_FREE` constant.
1813pub const WC_LIST_FREE: u32 = 6; // c:923
1814/// `WC_SUBLIST_END` constant.
1815pub const WC_SUBLIST_END: wordcode = 0;
1816/// `WC_SUBLIST_AND` constant.
1817pub const WC_SUBLIST_AND: wordcode = 1;
1818/// `WC_SUBLIST_OR` constant.
1819pub const WC_SUBLIST_OR: wordcode = 2;
1820/// `WC_SUBLIST_COPROC` constant.
1821pub const WC_SUBLIST_COPROC: wordcode = 4;
1822/// `WC_SUBLIST_NOT` constant.
1823pub const WC_SUBLIST_NOT: wordcode = 8;
1824/// `WC_SUBLIST_SIMPLE` constant.
1825pub const WC_SUBLIST_SIMPLE: wordcode = 16;
1826/// `WC_SUBLIST_FREE` constant.
1827pub const WC_SUBLIST_FREE: u32 = 5; // c:935
1828/// `WC_PIPE_END` constant.
1829pub const WC_PIPE_END: wordcode = 0;
1830/// `WC_PIPE_MID` constant.
1831pub const WC_PIPE_MID: wordcode = 1;
1832/// `WC_ASSIGN_SCALAR` constant.
1833pub const WC_ASSIGN_SCALAR: wordcode = 0;
1834/// `WC_ASSIGN_ARRAY` constant.
1835pub const WC_ASSIGN_ARRAY: wordcode = 1;
1836/// `WC_ASSIGN_NEW` constant.
1837pub const WC_ASSIGN_NEW: wordcode = 0;
1838/// `WC_ASSIGN_INC` constant.
1839pub const WC_ASSIGN_INC: wordcode = 1;
1840/// `WC_TIMED_EMPTY` constant.
1841pub const WC_TIMED_EMPTY: wordcode = 0;
1842/// `WC_TIMED_PIPE` constant.
1843pub const WC_TIMED_PIPE: wordcode = 1;
1844/// `WC_FOR_PPARAM` constant.
1845pub const WC_FOR_PPARAM: wordcode = 0;
1846/// `WC_FOR_LIST` constant.
1847pub const WC_FOR_LIST: wordcode = 1;
1848/// `WC_FOR_COND` constant.
1849pub const WC_FOR_COND: wordcode = 2;
1850/// `WC_SELECT_PPARAM` constant.
1851pub const WC_SELECT_PPARAM: wordcode = 0;
1852/// `WC_SELECT_LIST` constant.
1853pub const WC_SELECT_LIST: wordcode = 1;
1854/// `WC_WHILE_WHILE` constant.
1855pub const WC_WHILE_WHILE: wordcode = 0;
1856/// `WC_WHILE_UNTIL` constant.
1857pub const WC_WHILE_UNTIL: wordcode = 1;
1858/// `WC_CASE_HEAD` constant.
1859pub const WC_CASE_HEAD: wordcode = 0;
1860/// `WC_CASE_OR` constant.
1861pub const WC_CASE_OR: wordcode = 1;
1862/// `WC_CASE_AND` constant.
1863pub const WC_CASE_AND: wordcode = 2;
1864/// `WC_CASE_TESTAND` constant.
1865pub const WC_CASE_TESTAND: wordcode = 3;
1866/// `WC_CASE_FREE` constant.
1867pub const WC_CASE_FREE: u32 = 3; // c:1020
1868/// `WC_IF_HEAD` constant.
1869pub const WC_IF_HEAD: wordcode = 0;
1870/// `WC_IF_IF` constant.
1871pub const WC_IF_IF: wordcode = 1;
1872/// `WC_IF_ELIF` constant.
1873pub const WC_IF_ELIF: wordcode = 2;
1874/// `WC_IF_ELSE` constant.
1875pub const WC_IF_ELSE: wordcode = 3;
1876
1877// =============================================================================
1878// 16b. WC accessor + builder macros (zsh.h:918-1038).
1879// Each WC_X_TYPE / WC_X_SKIP / WCB_X is one of the per-opcode
1880// `wc_data` slicers / `wc_bld` constructors.
1881// =============================================================================
1882/// `WCB_END` — see implementation.
1883#[inline]
1884#[allow(non_snake_case)]
1885pub fn WCB_END() -> wordcode {
1886 wc_bld(WC_END, 0)
1887} // c:918
1888/// `WC_LIST_TYPE` — see implementation.
1889#[inline]
1890#[allow(non_snake_case)]
1891pub fn WC_LIST_TYPE(c: wordcode) -> wordcode {
1892 wc_data(c)
1893} // c:920
1894/// `WC_LIST_SKIP` — see implementation.
1895#[inline]
1896#[allow(non_snake_case)]
1897pub fn WC_LIST_SKIP(c: wordcode) -> wordcode {
1898 wc_data(c) >> WC_LIST_FREE
1899} // c:924
1900/// `WCB_LIST` — see implementation.
1901#[inline]
1902#[allow(non_snake_case)]
1903pub fn WCB_LIST(t: wordcode, o: wordcode) -> wordcode {
1904 wc_bld(WC_LIST, t | (o << WC_LIST_FREE))
1905}
1906/// `WC_SUBLIST_TYPE` — see implementation.
1907#[inline]
1908#[allow(non_snake_case)]
1909pub fn WC_SUBLIST_TYPE(c: wordcode) -> wordcode {
1910 wc_data(c) & 3
1911} // c:927
1912/// `WC_SUBLIST_FLAGS` — see implementation.
1913#[inline]
1914#[allow(non_snake_case)]
1915pub fn WC_SUBLIST_FLAGS(c: wordcode) -> wordcode {
1916 wc_data(c) & 0x1c
1917} // c:931
1918/// `WC_SUBLIST_SKIP` — see implementation.
1919#[inline]
1920#[allow(non_snake_case)]
1921pub fn WC_SUBLIST_SKIP(c: wordcode) -> wordcode {
1922 wc_data(c) >> WC_SUBLIST_FREE
1923}
1924/// `WCB_SUBLIST` — see implementation.
1925#[inline]
1926#[allow(non_snake_case)]
1927pub fn WCB_SUBLIST(t: wordcode, f: wordcode, o: wordcode) -> wordcode {
1928 wc_bld(WC_SUBLIST, t | f | (o << WC_SUBLIST_FREE))
1929}
1930/// `WC_PIPE_TYPE` — see implementation.
1931#[inline]
1932#[allow(non_snake_case)]
1933pub fn WC_PIPE_TYPE(c: wordcode) -> wordcode {
1934 wc_data(c) & 1
1935} // c:940
1936/// `WC_PIPE_LINENO` — see implementation.
1937#[inline]
1938#[allow(non_snake_case)]
1939pub fn WC_PIPE_LINENO(c: wordcode) -> wordcode {
1940 wc_data(c) >> 1
1941}
1942/// `WCB_PIPE` — see implementation.
1943#[inline]
1944#[allow(non_snake_case)]
1945pub fn WCB_PIPE(t: wordcode, l: wordcode) -> wordcode {
1946 wc_bld(WC_PIPE, t | (l << 1))
1947}
1948/// `WC_REDIR_TYPE` — see implementation.
1949#[inline]
1950#[allow(non_snake_case)]
1951pub fn WC_REDIR_TYPE(c: wordcode) -> i32 {
1952 (wc_data(c) & REDIR_TYPE_MASK as u32) as i32
1953}
1954/// `WC_REDIR_VARID` — see implementation.
1955#[inline]
1956#[allow(non_snake_case)]
1957pub fn WC_REDIR_VARID(c: wordcode) -> i32 {
1958 (wc_data(c) & REDIR_VARID_MASK as u32) as i32
1959}
1960/// `WC_REDIR_FROM_HEREDOC` — see implementation.
1961#[inline]
1962#[allow(non_snake_case)]
1963pub fn WC_REDIR_FROM_HEREDOC(c: wordcode) -> i32 {
1964 (wc_data(c) & REDIR_FROM_HEREDOC_MASK as u32) as i32
1965}
1966/// `WCB_REDIR` — see implementation.
1967#[inline]
1968#[allow(non_snake_case)]
1969pub fn WCB_REDIR(t: wordcode) -> wordcode {
1970 wc_bld(WC_REDIR, t)
1971}
1972/// `WC_REDIR_WORDS` — see implementation.
1973#[inline]
1974#[allow(non_snake_case)]
1975pub fn WC_REDIR_WORDS(c: wordcode) -> i32 {
1976 (if WC_REDIR_VARID(c) != 0 { 4 } else { 3 })
1977 + (if WC_REDIR_FROM_HEREDOC(c) != 0 { 2 } else { 0 })
1978}
1979/// `WC_ASSIGN_TYPE` — see implementation.
1980#[inline]
1981#[allow(non_snake_case)]
1982pub fn WC_ASSIGN_TYPE(c: wordcode) -> wordcode {
1983 wc_data(c) & 1
1984} // c:955
1985/// `WC_ASSIGN_TYPE2` — see implementation.
1986#[inline]
1987#[allow(non_snake_case)]
1988pub fn WC_ASSIGN_TYPE2(c: wordcode) -> wordcode {
1989 (wc_data(c) & 2) >> 1
1990}
1991/// `WC_ASSIGN_NUM` — see implementation.
1992#[inline]
1993#[allow(non_snake_case)]
1994pub fn WC_ASSIGN_NUM(c: wordcode) -> wordcode {
1995 wc_data(c) >> 2
1996}
1997/// `WCB_ASSIGN` — see implementation.
1998#[inline]
1999#[allow(non_snake_case)]
2000pub fn WCB_ASSIGN(t: wordcode, a: wordcode, n: wordcode) -> wordcode {
2001 wc_bld(WC_ASSIGN, t | (a << 1) | (n << 2))
2002}
2003/// `WC_SIMPLE_ARGC` — see implementation.
2004#[inline]
2005#[allow(non_snake_case)]
2006pub fn WC_SIMPLE_ARGC(c: wordcode) -> wordcode {
2007 wc_data(c)
2008} // c:970
2009/// `WCB_SIMPLE` — see implementation.
2010#[inline]
2011#[allow(non_snake_case)]
2012pub fn WCB_SIMPLE(n: wordcode) -> wordcode {
2013 wc_bld(WC_SIMPLE, n)
2014}
2015/// `WC_TYPESET_ARGC` — see implementation.
2016#[inline]
2017#[allow(non_snake_case)]
2018pub fn WC_TYPESET_ARGC(c: wordcode) -> wordcode {
2019 wc_data(c)
2020} // c:973
2021/// `WCB_TYPESET` — see implementation.
2022#[inline]
2023#[allow(non_snake_case)]
2024pub fn WCB_TYPESET(n: wordcode) -> wordcode {
2025 wc_bld(WC_TYPESET, n)
2026}
2027/// `WC_SUBSH_SKIP` — see implementation.
2028#[inline]
2029#[allow(non_snake_case)]
2030pub fn WC_SUBSH_SKIP(c: wordcode) -> wordcode {
2031 wc_data(c)
2032} // c:976
2033/// `WCB_SUBSH` — see implementation.
2034#[inline]
2035#[allow(non_snake_case)]
2036pub fn WCB_SUBSH(o: wordcode) -> wordcode {
2037 wc_bld(WC_SUBSH, o)
2038}
2039/// `WC_CURSH_SKIP` — see implementation.
2040#[inline]
2041#[allow(non_snake_case)]
2042pub fn WC_CURSH_SKIP(c: wordcode) -> wordcode {
2043 wc_data(c)
2044} // c:979
2045/// `WCB_CURSH` — see implementation.
2046#[inline]
2047#[allow(non_snake_case)]
2048pub fn WCB_CURSH(o: wordcode) -> wordcode {
2049 wc_bld(WC_CURSH, o)
2050}
2051/// `WC_TIMED_TYPE` — see implementation.
2052#[inline]
2053#[allow(non_snake_case)]
2054pub fn WC_TIMED_TYPE(c: wordcode) -> wordcode {
2055 wc_data(c)
2056} // c:982
2057/// `WCB_TIMED` — see implementation.
2058#[inline]
2059#[allow(non_snake_case)]
2060pub fn WCB_TIMED(t: wordcode) -> wordcode {
2061 wc_bld(WC_TIMED, t)
2062}
2063/// `WC_FUNCDEF_SKIP` — see implementation.
2064#[inline]
2065#[allow(non_snake_case)]
2066pub fn WC_FUNCDEF_SKIP(c: wordcode) -> wordcode {
2067 wc_data(c)
2068} // c:987
2069/// `WCB_FUNCDEF` — see implementation.
2070#[inline]
2071#[allow(non_snake_case)]
2072pub fn WCB_FUNCDEF(o: wordcode) -> wordcode {
2073 wc_bld(WC_FUNCDEF, o)
2074}
2075/// `WC_FOR_TYPE` — see implementation.
2076#[inline]
2077#[allow(non_snake_case)]
2078pub fn WC_FOR_TYPE(c: wordcode) -> wordcode {
2079 wc_data(c) & 3
2080} // c:990
2081/// `WC_FOR_SKIP` — see implementation.
2082#[inline]
2083#[allow(non_snake_case)]
2084pub fn WC_FOR_SKIP(c: wordcode) -> wordcode {
2085 wc_data(c) >> 2
2086}
2087/// `WCB_FOR` — see implementation.
2088#[inline]
2089#[allow(non_snake_case)]
2090pub fn WCB_FOR(t: wordcode, o: wordcode) -> wordcode {
2091 wc_bld(WC_FOR, t | (o << 2))
2092}
2093/// `WC_SELECT_TYPE` — see implementation.
2094#[inline]
2095#[allow(non_snake_case)]
2096pub fn WC_SELECT_TYPE(c: wordcode) -> wordcode {
2097 wc_data(c) & 1
2098} // c:997
2099/// `WC_SELECT_SKIP` — see implementation.
2100#[inline]
2101#[allow(non_snake_case)]
2102pub fn WC_SELECT_SKIP(c: wordcode) -> wordcode {
2103 wc_data(c) >> 1
2104}
2105/// `WCB_SELECT` — see implementation.
2106#[inline]
2107#[allow(non_snake_case)]
2108pub fn WCB_SELECT(t: wordcode, o: wordcode) -> wordcode {
2109 wc_bld(WC_SELECT, t | (o << 1))
2110}
2111/// `WC_WHILE_TYPE` — see implementation.
2112#[inline]
2113#[allow(non_snake_case)]
2114pub fn WC_WHILE_TYPE(c: wordcode) -> wordcode {
2115 wc_data(c) & 1
2116} // c:1003
2117/// `WC_WHILE_SKIP` — see implementation.
2118#[inline]
2119#[allow(non_snake_case)]
2120pub fn WC_WHILE_SKIP(c: wordcode) -> wordcode {
2121 wc_data(c) >> 1
2122}
2123/// `WCB_WHILE` — see implementation.
2124#[inline]
2125#[allow(non_snake_case)]
2126pub fn WCB_WHILE(t: wordcode, o: wordcode) -> wordcode {
2127 wc_bld(WC_WHILE, t | (o << 1))
2128}
2129/// `WC_REPEAT_SKIP` — see implementation.
2130#[inline]
2131#[allow(non_snake_case)]
2132pub fn WC_REPEAT_SKIP(c: wordcode) -> wordcode {
2133 wc_data(c)
2134} // c:1009
2135/// `WCB_REPEAT` — see implementation.
2136#[inline]
2137#[allow(non_snake_case)]
2138pub fn WCB_REPEAT(o: wordcode) -> wordcode {
2139 wc_bld(WC_REPEAT, o)
2140}
2141/// `WC_TRY_SKIP` — see implementation.
2142#[inline]
2143#[allow(non_snake_case)]
2144pub fn WC_TRY_SKIP(c: wordcode) -> wordcode {
2145 wc_data(c)
2146} // c:1012
2147/// `WCB_TRY` — see implementation.
2148#[inline]
2149#[allow(non_snake_case)]
2150pub fn WCB_TRY(o: wordcode) -> wordcode {
2151 wc_bld(WC_TRY, o)
2152}
2153/// `WC_CASE_TYPE` — see implementation.
2154#[inline]
2155#[allow(non_snake_case)]
2156pub fn WC_CASE_TYPE(c: wordcode) -> wordcode {
2157 wc_data(c) & 7
2158} // c:1015
2159/// `WC_CASE_SKIP` — see implementation.
2160#[inline]
2161#[allow(non_snake_case)]
2162pub fn WC_CASE_SKIP(c: wordcode) -> wordcode {
2163 wc_data(c) >> WC_CASE_FREE
2164}
2165/// `WCB_CASE` — see implementation.
2166#[inline]
2167#[allow(non_snake_case)]
2168pub fn WCB_CASE(t: wordcode, o: wordcode) -> wordcode {
2169 wc_bld(WC_CASE, t | (o << WC_CASE_FREE))
2170}
2171/// `WC_IF_TYPE` — see implementation.
2172#[inline]
2173#[allow(non_snake_case)]
2174pub fn WC_IF_TYPE(c: wordcode) -> wordcode {
2175 wc_data(c) & 3
2176} // c:1024
2177/// `WC_IF_SKIP` — see implementation.
2178#[inline]
2179#[allow(non_snake_case)]
2180pub fn WC_IF_SKIP(c: wordcode) -> wordcode {
2181 wc_data(c) >> 2
2182}
2183/// `WCB_IF` — see implementation.
2184#[inline]
2185#[allow(non_snake_case)]
2186pub fn WCB_IF(t: wordcode, o: wordcode) -> wordcode {
2187 wc_bld(WC_IF, t | (o << 2))
2188}
2189/// `WC_COND_TYPE` — see implementation.
2190#[inline]
2191#[allow(non_snake_case)]
2192pub fn WC_COND_TYPE(c: wordcode) -> wordcode {
2193 wc_data(c) & 127
2194} // c:1032
2195/// `WC_COND_SKIP` — see implementation.
2196#[inline]
2197#[allow(non_snake_case)]
2198pub fn WC_COND_SKIP(c: wordcode) -> wordcode {
2199 wc_data(c) >> 7
2200}
2201/// `WCB_COND` — see implementation.
2202#[inline]
2203#[allow(non_snake_case)]
2204pub fn WCB_COND(t: wordcode, o: wordcode) -> wordcode {
2205 wc_bld(WC_COND, t | (o << 7))
2206}
2207/// `WCB_ARITH` — see implementation.
2208#[inline]
2209#[allow(non_snake_case)]
2210pub fn WCB_ARITH() -> wordcode {
2211 wc_bld(WC_ARITH, 0)
2212} // c:1036
2213/// `WCB_AUTOFN` — see implementation.
2214#[inline]
2215#[allow(non_snake_case)]
2216pub fn WCB_AUTOFN() -> wordcode {
2217 wc_bld(WC_AUTOFN, 0)
2218} // c:1038
2219
2220// =============================================================================
2221// 16c. Other macros: BUILTIN/BIN_PREFIX/CONDDEF/HOOKDEF/PARAMDEF/etc.
2222// =============================================================================
2223
2224/// Port of `#define NULLBINCMD` from `Src/zsh.h:1438`.
2225pub const NULLBINCMD: Option<HandlerFunc> = None; // c:1438
2226
2227/// Port of `#define EMULATION(X)` from `Src/zsh.h:2347`.
2228/// C macro: `(emulation & (X))`. Reads the canonical `emulation`
2229/// static from `crate::ported::options::emulation` directly.
2230#[inline]
2231#[allow(non_snake_case)]
2232pub fn EMULATION(x: i32) -> bool {
2233 // c:2347
2234 let emul = crate::ported::options::emulation.load(std::sync::atomic::Ordering::Relaxed);
2235 (emul & x) != 0
2236}
2237
2238/// Port of `#define SHELL_EMULATION()` from `Src/zsh.h:2350`.
2239/// C macro: `(emulation & ((1<<5)-1))`. Reads the canonical
2240/// `emulation` static directly.
2241#[inline]
2242#[allow(non_snake_case)]
2243pub fn SHELL_EMULATION() -> i32 {
2244 // c:2350
2245 let emul = crate::ported::options::emulation.load(std::sync::atomic::Ordering::Relaxed);
2246 emul & ((1 << 5) - 1)
2247}
2248
2249/// Port of `#define IN_EVAL_TRAP()` from `Src/zsh.h:2962`.
2250/// C macro reads the four globals `intrap` / `trapisfunc` /
2251/// `traplocallevel` / `locallevel` directly with no args; Rust
2252/// matches by reading the canonical statics
2253/// (`signals::intrap`, `signals::trapisfunc`,
2254/// `signals::traplocallevel`, `params::locallevel`) inside.
2255#[inline]
2256#[allow(non_snake_case)]
2257pub fn IN_EVAL_TRAP() -> bool {
2258 // c:2962
2259 crate::ported::signals::intrap.load(Ordering::Relaxed) != 0
2260 && crate::ported::signals::trapisfunc.load(Ordering::Relaxed) == 0
2261 && crate::ported::signals::traplocallevel.load(Ordering::Relaxed)
2262 == crate::ported::params::locallevel.load(Ordering::Relaxed)
2263}
2264
2265/// Port of `#define ASG_ARRAYP(asg)` from `Src/zsh.h:1288`.
2266#[inline]
2267#[allow(non_snake_case)]
2268pub fn ASG_ARRAYP(asg: &asgment) -> bool {
2269 (asg.flags & ASG_ARRAY) != 0
2270}
2271
2272/// Port of `#define ASG_VALUEP(asg)` from `Src/zsh.h:1296`.
2273#[inline]
2274#[allow(non_snake_case)]
2275pub fn ASG_VALUEP(asg: &asgment) -> bool {
2276 ASG_ARRAYP(asg) || asg.scalar.is_some()
2277}
2278
2279/// Port of `#define MB_METASTRLEN2END(str, widthp, eptr)` from
2280/// `Src/zsh.h:3282/3363`. C: `mb_metastrlenend(str, widthp, eptr)`
2281/// (multibyte) or `ztrlenend(str, eptr)` (non-multibyte). Rust port
2282/// counts metafied chars from `str` up to `eptr` (exclusive).
2283#[inline]
2284#[allow(non_snake_case)]
2285pub fn MB_METASTRLEN2END(s: &str, widthp: bool, eptr: usize) -> usize {
2286 let truncated = if eptr <= s.len() { &s[..eptr] } else { s };
2287 MB_METASTRLEN2(truncated, widthp)
2288}
2289
2290// Hook-table indices (zsh.h:3259-3262). C: `(zshhooks + N)` —
2291// the Rust port exposes the offsets; consumers index into the
2292// `zshhooks[]` array themselves.
2293/// `EXITHOOK_OFFSET` constant.
2294pub const EXITHOOK_OFFSET: usize = 0; // c:3259
2295/// `BEFORETRAPHOOK_OFFSET` constant.
2296pub const BEFORETRAPHOOK_OFFSET: usize = 1; // c:3260
2297/// `AFTERTRAPHOOK_OFFSET` constant.
2298pub const AFTERTRAPHOOK_OFFSET: usize = 2; // c:3261
2299/// `GETCOLORATTR_OFFSET` constant.
2300pub const GETCOLORATTR_OFFSET: usize = 3; // c:3262
2301
2302/// Port of `#define STOPHIST` from `Src/zsh.h:2267`. Increments the
2303/// `stophist` global by 4. Rust port exposes the delta; the global
2304/// itself lives in `hist.rs`.
2305pub const STOPHIST_DELTA: i32 = 4; // c:2267
2306/// `ALLOWHIST_DELTA` constant.
2307pub const ALLOWHIST_DELTA: i32 = -4; // c:2268
2308
2309/// Aliases under the canonical C macro names. C uses these in
2310/// statement-style: `STOPHIST` and `ALLOWHIST` expand to assignments
2311/// modifying the global; Rust port exposes them as the deltas.
2312pub const STOPHIST: i32 = STOPHIST_DELTA;
2313/// `ALLOWHIST` constant.
2314pub const ALLOWHIST: i32 = ALLOWHIST_DELTA;
2315
2316/// Hook-table indices under their canonical zsh.h names (C: `(zshhooks
2317/// + N)`).
2318pub const EXITHOOK: usize = EXITHOOK_OFFSET;
2319/// `BEFORETRAPHOOK` constant.
2320pub const BEFORETRAPHOOK: usize = BEFORETRAPHOOK_OFFSET;
2321/// `AFTERTRAPHOOK` constant.
2322pub const AFTERTRAPHOOK: usize = AFTERTRAPHOOK_OFFSET;
2323/// `GETCOLORATTR` constant.
2324pub const GETCOLORATTR: usize = GETCOLORATTR_OFFSET;
2325
2326/// Port of `#define ZLONG_CONST(x)` from `Src/zsh.h:68/72/78/83`.
2327/// C casts an integer literal to `zlong` via the `l`/`ll` suffix.
2328/// In Rust integer literals are typed at the use site; this macro
2329/// is an explicit cast to `zlong` (= `i64`).
2330#[inline]
2331#[allow(non_snake_case)]
2332pub const fn ZLONG_CONST(x: i64) -> zlong {
2333 x
2334} // c:68
2335
2336/// Port of `#define STRINGIFY_LITERAL(x)` from `Src/zsh.h:2915`. C
2337/// uses the `#` operator to stringify an identifier. Rust's
2338/// `stringify!` macro does the same.
2339#[macro_export]
2340macro_rules! STRINGIFY_LITERAL {
2341 ($x:tt) => {
2342 stringify!($x)
2343 };
2344}
2345
2346/// Port of `#define STRINGIFY(x)` from `Src/zsh.h:2916`. Two-pass
2347/// stringification (expand x first, then stringify).
2348#[macro_export]
2349macro_rules! STRINGIFY {
2350 ($x:tt) => {
2351 $crate::STRINGIFY_LITERAL!($x)
2352 };
2353}
2354
2355/// Port of `#define ERRMSG(x)` from `Src/zsh.h:2917`. Build a debug
2356/// error-message prefix `__FILE__ ":" __LINE__ ": " x`.
2357#[macro_export]
2358macro_rules! ERRMSG {
2359 ($msg:expr) => {
2360 concat!(file!(), ":", line!(), ": ", $msg)
2361 };
2362}
2363
2364/// Port of `#define HEAPID_FMT` from `Src/zsh.h:2831`. printf format
2365/// specifier for `Heapid` values. C uses `"%x"`; Rust uses `"{:x}"`.
2366pub const HEAPID_FMT: &str = "{:x}"; // c:2831
2367
2368/// Port of `#define HEAP_ERROR(heap_id)` from `Src/zsh.h:2864`. Debug-
2369/// only macro that fprintf's an "invalid heap" error to stderr.
2370/// Rust port: eprintln! with the same format. Only active under
2371/// the `zsh-heap-debug` feature.
2372#[macro_export]
2373macro_rules! HEAP_ERROR {
2374 ($heap_id:expr) => {
2375 eprintln!(
2376 "{}:{}: HEAP DEBUG: invalid heap: {:x}.",
2377 file!(),
2378 line!(),
2379 $heap_id
2380 )
2381 };
2382}
2383
2384/// Port of `#define DPUTS(X, Y)` macro from `Src/zsh.h:2918` (macro).
2385///
2386/// C body (DEBUG defined, c:2918):
2387/// ```c
2388/// # define DPUTS(X,Y) if (!(X)) {;} else dputs(ERRMSG(Y))
2389/// ```
2390/// where `ERRMSG(x)` is `(__FILE__ ":" STRINGIFY(__LINE__) ": " x)`
2391/// (c:2917). Without DEBUG (c:2923) the macro expands to nothing.
2392///
2393/// The Rust port routes through `crate::ported::utils::dputs` (port
2394/// of `dputs` at `Src/utils.c:253`) under `#[cfg(feature = "zsh-debug")]`
2395/// — Rust's analogue to C's `#ifdef DEBUG` (set by configure's
2396/// `--enable-zsh-debug`). Stock zsh ships with DEBUG un-set, so the
2397/// default zshrs build (without `--features zsh-debug`) is silent
2398/// too. The file:line prefix uses `file!()` / `line!()` to mirror
2399/// `__FILE__:__LINE__`.
2400#[macro_export]
2401macro_rules! DPUTS {
2402 // c:2918
2403 ($x:expr, $y:expr) => {
2404 // c:2918
2405 #[cfg(feature = "zsh-debug")] // c:2918 ifdef DEBUG
2406 {
2407 if $x {
2408 // c:2918 if (X)
2409 crate::ported::utils::dputs(&format!(
2410 // c:2918 dputs(ERRMSG(Y))
2411 "{}:{}: {}",
2412 file!(),
2413 line!(),
2414 $y // c:2917 ERRMSG
2415 )); // c:2918
2416 } // c:2918
2417 } // c:2914 ifdef DEBUG
2418 }; // c:2918
2419} // c:2918
2420
2421/// Port of `#define DPUTS1(X, Y, Z1)` macro from `Src/zsh.h:2919` (macro).
2422///
2423/// C body (DEBUG defined):
2424/// ```c
2425/// # define DPUTS1(X,Y,Z1) if (!(X)) {;} else dputs(ERRMSG(Y), Z1)
2426/// ```
2427/// One-arg printf-style variant — `Y` is a printf format string with
2428/// one `%`-substitution, `Z1` is the argument. The Rust port uses
2429/// `format!` with `{}` placeholders; callers should write Rust-style
2430/// format strings (`"BUG: x = {}"`) instead of C printf strings
2431/// (`"BUG: x = %d"`).
2432#[macro_export]
2433macro_rules! DPUTS1 {
2434 // c:2919
2435 ($x:expr, $y:expr, $z1:expr) => {
2436 // c:2919
2437 #[cfg(feature = "zsh-debug")] // c:2919
2438 {
2439 if $x {
2440 // c:2919
2441 crate::ported::utils::dputs(&format!(
2442 // c:2919
2443 "{}:{}: {}",
2444 file!(),
2445 line!(),
2446 format!($y, $z1) // c:2917
2447 )); // c:2919
2448 } // c:2919
2449 } // c:2914
2450 }; // c:2919
2451} // c:2919
2452
2453/// Port of `#define DPUTS2(X, Y, Z1, Z2)` macro from `Src/zsh.h:2920` (macro).
2454///
2455/// Two-arg printf-style variant. Same shape as DPUTS1 but with two
2456/// substitution arguments.
2457#[macro_export]
2458macro_rules! DPUTS2 {
2459 // c:2920
2460 ($x:expr, $y:expr, $z1:expr, $z2:expr) => {
2461 // c:2920
2462 #[cfg(feature = "zsh-debug")] // c:2920
2463 {
2464 if $x {
2465 // c:2920
2466 crate::ported::utils::dputs(&format!(
2467 // c:2920
2468 "{}:{}: {}",
2469 file!(),
2470 line!(),
2471 format!($y, $z1, $z2) // c:2917
2472 )); // c:2920
2473 } // c:2920
2474 } // c:2914
2475 }; // c:2920
2476} // c:2920
2477
2478/// Port of `#define DPUTS3(X, Y, Z1, Z2, Z3)` macro from `Src/zsh.h:2921` (macro).
2479///
2480/// Three-arg printf-style variant. Same shape as DPUTS1/DPUTS2 but
2481/// with three substitution arguments.
2482#[macro_export]
2483macro_rules! DPUTS3 {
2484 // c:2921
2485 ($x:expr, $y:expr, $z1:expr, $z2:expr, $z3:expr) => {
2486 // c:2921
2487 #[cfg(feature = "zsh-debug")] // c:2921
2488 {
2489 if $x {
2490 // c:2921
2491 crate::ported::utils::dputs(&format!(
2492 // c:2921
2493 "{}:{}: {}",
2494 file!(),
2495 line!(),
2496 format!($y, $z1, $z2, $z3) // c:2917
2497 )); // c:2921
2498 } // c:2921
2499 } // c:2914
2500 }; // c:2921
2501} // c:2921
2502
2503/// Port of `#define SGTTYFLAG` from `Src/zsh.h:2614/2616`. Termios
2504/// flag accessor — `shttyinfo.tio.c_oflag` (HAVE_TERMIOS) or
2505/// `shttyinfo.sgttyb.sg_flags` (sgtty fallback). Rust port exposes
2506/// the field name; consumers access via `&ttyinfo.tio.c_oflag`.
2507pub const SGTTYFLAG_NAME: &str = "tio.c_oflag";
2508
2509/// Canonical alias under the C macro name (consumers reference it
2510/// in error messages / debug output).
2511pub const SGTTYFLAG: &str = SGTTYFLAG_NAME;
2512
2513/// Port of `#define SGTABTYPE` from `Src/zsh.h:2619/2622/2625`.
2514/// Tab-expansion mode constant — `TAB3` / `OXTABS` / `XTABS` per
2515/// platform. macOS/BSD use `OXTABS`; Linux uses `XTABS`.
2516#[cfg(target_os = "linux")]
2517pub const SGTABTYPE: u32 = libc::XTABS;
2518/// `SGTABTYPE` constant.
2519#[cfg(not(target_os = "linux"))]
2520pub const SGTABTYPE: u32 = 0;
2521
2522/// Port of `#define ZWS(s)` from `Src/zsh.h:3329/3373`. Wide-string
2523/// cast. In Rust `&str` is already UTF-8; pass through.
2524#[inline]
2525#[allow(non_snake_case)]
2526pub fn ZWS(s: &str) -> &str {
2527 s
2528}
2529
2530// =============================================================================
2531// 16d. BUILTIN / BIN_PREFIX / CONDDEF / HOOKDEF / NUMMATHFUNC /
2532// STRMATHFUNC / PARAMDEF / INTPARAMDEF / STRPARAMDEF / ARRPARAMDEF /
2533// SPECIALPMDEF / WRAPDEF — table-row builder macros (zsh.h:1450-2125).
2534// These build initialiser literals for the various per-table arrays.
2535// Rust ports as `const fn`-equivalent constructors returning the
2536// matching struct.
2537// =============================================================================
2538
2539/// Port of `BUILTIN(name, flags, handler, min, max, funcid, optstr, defopts)`
2540/// from `Src/zsh.h:1450`.
2541#[inline]
2542#[allow(non_snake_case)]
2543pub fn BUILTIN(
2544 name: &str,
2545 flags: i32,
2546 handler: Option<HandlerFunc>,
2547 min: i32,
2548 max: i32,
2549 funcid: i32,
2550 optstr: Option<&str>,
2551 defopts: Option<&str>,
2552) -> builtin {
2553 builtin {
2554 node: hashnode {
2555 next: None,
2556 nam: name.to_string(),
2557 flags,
2558 },
2559 handlerfunc: handler,
2560 minargs: min,
2561 maxargs: max,
2562 funcid,
2563 optstr: optstr.map(|s| s.to_string()),
2564 defopts: defopts.map(|s| s.to_string()),
2565 }
2566}
2567
2568/// Port of `BIN_PREFIX(name, flags)` from `Src/zsh.h:1452`. Builds a
2569/// prefix-builtin entry (no handler, marked with BINF_PREFIX).
2570#[inline]
2571#[allow(non_snake_case)]
2572pub fn BIN_PREFIX(name: &str, flags: i32) -> builtin {
2573 BUILTIN(
2574 name,
2575 flags | BINF_PREFIX as i32,
2576 NULLBINCMD,
2577 0,
2578 0,
2579 0,
2580 None,
2581 None,
2582 )
2583}
2584
2585/// Port of `CONDDEF(name, flags, handler, min, max, condid)` from
2586/// `Src/zsh.h:701`.
2587#[inline]
2588#[allow(non_snake_case)]
2589pub fn CONDDEF(
2590 name: &str,
2591 flags: i32,
2592 handler: CondHandler,
2593 min: i32,
2594 max: i32,
2595 condid: i32,
2596) -> conddef {
2597 conddef {
2598 next: None,
2599 name: name.to_string(),
2600 flags,
2601 handler: Some(handler),
2602 min,
2603 max,
2604 condid,
2605 module: None,
2606 }
2607}
2608
2609/// Port of `HOOKDEF(name, func, flags)` from `Src/zsh.h:1594`:
2610/// `{ NULL, name, (Hookfn) func, flags, NULL }`. `func` accepts `None`
2611/// to match C's `HOOKDEF("exit", NULL, HOOKF_ALL)` form.
2612#[inline]
2613#[allow(non_snake_case)]
2614pub fn HOOKDEF(name: &str, func: Option<Hookfn>, flags: i32) -> hookdef {
2615 hookdef {
2616 next: std::ptr::null_mut(),
2617 name: name.to_string(),
2618 def: func,
2619 flags,
2620 funcs: std::ptr::null_mut(),
2621 }
2622}
2623
2624/// Port of `NUMMATHFUNC(name, func, min, max, id)` from `Src/zsh.h:133`.
2625#[inline]
2626#[allow(non_snake_case)]
2627pub fn NUMMATHFUNC(name: &str, func: NumMathFunc, min: i32, max: i32, id: i32) -> mathfunc {
2628 mathfunc {
2629 next: None,
2630 name: name.to_string(),
2631 flags: 0,
2632 nfunc: Some(func),
2633 sfunc: None,
2634 module: None,
2635 minargs: min,
2636 maxargs: max,
2637 funcid: id,
2638 }
2639}
2640
2641/// Port of `STRMATHFUNC(name, func, id)` from `Src/zsh.h:135`.
2642#[inline]
2643#[allow(non_snake_case)]
2644pub fn STRMATHFUNC(name: &str, func: StrMathFunc, id: i32) -> mathfunc {
2645 mathfunc {
2646 next: None,
2647 name: name.to_string(),
2648 flags: MFF_STR,
2649 nfunc: None,
2650 sfunc: Some(func),
2651 module: None,
2652 minargs: 0,
2653 maxargs: 0,
2654 funcid: id,
2655 }
2656}
2657
2658/// Port of `PARAMDEF(name, flags, var, gsu)` from `Src/zsh.h:2096`.
2659#[inline]
2660#[allow(non_snake_case)]
2661pub fn PARAMDEF(name: &str, flags: i32, var: usize, gsu: usize) -> paramdef {
2662 paramdef {
2663 name: name.to_string(),
2664 flags,
2665 var,
2666 gsu,
2667 getnfn: None,
2668 scantfn: None,
2669 pm: None,
2670 }
2671}
2672
2673/// Port of `INTPARAMDEF(name, var)` from `Src/zsh.h:2105`.
2674#[inline]
2675#[allow(non_snake_case)]
2676pub fn INTPARAMDEF(name: &str, var: usize) -> paramdef {
2677 PARAMDEF(name, PM_INTEGER as i32, var, 0)
2678}
2679
2680/// Port of `STRPARAMDEF(name, var)` from `Src/zsh.h:2107`.
2681#[inline]
2682#[allow(non_snake_case)]
2683pub fn STRPARAMDEF(name: &str, var: usize) -> paramdef {
2684 PARAMDEF(name, PM_SCALAR as i32, var, 0)
2685}
2686
2687/// Port of `ARRPARAMDEF(name, var)` from `Src/zsh.h:2109`.
2688#[inline]
2689#[allow(non_snake_case)]
2690pub fn ARRPARAMDEF(name: &str, var: usize) -> paramdef {
2691 PARAMDEF(name, PM_ARRAY as i32, var, 0)
2692}
2693
2694/// Port of `SPECIALPMDEF(name, flags, gsufn, getfn, scanfn)` from
2695/// `Src/zsh.h:2123`.
2696#[inline]
2697#[allow(non_snake_case)]
2698pub fn SPECIALPMDEF(
2699 name: &str,
2700 flags: i32,
2701 gsufn: usize,
2702 getfn: Option<GetNodeFunc>,
2703 scanfn: Option<ScanTabFunc>,
2704) -> paramdef {
2705 paramdef {
2706 name: name.to_string(),
2707 flags: flags | (PM_SPECIAL | PM_HIDE | PM_HIDEVAL) as i32,
2708 var: 0,
2709 gsu: gsufn,
2710 getnfn: getfn,
2711 scantfn: scanfn,
2712 pm: None,
2713 }
2714}
2715/// Port of `WRAPDEF(func)` from `Src/zsh.h:1371`.
2716#[inline]
2717#[allow(non_snake_case)]
2718pub fn WRAPDEF(func: WrapFunc) -> funcwrap {
2719 funcwrap {
2720 next: None,
2721 flags: 0,
2722 handler: Some(func),
2723 module: None,
2724 }
2725}
2726
2727// =============================================================================
2728// 17. Job structures (zsh.h:1046-1166).
2729// =============================================================================
2730/// Port of `struct jobfile` from `Src/zsh.h:1046` — a record to be
2731/// deleted or closed at job exit. C is a tagged union
2732/// (`union { char *name; int fd; } u;` + `int is_fd`); the Rust port
2733/// flattens both arms plus the `is_fd` discriminant (only the field
2734/// selected by `is_fd` is valid). `is_fd == 0` → unlink `name`;
2735/// `is_fd == 1` → close `fd`.
2736#[allow(non_camel_case_types)]
2737#[derive(Debug, Clone)]
2738pub struct jobfile {
2739 // c:1046
2740 /// `name` field (`u.name`, valid when `is_fd == 0`).
2741 pub name: Option<String>,
2742 /// `fd` field (`u.fd`, valid when `is_fd == 1`).
2743 pub fd: i32,
2744 /// `is_fd` discriminant.
2745 pub is_fd: i32,
2746}
2747/// `STAT_CHANGED` constant.
2748pub const STAT_CHANGED: i32 = 0x0001; // c:1073
2749/// `STAT_STOPPED` constant.
2750pub const STAT_STOPPED: i32 = 0x0002;
2751/// `STAT_TIMED` constant.
2752pub const STAT_TIMED: i32 = 0x0004;
2753/// `STAT_DONE` constant.
2754pub const STAT_DONE: i32 = 0x0008;
2755/// `STAT_LOCKED` constant.
2756pub const STAT_LOCKED: i32 = 0x0010;
2757/// `STAT_NOPRINT` constant.
2758pub const STAT_NOPRINT: i32 = 0x0020;
2759/// `STAT_INUSE` constant.
2760pub const STAT_INUSE: i32 = 0x0040;
2761/// `STAT_SUPERJOB` constant.
2762pub const STAT_SUPERJOB: i32 = 0x0080;
2763/// `STAT_SUBJOB` constant.
2764pub const STAT_SUBJOB: i32 = 0x0100;
2765/// `STAT_WASSUPER` constant.
2766pub const STAT_WASSUPER: i32 = 0x0200;
2767/// `STAT_CURSH` constant.
2768pub const STAT_CURSH: i32 = 0x0400;
2769/// `STAT_NOSTTY` constant.
2770pub const STAT_NOSTTY: i32 = 0x0800;
2771/// `STAT_ATTACH` constant.
2772pub const STAT_ATTACH: i32 = 0x1000;
2773/// `STAT_SUBLEADER` constant.
2774pub const STAT_SUBLEADER: i32 = 0x2000;
2775/// `STAT_BUILTIN` constant.
2776pub const STAT_BUILTIN: i32 = 0x4000;
2777/// `STAT_SUBJOB_ORPHANED` constant.
2778pub const STAT_SUBJOB_ORPHANED: i32 = 0x8000;
2779/// `STAT_DISOWN` constant.
2780pub const STAT_DISOWN: i32 = 0x10000; // c:1095
2781/// `SP_RUNNING` constant.
2782pub const SP_RUNNING: i32 = -1; // c:1097
2783/// `JOBTEXTSIZE` constant.
2784pub const JOBTEXTSIZE: usize = 80; // c:1104
2785 // C: `#define MAXJOBS_ALLOC 50` (Src/zsh.h:1107) — an int literal.
2786 // Stored as `usize` so callers using it for Vec capacity / slice
2787 // indexing don't need `as usize` casts everywhere. Matches the
2788 // adjacent `MAX_PIPESTATS: usize` type choice (both are array
2789 // sizes in C).
2790/// `MAXJOBS_ALLOC` constant.
2791pub const MAXJOBS_ALLOC: usize = 50; // c:1107
2792/// `MAX_PIPESTATS` constant.
2793pub const MAX_PIPESTATS: usize = 256; // c:1166
2794/// `timeinfo` — see fields for layout.
2795#[allow(non_camel_case_types)]
2796#[derive(Debug, Clone, Default)]
2797pub struct timeinfo {
2798 // c:1099-1115 — when HAVE_GETRUSAGE the C type is `struct rusage`
2799 // and printtime reads ru_maxrss / ru_majflt / ru_minflt / ru_nswap /
2800 // ru_ixrss / ru_idrss / ru_isrss / ru_inblock / ru_oublock /
2801 // ru_nvcsw / ru_nivcsw / ru_msgsnd / ru_msgrcv / ru_nsignals.
2802 /// `ut` field.
2803 pub ut: i64,
2804 /// `st` field.
2805 pub st: i64,
2806 /// Maximum resident set size (KB). ru_maxrss (c:945-952)
2807 pub maxrss: i64,
2808 /// Major page faults. ru_majflt (c:954-957)
2809 pub majflt: i64,
2810 /// Minor page faults. ru_minflt (c:959-962)
2811 pub minflt: i64,
2812 /// Number of swaps. ru_nswap (c:896-899)
2813 pub nswap: i64,
2814 /// Integral shared memory size. ru_ixrss (c:901-907)
2815 pub ixrss: i64,
2816 /// Integral unshared data size. ru_idrss (c:909-919)
2817 pub idrss: i64,
2818 /// Integral unshared stack size. ru_isrss
2819 pub isrss: i64,
2820 /// Block input operations. ru_inblock
2821 pub inblock: i64,
2822 /// Block output operations. ru_oublock
2823 pub oublock: i64,
2824 /// Voluntary context switches. ru_nvcsw
2825 pub nvcsw: i64,
2826 /// Involuntary context switches. ru_nivcsw
2827 pub nivcsw: i64,
2828 /// IPC messages sent. ru_msgsnd
2829 pub msgsnd: i64,
2830 /// IPC messages received. ru_msgrcv
2831 pub msgrcv: i64,
2832 /// Signals received. ru_nsignals
2833 pub nsignals: i64,
2834}
2835
2836impl timeinfo {
2837 /// `user_dur` — see implementation.
2838 pub fn user_dur(&self) -> std::time::Duration {
2839 std::time::Duration::from_micros(self.ut as u64)
2840 }
2841 /// `sys_dur` — see implementation.
2842 pub fn sys_dur(&self) -> std::time::Duration {
2843 std::time::Duration::from_micros(self.st as u64)
2844 }
2845
2846 /// Populate this `timeinfo` from a `libc::rusage` snapshot.
2847 /// On macOS `ru_maxrss` is in bytes; on Linux it's KB — caller
2848 /// normalises via cfg.
2849 #[cfg(unix)]
2850 pub fn from_rusage(r: &libc::rusage) -> Self {
2851 let ut = r.ru_utime.tv_sec as i64 * 1_000_000 + r.ru_utime.tv_usec as i64;
2852 let st = r.ru_stime.tv_sec as i64 * 1_000_000 + r.ru_stime.tv_usec as i64;
2853 #[cfg(target_os = "macos")]
2854 let maxrss = r.ru_maxrss / 1024;
2855 #[cfg(not(target_os = "macos"))]
2856 let maxrss = r.ru_maxrss as i64;
2857 Self {
2858 ut,
2859 st,
2860 maxrss: maxrss as i64,
2861 majflt: r.ru_majflt as i64,
2862 minflt: r.ru_minflt as i64,
2863 nswap: r.ru_nswap as i64,
2864 ixrss: r.ru_ixrss as i64,
2865 idrss: r.ru_idrss as i64,
2866 isrss: r.ru_isrss as i64,
2867 inblock: r.ru_inblock as i64,
2868 oublock: r.ru_oublock as i64,
2869 nvcsw: r.ru_nvcsw as i64,
2870 nivcsw: r.ru_nivcsw as i64,
2871 msgsnd: r.ru_msgsnd as i64,
2872 msgrcv: r.ru_msgrcv as i64,
2873 nsignals: r.ru_nsignals as i64,
2874 }
2875 }
2876}
2877
2878// =============================================================================
2879// 18. Hash table types (zsh.h:1172-1235) — DISABLED.
2880// =============================================================================
2881/// `DISABLED` constant.
2882pub const DISABLED: i32 = 1 << 0; // c:1235
2883
2884// =============================================================================
2885// 19. Alias / asgment / cmdnam / shfunc / funcstack flags + macros.
2886// =============================================================================
2887/// `HASHED` constant.
2888pub const HASHED: i32 = 1 << 1; // c:1312
2889/// `ALIAS_GLOBAL` constant.
2890pub const ALIAS_GLOBAL: i32 = 1 << 1; // c:1261
2891/// `ALIAS_SUFFIX` constant.
2892pub const ALIAS_SUFFIX: i32 = 1 << 2; // c:1263
2893/// `ASG_ARRAY` constant.
2894pub const ASG_ARRAY: i32 = 1; // c:1280
2895/// `ASG_KEY_VALUE` constant.
2896pub const ASG_KEY_VALUE: i32 = 2; // c:1282
2897/// `SFC_NONE` constant.
2898pub const SFC_NONE: i32 = 0; // c:1329
2899/// `SFC_DIRECT` constant.
2900pub const SFC_DIRECT: i32 = 1;
2901/// `SFC_SIGNAL` constant.
2902pub const SFC_SIGNAL: i32 = 2;
2903/// `SFC_HOOK` constant.
2904pub const SFC_HOOK: i32 = 3;
2905/// `SFC_WIDGET` constant.
2906pub const SFC_WIDGET: i32 = 4;
2907/// `SFC_COMPLETE` constant.
2908pub const SFC_COMPLETE: i32 = 5;
2909/// `SFC_CWIDGET` constant.
2910pub const SFC_CWIDGET: i32 = 6;
2911/// `SFC_SUBST` constant.
2912pub const SFC_SUBST: i32 = 7;
2913/// `FS_SOURCE` constant.
2914pub const FS_SOURCE: i32 = 0; // c:1341
2915/// `FS_FUNC` constant.
2916pub const FS_FUNC: i32 = 1;
2917/// `FS_EVAL` constant.
2918pub const FS_EVAL: i32 = 2;
2919/// `WRAPF_ADDED` constant.
2920pub const WRAPF_ADDED: i32 = 1; // c:1369
2921/// `HOOK_SUFFIX` constant.
2922pub const HOOK_SUFFIX: &str = "_functions"; // c:1379
2923/// `HOOK_SUFFIX_LEN` constant.
2924pub const HOOK_SUFFIX_LEN: usize = 11; // c:1381
2925
2926// =============================================================================
2927// 20. Options struct + MAX_OPS + OPT_* macros (zsh.h:1396-1427).
2928// =============================================================================
2929/// `MAX_OPS` constant.
2930pub const MAX_OPS: usize = 128; // c:1396
2931/// `options` — see fields for layout.
2932#[allow(non_camel_case_types)]
2933#[derive(Clone)]
2934pub struct options {
2935 // c:1416
2936 pub ind: [u8; MAX_OPS],
2937 /// `args` field.
2938 pub args: Vec<String>,
2939 /// `argscount` field.
2940 pub argscount: i32,
2941 /// `argsalloc` field.
2942 pub argsalloc: i32,
2943}
2944/// `PARSEARGS_TOPLEVEL` constant.
2945pub const PARSEARGS_TOPLEVEL: i32 = 0x1; // c:1425
2946/// `PARSEARGS_LOGIN` constant.
2947pub const PARSEARGS_LOGIN: i32 = 0x2; // c:1426
2948
2949// Port of OPT_* macros from Src/zsh.h:1400-1414. Each takes
2950// `Options ops` (= `struct options *`) and a char index. The Rust
2951// port takes `&options` (a reference to the struct ported above) and
2952// indexes `ind[c]`. Char indexing is direct (not c-1) per zsh.h:1408
2953// `((ops)->ind[c] != 0)`.
2954
2955/// Port of `OPT_MINUS(ops,c)` from `Src/zsh.h:1400` —
2956/// `((ops)->ind[c] & 1)`. True if option was set as `-X`.
2957#[inline]
2958#[allow(non_snake_case)]
2959pub fn OPT_MINUS(ops: &options, c: u8) -> bool {
2960 (ops.ind[c as usize] & 1) != 0
2961}
2962
2963/// Port of `OPT_PLUS(ops,c)` from `Src/zsh.h:1402` —
2964/// `((ops)->ind[c] & 2)`. True if option was set as `+X`.
2965#[inline]
2966#[allow(non_snake_case)]
2967pub fn OPT_PLUS(ops: &options, c: u8) -> bool {
2968 (ops.ind[c as usize] & 2) != 0
2969}
2970
2971/// Port of `OPT_ISSET(ops,c)` from `Src/zsh.h:1408` —
2972/// `((ops)->ind[c] != 0)`. True if option was set any way.
2973#[inline]
2974#[allow(non_snake_case)]
2975pub fn OPT_ISSET(ops: &options, c: u8) -> bool {
2976 ops.ind[c as usize] != 0
2977}
2978
2979/// Port of `OPT_HASARG(ops,c)` from `Src/zsh.h:1410` —
2980/// `((ops)->ind[c] > 3)`. True if option carries an argument.
2981#[inline]
2982#[allow(non_snake_case)]
2983pub fn OPT_HASARG(ops: &options, c: u8) -> bool {
2984 ops.ind[c as usize] > 3
2985}
2986
2987// =============================================================================
2988// 21. Builtin types + BINF_* (zsh.h:1436-1486).
2989// =============================================================================
2990/// `HandlerFunc` type alias.
2991pub type HandlerFunc = fn(name: &str, args: &[String], ops: &options, funcid: i32) -> i32;
2992/// `BINF_PLUSOPTS` constant.
2993pub const BINF_PLUSOPTS: u32 = 1 << 1; // c:1457
2994/// `BINF_PRINTOPTS` constant.
2995pub const BINF_PRINTOPTS: u32 = 1 << 2; // c:1458
2996/// `BINF_ADDED` constant.
2997pub const BINF_ADDED: u32 = 1 << 3; // c:1459
2998/// `BINF_MAGICEQUALS` constant.
2999pub const BINF_MAGICEQUALS: u32 = 1 << 4; // c:1460
3000/// `BINF_PREFIX` constant.
3001pub const BINF_PREFIX: u32 = 1 << 5; // c:1461
3002/// `BINF_DASH` constant.
3003pub const BINF_DASH: u32 = 1 << 6; // c:1462
3004/// `BINF_BUILTIN` constant.
3005pub const BINF_BUILTIN: u32 = 1 << 7; // c:1463
3006/// `BINF_COMMAND` constant.
3007pub const BINF_COMMAND: u32 = 1 << 8; // c:1464
3008/// `BINF_EXEC` constant.
3009pub const BINF_EXEC: u32 = 1 << 9; // c:1465
3010/// `BINF_NOGLOB` constant.
3011pub const BINF_NOGLOB: u32 = 1 << 10; // c:1466
3012/// `BINF_PSPECIAL` constant.
3013pub const BINF_PSPECIAL: u32 = 1 << 11; // c:1467
3014/// `BINF_SKIPINVALID` constant.
3015pub const BINF_SKIPINVALID: u32 = 1 << 12; // c:1469
3016/// `BINF_KEEPNUM` constant.
3017pub const BINF_KEEPNUM: u32 = 1 << 13; // c:1470
3018/// `BINF_SKIPDASH` constant.
3019pub const BINF_SKIPDASH: u32 = 1 << 14; // c:1471
3020/// `BINF_DASHDASHVALID` constant.
3021pub const BINF_DASHDASHVALID: u32 = 1 << 15; // c:1472
3022/// `BINF_CLEARENV` constant.
3023pub const BINF_CLEARENV: u32 = 1 << 16; // c:1473
3024/// `BINF_AUTOALL` constant.
3025pub const BINF_AUTOALL: u32 = 1 << 17; // c:1474
3026/// `BINF_HANDLES_OPTS` constant.
3027pub const BINF_HANDLES_OPTS: u32 = 1 << 18; // c:1480
3028/// `BINF_ASSIGN` constant.
3029pub const BINF_ASSIGN: u32 = 1 << 19; // c:1486
3030
3031// =============================================================================
3032// 22. Module flags (zsh.h:1516-1532).
3033// =============================================================================
3034/// `MOD_BUSY` constant.
3035pub const MOD_BUSY: i32 = 1 << 0; // c:1516
3036/// `MOD_UNLOAD` constant.
3037pub const MOD_UNLOAD: i32 = 1 << 1; // c:1522
3038/// `MOD_SETUP` constant.
3039pub const MOD_SETUP: i32 = 1 << 2; // c:1524
3040/// `MOD_LINKED` constant.
3041pub const MOD_LINKED: i32 = 1 << 3; // c:1526
3042/// `MOD_INIT_S` constant.
3043pub const MOD_INIT_S: i32 = 1 << 4; // c:1528
3044/// `MOD_INIT_B` constant.
3045pub const MOD_INIT_B: i32 = 1 << 5; // c:1530
3046/// `MOD_ALIAS` constant.
3047pub const MOD_ALIAS: i32 = 1 << 6; // c:1532
3048/// `HOOKF_ALL` constant.
3049pub const HOOKF_ALL: i32 = 1; // c:1592
3050
3051// =============================================================================
3052// 23. Pattern flags (zsh.h:1624-1637).
3053// =============================================================================
3054/// `PAT_HEAPDUP` constant.
3055pub const PAT_HEAPDUP: i32 = 0x0000; // c:1624
3056/// `PAT_FILE` constant.
3057pub const PAT_FILE: i32 = 0x0001;
3058/// `PAT_FILET` constant.
3059pub const PAT_FILET: i32 = 0x0002;
3060/// `PAT_ANY` constant.
3061pub const PAT_ANY: i32 = 0x0004;
3062/// `PAT_NOANCH` constant.
3063pub const PAT_NOANCH: i32 = 0x0008;
3064/// `PAT_NOGLD` constant.
3065pub const PAT_NOGLD: i32 = 0x0010;
3066/// `PAT_PURES` constant.
3067pub const PAT_PURES: i32 = 0x0020;
3068/// `PAT_STATIC` constant.
3069pub const PAT_STATIC: i32 = 0x0040;
3070/// `PAT_SCAN` constant.
3071pub const PAT_SCAN: i32 = 0x0080;
3072/// `PAT_ZDUP` constant.
3073pub const PAT_ZDUP: i32 = 0x0100;
3074/// `PAT_NOTSTART` constant.
3075pub const PAT_NOTSTART: i32 = 0x0200;
3076/// `PAT_NOTEND` constant.
3077pub const PAT_NOTEND: i32 = 0x0400;
3078/// `PAT_HAS_EXCLUDP` constant.
3079pub const PAT_HAS_EXCLUDP: i32 = 0x0800;
3080/// `PAT_LCMATCHUC` constant.
3081pub const PAT_LCMATCHUC: i32 = 0x1000;
3082
3083// =============================================================================
3084// 24. zpc_chars enum (zsh.h:1643-1676).
3085// =============================================================================
3086/// `ZPC_SLASH` constant.
3087pub const ZPC_SLASH: i32 = 0;
3088/// `ZPC_NULL` constant.
3089pub const ZPC_NULL: i32 = 1;
3090/// `ZPC_BAR` constant.
3091pub const ZPC_BAR: i32 = 2;
3092/// `ZPC_OUTPAR` constant.
3093pub const ZPC_OUTPAR: i32 = 3;
3094/// `ZPC_TILDE` constant.
3095pub const ZPC_TILDE: i32 = 4;
3096/// `ZPC_SEG_COUNT` constant.
3097pub const ZPC_SEG_COUNT: i32 = 5;
3098/// `ZPC_INPAR` constant.
3099pub const ZPC_INPAR: i32 = ZPC_SEG_COUNT;
3100/// `ZPC_QUEST` constant.
3101pub const ZPC_QUEST: i32 = ZPC_SEG_COUNT + 1;
3102/// `ZPC_STAR` constant.
3103pub const ZPC_STAR: i32 = ZPC_SEG_COUNT + 2;
3104/// `ZPC_INBRACK` constant.
3105pub const ZPC_INBRACK: i32 = ZPC_SEG_COUNT + 3;
3106/// `ZPC_INANG` constant.
3107pub const ZPC_INANG: i32 = ZPC_SEG_COUNT + 4;
3108/// `ZPC_HAT` constant.
3109pub const ZPC_HAT: i32 = ZPC_SEG_COUNT + 5;
3110/// `ZPC_HASH` constant.
3111pub const ZPC_HASH: i32 = ZPC_SEG_COUNT + 6;
3112/// `ZPC_BNULLKEEP` constant.
3113pub const ZPC_BNULLKEEP: i32 = ZPC_SEG_COUNT + 7;
3114/// `ZPC_NO_KSH_GLOB` constant.
3115pub const ZPC_NO_KSH_GLOB: i32 = ZPC_SEG_COUNT + 8;
3116/// `ZPC_KSH_QUEST` constant.
3117pub const ZPC_KSH_QUEST: i32 = ZPC_NO_KSH_GLOB;
3118/// `ZPC_KSH_STAR` constant.
3119pub const ZPC_KSH_STAR: i32 = ZPC_NO_KSH_GLOB + 1;
3120/// `ZPC_KSH_PLUS` constant.
3121pub const ZPC_KSH_PLUS: i32 = ZPC_NO_KSH_GLOB + 2;
3122/// `ZPC_KSH_BANG` constant.
3123pub const ZPC_KSH_BANG: i32 = ZPC_NO_KSH_GLOB + 3;
3124/// `ZPC_KSH_BANG2` constant.
3125pub const ZPC_KSH_BANG2: i32 = ZPC_NO_KSH_GLOB + 4;
3126/// `ZPC_KSH_AT` constant.
3127pub const ZPC_KSH_AT: i32 = ZPC_NO_KSH_GLOB + 5;
3128/// `ZPC_COUNT` constant.
3129pub const ZPC_COUNT: i32 = ZPC_NO_KSH_GLOB + 6;
3130
3131// =============================================================================
3132// 25. PP_* (zsh.h:1707-1735) + GF_* + ZMB_*.
3133// =============================================================================
3134/// `PP_FIRST` constant.
3135pub const PP_FIRST: i32 = 1;
3136/// `PP_ALPHA` constant.
3137pub const PP_ALPHA: i32 = 1;
3138/// `PP_ALNUM` constant.
3139pub const PP_ALNUM: i32 = 2;
3140/// `PP_ASCII` constant.
3141pub const PP_ASCII: i32 = 3;
3142/// `PP_BLANK` constant.
3143pub const PP_BLANK: i32 = 4;
3144/// `PP_CNTRL` constant.
3145pub const PP_CNTRL: i32 = 5;
3146/// `PP_DIGIT` constant.
3147pub const PP_DIGIT: i32 = 6;
3148/// `PP_GRAPH` constant.
3149pub const PP_GRAPH: i32 = 7;
3150/// `PP_LOWER` constant.
3151pub const PP_LOWER: i32 = 8;
3152/// `PP_PRINT` constant.
3153pub const PP_PRINT: i32 = 9;
3154/// `PP_PUNCT` constant.
3155pub const PP_PUNCT: i32 = 10;
3156/// `PP_SPACE` constant.
3157pub const PP_SPACE: i32 = 11;
3158/// `PP_UPPER` constant.
3159pub const PP_UPPER: i32 = 12;
3160/// `PP_XDIGIT` constant.
3161pub const PP_XDIGIT: i32 = 13;
3162/// `PP_IDENT` constant.
3163pub const PP_IDENT: i32 = 14;
3164/// `PP_IFS` constant.
3165pub const PP_IFS: i32 = 15;
3166/// `PP_IFSSPACE` constant.
3167pub const PP_IFSSPACE: i32 = 16;
3168/// `PP_WORD` constant.
3169pub const PP_WORD: i32 = 17;
3170/// `PP_INCOMPLETE` constant.
3171pub const PP_INCOMPLETE: i32 = 18;
3172/// `PP_INVALID` constant.
3173pub const PP_INVALID: i32 = 19;
3174/// `PP_LAST` constant.
3175pub const PP_LAST: i32 = 19;
3176/// `PP_UNKWN` constant.
3177pub const PP_UNKWN: i32 = 20;
3178/// `PP_RANGE` constant.
3179pub const PP_RANGE: i32 = 21;
3180/// `GF_LCMATCHUC` constant.
3181pub const GF_LCMATCHUC: i32 = 0x0100;
3182/// `GF_IGNCASE` constant.
3183pub const GF_IGNCASE: i32 = 0x0200;
3184/// `GF_BACKREF` constant.
3185pub const GF_BACKREF: i32 = 0x0400;
3186/// `GF_MATCHREF` constant.
3187pub const GF_MATCHREF: i32 = 0x0800;
3188/// `GF_MULTIBYTE` constant.
3189pub const GF_MULTIBYTE: i32 = 0x1000;
3190/// `ZMB_VALID` constant.
3191pub const ZMB_VALID: i32 = 0;
3192/// `ZMB_INCOMPLETE` constant.
3193pub const ZMB_INCOMPLETE: i32 = 1;
3194/// `ZMB_INVALID` constant.
3195pub const ZMB_INVALID: i32 = 2;
3196
3197// =============================================================================
3198// 26. Param type flags (zsh.h:1878-1949).
3199// =============================================================================
3200/// `PM_SCALAR` constant.
3201pub const PM_SCALAR: u32 = 0;
3202/// `PM_ARRAY` constant.
3203pub const PM_ARRAY: u32 = 1 << 0;
3204/// `PM_INTEGER` constant.
3205pub const PM_INTEGER: u32 = 1 << 1;
3206/// `PM_EFLOAT` constant.
3207pub const PM_EFLOAT: u32 = 1 << 2;
3208/// `PM_FFLOAT` constant.
3209pub const PM_FFLOAT: u32 = 1 << 3;
3210/// `PM_HASHED` constant.
3211pub const PM_HASHED: u32 = 1 << 4;
3212/// `PM_LEFT` constant.
3213pub const PM_LEFT: u32 = 1 << 5;
3214/// `PM_RIGHT_B` constant.
3215pub const PM_RIGHT_B: u32 = 1 << 6;
3216/// `PM_RIGHT_Z` constant.
3217pub const PM_RIGHT_Z: u32 = 1 << 7;
3218/// `PM_LOWER` constant.
3219pub const PM_LOWER: u32 = 1 << 8;
3220/// `PM_UPPER` constant.
3221pub const PM_UPPER: u32 = 1 << 9;
3222/// `PM_UNDEFINED` constant.
3223pub const PM_UNDEFINED: u32 = 1 << 9;
3224/// `PM_READONLY` constant.
3225pub const PM_READONLY: u32 = 1 << 10;
3226/// `PM_TAGGED` constant.
3227pub const PM_TAGGED: u32 = 1 << 11;
3228/// `PM_EXPORTED` constant.
3229pub const PM_EXPORTED: u32 = 1 << 12;
3230/// `PM_ABSPATH_USED` constant.
3231pub const PM_ABSPATH_USED: u32 = 1 << 12;
3232/// `PM_UNIQUE` constant.
3233pub const PM_UNIQUE: u32 = 1 << 13;
3234/// `PM_UNALIASED` constant.
3235pub const PM_UNALIASED: u32 = 1 << 13;
3236/// `PM_HIDE` constant.
3237pub const PM_HIDE: u32 = 1 << 14;
3238/// `PM_CUR_FPATH` constant.
3239pub const PM_CUR_FPATH: u32 = 1 << 14;
3240/// `PM_HIDEVAL` constant.
3241pub const PM_HIDEVAL: u32 = 1 << 15;
3242/// `PM_WARNNESTED` constant.
3243pub const PM_WARNNESTED: u32 = 1 << 15;
3244/// `PM_TIED` constant.
3245pub const PM_TIED: u32 = 1 << 16;
3246/// `PM_TAGGED_LOCAL` constant.
3247pub const PM_TAGGED_LOCAL: u32 = 1 << 16;
3248/// `PM_DONTIMPORT_SUID` constant.
3249pub const PM_DONTIMPORT_SUID: u32 = 1 << 17;
3250/// `PM_LOADDIR` constant.
3251pub const PM_LOADDIR: u32 = 1 << 17;
3252/// `PM_SINGLE` constant.
3253pub const PM_SINGLE: u32 = 1 << 18;
3254/// `PM_ANONYMOUS` constant.
3255pub const PM_ANONYMOUS: u32 = 1 << 18;
3256/// `PM_LOCAL` constant.
3257pub const PM_LOCAL: u32 = 1 << 19;
3258/// `PM_KSHSTORED` constant.
3259pub const PM_KSHSTORED: u32 = 1 << 19;
3260/// `PM_SPECIAL` constant.
3261pub const PM_SPECIAL: u32 = 1 << 20;
3262/// `PM_ZSHSTORED` constant.
3263pub const PM_ZSHSTORED: u32 = 1 << 20;
3264/// `PM_RO_BY_DESIGN` constant.
3265pub const PM_RO_BY_DESIGN: u32 = 1 << 21;
3266/// `PM_READONLY_SPECIAL` constant.
3267pub const PM_READONLY_SPECIAL: u32 = PM_SPECIAL | PM_READONLY | PM_RO_BY_DESIGN;
3268/// `PM_DONTIMPORT` constant.
3269pub const PM_DONTIMPORT: u32 = 1 << 22;
3270/// `PM_DECLARED` constant.
3271pub const PM_DECLARED: u32 = 1 << 22;
3272/// `PM_RESTRICTED` constant.
3273pub const PM_RESTRICTED: u32 = 1 << 23;
3274/// `PM_UNSET` constant.
3275pub const PM_UNSET: u32 = 1 << 24;
3276/// `PM_DEFAULTED` constant.
3277pub const PM_DEFAULTED: u32 = PM_DECLARED | PM_UNSET;
3278/// `PM_REMOVABLE` constant.
3279pub const PM_REMOVABLE: u32 = 1 << 25;
3280/// `PM_AUTOLOAD` constant.
3281pub const PM_AUTOLOAD: u32 = 1 << 26;
3282/// `PM_NORESTORE` constant.
3283pub const PM_NORESTORE: u32 = 1 << 27;
3284/// `PM_AUTOALL` constant.
3285pub const PM_AUTOALL: u32 = 1 << 27;
3286/// `PM_HASHELEM` constant.
3287pub const PM_HASHELEM: u32 = 1 << 28;
3288/// `PM_NAMEDDIR` constant.
3289pub const PM_NAMEDDIR: u32 = 1 << 29;
3290/// `PM_NAMEREF` constant.
3291pub const PM_NAMEREF: u32 = 1 << 30;
3292/// `PM_TYPE` — see implementation.
3293#[inline]
3294#[allow(non_snake_case)]
3295pub const fn PM_TYPE(x: u32) -> u32 {
3296 x & (PM_SCALAR | PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED | PM_NAMEREF)
3297}
3298/// `TYPESET_OPTSTR` constant.
3299pub const TYPESET_OPTSTR: &str = "aiEFALRZlurtxUhHT"; // c:1947
3300/// `TYPESET_OPTNUM` constant.
3301pub const TYPESET_OPTNUM: &str = "LRZiEF"; // c:1950
3302
3303// =============================================================================
3304// 27. SCANPM_* (zsh.h:1953-1973).
3305// =============================================================================
3306/// `SCANPM_WANTVALS` constant.
3307pub const SCANPM_WANTVALS: u32 = 1 << 0;
3308/// `SCANPM_WANTKEYS` constant.
3309pub const SCANPM_WANTKEYS: u32 = 1 << 1;
3310/// `SCANPM_WANTINDEX` constant.
3311pub const SCANPM_WANTINDEX: u32 = 1 << 2;
3312/// `SCANPM_MATCHKEY` constant.
3313pub const SCANPM_MATCHKEY: u32 = 1 << 3;
3314/// `SCANPM_MATCHVAL` constant.
3315pub const SCANPM_MATCHVAL: u32 = 1 << 4;
3316/// `SCANPM_MATCHMANY` constant.
3317pub const SCANPM_MATCHMANY: u32 = 1 << 5;
3318/// `SCANPM_ASSIGNING` constant.
3319pub const SCANPM_ASSIGNING: u32 = 1 << 6;
3320/// `SCANPM_KEYMATCH` constant.
3321pub const SCANPM_KEYMATCH: u32 = 1 << 7;
3322/// `SCANPM_DQUOTED` constant.
3323pub const SCANPM_DQUOTED: u32 = 1 << 8;
3324/// `SCANPM_ARRONLY` constant.
3325pub const SCANPM_ARRONLY: u32 = 1 << 9;
3326/// `SCANPM_CHECKING` constant.
3327pub const SCANPM_CHECKING: u32 = 1 << 10;
3328/// `SCANPM_NOEXEC` constant.
3329pub const SCANPM_NOEXEC: u32 = 1 << 11;
3330/// `SCANPM_NONAMESPC` constant.
3331pub const SCANPM_NONAMESPC: u32 = 1 << 12;
3332/// `SCANPM_NONAMEREF` constant.
3333pub const SCANPM_NONAMEREF: u32 = 1 << 13;
3334/// `SCANPM_ISVAR_AT` constant.
3335pub const SCANPM_ISVAR_AT: u32 = 1 << 14;
3336
3337// =============================================================================
3338// 28. SUB_* substitution flags (zsh.h:1981-1996).
3339// =============================================================================
3340/// `SUB_END` constant.
3341pub const SUB_END: i32 = 0x0001;
3342/// `SUB_LONG` constant.
3343pub const SUB_LONG: i32 = 0x0002;
3344/// `SUB_SUBSTR` constant.
3345pub const SUB_SUBSTR: i32 = 0x0004;
3346/// `SUB_MATCH` constant.
3347pub const SUB_MATCH: i32 = 0x0008;
3348/// `SUB_REST` constant.
3349pub const SUB_REST: i32 = 0x0010;
3350/// `SUB_BIND` constant.
3351pub const SUB_BIND: i32 = 0x0020;
3352/// `SUB_EIND` constant.
3353pub const SUB_EIND: i32 = 0x0040;
3354/// `SUB_LEN` constant.
3355pub const SUB_LEN: i32 = 0x0080;
3356/// `SUB_ALL` constant.
3357pub const SUB_ALL: i32 = 0x0100;
3358/// `SUB_GLOBAL` constant.
3359pub const SUB_GLOBAL: i32 = 0x0200;
3360/// `SUB_DOSUBST` constant.
3361pub const SUB_DOSUBST: i32 = 0x0400;
3362/// `SUB_RETFAIL` constant.
3363pub const SUB_RETFAIL: i32 = 0x0800;
3364/// `SUB_START` constant.
3365pub const SUB_START: i32 = 0x1000;
3366/// `SUB_LIST` constant.
3367pub const SUB_LIST: i32 = 0x2000;
3368/// `SUB_EGLOB` constant.
3369pub const SUB_EGLOB: i32 = 0x4000;
3370
3371// =============================================================================
3372// 29. ZSHTOK_* + PREFORK_* + MULTSUB_* (zsh.h:2014-2065).
3373// =============================================================================
3374/// `ZSHTOK_SUBST` constant.
3375pub const ZSHTOK_SUBST: i32 = 0x0001;
3376/// `ZSHTOK_SHGLOB` constant.
3377pub const ZSHTOK_SHGLOB: i32 = 0x0002;
3378/// `PREFORK_TYPESET` constant.
3379pub const PREFORK_TYPESET: i32 = 0x01;
3380/// `PREFORK_ASSIGN` constant.
3381pub const PREFORK_ASSIGN: i32 = 0x02;
3382/// `PREFORK_SINGLE` constant.
3383pub const PREFORK_SINGLE: i32 = 0x04;
3384/// `PREFORK_SPLIT` constant.
3385pub const PREFORK_SPLIT: i32 = 0x08;
3386/// `PREFORK_SHWORDSPLIT` constant.
3387pub const PREFORK_SHWORDSPLIT: i32 = 0x10;
3388/// `PREFORK_NOSHWORDSPLIT` constant.
3389pub const PREFORK_NOSHWORDSPLIT: i32 = 0x20;
3390/// `PREFORK_SUBEXP` constant.
3391pub const PREFORK_SUBEXP: i32 = 0x40;
3392/// `PREFORK_KEY_VALUE` constant.
3393pub const PREFORK_KEY_VALUE: i32 = 0x80;
3394/// `PREFORK_NO_UNTOK` constant.
3395pub const PREFORK_NO_UNTOK: i32 = 0x100;
3396/// `MULTSUB_WS_AT_START` constant.
3397pub const MULTSUB_WS_AT_START: i32 = 1;
3398/// `MULTSUB_WS_AT_END` constant.
3399pub const MULTSUB_WS_AT_END: i32 = 2;
3400/// `MULTSUB_PARAM_NAME` constant.
3401pub const MULTSUB_PARAM_NAME: i32 = 4;
3402
3403// =============================================================================
3404// 30. ASSPM_* (zsh.h:2130-2145).
3405// =============================================================================
3406/// `ASSPM_AUGMENT` constant.
3407pub const ASSPM_AUGMENT: i32 = 1 << 0;
3408/// `ASSPM_WARN_CREATE` constant.
3409pub const ASSPM_WARN_CREATE: i32 = 1 << 1;
3410/// `ASSPM_WARN_NESTED` constant.
3411pub const ASSPM_WARN_NESTED: i32 = 1 << 2;
3412/// `ASSPM_WARN` constant.
3413pub const ASSPM_WARN: i32 = ASSPM_WARN_CREATE | ASSPM_WARN_NESTED;
3414/// `ASSPM_ENV_IMPORT` constant.
3415pub const ASSPM_ENV_IMPORT: i32 = 1 << 3;
3416/// `ASSPM_KEY_VALUE` constant.
3417pub const ASSPM_KEY_VALUE: i32 = 1 << 4;
3418
3419// =============================================================================
3420// 31. ND_* + PRINT_* + loop_return + source_return + noerrexit_bits.
3421// =============================================================================
3422/// `ND_USERNAME` constant.
3423pub const ND_USERNAME: i32 = 1 << 1; // c:2157
3424/// `ND_NOABBREV` constant.
3425pub const ND_NOABBREV: i32 = 1 << 2; // c:2158
3426/// `PRINT_NAMEONLY` constant.
3427pub const PRINT_NAMEONLY: i32 = 1 << 0; // c:2179
3428/// `PRINT_TYPE` constant.
3429pub const PRINT_TYPE: i32 = 1 << 1;
3430/// `PRINT_LIST` constant.
3431pub const PRINT_LIST: i32 = 1 << 2;
3432/// `PRINT_KV_PAIR` constant.
3433pub const PRINT_KV_PAIR: i32 = 1 << 3;
3434/// `PRINT_INCLUDEVALUE` constant.
3435pub const PRINT_INCLUDEVALUE: i32 = 1 << 4;
3436/// `PRINT_TYPESET` constant.
3437pub const PRINT_TYPESET: i32 = 1 << 5;
3438/// `PRINT_LINE` constant.
3439pub const PRINT_LINE: i32 = 1 << 6;
3440/// `PRINT_POSIX_EXPORT` constant.
3441pub const PRINT_POSIX_EXPORT: i32 = 1 << 7;
3442/// `PRINT_POSIX_READONLY` constant.
3443pub const PRINT_POSIX_READONLY: i32 = 1 << 8;
3444/// `PRINT_WITH_NAMESPACE` constant.
3445pub const PRINT_WITH_NAMESPACE: i32 = 1 << 9;
3446/// `PRINT_WHENCE_CSH` constant.
3447pub const PRINT_WHENCE_CSH: i32 = 1 << 7; // c:2191
3448/// `PRINT_WHENCE_VERBOSE` constant.
3449pub const PRINT_WHENCE_VERBOSE: i32 = 1 << 8;
3450/// `PRINT_WHENCE_SIMPLE` constant.
3451pub const PRINT_WHENCE_SIMPLE: i32 = 1 << 9;
3452/// `PRINT_WHENCE_FUNCDEF` constant.
3453pub const PRINT_WHENCE_FUNCDEF: i32 = 1 << 10;
3454/// `PRINT_WHENCE_WORD` constant.
3455pub const PRINT_WHENCE_WORD: i32 = 1 << 11;
3456/// `LOOP_OK` constant.
3457pub const LOOP_OK: i32 = 0; // c:2199
3458/// `LOOP_EMPTY` constant.
3459pub const LOOP_EMPTY: i32 = 1;
3460/// `LOOP_ERROR` constant.
3461pub const LOOP_ERROR: i32 = 2;
3462/// `SOURCE_OK` constant.
3463pub const SOURCE_OK: i32 = 0; // c:2210
3464/// `SOURCE_NOT_FOUND` constant.
3465pub const SOURCE_NOT_FOUND: i32 = 1;
3466/// `SOURCE_ERROR` constant.
3467pub const SOURCE_ERROR: i32 = 2;
3468/// `NOERREXIT_EXIT` constant.
3469pub const NOERREXIT_EXIT: i32 = 1; // c:2219
3470/// `NOERREXIT_RETURN` constant.
3471pub const NOERREXIT_RETURN: i32 = 2;
3472/// `NOERREXIT_SIGNAL` constant.
3473pub const NOERREXIT_SIGNAL: i32 = 8;
3474
3475// =============================================================================
3476// 32. History flags + GETHIST_* + HISTFLAG_* + HFILE_* + LEXFLAGS_*.
3477// =============================================================================
3478/// `HIST_MAKEUNIQUE` constant.
3479pub const HIST_MAKEUNIQUE: u32 = 0x00000001; // c:2252
3480/// `HIST_OLD` constant.
3481pub const HIST_OLD: u32 = 0x00000002;
3482/// `HIST_READ` constant.
3483pub const HIST_READ: u32 = 0x00000004;
3484/// `HIST_DUP` constant.
3485pub const HIST_DUP: u32 = 0x00000008;
3486/// `HIST_FOREIGN` constant.
3487pub const HIST_FOREIGN: u32 = 0x00000010;
3488/// `HIST_TMPSTORE` constant.
3489pub const HIST_TMPSTORE: u32 = 0x00000020;
3490/// `HIST_NOWRITE` constant.
3491pub const HIST_NOWRITE: u32 = 0x00000040;
3492/// `GETHIST_UPWARD` constant.
3493pub const GETHIST_UPWARD: i32 = -1;
3494/// `GETHIST_DOWNWARD` constant.
3495pub const GETHIST_DOWNWARD: i32 = 1;
3496/// `GETHIST_EXACT` constant.
3497pub const GETHIST_EXACT: i32 = 0;
3498/// `HISTFLAG_DONE` constant.
3499pub const HISTFLAG_DONE: i32 = 1; // c:2270
3500/// `HISTFLAG_NOEXEC` constant.
3501pub const HISTFLAG_NOEXEC: i32 = 2;
3502/// `HISTFLAG_RECALL` constant.
3503pub const HISTFLAG_RECALL: i32 = 4;
3504/// `HISTFLAG_SETTY` constant.
3505pub const HISTFLAG_SETTY: i32 = 8;
3506/// `HFILE_APPEND` constant.
3507pub const HFILE_APPEND: u32 = 0x0001;
3508/// `HFILE_SKIPOLD` constant.
3509pub const HFILE_SKIPOLD: u32 = 0x0002;
3510/// `HFILE_SKIPDUPS` constant.
3511pub const HFILE_SKIPDUPS: u32 = 0x0004;
3512/// `HFILE_SKIPFOREIGN` constant.
3513pub const HFILE_SKIPFOREIGN: u32 = 0x0008;
3514/// `HFILE_FAST` constant.
3515pub const HFILE_FAST: u32 = 0x0010;
3516/// `HFILE_NO_REWRITE` constant.
3517pub const HFILE_NO_REWRITE: u32 = 0x0020;
3518/// `HFILE_USE_OPTIONS` constant.
3519pub const HFILE_USE_OPTIONS: u32 = 0x8000;
3520/// `LEXFLAGS_ACTIVE` constant.
3521pub const LEXFLAGS_ACTIVE: i32 = 0x0001;
3522/// `LEXFLAGS_ZLE` constant.
3523pub const LEXFLAGS_ZLE: i32 = 0x0002;
3524/// `LEXFLAGS_COMMENTS_KEEP` constant.
3525pub const LEXFLAGS_COMMENTS_KEEP: i32 = 0x0004;
3526/// `LEXFLAGS_COMMENTS_STRIP` constant.
3527pub const LEXFLAGS_COMMENTS_STRIP: i32 = 0x0008;
3528/// `LEXFLAGS_COMMENTS` constant.
3529pub const LEXFLAGS_COMMENTS: i32 = LEXFLAGS_COMMENTS_KEEP | LEXFLAGS_COMMENTS_STRIP;
3530/// `LEXFLAGS_NEWLINE` constant.
3531pub const LEXFLAGS_NEWLINE: i32 = 0x0010;
3532
3533// =============================================================================
3534// 33. Completion context (zsh.h:2322-2332).
3535// =============================================================================
3536/// `IN_NOTHING` constant.
3537pub const IN_NOTHING: i32 = 0;
3538/// `IN_CMD` constant.
3539pub const IN_CMD: i32 = 1;
3540/// `IN_MATH` constant.
3541pub const IN_MATH: i32 = 2;
3542/// `IN_COND` constant.
3543pub const IN_COND: i32 = 3;
3544/// `IN_ENV` constant.
3545pub const IN_ENV: i32 = 4;
3546/// `IN_PAR` constant.
3547pub const IN_PAR: i32 = 5;
3548
3549// =============================================================================
3550// 34. Emulation flags (zsh.h:2341-2358).
3551// =============================================================================
3552/// `EMULATE_CSH` constant.
3553pub const EMULATE_CSH: i32 = 1 << 1; // c:2341
3554/// `EMULATE_KSH` constant.
3555pub const EMULATE_KSH: i32 = 1 << 2;
3556/// `EMULATE_SH` constant.
3557pub const EMULATE_SH: i32 = 1 << 3;
3558/// `EMULATE_ZSH` constant.
3559pub const EMULATE_ZSH: i32 = 1 << 4;
3560/// `EMULATE_FULLY` constant.
3561pub const EMULATE_FULLY: i32 = 1 << 5;
3562/// `EMULATE_UNUSED` constant.
3563pub const EMULATE_UNUSED: i32 = 1 << 6;
3564
3565// =============================================================================
3566// 35. Option indices (zsh.h:2362-2550).
3567// =============================================================================
3568/// `OPT_INVALID` constant.
3569pub const OPT_INVALID: i32 = 0;
3570/// `ALIASESOPT` constant.
3571pub const ALIASESOPT: i32 = 1;
3572/// `ALIASFUNCDEF` constant.
3573pub const ALIASFUNCDEF: i32 = 2;
3574/// `ALLEXPORT` constant.
3575pub const ALLEXPORT: i32 = 3;
3576/// `ALWAYSLASTPROMPT` constant.
3577pub const ALWAYSLASTPROMPT: i32 = 4;
3578/// `ALWAYSTOEND` constant.
3579pub const ALWAYSTOEND: i32 = 5;
3580/// `APPENDHISTORY` constant.
3581pub const APPENDHISTORY: i32 = 6;
3582/// `AUTOCD` constant.
3583pub const AUTOCD: i32 = 7;
3584/// `AUTOCONTINUE` constant.
3585pub const AUTOCONTINUE: i32 = 8;
3586/// `AUTOLIST` constant.
3587pub const AUTOLIST: i32 = 9;
3588/// `AUTOMENU` constant.
3589pub const AUTOMENU: i32 = 10;
3590/// `AUTONAMEDIRS` constant.
3591pub const AUTONAMEDIRS: i32 = 11;
3592/// `AUTOPARAMKEYS` constant.
3593pub const AUTOPARAMKEYS: i32 = 12;
3594/// `AUTOPARAMSLASH` constant.
3595pub const AUTOPARAMSLASH: i32 = 13;
3596/// `AUTOPUSHD` constant.
3597pub const AUTOPUSHD: i32 = 14;
3598/// `AUTOREMOVESLASH` constant.
3599pub const AUTOREMOVESLASH: i32 = 15;
3600/// `AUTORESUME` constant.
3601pub const AUTORESUME: i32 = 16;
3602/// `BADPATTERN` constant.
3603pub const BADPATTERN: i32 = 17;
3604/// `BANGHIST` constant.
3605pub const BANGHIST: i32 = 18;
3606/// `BAREGLOBQUAL` constant.
3607pub const BAREGLOBQUAL: i32 = 19;
3608/// `BASHAUTOLIST` constant.
3609pub const BASHAUTOLIST: i32 = 20;
3610/// `BASHREMATCH` constant.
3611pub const BASHREMATCH: i32 = 21;
3612/// `BEEP` constant.
3613pub const BEEP: i32 = 22;
3614/// `BGNICE` constant.
3615pub const BGNICE: i32 = 23;
3616/// `BRACECCL` constant.
3617pub const BRACECCL: i32 = 24;
3618/// `BSDECHO` constant.
3619pub const BSDECHO: i32 = 25;
3620/// `CASEGLOB` constant.
3621pub const CASEGLOB: i32 = 26;
3622/// `CASEMATCH` constant.
3623pub const CASEMATCH: i32 = 27;
3624/// `CASEPATHS` constant.
3625pub const CASEPATHS: i32 = 28;
3626/// `CBASES` constant.
3627pub const CBASES: i32 = 29;
3628/// `CDABLEVARS` constant.
3629pub const CDABLEVARS: i32 = 30;
3630/// `CDSILENT` constant.
3631pub const CDSILENT: i32 = 31;
3632/// `CHASEDOTS` constant.
3633pub const CHASEDOTS: i32 = 32;
3634/// `CHASELINKS` constant.
3635pub const CHASELINKS: i32 = 33;
3636/// `CHECKJOBS` constant.
3637pub const CHECKJOBS: i32 = 34;
3638/// `CHECKRUNNINGJOBS` constant.
3639pub const CHECKRUNNINGJOBS: i32 = 35;
3640/// `CLOBBER` constant.
3641pub const CLOBBER: i32 = 36;
3642/// `CLOBBEREMPTY` constant.
3643pub const CLOBBEREMPTY: i32 = 37;
3644/// `APPENDCREATE` constant.
3645pub const APPENDCREATE: i32 = 38;
3646/// `COMBININGCHARS` constant.
3647pub const COMBININGCHARS: i32 = 39;
3648/// `COMPLETEALIASES` constant.
3649pub const COMPLETEALIASES: i32 = 40;
3650/// `COMPLETEINWORD` constant.
3651pub const COMPLETEINWORD: i32 = 41;
3652/// `CORRECT` constant.
3653pub const CORRECT: i32 = 42;
3654/// `CORRECTALL` constant.
3655pub const CORRECTALL: i32 = 43;
3656/// `CONTINUEONERROR` constant.
3657pub const CONTINUEONERROR: i32 = 44;
3658/// `CPRECEDENCES` constant.
3659pub const CPRECEDENCES: i32 = 45;
3660/// `CSHJUNKIEHISTORY` constant.
3661pub const CSHJUNKIEHISTORY: i32 = 46;
3662/// `CSHJUNKIELOOPS` constant.
3663pub const CSHJUNKIELOOPS: i32 = 47;
3664/// `CSHJUNKIEQUOTES` constant.
3665pub const CSHJUNKIEQUOTES: i32 = 48;
3666/// `CSHNULLCMD` constant.
3667pub const CSHNULLCMD: i32 = 49;
3668/// `CSHNULLGLOB` constant.
3669pub const CSHNULLGLOB: i32 = 50;
3670/// `DEBUGBEFORECMD` constant.
3671pub const DEBUGBEFORECMD: i32 = 51;
3672/// `EMACSMODE` constant.
3673pub const EMACSMODE: i32 = 52;
3674/// `EQUALSOPT` constant.
3675pub const EQUALSOPT: i32 = 53; // C name "EQUALS" collides with our token const
3676/// `ERREXIT` constant.
3677pub const ERREXIT: i32 = 54;
3678/// `ERRRETURN` constant.
3679pub const ERRRETURN: i32 = 55;
3680/// `EXECOPT` constant.
3681pub const EXECOPT: i32 = 56;
3682/// `EXTENDEDGLOB` constant.
3683pub const EXTENDEDGLOB: i32 = 57;
3684/// `EXTENDEDHISTORY` constant.
3685pub const EXTENDEDHISTORY: i32 = 58;
3686/// `EVALLINENO` constant.
3687pub const EVALLINENO: i32 = 59;
3688/// `FLOWCONTROL` constant.
3689pub const FLOWCONTROL: i32 = 60;
3690/// `FORCEFLOAT` constant.
3691pub const FORCEFLOAT: i32 = 61;
3692/// `FUNCTIONARGZERO` constant.
3693pub const FUNCTIONARGZERO: i32 = 62;
3694/// `GLOBOPT` constant.
3695pub const GLOBOPT: i32 = 63;
3696/// `GLOBALEXPORT` constant.
3697pub const GLOBALEXPORT: i32 = 64;
3698/// `GLOBALRCS` constant.
3699pub const GLOBALRCS: i32 = 65;
3700/// `GLOBASSIGN` constant.
3701pub const GLOBASSIGN: i32 = 66;
3702/// `GLOBCOMPLETE` constant.
3703pub const GLOBCOMPLETE: i32 = 67;
3704/// `GLOBDOTS` constant.
3705pub const GLOBDOTS: i32 = 68;
3706/// `GLOBSTARSHORT` constant.
3707pub const GLOBSTARSHORT: i32 = 69;
3708/// `GLOBSUBST` constant.
3709pub const GLOBSUBST: i32 = 70;
3710/// `HASHCMDS` constant.
3711pub const HASHCMDS: i32 = 71;
3712/// `HASHDIRS` constant.
3713pub const HASHDIRS: i32 = 72;
3714/// `HASHEXECUTABLESONLY` constant.
3715pub const HASHEXECUTABLESONLY: i32 = 73;
3716/// `HASHLISTALL` constant.
3717pub const HASHLISTALL: i32 = 74;
3718/// `HISTALLOWCLOBBER` constant.
3719pub const HISTALLOWCLOBBER: i32 = 75;
3720/// `HISTBEEP` constant.
3721pub const HISTBEEP: i32 = 76;
3722/// `HISTEXPIREDUPSFIRST` constant.
3723pub const HISTEXPIREDUPSFIRST: i32 = 77;
3724/// `HISTFCNTLLOCK` constant.
3725pub const HISTFCNTLLOCK: i32 = 78;
3726/// `HISTFINDNODUPS` constant.
3727pub const HISTFINDNODUPS: i32 = 79;
3728/// `HISTIGNOREALLDUPS` constant.
3729pub const HISTIGNOREALLDUPS: i32 = 80;
3730/// `HISTIGNOREDUPS` constant.
3731pub const HISTIGNOREDUPS: i32 = 81;
3732/// `HISTIGNORESPACE` constant.
3733pub const HISTIGNORESPACE: i32 = 82;
3734/// `HISTLEXWORDS` constant.
3735pub const HISTLEXWORDS: i32 = 83;
3736/// `HISTNOFUNCTIONS` constant.
3737pub const HISTNOFUNCTIONS: i32 = 84;
3738/// `HISTNOSTORE` constant.
3739pub const HISTNOSTORE: i32 = 85;
3740/// `HISTREDUCEBLANKS` constant.
3741pub const HISTREDUCEBLANKS: i32 = 86;
3742/// `HISTSAVEBYCOPY` constant.
3743pub const HISTSAVEBYCOPY: i32 = 87;
3744/// `HISTSAVENODUPS` constant.
3745pub const HISTSAVENODUPS: i32 = 88;
3746/// `HISTSUBSTPATTERN` constant.
3747pub const HISTSUBSTPATTERN: i32 = 89;
3748/// `HISTVERIFY` constant.
3749pub const HISTVERIFY: i32 = 90;
3750/// `HUP` constant.
3751pub const HUP: i32 = 91;
3752/// `IGNOREBRACES` constant.
3753pub const IGNOREBRACES: i32 = 92;
3754/// `IGNORECLOSEBRACES` constant.
3755pub const IGNORECLOSEBRACES: i32 = 93;
3756/// `IGNOREEOF` constant.
3757pub const IGNOREEOF: i32 = 94;
3758/// `INCAPPENDHISTORY` constant.
3759pub const INCAPPENDHISTORY: i32 = 95;
3760/// `INCAPPENDHISTORYTIME` constant.
3761pub const INCAPPENDHISTORYTIME: i32 = 96;
3762/// `INTERACTIVE` constant.
3763pub const INTERACTIVE: i32 = 97;
3764/// `INTERACTIVECOMMENTS` constant.
3765pub const INTERACTIVECOMMENTS: i32 = 98;
3766/// `KSHARRAYS` constant.
3767pub const KSHARRAYS: i32 = 99;
3768/// `KSHAUTOLOAD` constant.
3769pub const KSHAUTOLOAD: i32 = 100;
3770/// `KSHGLOB` constant.
3771pub const KSHGLOB: i32 = 101;
3772/// `KSHOPTIONPRINT` constant.
3773pub const KSHOPTIONPRINT: i32 = 102;
3774/// `KSHTYPESET` constant.
3775pub const KSHTYPESET: i32 = 103;
3776/// `KSHZEROSUBSCRIPT` constant.
3777pub const KSHZEROSUBSCRIPT: i32 = 104;
3778/// `LISTAMBIGUOUS` constant.
3779pub const LISTAMBIGUOUS: i32 = 105;
3780/// `LISTBEEP` constant.
3781pub const LISTBEEP: i32 = 106;
3782/// `LISTPACKED` constant.
3783pub const LISTPACKED: i32 = 107;
3784/// `LISTROWSFIRST` constant.
3785pub const LISTROWSFIRST: i32 = 108;
3786/// `LISTTYPES` constant.
3787pub const LISTTYPES: i32 = 109;
3788/// `LOCALLOOPS` constant.
3789pub const LOCALLOOPS: i32 = 110;
3790/// `LOCALOPTIONS` constant.
3791pub const LOCALOPTIONS: i32 = 111;
3792/// `LOCALPATTERNS` constant.
3793pub const LOCALPATTERNS: i32 = 112;
3794/// `LOCALTRAPS` constant.
3795pub const LOCALTRAPS: i32 = 113;
3796/// `LOGINSHELL` constant.
3797pub const LOGINSHELL: i32 = 114;
3798/// `LONGLISTJOBS` constant.
3799pub const LONGLISTJOBS: i32 = 115;
3800/// `MAGICEQUALSUBST` constant.
3801pub const MAGICEQUALSUBST: i32 = 116;
3802/// `MAILWARNING` constant.
3803pub const MAILWARNING: i32 = 117;
3804/// `MARKDIRS` constant.
3805pub const MARKDIRS: i32 = 118;
3806/// `MENUCOMPLETE` constant.
3807pub const MENUCOMPLETE: i32 = 119;
3808/// `MONITOR` constant.
3809pub const MONITOR: i32 = 120;
3810/// `MULTIBYTE` constant.
3811pub const MULTIBYTE: i32 = 121;
3812/// `MULTIFUNCDEF` constant.
3813pub const MULTIFUNCDEF: i32 = 122;
3814/// `MULTIOS` constant.
3815pub const MULTIOS: i32 = 123;
3816/// `NOMATCH` constant.
3817pub const NOMATCH: i32 = 124;
3818/// `NOTIFY` constant.
3819pub const NOTIFY: i32 = 125;
3820/// `NULLGLOB` constant.
3821pub const NULLGLOB: i32 = 126;
3822/// `NUMERICGLOBSORT` constant.
3823pub const NUMERICGLOBSORT: i32 = 127;
3824/// `OCTALZEROES` constant.
3825pub const OCTALZEROES: i32 = 128;
3826/// `OVERSTRIKE` constant.
3827pub const OVERSTRIKE: i32 = 129;
3828/// `PATHDIRS` constant.
3829pub const PATHDIRS: i32 = 130;
3830/// `PATHSCRIPT` constant.
3831pub const PATHSCRIPT: i32 = 131;
3832/// `PIPEFAIL` constant.
3833pub const PIPEFAIL: i32 = 132;
3834/// `POSIXALIASES` constant.
3835pub const POSIXALIASES: i32 = 133;
3836/// `POSIXARGZERO` constant.
3837pub const POSIXARGZERO: i32 = 134;
3838/// `POSIXBUILTINS` constant.
3839pub const POSIXBUILTINS: i32 = 135;
3840/// `POSIXCD` constant.
3841pub const POSIXCD: i32 = 136;
3842/// `POSIXIDENTIFIERS` constant.
3843pub const POSIXIDENTIFIERS: i32 = 137;
3844/// `POSIXJOBS` constant.
3845pub const POSIXJOBS: i32 = 138;
3846/// `POSIXSTRINGS` constant.
3847pub const POSIXSTRINGS: i32 = 139;
3848/// `POSIXTRAPS` constant.
3849pub const POSIXTRAPS: i32 = 140;
3850/// `PRINTEIGHTBIT` constant.
3851pub const PRINTEIGHTBIT: i32 = 141;
3852/// `PRINTEXITVALUE` constant.
3853pub const PRINTEXITVALUE: i32 = 142;
3854/// `PRIVILEGED` constant.
3855pub const PRIVILEGED: i32 = 143;
3856/// `PROMPTBANG` constant.
3857pub const PROMPTBANG: i32 = 144;
3858/// `PROMPTCR` constant.
3859pub const PROMPTCR: i32 = 145;
3860/// `PROMPTPERCENT` constant.
3861pub const PROMPTPERCENT: i32 = 146;
3862/// `PROMPTSP` constant.
3863pub const PROMPTSP: i32 = 147;
3864/// `PROMPTSUBST` constant.
3865pub const PROMPTSUBST: i32 = 148;
3866/// `PUSHDIGNOREDUPS` constant.
3867pub const PUSHDIGNOREDUPS: i32 = 149;
3868/// `PUSHDMINUS` constant.
3869pub const PUSHDMINUS: i32 = 150;
3870/// `PUSHDSILENT` constant.
3871pub const PUSHDSILENT: i32 = 151;
3872/// `PUSHDTOHOME` constant.
3873pub const PUSHDTOHOME: i32 = 152;
3874/// `RCEXPANDPARAM` constant.
3875pub const RCEXPANDPARAM: i32 = 153;
3876/// `RCQUOTES` constant.
3877pub const RCQUOTES: i32 = 154;
3878/// `RCS` constant.
3879pub const RCS: i32 = 155;
3880/// `RECEXACT` constant.
3881pub const RECEXACT: i32 = 156;
3882/// `REMATCHPCRE` constant.
3883pub const REMATCHPCRE: i32 = 157;
3884/// `RESTRICTED` constant.
3885pub const RESTRICTED: i32 = 158;
3886/// `RMSTARSILENT` constant.
3887pub const RMSTARSILENT: i32 = 159;
3888/// `RMSTARWAIT` constant.
3889pub const RMSTARWAIT: i32 = 160;
3890/// `SHAREHISTORY` constant.
3891pub const SHAREHISTORY: i32 = 161;
3892/// `SHFILEEXPANSION` constant.
3893pub const SHFILEEXPANSION: i32 = 162;
3894/// `SHGLOB` constant.
3895pub const SHGLOB: i32 = 163;
3896/// `SHINSTDIN` constant.
3897pub const SHINSTDIN: i32 = 164;
3898/// `SHNULLCMD` constant.
3899pub const SHNULLCMD: i32 = 165;
3900/// `SHOPTIONLETTERS` constant.
3901pub const SHOPTIONLETTERS: i32 = 166;
3902/// `SHORTLOOPS` constant.
3903pub const SHORTLOOPS: i32 = 167;
3904/// `SHORTREPEAT` constant.
3905pub const SHORTREPEAT: i32 = 168;
3906/// `SHWORDSPLIT` constant.
3907pub const SHWORDSPLIT: i32 = 169;
3908/// `SINGLECOMMAND` constant.
3909pub const SINGLECOMMAND: i32 = 170;
3910/// `SINGLELINEZLE` constant.
3911pub const SINGLELINEZLE: i32 = 171;
3912/// `SOURCETRACE` constant.
3913pub const SOURCETRACE: i32 = 172;
3914/// `SUNKEYBOARDHACK` constant.
3915pub const SUNKEYBOARDHACK: i32 = 173;
3916/// `TRANSIENTRPROMPT` constant.
3917pub const TRANSIENTRPROMPT: i32 = 174;
3918/// `TRAPSASYNC` constant.
3919pub const TRAPSASYNC: i32 = 175;
3920/// `TYPESETSILENT` constant.
3921pub const TYPESETSILENT: i32 = 176;
3922/// `TYPESETTOUNSET` constant.
3923pub const TYPESETTOUNSET: i32 = 177;
3924/// `UNSET` constant.
3925pub const UNSET: i32 = 178;
3926/// `VERBOSE` constant.
3927pub const VERBOSE: i32 = 179;
3928/// `VIMODE` constant.
3929pub const VIMODE: i32 = 180;
3930/// `WARNCREATEGLOBAL` constant.
3931pub const WARNCREATEGLOBAL: i32 = 181;
3932/// `WARNNESTEDVAR` constant.
3933pub const WARNNESTEDVAR: i32 = 182;
3934/// `XTRACE` constant.
3935pub const XTRACE: i32 = 183;
3936/// `USEZLE` constant.
3937pub const USEZLE: i32 = 184;
3938/// `DVORAK` constant.
3939pub const DVORAK: i32 = 185;
3940/// `OPT_SIZE` constant.
3941pub const OPT_SIZE: i32 = 186;
3942/// `OptIndex` type alias.
3943pub type OptIndex = u8; // c:2556
3944
3945// #define isset(X) (opts[X]) // c:2559
3946/// Port of `isset(X)` macro from `Src/zsh.h:2559`.
3947/// Returns true if option is set.
3948#[inline]
3949pub fn isset(opt: i32) -> bool {
3950 // c:Src/zsh.h:2557 `#define isset(X) (opts[X])` — a single array load.
3951 // Backed by the extensions::opts_cache fast path (one relaxed atomic
3952 // load) instead of the old name→num→name + RwLock + String-hash path.
3953 crate::opts_cache::is_set(opt)
3954}
3955
3956// #define unset(X) (!opts[X]) // c:2560
3957/// Port of `unset(X)` macro from `Src/zsh.h:2560`.
3958/// Returns true if option is NOT set.
3959#[inline]
3960pub fn unset(opt: i32) -> bool {
3961 !isset(opt)
3962}
3963
3964// #define interact (isset(INTERACTIVE)) // c:2562
3965/// Port of `interact` macro from `Src/zsh.h:2562`.
3966#[inline]
3967pub fn interact() -> bool {
3968 isset(INTERACTIVE)
3969}
3970
3971// #define jobbing (isset(MONITOR)) // c:2563
3972/// Port of `jobbing` macro from `Src/zsh.h:2563`.
3973#[inline]
3974pub fn jobbing() -> bool {
3975 isset(MONITOR)
3976}
3977
3978// #define islogin (isset(LOGINSHELL)) // c:2564
3979/// Port of `islogin` macro from `Src/zsh.h:2564`.
3980#[inline]
3981pub fn islogin() -> bool {
3982 isset(LOGINSHELL)
3983}
3984
3985/// Helper: convert option constant to its name for lookup.
3986///
3987/// Cached O(1) number→name lookup. The canonical match below has ~185
3988/// arms of `x if x == CONST` guards, which the compiler lowers to a
3989/// LINEAR comparison chain (guards defeat jump-table lowering). It used
3990/// to run per call; `optno_by_name` calls it in a `1..OPT_SIZE` loop,
3991/// so a single `optlookup`/`isset` was O(OPT_SIZE²). That dominated
3992/// startup — compinit issues ~600k isset() calls and effectively hung.
3993/// Building the table once (closure, not a new fn) makes every later
3994/// `opt_name` a single vector index.
3995pub fn opt_name(opt: i32) -> &'static str {
3996 static OPT_NAMES: std::sync::OnceLock<Vec<&'static str>> = std::sync::OnceLock::new();
3997 let table = OPT_NAMES.get_or_init(|| {
3998 let build = |opt: i32| -> &'static str {
3999 match opt {
4000 x if x == ALIASFUNCDEF => "aliasfuncdef",
4001 x if x == ALLEXPORT => "allexport",
4002 x if x == ALWAYSLASTPROMPT => "alwayslastprompt",
4003 x if x == ALWAYSTOEND => "alwaystoend",
4004 x if x == APPENDHISTORY => "appendhistory",
4005 x if x == AUTOCD => "autocd",
4006 x if x == AUTOCONTINUE => "autocontinue",
4007 x if x == AUTOLIST => "autolist",
4008 x if x == AUTOMENU => "automenu",
4009 x if x == AUTONAMEDIRS => "autonamedirs",
4010 x if x == AUTOPARAMKEYS => "autoparamkeys",
4011 x if x == AUTOPARAMSLASH => "autoparamslash",
4012 x if x == AUTOPUSHD => "autopushd",
4013 x if x == AUTOREMOVESLASH => "autoremoveslash",
4014 x if x == AUTORESUME => "autoresume",
4015 x if x == BADPATTERN => "badpattern",
4016 x if x == BANGHIST => "banghist",
4017 x if x == BAREGLOBQUAL => "bareglobqual",
4018 x if x == BASHAUTOLIST => "bashautolist",
4019 x if x == BASHREMATCH => "bashrematch",
4020 x if x == BEEP => "beep",
4021 x if x == BGNICE => "bgnice",
4022 x if x == BRACECCL => "braceccl",
4023 x if x == BSDECHO => "bsdecho",
4024 x if x == CASEGLOB => "caseglob",
4025 x if x == CASEMATCH => "casematch",
4026 x if x == CASEPATHS => "casepaths",
4027 x if x == CBASES => "cbases",
4028 x if x == CDABLEVARS => "cdablevars",
4029 x if x == CDSILENT => "cdsilent",
4030 x if x == CHASEDOTS => "chasedots",
4031 x if x == CHASELINKS => "chaselinks",
4032 x if x == CHECKJOBS => "checkjobs",
4033 x if x == CHECKRUNNINGJOBS => "checkrunningjobs",
4034 x if x == CLOBBER => "clobber",
4035 x if x == CLOBBEREMPTY => "clobberempty",
4036 x if x == APPENDCREATE => "appendcreate",
4037 x if x == COMBININGCHARS => "combiningchars",
4038 x if x == COMPLETEALIASES => "completealiases",
4039 x if x == COMPLETEINWORD => "completeinword",
4040 x if x == CORRECT => "correct",
4041 x if x == CORRECTALL => "correctall",
4042 x if x == CPRECEDENCES => "cprecedences",
4043 x if x == CSHJUNKIEHISTORY => "cshjunkiehistory",
4044 x if x == CSHJUNKIELOOPS => "cshjunkieloops",
4045 x if x == CSHJUNKIEQUOTES => "cshjunkiequotes",
4046 x if x == CSHNULLCMD => "cshnullcmd",
4047 x if x == CSHNULLGLOB => "cshnullglob",
4048 x if x == CONTINUEONERROR => "continueonerror",
4049 x if x == DEBUGBEFORECMD => "debugbeforecmd",
4050 x if x == EMACSMODE => "emacs",
4051 x if x == EQUALSOPT => "equals",
4052 x if x == ERREXIT => "errexit",
4053 x if x == ERRRETURN => "errreturn",
4054 x if x == EXECOPT => "exec",
4055 x if x == EXTENDEDGLOB => "extendedglob",
4056 x if x == EXTENDEDHISTORY => "extendedhistory",
4057 x if x == EVALLINENO => "evallineno",
4058 x if x == FLOWCONTROL => "flowcontrol",
4059 x if x == FORCEFLOAT => "forcefloat",
4060 x if x == FUNCTIONARGZERO => "functionargzero",
4061 x if x == GLOBOPT => "glob",
4062 x if x == GLOBALEXPORT => "globalexport",
4063 x if x == GLOBALRCS => "globalrcs",
4064 x if x == GLOBASSIGN => "globassign",
4065 x if x == GLOBCOMPLETE => "globcomplete",
4066 x if x == GLOBDOTS => "globdots",
4067 x if x == GLOBSTARSHORT => "globstarshort",
4068 x if x == GLOBSUBST => "globsubst",
4069 x if x == HASHCMDS => "hashcmds",
4070 x if x == HASHDIRS => "hashdirs",
4071 x if x == HASHEXECUTABLESONLY => "hashexecutablesonly",
4072 x if x == HASHLISTALL => "hashlistall",
4073 x if x == HISTALLOWCLOBBER => "histallowclobber",
4074 x if x == HISTBEEP => "histbeep",
4075 x if x == HISTEXPIREDUPSFIRST => "histexpiredupsfirst",
4076 x if x == HISTFCNTLLOCK => "histfcntllock",
4077 x if x == HISTFINDNODUPS => "histfindnodups",
4078 x if x == HISTIGNOREALLDUPS => "histignorealldups",
4079 x if x == HISTIGNOREDUPS => "histignoredups",
4080 x if x == HISTIGNORESPACE => "histignorespace",
4081 x if x == HISTLEXWORDS => "histlexwords",
4082 x if x == HISTNOFUNCTIONS => "histnofunctions",
4083 x if x == HISTNOSTORE => "histnostore",
4084 x if x == HISTREDUCEBLANKS => "histreduceblanks",
4085 x if x == HISTSAVEBYCOPY => "histsavebycopy",
4086 x if x == HISTSAVENODUPS => "histsavenodups",
4087 x if x == HISTSUBSTPATTERN => "histsubstpattern",
4088 x if x == HISTVERIFY => "histverify",
4089 x if x == HUP => "hup",
4090 x if x == IGNOREBRACES => "ignorebraces",
4091 x if x == IGNORECLOSEBRACES => "ignoreclosebraces",
4092 x if x == IGNOREEOF => "ignoreeof",
4093 x if x == INCAPPENDHISTORY => "incappendhistory",
4094 x if x == INCAPPENDHISTORYTIME => "incappendhistorytime",
4095 x if x == INTERACTIVE => "interactive",
4096 x if x == INTERACTIVECOMMENTS => "interactivecomments",
4097 x if x == KSHARRAYS => "ksharrays",
4098 x if x == KSHAUTOLOAD => "kshautoload",
4099 x if x == KSHGLOB => "kshglob",
4100 x if x == KSHOPTIONPRINT => "kshoptionprint",
4101 x if x == KSHTYPESET => "kshtypeset",
4102 x if x == KSHZEROSUBSCRIPT => "kshzerosubscript",
4103 x if x == LISTAMBIGUOUS => "listambiguous",
4104 x if x == LISTBEEP => "listbeep",
4105 x if x == LISTPACKED => "listpacked",
4106 x if x == LISTROWSFIRST => "listrowsfirst",
4107 x if x == LISTTYPES => "listtypes",
4108 x if x == LOCALOPTIONS => "localoptions",
4109 x if x == LOCALLOOPS => "localloops",
4110 x if x == LOCALPATTERNS => "localpatterns",
4111 x if x == LOCALTRAPS => "localtraps",
4112 x if x == LOGINSHELL => "loginshell",
4113 x if x == LONGLISTJOBS => "longlistjobs",
4114 x if x == MAGICEQUALSUBST => "magicequalsubst",
4115 x if x == MAILWARNING => "mailwarning",
4116 x if x == MARKDIRS => "markdirs",
4117 x if x == MENUCOMPLETE => "menucomplete",
4118 x if x == MONITOR => "monitor",
4119 x if x == MULTIBYTE => "multibyte",
4120 x if x == MULTIFUNCDEF => "multifuncdef",
4121 x if x == MULTIOS => "multios",
4122 x if x == NOMATCH => "nomatch",
4123 x if x == NOTIFY => "notify",
4124 x if x == NULLGLOB => "nullglob",
4125 x if x == NUMERICGLOBSORT => "numericglobsort",
4126 x if x == OCTALZEROES => "octalzeroes",
4127 x if x == OVERSTRIKE => "overstrike",
4128 x if x == PATHDIRS => "pathdirs",
4129 x if x == PATHSCRIPT => "pathscript",
4130 x if x == PIPEFAIL => "pipefail",
4131 x if x == POSIXALIASES => "posixaliases",
4132 x if x == POSIXARGZERO => "posixargzero",
4133 x if x == POSIXBUILTINS => "posixbuiltins",
4134 x if x == POSIXCD => "posixcd",
4135 x if x == POSIXIDENTIFIERS => "posixidentifiers",
4136 x if x == POSIXJOBS => "posixjobs",
4137 x if x == POSIXSTRINGS => "posixstrings",
4138 x if x == POSIXTRAPS => "posixtraps",
4139 x if x == PRINTEIGHTBIT => "printeightbit",
4140 x if x == PRINTEXITVALUE => "printexitvalue",
4141 x if x == PRIVILEGED => "privileged",
4142 x if x == PROMPTBANG => "promptbang",
4143 x if x == PROMPTCR => "promptcr",
4144 x if x == PROMPTPERCENT => "promptpercent",
4145 x if x == PROMPTSP => "promptsp",
4146 x if x == PROMPTSUBST => "promptsubst",
4147 x if x == PUSHDIGNOREDUPS => "pushdignoredups",
4148 x if x == PUSHDMINUS => "pushdminus",
4149 x if x == PUSHDSILENT => "pushdsilent",
4150 x if x == PUSHDTOHOME => "pushdtohome",
4151 x if x == RCEXPANDPARAM => "rcexpandparam",
4152 x if x == RCQUOTES => "rcquotes",
4153 x if x == RCS => "rcs",
4154 x if x == RECEXACT => "recexact",
4155 x if x == REMATCHPCRE => "rematchpcre",
4156 x if x == RESTRICTED => "restricted",
4157 x if x == RMSTARSILENT => "rmstarsilent",
4158 x if x == RMSTARWAIT => "rmstarwait",
4159 x if x == SHAREHISTORY => "sharehistory",
4160 x if x == SHFILEEXPANSION => "shfileexpansion",
4161 x if x == SHGLOB => "shglob",
4162 x if x == SHINSTDIN => "shinstdin",
4163 x if x == SHNULLCMD => "shnullcmd",
4164 x if x == SHOPTIONLETTERS => "shoptionletters",
4165 x if x == SHORTLOOPS => "shortloops",
4166 x if x == SHORTREPEAT => "shortrepeat",
4167 x if x == SHWORDSPLIT => "shwordsplit",
4168 x if x == SINGLECOMMAND => "singlecommand",
4169 x if x == SINGLELINEZLE => "singlelinezle",
4170 x if x == SOURCETRACE => "sourcetrace",
4171 x if x == SUNKEYBOARDHACK => "sunkeyboardhack",
4172 x if x == TRANSIENTRPROMPT => "transientrprompt",
4173 x if x == TRAPSASYNC => "trapsasync",
4174 x if x == TYPESETSILENT => "typesetsilent",
4175 x if x == TYPESETTOUNSET => "typesettounset",
4176 x if x == UNSET => "unset",
4177 x if x == VERBOSE => "verbose",
4178 x if x == ALIASESOPT => "aliases",
4179 x if x == WARNCREATEGLOBAL => "warncreateglobal",
4180 x if x == WARNNESTEDVAR => "warnnestedvar",
4181 x if x == XTRACE => "xtrace",
4182 x if x == USEZLE => "zle",
4183 x if x == DVORAK => "dvorak",
4184 // VIMODE was missing entirely from the opt_name table.
4185 // The storage key in ZSH_OPTIONS_SET is "vi" (not "vimode")
4186 // — must match so isset(VIMODE) and opt_state_set("vi")
4187 // address the same slot.
4188 x if x == VIMODE => "vi",
4189 _ => "",
4190 }
4191 };
4192 (0..OPT_SIZE).map(build).collect()
4193 });
4194 table.get(opt as usize).copied().unwrap_or("")
4195}
4196
4197// =============================================================================
4198// 36. Terminal control (zsh.h:2633-2680).
4199// =============================================================================
4200/// `TERM_BAD` constant.
4201pub const TERM_BAD: i32 = 0x01;
4202/// `TERM_UNKNOWN` constant.
4203pub const TERM_UNKNOWN: i32 = 0x02;
4204/// `TERM_NOUP` constant.
4205pub const TERM_NOUP: i32 = 0x04;
4206/// `TERM_SHORT` constant.
4207pub const TERM_SHORT: i32 = 0x08;
4208/// `TERM_NARROW` constant.
4209pub const TERM_NARROW: i32 = 0x10;
4210/// `TCCLEARSCREEN` constant.
4211pub const TCCLEARSCREEN: i32 = 0;
4212/// `TCLEFT` constant.
4213pub const TCLEFT: i32 = 1;
4214/// `TCMULTLEFT` constant.
4215pub const TCMULTLEFT: i32 = 2;
4216/// `TCRIGHT` constant.
4217pub const TCRIGHT: i32 = 3;
4218/// `TCMULTRIGHT` constant.
4219pub const TCMULTRIGHT: i32 = 4;
4220/// `TCUP` constant.
4221pub const TCUP: i32 = 5;
4222/// `TCMULTUP` constant.
4223pub const TCMULTUP: i32 = 6;
4224/// `TCDOWN` constant.
4225pub const TCDOWN: i32 = 7;
4226/// `TCMULTDOWN` constant.
4227pub const TCMULTDOWN: i32 = 8;
4228/// `TCDEL` constant.
4229pub const TCDEL: i32 = 9;
4230/// `TCMULTDEL` constant.
4231pub const TCMULTDEL: i32 = 10;
4232/// `TCINS` constant.
4233pub const TCINS: i32 = 11;
4234/// `TCMULTINS` constant.
4235pub const TCMULTINS: i32 = 12;
4236/// `TCCLEAREOD` constant.
4237pub const TCCLEAREOD: i32 = 13;
4238/// `TCCLEAREOL` constant.
4239pub const TCCLEAREOL: i32 = 14;
4240/// `TCINSLINE` constant.
4241pub const TCINSLINE: i32 = 15;
4242/// `TCDELLINE` constant.
4243pub const TCDELLINE: i32 = 16;
4244/// `TCNEXTTAB` constant.
4245pub const TCNEXTTAB: i32 = 17;
4246/// `TCBOLDFACEBEG` constant.
4247pub const TCBOLDFACEBEG: i32 = 18;
4248/// `TCFAINTBEG` constant.
4249pub const TCFAINTBEG: i32 = 19;
4250/// `TCSTANDOUTBEG` constant.
4251pub const TCSTANDOUTBEG: i32 = 20;
4252/// `TCUNDERLINEBEG` constant.
4253pub const TCUNDERLINEBEG: i32 = 21;
4254/// `TCITALICSBEG` constant.
4255pub const TCITALICSBEG: i32 = 22;
4256/// `TCALLATTRSOFF` constant.
4257pub const TCALLATTRSOFF: i32 = 23;
4258/// `TCSTANDOUTEND` constant.
4259pub const TCSTANDOUTEND: i32 = 24;
4260/// `TCUNDERLINEEND` constant.
4261pub const TCUNDERLINEEND: i32 = 25;
4262/// `TCITALICSEND` constant.
4263pub const TCITALICSEND: i32 = 26;
4264/// `TCHORIZPOS` constant.
4265pub const TCHORIZPOS: i32 = 27;
4266/// `TCUPCURSOR` constant.
4267pub const TCUPCURSOR: i32 = 28;
4268/// `TCDOWNCURSOR` constant.
4269pub const TCDOWNCURSOR: i32 = 29;
4270/// `TCLEFTCURSOR` constant.
4271pub const TCLEFTCURSOR: i32 = 30;
4272/// `TCRIGHTCURSOR` constant.
4273pub const TCRIGHTCURSOR: i32 = 31;
4274/// `TCSAVECURSOR` constant.
4275pub const TCSAVECURSOR: i32 = 32;
4276/// `TCRESTRCURSOR` constant.
4277pub const TCRESTRCURSOR: i32 = 33;
4278/// `TCBACKSPACE` constant.
4279pub const TCBACKSPACE: i32 = 34;
4280/// `TCFGCOLOUR` constant.
4281pub const TCFGCOLOUR: i32 = 35;
4282/// `TCBGCOLOUR` constant.
4283pub const TCBGCOLOUR: i32 = 36;
4284/// `TCCURINV` constant.
4285pub const TCCURINV: i32 = 37;
4286/// `TCCURVIS` constant.
4287pub const TCCURVIS: i32 = 38;
4288/// `TC_COUNT` constant.
4289pub const TC_COUNT: i32 = 39;
4290
4291// =============================================================================
4292// 37. Text attributes (zattr) (zsh.h:2689-2750).
4293// =============================================================================
4294/// `zattr` type alias.
4295pub type zattr = u64; // c:2689
4296/// `TXTBOLDFACE` constant.
4297pub const TXTBOLDFACE: zattr = 0x0001;
4298/// `TXTFAINT` constant.
4299pub const TXTFAINT: zattr = 0x0002;
4300/// `TXTSTANDOUT` constant.
4301pub const TXTSTANDOUT: zattr = 0x0004;
4302/// `TXTUNDERLINE` constant.
4303pub const TXTUNDERLINE: zattr = 0x0008;
4304/// `TXTITALIC` constant.
4305pub const TXTITALIC: zattr = 0x0010;
4306/// `TXTFGCOLOUR` constant.
4307pub const TXTFGCOLOUR: zattr = 0x0020;
4308/// `TXTBGCOLOUR` constant.
4309pub const TXTBGCOLOUR: zattr = 0x0040;
4310/// `TXT_ATTR_ALL` constant.
4311pub const TXT_ATTR_ALL: zattr = 0x007F;
4312/// `TXT_MULTIWORD_MASK` constant.
4313pub const TXT_MULTIWORD_MASK: zattr = 0x0400;
4314/// `TXT_ERROR` constant.
4315pub const TXT_ERROR: zattr = 0xF00000F000000003;
4316/// `TXT_ATTR_FONT_WEIGHT` constant.
4317pub const TXT_ATTR_FONT_WEIGHT: zattr = TXTBOLDFACE | TXTFAINT;
4318/// `TXT_ATTR_FG_COL_MASK` constant.
4319pub const TXT_ATTR_FG_COL_MASK: zattr = 0x000000FFFFFF0000;
4320/// `TXT_ATTR_FG_COL_SHIFT` constant.
4321pub const TXT_ATTR_FG_COL_SHIFT: u32 = 16;
4322/// `TXT_ATTR_BG_COL_MASK` constant.
4323pub const TXT_ATTR_BG_COL_MASK: zattr = 0xFFFFFF0000000000;
4324/// `TXT_ATTR_BG_COL_SHIFT` constant.
4325pub const TXT_ATTR_BG_COL_SHIFT: u32 = 40;
4326/// `TXT_ATTR_FG_24BIT` constant.
4327pub const TXT_ATTR_FG_24BIT: zattr = 0x4000;
4328/// `TXT_ATTR_BG_24BIT` constant.
4329pub const TXT_ATTR_BG_24BIT: zattr = 0x8000;
4330/// `TXT_ATTR_FG_MASK` constant.
4331pub const TXT_ATTR_FG_MASK: zattr = TXTFGCOLOUR | TXT_ATTR_FG_COL_MASK | TXT_ATTR_FG_24BIT;
4332/// `TXT_ATTR_BG_MASK` constant.
4333pub const TXT_ATTR_BG_MASK: zattr = TXTBGCOLOUR | TXT_ATTR_BG_COL_MASK | TXT_ATTR_BG_24BIT;
4334/// `TXT_ATTR_COLOUR_MASK` constant.
4335pub const TXT_ATTR_COLOUR_MASK: zattr = TXT_ATTR_FG_MASK | TXT_ATTR_BG_MASK;
4336/// `COL_SEQ_FG` constant.
4337pub const COL_SEQ_FG: i32 = 0;
4338/// `COL_SEQ_BG` constant.
4339pub const COL_SEQ_BG: i32 = 1;
4340/// `color_rgb` — see fields for layout.
4341#[allow(non_camel_case_types)]
4342pub struct color_rgb {
4343 // c:2752
4344 /// `red` field.
4345 pub red: u32,
4346 /// `green` field.
4347 pub green: u32,
4348 /// `blue` field.
4349 pub blue: u32,
4350}
4351/// `Color_rgb` type alias.
4352pub type Color_rgb = Box<color_rgb>;
4353/// `TSC_RAW` constant.
4354pub const TSC_RAW: i32 = 0x0001; // c:2764
4355/// `TSC_PROMPT` constant.
4356pub const TSC_PROMPT: i32 = 0x0002;
4357/// `TSC_DIRTY` constant — zsh 5.9.1 zsh.h:2766. The 5.9 release's
4358/// tsetcap re-applies the still-active attributes + colours after a
4359/// cap that may have clobbered them (every END cap, ALLATTRSOFF, and
4360/// BOLDFACEBEG). Master's prompt.c rewrite (applytextattributes)
4361/// dropped the flag, but the zshrs parity floor is the 5.9.x release
4362/// binary, whose emission sequences depend on it.
4363pub const TSC_DIRTY: i32 = 0x0004;
4364
4365// =============================================================================
4366// 38. Prompt %_ command stack (zsh.h:2773-2809).
4367// =============================================================================
4368/// `CMDSTACKSZ` constant.
4369pub const CMDSTACKSZ: usize = 256;
4370/// `CS_FOR` constant.
4371pub const CS_FOR: i32 = 0;
4372/// `CS_WHILE` constant.
4373pub const CS_WHILE: i32 = 1;
4374/// `CS_REPEAT` constant.
4375pub const CS_REPEAT: i32 = 2;
4376/// `CS_SELECT` constant.
4377pub const CS_SELECT: i32 = 3;
4378/// `CS_UNTIL` constant.
4379pub const CS_UNTIL: i32 = 4;
4380/// `CS_IF` constant.
4381pub const CS_IF: i32 = 5;
4382/// `CS_IFTHEN` constant.
4383pub const CS_IFTHEN: i32 = 6;
4384/// `CS_ELSE` constant.
4385pub const CS_ELSE: i32 = 7;
4386/// `CS_ELIF` constant.
4387pub const CS_ELIF: i32 = 8;
4388/// `CS_MATH` constant.
4389pub const CS_MATH: i32 = 9;
4390/// `CS_COND` constant.
4391pub const CS_COND: i32 = 10;
4392/// `CS_CMDOR` constant.
4393pub const CS_CMDOR: i32 = 11;
4394/// `CS_CMDAND` constant.
4395pub const CS_CMDAND: i32 = 12;
4396/// `CS_PIPE` constant.
4397pub const CS_PIPE: i32 = 13;
4398/// `CS_ERRPIPE` constant.
4399pub const CS_ERRPIPE: i32 = 14;
4400/// `CS_FOREACH` constant.
4401pub const CS_FOREACH: i32 = 15;
4402/// `CS_CASE` constant.
4403pub const CS_CASE: i32 = 16;
4404/// `CS_FUNCDEF` constant.
4405pub const CS_FUNCDEF: i32 = 17;
4406/// `CS_SUBSH` constant.
4407pub const CS_SUBSH: i32 = 18;
4408/// `CS_CURSH` constant.
4409pub const CS_CURSH: i32 = 19;
4410/// `CS_ARRAY` constant.
4411pub const CS_ARRAY: i32 = 20;
4412/// `CS_QUOTE` constant.
4413pub const CS_QUOTE: i32 = 21;
4414/// `CS_DQUOTE` constant.
4415pub const CS_DQUOTE: i32 = 22;
4416/// `CS_BQUOTE` constant.
4417pub const CS_BQUOTE: i32 = 23;
4418/// `CS_CMDSUBST` constant.
4419pub const CS_CMDSUBST: i32 = 24;
4420/// `CS_MATHSUBST` constant.
4421pub const CS_MATHSUBST: i32 = 25;
4422/// `CS_ELIFTHEN` constant.
4423pub const CS_ELIFTHEN: i32 = 26;
4424/// `CS_HEREDOC` constant.
4425pub const CS_HEREDOC: i32 = 27;
4426/// `CS_HEREDOCD` constant.
4427pub const CS_HEREDOCD: i32 = 28;
4428/// `CS_BRACE` constant.
4429pub const CS_BRACE: i32 = 29;
4430/// `CS_BRACEPAR` constant.
4431pub const CS_BRACEPAR: i32 = 30;
4432/// `CS_ALWAYS` constant.
4433pub const CS_ALWAYS: i32 = 31;
4434/// `CS_COUNT` constant.
4435pub const CS_COUNT: i32 = 32;
4436
4437// =============================================================================
4438// 39. Heap memory + Heapid (zsh.h:2826-2862).
4439// =============================================================================
4440/// `Heapid` type alias.
4441pub type Heapid = u32; // c:2826
4442/// `HEAPID_PERMANENT` constant.
4443pub const HEAPID_PERMANENT: Heapid = u32::MAX; // c:2834
4444/// `HDV_PUSH` constant.
4445pub const HDV_PUSH: i32 = 0x01;
4446/// `HDV_POP` constant.
4447pub const HDV_POP: i32 = 0x02;
4448/// `HDV_CREATE` constant.
4449pub const HDV_CREATE: i32 = 0x04;
4450/// `HDV_FREE` constant.
4451pub const HDV_FREE: i32 = 0x08;
4452/// `HDV_NEW` constant.
4453pub const HDV_NEW: i32 = 0x10;
4454/// `HDV_OLD` constant.
4455pub const HDV_OLD: i32 = 0x20;
4456/// `HDV_SWITCH` constant.
4457pub const HDV_SWITCH: i32 = 0x40;
4458/// `HDV_ALLOC` constant.
4459pub const HDV_ALLOC: i32 = 0x80;
4460
4461// =============================================================================
4462// 40. Signal trap state (zsh.h:2935-2984).
4463// =============================================================================
4464/// `ZSIG_TRAPPED` constant.
4465pub const ZSIG_TRAPPED: i32 = 1 << 0;
4466/// `ZSIG_IGNORED` constant.
4467pub const ZSIG_IGNORED: i32 = 1 << 1;
4468/// `ZSIG_FUNC` constant.
4469pub const ZSIG_FUNC: i32 = 1 << 2;
4470/// `ZSIG_MASK` constant.
4471pub const ZSIG_MASK: i32 = ZSIG_TRAPPED | ZSIG_IGNORED | ZSIG_FUNC;
4472/// `ZSIG_ALIAS` constant.
4473pub const ZSIG_ALIAS: i32 = 1 << 3;
4474/// `ZSIG_SHIFT` constant.
4475pub const ZSIG_SHIFT: i32 = 4;
4476/// `TRAP_STATE_INACTIVE` constant.
4477pub const TRAP_STATE_INACTIVE: i32 = 0;
4478/// `TRAP_STATE_PRIMED` constant.
4479pub const TRAP_STATE_PRIMED: i32 = 1;
4480/// `TRAP_STATE_FORCE_RETURN` constant.
4481pub const TRAP_STATE_FORCE_RETURN: i32 = 2;
4482/// `ERRFLAG_ERROR` constant.
4483pub const ERRFLAG_ERROR: i32 = 1;
4484/// `ERRFLAG_INT` constant.
4485pub const ERRFLAG_INT: i32 = 2;
4486/// `ERRFLAG_HARD` constant.
4487pub const ERRFLAG_HARD: i32 = 4;
4488
4489// =============================================================================
4490// 41. Sorting (zsh.h:2992-3008).
4491// =============================================================================
4492/// `SORTIT_ANYOLDHOW` constant.
4493pub const SORTIT_ANYOLDHOW: i32 = 0;
4494/// `SORTIT_IGNORING_CASE` constant.
4495pub const SORTIT_IGNORING_CASE: i32 = 1;
4496/// `SORTIT_NUMERICALLY` constant.
4497pub const SORTIT_NUMERICALLY: i32 = 2;
4498/// `SORTIT_NUMERICALLY_SIGNED` constant.
4499pub const SORTIT_NUMERICALLY_SIGNED: i32 = 4;
4500/// `SORTIT_BACKWARDS` constant.
4501pub const SORTIT_BACKWARDS: i32 = 8;
4502/// `SORTIT_IGNORING_BACKSLASHES` constant.
4503pub const SORTIT_IGNORING_BACKSLASHES: i32 = 16;
4504/// `SORTIT_SOMEHOW` constant.
4505pub const SORTIT_SOMEHOW: i32 = 32;
4506
4507// =============================================================================
4508// 42. Case modify + Getkey (zsh.h:3122-3197).
4509// =============================================================================
4510/// `CASMOD_NONE` constant.
4511pub const CASMOD_NONE: i32 = 0;
4512/// `CASMOD_UPPER` constant.
4513pub const CASMOD_UPPER: i32 = 1;
4514/// `CASMOD_LOWER` constant.
4515pub const CASMOD_LOWER: i32 = 2;
4516/// `CASMOD_CAPS` constant.
4517pub const CASMOD_CAPS: i32 = 3;
4518/// `GETKEY_OCTAL_ESC` constant.
4519pub const GETKEY_OCTAL_ESC: i32 = 1 << 0;
4520/// `GETKEY_EMACS` constant.
4521pub const GETKEY_EMACS: i32 = 1 << 1;
4522/// `GETKEY_CTRL` constant.
4523pub const GETKEY_CTRL: i32 = 1 << 2;
4524/// `GETKEY_BACKSLASH_C` constant.
4525pub const GETKEY_BACKSLASH_C: i32 = 1 << 3;
4526/// `GETKEY_DOLLAR_QUOTE` constant.
4527pub const GETKEY_DOLLAR_QUOTE: i32 = 1 << 4;
4528/// `GETKEY_BACKSLASH_MINUS` constant.
4529pub const GETKEY_BACKSLASH_MINUS: i32 = 1 << 5;
4530/// `GETKEY_SINGLE_CHAR` constant.
4531pub const GETKEY_SINGLE_CHAR: i32 = 1 << 6;
4532/// `GETKEY_UPDATE_OFFSET` constant.
4533pub const GETKEY_UPDATE_OFFSET: i32 = 1 << 7;
4534/// `GETKEY_PRINTF_PERCENT` constant.
4535pub const GETKEY_PRINTF_PERCENT: i32 = 1 << 8;
4536/// `GETKEYS_ECHO` constant.
4537pub const GETKEYS_ECHO: i32 = GETKEY_BACKSLASH_C;
4538/// `GETKEYS_PRINTF_FMT` constant.
4539pub const GETKEYS_PRINTF_FMT: i32 = GETKEY_OCTAL_ESC | GETKEY_BACKSLASH_C | GETKEY_PRINTF_PERCENT;
4540/// `GETKEYS_PRINTF_ARG` constant.
4541pub const GETKEYS_PRINTF_ARG: i32 = GETKEY_BACKSLASH_C;
4542/// `GETKEYS_PRINT` constant.
4543pub const GETKEYS_PRINT: i32 = GETKEY_OCTAL_ESC | GETKEY_BACKSLASH_C | GETKEY_EMACS;
4544/// `GETKEYS_BINDKEY` constant.
4545pub const GETKEYS_BINDKEY: i32 = GETKEY_OCTAL_ESC | GETKEY_EMACS | GETKEY_CTRL;
4546/// `GETKEYS_DOLLARS_QUOTE` constant.
4547pub const GETKEYS_DOLLARS_QUOTE: i32 = GETKEY_OCTAL_ESC | GETKEY_EMACS | GETKEY_DOLLAR_QUOTE;
4548/// `GETKEYS_MATH` constant.
4549pub const GETKEYS_MATH: i32 = GETKEY_OCTAL_ESC | GETKEY_EMACS | GETKEY_CTRL | GETKEY_SINGLE_CHAR;
4550/// `GETKEYS_SEP` constant.
4551pub const GETKEYS_SEP: i32 = GETKEY_OCTAL_ESC | GETKEY_EMACS;
4552pub const GETKEYS_SUFFIX: i32 =
4553 GETKEY_OCTAL_ESC | GETKEY_EMACS | GETKEY_CTRL | GETKEY_BACKSLASH_MINUS;
4554
4555// =============================================================================
4556// 43. zle flags (zsh.h:3203-3216).
4557// =============================================================================
4558/// `ZLRF_HISTORY` constant.
4559pub const ZLRF_HISTORY: i32 = 0x01;
4560/// `ZLRF_NOSETTY` constant.
4561pub const ZLRF_NOSETTY: i32 = 0x02;
4562/// `ZLRF_IGNOREEOF` constant.
4563pub const ZLRF_IGNOREEOF: i32 = 0x04;
4564/// `ZLCON_LINE_START` constant.
4565pub const ZLCON_LINE_START: i32 = 0;
4566/// `ZLCON_LINE_CONT` constant.
4567pub const ZLCON_LINE_CONT: i32 = 1;
4568/// `ZLCON_SELECT` constant.
4569pub const ZLCON_SELECT: i32 = 2;
4570/// `ZLCON_VARED` constant.
4571pub const ZLCON_VARED: i32 = 3;
4572/// `ZLE_CMD_GET_LINE` constant.
4573pub const ZLE_CMD_GET_LINE: i32 = 0;
4574/// `ZLE_CMD_READ` constant.
4575pub const ZLE_CMD_READ: i32 = 1;
4576/// `ZLE_CMD_ADD_TO_LINE` constant.
4577pub const ZLE_CMD_ADD_TO_LINE: i32 = 2;
4578/// `ZLE_CMD_TRASH` constant.
4579pub const ZLE_CMD_TRASH: i32 = 3;
4580/// `ZLE_CMD_RESET_PROMPT` constant.
4581pub const ZLE_CMD_RESET_PROMPT: i32 = 4;
4582/// `ZLE_CMD_REFRESH` constant.
4583pub const ZLE_CMD_REFRESH: i32 = 5;
4584/// `ZLE_CMD_SET_KEYMAP` constant.
4585pub const ZLE_CMD_SET_KEYMAP: i32 = 6;
4586/// `ZLE_CMD_GET_KEY` constant.
4587pub const ZLE_CMD_GET_KEY: i32 = 7;
4588/// `ZLE_CMD_SET_HIST_LINE` constant.
4589pub const ZLE_CMD_SET_HIST_LINE: i32 = 8;
4590/// `ZLE_CMD_PREEXEC` constant.
4591pub const ZLE_CMD_PREEXEC: i32 = 9;
4592/// `ZLE_CMD_POSTEXEC` constant.
4593pub const ZLE_CMD_POSTEXEC: i32 = 10;
4594/// `ZLE_CMD_CHPWD` constant.
4595pub const ZLE_CMD_CHPWD: i32 = 11;
4596
4597// =============================================================================
4598// 44. zexit + nice format (zsh.h:3252-3268).
4599// =============================================================================
4600/// `ZEXIT_NORMAL` constant.
4601pub const ZEXIT_NORMAL: i32 = 0;
4602/// `ZEXIT_SIGNAL` constant.
4603pub const ZEXIT_SIGNAL: i32 = 1;
4604/// `ZEXIT_DEFERRED` constant.
4605pub const ZEXIT_DEFERRED: i32 = 2;
4606/// `NICEFLAG_HEAP` constant.
4607pub const NICEFLAG_HEAP: i32 = 1;
4608/// `NICEFLAG_QUOTE` constant.
4609pub const NICEFLAG_QUOTE: i32 = 2;
4610/// `NICEFLAG_NODUP` constant.
4611pub const NICEFLAG_NODUP: i32 = 4;
4612
4613// =============================================================================
4614// 45. Multibyte macros (zsh.h:3271-3375).
4615// =============================================================================
4616/// `convchar_t` type alias.
4617pub type convchar_t = u32; // c:3276/3357
4618/// `MB_INCOMPLETE` constant.
4619pub const MB_INCOMPLETE: usize = usize::MAX - 1; // c:3313
4620/// `MB_INVALID` constant.
4621pub const MB_INVALID: usize = usize::MAX; // c:3314
4622/// `MB_CUR_MAX` constant.
4623pub const MB_CUR_MAX: usize = 6; // c:3324
4624
4625/// Port of `MB_METACHARINIT()` from `Src/zsh.h:3275/3356`. C calls
4626/// `mb_charinit()` to reset multibyte state. Rust char iteration is
4627/// stateless; no-op.
4628#[inline]
4629#[allow(non_snake_case)]
4630pub fn MB_METACHARINIT() {} // c:3275
4631
4632/// Port of `MB_METACHARLEN(str)` from `Src/zsh.h:3278/3359`. Returns
4633/// the byte length of the next metafied character. C: `*str == Meta
4634/// ? 2 : 1` (non-multibyte); `mb_metacharlenconv(str, NULL)`
4635/// (multibyte). Rust returns the same byte length.
4636#[inline]
4637#[allow(non_snake_case)]
4638pub fn MB_METACHARLEN(s: &[u8]) -> usize {
4639 // c:3278/3359
4640 if s.is_empty() {
4641 0
4642 } else if s[0] == Meta {
4643 2
4644 } else {
4645 1
4646 }
4647}
4648
4649/// Port of `MB_METACHARLENCONV(str, cp)` from `Src/zsh.h:3277/3358`.
4650/// Returns byte length + (optionally) the converted char. Rust port
4651/// returns `(byte_len, Option<char>)`.
4652#[inline]
4653#[allow(non_snake_case)]
4654pub fn MB_METACHARLENCONV(s: &[u8]) -> (usize, Option<char>) {
4655 // c:3277
4656 if s.is_empty() {
4657 return (0, None);
4658 }
4659 if s[0] == Meta && s.len() >= 2 {
4660 let unmeta = s[1] ^ 0x20;
4661 (2, Some(unmeta as char))
4662 } else {
4663 (1, Some(s[0] as char))
4664 }
4665}
4666
4667/// Port of `MB_METASTRLEN(str)` from `Src/zsh.h:3279/3360`. Counts
4668/// metafied characters in the string.
4669#[inline]
4670#[allow(non_snake_case)]
4671pub fn MB_METASTRLEN(s: &str) -> usize {
4672 // c:3279
4673 let mut n = 0;
4674 let mut i = 0;
4675 let bytes = s.as_bytes();
4676 while i < bytes.len() {
4677 if bytes[i] == Meta && i + 1 < bytes.len() {
4678 i += 2;
4679 } else {
4680 i += 1;
4681 }
4682 n += 1;
4683 }
4684 n
4685}
4686
4687/// Port of `MB_METASTRWIDTH(str)` from `Src/zsh.h:3280/3361`. Counts
4688/// display width. In non-multibyte mode this is the same as
4689/// `MB_METASTRLEN`; in multibyte mode it accounts for wide chars.
4690#[inline]
4691#[allow(non_snake_case)]
4692pub fn MB_METASTRWIDTH(s: &str) -> usize {
4693 // c:3280
4694 MB_METASTRLEN(s)
4695}
4696
4697/// Port of `MB_METASTRLEN2(str, widthp)` from `Src/zsh.h:3281/3362`.
4698/// Variant that returns either char count or width depending on
4699/// `widthp`.
4700#[inline]
4701#[allow(non_snake_case)]
4702pub fn MB_METASTRLEN2(s: &str, widthp: bool) -> usize {
4703 // c:3281
4704 if widthp {
4705 MB_METASTRWIDTH(s)
4706 } else {
4707 MB_METASTRLEN(s)
4708 }
4709}
4710
4711/// Port of `MB_CHARINIT()` from `Src/zsh.h:3286/3365`. No-op
4712/// counterpart of `MB_METACHARINIT` for unmetafied input.
4713#[inline]
4714#[allow(non_snake_case)]
4715pub fn MB_CHARINIT() {} // c:3286
4716
4717/// Port of `MB_CHARLEN(str, len)` from `Src/zsh.h:3288/3367`. Byte
4718/// length of the next char in an unmetafied byte string.
4719#[inline]
4720#[allow(non_snake_case)]
4721pub fn MB_CHARLEN(s: &[u8], len: usize) -> usize {
4722 // c:3288
4723 if len == 0 || s.is_empty() {
4724 0
4725 } else {
4726 1
4727 }
4728}
4729
4730/// Port of `MB_CHARLENCONV(str, len, cp)` from `Src/zsh.h:3287/3366`.
4731/// Byte length + converted char of the next char in an unmetafied
4732/// byte string.
4733#[inline]
4734#[allow(non_snake_case)]
4735pub fn MB_CHARLENCONV(s: &[u8], len: usize) -> (usize, Option<char>) {
4736 // c:3287
4737 if len == 0 || s.is_empty() {
4738 (0, None)
4739 } else {
4740 (1, Some(s[0] as char))
4741 }
4742}
4743
4744/// Port of `WCWIDTH(wc)` from `Src/zsh.h:3300`. Display width of a
4745/// wide character: 0 for combining marks / control chars, 2 for
4746/// CJK-wide / emoji, 1 otherwise.
4747///
4748/// Delegates to the `unicode-width` crate (the same data path
4749/// `crate::ported::compat::u9_wcwidth` uses) so combining-mark
4750/// detection comes from the latest UCD. The previous inline
4751/// CJK-only rule returned 1 for combining marks (e.g. U+0301
4752/// combining-acute), which broke `IS_COMBINING(wc)` =
4753/// `WCWIDTH(wc) == 0` and silently disabled every cluster-walk
4754/// codepath that depended on it (alignmultiwordleft / right,
4755/// inccs / deccs realign).
4756#[inline]
4757#[allow(non_snake_case)]
4758pub fn WCWIDTH(wc: char) -> i32 {
4759 // c:3300 — `#define WCWIDTH(wc) wcwidth(wc)`: control chars are -1
4760 // per wcwidth(3), NOT 0. The previous 0 fallback made
4761 // IS_COMBINING('\n') true (c:3343 gates on `WCWIDTH(wc) == 0`), so
4762 // the refresh build's combining-cluster absorption swallowed hard
4763 // newlines into the preceding char's cluster — a multiline BUFFER
4764 // flattened to ONE video row, nextline never ran, and every later
4765 // frame painted anchored rows below where VLN said (zsh-expand's
4766 // multiline `i ` snippet scrambled the display on each keystroke).
4767 unicode_width::UnicodeWidthChar::width(wc)
4768 .map(|w| w as i32)
4769 .unwrap_or_else(|| if wc.is_control() { -1 } else { 1 })
4770}
4771
4772/// Port of `WCWIDTH_WINT(wc)` from `Src/zsh.h:3311/3369`. Always
4773/// 1 in non-multibyte mode; uses WCWIDTH in multibyte mode.
4774#[inline]
4775#[allow(non_snake_case)]
4776pub fn WCWIDTH_WINT(wc: char) -> i32 {
4777 // c:3311
4778 WCWIDTH(wc)
4779}
4780
4781/// Port of `IS_COMBINING(wc)` from `Src/zsh.h:3343`. True iff `wc`
4782/// is a non-zero combining character (zero display width).
4783#[inline]
4784#[allow(non_snake_case)]
4785pub fn IS_COMBINING(wc: char) -> bool {
4786 // c:3343
4787 wc as u32 != 0 && WCWIDTH(wc) == 0
4788}
4789
4790/// Port of `IS_BASECHAR(wc)` from `Src/zsh.h:3352`. True iff `wc`
4791/// is a graphic character with non-zero width (suitable as base for
4792/// a combining character).
4793#[inline]
4794#[allow(non_snake_case)]
4795pub fn IS_BASECHAR(wc: char) -> bool {
4796 // c:3352
4797 !wc.is_whitespace() && !wc.is_control() && WCWIDTH(wc) > 0
4798}
4799
4800/// Port of `ZWC(c)` from `Src/zsh.h:3328/3372`. C casts a char
4801/// literal to `wchar_t` via the `L` prefix (`L'a'`). Rust's `char`
4802/// is already 32-bit Unicode; the cast is a no-op.
4803#[inline]
4804#[allow(non_snake_case)]
4805pub const fn ZWC(c: char) -> char {
4806 c
4807} // c:3328
4808
4809// =============================================================================
4810// 46. Options accessor compat (already-allowed alias for OPT_*).
4811// =============================================================================
4812
4813/// Port of `OPT_ARG(ops, c)` from `Src/zsh.h:1412` —
4814/// `((ops)->args[((ops)->ind[c] >> 2) - 1])`. Returns the argument
4815/// associated with option `c`. Caller must have already checked
4816/// `OPT_HASARG(ops,c)`; out-of-range indices yield `None` (C would
4817/// dereference past `args[]`, which is undefined — Rust port stays
4818/// safe).
4819#[inline]
4820#[allow(non_snake_case)]
4821pub fn OPT_ARG<'a>(ops: &'a options, c: u8) -> Option<&'a str> {
4822 let idx = (ops.ind[c as usize] >> 2) as usize;
4823 if idx == 0 {
4824 return None;
4825 }
4826 ops.args.get(idx - 1).map(|s| s.as_str())
4827}
4828
4829/// Port of `OPT_ARG_SAFE(ops, c)` from `Src/zsh.h:1414` —
4830/// `(OPT_HASARG(ops,c) ? OPT_ARG(ops,c) : NULL)`.
4831#[inline]
4832#[allow(non_snake_case)]
4833pub fn OPT_ARG_SAFE<'a>(ops: &'a options, c: u8) -> Option<&'a str> {
4834 if OPT_HASARG(ops, c) {
4835 OPT_ARG(ops, c)
4836 } else {
4837 None
4838 }
4839}
4840
4841// Suppress dead-code warnings for the AtomicI32 we don't use yet.
4842#[allow(dead_code)]
4843const _MARKER_KEEP: AtomicI32 = AtomicI32::new(0);
4844
4845#[cfg(test)]
4846mod tests {
4847 use super::*;
4848
4849 #[test]
4850 fn zlong_zulong_sizes() {
4851 let _g = crate::test_util::global_state_lock();
4852 assert_eq!(std::mem::size_of::<zlong>(), 8);
4853 assert_eq!(std::mem::size_of::<zulong>(), 8);
4854 }
4855
4856 #[test]
4857 fn meta_byte_value() {
4858 let _g = crate::test_util::global_state_lock();
4859 assert_eq!(Meta as u32, 0x83);
4860 }
4861
4862 #[test]
4863 fn parser_tokens_correct() {
4864 let _g = crate::test_util::global_state_lock();
4865 assert_eq!(Pound as u32, 0x84);
4866 assert_eq!(Bang as u32, 0x9c);
4867 assert_eq!(Snull as u32, 0x9d);
4868 assert_eq!(Dnull as u32, 0x9e);
4869 assert_eq!(Bnull as u32, 0x9f);
4870 assert_eq!(Bnullkeep as u32, 0xa0);
4871 assert_eq!(Nularg as u32, 0xa1);
4872 assert_eq!(Marker as u32, 0xa2);
4873 }
4874
4875 #[test]
4876 fn pm_type_isolates_type_bits() {
4877 let _g = crate::test_util::global_state_lock();
4878 assert_eq!(PM_TYPE(PM_INTEGER | PM_EXPORTED), PM_INTEGER);
4879 assert_eq!(PM_TYPE(PM_ARRAY | PM_READONLY), PM_ARRAY);
4880 }
4881
4882 #[test]
4883 fn opt_isset_basic() {
4884 let _g = crate::test_util::global_state_lock();
4885 let mut ops = options {
4886 ind: [0u8; MAX_OPS],
4887 args: Vec::new(),
4888 argscount: 0,
4889 argsalloc: 0,
4890 };
4891 ops.ind[b'l' as usize] = 1; // OPT_MINUS bit
4892 assert!(OPT_ISSET(&ops, b'l'));
4893 assert!(OPT_MINUS(&ops, b'l'));
4894 assert!(!OPT_PLUS(&ops, b'l'));
4895 assert!(!OPT_ISSET(&ops, b'r'));
4896 }
4897
4898 #[test]
4899 fn binf_constants_correct() {
4900 let _g = crate::test_util::global_state_lock();
4901 assert_eq!(BINF_PREFIX, 1 << 5);
4902 assert_eq!(BINF_ASSIGN, 1 << 19);
4903 }
4904
4905 #[test]
4906 fn cond_constants_correct() {
4907 let _g = crate::test_util::global_state_lock();
4908 assert_eq!(COND_NOT, 0);
4909 assert_eq!(COND_MODI, 19);
4910 }
4911
4912 #[test]
4913 fn fdt_constants_correct() {
4914 let _g = crate::test_util::global_state_lock();
4915 assert_eq!(FDT_UNUSED, 0);
4916 assert_eq!(FDT_PROC_SUBST, 7);
4917 assert_eq!(FDT_TYPE_MASK, 15);
4918 }
4919
4920 #[test]
4921 fn redir_iswrite_classification() {
4922 let _g = crate::test_util::global_state_lock();
4923 assert!(IS_WRITE_FILE(REDIR_WRITE));
4924 assert!(IS_WRITE_FILE(REDIR_READWRITE));
4925 assert!(!IS_WRITE_FILE(REDIR_READ));
4926 assert!(IS_ERROR_REDIR(REDIR_ERRWRITE));
4927 assert!(IS_ERROR_REDIR(REDIR_ERRAPPNOW));
4928 assert!(!IS_ERROR_REDIR(REDIR_WRITE));
4929 }
4930
4931 #[test]
4932 fn wc_macros_round_trip() {
4933 let _g = crate::test_util::global_state_lock();
4934 let w = wc_bld(WC_LIST, 42);
4935 assert_eq!(wc_code(w), WC_LIST);
4936 assert_eq!(wc_data(w), 42);
4937 }
4938
4939 #[test]
4940 fn mb_metastrlen_counts_meta_pairs() {
4941 let _g = crate::test_util::global_state_lock();
4942 assert_eq!(MB_METASTRLEN("abc"), 3);
4943 // META is char 0x83, but in UTF-8 it encodes as 2 bytes
4944 // (0xC2 0x83). The byte-level metafied counter walks the
4945 // raw bytes; "abc" has 3 bytes → 3. Just test ASCII here.
4946 assert_eq!(MB_METASTRLEN("hello"), 5);
4947 assert_eq!(MB_METASTRLEN(""), 0);
4948 }
4949
4950 #[test]
4951 fn mb_charlen_basic() {
4952 let _g = crate::test_util::global_state_lock();
4953 assert_eq!(MB_CHARLEN(b"abc", 3), 1);
4954 assert_eq!(MB_CHARLEN(b"", 0), 0);
4955 }
4956
4957 #[test]
4958 fn wcwidth_basic() {
4959 let _g = crate::test_util::global_state_lock();
4960 assert_eq!(WCWIDTH('a'), 1);
4961 // wcwidth(3): control chars are -1, NOT 0 — the old `0` pin
4962 // documented a divergence that made IS_COMBINING('\n') true
4963 // (refresh build swallowed hard newlines into combining
4964 // clusters, flattening multiline buffers to one video row).
4965 assert_eq!(WCWIDTH('\u{0007}'), -1); // BEL is control
4966 assert_eq!(WCWIDTH('\n'), -1); // newline is control
4967 assert!(!IS_COMBINING('\n'), "hard newline is never a combining mark");
4968 assert_eq!(WCWIDTH('\u{4E2D}'), 2); // CJK
4969 }
4970
4971 #[test]
4972 fn is_combining_zero_width() {
4973 let _g = crate::test_util::global_state_lock();
4974 assert!(!IS_COMBINING('a')); // width 1
4975 assert!(!IS_COMBINING('\u{0000}')); // null returns false per c:3343
4976 // Control chars are wcwidth -1 per wcwidth(3), so IS_COMBINING
4977 // (`WCWIDTH(wc) == 0`, c:3343) is FALSE for them — the old pin
4978 // asserted the width-0 divergence that made the refresh build
4979 // absorb '\n'/BEL into combining clusters.
4980 assert!(!IS_COMBINING('\u{0007}'));
4981 // Real combining mark (unicode-width table): width 0 → true.
4982 assert!(IS_COMBINING('\u{0301}'));
4983 }
4984
4985 #[test]
4986 fn pat_flags_correct() {
4987 let _g = crate::test_util::global_state_lock();
4988 assert_eq!(PAT_FILE, 0x0001);
4989 assert_eq!(PAT_LCMATCHUC, 0x1000);
4990 }
4991
4992 #[test]
4993 fn sub_flags_correct() {
4994 let _g = crate::test_util::global_state_lock();
4995 assert_eq!(SUB_END, 0x0001);
4996 assert_eq!(SUB_EGLOB, 0x4000);
4997 }
4998
4999 #[test]
5000 fn pp_constants_ordered() {
5001 let _g = crate::test_util::global_state_lock();
5002 assert_eq!(PP_FIRST, PP_ALPHA);
5003 assert!(PP_LAST >= PP_ALPHA);
5004 assert!(PP_RANGE > PP_LAST);
5005 }
5006
5007 #[test]
5008 fn typeset_optstr_constants() {
5009 let _g = crate::test_util::global_state_lock();
5010 assert_eq!(TYPESET_OPTSTR, "aiEFALRZlurtxUhHT");
5011 assert_eq!(TYPESET_OPTNUM, "LRZiEF");
5012 }
5013
5014 #[test]
5015 fn job_stat_flags_distinct() {
5016 let _g = crate::test_util::global_state_lock();
5017 let all = STAT_CHANGED
5018 | STAT_STOPPED
5019 | STAT_TIMED
5020 | STAT_DONE
5021 | STAT_LOCKED
5022 | STAT_NOPRINT
5023 | STAT_INUSE
5024 | STAT_SUPERJOB
5025 | STAT_SUBJOB
5026 | STAT_WASSUPER
5027 | STAT_CURSH
5028 | STAT_NOSTTY
5029 | STAT_ATTACH
5030 | STAT_SUBLEADER
5031 | STAT_BUILTIN
5032 | STAT_SUBJOB_ORPHANED
5033 | STAT_DISOWN;
5034 assert_eq!(all.count_ones(), 17);
5035 }
5036
5037 #[test]
5038 fn opt_size_at_186() {
5039 let _g = crate::test_util::global_state_lock();
5040 assert_eq!(OPT_SIZE, 186);
5041 }
5042
5043 #[test]
5044 fn cs_count_is_32() {
5045 let _g = crate::test_util::global_state_lock();
5046 assert_eq!(CS_COUNT, 32);
5047 }
5048
5049 #[test]
5050 fn zwc_passes_through() {
5051 let _g = crate::test_util::global_state_lock();
5052 assert_eq!(ZWC('a'), 'a');
5053 }
5054
5055 /// `IS_DASH` matches both ASCII '-' (0x2D) and the tokenized
5056 /// Dash marker (0x9B) the lexer emits inside `[[ ... ]]`. Both
5057 /// must be recognised — regression that drops one would break
5058 /// either user-typed input OR pre-lexed cond expressions.
5059 #[test]
5060 fn is_dash_recognises_both_ascii_and_lexed_token() {
5061 let _g = crate::test_util::global_state_lock();
5062 assert!(IS_DASH('-'), "ASCII '-' is dash");
5063 assert!(IS_DASH('\u{9b}'), "lexed Dash token is dash");
5064 assert!(!IS_DASH('+'), "non-dash chars must NOT match");
5065 assert!(!IS_DASH(' '), "space is not dash");
5066 }
5067
5068 /// c:1408 — `OPT_ISSET(ops, c)` returns true iff `ops.ind[c] != 0`.
5069 /// Catches a regression where the indexing returns NUL-byte
5070 /// "false" for a set option, breaking every `-x` flag check.
5071 #[test]
5072 fn opt_isset_reads_ind_array_directly() {
5073 let _g = crate::test_util::global_state_lock();
5074 let mut ops = options {
5075 ind: [0u8; MAX_OPS],
5076 args: Vec::new(),
5077 argscount: 0,
5078 argsalloc: 0,
5079 };
5080 assert!(!OPT_ISSET(&ops, b'x'));
5081 ops.ind[b'x' as usize] = 1;
5082 assert!(
5083 OPT_ISSET(&ops, b'x'),
5084 "after setting ind, OPT_ISSET must be true"
5085 );
5086 ops.ind[b'x' as usize] = 0;
5087 assert!(
5088 !OPT_ISSET(&ops, b'x'),
5089 "clearing ind must make OPT_ISSET false"
5090 );
5091 }
5092
5093 /// `PM_TYPE` masks just the type-bits of a flag word (PM_SCALAR /
5094 /// PM_INTEGER / PM_ARRAY / PM_HASHED / etc.). Modifier flags
5095 /// (PM_READONLY, PM_EXPORTED) MUST NOT leak through. A regression
5096 /// returning the full flag word would silently mis-dispatch every
5097 /// param introspection path.
5098 #[test]
5099 fn pm_type_strips_modifier_flags() {
5100 let _g = crate::test_util::global_state_lock();
5101 let with_mods = PM_INTEGER | PM_READONLY | PM_EXPORTED;
5102 assert_eq!(PM_TYPE(with_mods), PM_INTEGER);
5103 let just_array = PM_TYPE(PM_ARRAY | PM_LEFT | PM_TIED);
5104 assert_eq!(just_array, PM_ARRAY);
5105 }
5106
5107 /// `Src/zsh.h:1878-1944` — `PM_*` flag values are load-bearing.
5108 /// Pin EVERY parameter-mode flag against the canonical C define.
5109 /// If any value drifts, serialised param state (typeset, export,
5110 /// hash dumps) corrupts on the next read.
5111 #[test]
5112 fn pm_flags_match_c_zsh_h_canonical_values() {
5113 let _g = crate::test_util::global_state_lock();
5114 assert_eq!(PM_SCALAR, 0, "c:1878");
5115 assert_eq!(PM_ARRAY, 1 << 0, "c:1879");
5116 assert_eq!(PM_INTEGER, 1 << 1, "c:1880");
5117 assert_eq!(PM_EFLOAT, 1 << 2, "c:1881");
5118 assert_eq!(PM_FFLOAT, 1 << 3, "c:1882");
5119 assert_eq!(PM_HASHED, 1 << 4, "c:1883");
5120 assert_eq!(PM_LEFT, 1 << 5, "c:1888");
5121 assert_eq!(PM_RIGHT_B, 1 << 6, "c:1889");
5122 assert_eq!(PM_RIGHT_Z, 1 << 7, "c:1890");
5123 assert_eq!(PM_LOWER, 1 << 8, "c:1891");
5124 assert_eq!(PM_UPPER, 1 << 9, "c:1895");
5125 assert_eq!(PM_UNDEFINED, 1 << 9, "c:1896 (aliases PM_UPPER for funcs)");
5126 assert_eq!(PM_READONLY, 1 << 10, "c:1898");
5127 assert_eq!(PM_TAGGED, 1 << 11, "c:1899");
5128 assert_eq!(PM_EXPORTED, 1 << 12, "c:1900");
5129 assert_eq!(
5130 PM_ABSPATH_USED,
5131 1 << 12,
5132 "c:1901 (aliases EXPORTED for funcs)"
5133 );
5134 assert_eq!(PM_UNIQUE, 1 << 13, "c:1905");
5135 assert_eq!(PM_HIDE, 1 << 14, "c:1908");
5136 assert_eq!(PM_HIDEVAL, 1 << 15, "c:1910");
5137 assert_eq!(PM_TIED, 1 << 16, "c:1912");
5138 assert_eq!(PM_SPECIAL, 1 << 20, "c:1922");
5139 assert_eq!(PM_RO_BY_DESIGN, 1 << 21, "c:1924");
5140 assert_eq!(PM_LOCAL, 1 << 19, "c:1920");
5141 assert_eq!(PM_UNSET, 1 << 24, "c:1930");
5142 assert_eq!(PM_NAMEREF, 1 << 30, "c:1944");
5143 }
5144
5145 /// `Src/zsh.h:1953-1965` — `SCANPM_*` flag values for parameter
5146 /// scanning. Used by `${(k)hash}` / `${(K)hash}` / `${(m)hash}`
5147 /// expansion paths. Drift here mis-routes every hash scan.
5148 #[test]
5149 fn scanpm_flags_match_c_zsh_h_canonical_values() {
5150 let _g = crate::test_util::global_state_lock();
5151 assert_eq!(SCANPM_WANTVALS, 1 << 0, "c:1953");
5152 assert_eq!(SCANPM_WANTKEYS, 1 << 1, "c:1954");
5153 assert_eq!(SCANPM_WANTINDEX, 1 << 2, "c:1955");
5154 assert_eq!(SCANPM_MATCHKEY, 1 << 3, "c:1956");
5155 assert_eq!(SCANPM_MATCHVAL, 1 << 4, "c:1957");
5156 assert_eq!(SCANPM_MATCHMANY, 1 << 5, "c:1958");
5157 assert_eq!(SCANPM_ASSIGNING, 1 << 6, "c:1959");
5158 assert_eq!(SCANPM_KEYMATCH, 1 << 7, "c:1960");
5159 assert_eq!(SCANPM_DQUOTED, 1 << 8, "c:1961");
5160 assert_eq!(SCANPM_ARRONLY, 1 << 9, "c:1965");
5161 }
5162
5163 /// `Src/zsh.h:144-224` — parser token byte values. These are
5164 /// **load-bearing single-byte sentinels** for every lex/parse
5165 /// path (Pound for `#` comments, Star for `*` glob, Stringg for
5166 /// `$param`, etc.). A drift on any byte would silently mis-route
5167 /// every parsed token.
5168 #[test]
5169 fn token_byte_values_match_c_zsh_h() {
5170 let _g = crate::test_util::global_state_lock();
5171 assert_eq!(Meta, 0x83, "c:144");
5172 assert_eq!(Pound, '\u{84}', "c:159");
5173 assert_eq!(Stringg, '\u{85}', "c:160");
5174 assert_eq!(Hat, '\u{86}', "c:161");
5175 assert_eq!(Star, '\u{87}', "c:162");
5176 assert_eq!(Inpar, '\u{88}', "c:163");
5177 assert_eq!(Inparmath, '\u{89}', "c:164");
5178 assert_eq!(Outpar, '\u{8a}', "c:165");
5179 assert_eq!(Outparmath, '\u{8b}', "c:166");
5180 assert_eq!(Qstring, '\u{8c}', "c:167");
5181 assert_eq!(Equals, '\u{8d}', "c:168");
5182 assert_eq!(Bar, '\u{8e}', "c:169");
5183 assert_eq!(Inbrace, '\u{8f}', "c:170");
5184 assert_eq!(Outbrace, '\u{90}', "c:171");
5185 assert_eq!(Inbrack, '\u{91}', "c:172");
5186 assert_eq!(Outbrack, '\u{92}', "c:173");
5187 assert_eq!(Tick, '\u{93}', "c:174");
5188 assert_eq!(Inang, '\u{94}', "c:175");
5189 assert_eq!(Outang, '\u{95}', "c:176");
5190 assert_eq!(OutangProc, '\u{96}', "c:177");
5191 assert_eq!(Quest, '\u{97}', "c:178");
5192 assert_eq!(Tilde, '\u{98}', "c:179");
5193 assert_eq!(Qtick, '\u{99}', "c:180");
5194 assert_eq!(Comma, '\u{9a}', "c:181");
5195 assert_eq!(Dash, '\u{9b}', "c:182");
5196 assert_eq!(Bang, '\u{9c}', "c:183");
5197 assert_eq!(LAST_NORMAL_TOK, Bang, "c:188 == Bang");
5198 assert_eq!(Snull, '\u{9d}', "c:193");
5199 assert_eq!(Dnull, '\u{9e}', "c:194");
5200 assert_eq!(Bnull, '\u{9f}', "c:195");
5201 assert_eq!(Bnullkeep, '\u{a0}', "c:200");
5202 assert_eq!(Nularg, '\u{a1}', "c:206");
5203 assert_eq!(Marker, '\u{a2}', "c:224");
5204 }
5205
5206 /// `Src/zsh.h:226-232` — SPECCHARS / PATCHARS string literals.
5207 /// Pin the exact 25-char SPECCHARS set and 13-char PATCHARS set
5208 /// against the canonical C define. Drift on either would silently
5209 /// change which chars trigger quoting / pattern matching.
5210 #[test]
5211 fn specchars_patchars_match_c_zsh_h() {
5212 let _g = crate::test_util::global_state_lock();
5213 // c:228 — `SPECCHARS "#$^*()=|{}[]`<>?~;&\n\t \\\'\""`.
5214 assert_eq!(
5215 SPECCHARS, "#$^*()=|{}[]`<>?~;&\n\t \\\'\"",
5216 "c:228 — SPECCHARS literal must match C verbatim"
5217 );
5218 assert_eq!(
5219 SPECCHARS.chars().count(),
5220 25,
5221 "c:228 — SPECCHARS has 25 chars"
5222 );
5223 // c:232 — `PATCHARS "#^*()|[]<>?~\\"`.
5224 assert_eq!(
5225 PATCHARS, "#^*()|[]<>?~\\",
5226 "c:232 — PATCHARS literal must match C verbatim"
5227 );
5228 assert_eq!(
5229 PATCHARS.chars().count(),
5230 13,
5231 "c:232 — PATCHARS has 13 chars"
5232 );
5233 }
5234
5235 /// `Src/zsh.h:149-153` — DEFAULT_IFS and DEFAULT_IFS_SH literals.
5236 #[test]
5237 fn default_ifs_strings_match_c_zsh_h() {
5238 let _g = crate::test_util::global_state_lock();
5239 // c:149 — `DEFAULT_IFS " \t\n\203 "` (5 chars; \203 is Meta).
5240 assert_eq!(
5241 DEFAULT_IFS, " \t\n\u{83} ",
5242 "c:149 — DEFAULT_IFS = space + tab + newline + Meta + space"
5243 );
5244 assert_eq!(
5245 DEFAULT_IFS.chars().count(),
5246 5,
5247 "c:149 — DEFAULT_IFS is 5 chars"
5248 );
5249 // c:153 — `DEFAULT_IFS_SH " \t\n"` (3 chars, POSIX sh).
5250 assert_eq!(
5251 DEFAULT_IFS_SH, " \t\n",
5252 "c:153 — DEFAULT_IFS_SH = POSIX 3-char set"
5253 );
5254 }
5255
5256 /// `Src/zsh.h:1879-1883` — `PM_TYPE_MASK` covers the 5 type bits
5257 /// (PM_ARRAY..PM_HASHED). Every non-type flag must be OUTSIDE
5258 /// this mask. Pin so a regression that bleeds modifier flags
5259 /// into the type space fails.
5260 #[test]
5261 fn pm_type_mask_excludes_modifier_flags() {
5262 let _g = crate::test_util::global_state_lock();
5263 let type_mask = PM_ARRAY | PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_HASHED;
5264 // Modifier flags MUST be outside the type-mask range.
5265 for modifier in &[
5266 PM_LEFT,
5267 PM_RIGHT_B,
5268 PM_RIGHT_Z,
5269 PM_LOWER,
5270 PM_UPPER,
5271 PM_READONLY,
5272 PM_EXPORTED,
5273 PM_LOCAL,
5274 PM_UNSET,
5275 ] {
5276 assert_eq!(
5277 modifier & type_mask,
5278 0,
5279 "modifier flag 0x{:x} must NOT overlap type mask 0x{:x}",
5280 modifier,
5281 type_mask
5282 );
5283 }
5284 }
5285
5286 /// `Src/zsh.h` IS_WRITE_FILE — `X >= REDIR_WRITE && X <= REDIR_READWRITE`
5287 /// (0..=8). Comprehensive sweep: every redir-type ID 0..=17 plus
5288 /// boundaries. A regression that flips the comparison would break
5289 /// every `>file` / `>>file` / `1>file` redirection emit.
5290 #[test]
5291 fn is_write_file_sweep_all_redir_types() {
5292 let _g = crate::test_util::global_state_lock();
5293 // c:298-299 — write-file family: 0..=8 inclusive.
5294 for x in REDIR_WRITE..=REDIR_READWRITE {
5295 assert!(
5296 IS_WRITE_FILE(x),
5297 "redir-type {} ({}) must be IS_WRITE_FILE",
5298 x,
5299 x
5300 );
5301 }
5302 // Outside the range — NOT write-file.
5303 for x in [
5304 REDIR_READ,
5305 REDIR_HEREDOC,
5306 REDIR_HEREDOCDASH,
5307 REDIR_HERESTR,
5308 REDIR_MERGEIN,
5309 REDIR_MERGEOUT,
5310 REDIR_CLOSE,
5311 REDIR_INPIPE,
5312 REDIR_OUTPIPE,
5313 ] {
5314 assert!(
5315 !IS_WRITE_FILE(x),
5316 "redir-type {} must NOT be IS_WRITE_FILE",
5317 x
5318 );
5319 }
5320 }
5321
5322 /// `Src/zsh.h` IS_APPEND_REDIR — `IS_WRITE_FILE && (X & 2)`. Bit 1
5323 /// distinguishes write (0/1/4/5) from append (2/3/6/7). Pin every
5324 /// boundary so a regression that masks the wrong bit silently
5325 /// dispatches `>file` as `>>file`.
5326 #[test]
5327 fn is_append_redir_pins_bit_1() {
5328 let _g = crate::test_util::global_state_lock();
5329 // c:303-304 — true ONLY for 2/3/6/7 in the write-file family.
5330 assert!(IS_APPEND_REDIR(REDIR_APP), "REDIR_APP=2 is append");
5331 assert!(IS_APPEND_REDIR(REDIR_APPNOW), "REDIR_APPNOW=3 is append");
5332 assert!(IS_APPEND_REDIR(REDIR_ERRAPP), "REDIR_ERRAPP=6 is append");
5333 assert!(
5334 IS_APPEND_REDIR(REDIR_ERRAPPNOW),
5335 "REDIR_ERRAPPNOW=7 is append"
5336 );
5337 // NOT append.
5338 assert!(!IS_APPEND_REDIR(REDIR_WRITE), "REDIR_WRITE=0 is not append");
5339 assert!(
5340 !IS_APPEND_REDIR(REDIR_WRITENOW),
5341 "REDIR_WRITENOW=1 is not append"
5342 );
5343 assert!(
5344 !IS_APPEND_REDIR(REDIR_ERRWRITE),
5345 "REDIR_ERRWRITE=4 is not append"
5346 );
5347 assert!(
5348 !IS_APPEND_REDIR(REDIR_ERRWRITENOW),
5349 "REDIR_ERRWRITENOW=5 is not append"
5350 );
5351 // Outside the write-file family — never append.
5352 assert!(
5353 !IS_APPEND_REDIR(REDIR_READ),
5354 "REDIR_READ=9 is not write-file"
5355 );
5356 }
5357
5358 /// `Src/zsh.h` IS_CLOBBER_REDIR — `IS_WRITE_FILE && (X & 1)`. Bit 0
5359 /// is the `NOW` suffix (>! / >>!) that bypasses NO_CLOBBER. Pin
5360 /// boundary so a regression mis-flagging clobber would break user
5361 /// scripts that rely on NO_CLOBBER semantics.
5362 #[test]
5363 fn is_clobber_redir_pins_bit_0() {
5364 let _g = crate::test_util::global_state_lock();
5365 // c:308-309 — true ONLY for 1/3/5/7 in the write-file family.
5366 assert!(
5367 IS_CLOBBER_REDIR(REDIR_WRITENOW),
5368 "REDIR_WRITENOW=1 is clobber"
5369 );
5370 assert!(IS_CLOBBER_REDIR(REDIR_APPNOW), "REDIR_APPNOW=3 is clobber");
5371 assert!(
5372 IS_CLOBBER_REDIR(REDIR_ERRWRITENOW),
5373 "REDIR_ERRWRITENOW=5 is clobber"
5374 );
5375 assert!(
5376 IS_CLOBBER_REDIR(REDIR_ERRAPPNOW),
5377 "REDIR_ERRAPPNOW=7 is clobber"
5378 );
5379 // NOT clobber.
5380 assert!(!IS_CLOBBER_REDIR(REDIR_WRITE));
5381 assert!(!IS_CLOBBER_REDIR(REDIR_APP));
5382 assert!(!IS_CLOBBER_REDIR(REDIR_ERRWRITE));
5383 assert!(!IS_CLOBBER_REDIR(REDIR_ERRAPP));
5384 }
5385
5386 /// `Src/zsh.h` IS_ERROR_REDIR — `X >= REDIR_ERRWRITE && X <=
5387 /// REDIR_ERRAPPNOW` (4..=7). Pin both boundaries — a regression
5388 /// flipping `<=` to `<` would silently exclude REDIR_ERRAPPNOW.
5389 #[test]
5390 fn is_error_redir_inclusive_range() {
5391 let _g = crate::test_util::global_state_lock();
5392 // c:313-314 — true ONLY for 4..=7.
5393 for x in REDIR_ERRWRITE..=REDIR_ERRAPPNOW {
5394 assert!(IS_ERROR_REDIR(x), "redir-type {} must be IS_ERROR_REDIR", x);
5395 }
5396 // Outside — never error.
5397 for x in [
5398 REDIR_WRITE,
5399 REDIR_WRITENOW,
5400 REDIR_APP,
5401 REDIR_APPNOW,
5402 REDIR_READWRITE,
5403 REDIR_READ,
5404 REDIR_HEREDOC,
5405 REDIR_INPIPE,
5406 ] {
5407 assert!(
5408 !IS_ERROR_REDIR(x),
5409 "redir-type {} must NOT be IS_ERROR_REDIR",
5410 x
5411 );
5412 }
5413 }
5414
5415 /// `Src/zsh.h` IS_READFD — `(X >= REDIR_READWRITE && X <= REDIR_MERGEIN)
5416 /// || X == REDIR_INPIPE`. Read-fd family: 8..=13 OR 16. Pin so a
5417 /// regression that drops the OR INPIPE arm breaks process
5418 /// substitution `<(cmd)` redirections.
5419 #[test]
5420 fn is_readfd_range_plus_inpipe() {
5421 let _g = crate::test_util::global_state_lock();
5422 // c:318-319 — true for 8..=13 INCLUSIVE plus INPIPE=16.
5423 for x in REDIR_READWRITE..=REDIR_MERGEIN {
5424 assert!(IS_READFD(x), "redir-type {} must be IS_READFD", x);
5425 }
5426 assert!(
5427 IS_READFD(REDIR_INPIPE),
5428 "REDIR_INPIPE=16 must be IS_READFD (special-case OR arm)"
5429 );
5430 // Outside — not readfd.
5431 assert!(!IS_READFD(REDIR_WRITE));
5432 assert!(!IS_READFD(REDIR_MERGEOUT));
5433 assert!(!IS_READFD(REDIR_CLOSE));
5434 assert!(!IS_READFD(REDIR_OUTPIPE));
5435 }
5436
5437 /// `Src/zsh.h:273-290` — REDIR_* numeric values are load-bearing
5438 /// because IS_APPEND/IS_CLOBBER use bit-arithmetic on the values.
5439 /// Pin EVERY entry's exact value so a reorder silently flips the
5440 /// append-vs-write classification across the parser + executor.
5441 #[test]
5442 fn redir_constants_have_exact_canonical_values() {
5443 let _g = crate::test_util::global_state_lock();
5444 assert_eq!(REDIR_WRITE, 0);
5445 assert_eq!(REDIR_WRITENOW, 1);
5446 assert_eq!(REDIR_APP, 2);
5447 assert_eq!(REDIR_APPNOW, 3);
5448 assert_eq!(REDIR_ERRWRITE, 4);
5449 assert_eq!(REDIR_ERRWRITENOW, 5);
5450 assert_eq!(REDIR_ERRAPP, 6);
5451 assert_eq!(REDIR_ERRAPPNOW, 7);
5452 assert_eq!(REDIR_READWRITE, 8);
5453 assert_eq!(REDIR_READ, 9);
5454 assert_eq!(REDIR_HEREDOC, 10);
5455 assert_eq!(REDIR_HEREDOCDASH, 11);
5456 assert_eq!(REDIR_HERESTR, 12);
5457 assert_eq!(REDIR_MERGEIN, 13);
5458 assert_eq!(REDIR_MERGEOUT, 14);
5459 assert_eq!(REDIR_CLOSE, 15);
5460 assert_eq!(REDIR_INPIPE, 16);
5461 assert_eq!(REDIR_OUTPIPE, 17);
5462 }
5463
5464 /// `Src/zsh.h` REDIR_TYPE_MASK / REDIR_VARID_MASK /
5465 /// REDIR_FROM_HEREDOC_MASK — these encode redir flags in the
5466 /// wordcode redir entry. The type-mask MUST be 0x1f (5 bits) so
5467 /// it covers REDIR_OUTPIPE=17 (0x11) without overlapping the
5468 /// 0x20/0x40 flag bits.
5469 #[test]
5470 fn redir_masks_have_no_overlap() {
5471 let _g = crate::test_util::global_state_lock();
5472 assert_eq!(REDIR_TYPE_MASK, 0x1f);
5473 assert_eq!(REDIR_VARID_MASK, 0x20);
5474 assert_eq!(REDIR_FROM_HEREDOC_MASK, 0x40);
5475 // Masks must be pairwise disjoint.
5476 assert_eq!(REDIR_TYPE_MASK & REDIR_VARID_MASK, 0);
5477 assert_eq!(REDIR_TYPE_MASK & REDIR_FROM_HEREDOC_MASK, 0);
5478 assert_eq!(REDIR_VARID_MASK & REDIR_FROM_HEREDOC_MASK, 0);
5479 // Type-mask must cover the largest REDIR_* value (17 = 0x11).
5480 assert_eq!(
5481 REDIR_OUTPIPE & REDIR_TYPE_MASK,
5482 REDIR_OUTPIPE,
5483 "type-mask must include every REDIR_* up to OUTPIPE=17"
5484 );
5485 }
5486
5487 // ─── WCWIDTH / IS_COMBINING / IS_BASECHAR pin tests ──────────────
5488
5489 /// `WCWIDTH('a')` = 1 (basic ASCII single width).
5490 #[test]
5491 fn zshh_corpus_wcwidth_ascii_is_one() {
5492 assert_eq!(WCWIDTH('a'), 1);
5493 assert_eq!(WCWIDTH('Z'), 1);
5494 assert_eq!(WCWIDTH('0'), 1);
5495 assert_eq!(WCWIDTH(' '), 1);
5496 }
5497
5498 /// `WCWIDTH` on common CJK char is 2 (East Asian Wide).
5499 #[test]
5500 fn zshh_corpus_wcwidth_cjk_is_two() {
5501 // U+4E2D '中' (Chinese for middle) — wide.
5502 assert_eq!(WCWIDTH('中'), 2);
5503 // U+65E5 '日' (Japanese for day) — wide.
5504 assert_eq!(WCWIDTH('日'), 2);
5505 }
5506
5507 /// `WCWIDTH` on combining mark is 0.
5508 /// U+0301 = COMBINING ACUTE ACCENT.
5509 #[test]
5510 fn zshh_corpus_wcwidth_combining_is_zero() {
5511 assert_eq!(WCWIDTH('\u{0301}'), 0, "combining acute accent has width 0");
5512 }
5513
5514 /// `IS_COMBINING` true for combining accent codepoints.
5515 #[test]
5516 fn zshh_corpus_is_combining_true_for_accents() {
5517 assert!(IS_COMBINING('\u{0301}'), "U+0301 COMBINING ACUTE");
5518 assert!(IS_COMBINING('\u{0300}'), "U+0300 COMBINING GRAVE");
5519 }
5520
5521 /// `IS_COMBINING` false for normal ASCII letters.
5522 #[test]
5523 fn zshh_corpus_is_combining_false_for_ascii() {
5524 assert!(!IS_COMBINING('a'));
5525 assert!(!IS_COMBINING('Z'));
5526 assert!(!IS_COMBINING('0'));
5527 }
5528
5529 /// `IS_BASECHAR` true for ordinary printable chars.
5530 #[test]
5531 fn zshh_corpus_is_basechar_true_for_letters() {
5532 assert!(IS_BASECHAR('a'));
5533 assert!(IS_BASECHAR('A'));
5534 assert!(IS_BASECHAR('z'));
5535 assert!(IS_BASECHAR('日'));
5536 }
5537
5538 /// `IS_BASECHAR` false for combining marks.
5539 #[test]
5540 fn zshh_corpus_is_basechar_false_for_combining() {
5541 assert!(
5542 !IS_BASECHAR('\u{0301}'),
5543 "combining accent is not a base char"
5544 );
5545 }
5546
5547 /// Pound (lex marker) is in the imeta range 0x83..=0xa2.
5548 #[test]
5549 fn zshh_corpus_pound_marker_in_imeta_range() {
5550 let p = Pound as u32;
5551 assert!(
5552 p >= 0x83 && p <= 0xa2,
5553 "Pound = {:#x} must be in imeta range 0x83..=0xa2",
5554 p
5555 );
5556 }
5557
5558 // ═══════════════════════════════════════════════════════════════════
5559 // C-parity tests pinning Src/zsh.h macro ports.
5560 // ═══════════════════════════════════════════════════════════════════
5561
5562 /// `minimum(3, 5)` returns 3. C `#define minimum(x,y) ((x)<(y)?(x):(y))`.
5563 #[test]
5564 fn minimum_picks_smaller_int() {
5565 assert_eq!(minimum(3, 5), 3);
5566 assert_eq!(minimum(5, 3), 3);
5567 }
5568
5569 /// `minimum(3, 3)` returns either (both equal).
5570 #[test]
5571 fn minimum_equal_values_returns_value() {
5572 assert_eq!(minimum(7, 7), 7);
5573 }
5574
5575 /// `minimum(-5, 5)` returns -5 (negative smaller).
5576 #[test]
5577 fn minimum_negative_picks_negative() {
5578 assert_eq!(minimum(-5, 5), -5);
5579 }
5580
5581 /// `QT_IS_SINGLE(QT_SINGLE)` returns true.
5582 /// C `#define QT_IS_SINGLE(x) (x == QT_SINGLE || x == QT_SINGLE_OPTIONAL)`.
5583 #[test]
5584 fn QT_IS_SINGLE_recognises_QT_SINGLE() {
5585 assert!(QT_IS_SINGLE(QT_SINGLE));
5586 }
5587
5588 /// `QT_IS_SINGLE(QT_NONE)` returns false.
5589 #[test]
5590 fn QT_IS_SINGLE_QT_NONE_returns_false() {
5591 assert!(!QT_IS_SINGLE(QT_NONE));
5592 }
5593
5594 /// `IS_WRITE_FILE(REDIR_WRITE)` returns true. C `#define
5595 /// IS_WRITE_FILE(x)` — any write-redirect family.
5596 #[test]
5597 fn IS_WRITE_FILE_recognises_write_token() {
5598 assert!(IS_WRITE_FILE(REDIR_WRITE));
5599 }
5600
5601 /// `IS_APPEND_REDIR(REDIR_APP)` returns true.
5602 #[test]
5603 fn IS_APPEND_REDIR_recognises_app_token() {
5604 assert!(IS_APPEND_REDIR(REDIR_APP));
5605 }
5606
5607 /// `IS_ERROR_REDIR(REDIR_ERRWRITE)` returns true.
5608 #[test]
5609 fn IS_ERROR_REDIR_recognises_errwrite_token() {
5610 assert!(IS_ERROR_REDIR(REDIR_ERRWRITE));
5611 }
5612
5613 /// `IS_READFD(REDIR_READ)` returns true.
5614 #[test]
5615 fn IS_READFD_recognises_read_token() {
5616 assert!(IS_READFD(REDIR_READ));
5617 }
5618
5619 // ═══════════════════════════════════════════════════════════════════
5620 // Additional C-parity tests for Src/zsh.h wordcode + macro helpers.
5621 // ═══════════════════════════════════════════════════════════════════
5622
5623 /// c:918 — `WCB_END()` returns the WC_END opcode at offset 0.
5624 #[test]
5625 fn WCB_END_returns_wc_end_opcode() {
5626 let end = WCB_END();
5627 assert_eq!(wc_code(end), WC_END, "WCB_END encodes WC_END opcode");
5628 assert_eq!(wc_data(end), 0, "WCB_END encodes zero data");
5629 }
5630
5631 /// c:wc_bld — round-trip: wc_code(wc_bld(c, d)) == c.
5632 #[test]
5633 fn wc_bld_code_round_trip() {
5634 for opcode in [WC_END, WC_LIST, WC_SUBLIST, WC_PIPE] {
5635 let w = wc_bld(opcode, 42);
5636 assert_eq!(wc_code(w), opcode, "wc_code round-trips opcode {}", opcode);
5637 }
5638 }
5639
5640 /// c:wc_bld — round-trip data field: wc_data(wc_bld(c, d)) == d.
5641 #[test]
5642 fn wc_bld_data_round_trip() {
5643 for data in [0u32, 1, 42, 0xFFFF, 0x00FFFFFF] {
5644 let w = wc_bld(WC_LIST, data);
5645 assert_eq!(wc_data(w), data, "wc_data round-trips data {}", data);
5646 }
5647 }
5648
5649 /// c:920 — `WC_LIST_TYPE` reads the data field (matches wc_data).
5650 #[test]
5651 fn WC_LIST_TYPE_reads_data_field() {
5652 let w = WCB_LIST(7, 0);
5653 assert_eq!(WC_LIST_TYPE(w), 7, "list type round-trips");
5654 }
5655
5656 /// c:924 — `WC_LIST_SKIP` shifts down by WC_LIST_FREE bits.
5657 #[test]
5658 fn WC_LIST_SKIP_round_trip() {
5659 let w = WCB_LIST(0, 100);
5660 assert_eq!(WC_LIST_SKIP(w), 100, "list skip round-trips");
5661 }
5662
5663 /// c:927 — `WC_SUBLIST_TYPE` is data & 3 (low 2 bits).
5664 #[test]
5665 fn WC_SUBLIST_TYPE_masks_low_2_bits() {
5666 let w = WCB_SUBLIST(2, 0, 0); // type=2 fits in 2 bits
5667 assert_eq!(WC_SUBLIST_TYPE(w), 2);
5668 }
5669
5670 /// c:931 — `WC_SUBLIST_FLAGS` masks bits 2-4 (0x1c).
5671 #[test]
5672 fn WC_SUBLIST_FLAGS_masks_bits_2_through_4() {
5673 let w = WCB_SUBLIST(0, 0x04, 0); // flag bit 2
5674 assert_eq!(WC_SUBLIST_FLAGS(w), 0x04);
5675 }
5676
5677 /// c:940 — `WC_PIPE_TYPE` is data & 1 (low bit only).
5678 #[test]
5679 fn WC_PIPE_TYPE_masks_low_bit() {
5680 let w = WCB_PIPE(1, 100);
5681 assert_eq!(WC_PIPE_TYPE(w), 1);
5682 let w0 = WCB_PIPE(0, 100);
5683 assert_eq!(WC_PIPE_TYPE(w0), 0);
5684 }
5685
5686 /// c:940 — `WC_PIPE_LINENO` is data >> 1.
5687 #[test]
5688 fn WC_PIPE_LINENO_shifts_down_by_one() {
5689 let w = WCB_PIPE(0, 42);
5690 assert_eq!(WC_PIPE_LINENO(w), 42, "lineno round-trips through >> 1");
5691 }
5692
5693 /// c:215 — `IS_DASH('-')` returns true; other chars return false.
5694 #[test]
5695 fn IS_DASH_only_recognizes_hyphen() {
5696 assert!(IS_DASH('-'));
5697 assert!(!IS_DASH('+'));
5698 assert!(!IS_DASH(' '));
5699 assert!(!IS_DASH('a'));
5700 assert!(!IS_DASH('\0'));
5701 }
5702
5703 /// c:32 — `minimum(a, b)` returns the smaller of two values.
5704 #[test]
5705 fn minimum_returns_smaller_value() {
5706 assert_eq!(minimum(3, 7), 3);
5707 assert_eq!(minimum(7, 3), 3);
5708 assert_eq!(
5709 minimum(5, 5),
5710 5,
5711 "equal → either (returns first per PartialOrd)"
5712 );
5713 assert_eq!(minimum(-10, 10), -10);
5714 }
5715
5716 /// c:32 — minimum works with floats.
5717 #[test]
5718 fn minimum_works_with_floats() {
5719 assert_eq!(minimum(1.5_f64, 2.5_f64), 1.5);
5720 assert_eq!(minimum(-1.0_f64, 0.0_f64), -1.0);
5721 }
5722
5723 /// c:246 — `QT_IS_SINGLE(QT_SINGLE)` returns true.
5724 #[test]
5725 fn QT_IS_SINGLE_recognizes_single_quote() {
5726 // QT_SINGLE is the canonical single-quote token value.
5727 // Sanity: any non-QT_SINGLE returns false; QT_SINGLE → true.
5728 assert!(QT_IS_SINGLE(crate::ported::zsh_h::QT_SINGLE));
5729 assert!(!QT_IS_SINGLE(0));
5730 assert!(!QT_IS_SINGLE(-1));
5731 }
5732
5733 // ═══════════════════════════════════════════════════════════════════
5734 // Additional C-parity tests for Src/zsh.h wordcode WC_* helpers.
5735 // ═══════════════════════════════════════════════════════════════════
5736
5737 /// c:970 — `WCB_SIMPLE(N) / WC_SIMPLE_ARGC` round-trip preserves argc.
5738 #[test]
5739 fn WCB_SIMPLE_round_trips_argc() {
5740 for n in [0u32, 1, 42, 1000, 0xFFFF] {
5741 let w = WCB_SIMPLE(n);
5742 assert_eq!(WC_SIMPLE_ARGC(w), n, "argc {} must round-trip", n);
5743 }
5744 }
5745
5746 /// c:973 — `WCB_TYPESET / WC_TYPESET_ARGC` round-trip.
5747 #[test]
5748 fn WCB_TYPESET_round_trips_argc() {
5749 for n in [0u32, 5, 100, 1000] {
5750 let w = WCB_TYPESET(n);
5751 assert_eq!(WC_TYPESET_ARGC(w), n);
5752 }
5753 }
5754
5755 /// c:976 — `WCB_SUBSH / WC_SUBSH_SKIP` round-trip preserves skip offset.
5756 #[test]
5757 fn WCB_SUBSH_round_trips_skip() {
5758 for o in [0u32, 1, 100, 0x10000] {
5759 let w = WCB_SUBSH(o);
5760 assert_eq!(WC_SUBSH_SKIP(w), o);
5761 }
5762 }
5763
5764 /// c:979 — `WCB_CURSH / WC_CURSH_SKIP` round-trip.
5765 #[test]
5766 fn WCB_CURSH_round_trips_skip() {
5767 for o in [0u32, 1, 50, 500] {
5768 let w = WCB_CURSH(o);
5769 assert_eq!(WC_CURSH_SKIP(w), o);
5770 }
5771 }
5772
5773 /// c:982 — `WCB_TIMED / WC_TIMED_TYPE` round-trip.
5774 #[test]
5775 fn WCB_TIMED_round_trips_type() {
5776 for t in [0u32, 1, 2] {
5777 let w = WCB_TIMED(t);
5778 assert_eq!(WC_TIMED_TYPE(w), t);
5779 }
5780 }
5781
5782 /// c:987 — `WCB_FUNCDEF / WC_FUNCDEF_SKIP` round-trip.
5783 #[test]
5784 fn WCB_FUNCDEF_round_trips_skip() {
5785 for o in [0u32, 10, 100] {
5786 let w = WCB_FUNCDEF(o);
5787 assert_eq!(WC_FUNCDEF_SKIP(w), o);
5788 }
5789 }
5790
5791 /// c:990 — `WCB_FOR(type, skip)` encodes type in low 2 bits, skip
5792 /// in upper bits.
5793 #[test]
5794 fn WCB_FOR_packs_type_low_skip_high() {
5795 // type fits in 2 bits (0..3)
5796 for t in [0u32, 1, 2, 3] {
5797 for o in [0u32, 10, 100] {
5798 let w = WCB_FOR(t, o);
5799 assert_eq!(WC_FOR_TYPE(w), t, "type round-trip for ({}, {})", t, o);
5800 assert_eq!(WC_FOR_SKIP(w), o, "skip round-trip for ({}, {})", t, o);
5801 }
5802 }
5803 }
5804
5805 /// c:997 — `WC_SELECT_TYPE(c)` masks low bit only.
5806 #[test]
5807 fn WC_SELECT_TYPE_masks_low_bit() {
5808 // wc_bld with 0b11 in data → SELECT_TYPE = 1 (low bit).
5809 let w = wc_bld(WC_SELECT, 3);
5810 assert_eq!(WC_SELECT_TYPE(w), 1);
5811 let w0 = wc_bld(WC_SELECT, 4);
5812 assert_eq!(WC_SELECT_TYPE(w0), 0, "0b100 & 1 = 0");
5813 }
5814
5815 /// c:997 — `WC_SELECT_SKIP(c)` is data >> 1.
5816 #[test]
5817 fn WC_SELECT_SKIP_shifts_right_one() {
5818 let w = wc_bld(WC_SELECT, 42);
5819 assert_eq!(WC_SELECT_SKIP(w), 42 >> 1);
5820 }
5821
5822 /// c:990 — WC_FOR_TYPE only reads 2 bits — high bits ignored.
5823 #[test]
5824 fn WC_FOR_TYPE_only_uses_low_2_bits() {
5825 // 0b1011 → 0b11 = 3 (low 2 bits).
5826 let w = wc_bld(WC_FOR, 0b1011);
5827 assert_eq!(WC_FOR_TYPE(w), 3);
5828 }
5829
5830 // ═══════════════════════════════════════════════════════════════════
5831 // Additional C-parity tests for Src/zsh.h PM_* parameter flag bits
5832 // c:3174-3206 — scalar/array/integer/float/hashed/case/readonly/etc.
5833 // ═══════════════════════════════════════════════════════════════════
5834
5835 /// c:3174 — `PM_SCALAR` = 0 (default param type).
5836 #[test]
5837 fn pm_scalar_is_zero() {
5838 assert_eq!(PM_SCALAR, 0, "PM_SCALAR is the default (no bits)");
5839 }
5840
5841 /// c:3176-3184 — PM_ARRAY/INTEGER/EFLOAT/FFLOAT/HASHED canonical bit positions.
5842 #[test]
5843 fn pm_type_flags_canonical_bit_positions() {
5844 assert_eq!(PM_ARRAY, 1 << 0, "c:3176");
5845 assert_eq!(PM_INTEGER, 1 << 1, "c:3178");
5846 assert_eq!(PM_EFLOAT, 1 << 2, "c:3180");
5847 assert_eq!(PM_FFLOAT, 1 << 3, "c:3182");
5848 assert_eq!(PM_HASHED, 1 << 4, "c:3184");
5849 }
5850
5851 /// c:3186-3194 — PM_LEFT/RIGHT_B/RIGHT_Z/LOWER/UPPER canonical bits.
5852 #[test]
5853 fn pm_padding_case_flags_canonical_bit_positions() {
5854 assert_eq!(PM_LEFT, 1 << 5, "c:3186");
5855 assert_eq!(PM_RIGHT_B, 1 << 6, "c:3188");
5856 assert_eq!(PM_RIGHT_Z, 1 << 7, "c:3190");
5857 assert_eq!(PM_LOWER, 1 << 8, "c:3192");
5858 assert_eq!(PM_UPPER, 1 << 9, "c:3194");
5859 }
5860
5861 /// c:3196 — PM_UNDEFINED INTENTIONALLY aliases PM_UPPER (both 1<<9).
5862 /// Per c:3196 comment, autoload-undefined fns reuse the UPPER bit
5863 /// because undefined fns can never have case attributes.
5864 #[test]
5865 fn pm_undefined_aliases_pm_upper() {
5866 assert_eq!(
5867 PM_UNDEFINED, PM_UPPER,
5868 "c:3196 INTENTIONAL alias: undefined fns reuse UPPER bit"
5869 );
5870 }
5871
5872 /// c:3204 — PM_ABSPATH_USED INTENTIONALLY aliases PM_EXPORTED.
5873 /// c:3204 comment: only-for-internal-tracking flag reuses exported bit.
5874 #[test]
5875 fn pm_abspath_used_aliases_pm_exported() {
5876 assert_eq!(
5877 PM_ABSPATH_USED, PM_EXPORTED,
5878 "c:3204 INTENTIONAL alias: bit reuse for path-tracking"
5879 );
5880 }
5881
5882 /// c:3198 — PM_READONLY = 1 << 10.
5883 #[test]
5884 fn pm_readonly_is_bit_10() {
5885 assert_eq!(PM_READONLY, 1 << 10);
5886 }
5887
5888 /// c:3174-3206 — PM_* flags are all u32 (compile-time type pin).
5889 #[test]
5890 fn pm_flags_are_u32_type() {
5891 let _: u32 = PM_SCALAR;
5892 let _: u32 = PM_ARRAY;
5893 let _: u32 = PM_INTEGER;
5894 let _: u32 = PM_READONLY;
5895 }
5896
5897 /// c:3176-3194 — distinct type flags are pairwise disjoint
5898 /// (excluding intentional aliases like UNDEFINED=UPPER).
5899 #[test]
5900 fn pm_distinct_type_flags_pairwise_disjoint() {
5901 let codes = [
5902 PM_ARRAY, PM_INTEGER, PM_EFLOAT, PM_FFLOAT, PM_HASHED, PM_LEFT, PM_RIGHT_B, PM_RIGHT_Z,
5903 PM_LOWER, PM_UPPER,
5904 ];
5905 let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
5906 assert_eq!(
5907 unique.len(),
5908 codes.len(),
5909 "distinct PM type/padding flags must be pairwise disjoint"
5910 );
5911 }
5912
5913 /// c:3176-3194 — every distinct PM_* type/padding flag is a single bit.
5914 #[test]
5915 fn pm_distinct_type_flags_all_single_bits() {
5916 for &v in &[
5917 PM_ARRAY,
5918 PM_INTEGER,
5919 PM_EFLOAT,
5920 PM_FFLOAT,
5921 PM_HASHED,
5922 PM_LEFT,
5923 PM_RIGHT_B,
5924 PM_RIGHT_Z,
5925 PM_LOWER,
5926 PM_UPPER,
5927 PM_READONLY,
5928 PM_TAGGED,
5929 PM_EXPORTED,
5930 PM_UNIQUE,
5931 ] {
5932 assert!(
5933 v.is_power_of_two(),
5934 "PM_* flag {:#x} must be a single bit",
5935 v
5936 );
5937 }
5938 }
5939
5940 /// c:3174 — PM_SCALAR being 0 means "all flags clear" matches PM_SCALAR.
5941 #[test]
5942 fn pm_scalar_zero_is_default_state() {
5943 assert_eq!(
5944 PM_SCALAR & (PM_ARRAY | PM_INTEGER | PM_HASHED),
5945 0,
5946 "PM_SCALAR=0 by design: clear-all-bits state"
5947 );
5948 }
5949
5950 // ═══════════════════════════════════════════════════════════════════
5951 // Additional C-parity tests for Src/zsh.h PRINT_* + HIST_* flag bits
5952 // c:3400-3428 PRINT_* / c:3452-3464 HIST_*
5953 // ═══════════════════════════════════════════════════════════════════
5954
5955 /// c:3400-3418 — PRINT_NAMEONLY/TYPE/LIST/KV_PAIR/INCLUDEVALUE/TYPESET/
5956 /// LINE/POSIX_EXPORT/POSIX_READONLY/WITH_NAMESPACE canonical bits 0-9.
5957 #[test]
5958 fn print_canonical_bit_positions() {
5959 assert_eq!(PRINT_NAMEONLY, 1 << 0, "c:3400");
5960 assert_eq!(PRINT_TYPE, 1 << 1, "c:3402");
5961 assert_eq!(PRINT_LIST, 1 << 2, "c:3404");
5962 assert_eq!(PRINT_KV_PAIR, 1 << 3, "c:3406");
5963 assert_eq!(PRINT_INCLUDEVALUE, 1 << 4, "c:3408");
5964 assert_eq!(PRINT_TYPESET, 1 << 5, "c:3410");
5965 assert_eq!(PRINT_LINE, 1 << 6, "c:3412");
5966 assert_eq!(PRINT_POSIX_EXPORT, 1 << 7, "c:3414");
5967 assert_eq!(PRINT_POSIX_READONLY, 1 << 8, "c:3416");
5968 assert_eq!(PRINT_WITH_NAMESPACE, 1 << 9, "c:3418");
5969 }
5970
5971 /// c:3420 — PRINT_WHENCE_CSH INTENTIONALLY aliases PRINT_POSIX_EXPORT
5972 /// (both bit 7). Per c:2191 comment: typeset and whence are separate
5973 /// builtins, so flag-bit reuse is safe.
5974 #[test]
5975 fn print_whence_csh_aliases_print_posix_export() {
5976 assert_eq!(
5977 PRINT_WHENCE_CSH, PRINT_POSIX_EXPORT,
5978 "c:3420 INTENTIONAL alias: whence vs typeset disambiguated by builtin"
5979 );
5980 }
5981
5982 /// c:3422 — PRINT_WHENCE_VERBOSE aliases PRINT_POSIX_READONLY.
5983 #[test]
5984 fn print_whence_verbose_aliases_print_posix_readonly() {
5985 assert_eq!(
5986 PRINT_WHENCE_VERBOSE, PRINT_POSIX_READONLY,
5987 "c:3422 INTENTIONAL alias"
5988 );
5989 }
5990
5991 /// c:3424 — PRINT_WHENCE_SIMPLE aliases PRINT_WITH_NAMESPACE.
5992 #[test]
5993 fn print_whence_simple_aliases_print_with_namespace() {
5994 assert_eq!(
5995 PRINT_WHENCE_SIMPLE, PRINT_WITH_NAMESPACE,
5996 "c:3424 INTENTIONAL alias"
5997 );
5998 }
5999
6000 /// c:3400-3428 — every PRINT_* flag is i32 type (compile-time pin).
6001 #[test]
6002 fn print_flags_are_i32_type() {
6003 let _: i32 = PRINT_NAMEONLY;
6004 let _: i32 = PRINT_TYPE;
6005 let _: i32 = PRINT_WHENCE_CSH;
6006 }
6007
6008 /// c:3452-3464 — HIST_MAKEUNIQUE/OLD/READ/DUP/FOREIGN/TMPSTORE/NOWRITE
6009 /// canonical bit values match upstream zsh-source positions.
6010 #[test]
6011 fn hist_canonical_bit_positions() {
6012 assert_eq!(HIST_MAKEUNIQUE, 0x01, "c:3452");
6013 assert_eq!(HIST_OLD, 0x02, "c:3454");
6014 assert_eq!(HIST_READ, 0x04, "c:3456");
6015 assert_eq!(HIST_DUP, 0x08, "c:3458");
6016 assert_eq!(HIST_FOREIGN, 0x10, "c:3460");
6017 assert_eq!(HIST_TMPSTORE, 0x20, "c:3462");
6018 assert_eq!(HIST_NOWRITE, 0x40, "c:3464");
6019 }
6020
6021 /// c:3452-3464 — all HIST_* are u32 type (compile-time pin).
6022 #[test]
6023 fn hist_flags_are_u32_type() {
6024 let _: u32 = HIST_MAKEUNIQUE;
6025 let _: u32 = HIST_OLD;
6026 let _: u32 = HIST_NOWRITE;
6027 }
6028
6029 /// c:3452-3464 — HIST_* are all single bits.
6030 #[test]
6031 fn hist_flags_all_single_bits() {
6032 for &v in &[
6033 HIST_MAKEUNIQUE,
6034 HIST_OLD,
6035 HIST_READ,
6036 HIST_DUP,
6037 HIST_FOREIGN,
6038 HIST_TMPSTORE,
6039 HIST_NOWRITE,
6040 ] {
6041 assert!(v.is_power_of_two(), "HIST_* {:#x} must be a single bit", v);
6042 }
6043 }
6044
6045 /// c:3452-3464 — HIST_* are pairwise distinct.
6046 #[test]
6047 fn hist_flags_pairwise_distinct() {
6048 let codes = [
6049 HIST_MAKEUNIQUE,
6050 HIST_OLD,
6051 HIST_READ,
6052 HIST_DUP,
6053 HIST_FOREIGN,
6054 HIST_TMPSTORE,
6055 HIST_NOWRITE,
6056 ];
6057 let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
6058 assert_eq!(
6059 unique.len(),
6060 codes.len(),
6061 "HIST_* must be pairwise distinct"
6062 );
6063 }
6064
6065 /// c:3400-3418 — first 7 non-aliased PRINT_* bits are pairwise distinct.
6066 #[test]
6067 fn print_non_aliased_pairwise_distinct() {
6068 let codes = [
6069 PRINT_NAMEONLY,
6070 PRINT_TYPE,
6071 PRINT_LIST,
6072 PRINT_KV_PAIR,
6073 PRINT_INCLUDEVALUE,
6074 PRINT_TYPESET,
6075 PRINT_LINE,
6076 ];
6077 let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
6078 assert_eq!(
6079 unique.len(),
6080 codes.len(),
6081 "non-aliased PRINT_* must be pairwise distinct"
6082 );
6083 }
6084}