lib/buffer: add simple grow-able buffer
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>
This commit is contained in:
parent
40681c41ce
commit
0a9939816c
|
@ -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 */
|
|
@ -3,6 +3,7 @@ noinst_LTLIBRARIES += libcommon.la
|
||||||
libcommon_la_CFLAGS = $(AM_CFLAGS)
|
libcommon_la_CFLAGS = $(AM_CFLAGS)
|
||||||
libcommon_la_SOURCES = \
|
libcommon_la_SOURCES = \
|
||||||
lib/blkdev.c \
|
lib/blkdev.c \
|
||||||
|
lib/buffer.c \
|
||||||
lib/canonicalize.c \
|
lib/canonicalize.c \
|
||||||
lib/crc32.c \
|
lib/crc32.c \
|
||||||
lib/crc32c.c \
|
lib/crc32c.c \
|
||||||
|
@ -76,6 +77,7 @@ dist_man_MANS += lib/terminal-colors.d.5
|
||||||
|
|
||||||
check_PROGRAMS += \
|
check_PROGRAMS += \
|
||||||
test_blkdev \
|
test_blkdev \
|
||||||
|
test_buffer \
|
||||||
test_canonicalize \
|
test_canonicalize \
|
||||||
test_colors \
|
test_colors \
|
||||||
test_fileutils \
|
test_fileutils \
|
||||||
|
@ -186,3 +188,6 @@ test_pwdutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
|
||||||
|
|
||||||
test_remove_env_SOURCES = lib/env.c
|
test_remove_env_SOURCES = lib/env.c
|
||||||
test_remove_env_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
|
test_remove_env_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
|
||||||
|
|
||||||
|
test_buffer_SOURCES = lib/buffer.c
|
||||||
|
test_buffer_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_BUFFER
|
||||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue