Skip to content

StrInitStack

Description

Open a scope that declares a Str named name, backed by a fixed-capacity stack array of ne characters. The body that follows the macro call (NOT a macro argument) sees name as an initialised, empty Str with capacity ne. name’s lexical scope is exactly the body: outside the macro the identifier is no longer bound.

No allocator – the backing storage is the stack. The body is responsible for keeping content bounded by ne. Any operation that would grow name past ne ends up calling StrReserve, which sees the NULL allocator and aborts via LOG_FATAL("vector not growable, no allocator assigned, probably stack inited"). Use a heap-backed Str if you need spill behaviour.

The macro uses the for-chain scope idiom – the body is regular code below the macro, not a brace-delimited argument:

StrInitStack(buf, 1024) { ssize_t n = read(fd, StrBegin(&buf), 1023); StrResize(&buf, (size)n); StrMergeR(out, &buf); }

Success

Body runs once; name is valid for the body’s scope. On normal fall-through both name and the backing array are zeroed by the macro’s exit updates before name falls out of scope.

Failure

The macro itself cannot fail. Operations inside the body that try to grow name past ne abort.

updates (the same C-level limitation that applies to Scope). break exits the innermost for cleanly: the backing array is still zeroed by the outer for’s update, but the name handle’s MemSet is skipped – harmless because name’s scope is the body anyway and the identifier is no longer reachable after the macro. continue inside the body does NOT restart – it jumps to the inner for’s update clause, which zeroes name and then re-checks the (already-false) condition, exiting the scope. Treat it as a silent early-exit, not a loop control. ne is evaluated twice (the +1 for the array dimension, and the capacity assignment); sizeof(UNPL(_d)) reads the array’s type, not ne. Pass a side-effect-free expression (literal or simple variable) regardless.

Usage example (Cross-references)

