]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/buffer: add simple grow-able buffer
authorKarel Zak <kzak@redhat.com>
Fri, 25 Sep 2020 15:21:57 +0000 (17:21 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 29 Sep 2020 10:06:11 +0000 (12:06 +0200)
The goal is to use it in libmount when generate options strings
and in libsmartcols to replace libscols_buffer.

Signed-off-by: Karel Zak <kzak@redhat.com>
include/buffer.h [new file with mode: 0644]
lib/Makemodule.am
lib/buffer.c [new file with mode: 0644]

diff --git a/include/buffer.h b/include/buffer.h
new file mode 100644 (file)
index 0000000..5bc7037
--- /dev/null
@@ -0,0 +1,28 @@
+#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 */
index cab44480d1bbfcbc52088199948069d1243a3aad..590f2f8c11a648ef757568cdf8e50a6d3a805298 100644 (file)
@@ -3,6 +3,7 @@ noinst_LTLIBRARIES += libcommon.la
 libcommon_la_CFLAGS = $(AM_CFLAGS)
 libcommon_la_SOURCES = \
        lib/blkdev.c \
+       lib/buffer.c \
        lib/canonicalize.c \
        lib/crc32.c \
        lib/crc32c.c \
@@ -76,6 +77,7 @@ dist_man_MANS += lib/terminal-colors.d.5
 
 check_PROGRAMS += \
        test_blkdev \
+       test_buffer \
        test_canonicalize \
        test_colors \
        test_fileutils \
@@ -186,3 +188,6 @@ test_pwdutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
 
 test_remove_env_SOURCES = lib/env.c
 test_remove_env_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
+
+test_buffer_SOURCES = lib/buffer.c
+test_buffer_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_BUFFER
diff --git a/lib/buffer.c b/lib/buffer.c
new file mode 100644 (file)
index 0000000..a25da0c
--- /dev/null
@@ -0,0 +1,154 @@
+
+#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 */