]> git.xonotic.org Git - xonotic/gmqcc.git/blob - util.c
-fdarkplaces-stringtablebug
[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 void util_debug(const char *area, const char *ms, ...) {
136     if (!opts_debug)
137         return;
138         
139     va_list  va;
140     va_start(va, ms);
141     fprintf (stdout, "DEBUG: ");
142     fputc   ('[',  stdout);
143     fprintf(stdout, "%s", area);
144     fputs   ("] ", stdout);
145     vfprintf(stdout, ms, va);
146     va_end  (va);
147 }
148
149 /*
150  * Endianess swapping, all data must be stored little-endian.  This
151  * reorders by stride and length, much nicer than other functions for
152  * certian-sized types like short or int.
153  */
154 void util_endianswap(void *m, int s, int l) {
155     size_t w = 0;
156     size_t i = 0;
157
158     /* ignore if we're already LE */
159     // if(*((char *)&s))
160     //    return;
161
162     for(; w < l; w++) {
163         for(;  i < s << 1; i++) {
164             unsigned char *p = &((unsigned char *)m+w*s)[i];
165             *p = ((*p * 0x0802LU & 0x22110LU) | (*p * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; 
166         }
167     }
168 }
169
170 /*
171  * This is an implementation of CRC32.  The polynomial has been offline
172  * computed for faster generation at the cost of larger code size.  This
173  * is used to compute hashes for hash-table.  This is not used for crc16
174  * generation of progs header calculation.
175  */
176 #define util_crc32_update(O,C) \
177     (util_crc32_table[((C)^((unsigned char)O)) & 0xFF] ^ ((C)>>8))
178
179 /* CRC polynomial 0xEDB88320 */
180 static const uint32_t util_crc32_table[] = {
181     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
182     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
183     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
184     0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
185     0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
186     0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
187     0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
188     0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
189     0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
190     0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
191     0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
192     0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
193     0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
194     0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
195     0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
196     0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
197     0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
198     0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
199     0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
200     0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
201     0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
202     0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
203     0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
204     0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
205     0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
206     0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
207     0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
208     0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
209     0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
210     0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
211     0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
212     0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
213     0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
214     0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
215     0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
216     0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
217     0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
218     0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
219     0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
220     0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
221     0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
222     0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
223     0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
224 };
225
226 uint32_t util_crc32(const char *key, int len, register const short clamp) {
227     register uint32_t hash = 0xFFFFFFFF;
228     for (; len; --len, ++key)
229         hash = util_crc32_update(*key, hash);
230     return (~hash) % clamp;
231 }
232
233 /*
234  * Implements libc getline for systems that don't have it, which is 
235  * assmed all.  This works the same as getline().
236  */
237 int util_getline(char **lineptr, size_t *n, FILE *stream) {
238     int   chr;
239     int   ret;
240     char *pos;    
241
242     if (!lineptr || !n || !stream)
243         return -1;
244     if (!*lineptr) {
245         if (!(*lineptr = mem_a((*n = 64))))
246             return -1;
247     }
248
249     chr = *n;
250     pos = *lineptr;
251
252     for (;;) {
253         int c = getc(stream);
254         
255         if (chr < 2) {
256             char *tmp = mem_a((*n+=(*n>16)?*n:64));
257             if  (!tmp)
258                 return -1;
259             
260             chr = *n + *lineptr - pos;
261             strcpy(tmp,*lineptr);
262             if (!(*lineptr = tmp)) {
263                 mem_d (tmp);
264                 return -1;
265             } 
266             pos = *n - chr + *lineptr;
267         }
268
269         if (ferror(stream))
270             return -1;
271         if (c == EOF) {
272             if (pos == *lineptr)
273                 return -1;
274             else
275                 break;
276         }
277
278         *pos++ = c;
279          chr--;
280         if (c == '\n')
281             break;
282     }
283     *pos = '\0';
284     return (ret = pos - *lineptr);
285 }