--- /dev/null
+#ifndef UTIL_LINUX_BUFFER
+#define UTIL_LINUX_BUFFER
+
+#include "c.h"
+
+struct ul_buffer {
+ char *begin; /* begin of the data */
+ char *end; /* current end of data */
+
+ size_t sz; /* allocated space for data */
+ size_t chunksize;
+};
+
+#define UL_INIT_BUFFER { .begin = NULL }
+
+void ul_buffer_reset_data(struct ul_buffer *buf);
+void ul_buffer_free_data(struct ul_buffer *buf);
+int ul_buffer_is_empty(struct ul_buffer *buf);
+void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz);
+void ul_buffer_refer_string(struct ul_buffer *buf, char *str);
+int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz);
+int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz);
+int ul_buffer_append_string(struct ul_buffer *buf, const char *str);
+int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str);
+int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz);
+char *ul_buffer_get_data(struct ul_buffer *buf);
+
+#endif /* UTIL_LINUX_BUFFER */
--- /dev/null
+
+#include "buffer.h"
+
+void ul_buffer_reset_data(struct ul_buffer *buf)
+{
+ if (buf->begin)
+ buf->begin[0] = '\0';
+ buf->end = buf->begin;
+}
+
+void ul_buffer_free_data(struct ul_buffer *buf)
+{
+ assert(buf);
+
+ free(buf->begin);
+ buf->begin = NULL;
+ buf->end = NULL;
+ buf->sz = 0;
+}
+
+void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz)
+{
+ buf->chunksize = sz;
+}
+
+int ul_buffer_is_empty(struct ul_buffer *buf)
+{
+ return buf->begin == buf->end;
+}
+
+void ul_buffer_refer_string(struct ul_buffer *buf, char *str)
+{
+ if (buf->sz)
+ ul_buffer_free_data(buf);
+ buf->begin = str;
+ buf->sz = str ? strlen(str) : 0;
+ buf->end = buf->begin + buf->sz;
+}
+
+int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz)
+{
+ char *tmp;
+ size_t len = 0;
+
+ assert(buf);
+
+ if (sz <= buf->sz)
+ return 0;
+
+ if (buf->end && buf->begin)
+ len = buf->end - buf->begin;
+
+ if (buf->chunksize)
+ sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1;
+
+ tmp = realloc(buf->begin, sz);
+ if (!tmp)
+ return -ENOMEM;
+
+ buf->begin = tmp;
+ buf->end = buf->begin + len;
+ buf->sz = sz;
+
+ return 0;
+}
+
+int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz)
+{
+ size_t maxsz = 0;
+
+ if (!buf)
+ return -EINVAL;
+ if (!data || !*data)
+ return 0;
+
+ if (buf->begin && buf->end)
+ maxsz = buf->sz - (buf->end - buf->begin);
+
+ if (maxsz <= sz + 1) {
+ int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1);
+ if (rc)
+ return rc;
+ }
+ memcpy(buf->end, data, sz);
+ buf->end += sz;
+ *buf->end = '\0'; /* make sure it's terminated */
+ return 0;
+}
+
+int ul_buffer_append_string(struct ul_buffer *buf, const char *str)
+{
+ return ul_buffer_append_data(buf, str, strlen(str));
+}
+
+int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str)
+{
+ size_t i;
+ size_t len = strlen(str);
+
+ for (i = 0; len && i < n; i++) {
+ int rc = ul_buffer_append_data(buf, str, len);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz)
+{
+ ul_buffer_reset_data(buf);
+ return ul_buffer_append_data(buf, data, sz);
+}
+
+char *ul_buffer_get_data(struct ul_buffer *buf)
+{
+ return buf->begin;
+}
+
+#ifdef TEST_PROGRAM_BUFFER
+int main(void)
+{
+ struct ul_buffer buf = UL_INIT_BUFFER;
+ char *str;
+
+ ul_buffer_set_chunksize(&buf, 16);
+
+ ul_buffer_append_string(&buf, "AAA");
+ ul_buffer_append_data(&buf, "=", 1);
+ ul_buffer_append_string(&buf, "aaa");
+ ul_buffer_append_data(&buf, ",", 1);
+ ul_buffer_append_string(&buf, "BBB");
+ ul_buffer_append_string(&buf, "=");
+ ul_buffer_append_string(&buf, "bbb");
+
+ str = ul_buffer_get_data(&buf);
+ printf("data '%s'\n", str);
+
+ ul_buffer_reset_data(&buf);
+ ul_buffer_append_string(&buf, "This is really long string to test the buffer function.");
+ ul_buffer_append_string(&buf, " YES!");
+ str = ul_buffer_get_data(&buf);
+ printf("data '%s'\n", str);
+
+ ul_buffer_free_data(&buf);
+ str = strdup("foo");
+ ul_buffer_refer_string(&buf, str);
+ ul_buffer_append_data(&buf, ",", 1);
+ ul_buffer_append_string(&buf, "bar");
+ str = ul_buffer_get_data(&buf);
+ printf("data '%s'\n", str);
+
+ ul_buffer_free_data(&buf);
+}
+#endif /* TEST_PROGRAM_BUFFER */