From 9695ea005d4af93dcd60f74f10fd3c54499a182f Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Thu, 11 Nov 2021 16:31:58 -0800 Subject: chore: split up base library into individual files for smaller binaries --- sys/base/string/append.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ sys/base/string/appendf.c | 31 +++++++++++++++++++++++++++ sys/base/string/clear.c | 9 ++++++++ sys/base/string/copyn.c | 11 ++++++++++ sys/base/string/equals.c | 12 +++++++++++ sys/base/string/find.c | 11 ++++++++++ sys/base/string/fit.c | 20 +++++++++++++++++ sys/base/string/free.c | 8 +++++++ sys/base/string/grow.c | 33 +++++++++++++++++++++++++++++ sys/base/string/internal.h | 12 +++++++++++ sys/base/string/join.c | 16 ++++++++++++++ sys/base/string/len.c | 17 +++++++++++++++ sys/base/string/lower.c | 12 +++++++++++ sys/base/string/make.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ sys/base/string/makef.c | 25 ++++++++++++++++++++++ sys/base/string/read.c | 12 +++++++++++ sys/base/string/replace.c | 26 +++++++++++++++++++++++ sys/base/string/rules.mk | 19 +++++++++++++++++ sys/base/string/split.c | 39 ++++++++++++++++++++++++++++++++++ sys/base/string/upper.c | 12 +++++++++++ 20 files changed, 431 insertions(+) create mode 100644 sys/base/string/append.c create mode 100644 sys/base/string/appendf.c create mode 100644 sys/base/string/clear.c create mode 100644 sys/base/string/copyn.c create mode 100644 sys/base/string/equals.c create mode 100644 sys/base/string/find.c create mode 100644 sys/base/string/fit.c create mode 100644 sys/base/string/free.c create mode 100644 sys/base/string/grow.c create mode 100644 sys/base/string/internal.h create mode 100644 sys/base/string/join.c create mode 100644 sys/base/string/len.c create mode 100644 sys/base/string/lower.c create mode 100644 sys/base/string/make.c create mode 100644 sys/base/string/makef.c create mode 100644 sys/base/string/read.c create mode 100644 sys/base/string/replace.c create mode 100644 sys/base/string/rules.mk create mode 100644 sys/base/string/split.c create mode 100644 sys/base/string/upper.c (limited to 'sys/base/string') diff --git a/sys/base/string/append.c b/sys/base/string/append.c new file mode 100644 index 0000000..d4d0396 --- /dev/null +++ b/sys/base/string/append.c @@ -0,0 +1,53 @@ +#include "internal.h" + +// append will append the given null terminated c string to the string data +// structure. this variant can append a substring of length len of the given +// string to our buffer. the result is reallocated if not enough room is present +// in the buffer. +int +str·appendlen(string *s, vlong n, const byte* b) +{ + /* + bl = strlen(b); + if (n > bl) panicf("attempted to make a substring longer than string"); + */ + + str·grow(s, n); + if(*s == nil) + return 0; + + Hdr* h = (Hdr*)(*s - sizeof(Hdr)); + + memcpy(*s + str·len(*s), b, n); + h->len += n; + (*s)[h->len] = '\0'; + + return n; +} + +// append will append the given null terminated c string to the string data +// structure. this variant will append the entire string. +int +str·append(string *s, const byte* b) +{ + return str·appendlen(s, strlen(b), b); +} + +// appendbyte will append the given byte to our string. +// NOTE: as the byte is on the stack, it is not null-terminated. +// can not pass to the above functions. +int +str·appendbyte(string *s, const byte b) +{ + str·grow(s, 1); + if(*s == nil) + return 0; + + Hdr* h = (Hdr*)(*s - sizeof(Hdr)); + + *(*s + str·len(*s)) = b; + h->len++; + (*s)[h->len] = '\0'; // NOTE: I don't think an explicit zero is required..? + + return 1; +} diff --git a/sys/base/string/appendf.c b/sys/base/string/appendf.c new file mode 100644 index 0000000..4b8d76c --- /dev/null +++ b/sys/base/string/appendf.c @@ -0,0 +1,31 @@ +#include "internal.h" + +/* + * appendf will append the given formatted string to our buffer. + * returns the newly minted string + */ + +int +str·appendf(string *s, const byte* fmt, ...) +{ + va_list args; + va_start(args, fmt); + int remain = str·cap(*s) - str·len(*s); + int n = vsnprintf(*s + str·len(*s), remain + 1, fmt, args); + va_end(args); + + if(n > remain){ + // If the first write was incomplete, we overwite the data again. + str·grow(s, n); + va_list args; + va_start(args, fmt); + n = vsnprintf(*s + str·len(*s), n + 1, fmt, args); + assert(n - remain <= str·cap(*s)); + va_end(args); + } + + Hdr* h = (Hdr*)(*s - sizeof(Hdr)); + h->len += n; + + return n; +} diff --git a/sys/base/string/clear.c b/sys/base/string/clear.c new file mode 100644 index 0000000..986f809 --- /dev/null +++ b/sys/base/string/clear.c @@ -0,0 +1,9 @@ +#include "internal.h" + +void +str·clear(string *s) +{ + Hdr* h = (Hdr*)(*s - sizeof(Hdr)); + h->len = 0; + *s[0] = '\0'; +} diff --git a/sys/base/string/copyn.c b/sys/base/string/copyn.c new file mode 100644 index 0000000..09c2879 --- /dev/null +++ b/sys/base/string/copyn.c @@ -0,0 +1,11 @@ +#include "internal.h" + +char * +str·copyn(char *dst, char *src, int n) +{ + while(*src && n-- > 0) + *dst++ = *src++; + + *dst = 0; + return dst; +} diff --git a/sys/base/string/equals.c b/sys/base/string/equals.c new file mode 100644 index 0000000..a975cf5 --- /dev/null +++ b/sys/base/string/equals.c @@ -0,0 +1,12 @@ +#include "internal.h" + +// Equals returns true if string s and t are equivalent. +bool +str·equals(const string s, const string t) +{ + vlong sL = str·len(s); + vlong tL = str·len(t); + if (sL != tL) return false; + + return memcmp(s, t, sL) == 0; +} diff --git a/sys/base/string/find.c b/sys/base/string/find.c new file mode 100644 index 0000000..20f990e --- /dev/null +++ b/sys/base/string/find.c @@ -0,0 +1,11 @@ +#include "internal.h" + +// find will find the first occurence of +// substr in the string returns -1 if nothing was found. +int +str·find(string s, const byte* substr) +{ + byte* loc = strstr(s, substr); + if (loc == nil) return -1; + return (int)(loc - s); +} diff --git a/sys/base/string/fit.c b/sys/base/string/fit.c new file mode 100644 index 0000000..56ab041 --- /dev/null +++ b/sys/base/string/fit.c @@ -0,0 +1,20 @@ +#include "internal.h" + +// fit reallocates the string such that the buffer is exactly sized for the +// buffer. if the capacity equals the length, then the function is a noop. the +// byte array is unchanged. +void +str·fit(string *s) +{ + Hdr* h; + vlong cap = str·cap(*s); + vlong len = str·len(*s); + + if (cap == len) return; + + h = (Hdr*)(s - sizeof(Hdr)); + h = realloc(h, sizeof(*h) + len + 1); + h->cap = len; + + *s = h->buf; +} diff --git a/sys/base/string/free.c b/sys/base/string/free.c new file mode 100644 index 0000000..7b5ee98 --- /dev/null +++ b/sys/base/string/free.c @@ -0,0 +1,8 @@ +#include "internal.h" + +// free returns memory associated to the buffer. +void +str·free(string s) +{ + free(s - sizeof(Hdr)); +} diff --git a/sys/base/string/grow.c b/sys/base/string/grow.c new file mode 100644 index 0000000..39a9d2f --- /dev/null +++ b/sys/base/string/grow.c @@ -0,0 +1,33 @@ +#include "internal.h" + +// grow ensures that the string can encompass at least delta bytes. +// if it already can, this is a no op. +// if it can't, the string will be reallocated. +void +str·grow(string *s, vlong delta) +{ + Hdr *h, *newh; + vlong cap = str·cap(*s); + vlong len = str·len(*s); + assert(cap >= len); // To prevent unsigned behavior + + if (cap - len >= delta) return; + + h = (Hdr*)(*s - sizeof(Hdr)); + + vlong newCap = cap + delta; + assert(newCap >= cap); // To prevent unsigned behavior + if (newCap < MAX_STRING_ALLOC) { + newCap *= 2; + } else + newCap += MAX_STRING_ALLOC; + + newh = (Hdr*)realloc(h, sizeof(*h) + newCap + 1); + if (newh == nil) return; + + memset(newh->buf + len, '\0', newCap - len); + newh->cap = newCap; + newh->len = len; + + *s = newh->buf; +} diff --git a/sys/base/string/internal.h b/sys/base/string/internal.h new file mode 100644 index 0000000..8c16c64 --- /dev/null +++ b/sys/base/string/internal.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +#define MAX_STRING_ALLOC 1024 * 1024 + +typedef struct Hdr +{ + vlong len; + vlong cap; + byte buf[]; +} Hdr; diff --git a/sys/base/string/join.c b/sys/base/string/join.c new file mode 100644 index 0000000..fb97b6c --- /dev/null +++ b/sys/base/string/join.c @@ -0,0 +1,16 @@ +#include "internal.h" + +string +str·join(vlong len, byte** fields, const byte* sep) +{ + string s = str·makecap("", 0, 10); + int j = 0; + + for (j = 0; j < len; j++) { + str·append(&s, fields[j]); + if (j < len - 1) + str·appendlen(&s, 1, sep); + } + + return s; +} diff --git a/sys/base/string/len.c b/sys/base/string/len.c new file mode 100644 index 0000000..5e42919 --- /dev/null +++ b/sys/base/string/len.c @@ -0,0 +1,17 @@ +#include "internal.h" + +// len returns the length of the string. +int +str·len(const string s) +{ + Hdr* h = (Hdr*)(s - sizeof(Hdr)); + return h->len; +} + +// cap returns the capacity of the string buffer. +int +str·cap(const string s) +{ + Hdr* h = (Hdr*)(s - sizeof(Hdr)); + return h->cap; +} diff --git a/sys/base/string/lower.c b/sys/base/string/lower.c new file mode 100644 index 0000000..c6935f8 --- /dev/null +++ b/sys/base/string/lower.c @@ -0,0 +1,12 @@ +#include "internal.h" + +// lower will force all runes in the string to be lowercase +void +str·lower(string s) +{ + byte *b, *e; + b = s; + e = b + str·len(s); + while (b++ != e) + *b = tolower(*b); +} diff --git a/sys/base/string/make.c b/sys/base/string/make.c new file mode 100644 index 0000000..eb71543 --- /dev/null +++ b/sys/base/string/make.c @@ -0,0 +1,53 @@ +#include "internal.h" + +// new returns a new dynamic string object, initialized from the given c string. +// len defines the length of the c substring that we will copy into our buffer. +// the backing buffer will have capacity cap. +string +str·makecap(const byte *s, vlong len, vlong cap) +{ + struct Hdr* h; + + h = malloc(sizeof(*h) + cap + 1); + if (s == nil) memset(h, 0, sizeof(*h)); + + if (h == nil) return nil; // Allocation failed. + + h->len = (s == nil) ? 0 : len; + h->cap = cap; + + if (cap < h->len) goto cleanup; + + if (s != nil && cap > 0) { + memcpy(h->buf, s, h->len); + memset(h->buf + h->len, '\0', h->cap - h->len + 1); + } + + return h->buf; + +cleanup: + free(h); + panicf("Attempted to create a string with less capacity than length"); + return nil; +} + +// new returns a new dynamic string object, initialized from the given c string. +// the backing buffer capacity is equivalent to the string length. +string +str·makelen(const byte *s, vlong len) +{ + vlong sl = (!s) ? 0 : strlen(s); + if (sl < len) panicf("attempted to take a bigger substring than string length"); + + vlong cap = (len == 0) ? 1 : len; + return str·makecap(s, len, cap); +} + +// new returns a new dynamic string object, initialized from the given c string. +// the backing buffer capacity is equivalent to the string length. +string +str·make(const byte *s) +{ + vlong len = (!s) ? 0 : strlen(s); + return str·makelen(s, len); +} diff --git a/sys/base/string/makef.c b/sys/base/string/makef.c new file mode 100644 index 0000000..8fb9c38 --- /dev/null +++ b/sys/base/string/makef.c @@ -0,0 +1,25 @@ +#include "internal.h" + +// Newf returns a new dynamic string object +string +str·makef(const byte *fmt, ...) +{ + vlong n; + string s; + va_list args; + + va_start(args, fmt); + n = vsnprintf(nil, 0, fmt, args); + va_end(args); + + s = str·makecap(nil, 0, n); + + va_start(args, fmt); + vsnprintf(s, n + 1, fmt, args); + va_end(args); + + Hdr* h = (Hdr*)(s - sizeof(Hdr)); + h->len = n; + + return s; +} diff --git a/sys/base/string/read.c b/sys/base/string/read.c new file mode 100644 index 0000000..df2028f --- /dev/null +++ b/sys/base/string/read.c @@ -0,0 +1,12 @@ +#include "internal.h" + +int +str·read(string s, int size, int n, void *buf) +{ + int len; + + len = MIN(n * size, str·len(s)); + memcpy(buf, s, len); + + return len; +} diff --git a/sys/base/string/replace.c b/sys/base/string/replace.c new file mode 100644 index 0000000..127daed --- /dev/null +++ b/sys/base/string/replace.c @@ -0,0 +1,26 @@ +#include "internal.h" + +// replace will replace all occurences of the given bytes 'from' to bytes 'to' +// edits are done in place and modify the string. +// NOTE: as of now strings from and to must be the same size. +void +str·replace(string s, const byte* from, const byte* to) +{ + vlong fromL = strlen(from); + vlong toL = strlen(to); + if (toL != fromL) { panicf("different sized replacement string not supported"); } + + vlong l = str·len(s); + vlong i = l; + vlong j = l; + + for (i = 0; i < l; i++) { + for (j = 0; j < toL; j++) { + if (s[i] == from[j]) { + s[i] = to[j]; + break; + } + } + } +} + diff --git a/sys/base/string/rules.mk b/sys/base/string/rules.mk new file mode 100644 index 0000000..e517ca5 --- /dev/null +++ b/sys/base/string/rules.mk @@ -0,0 +1,19 @@ +SRCS_$(d)+=\ + $(d)/string/append.c\ + $(d)/string/appendf.c\ + $(d)/string/clear.c\ + $(d)/string/copyn.c\ + $(d)/string/equals.c\ + $(d)/string/find.c\ + $(d)/string/fit.c\ + $(d)/string/free.c\ + $(d)/string/grow.c\ + $(d)/string/join.c\ + $(d)/string/len.c\ + $(d)/string/lower.c\ + $(d)/string/make.c\ + $(d)/string/makef.c\ + $(d)/string/read.c\ + $(d)/string/replace.c\ + $(d)/string/split.c\ + $(d)/string/upper.c\ diff --git a/sys/base/string/split.c b/sys/base/string/split.c new file mode 100644 index 0000000..2aa68b4 --- /dev/null +++ b/sys/base/string/split.c @@ -0,0 +1,39 @@ +#include "internal.h" + +// split will split the string by the given token. +// returns a stretchy buffer of strings that result from the partition. +// it is the caller's responsibility to clean the memory. +string* +str·split(string s, const byte* tok) +{ + string* fields = nil; + vlong start = 0; + + vlong sL = str·len(s); + vlong tokL = strlen(tok); + if (sL == 0 || tokL == 0) return nil; + + buffit(fields, 5); + + for (vlong i = 0; i < sL - tokL; i++) { + if ((tokL == 1 && s[i] == tokL) || !memcmp(s + i, tok, tokL)) { + bufpush(fields, str·makelen(s + start, i - start)); + if (fields[buflen(fields) - 1] == nil) goto cleanup; + + start = i + tokL; + i += tokL - 1; + } + } + + bufpush(fields, str·makelen(s + start, sL - start)); + + return fields; + +cleanup: + for (vlong i = 0; i < buflen(fields); i++) { + str·free(fields[i]); + } + buffree(fields); + return nil; +} + diff --git a/sys/base/string/upper.c b/sys/base/string/upper.c new file mode 100644 index 0000000..ab692c1 --- /dev/null +++ b/sys/base/string/upper.c @@ -0,0 +1,12 @@ +#include "internal.h" + +// Upper will force all runes in the string to be uppercase. +void +str·upper(string s) +{ + byte *b, *e; + b = s; + e = b + str·len(s); + while (b++ != e) + *b = toupper(*b); +} -- cgit v1.2.1