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 <patchdev@fat-dragon.org>
This commit is contained in:
Dan Cross 2018-10-10 20:00:24 +00:00 committed by Andrew Pamment
parent 82b6ec3a3b
commit 9a7ceeee3d
6 changed files with 284 additions and 2 deletions

View File

@ -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}

View File

@ -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"

4
src/stralloc/README Normal file
View File

@ -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.

162
src/stralloc/stralloc.3 Normal file
View File

@ -0,0 +1,162 @@
.TH stralloc 3
.SH NAME
stralloc \- dynamically allocated strings
.SH SYNTAX
.B #include <stralloc.h>
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)

65
src/stralloc/stralloc.c Normal file
View File

@ -0,0 +1,65 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#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;
}

49
src/stralloc/stralloc.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef STRALLOC_H
#define STRALLOC_H
#include <assert.h>
#include <stddef.h>
#include <string.h>
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