diff options
Diffstat (limited to 'nss/buf.c')
-rw-r--r-- | nss/buf.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/nss/buf.c b/nss/buf.c new file mode 100644 index 0000000..75c62f9 --- /dev/null +++ b/nss/buf.c @@ -0,0 +1,92 @@ +#define _GNU_SOURCE +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +#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; +} |