Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/nss/buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'nss/buf.c')
-rw-r--r--nss/buf.c92
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;
+}