pub fn addfd(
forked: i32,
save: &mut [i32; 10],
mfds: &mut [Option<Box<multio>>; 10],
fd1: i32,
fd2: i32,
rflag: i32,
varid: Option<&str>,
)Expand description
Port of static void addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag, char *varid)
from Src/exec.c:2397.
C body (~100 lines, three branches):
if (varid) {
/* {varid}>file form — move fd above 10 and bind $varid to it */
} else if (!mfds[fd1] || unset(MULTIOS)) {
/* new multio OR MULTIOS off — first redir on this fd */
} else {
/* additional redir on a fd that's already a multio (split or extend) */
}Register fd2 (already-open) as a redirection target for fd1.
Three branches: varid writes the moved fd to $varid and bumps
fdtable[fd1] = FDT_EXTERNAL; new-multio path saves the original fd1
(when !forked) and stamps mfds[fd1] as a single-entry struct;
extend-multio path either splits a ct=1 stream into a pipe + 2 fds
via mpipe, or appends another fd to an already-split stream
(re-allocating mfds for fd1 past the MULTIOUNIT boundary).
multio.fds is now Vec<i32> (zsh_h.rs:1397) so the C
hrealloc at c:2485 maps to Vec::push; MULTIOUNIT is no
longer a hard cap (still 8 for the initial allocation, grown
on demand thereafter).
fdtable[fdN] |= FDT_SAVED_MASK at c:2440 — Rust fdtable_set
stores the int value but doesn’t expose a bitwise-OR setter; we
re-read + OR + re-store as two atomic-feeling steps.