Skip to content

StrReadFmt

Description

Parse input string according to format string with rust-style placeholders, extracting values into provided arguments. Delegates to the in-tree formatted-read backend.

The new input value after a successful read will be in [input, input + len(input)]
Provided input string must be an assignable l-value. The macro automatically updates given input string to new parse position after a successful parse. If parse fails, the input pointer does not change.

The input must not be passed to any allocator’s deallocate call after use. The pointer value is updated on successful read; after the call it might be (input) + 1 or (input + 1233493783847394), neither of which is a valid free target.

Not providing an assignable input (first parameter) will result in undefined behavior. If you’re lucky you’ll get a segfault.

Parameters

Name Direction Description
input in Input string to parse (must be null-terminated).
fmtstr in Format string with {} placeholders (must be null-terminated). argument should be a modifiable l-value wrapped with &variable.

Usage example (from documentation)

   void ParseInput(Zstr in, Zstr *out_rest, DefaultAllocator *alloc) {
       Zstr p  = in;                       // local cursor; in is not mutated
       i32  id = 0;
       Str  name = StrInit(alloc);
       StrReadFmt(p, "Person id = {} and name = {}", &id, &name);
       // p now points one past the consumed text on success.
       *out_rest = p;
       StrDeinit(&name);
   }

Success

Statement form – input is advanced in place to point at the first character past the consumed text.

Failure

Backend logs an error and returns without consuming input; input is left pointing at its original position.

Usage example (Cross-references)

