X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=util.c;h=e6823e95f6b8b1154a62e8f0e1f12d1e03dbf341;hp=3c2e4d38870c7732099faccf4540061d6a09a681;hb=f4edbe21653509e671fa9e9b0c97c445acfa0ccc;hpb=906f319673f6a2eddb62e59acc970b9497f3e96a diff --git a/util.c b/util.c index 3c2e4d3..e6823e9 100644 --- a/util.c +++ b/util.c @@ -92,7 +92,7 @@ void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file } oldinfo = ((struct memblock_t*)ptrn - 1); - newinfo = malloc(sizeof(struct memblock_t) + byte); + newinfo = ((struct memblock_t*)malloc(sizeof(struct memblock_t) + byte)); util_debug("MEM", "reallocation: % 8u -> %u (bytes) address 0x%08X -> 0x%08X @ %s:%u\n", oldinfo->byte, byte, ptrn, (void*)(newinfo+1), file, line); @@ -101,27 +101,33 @@ void *util_memory_r(void *ptrn, size_t byte, unsigned int line, const char *file util_memory_d(oldinfo+1, line, file); return NULL; } + + /* copy old */ + memcpy(newinfo+1, oldinfo+1, oldinfo->byte); + + /* free old */ + if (oldinfo->prev) + oldinfo->prev->next = oldinfo->next; + if (oldinfo->next) + oldinfo->next->prev = oldinfo->prev; + if (oldinfo == mem_start) + mem_start = oldinfo->next; + + /* fill info */ newinfo->line = line; newinfo->byte = byte; newinfo->file = file; - newinfo->next = oldinfo->next; - newinfo->prev = oldinfo->prev; - if (newinfo->next) - newinfo->next->prev = newinfo; - if (newinfo->prev) - newinfo->prev->next = newinfo; - if (mem_start == oldinfo) - mem_start = newinfo; + newinfo->prev = NULL; + newinfo->next = mem_start; + if (mem_start) + mem_start->prev = newinfo; + mem_start = newinfo; - /* copy old */ - memcpy(newinfo+1, oldinfo+1, oldinfo->byte); + mem_ab -= oldinfo->byte; + mem_ab += newinfo->byte; - /* drop old */ - mem_db += newinfo->byte; - mem_db -= oldinfo->byte; free(oldinfo); - /* update */ return newinfo+1; } @@ -264,8 +270,8 @@ void util_endianswap(void *m, int s, int l) { if(*((char *)&s)) return; - for(; w < l; w++) { - for(; i < s << 1; i++) { + for(; w < (size_t)l; w++) { + for(; i < (size_t)(s << 1); i++) { unsigned char *p = (unsigned char *)m+w*s; unsigned char t = p[i]; p[i] = p[s-i-1]; @@ -444,16 +450,10 @@ int util_getline(char **lineptr, size_t *n, FILE *stream) { int c = getc(stream); if (chr < 2) { - char *tmp = (char*)mem_a((*n+=(*n>16)?*n:64)); - if (!tmp) - return -1; - - memcpy(tmp, *lineptr, pos - *lineptr); + *n += (*n > 16) ? *n : 64; chr = *n + *lineptr - pos; - if (!(*lineptr = tmp)) { - mem_d (tmp); + if (!(*lineptr = (char*)mem_r(*lineptr,*n))) return -1; - } pos = *n - chr + *lineptr; } @@ -477,32 +477,21 @@ int util_getline(char **lineptr, size_t *n, FILE *stream) { size_t util_strtocmd(const char *in, char *out, size_t outsz) { size_t sz = 1; - for (; *in && sz < outsz; ++in, ++out, ++sz) { - if (*in == '-') - *out = '_'; - else if (isalpha(*in) && !isupper(*in)) - *out = *in + 'A' - 'a'; - else - *out = *in; - } + for (; *in && sz < outsz; ++in, ++out, ++sz) + *out = (*in == '-') ? '_' : (isalpha(*in) && !isupper(*in)) ? *in + 'A' - 'a': *in; *out = 0; return sz-1; } size_t util_strtononcmd(const char *in, char *out, size_t outsz) { size_t sz = 1; - for (; *in && sz < outsz; ++in, ++out, ++sz) { - if (*in == '_') - *out = '-'; - else if (isalpha(*in) && isupper(*in)) - *out = *in + 'a' - 'A'; - else - *out = *in; - } + for (; *in && sz < outsz; ++in, ++out, ++sz) + *out = (*in == '_') ? '-' : (isalpha(*in) && isupper(*in)) ? *in + 'a' - 'A' : *in; *out = 0; return sz-1; } + FILE *util_fopen(const char *filename, const char *mode) { #ifdef WIN32 @@ -523,3 +512,149 @@ void _util_vec_grow(void **a, size_t i, size_t s) { *a = (void*)((size_t*)p + 2); _vec_beg(*a) = m; } + +/* + * Hash table for generic data, based on dynamic memory allocations + * all around. This is the internal interface, please look for + * EXPOSED INTERFACE comment below + */ +typedef struct hash_node_t { + char *key; /* the key for this node in table */ + void *value; /* allocated memory storing data */ + size_t size; /* size of data */ + struct hash_node_t *next; /* next node (linked list) */ +} hash_node_t; + + +size_t _util_hthash(hash_table_t *ht, const char *key) { + uint64_t val; + size_t len = strlen(key); + size_t itr = 0; + + + while (val < ((uint64_t)~1) /* MAX SIZE OF UINT64 */ && itr < len) { + val = val << 8; + val += key[itr]; + + itr++; + } + + return val % ht->size; +} + +hash_node_t *_util_htnewpair(const char *key, void *value, size_t size) { + hash_node_t *node; + if (!(node = mem_a(sizeof(hash_node_t)))) + return NULL; + + if (!(node->key = util_strdup(key))) { + mem_d(node); + return NULL; + } + + if (!(node->value = mem_a(size))) { + mem_d(node->key); + mem_d(node); + return NULL; + } + + memcpy(node->value, value, size); + node->size = size; + node->next = NULL; + + return node; +} + +/* + * EXPOSED INTERFACE for the hashtable implementation + * util_htnew(size) -- to make a new hashtable + * util_htset(table, key, value, sizeof(value)) -- to set something in the table + * util_htget(table, key) -- to get something from the table + * util_htdel(table) -- to delete the table + */ +hash_table_t *util_htnew(size_t size) { + hash_table_t *hashtable = NULL; + if (size < 1) + return NULL; + + if (!(hashtable = mem_a(sizeof(hash_table_t)))) + return NULL; + + if (!(hashtable->table = mem_a(sizeof(hash_node_t*) * size))) { + mem_d(hashtable); + return NULL; + } + + hashtable->size = size; + memset(hashtable->table, 0, sizeof(hash_node_t*) * size); + + return hashtable; +} + +void util_htset(hash_table_t *ht, const char *key, void *value, size_t size) { + size_t bin = 0; + hash_node_t *newnode = NULL; + hash_node_t *next = NULL; + hash_node_t *last = NULL; + + bin = _util_hthash(ht, key); + next = ht->table[bin]; + + while (next && next->key && strcmp(key, next->key)) + last = next, next = next->next; + + /* already in table, do a replace */ + if (next && next->key && !strcmp(key, next->key)) { + mem_d(next->value); + next->value = mem_a(size); + next->size = size; + memcpy(next->value, value, size); + } else { + /* not found, grow a pair man :P */ + newnode = _util_htnewpair(key, value, size); + if (next == ht->table[bin]) { + newnode->next = next; + ht->table[bin] = newnode; + } else if (!next) { + last->next = newnode; + } else { + newnode->next = next; + last->next = newnode; + } + } +} + +void *util_htget(hash_table_t *ht, const char *key) { + size_t bin = _util_hthash(ht, key); + hash_node_t *pair = ht->table[bin]; + + while (pair && pair->key && strcmp(key, pair->key) > 0) + pair = pair->next; + + if (!pair || !pair->key || strcmp(key, pair->key) != 0) + return NULL; + + return pair->value; +} + +/* + * Free all allocated data in a hashtable, this is quite the amount + * of work. + */ +void util_htdel(hash_table_t *ht) { + size_t i = 0; + for (; i < ht->size; i++) { + hash_node_t *n = ht->table[i]; + + /* free in list */ + while (n) { + if (n->key) mem_d(n->key); + if (n->value) mem_d(n->value); + n = n->next; + } + + } + /* free table */ + mem_d(ht->table); + mem_d(ht); +}