X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=common.c;fp=common.c;h=9dbadf369983950b2126efc8a5dcde63a307d2f2;hb=4706199a81dc631b6969927e1a6ad27591852b20;hp=0000000000000000000000000000000000000000;hpb=503abee3b3bf76015786f5a99e31117fbfe2d310;p=dcpu16 diff --git a/common.c b/common.c new file mode 100644 index 0000000..9dbadf3 --- /dev/null +++ b/common.c @@ -0,0 +1,202 @@ +/* common.c + * Utility functions shared between modules, but not exported. + */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "dcpu16.h" + +/* initialize a generic dynamic array struct */ +int dynarray_init(struct dynamic_array *da, size_t entry_size, size_t grow_size) { + assert(da); + assert(entry_size); + assert(grow_size); + + if (entry_size == 0 || grow_size == 0) { + fprintf(stderr, "%s: internal error: sizes cannot be zero\n", __func__); + errno = EINVAL; + return -1; + } + + da->allocated = 0; + da->entries = 0; + da->entry_size = entry_size; + da->grow_size = grow_size; + da->a = malloc(da->entry_size * da->grow_size); + if (da->a == NULL) { + fprintf(stderr, "%s():%s\n", "malloc", strerror(errno)); + return -1; + } + da->allocated = da->grow_size; + return 0; +} + +/* allocate and initialize a new generic dynamic array */ +struct dynamic_array *dynarray_new(size_t entry_size, size_t grow_size) { + struct dynamic_array *da; + + assert(entry_size); + assert(grow_size); + + da = calloc(1, sizeof *da); + if (da == NULL) { + fprintf(stderr, "%s():%s\n", "calloc", strerror(errno)); + return NULL; + } + + if (dynarray_init(da, entry_size, grow_size)) { + fprintf(stderr, "%s():%s\n", "dynarray_init", strerror(errno)); + free(da); + return NULL; + } + + return da; +} + +/* copy item onto end of array */ +void *dynarray_add(struct dynamic_array *da, void *item) { + void *dst; + + assert(da); + assert(item); + + /* make room, make room */ + if (da->entries == da->allocated) { + size_t new_allocated = da->allocated + da->grow_size; + void *tmp_ptr = realloc(da->a, new_allocated * da->entry_size); + if (tmp_ptr == NULL) { + fprintf(stderr, "%s():%s\n", "realloc", strerror(errno)); + return NULL; + } + da->a = tmp_ptr; + da->allocated = new_allocated; + + } + + dst = DYNARRAY_ITEM(*da, da->entries); + memcpy(dst, item, da->entry_size); + + da->entries++; + + return dst; +} + +/* simplified strtoul with range checking */ +int str_to_word(char *s) { + unsigned long l; + char *ep; + + assert(s); + + errno = 0; + l = strtoul(s, &ep, 0); + + if (errno + || !(*s && *ep == '\0') ) { + /* out of range of conversion, or invalid character encountered */ + return -1; + } + + if (l >= DCPU16_RAM) { + /* out of range for our needs */ + errno = ERANGE; + return -1; + } + + return l; +} + +/* just like strtok_r, but ignores separators within quotes */ +char *strqtok_r(char *str, const char *sep, int esc, const char *quote, char **lastq, char **lasts) { + int escaped = 0; + int retry; + char *tok, + *lastq_ret = NULL, + *src, + *dst; + + if (str) { + *lasts = str; + *lastq = NULL; + } + + /* next token starts after any leading seps */ + *lasts += strspn(*lasts, sep); + tok = *lasts; + if (*tok == '\0') + return NULL; + + do { + retry = 0; + while (**lasts) { + /* the previous character was the escape, do not consider this character any further */ + if (escaped) { + escaped = 0; + (*lasts)++; + continue; + } + + /* this character is the escape, do not consider the next character */ + if (**lasts == esc) { + escaped = 1; + (*lasts)++; + continue; + } + + /* we have a quote open, only consider matching quote to close */ + if (*lastq) { + if (**lasts == **lastq) + *lastq = NULL; + (*lasts)++; + continue; + } + + /* this character is an opening quote, remember what it is */ + if (strchr(quote, **lasts)) { + *lastq = *lasts; + (*lasts)++; + continue; + } + + /* this character is a separator, separate and be done */ + if (strchr(sep, **lasts)) { + **lasts = '\0'; + (*lasts)++; + break; + } + (*lasts)++; + } + + /* were we left with an unmatched quote? + remember where we had trouble + try everything following lonely quote again, but pretend quote is there */ + if (*lastq) { + lastq_ret = *lastq; + *lasts = *lastq + 1; + *lastq = NULL; + retry = 1; + } + } while (retry); + + /* now strip escape characters */ + for (src = dst = tok; *src; src++, dst++) { + if (*src == esc) { + src++; + if (*src == '\0') + break; + } + *dst = *src; + } + *dst = *src; + + /* remember where we had trouble */ + if (lastq_ret) + *lastq = lastq_ret; + + return tok; +}