Usage examples (Cross-references)
                FmtInfo fmt_info = {0};
                bool    spec_ok  = false;
                StrInitStack(spec_buf, 32) {
                    char *data = StrBegin(&spec_buf);
                    MemCopy(data, start, spec_len);
    
        bool ok = true;
        StrInitStack(digits, 32) {
            char *data        = StrBegin(&digits);
            u32   digit_count = 0;
        // `flag` aliases the caller's `tok` directly.
        ArgRun result = ARG_RUN_ERROR;
        StrInitStack(flagbuf, 128) {
            Zstr flag = tok;
            if (eq) {
        for (Zstr p = tok + 1; *p; ++p) {
            bool iter_ok = false;
            StrInitStack(buf, 3) {
                char *data = StrBegin(&buf);
                data[0]    = '-';
                            BUNDLE_REJECT
                        } decision = BUNDLE_REJECT;
                        StrInitStack(two, 3) {
                            char *data = StrBegin(&two);
                            data[0]    = '-';
        } else {
            bool ok = true;
            StrInitStack(buffer, 65) {
                char *data = StrBegin(&buffer);
                size  pos  = 0;
            } else {
                bool ok = true;
                StrInitStack(exp_buf, 8) {
                    char *data    = StrBegin(&exp_buf);
                    size  exp_pos = 0;
            } else {
                bool ok = true;
                StrInitStack(int_buf, 32) {
                    char *data    = StrBegin(&int_buf);
                    size  int_pos = 0;
    #    if FEATURE_PARSER_PDB
            if (pdb_cache_ok) {
                StrInitStack(module_path, MAX_PATH) {
                    char *data        = StrBegin(&module_path);
                    u64   module_base = 0;
            u32  v       = octets[i];
            bool iter_ok = true;
            StrInitStack(tmp, 4) {
                char *data = StrBegin(&tmp);
                i32   n    = 0;
    static bool append_hextet(char *dst, size dst_size, size *pos, u16 v) {
        bool ok = true;
        StrInitStack(tmp, 4) {
            char *data = StrBegin(&tmp);
            i32   n    = 0;
    
        bool ok = false;
        StrInitStack(host, 256) {
            char *host_data = StrBegin(&host);
            Zstr  port_str  = NULL;
        }
    
        StrInitStack(host, 48) {
            char *host_data = StrBegin(&host);
            u16   port      = 0;
        // then `StrMergeR` copies into the caller's `buf`. The
        // `StrInitStack` scope owns `tmpbuf`'s lifetime end-to-end.
        StrInitStack(tmpbuf, 1024) {
    #if PLATFORM_UNIX
            i32 rfd = is_stdout ? proc->_stdout_fd : proc->_stderr_fd;
        // directly for `StrResize` before copying out.
        bool got = false;
        StrInitStack(buffer, MAX_PATH) {
            DWORD len = GetModuleFileNameA(NULL, StrBegin(&buffer), MAX_PATH);
            if (len == 0 || len >= MAX_PATH) {
        // we accept `>= 0` as success rather than the legacy `!= -1` shape.
        bool got = false;
        StrInitStack(buffer, 4096) {
            char   *data = StrBegin(&buffer);
            ssize_t len  = proc_readlink("/proc/self/exe", data, 4095);
        // `-Werror=implicit-function-declaration` here.
        HANDLE hFind = INVALID_HANDLE_VALUE;
        StrInitStack(search_path, MAX_PATH) {
            size path_len = ZstrLen(path);
            if (path_len + 3 > MAX_PATH) {
        // intermediate components. Restores the slash before continuing.
        i8 ok = 1;
        StrInitStack(buf, 4096) {
            char *data = StrBegin(&buf);
            MemCopy(data, path, n);
            // `reserve_vec`.
            bool inner_ok = false;
            StrInitStack(child, DIR_REMOVE_ALL_PATH_CAP) {
                StrAppendFmt(&child, trail_sep ? "{}{}" : "{}/{}", path, entry_nm);
                if (e->type == DIR_ENTRY_TYPE_DIRECTORY) {
        }
        bool ok = true;
        StrInitStack(chunk, 4096) {
            char *data = StrBegin(&chunk);
            for (;;) {
                // `parse_ipv4` / `parse_ipv6` can scan it. Cap matches
                // the longest reasonable IPv6-with-zone-id literal.
                StrInitStack(ip_buf, 64) {
                    StrPushBackMany(&ip_buf, (Zstr)StrIterDataAt(&si, ip_start), ip_len);
                    got_v4 = parse_ipv4(StrBegin(&ip_buf), v4);
                u64 ip_len = (u64)(StrIterIndex(&si) - ip_start);
                if (ip_len > 0 && ip_len < 64) {
                    StrInitStack(ip_buf, 64) {
                        StrPushBackMany(&ip_buf, (Zstr)StrIterDataAt(&si, ip_start), ip_len);
                        u8 v4[4]  = {0};
    
        bool found = false;
        StrInitStack(norm, 256) {
            // `normalize_hostname` strips trailing dots and lowercases;
            // `StrInitStack` zero-fills the trailing slot so `StrBegin`
        // NUL lives next to the bytes, with no parallel `char host[]`.
        bool ok = false;
        StrInitStack(host, 256) {
            StrPushBackMany(&host, spec, colon_at);
            ok = dns_resolve_5_zstr(self, StrBegin(&host), port, kind, out);
    // Test StrInitStack macro
    bool test_str_init_stack(void) {
        WriteFmt("Testing StrInitStack\n");
    
        DefaultAllocator alloc = DefaultAllocatorInit();
    
        // StrInitStack declares and scopes `stack_str` itself (for-chain idiom).
        StrInitStack(stack_str, 20) {
            StrPushBackMany(&stack_str, "Hello, Stack!");
            ValidateStr(&stack_str);
            Str           UNPL(m)         = StrInit(&UNPL(log_alloc));                                                     \
            StrAppendFmt(&UNPL(m), __VA_ARGS__);                                                                           \
            StrInitStack(UNPL(syserr), 256) {                                                                              \
                StrError(UNPL(sys_eno), &UNPL(syserr));                                                                    \
                StrAppendFmt(&UNPL(m), " : {}", UNPL(syserr));                                                             \
            Str           UNPL(m)         = StrInit(&UNPL(log_alloc));                                                     \
            StrAppendFmt(&UNPL(m), __VA_ARGS__);                                                                           \
            StrInitStack(UNPL(syserr), 256) {                                                                              \
                StrError(UNPL(sys_eno), &UNPL(syserr));                                                                    \
                StrAppendFmt(&UNPL(m), " : {}", UNPL(syserr));                                                             \
            Str           UNPL(m)         = StrInit(&UNPL(log_alloc));                                                     \
            StrAppendFmt(&UNPL(m), __VA_ARGS__);                                                                           \
            StrInitStack(UNPL(syserr), 256) {                                                                              \
                StrError(UNPL(sys_eno), &UNPL(syserr));                                                                    \
                StrAppendFmt(&UNPL(m), " : {}", UNPL(syserr));                                                             \
Last updated on