Add simple string buffer library

This commit is contained in:
Dietrich Epp 2022-07-16 17:04:27 -04:00
parent ec3c80360f
commit 0ba00114d6
4 changed files with 129 additions and 0 deletions

View File

@ -5,6 +5,7 @@ cc_library(
name = "lib", name = "lib",
srcs = [ srcs = [
"crc32.c", "crc32.c",
"strbuf.c",
"toolbox.c", "toolbox.c",
"util.c", "util.c",
], ],
@ -13,6 +14,7 @@ cc_library(
"defs.h", "defs.h",
"endian.h", "endian.h",
"error.h", "error.h",
"strbuf.h",
"util.h", "util.h",
], ],
copts = COPTS, copts = COPTS,
@ -59,3 +61,15 @@ cc_test(
":lib", ":lib",
], ],
) )
cc_test(
name = "strbuf_test",
size = "small",
srcs = [
"strbuf_test.c",
],
copts = COPTS,
deps = [
":lib",
],
)

41
lib/strbuf.c Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2022 Dietrich Epp.
// This file is part of SyncFiles. SyncFiles is licensed under the terms of the
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
#include "lib/strbuf.h"
#include <stdlib.h>
#include <string.h>
bool StrbufAlloc(struct Strbuf *restrict b, size_t n)
{
size_t req = n + 1;
if (req > b->alloc) {
size_t nalloc = (b->alloc + 16) * 3 / 2;
if (req > nalloc) {
nalloc = req;
}
char *nbuf = realloc(b->buf, nalloc);
if (nbuf == NULL) {
return false;
}
b->buf = nbuf;
b->alloc = nalloc;
}
return true;
}
bool StrbufReserve(struct Strbuf *restrict b, size_t n)
{
return StrbufAlloc(b, b->len + n);
}
bool StrbufAppendMem(struct Strbuf *restrict b, const char *s, size_t n)
{
if (!StrbufReserve(b, n)) {
return false;
}
memcpy(b->buf + b->len, s, n);
b->buf[b->len + n] = '\0';
b->len += n;
return true;
}

29
lib/strbuf.h Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2022 Dietrich Epp.
// This file is part of SyncFiles. SyncFiles is licensed under the terms of the
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
#ifndef LIB_STRBUF_H
#define LIB_STRBUF_H
#include <stddef.h>
#include "lib/defs.h"
// A strbuf is a buffer for building a string. The structure can be
// zero-initialized.
struct Strbuf {
char *buf; // String data. May be NULL if strbuf is empty.
size_t len; // String length, not including nul terminator.
size_t alloc; // Data reserved for string, not including terminator.
};
// Reserve enough space in the strbuf to store a string which is n bytes long.
// Also reserve enough space for the nul byte after. Return true on success.
bool StrbufAlloc(struct Strbuf *restrict b, size_t n);
// Reserve enough space in the strbuf to append n bytes to the buffer. Also
// reserve enough space for the nul byte after. Return true on success.
bool StrbufReserve(struct Strbuf *restrict b, size_t n);
// Append the given data to the buffer. Return true on success.
bool StrbufAppendMem(struct Strbuf *restrict b, const char *s, size_t n);
#endif

45
lib/strbuf_test.c Normal file
View File

@ -0,0 +1,45 @@
// Copyright 2022 Dietrich Epp.
// This file is part of SyncFiles. SyncFiles is licensed under the terms of the
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
#include "lib/strbuf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Segment {
const char *buf;
size_t size;
};
#define S "0123456789"
#define S8 S S S S S S S S
static const struct Segment kSegments[] = {
{"abc", 3},
{S8, 80},
{"def", 3},
{0, 0},
};
static const char kOut[] = "abc" S8 "def";
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
struct Strbuf s = {0, 0, 0};
for (int i = 0; kSegments[i].buf != NULL; i++) {
bool r = StrbufAppendMem(&s, kSegments[i].buf, kSegments[i].size);
if (!r) {
fputs("StrbufAppendMem returned false\n", stderr);
exit(1);
}
}
if (s.len != sizeof(kOut) - 1 || memcmp(s.buf, kOut, sizeof(kOut)) != 0) {
fputs("Invalid result\n", stderr);
exit(1);
}
free(s.buf);
return 0;
}