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