Skip to content

BufAppendFmt

Description

Append encoded bytes to the end of buf. Existing contents are preserved; new bytes land after BufLength(buf). Directives are {<Nr} / {>Nr} with N in {1, 2, 4, 8}.

Success

Returns true; buf extended by exactly the encoded bytes.

Failure

Returns false on format-parse error or grow-buffer failure. buf may be left partially extended.

Usage example (Cross-references)

Usage examples (Cross-references)
        u16 qtype  = (u16)type;
        u16 qclass = 1u;
        return BufAppendFmt(out, "{>2r}{>2r}", qtype, qclass);
    }
        Buf              b     = BufInit(&alloc);
        BufWriteU8(&b, 0x99); // existing byte; append must preserve
        bool     ok       = BufAppendFmt(&b, "{<2r}{>4r}", (u16)0xCAFE, (u32)0xDEADBEEF);
        const u8 expect[] = {0x99, 0xFE, 0xCA, 0xDE, 0xAD, 0xBE, 0xEF};
        ok                = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        Buf              b     = BufInit(&alloc);
        // Reserve a 4-byte length placeholder followed by 8 bytes of body.
        BufAppendFmt(&b, "{<4r}", (u32)0);
        BufWriteU64LE(&b, 0x1122334455667788ull);
        // Patch the placeholder with the real value.
        DefaultAllocator alloc = DefaultAllocatorInit();
        Buf              b     = BufInit(&alloc);
        BufAppendFmt(&b, "{<2r}{>4r}{<8r}", (u16)0x1234, (u32)0xDEADBEEF, (u64)0x0102030405060708ull);
    
        BufIter it = BufIterFromBuf(&b);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Buf              b     = BufInit(&alloc);
        BufAppendFmt(&b, "{<2r}", (u16)0xABCD); // only 2 bytes; reader wants 6
    
        BufIter it    = BufIterFromBuf(&b);
        DefaultAllocator alloc    = DefaultAllocatorInit();
        Buf              b        = BufInit(&alloc);
        bool             ok       = BufAppendFmt(&b, "{<1r}", (u8)0x7E);
        const u8         expect[] = {0x7E};
        ok = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        DefaultAllocator alloc    = DefaultAllocatorInit();
        Buf              b        = BufInit(&alloc);
        bool             ok       = BufAppendFmt(&b, "{<8r}", (i64)0x0102030405060708ll);
        const u8         expect[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
        ok = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
            u64 u;
        } in              = {.u = 0x0102030405060708ull};
        bool     ok       = BufAppendFmt(&b, "{<8r}", in.f);
        const u8 expect[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
        ok                = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        Buf              b     = BufInit(&alloc);
    
        bool r = BufAppendFmt(&b, "{>4r}", (u32)0xAABBCCDD);
    
        const u8 *d  = BufData(&b);
        Buf              b     = BufInit(&alloc);
    
        bool ok = BufAppendFmt(&b, "{<1r}", (u8)0xAB);
    
        BufIter it  = BufIterFromBuf(&b);
    // Append the 15 reserved header bytes (all zero).
    static void put_reserved15(Buf *b) {
        BufAppendFmt(b, "{>8r}{>4r}{>2r}{>1r}", (u64)0, (u32)0, (u16)0, (u8)0);
    }
    // Append the six big-endian u32 counts.
    static void put_counts(Buf *b, u32 timecnt, u32 typecnt) {
        BufAppendFmt(b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)0, (u32)0, (u32)0, timecnt, typecnt, (u32)0);
    }
    static void put_body(Buf *b, bool wide, i64 t0, i64 t1, i32 std_off, i32 dst_off) {
        if (wide) {
            BufAppendFmt(b, "{>8r}{>8r}", t0, t1);
        } else {
            BufAppendFmt(b, "{>4r}{>4r}", (i32)t0, (i32)t1);
            BufAppendFmt(b, "{>8r}{>8r}", t0, t1);
        } else {
            BufAppendFmt(b, "{>4r}{>4r}", (i32)t0, (i32)t1);
        }
        BufAppendFmt(b, "{>1r}{>1r}", (u8)1, (u8)0);               // type indices: DST then STD
            BufAppendFmt(b, "{>4r}{>4r}", (i32)t0, (i32)t1);
        }
        BufAppendFmt(b, "{>1r}{>1r}", (u8)1, (u8)0);               // type indices: DST then STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", std_off, (u8)0, (u8)0); // ttinfo[0] STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", dst_off, (u8)1, (u8)0); // ttinfo[1] DST
        }
        BufAppendFmt(b, "{>1r}{>1r}", (u8)1, (u8)0);               // type indices: DST then STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", std_off, (u8)0, (u8)0); // ttinfo[0] STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", dst_off, (u8)1, (u8)0); // ttinfo[1] DST
    }
        BufAppendFmt(b, "{>1r}{>1r}", (u8)1, (u8)0);               // type indices: DST then STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", std_off, (u8)0, (u8)0); // ttinfo[0] STD
        BufAppendFmt(b, "{>4r}{>1r}{>1r}", dst_off, (u8)1, (u8)0); // ttinfo[1] DST
    }
    
    static void build_v1(Buf *b) {
        BufAppendFmt(b, "TZif{>1r}", (u8)0);                  // magic + version 1
        put_reserved15(b);
        put_counts(b, 2, 2);
        // computation is exercised: a wrong size mislands the v2 header and
        // the parse fails. v1_data = 2*4 + 2*1 + 2*6 + 4 + 1*8 + 2 + 2 = 38.
        BufAppendFmt(b, "TZif{>1r}", (u8)'2');
        put_reserved15(b);
        BufAppendFmt(b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(b, "TZif{>1r}", (u8)'2');
        put_reserved15(b);
        BufAppendFmt(b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0); // 38 bytes
        // v2 header + 8-byte-time data block (the authoritative one).
        put_reserved15(b);
        BufAppendFmt(b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0); // 38 bytes
        // v2 header + 8-byte-time data block (the authoritative one).
        BufAppendFmt(b, "TZif{>1r}", (u8)'2');
        BufAppendFmt(b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0); // 38 bytes
        // v2 header + 8-byte-time data block (the authoritative one).
        BufAppendFmt(b, "TZif{>1r}", (u8)'2');
        put_reserved15(b);
        put_counts(b, 2, 2);
        DefaultAllocator a = DefaultAllocatorInit();
        Buf              b = BufInit(&a);
        BufAppendFmt(&b, "TZif{>1r}", (u8)0);
        put_reserved15(&b);
        put_counts(&b, 0, 2);
        put_reserved15(&b);
        put_counts(&b, 0, 2);
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-14400, (u8)1, (u8)0); // ttinfo[0] DST
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-18000, (u8)0, (u8)0); // ttinfo[1] STD
        i32  off = 0;
        put_counts(&b, 0, 2);
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-14400, (u8)1, (u8)0); // ttinfo[0] DST
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-18000, (u8)0, (u8)0); // ttinfo[1] STD
        i32  off = 0;
        bool ok  = TzifOffsetFromBuf(BufData(&b), BufLength(&b), 0, &off);
        DefaultAllocator a = DefaultAllocatorInit();
        Buf              b = BufInit(&a);
        BufAppendFmt(&b, "TZif{>1r}", (u8)0);
        put_reserved15(&b);
        put_counts(&b, 0, 1);
        put_reserved15(&b);
        put_counts(&b, 0, 1);
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-14400, (u8)1, (u8)0); // sole ttinfo: DST, no STD
        i32  off = 7;
        bool ok  = TzifOffsetFromBuf(BufData(&b), BufLength(&b), 0, &off);
        DefaultAllocator a = DefaultAllocatorInit();
        Buf              b = BufInit(&a);
        BufAppendFmt(&b, "TZif{>1r}", (u8)'2');
        put_reserved15(&b);
        BufAppendFmt(&b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(&b, "TZif{>1r}", (u8)'2');
        put_reserved15(&b);
        BufAppendFmt(&b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(&b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0);
        BufAppendFmt(&b, "TZif{>1r}", (u8)'2');
        put_reserved15(&b);
        BufAppendFmt(&b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(&b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0);
        BufAppendFmt(&b, "TZif{>1r}", (u8)'2');
        put_reserved15(&b);
        BufAppendFmt(&b, "{>4r}{>4r}{>4r}{>4r}{>4r}{>4r}", (u32)2, (u32)2, (u32)1, (u32)2, (u32)2, (u32)4);
        BufAppendFmt(&b, "{>8r}{>8r}{>8r}{>8r}{>4r}{>2r}", (u64)0, (u64)0, (u64)0, (u64)0, (u32)0, (u16)0);
        BufAppendFmt(&b, "TZif{>1r}", (u8)'2');
        put_reserved15(&b);
        put_counts(&b, 0, 1);
        put_reserved15(&b);
        put_counts(&b, 0, 1);
        BufAppendFmt(&b, "{>4r}{>1r}{>1r}", (i32)-14400, (u8)1, (u8)0); // v2 sole ttinfo: DST, no STD
        i32  off = 7;
        bool ok  = TzifOffsetFromBuf(BufData(&b), BufLength(&b), 0, &off);
Last updated on