From 9a7ceeee3d2adbac0b7ef2f2a8db74111dd012b5 Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Wed, 10 Oct 2018 20:00:24 +0000 Subject: [PATCH] Import a (modernized) version of djb's `stralloc` library. Lots of code in Magicka is involved in dynamic string manipulation. `stralloc` isn't a bad library for this sort of thing. Note that this is complements, but doesn't replace, existing string utilities. Signed-off-by: Dan Cross --- src/GNUmakefile.common | 4 +- src/bbs.h | 2 + src/stralloc/README | 4 + src/stralloc/stralloc.3 | 162 ++++++++++++++++++++++++++++++++++++++++ src/stralloc/stralloc.c | 65 ++++++++++++++++ src/stralloc/stralloc.h | 49 ++++++++++++ 6 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 src/stralloc/README create mode 100644 src/stralloc/stralloc.3 create mode 100644 src/stralloc/stralloc.c create mode 100644 src/stralloc/stralloc.h diff --git a/src/GNUmakefile.common b/src/GNUmakefile.common index cf0f92d..3a25a9c 100644 --- a/src/GNUmakefile.common +++ b/src/GNUmakefile.common @@ -47,13 +47,13 @@ HDRS:= bbs.h OBJS:= inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o \ doors.o bbs_list.o chat_system.o email.o files.o settings.o \ lua_glue.o strings.o bluewave.o hashmap/hashmap.o menus.o \ - nodelist.o blog.o util.o + nodelist.o blog.o util.o stralloc/stralloc.o WWWOBJS:= ../deps/aha/aha.o ../deps/hashids/hashids.o www.o www_email.o \ www_msgs.o www_last10.o www_blog.o www_files.o ${OBJS} ifeq ($(MAKECMDGOALS), www) -CFLAGS+= ${CFLAGS} -I${DEPSDIR}/libb64-1.2/include -DENABLE_WWW=1 +CFLAGS+= ${CFLAGS} -Istralloc -I${DEPSDIR}/libb64-1.2/include -DENABLE_WWW=1 endif %.o: %.c ${HDRS} diff --git a/src/bbs.h b/src/bbs.h index f7184ca..e441211 100644 --- a/src/bbs.h +++ b/src/bbs.h @@ -15,6 +15,8 @@ #include "lua/lauxlib.h" #include "jamlib/jam.h" +#include "stralloc/stralloc.h" + #define VERSION_MAJOR 0 #define VERSION_MINOR 12 #define VERSION_STR "alpha" diff --git a/src/stralloc/README b/src/stralloc/README new file mode 100644 index 0000000..9e316d5 --- /dev/null +++ b/src/stralloc/README @@ -0,0 +1,4 @@ +This is a cleanup and modernization of the stralloc +library from qmail, by Daniel J. Bernstein. Qmail was +placed into the public domain by its author; presumably +this library, as part of qmail, was as well. diff --git a/src/stralloc/stralloc.3 b/src/stralloc/stralloc.3 new file mode 100644 index 0000000..307e21d --- /dev/null +++ b/src/stralloc/stralloc.3 @@ -0,0 +1,162 @@ +.TH stralloc 3 +.SH NAME +stralloc \- dynamically allocated strings +.SH SYNTAX +.B #include + +int \fBstralloc_ready\fP(&\fIsa\fR,\fIlen\fR); +.br +int \fBstralloc_readyplus\fP(&\fIsa\fR,\fIlen\fR); + +int \fBstralloc_copy\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_copys\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_copyb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_cat\fP(&\fIsa\fR,&\fIsa2\fR); +.br +int \fBstralloc_cats\fP(&\fIsa\fR,\fIbuf\fR); +.br +int \fBstralloc_catb\fP(&\fIsa\fR,\fIbuf\fR,\fIlen\fR); + +int \fBstralloc_append1\fP(&\fIsa\fR,\fIb\fR); +.br +int \fBstralloc_0\fP(&\fIsa\fR); + +int \fBstralloc_starts\fP(&\fIsa\fR,\fIbuf\fR); + +stralloc \fIsa\fR = {0}; +.br +stralloc \fIsa2\fR = {0}; +.br +size_t \fIlen\fR; +.br +const char *\fIbuf\fR; +.br +char \fIb\fR; +.SH DESCRIPTION +A +.B stralloc +variable holds a string in dynamically allocated space. +String length is limited only by memory. +String contents are unrestricted. + +The +.B stralloc +structure has three components: +.I sa\fB.s +is a pointer to the string, or 0 if it is not allocated; +.I sa\fB.len +is the number of bytes in the string, if it is allocated; +.I sa\fB.a +is the number of bytes allocated for the string, if it is allocated. +A +.B stralloc +variable should be initialized to {0}, +meaning unallocated. + +.B stralloc_ready +makes sure that +.I sa +has enough space allocated for +.I len +characters. +It allocates extra space if necessary. + +.B stralloc_readyplus +makes sure that +.I sa +has enough space allocated for +.I len +characters more than its current length. +If +.I sa +is unallocated, +.B stralloc_readyplus +is the same as +.BR stralloc_ready . + +.B stralloc_copy +copies +.I sa2 +to +.IR sa , +allocating space if necessary. +Here +.I sa2 +is an allocated +.B stralloc +variable. + +.B stralloc_copys +copies a 0-terminated string, +.IR buf , +to +.IR sa , +without the 0. + +.B stralloc_copyb +copies +.I len +characters from +.I buf +to +.IR sa . + +.B stralloc_cat +appends +.I sa2 +to +.IR sa , +allocating space if necessary. +If +.I sa +is unallocated, +.B stralloc_cat +is the same as +.BR stralloc_copy . + +.B stralloc_cats +and +.B stralloc_catb +are analogous to +.B stralloc_copys +and +.BR stralloc_copyb . + +.B stralloc_append1 +adds a single character, +.IR b , +to +.IR sa , +allocating space if necessary. + +.B stralloc_0 +adds a single 0 character +to +.IR sa . + +.B stralloc_starts +returns 1 if the 0-terminated string +.IR buf , +without the 0, +is a prefix of +.IR sa . +.SH "ERROR HANDLING" +If a +.B stralloc +routine runs out of memory, +it leaves +.I sa +alone and returns 0, +setting +.B errno +appropriately. +On success it returns 1; +this guarantees that +.I sa +is allocated. +.SH "SEE ALSO" +alloc(3), +error(3) diff --git a/src/stralloc/stralloc.c b/src/stralloc/stralloc.c new file mode 100644 index 0000000..e2e8244 --- /dev/null +++ b/src/stralloc/stralloc.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#include "stralloc.h" + +int stralloc_ready(stralloc *sa, size_t n) { + size_t na; + char *ns; + + assert(sa != NULL); + if (sa->s == NULL) { + sa->len = 0; + sa->a = n; + sa->s = malloc(n); + return sa != NULL; + } + if (sa->a <= n) + return 1; + na = 30 + n + (n >> 3); + ns = realloc(sa->s, na); + if (ns == NULL) + return 0; + memset(ns + sa->len, 0, na - sa->len); + sa->a = na; + sa->s = ns; + return 1; +} + +int stralloc_starts(stralloc *sa, const char *s) { + size_t len; + assert(sa != NULL); + assert(s != NULL); + len = strlen(s); + return (sa->len >= len) && memcmp(sa->s, s, len); +} + +int stralloc_copyb(stralloc *sa, const char *s, size_t n) { + assert(sa != NULL); + assert(s != NULL); + if (!stralloc_ready(sa, n + 1)) return 0; + memmove(sa->s, s, n); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} + +int stralloc_catb(stralloc *sa, const char *s, size_t n) { + assert(sa != NULL); + assert(s != NULL); + if (sa->s == NULL) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa, n + 1)) return 0; + memmove(sa->s + sa->len, s, n); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} + +int stralloc_append1(stralloc *sa, char b) { + assert(sa != NULL); + if (!stralloc_readyplus(sa, 1)) return 0; + sa->s[sa->len++] = b; + return 1; +} diff --git a/src/stralloc/stralloc.h b/src/stralloc/stralloc.h new file mode 100644 index 0000000..8c21e9f --- /dev/null +++ b/src/stralloc/stralloc.h @@ -0,0 +1,49 @@ +#ifndef STRALLOC_H +#define STRALLOC_H + +#include +#include +#include + +typedef struct stralloc stralloc; +struct stralloc { + char *s; + size_t len; + size_t a; +}; + +extern int stralloc_ready(stralloc *sa, size_t n); +extern int stralloc_starts(stralloc *sa, const char *s); +extern int stralloc_copyb(stralloc *sa, const char *s, size_t n); +extern int stralloc_catb(stralloc *sa, const char *s, size_t n); +extern int stralloc_append1(stralloc *sa, char b); + +static inline int stralloc_readyplus(stralloc *sa, size_t n) { + assert(sa != NULL); + return stralloc_ready(sa, sa->len + n); +} + +static inline int stralloc_copy(stralloc *to, const stralloc *from) { + assert(from != NULL); + return stralloc_copyb(to, from->s, from->len); +} + +static inline int stralloc_cat(stralloc *to, const stralloc *from) { + assert(from != NULL); + return stralloc_catb(to, from->s, from->len); +} + +static inline int stralloc_copys(stralloc *sa, const char *s) { + assert(s != NULL); + return stralloc_copyb(sa, s, strlen(s)); +} + +static inline int stralloc_cats(stralloc *sa, const char *s) { + return stralloc_catb(sa, s, strlen(s)); +} + +static inline int stralloc_0(stralloc *sa) { + return stralloc_append1(sa, '\0'); +} + +#endif