/* common.c * Utility functions shared between modules, but not exported. */ #include #include #include #include #include #include #include #ifdef __MACH__ #include #include #endif /* __MACH__ */ #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; } void dynarray_empty(struct dynamic_array *da, void (*free_element)(void *)) { while ( da->entries-- ) { void *element = (void *)DYNARRAY_ITEM(*da, da->entries); free_element(element); } free(da->a); da->a = NULL; da->allocated = 0; } /* 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; } /* like gettimeofday, except with nanoseconds */ inline int gettimespecofday(struct timespec *ts) { int retval = 0; #ifdef __MACH__ clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); ts->tv_sec = mts.tv_sec; ts->tv_nsec = mts.tv_nsec; #else /* __MACH__ */ retval = clock_gettime(CLOCK_REALTIME, ts); #endif /* __MACH__ */ return retval; } inline int timespec_add(struct timespec *result, const struct timespec *x) { result->tv_sec += x->tv_sec; result->tv_nsec += x->tv_nsec; result->tv_sec += result->tv_nsec / 1000000000; result->tv_nsec %= 1000000000; return 0; } inline int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) { if (x->tv_nsec < y->tv_nsec) { int z = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; y->tv_nsec -= 1000000000 * z; y->tv_sec += z; } if (x->tv_nsec - y->tv_nsec > 1000000000) { int z = (x->tv_nsec - y->tv_nsec) / 1000000000; y->tv_nsec += 1000000000 * z; y->tv_sec -= z; } result->tv_sec = x->tv_sec - y->tv_sec; result->tv_nsec = x->tv_nsec - y->tv_nsec; return x->tv_sec < y->tv_sec; } int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. tv_usec is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; }