From 7f11104a5737adf261d10bc1a7b85e740f2eb491 Mon Sep 17 00:00:00 2001 From: rsc Date: Thu, 11 Dec 2003 18:15:57 +0000 Subject: Add libString. --- src/libString/mkfile | 27 +++++++++ src/libString/s_alloc.c | 86 +++++++++++++++++++++++++++ src/libString/s_append.c | 17 ++++++ src/libString/s_array.c | 17 ++++++ src/libString/s_copy.c | 19 ++++++ src/libString/s_getline.c | 72 ++++++++++++++++++++++ src/libString/s_grow.c | 34 +++++++++++ src/libString/s_memappend.c | 20 +++++++ src/libString/s_nappend.c | 18 ++++++ src/libString/s_parse.c | 40 +++++++++++++ src/libString/s_putc.c | 13 ++++ src/libString/s_rdinstack.c | 141 ++++++++++++++++++++++++++++++++++++++++++++ src/libString/s_read.c | 38 ++++++++++++ src/libString/s_read_line.c | 31 ++++++++++ src/libString/s_reset.c | 23 ++++++++ src/libString/s_terminate.c | 13 ++++ src/libString/s_tolower.c | 15 +++++ src/libString/s_unique.c | 16 +++++ 18 files changed, 640 insertions(+) create mode 100644 src/libString/mkfile create mode 100644 src/libString/s_alloc.c create mode 100644 src/libString/s_append.c create mode 100644 src/libString/s_array.c create mode 100644 src/libString/s_copy.c create mode 100644 src/libString/s_getline.c create mode 100644 src/libString/s_grow.c create mode 100644 src/libString/s_memappend.c create mode 100644 src/libString/s_nappend.c create mode 100644 src/libString/s_parse.c create mode 100644 src/libString/s_putc.c create mode 100644 src/libString/s_rdinstack.c create mode 100644 src/libString/s_read.c create mode 100644 src/libString/s_read_line.c create mode 100644 src/libString/s_reset.c create mode 100644 src/libString/s_terminate.c create mode 100644 src/libString/s_tolower.c create mode 100644 src/libString/s_unique.c (limited to 'src/libString') diff --git a/src/libString/mkfile b/src/libString/mkfile new file mode 100644 index 00000000..49803b45 --- /dev/null +++ b/src/libString/mkfile @@ -0,0 +1,27 @@ +PLAN9=../.. +<$PLAN9/src/mkhdr + +LIB=libString.a + +OFILES=\ + s_alloc.$O\ + s_append.$O\ + s_array.$O\ + s_copy.$O\ + s_getline.$O\ + s_grow.$O\ + s_memappend.$O\ + s_nappend.$O\ + s_parse.$O\ + s_putc.$O\ + s_rdinstack.$O\ + s_read.$O\ + s_read_line.$O\ + s_reset.$O\ + s_terminate.$O\ + s_tolower.$O\ + s_unique.$O\ + +HFILES=/sys/include/String.h + +<$PLAN9/src/mksyslib diff --git a/src/libString/s_alloc.c b/src/libString/s_alloc.c new file mode 100644 index 00000000..34f89164 --- /dev/null +++ b/src/libString/s_alloc.c @@ -0,0 +1,86 @@ +#include +#include +#include "libString.h" + +#define STRLEN 128 + +extern void +s_free(String *sp) +{ + if (sp == nil) + return; + lock(&sp->lk); + if(--(sp->ref) != 0){ + unlock(&sp->lk); + return; + } + unlock(&sp->lk); + + if(sp->fixed == 0 && sp->base != nil) + free(sp->base); + free(sp); +} + +/* get another reference to a string */ +extern String * +s_incref(String *sp) +{ + lock(&sp->lk); + sp->ref++; + unlock(&sp->lk); + + return sp; +} + +/* allocate a String head */ +extern String * +_s_alloc(void) +{ + String *s; + + s = mallocz(sizeof *s, 1); + if(s == nil) + return s; + s->ref = 1; + s->fixed = 0; + return s; +} + +/* create a new `short' String */ +extern String * +s_newalloc(int len) +{ + String *sp; + + sp = _s_alloc(); + if(sp == nil) + sysfatal("s_newalloc: %r"); + setmalloctag(sp, getcallerpc(&len)); + if(len < STRLEN) + len = STRLEN; + sp->base = sp->ptr = malloc(len); + if (sp->base == nil) + sysfatal("s_newalloc: %r"); + setmalloctag(sp->base, getcallerpc(&len)); + + sp->end = sp->base + len; + s_terminate(sp); + return sp; +} + +/* create a new `short' String */ +extern String * +s_new(void) +{ + String *sp; + + sp = _s_alloc(); + if(sp == nil) + sysfatal("s_new: %r"); + sp->base = sp->ptr = malloc(STRLEN); + if (sp->base == nil) + sysfatal("s_new: %r"); + sp->end = sp->base + STRLEN; + s_terminate(sp); + return sp; +} diff --git a/src/libString/s_append.c b/src/libString/s_append.c new file mode 100644 index 00000000..1b02d20e --- /dev/null +++ b/src/libString/s_append.c @@ -0,0 +1,17 @@ +#include +#include +#include "libString.h" + +/* append a char array to a String */ +String * +s_append(String *to, char *from) +{ + if (to == 0) + to = s_new(); + if (from == 0) + return to; + for(; *from; from++) + s_putc(to, *from); + s_terminate(to); + return to; +} diff --git a/src/libString/s_array.c b/src/libString/s_array.c new file mode 100644 index 00000000..3cf571b1 --- /dev/null +++ b/src/libString/s_array.c @@ -0,0 +1,17 @@ +#include +#include +#include "libString.h" + +extern String* _s_alloc(void); + +/* return a String containing a character array (this had better not grow) */ +extern String * +s_array(char *cp, int len) +{ + String *sp = _s_alloc(); + + sp->base = sp->ptr = cp; + sp->end = sp->base + len; + sp->fixed = 1; + return sp; +} diff --git a/src/libString/s_copy.c b/src/libString/s_copy.c new file mode 100644 index 00000000..5a23b3c2 --- /dev/null +++ b/src/libString/s_copy.c @@ -0,0 +1,19 @@ +#include +#include +#include "libString.h" + + +/* return a String containing a copy of the passed char array */ +extern String* +s_copy(char *cp) +{ + String *sp; + int len; + + len = strlen(cp)+1; + sp = s_newalloc(len); + setmalloctag(sp, getcallerpc(&cp)); + strcpy(sp->base, cp); + sp->ptr = sp->base + len - 1; /* point to 0 terminator */ + return sp; +} diff --git a/src/libString/s_getline.c b/src/libString/s_getline.c new file mode 100644 index 00000000..e46dc125 --- /dev/null +++ b/src/libString/s_getline.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "libString.h" + +/* Append an input line to a String. + * + * Returns a pointer to the character string (or 0). + * Leading whitespace and newlines are removed. + * + * Empty lines and lines starting with '#' are ignored. + */ +extern char * +s_getline(Biobuf *fp, String *to) +{ + int c; + int len=0; + + s_terminate(to); + + /* end of input */ + if ((c = Bgetc(fp)) < 0) + return 0; + + /* take care of inconsequentials */ + for(;;) { + /* eat leading white */ + while(c==' ' || c=='\t' || c=='\n' || c=='\r') + c = Bgetc(fp); + + if(c < 0) + return 0; + + /* take care of comments */ + if(c == '#'){ + do { + c = Bgetc(fp); + if(c < 0) + return 0; + } while(c != '\n'); + continue; + } + + /* if we got here, we've gotten something useful */ + break; + } + + /* gather up a line */ + for(;;) { + len++; + switch(c) { + case -1: + s_terminate(to); + return len ? to->ptr-len : 0; + case '\\': + c = Bgetc(fp); + if (c != '\n') { + s_putc(to, '\\'); + s_putc(to, c); + } + break; + case '\n': + s_terminate(to); + return len ? to->ptr-len : 0; + default: + s_putc(to, c); + break; + } + c = Bgetc(fp); + } + return 0; +} diff --git a/src/libString/s_grow.c b/src/libString/s_grow.c new file mode 100644 index 00000000..5cf2a141 --- /dev/null +++ b/src/libString/s_grow.c @@ -0,0 +1,34 @@ +#include +#include +#include "libString.h" + +/* grow a String's allocation by at least `incr' bytes */ +extern String* +s_grow(String *s, int incr) +{ + char *cp; + int size; + + if(s->fixed) + sysfatal("s_grow of constant string"); + s = s_unique(s); + + /* + * take a larger increment to avoid mallocing too often + */ + size = s->end-s->base; + if(size/2 < incr) + size += incr; + else + size += size/2; + + cp = realloc(s->base, size); + if (cp == 0) + sysfatal("s_grow: %r"); + s->ptr = (s->ptr - s->base) + cp; + s->end = cp + size; + s->base = cp; + + return s; +} + diff --git a/src/libString/s_memappend.c b/src/libString/s_memappend.c new file mode 100644 index 00000000..27b69850 --- /dev/null +++ b/src/libString/s_memappend.c @@ -0,0 +1,20 @@ +#include +#include +#include "libString.h" + +/* append a char array ( of up to n characters) to a String */ +String * +s_memappend(String *to, char *from, int n) +{ + char *e; + + if (to == 0) + to = s_new(); + if (from == 0) + return to; + for(e = from + n; from < e; from++) + s_putc(to, *from); + s_terminate(to); + return to; +} + diff --git a/src/libString/s_nappend.c b/src/libString/s_nappend.c new file mode 100644 index 00000000..fb41f932 --- /dev/null +++ b/src/libString/s_nappend.c @@ -0,0 +1,18 @@ +#include +#include +#include "libString.h" + +/* append a char array ( of up to n characters) to a String */ +String * +s_nappend(String *to, char *from, int n) +{ + if (to == 0) + to = s_new(); + if (from == 0) + return to; + for(; n && *from; from++, n--) + s_putc(to, *from); + s_terminate(to); + return to; +} + diff --git a/src/libString/s_parse.c b/src/libString/s_parse.c new file mode 100644 index 00000000..376a41e2 --- /dev/null +++ b/src/libString/s_parse.c @@ -0,0 +1,40 @@ +#include +#include +#include "libString.h" + +#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n') + +/* Get the next field from a String. The field is delimited by white space, + * single or double quotes. + */ +String * +s_parse(String *from, String *to) +{ + if (*from->ptr == '\0') + return 0; + if (to == 0) + to = s_new(); + if (*from->ptr == '\'') { + from->ptr++; + for (;*from->ptr != '\'' && *from->ptr != '\0'; from->ptr++) + s_putc(to, *from->ptr); + if (*from->ptr == '\'') + from->ptr++; + } else if (*from->ptr == '"') { + from->ptr++; + for (;*from->ptr != '"' && *from->ptr != '\0'; from->ptr++) + s_putc(to, *from->ptr); + if (*from->ptr == '"') + from->ptr++; + } else { + for (;!isspace(*from->ptr) && *from->ptr != '\0'; from->ptr++) + s_putc(to, *from->ptr); + } + s_terminate(to); + + /* crunch trailing white */ + while(isspace(*from->ptr)) + from->ptr++; + + return to; +} diff --git a/src/libString/s_putc.c b/src/libString/s_putc.c new file mode 100644 index 00000000..29a385d7 --- /dev/null +++ b/src/libString/s_putc.c @@ -0,0 +1,13 @@ +#include +#include +#include "libString.h" + +void +s_putc(String *s, int c) +{ + if(s->ref > 1) + sysfatal("can't s_putc a shared string"); + if (s->ptr >= s->end) + s_grow(s, 2); + *(s->ptr)++ = c; +} diff --git a/src/libString/s_rdinstack.c b/src/libString/s_rdinstack.c new file mode 100644 index 00000000..de12d219 --- /dev/null +++ b/src/libString/s_rdinstack.c @@ -0,0 +1,141 @@ + +#include +#include +#include +#include "libString.h" + +struct Sinstack{ + int depth; + Biobuf *fp[32]; /* hard limit to avoid infinite recursion */ +}; + +/* initialize */ +extern Sinstack * +s_allocinstack(char *file) +{ + Sinstack *sp; + Biobuf *fp; + + fp = Bopen(file, OREAD); + if(fp == nil) + return nil; + + sp = malloc(sizeof *sp); + sp->depth = 0; + sp->fp[0] = fp; + return sp; +} + +extern void +s_freeinstack(Sinstack *sp) +{ + while(sp->depth >= 0) + Bterm(sp->fp[sp->depth--]); + free(sp); +} + +/* Append an input line to a String. + * + * Empty lines and leading whitespace are removed. + */ +static char * +rdline(Biobuf *fp, String *to) +{ + int c; + int len = 0; + + c = Bgetc(fp); + + /* eat leading white */ + while(c==' ' || c=='\t' || c=='\n' || c=='\r') + c = Bgetc(fp); + + if(c < 0) + return 0; + + for(;;){ + switch(c) { + case -1: + goto out; + case '\\': + c = Bgetc(fp); + if (c != '\n') { + s_putc(to, '\\'); + s_putc(to, c); + len += 2; + } + break; + case '\r': + break; + case '\n': + if(len != 0) + goto out; + break; + default: + s_putc(to, c); + len++; + break; + } + c = Bgetc(fp); + } +out: + s_terminate(to); + return to->ptr - len; +} + +/* Append an input line to a String. + * + * Returns a pointer to the character string (or 0). + * Leading whitespace and newlines are removed. + * Lines starting with #include cause us to descend into the new file. + * Empty lines and other lines starting with '#' are ignored. + */ +extern char * +s_rdinstack(Sinstack *sp, String *to) +{ + char *p; + Biobuf *fp, *nfp; + + s_terminate(to); + fp = sp->fp[sp->depth]; + + for(;;){ + p = rdline(fp, to); + if(p == nil){ + if(sp->depth == 0) + break; + Bterm(fp); + sp->depth--; + return s_rdinstack(sp, to); + } + + if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){ + to->ptr = p; + p += 8; + + /* sanity (and looping) */ + if(sp->depth >= nelem(sp->fp)) + sysfatal("s_recgetline: includes too deep"); + + /* skip white */ + while(*p == ' ' || *p == '\t') + p++; + + nfp = Bopen(p, OREAD); + if(nfp == nil) + continue; + sp->depth++; + sp->fp[sp->depth] = nfp; + return s_rdinstack(sp, to); + } + + /* got milk? */ + if(*p != '#') + break; + + /* take care of comments */ + to->ptr = p; + s_terminate(to); + } + return p; +} diff --git a/src/libString/s_read.c b/src/libString/s_read.c new file mode 100644 index 00000000..59581eaf --- /dev/null +++ b/src/libString/s_read.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include "libString.h" + +enum +{ + Minread= 256, +}; + +/* Append up to 'len' input bytes to the string 'to'. + * + * Returns the number of characters read. + */ +extern int +s_read(Biobuf *fp, String *to, int len) +{ + int rv; + int n; + + if(to->ref > 1) + sysfatal("can't s_read a shared string"); + for(rv = 0; rv < len; rv += n){ + n = to->end - to->ptr; + if(n < Minread){ + s_grow(to, Minread); + n = to->end - to->ptr; + } + if(n > len - rv) + n = len - rv; + n = Bread(fp, to->ptr, n); + if(n <= 0) + break; + to->ptr += n; + } + s_terminate(to); + return rv; +} diff --git a/src/libString/s_read_line.c b/src/libString/s_read_line.c new file mode 100644 index 00000000..b1de5ac4 --- /dev/null +++ b/src/libString/s_read_line.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include "libString.h" + +/* Append an input line to a String. + * + * Returns a pointer to the character string (or 0). + * Trailing newline is left on. + */ +extern char * +s_read_line(Biobuf *fp, String *to) +{ + char *cp; + int llen; + + if(to->ref > 1) + sysfatal("can't s_read_line a shared string"); + s_terminate(to); + cp = Brdline(fp, '\n'); + if(cp == 0) + return 0; + llen = Blinelen(fp); + if(to->end - to->ptr < llen) + s_grow(to, llen); + memmove(to->ptr, cp, llen); + cp = to->ptr; + to->ptr += llen; + s_terminate(to); + return cp; +} diff --git a/src/libString/s_reset.c b/src/libString/s_reset.c new file mode 100644 index 00000000..cd2a7421 --- /dev/null +++ b/src/libString/s_reset.c @@ -0,0 +1,23 @@ +#include +#include +#include "libString.h" + +String* +s_reset(String *s) +{ + if(s != nil){ + s = s_unique(s); + s->ptr = s->base; + *s->ptr = '\0'; + } else + s = s_new(); + return s; +} + +String* +s_restart(String *s) +{ + s = s_unique(s); + s->ptr = s->base; + return s; +} diff --git a/src/libString/s_terminate.c b/src/libString/s_terminate.c new file mode 100644 index 00000000..dc893ab2 --- /dev/null +++ b/src/libString/s_terminate.c @@ -0,0 +1,13 @@ +#include +#include +#include "libString.h" + +void +s_terminate(String *s) +{ + if(s->ref > 1) + sysfatal("can't s_terminate a shared string"); + if (s->ptr >= s->end) + s_grow(s, 1); + *s->ptr = 0; +} diff --git a/src/libString/s_tolower.c b/src/libString/s_tolower.c new file mode 100644 index 00000000..737fff1f --- /dev/null +++ b/src/libString/s_tolower.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include "libString.h" + + +/* convert String to lower case */ +void +s_tolower(String *sp) +{ + char *cp; + + for(cp=sp->ptr; *cp; cp++) + *cp = tolower(*cp); +} diff --git a/src/libString/s_unique.c b/src/libString/s_unique.c new file mode 100644 index 00000000..134411c9 --- /dev/null +++ b/src/libString/s_unique.c @@ -0,0 +1,16 @@ +#include +#include +#include "libString.h" + +String* +s_unique(String *s) +{ + String *p; + + if(s->ref > 1){ + p = s; + s = s_clone(p); + s_free(p); + } + return s; +} -- cgit v1.2.3