#define _GNU_SOURCE #include #include #include #include #include #include #include "cgen.h" #include "buf.h" #include "config/debug.h" int write_buf(char** buf, size_t * buflen, const char* val) { /* write_buf will not write outside of (*buf)[0..(*buflen-1)] * if *buflen > strlen(val), then write_buf will ensure that *buf points to a null-terminated string. * on success, write_buf will advance *buf to the next free char, * set *buflen to indicate the quantity of remaining space, * and return 0. * on error, write_buf will set errno, return 1, and will not modify *buf or *buflen. * *buf and val should not overlap. */ LET(size_t copy_amt = strlen(val) + 1, copy_amt == 0, "Integer overflow.", out_err_overflow); if (*buflen < copy_amt) goto out_err_range; memcpy(*buf, val, copy_amt); *buf += copy_amt; *buflen -= copy_amt; return 0; out_err_overflow: errno = EOVERFLOW; return 1; out_err_range: errno = ERANGE; return 1; } int format_buf(char** buf, size_t* buflen, const char* fmt, ...) { /* format_buf will not write outside of (*buf)[0..(*buflen-1)] * if *buflen > 0, format_buf will ensure that *buf points to a null-terminated string. * on success, format_buf will advance *buf to the next free char, * set *buflen to indicate the quantity of remaining space, * and return 0. * on error, format_buf will set errno, return 1, and will not modify *buf or *buflen. * *buf should not overlap with fmt or any optional arguments. */ if (*buflen < 1) { errno = ERANGE; return 1; } va_list ap; va_start(ap, fmt); int status = vsnprintf(*buf, *buflen, fmt, ap); int err = errno; va_end(ap); if (status < 0) goto out_err; size_t written = (size_t) status; err = ERANGE; if (written >= *buflen) goto out_err; err = EOVERFLOW; LET(written = written + 1, written == 0, "Integer overflow.", out_err); *buf += written; *buflen -= written; return 0; out_err: (*buf)[*buflen-1] = '\0'; errno = err; return 1; }