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