/* 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 */ while (**lasts && strchr(sep, **lasts)) { **lasts = '\0'; (*lasts)++; } 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; }