]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - util.c
9b8fb5c9115c5ffbe25b72f2e11dfd3e8ed48b02
[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 uint64_t mem_ab = 0;
28 uint64_t mem_db = 0;
29 uint64_t mem_at = 0;
30 uint64_t 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
50     return data;
51 }
52
53 void util_memory_d(void *ptrn, unsigned int line, const char *file) {
54     void              *data = NULL;
55     struct memblock_t *info = NULL;
56     if (!ptrn) return;
57     data = (void*)((uintptr_t)ptrn-sizeof(struct memblock_t));
58     info = (struct memblock_t*)data;
59
60     util_debug("MEM", "released:   % 8u (bytes) address 0x%08X @ %s:%u\n", info->byte, data, file, line);
61     mem_db += info->byte;
62     mem_dt++;
63
64     free(data);
65 }
66
67 void util_meminfo() {
68     if (!opts_memchk)
69         return;
70
71     util_debug("MEM", "Memory information:\n\
72         Total allocations:   %llu\n\
73         Total deallocations: %llu\n\
74         Total allocated:     %llu (bytes)\n\
75         Total deallocated:   %llu (bytes)\n\
76         Leaks found:         lost %llu (bytes) in %d allocations\n",
77             mem_at,   mem_dt,
78             mem_ab,   mem_db,
79            (mem_ab -  mem_db),
80            (mem_at -  mem_dt)
81     );
82 }
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(const char *s) {
108     char *dst = (char*)s;
109     char *src = (char*)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  * Chops a substring from an existing string by creating a
126  * copy of it and null terminating it at the required position.
127  */
128 char *util_strchp(const char *s, const char *e) {
129     const char *c = NULL;
130     if (!s || !e)
131         return NULL;
132
133     c = s;
134     while (c != e)
135         c++;
136
137     return util_strdup(s);
138 }
139
140 /*
141  * Returns true if string is all uppercase, otherwise
142  * it returns false.
143  */
144 bool util_strupper(const char *str) {
145     while (*str) {
146         if(!isupper(*str))
147             return false;
148         str++;
149     }
150     return true;
151 }
152
153 /*
154  * Returns true if string is all digits, otherwise
155  * it returns false.
156  */
157 bool util_strdigit(const char *str) {
158     while (*str) {
159         if(!isdigit(*str))
160             return false;
161         str++;
162     }
163     return true;
164 }
165
166 bool util_strncmpexact(const char *src, const char *ned, size_t len) {
167     if (!strncmp(src, ned, len)) {
168         if (!src[len])
169             return true;
170     }
171     return false;
172 }
173
174 void util_debug(const char *area, const char *ms, ...) {
175     va_list  va;
176     if (!opts_debug)
177         return;
178
179     va_start(va, ms);
180     fprintf (stdout, "DEBUG: ");
181     fputc   ('[',  stdout);
182     fprintf(stdout, "%s", area);
183     fputs   ("] ", stdout);
184     vfprintf(stdout, ms, va);
185     va_end  (va);
186 }
187
188 /*
189  * Endianess swapping, all data must be stored little-endian.  This
190  * reorders by stride and length, much nicer than other functions for
191  * certian-sized types like short or int.
192  */
193 void util_endianswap(void *m, int s, int l) {
194     size_t w = 0;
195     size_t i = 0;
196
197     /* ignore if we're already LE */
198     if(*((char *)&s))
199         return;
200
201     for(; w < l; w++) {
202         for(;  i < s << 1; i++) {
203             unsigned char *p = (unsigned char *)m+w*s;
204             unsigned char  t = p[i];
205             p[i]             = p[s-i-1];
206             p[s-i-1]         = t;
207         }
208     }
209 }
210
211 /*
212  * This is an implementation of CRC32 & CRC16. The polynomials have been
213  * offline computed for faster generation at the cost of larger code size.
214  *
215  * CRC32 Polynomial: 0xEDB88320
216  * CRC16 Polynomial: 0x00001021
217  */
218 static const uint32_t util_crc32_table[] = {
219     0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
220     0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
221     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
222     0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
223     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
224     0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
225     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
226     0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
227     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
228     0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
229     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
230     0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
231     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
232     0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
233     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
234     0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
235     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
236     0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
237     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
238     0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
239     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
240     0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
241     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
242     0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
243     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
244     0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
245     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
246     0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
247     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
248     0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
249     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
250     0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
251     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
252     0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
253     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
254     0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
255     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
256     0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
257     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
258     0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
259     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
260     0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
261     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
262 };
263 static const uint16_t util_crc16_table[] = {
264     0x0000,     0x1021,     0x2042,     0x3063,     0x4084,     0x50A5,
265     0x60C6,     0x70E7,     0x8108,     0x9129,     0xA14A,     0xB16B,
266     0xC18C,     0xD1AD,     0xE1CE,     0xF1EF,     0x1231,     0x0210,
267     0x3273,     0x2252,     0x52B5,     0x4294,     0x72F7,     0x62D6,
268     0x9339,     0x8318,     0xB37B,     0xA35A,     0xD3BD,     0xC39C,
269     0xF3FF,     0xE3DE,     0x2462,     0x3443,     0x0420,     0x1401,
270     0x64E6,     0x74C7,     0x44A4,     0x5485,     0xA56A,     0xB54B,
271     0x8528,     0x9509,     0xE5EE,     0xF5CF,     0xC5AC,     0xD58D,
272     0x3653,     0x2672,     0x1611,     0x0630,     0x76D7,     0x66F6,
273     0x5695,     0x46B4,     0xB75B,     0xA77A,     0x9719,     0x8738,
274     0xF7DF,     0xE7FE,     0xD79D,     0xC7BC,     0x48C4,     0x58E5,
275     0x6886,     0x78A7,     0x0840,     0x1861,     0x2802,     0x3823,
276     0xC9CC,     0xD9ED,     0xE98E,     0xF9AF,     0x8948,     0x9969,
277     0xA90A,     0xB92B,     0x5AF5,     0x4AD4,     0x7AB7,     0x6A96,
278     0x1A71,     0x0A50,     0x3A33,     0x2A12,     0xDBFD,     0xCBDC,
279     0xFBBF,     0xEB9E,     0x9B79,     0x8B58,     0xBB3B,     0xAB1A,
280     0x6CA6,     0x7C87,     0x4CE4,     0x5CC5,     0x2C22,     0x3C03,
281     0x0C60,     0x1C41,     0xEDAE,     0xFD8F,     0xCDEC,     0xDDCD,
282     0xAD2A,     0xBD0B,     0x8D68,     0x9D49,     0x7E97,     0x6EB6,
283     0x5ED5,     0x4EF4,     0x3E13,     0x2E32,     0x1E51,     0x0E70,
284     0xFF9F,     0xEFBE,     0xDFDD,     0xCFFC,     0xBF1B,     0xAF3A,
285     0x9F59,     0x8F78,     0x9188,     0x81A9,     0xB1CA,     0xA1EB,
286     0xD10C,     0xC12D,     0xF14E,     0xE16F,     0x1080,     0x00A1,
287     0x30C2,     0x20E3,     0x5004,     0x4025,     0x7046,     0x6067,
288     0x83B9,     0x9398,     0xA3FB,     0xB3DA,     0xC33D,     0xD31C,
289     0xE37F,     0xF35E,     0x02B1,     0x1290,     0x22F3,     0x32D2,
290     0x4235,     0x5214,     0x6277,     0x7256,     0xB5EA,     0xA5CB,
291     0x95A8,     0x8589,     0xF56E,     0xE54F,     0xD52C,     0xC50D,
292     0x34E2,     0x24C3,     0x14A0,     0x0481,     0x7466,     0x6447,
293     0x5424,     0x4405,     0xA7DB,     0xB7FA,     0x8799,     0x97B8,
294     0xE75F,     0xF77E,     0xC71D,     0xD73C,     0x26D3,     0x36F2,
295     0x0691,     0x16B0,     0x6657,     0x7676,     0x4615,     0x5634,
296     0xD94C,     0xC96D,     0xF90E,     0xE92F,     0x99C8,     0x89E9,
297     0xB98A,     0xA9AB,     0x5844,     0x4865,     0x7806,     0x6827,
298     0x18C0,     0x08E1,     0x3882,     0x28A3,     0xCB7D,     0xDB5C,
299     0xEB3F,     0xFB1E,     0x8BF9,     0x9BD8,     0xABBB,     0xBB9A,
300     0x4A75,     0x5A54,     0x6A37,     0x7A16,     0x0AF1,     0x1AD0,
301     0x2AB3,     0x3A92,     0xFD2E,     0xED0F,     0xDD6C,     0xCD4D,
302     0xBDAA,     0xAD8B,     0x9DE8,     0x8DC9,     0x7C26,     0x6C07,
303     0x5C64,     0x4C45,     0x3CA2,     0x2C83,     0x1CE0,     0x0CC1,
304     0xEF1F,     0xFF3E,     0xCF5D,     0xDF7C,     0xAF9B,     0xBFBA,
305     0x8FD9,     0x9FF8,     0x6E17,     0x7E36,     0x4E55,     0x5E74,
306     0x2E93,     0x3EB2,     0x0ED1,     0x1EF0
307 };
308
309 /*
310  * Implements a CRC function for X worth bits using (uint[X]_t)
311  * as type. and util_crc[X]_table.
312  */
313 #define CRC(X) \
314 uint##X##_t util_crc##X(const char *k, int len, const short clamp) {  \
315     register uint##X##_t h= (uint##X##_t)0xFFFFFFFF;                  \
316     for (; len; --len, ++k)                                           \
317         h = util_crc##X##_table[(h^((unsigned char)*k))&0xFF]^(h>>8); \
318     return (~h)%clamp;                                                \
319 }
320 CRC(32)
321 CRC(16)
322 #undef CRC
323
324 /*
325  * Implements libc getline for systems that don't have it, which is
326  * assmed all.  This works the same as getline().
327  */
328 int util_getline(char **lineptr, size_t *n, FILE *stream) {
329     int   chr;
330     int   ret;
331     char *pos;
332
333     if (!lineptr || !n || !stream)
334         return -1;
335     if (!*lineptr) {
336         if (!(*lineptr = mem_a((*n=64))))
337             return -1;
338     }
339
340     chr = *n;
341     pos = *lineptr;
342
343     for (;;) {
344         int c = getc(stream);
345
346         if (chr < 2) {
347             char *tmp = mem_a((*n+=(*n>16)?*n:64));
348             if  (!tmp)
349                 return -1;
350
351             chr = *n + *lineptr - pos;
352             strcpy(tmp,*lineptr);
353             if (!(*lineptr = tmp)) {
354                 mem_d (tmp);
355                 return -1;
356             }
357             pos = *n - chr + *lineptr;
358         }
359
360         if (ferror(stream))
361             return -1;
362         if (c == EOF) {
363             if (pos == *lineptr)
364                 return -1;
365             else
366                 break;
367         }
368
369         *pos++ = c;
370         chr--;
371         if (c == '\n')
372             break;
373     }
374     *pos = '\0';
375     return (ret = pos - *lineptr);
376 }
377
378 /* TODO: opts.c? when it gets large enugh */
379 /* global options */
380 bool opts_debug                     = false;
381 bool opts_memchk                    = false;
382 bool opts_darkplaces_stringtablebug = false;
383 bool opts_omit_nullcode             = false;
384 int  opts_compiler                  = COMPILER_GMQCC;