]> git.xonotic.org Git - xonotic/gmqcc.git/blob - util.c
slightly faster hash function (using crc32), with precomputed polynomial table (256x3...
[xonotic/gmqcc.git] / util.c
1 /*
2  * Copyright (C) 2012 
3  *     Dale Weiler
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is furnished to do
10  * so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 #include <stdarg.h>
24 #include <errno.h>
25 #include "gmqcc.h"
26
27 unsigned long long mem_ab = 0;
28 unsigned long long mem_db = 0;
29 unsigned long long mem_at = 0;
30 unsigned long long mem_dt = 0;
31
32 struct memblock_t {
33     const char  *file;
34     unsigned int line;
35     unsigned int byte;
36 };
37
38 void *util_memory_a(unsigned int byte, unsigned int line, const char *file) {
39     struct memblock_t *info = malloc(sizeof(struct memblock_t) + byte);
40     void              *data =(void*)((uintptr_t)info+sizeof(struct memblock_t));
41     if (!data) return NULL;
42     info->line = line;
43     info->byte = byte;
44     info->file = file;
45     
46     util_debug("MEM", "allocation: % 8u (bytes) address 0x%08X @ %s:%u\n", byte, data, file, line);
47     mem_at++;
48     mem_ab += info->byte;
49     return data;
50 }
51
52 void util_memory_d(void *ptrn, unsigned int line, const char *file) {
53     if (!ptrn) return;
54     void              *data = (void*)((uintptr_t)ptrn-sizeof(struct memblock_t));
55     struct memblock_t *info = (struct memblock_t*)data;
56     
57     util_debug("MEM", "released:   % 8u (bytes) address 0x%08X @ %s:%u\n", info->byte, data, file, line);
58     mem_db += info->byte;
59     mem_dt++;
60     free(data);
61 }
62
63 void util_meminfo() {
64     if (!opts_memchk)
65         return;
66         
67     util_debug("MEM", "Memory information:\n\
68         Total allocations:   %llu\n\
69         Total deallocations: %llu\n\
70         Total allocated:     %llu (bytes)\n\
71         Total deallocated:   %llu (bytes)\n",
72             mem_at, mem_dt,
73             mem_ab, mem_db
74     );
75 }
76
77 //#ifndef mem_d
78 //#define mem_d(x) util_memory_d((x), __LINE__, __FILE__)
79 //#endif
80 //#ifndef mem_a
81 //#define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
82 //#endif
83
84 /*
85  * Some string utility functions, because strdup uses malloc, and we want
86  * to track all memory (without replacing malloc).
87  */
88 char *util_strdup(const char *s) {
89     size_t  len = 0;
90     char   *ptr = NULL;
91     
92     if (!s)
93         return NULL;
94         
95     if ((len = strlen(s)) && (ptr = mem_a(len+1))) {
96         memcpy(ptr, s, len);
97         ptr[len] = '\0';
98     }
99     return ptr;
100 }
101
102 /*
103  * Remove quotes from a string, escapes from \ in string
104  * as well.  This function shouldn't be used to create a
105  * char array that is later freed (it uses pointer arith)
106  */
107 char *util_strrq(char *s) {
108     char *dst = s;
109     char *src = s;
110     char  chr;
111     while ((chr = *src++) != '\0') {
112         if (chr == '\\') {
113             *dst++ = chr;
114             if ((chr = *src++) == '\0')
115                 break;
116             *dst++ = chr;
117         } else if (chr != '"')
118             *dst++ = chr;
119     }
120     *dst = '\0';
121     return dst;
122 }
123
124 /*
125  * Remove newline from a string (if it exists).  This is
126  * done pointer wise instead of strlen(), and an array
127  * access.
128  */
129 char *util_strrnl(char *src) {
130     if (!src) return NULL;
131     char   *cpy = src;
132     while (*cpy && *cpy != '\n')
133         cpy++;
134         
135     *cpy = '\0';
136     return src;
137 }
138
139 void util_debug(const char *area, const char *ms, ...) {
140     if (!opts_debug)
141         return;
142         
143     va_list  va;
144     va_start(va, ms);
145     fprintf (stdout, "DEBUG: ");
146     fputc   ('[',  stdout);
147     fprintf(stdout, "%s", area);
148     fputs   ("] ", stdout);
149     vfprintf(stdout, ms, va);
150     va_end  (va);
151 }
152
153 /*
154  * Endianess swapping, all data must be stored little-endian.  This
155  * reorders by stride and length, much nicer than other functions for
156  * certian-sized types like short or int.
157  */
158 void util_endianswap(void *m, int s, int l) {
159     size_t w = 0;
160     size_t i = 0;
161
162     /* ignore if we're already LE */
163     if(*((char *)&s))
164         return;
165
166     for(; w < l; w++) {
167         for(;  i < s << 1; i++) {
168             unsigned char *p = (unsigned char *)m+w*s;
169             unsigned char  t = p[i];
170             p[i]             = p[s-i-1];
171             p[s-i-1]         = t;
172         }
173     }
174 }
175
176 /*
177  * This is an implementation of CRC32.  The polynomial has been offline
178  * computed for faster generation at the cost of larger code size.  This
179  * is used to compute hashes for hash-table.  This is not used for crc16
180  * generation of progs header calculation.
181  */
182 #define util_crc32_update(O,C) \
183     (util_crc32_table[((C)^((unsigned char)O)) & 0xFF] ^ ((C)>>8))
184
185 /* CRC polynomial 0xEDB88320 */
186 static const uint32_t util_crc32_table[] = {
187     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
188     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
189     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
190     0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
191     0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
192     0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
193     0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
194     0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
195     0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
196     0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
197     0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
198     0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
199     0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
200     0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
201     0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
202     0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
203     0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
204     0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
205     0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
206     0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
207     0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
208     0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
209     0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
210     0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
211     0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
212     0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
213     0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
214     0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
215     0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
216     0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
217     0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
218     0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
219     0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
220     0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
221     0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
222     0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
223     0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
224     0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
225     0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
226     0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
227     0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
228     0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
229     0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
230 };
231
232 uint32_t util_crc32(const char *key, int len, register const short clamp) {
233     register uint32_t hash = 0xFFFFFFFF;
234     for (; len; --len, ++key)
235         hash = util_crc32_update(*key, hash);
236     return (~hash) % clamp;
237 }
238
239 /*
240  * Implements libc getline for systems that don't have it, which is 
241  * assmed all.  This works the same as getline().
242  */
243 int util_getline(char **lineptr, size_t *n, FILE *stream) {
244     int   chr;
245     int   ret;
246     char *pos;    
247
248     if (!lineptr || !n || !stream)
249         return -1;
250     if (!*lineptr) {
251         if (!(*lineptr = mem_a((*n = 64))))
252             return -1;
253     }
254
255     chr = *n;
256     pos = *lineptr;
257
258     for (;;) {
259         int c = getc(stream);
260         
261         if (chr < 2) {
262             char *tmp = mem_a((*n+=(*n>16)?*n:64));
263             if  (!tmp)
264                 return -1;
265             
266             chr = *n + *lineptr - pos;
267             strcpy(tmp,*lineptr);
268             if (!(*lineptr = tmp)) {
269                 mem_d (tmp);
270                 return -1;
271             } 
272             pos = *n - chr + *lineptr;
273         }
274
275         if (ferror(stream))
276             return -1;
277         if (c == EOF) {
278             if (pos == *lineptr)
279                 return -1;
280             else
281                 break;
282         }
283
284         *pos++ = c;
285          chr--;
286         if (c == '\n')
287             break;
288     }
289     *pos = '\0';
290     return (ret = pos - *lineptr);
291 }