Usage examples (Cross-references)
            ProcReadFromStdout((p), &UNPL(buf));                                                                           \
            Zstr UNPL(in) = StrBegin(&UNPL(buf));                                                                          \
            StrReadFmt(UNPL(in), __VA_ARGS__);                                                                             \
            StrDeinit(&UNPL(buf));                                                                                         \
        } while (0)
            ProcReadFromStderr((p), &UNPL(buf));                                                                           \
            Zstr UNPL(in) = StrBegin(&UNPL(buf));                                                                          \
            StrReadFmt(UNPL(in), __VA_ARGS__);                                                                             \
            StrDeinit(&UNPL(buf));                                                                                         \
        } while (0)
        i32  year = 0;
        u32  mon = 0, day = 0, hh = 0, mm = 0, ss = 0;
        StrReadFmt(p, "{}-{}-{}T{}:{}:{}", year, mon, day, hh, mm, ss);
        if (p == i) {
            return i; // no date-time prefix matched
            p++;
            Zstr frac_at = p;
            StrReadFmt(p, "{}", nanos);
            if (p == frac_at) {
                return i; // '.' with no fraction
            Zstr off_at = ++p;
            u32  oh = 0, om = 0;
            StrReadFmt(p, "{}:{}", oh, om);
            if (p == off_at) {
                return i; // malformed offset
        Str        version = StrInit(alloc);
    
        StrReadFmt(cursor, "{} {} {}\r\n", method, req->url, version);
        if (cursor == in) {
            LOG_ERROR("http request parse failed: invalid request line");
    
            HttpHeader hh = HttpHeaderInit(alloc);
            StrReadFmt(cursor, "{}: {}\r\n", hh.key, hh.value);
            if (cursor == line_start) {
                LOG_ERROR("failed to parse header line");
        DateTime b = {0};
        Zstr     p = StrBegin(&s);
        StrReadFmt(p, "{}", b);
    
        bool ok = DateTimeCompare(a, b) == 0 && b.utc_offset_seconds == MST && b.nanosecond == 123456789u &&
        Zstr     in = "2026-06-26T17:34:11-07:00";
        DateTime d  = {0};
        StrReadFmt(in, "{}", d);
        return d.year == 2026 && d.month == 6 && d.day == 26 && d.hour == 17 && d.minute == 34 && d.second == 11 &&
               d.nanosecond == 0 && d.utc_offset_seconds == MST;
            return i;
        }
        StrReadFmt(i, "({}, {})", p->x, p->y);
        return i;
    }
            return i;
        }
        StrReadFmt(i, "[{}..{}]", b->min, b->max);
        return i;
    }
            return i;
        }
        StrReadFmt(i, "{}:{}@{}", r->id, r->bbox, r->centroid);
        return i;
    }
        Zstr    in = "(42, -9)";
        Point2D p  = {0};
        StrReadFmt(in, "{}", p);
        bool ok = (p.x == 42) && (p.y == -9);
        bool ok = StrAppendFmt(&out, "{}", src);
        Zstr in = StrBegin(&out);
        StrReadFmt(in, "{}", dst);
        ok = ok && (dst.x == src.x) && (dst.y == src.y);
        bool ok = StrAppendFmt(&out, "{}", src);
        Zstr in = StrBegin(&out);
        StrReadFmt(in, "{}", dst);
    
        ok = ok && (dst.min.x == src.min.x) && (dst.min.y == src.min.y);
        bool ok = StrAppendFmt(&out, "{}", src);
        Zstr in = StrBegin(&out);
        StrReadFmt(in, "{}", dst);
    
        ok = ok && (dst.id == src.id);
        (void)FloatTryFromStr(&f, "99");
    
        StrReadFmt(input, "{}", f);
    
        Str  text = FloatToStr(&f);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0x1";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 1) && (BitVecLen(&bv) == 4);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0xDEAD";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 0xDEAD) && (BitVecLen(&bv) == 16);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0xDEAD";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 0xDEAD) && (*z == '\0');
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0o1";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 1) && (BitVecLen(&bv) == 3);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0o10";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 8) && (*z == '\0');
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0o755";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecToInteger(&bv) == 0755) && (BitVecLen(&bv) == 9);
        Zstr z = "0x1f";
        u8   v = 0;
        StrReadFmt(z, "{}", v);
        return v == 31;
    }
        Zstr z = " 5";
        u8   v = 0;
        StrReadFmt(z, "{}", v);
        return v == 5;
    }
        Zstr z = "0xff";
        u8   v = 0;
        StrReadFmt(z, "{}", v);
        return v == 255;
    }
        Zstr z = "05";
        u8   v = 0;
        StrReadFmt(z, "{}", v);
        return v == 5;
    }
        Zstr z = "\\xZZ";            // '\', 'x', 'Z', 'Z'
        u8   v = 0;
        StrReadFmt(z, "{c}", v);
        bool ok = (v == 0x5C);       // '\'; mutant stores 42
        ok      = ok && (*z == 'x'); // only '\' consumed
        Zstr z = "A";
        u8   v = 0;
        StrReadFmt(z, "{a}", v);
        return v == 'a'; // mutants give 'A' (0x41) or '*' (42)
    }
        Zstr z = "a";
        u8   v = 0;
        StrReadFmt(z, "{A}", v);
        return v == 'A'; // mutant gives 'a' (0x61) or '*' (42)
    }
        u8   buf[4] = {0, 0, 0, 0};
        Zstr z      = "AB";
        StrReadFmt(z, "{c}", buf[0]);
        bool ok = (buf[0] == 'A');
        ok      = ok && (*z == 'B'); // exactly one byte consumed; mutant -> 0
        Zstr z    = "-inf";
        Zstr orig = z;
        StrReadFmt(z, "{}", v);
        // Real: consumed (z advanced) and v is -inf. Mutant: not consumed.
        return (z != orig) && F64IsInf(v) && (v < 0.0);
        Zstr z    = "-Inf";
        Zstr orig = z;
        StrReadFmt(z, "{}", v);
        return (z != orig) && F64IsInf(v) && (v < 0.0);
    }
        f64  v = 0.0;
        Zstr z = "5inf";
        StrReadFmt(z, "{}", v);
        // Real: advanced by 1 -> *z == 'i'. Mutant: advanced by 4 -> *z == '\0'.
        return double_equals(v, 5.0) && (*z == 'i');
        Zstr z    = "info";
        Zstr orig = z;
        StrReadFmt(z, "{}", v);
        // Real: not consumed (z unchanged). Mutant: consumed (z advanced).
        return (z == orig);
        f64  v = -1.0;
        Zstr z = " 3.14";
        StrReadFmt(z, "{}", v);
        // Real: v == 3.14. Mutant: parse fails, v left at -1.0.
        return double_equals(v, 3.14);
        Zstr z    = "1f";
        Zstr orig = z;
        StrReadFmt(z, "{}", v);
        // Real: rejected, not consumed (z unchanged). Mutant: consumed.
        return (z == orig);
        f64  v = SENTINEL;
        Zstr z = "0x";
        StrReadFmt(z, "{}", v);
    
        // Real code: rejected, v untouched. Mutant: accepted -> 0.0.
        f64  v = SENTINEL;
        Zstr z = "0b";
        StrReadFmt(z, "{}", v);
    
        return is_sentinel(v);
        f64  v = SENTINEL;
        Zstr z = "0o";
        StrReadFmt(z, "{}", v);
    
        return is_sentinel(v);
        f64  v = SENTINEL;
        Zstr z = "0X1F";
        StrReadFmt(z, "{}", v);
    
        // Real code: is_hex set via the 'X' branch, slice accepted, value 0.0.
        f64  v = SENTINEL;
        Zstr z = "0B11";
        StrReadFmt(z, "{}", v);
    
        return is_zero(v);
        f64  v = SENTINEL;
        Zstr z = "0O7";
        StrReadFmt(z, "{}", v);
    
        return is_zero(v);
        f64  v = SENTINEL;
        Zstr z = "12.5";
        StrReadFmt(z, "{}", v);
    
        return F64Abs(v - 12.5) < 1e-9;
        f64  v = SENTINEL;
        Zstr z = "0x1f";
        StrReadFmt(z, "{}", v);
    
        // Real: is_hex via lowercase 'x', accepted, StrToF64 -> 0.0.
    
        Zstr z = "3.5;";
        StrReadFmt(z, "{};", val);
    
        // On success the macro advances `z` to the cursor returned by
    
        Zstr z = "12.25";
        StrReadFmt(z, "{}", val);
    
        success = success && (ZstrLen(z) == 0);
    
        Zstr z = "1.5e2!";
        StrReadFmt(z, "{e}!", val);
    
        success = success && (ZstrLen(z) == 0);
    
        Zstr z = "-0.25";
        StrReadFmt(z, "{}", val);
    
        success = success && (ZstrLen(z) == 0);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0x3ff";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecLen(&bv) == 10) && (BitVecToInteger(&bv) == 0x3ff);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0xff";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecLen(&bv) == 8) && (BitVecToInteger(&bv) == 0xff);
        BitVec bv = BitVecInit(alloc_base);
        Zstr   z  = "0x10000";
        StrReadFmt(z, "{}", bv);
    
        bool ok = (BitVecLen(&bv) == 17) && (BitVecToInteger(&bv) == 0x10000);
        u8   v = 0;
        Zstr z = "\\x41";
        StrReadFmt(z, "{c}", v);
        return v == 0x41;
    }
        u8   v = 0;
        Zstr z = "\\x01";
        StrReadFmt(z, "{c}", v);
        return v == 0x01;
    }
        u8   v = 0;
        Zstr z = "\\x10";
        StrReadFmt(z, "{c}", v);
        return v == 0x10;
    }
        u8   v = 0;
        Zstr z = "\\x4f";
        StrReadFmt(z, "{c}", v);
        return v == 0x4f;
    }
    
        Zstr z = "78";
        StrReadFmt(z, "{o}", oct);
    
        Str  oct_text = IntToOctStr(&oct);
        f32  v = -1.0f;
        Zstr z = " ";
        StrReadFmt(z, "{c}", v);
        return f32_close(v, 0.0f);
    }
        f32  v = 0.0f;
        Zstr z = "inf";
        StrReadFmt(z, "{}", v);
        return v > 1e30f;
    }
        f32  v = 0.0f;
        Zstr z = "INF";
        StrReadFmt(z, "{}", v);
        return v > 1e30f;
    }
        f32  v = 0.0f;
        Zstr z = "nan";
        StrReadFmt(z, "{}", v);
        return v != v;                            // NaN is the only value not equal to itself
    }
        f32  v = 0.0f;
        Zstr z = "NAN";
        StrReadFmt(z, "{}", v);
        return v != v;
    }
        f32  v = 0.0f;
        Zstr z = "-inf";
        StrReadFmt(z, "{}", v);
        return v < -1e30f;
    }
        f32  v = 0.0f;
        Zstr z = "-inf";
        StrReadFmt(z, "{}", v);
        return v < -1e30f;
    }
        f32  v = 0.0f;
        Zstr z = "-INF";
        StrReadFmt(z, "{}", v);
        return v < -1e30f;
    }
        f32  v = 0.0f;
        Zstr z = "inf";
        StrReadFmt(z, "{}", v);
        return v > 1e30f; // 42.0 would fail this
    }
        f32  v = 0.0f;
        Zstr z = "1e+3";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 1000.0f);
    }
        f32  v = 0.0f;
        Zstr z = "1E+3";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 1000.0f);
    }
        f32  v = 0.0f;
        Zstr z = "2e-2";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 0.02f);
    }
        f32  v = 0.0f;
        Zstr z = "1e+3";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 1000.0f);
    }
        f32  v = 0.0f;
        Zstr z = "1e-3";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 0.001f);
    }
        f32  v = 0.0f;
        Zstr z = "+1.5";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 1.5f);
    }
        f32  v = 0.0f;
        Zstr z = "  3.5";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 3.5f);
    }
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "9z";
        StrReadFmt(z, "{}", v);
        bool ok = (IntCompare(&v, 9) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "5";
        StrReadFmt(z, "{}", v);
        bool ok = (IntCompare(&v, 5) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "+8";
        StrReadFmt(z, "{}", v);
        bool ok = (IntCompare(&v, 8) == 0);
        Int  v = IntFromStr("123", &alloc);
        Zstr z = "9_";
        StrReadFmt(z, "{}", v);
        bool ok = (IntCompare(&v, 123) == 0);
        Int  v = IntFromStr("200", &alloc);
        Zstr z = "0xFF";
        StrReadFmt(z, "{x}", v);
        bool ok = (IntCompare(&v, 200) == 0);
        Int  v = IntFromStr("200", &alloc);
        Zstr z = "0XFF";
        StrReadFmt(z, "{x}", v);
        bool ok = (IntCompare(&v, 200) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "ff";
        StrReadFmt(z, "{x}", v);
        bool ok = (IntCompare(&v, 255) == 0);
        Int  v = IntFromStr("5", &alloc);
        Zstr z = "0b1";
        StrReadFmt(z, "{b}", v);
        bool ok = (IntCompare(&v, 5) == 0);
        Int  v = IntFromStr("5", &alloc);
        Zstr z = "0B1";
        StrReadFmt(z, "{b}", v);
        bool ok = (IntCompare(&v, 5) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "101";
        StrReadFmt(z, "{b}", v);
        bool ok = (IntCompare(&v, 5) == 0);
        Int  v = IntFromStr("9", &alloc);
        Zstr z = "0o7";
        StrReadFmt(z, "{o}", v);
        bool ok = (IntCompare(&v, 9) == 0);
        Int  v = IntFromStr("9", &alloc);
        Zstr z = "0O7";
        StrReadFmt(z, "{o}", v);
        bool ok = (IntCompare(&v, 9) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "17";
        StrReadFmt(z, "{o}", v);
        bool ok = (IntCompare(&v, 15) == 0);
        Int  v = IntInit(ALLOCATOR_OF(&alloc));
        Zstr z = "   42";
        StrReadFmt(z, "{}", v);
        bool ok = (IntCompare(&v, 42) == 0);
        i8 i8_val = 0;
        z         = "-42";
        StrReadFmt(z, "{}", i8_val);
        success = success && (i8_val == -42);
        i16 i16_val = 0;
        z           = "-1234";
        StrReadFmt(z, "{}", i16_val);
        success = success && (i16_val == -1234);
        i32 i32_val = 0;
        z           = "-123456";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == -123456);
        i64 i64_val = 0;
        z           = "-1234567890";
        StrReadFmt(z, "{}", i64_val);
        success = success && (i64_val == -1234567890LL);
        u8 u8_val = 0;
        z         = "42";
        StrReadFmt(z, "{}", u8_val);
        success = success && (u8_val == 42);
        u16 u16_val = 0;
        z           = "1234";
        StrReadFmt(z, "{}", u16_val);
        success = success && (u16_val == 1234);
        u32 u32_val = 0;
        z           = "123456";
        StrReadFmt(z, "{}", u32_val);
        success = success && (u32_val == 123456);
        u64 u64_val = 0;
        z           = "1234567890";
        StrReadFmt(z, "{}", u64_val);
        success = success && (u64_val == 1234567890ULL);
        i8_val = 0;
        z      = "127";
        StrReadFmt(z, "{}", i8_val);
        success = success && (i8_val == 127);
        i8_val = 0;
        z      = "-128";
        StrReadFmt(z, "{}", i8_val);
        success = success && (i8_val == -128);
        u8_val = 0;
        z      = "255";
        StrReadFmt(z, "{}", u8_val);
        success = success && (u8_val == 255);
        u8_val = 0;
        z      = "0";
        StrReadFmt(z, "{}", u8_val);
        success = success && (u8_val == 0);
        i32_val = 0;
        z       = "000042";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == 42);
        i32_val = 0;
        z       = "-000042";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == -42);
        i32_val = 0;
        z       = "   42";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == 42);
        i32_val = 0;
        z       = "42   ";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == 42);
        i32_val = 0;
        z       = "  42  ";
        StrReadFmt(z, "{}", i32_val);
        success = success && (i32_val == 42);
        u32 val = 0;
        z       = "0xdeadbeef";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0xdeadbeef);
        val = 0;
        z   = "0xDEADBEEF";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0xDEADBEEF);
        val = 0;
        z   = "0x0";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0);
        val = 0;
        z   = "0xf";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0xf);
        val = 0;
        z   = "0xaBcDeF";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0xabcdef);
        i8 val = 0;
        z      = "0b101010";
        StrReadFmt(z, "{}", val);
        success = success && (val == 42);
        val = 0;
        z   = "0b0";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0);
        val = 0;
        z   = "0b1";
        StrReadFmt(z, "{}", val);
        success = success && (val == 1);
        i32 val = 0;
        z       = "0o755";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0755);
        val = 0;
        z   = "755";
        StrReadFmt(z, "{}", val);
        success = success && (val == 755);
        val = 0;
        z   = "0o0";
        StrReadFmt(z, "{}", val);
        success = success && (val == 0);
        val = 0;
        z   = "0o7";
        StrReadFmt(z, "{}", val);
        success = success && (val == 7);
        f32 f32_val = 0.0f;
        z           = "3.14159";
        StrReadFmt(z, "{}", f32_val);
        success = success && float_equals(f32_val, 3.14159f);
        f64 f64_val = 0.0;
        z           = "3.14159265359";
        StrReadFmt(z, "{}", f64_val);
        success = success && double_equals(f64_val, 3.14159265359);
        f64_val = 1.0;
        z       = "0.0";
        StrReadFmt(z, "{}", f64_val);
        success = success && double_equals(f64_val, 0.0);
        f64_val = 1.0;
        z       = "-0.0";
        StrReadFmt(z, "{}", f64_val);
        // -0.0 compares == to +0.0; the epsilon check captures the magnitude
        // regardless of which sign bit the parser landed on.
        f64_val = 0.0;
        z       = "42.0";
        StrReadFmt(z, "{}", f64_val);
        success = success && double_equals(f64_val, 42.0);
        f64_val = 0.0;
        z       = "0.42";
        StrReadFmt(z, "{}", f64_val);
        success = success && double_equals(f64_val, 0.42);
        f64 val = 0.0;
        z       = "1.23e4";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 12300.0);
        val = 0.0;
        z   = "1.23E4";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 12300.0);
        val = 0.0;
        z   = "1.23e+4";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 12300.0);
        val = 0.0;
        z   = "1.23e-4";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 0.000123);
        val = 0.0;
        z   = "1.0e0";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 1.0);
        val = 0.0;
        z   = "1.0E-0";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 1.0);
        val = 0.0;
        z   = "1.0e+0";
        StrReadFmt(z, "{}", val);
        success = success && double_equals(val, 1.0);
        Str s = StrInit(&alloc);
        z     = "Hello";
        StrReadFmt(z, "{}", s);
    
        Str expected = StrInitFromZstr("Hello", &alloc);
    
        z = "\"Hello, World!\"";
        StrReadFmt(z, "{s}", s);
    
        expected = StrInitFromZstr("Hello, World!", &alloc);
    
            z = "Allocator-backed";
            StrReadFmt(z, "{s}", ZstrIO(zs, alloc_base));
            success = success && (ZstrCompare(zs, "Allocator-backed") == 0);
    
            z = "\"Allocator-backed replacement\"";
            StrReadFmt(z, "{s}", ZstrIO(zs, alloc_base));
            success = success && (ZstrCompare(zs, "Allocator-backed replacement") == 0);
            zstr_deinit(&zs, alloc_base);
        Str name = StrInit(&alloc);
        z        = "Count: 42, Name: Alice";
        StrReadFmt(z, "Count: {}, Name: {}", num, name);
    
        success = success && (num == 42);
        f64 val = 0.0;
        z       = "Value: 3.14, Name: Bob";
        StrReadFmt(z, "Value: {}, Name: {}", val, name);
    
        success = success && double_equals(val, 3.14);
        i32 num = 42;
        z       = "Count: forty-two";
        StrReadFmt(z, "Count: {}", num);
        success = success && (num == 42);
        num = 42;
        z   = "Count: abc";
        StrReadFmt(z, "Count: {}", num);
        success = success && (num == 42);
        i8 small = 42;
        z        = "Value: 1000";
        StrReadFmt(z, "Value: {}", small);
        success = success && (small == 42);
        u8 u8_val = 0;
        z         = "A";
        StrReadFmt(z, "{c}", u8_val);
        WriteFmt("u8_val = {}, expected = {}, pass = {}\n", u8_val, 'A', (u8_val == 'A') ? "true" : "false");
        success = success && (u8_val == 'A');
        u8_val = 0;
        z      = "z";
        StrReadFmt(z, "{c}", u8_val);
        WriteFmt("u8_val = {}, expected = {}, pass = {}\n", u8_val, 'z', (u8_val == 'z') ? "true" : "false");
        success = success && (u8_val == 'z');
        i8 i8_val = 0;
        z         = "B";
        StrReadFmt(z, "{c}", i8_val);
        WriteFmt("i8_val = {}, expected = {}, pass = {}\n", i8_val, 'B', (i8_val == 'B') ? "true" : "false");
        success = success && (i8_val == 'B');
        i16 i16_val = 0;
        z           = "C";
        StrReadFmt(z, "{c}", i16_val);
        WriteFmt("i16_val = {}, expected = {}, pass = {}\n", i16_val, 'C', (i16_val == 'C') ? "true" : "false");
        success = success && (i16_val == 'C');
        i32 i32_val = 0;
        z           = "D";
        StrReadFmt(z, "{c}", i32_val);
        WriteFmt("i32_val = {}, expected = {}, pass = {}\n", i32_val, 'D', (i32_val == 'D') ? "true" : "false");
        success = success && (i32_val == 'D');
        i64 i64_val = 0;
        z           = "E";
        StrReadFmt(z, "{c}", i64_val);
        WriteFmt("i64_val = {}, expected = {}, pass = {}\n", i64_val, 'E', (i64_val == 'E') ? "true" : "false");
        success = success && (i64_val == 'E');
        u16 u16_val = 0;
        z           = "F";
        StrReadFmt(z, "{c}", u16_val);
        WriteFmt("u16_val = {}, expected = {}, pass = {}\n", u16_val, 'F', (u16_val == 'F') ? "true" : "false");
        success = success && (u16_val == 'F');
        u32 u32_val = 0;
        z           = "G";
        StrReadFmt(z, "{c}", u32_val);
        WriteFmt("u32_val = {}, expected = {}, pass = {}\n", u32_val, 'G', (u32_val == 'G') ? "true" : "false");
        success = success && (u32_val == 'G');
        u64 u64_val = 0;
        z           = "H";
        StrReadFmt(z, "{c}", u64_val);
        WriteFmt("u64_val = {}, expected = {}, pass = {}\n", u64_val, 'H', (u64_val == 'H') ? "true" : "false");
        success = success && (u64_val == 'H');
        u16_val = 0;
        z       = "AB";
        StrReadFmt(z, "{c}", u16_val);
        bool u16_multi_pass = (ZstrCompareN((Zstr)&u16_val, "AB", 2) == 0);
        WriteFmt("u16_val multi-char test: comparing memory with 'AB', pass = {}\n", u16_multi_pass ? "true" : "false");
        i16_val = 0;
        z       = "CD";
        StrReadFmt(z, "{c}", i16_val);
        bool i16_multi_pass = (ZstrCompareN((Zstr)&i16_val, "CD", 2) == 0);
        WriteFmt("i16_val multi-char test: comparing memory with 'CD', pass = {}\n", i16_multi_pass ? "true" : "false");
        u32_val = 0;
        z       = "EFGH";
        StrReadFmt(z, "{c}", u32_val);
        bool u32_multi_pass = (ZstrCompareN((Zstr)&u32_val, "EFGH", 4) == 0);
        WriteFmt("u32_val multi-char test: comparing memory with 'EFGH', pass = {}\n", u32_multi_pass ? "true" : "false");
        i32_val = 0;
        z       = "IJKL";
        StrReadFmt(z, "{c}", i32_val);
        bool i32_multi_pass = (ZstrCompareN((Zstr)&i32_val, "IJKL", 4) == 0);
        WriteFmt("i32_val multi-char test: comparing memory with 'IJKL', pass = {}\n", i32_multi_pass ? "true" : "false");
        u64_val = 0;
        z       = "MNOPQRST";
        StrReadFmt(z, "{c}", u64_val);
        bool u64_multi_pass = (ZstrCompareN((Zstr)&u64_val, "MNOPQRST", 8) == 0);
        WriteFmt(
        i64_val = 0;
        z       = "UVWXYZab";
        StrReadFmt(z, "{c}", i64_val);
        bool i64_multi_pass = (ZstrCompareN((Zstr)&i64_val, "UVWXYZab", 8) == 0);
        WriteFmt(
        f32 f32_val = 0.0f;
        z           = "A";
        StrReadFmt(z, "{c}", f32_val);
        bool f32_pass = (f32_val == (f32)'A');
        WriteFmt("f32_val = {}, expected = {}, pass = {}\n", f32_val, (f32)'A', f32_pass ? "true" : "false");
        f64 f64_val = 0.0;
        z           = "B";
        StrReadFmt(z, "{c}", f64_val);
        bool f64_pass = (f64_val == (f64)'B');
        WriteFmt("f64_val = {}, expected = {}, pass = {}\n", f64_val, (f64)'B', f64_pass ? "true" : "false");
        u8_val = 0;
        z      = "~";
        StrReadFmt(z, "{c}", u8_val);
        bool tilde_pass = (u8_val == '~');
        WriteFmt("u8_val = {}, expected = {} (~), pass = {}\n", u8_val, '~', tilde_pass ? "true" : "false");
        u32_val = 0;
        z       = "XY";
        StrReadFmt(z, "{c}", u32_val);
        bool xy_pass = (ZstrCompareN((Zstr)&u32_val, "XY", 2) == 0);
        WriteFmt("u32_val partial test: comparing memory with 'XY', pass = {}\n", xy_pass ? "true" : "false");
        u64_val = 0;
        z       = "abc";
        StrReadFmt(z, "{c}", u64_val);
        bool abc_pass = (ZstrCompareN((Zstr)&u64_val, "abc", 3) == 0);
        WriteFmt("u64_val partial test: comparing memory with 'abc', pass = {}\n", abc_pass ? "true" : "false");
        Str str_val = StrInit(&alloc);
        z           = "Hello";
        StrReadFmt(z, "{c}", str_val);
        Str  expected = StrInitFromZstr("Hello", &alloc);
        bool str_pass = (StrCmp(&str_val, &expected) == 0);
        str_val = StrInit(&alloc);
        z       = "\"World\"";
        StrReadFmt(z, "{cs}", str_val);
        expected             = StrInitFromZstr("World", &alloc);
        bool quoted_str_pass = (StrCmp(&str_val, &expected) == 0);
    
            z = in;
            StrReadFmt(z, "{a}", result);
    
            WriteFmt("Test 1 - :a (lowercase)\n");
    
            z = in;
            StrReadFmt(z, "{as}", result);
    
            WriteFmt("Test 1.1 - :as (lowercase string single word)\n");
    
            z = in;
            StrReadFmt(z, "{A}", result);
    
            WriteFmt("Test 2 - :A (uppercase)\n");
    
            z = in;
            StrReadFmt(z, "{A} {A}", result1, result2);
    
            WriteFmt("Test 2 - :A (uppercase with split format)\n");
    
            z = in;
            StrReadFmt(z, "{As}{A}", result1, result2);
            // result1 must consume first word only
            // result2 must consume the space after hello and then everything after it
    
            z = in;
            StrReadFmt(z, "{as}", result);
    
            WriteFmt("Test 3 - :a with quoted string\n");
    
            z = in;
            StrReadFmt(z, "{As}", result);
    
            WriteFmt("Test 4 - :A with mixed alphanumeric\n");
    
            z = in;
            StrReadFmt(z, "{c}", result);
    
            WriteFmt("Test 5 - :c (no case conversion)\n");
        BitVec bv1 = BitVecInit(alloc_base);
        z          = "10110";
        StrReadFmt(z, "{}", bv1);
        Str result1 = BitVecToStr(&bv1);
        success     = success && (ZstrCompare(StrBegin(&result1), "10110") == 0);
        BitVec bv2 = BitVecInit(alloc_base);
        z          = "0xDEAD";
        StrReadFmt(z, "{}", bv2);
        u64 value2 = BitVecToInteger(&bv2);
        success    = success && (value2 == 0xDEAD);
        BitVec bv3 = BitVecInit(alloc_base);
        z          = "0o755";
        StrReadFmt(z, "{}", bv3);
        u64 value3 = BitVecToInteger(&bv3);
        success    = success && (value3 == 0755);
        BitVec bv4 = BitVecInit(alloc_base);
        z          = "   1101";
        StrReadFmt(z, "{}", bv4);
        Str result4 = BitVecToStr(&bv4);
        success     = success && (ZstrCompare(StrBegin(&result4), "1101") == 0);
        BitVec bv5 = BitVecInit(alloc_base);
        z          = "0";
        StrReadFmt(z, "{}", bv5);
        Str result5 = BitVecToStr(&bv5);
        success     = success && (ZstrCompare(StrBegin(&result5), "0") == 0);
    
        z = "123456789012345678901234567890";
        StrReadFmt(z, "{}", dec);
        dec_text = IntToStr(&dec);
        success  = success && (ZstrCompare(StrBegin(&dec_text), "123456789012345678901234567890") == 0);
    
        z = "deadbeefcafebabe1234";
        StrReadFmt(z, "{x}", hex);
        hex_text = IntToHexStr(&hex);
        success  = success && (ZstrCompare(StrBegin(&hex_text), "deadbeefcafebabe1234") == 0);
    
        z = "10100011";
        StrReadFmt(z, "{b}", bin);
        bin_text = IntToBinary(&bin);
        success  = success && (ZstrCompare(StrBegin(&bin_text), "10100011") == 0);
    
        z = "755";
        StrReadFmt(z, "{o}", oct);
        oct_text = IntToOctStr(&oct);
        success  = success && (ZstrCompare(StrBegin(&oct_text), "755") == 0);
    
        z = "1234567890.012345";
        StrReadFmt(z, "{}", dec);
        dec_text = FloatToStr(&dec);
        success  = success && (ZstrCompare(StrBegin(&dec_text), "1234567890.012345") == 0);
    
        z = "1.234567e+04";
        StrReadFmt(z, "{e}", sci);
        sci_text = FloatToStr(&sci);
        success  = success && (ZstrCompare(StrBegin(&sci_text), "12345.67") == 0);
    
        z = "-0.00125";
        StrReadFmt(z, "{}", neg);
        neg_text = FloatToStr(&neg);
        success  = success && (ZstrCompare(StrBegin(&neg_text), "-0.00125") == 0);
        Zstr z = "42!";
        u8   v = 0;
        StrReadFmt(z, "{}", v);
        // Live: v == 42 and z advanced past "42" (now points at "!").
        return v == 42 && z[0] == '!';
        Zstr beg = z;
        u8   v   = 0;
        StrReadFmt(z, "{c}", v);
        bool ok = (v == 0x41);     // 'A'; mutants give 0x5C ('\') or 42 ('*')
        ok      = ok && (*z == 0); // all 4 bytes consumed; mutants leave "x41"
        Zstr z = "\\x00";      // '\', 'x', '0', '0'
        u8   v = 0xAA;         // poison so a no-write is detectable too
        StrReadFmt(z, "{c}", v);
        bool ok = (v == 0x00); // mutant stores 0x5C ('\')
        ok      = ok && (*z == 0);
        Zstr z = "\\x";              // '\', 'x', then NUL
        u8   v = 0;
        StrReadFmt(z, "{c}", v);
        bool ok = (v == 0x5C);       // '\' salvaged; mutants store 42 ('*')
        ok      = ok && (*z == 'x'); // only the '\' consumed
        Zstr start = input;
        u16  v     = 0;
        StrReadFmt(input, "{>2r}", v); // advances `input` on success
        return (input != start) && (v == 0x1234);
    }
        u16  v        = 0;
        u16  expected = IS_LITTLE_ENDIAN() ? (u16)0x3412 : (u16)0x1234;
        StrReadFmt(input, "{^2r}", v); // real: resolves NATIVE; mutant: LOG_FATAL
        return (input != start) && (v == expected);
    }
        i32  v = 0;
        Zstr z = "+5";
        StrReadFmt(z, "{}", v);
        return v == 5;
    }
        f32  v = 7.5f;
        Zstr z = "1f";
        StrReadFmt(z, "{}", v);
        // Real rejects "1f" -> v stays 7.5. Mutant bypasses the gate.
        ok = ok && (v == 7.5f);
        f32  v = 0.0f;
        Zstr z = "A";
        StrReadFmt(z, "{c}", v); // 'A' == 0x41 == 65
        return f32_close(v, 65.0f);
    }
        f32  v = 0.0f;
        Zstr z = "12g3";
        StrReadFmt(z, "{}", v);
        return f32_close(v, 12.0f);
    }
        Str  s = StrInit(&alloc);
        Zstr z = "\\x41BC"; // backslash, x, 4, 1, B, C  ->  'A', 'B', 'C'
        StrReadFmt(z, "{}", s);
    
        Str  expected = StrInitFromZstr("ABC", &alloc);
        Str  s = StrInit(&alloc);
        Zstr z = "\\x41"; // -> 'A'
        StrReadFmt(z, "{}", s);
    
        Str  expected = StrInitFromZstr("A", &alloc);
        Str  s = StrInit(&alloc);
        Zstr z = "\\x61";                             // -> 'a'
        StrReadFmt(z, "{A}", s);
    
        Str  expected = StrInitFromZstr("A", &alloc); // uppercased
        // "\x41BC" inside double quotes -> decoded "ABC"
        Zstr z = "\"\\x41BC\"";
        StrReadFmt(z, "{s}", s);
    
        Str  expected = StrInitFromZstr("ABC", &alloc);
        Str  s = StrInit(&alloc);
        Zstr z = "\"\\x41\""; // quoted -> 'A'
        StrReadFmt(z, "{s}", s);
    
        Str  expected = StrInitFromZstr("A", &alloc);
        Str  s = StrInit(&alloc);
        Zstr z = "\"\\x61\"";                         // quoted -> 'a'
        StrReadFmt(z, "{As}", s);
    
        Str  expected = StrInitFromZstr("A", &alloc); // uppercased
            Zstr     in = "2021-01-01T00:00:00Z";
            DateTime d  = {0};
            StrReadFmt(in, "{}", d);
            ok = ok && d.year == 2021 && d.month == 1 && d.day == 1 && d.hour == 0 && d.minute == 0 && d.second == 0 &&
                 d.nanosecond == 0 && d.utc_offset_seconds == 0 && d.weekday == 5 /* Friday, derived on parse */;
            Zstr     in = "2021-01-01T05:30:00+05:30";
            DateTime d  = {0};
            StrReadFmt(in, "{}", d);
            ok = ok && d.year == 2021 && d.hour == 5 && d.minute == 30 && d.utc_offset_seconds == 19800;
        }
            Zstr     in = "2020-12-31T14:30:00-09:30";
            DateTime d  = {0};
            StrReadFmt(in, "{}", d);
            ok = ok && d.year == 2020 && d.month == 12 && d.day == 31 && d.hour == 14 && d.minute == 30 &&
                 d.utc_offset_seconds == -34200;
            Zstr     in = "2021-01-01T00:00:00.123456789Z";
            DateTime d  = {0};
            StrReadFmt(in, "{}", d);
            ok = ok && d.nanosecond == 123456789 && d.utc_offset_seconds == 0;
        }
        Zstr p     = "ff";
        Zstr start = p;
        StrReadFmt(p, "{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}", v); // exactly 32 'x'
        return (p == start) && (v == 0);
    }
        Zstr p     = "5";
        Zstr start = p;
        StrReadFmt(p, "{11111111111111111111111111111111}", v); // valid 32-char width spec
        return (p == start) && (v == 999);
    }
        Str              out = StrInit(ALLOCATOR_OF(&a));
        Zstr             p   = "\\n\\n#rest";
        StrReadFmt(p, "{}#", out);
        bool ok = (StrLen(&out) == 2) && (StrBegin(&out)[0] == '\n') && (StrBegin(&out)[1] == '\n');
        StrDeinit(&out);
        {
            Zstr p = "0xff";
            StrReadFmt(p, "{}", v);
            if (v != 255)
                return false;
            Zstr start = p;
            u8   w     = 7;
            StrReadFmt(p, "{}", w);
            if (p != start || w != 7) // real: read fails, cursor + dest untouched
                return false;
        // read; the `max_read_len = rem_in` survivor would cap it at 42.
        Zstr p = "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""; // 50 'a' quoted
        StrReadFmt(p, "{s}", out);
        bool ok = (StrLen(&out) == 50);
        StrDeinit(&out);
        Float            f     = FloatInit(ab);
        (void)FloatTryFromStr(&f, "99"); // sentinel
        StrReadFmt(in, "{}", f);
        Str  t  = FloatToStr(&f);
        bool ok = (ZstrCompare(StrBegin(&t), expect) == 0);
        f64  v = SENTINEL;
        Zstr z = "inf";
        StrReadFmt(z, "{}", v);
        return F64IsInf(v) && v > 0;
    }
        f64  a = SENTINEL, b = SENTINEL, c = SENTINEL;
        Zstr za = "INF", zb = "nan", zc = "NaN";
        StrReadFmt(za, "{}", a);
        StrReadFmt(zb, "{}", b);
        StrReadFmt(zc, "{}", c);
        Zstr za = "INF", zb = "nan", zc = "NaN";
        StrReadFmt(za, "{}", a);
        StrReadFmt(zb, "{}", b);
        StrReadFmt(zc, "{}", c);
        return F64IsInf(a) && F64IsNan(b) && F64IsNan(c);
        StrReadFmt(za, "{}", a);
        StrReadFmt(zb, "{}", b);
        StrReadFmt(zc, "{}", c);
        return F64IsInf(a) && F64IsNan(b) && F64IsNan(c);
    }
        f64  a = SENTINEL, b = SENTINEL;
        Zstr za = "-inf", zb = "-INF";
        StrReadFmt(za, "{}", a);
        StrReadFmt(zb, "{}", b);
        return F64IsInf(a) && a < 0 && F64IsInf(b) && b < 0;
        Zstr za = "-inf", zb = "-INF";
        StrReadFmt(za, "{}", a);
        StrReadFmt(zb, "{}", b);
        return F64IsInf(a) && a < 0 && F64IsInf(b) && b < 0;
    }
        f64  v = SENTINEL;
        Zstr z = "1234";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 1234.0);
    }
        f64  v = SENTINEL;
        Zstr z = "0x1f";
        StrReadFmt(z, "{}", v);
        // accepted -> StrToF64("0x1f") parses leading 0 -> 0.0.
        return f64_is(v, 0.0);
        f64  v = SENTINEL;
        Zstr z = "0b11";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 0.0);
    }
        f64  v = SENTINEL;
        Zstr z = "0o7";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 0.0);
    }
        f64  v = SENTINEL;
        Zstr z = "0b101";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 0.0);
    }
        f64  v = SENTINEL;
        Zstr z = "0o17";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 0.0);
    }
        f64  v = SENTINEL;
        Zstr z = "0o70";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 0.0);
    }
        f64  v = SENTINEL;
        Zstr z = "1e+5";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 100000.0);
    }
        f64  v = SENTINEL;
        Zstr z = "1.2.3";
        StrReadFmt(z, "{}", v);
        // The f64 scanner stops the token at the 2nd '.', so the slice is "1.2" and
        // parses to 1.2, leaving ".3" unconsumed.  has_decimal must gate so a
        f64  v = SENTINEL;
        Zstr z = "12e";
        StrReadFmt(z, "{}", v);
        return f64_is(v, 12.0);
    }
        BitVec         bv  = BitVecInit(&dbg.base);
        Zstr           z   = "0x1";
        StrReadFmt(z, "{}", bv);
        bool ok = (BitVecToInteger(&bv) == 1) && (BitVecLen(&bv) == 4); // min-width clamp
        BitVecDeinit(&bv);
        BitVec           bv    = BitVecInit(&alloc.base);
        Zstr             z     = "0xDEAD";
        StrReadFmt(z, "{}", bv);
        bool ok = (BitVecToInteger(&bv) == 0xDEAD) && (BitVecLen(&bv) == 16);
        BitVecDeinit(&bv);
        BitVec         bv  = BitVecInit(&dbg.base);
        Zstr           z   = "0o1";
        StrReadFmt(z, "{}", bv);
        bool ok = (BitVecToInteger(&bv) == 1) && (BitVecLen(&bv) == 3);
        BitVecDeinit(&bv);
        BitVec         bv  = BitVecInit(&dbg.base);
        Zstr           z   = "10110";
        StrReadFmt(z, "{}", bv);
        bool ok = (BitVecLen(&bv) == 5) && (BitVecToInteger(&bv) == 13);
        BitVecDeinit(&bv);
        Int            v   = IntInit(&dbg.base);
        Zstr           z   = "12345";
        StrReadFmt(z, "{}", v);
        Str  t  = IntToStr(&v);
        bool ok = (ZstrCompare(StrBegin(&t), "12345") == 0);
        Int              v     = IntInit(&alloc.base);
        Zstr             z     = "+99";
        StrReadFmt(z, "{}", v);
        Str  t  = IntToStr(&v);
        bool ok = (ZstrCompare(StrBegin(&t), "99") == 0);
        Int              v     = IntInit(&alloc.base);
        Zstr             z     = "ff";
        StrReadFmt(z, "{x}", v);
        Str  t  = IntToStr(&v);
        bool ok = (ZstrCompare(StrBegin(&t), "255") == 0);
        Float          f   = FloatInit(&dbg.base);
        Zstr           z   = "3.14159";
        StrReadFmt(z, "{}", f);
        Str  t  = FloatToStr(&f);
        bool ok = (ZstrCompare(StrBegin(&t), "3.14159") == 0);
        Str            s   = StrInit(ALLOCATOR_OF(&dbg));
        Zstr           p   = input;
        StrReadFmt(p, fmt, s); // reader frees s on the unterminated/error branch
        bool ok = (DebugAllocatorLiveCount(&dbg) == 0) && (DebugAllocatorLiveBytes(&dbg) == 0);
        DebugAllocatorDeinit(&dbg);
        BitVec         bv  = BitVecInit(ALLOCATOR_OF(&dbg));
        Zstr           p   = input;
        StrReadFmt(p, "{}", bv);
        BitVecDeinit(&bv);
        bool ok = (DebugAllocatorLiveCount(&dbg) == 0) && (DebugAllocatorLiveBytes(&dbg) == 0);
        Str            s   = StrInit(ALLOCATOR_OF(&dbg));
        Zstr           p   = "aaaaaaaaaaaaaaaaaaaaaaaa\\q"; // 24 'a' + invalid \q
        StrReadFmt(p, "{}", s);
        bool ok = (DebugAllocatorLiveCount(&dbg) == 0) && (DebugAllocatorLiveBytes(&dbg) == 0);
        DebugAllocatorDeinit(&dbg);
        Float          fv  = FloatInit(ALLOCATOR_OF(&dbg));
        Zstr           p   = "1e99999999999999999999999999999999999999999999999999";
        StrReadFmt(p, "{}", fv);
        FloatDeinit(&fv);
        bool ok = (DebugAllocatorLiveCount(&dbg) == 0) && (DebugAllocatorLiveBytes(&dbg) == 0);
        Zstr input = "42";
        Zstr start = input;
        StrReadFmt(input, "{}", value);
        bool ok = (input != start); // pointer advanced => read succeeded
        Zstr input = "2.5";
        Zstr start = input;
        StrReadFmt(input, "{}", value);
        bool ok = (input != start); // pointer advanced => read succeeded
Last updated on