Skip to main content

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