]> git.xonotic.org Git - xonotic/gmqcc.git/blob - util.c
ensure all data is LE format, cleanups, etc.
[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         util_debug("MEM", "Memory information:\n\
65         Total allocations:   %llu\n\
66         Total deallocations: %llu\n\
67         Total allocated:     %llu (bytes)\n\
68         Total deallocated:   %llu (bytes)\n",
69                 mem_at, mem_dt,
70                 mem_ab, mem_db
71         );
72 }
73
74 //#ifndef mem_d
75 //#define mem_d(x) util_memory_d((x), __LINE__, __FILE__)
76 //#endif
77 //#ifndef mem_a
78 //#define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
79 //#endif
80
81 /*
82  * Some string utility functions, because strdup uses malloc, and we want
83  * to track all memory (without replacing malloc).
84  */
85 char *util_strdup(const char *s) {
86     size_t  len = 0;
87     char   *ptr = NULL;
88     
89     if (!s)
90         return NULL;
91         
92     if ((len = strlen(s)) && (ptr = mem_a(len+1))) {
93         memcpy(ptr, s, len);
94         ptr[len] = '\0';
95     }
96     return ptr;
97 }
98
99 /*
100  * Remove quotes from a string, escapes from \ in string
101  * as well.  This function shouldn't be used to create a
102  * char array that is later freed (it uses pointer arith)
103  */
104 char *util_strrq(char *s) {
105     char *dst = s;
106     char *src = s;
107     char  chr;
108     while ((chr = *src++) != '\0') {
109         if (chr == '\\') {
110             *dst++ = chr;
111             if ((chr = *src++) == '\0')
112                 break;
113             *dst++ = chr;
114         } else if (chr != '"')
115             *dst++ = chr;
116     }
117     *dst = '\0';
118     return dst;
119 }
120
121 /*
122  * Remove newline from a string (if it exists).  This is
123  * done pointer wise instead of strlen(), and an array
124  * access.
125  */
126 char *util_strrnl(char *src) {
127     if (!src) return NULL;
128     char   *cpy = src;
129     while (*cpy && *cpy != '\n')
130         cpy++;
131         
132     *cpy = '\0';
133     return src;
134 }
135
136 void util_debug(const char *area, const char *ms, ...) {
137     va_list  va;
138     va_start(va, ms);
139     fprintf (stdout, "DEBUG: ");
140     fputc   ('[',  stdout);
141     fprintf(stdout, "%s", area);
142     fputs   ("] ", stdout);
143     vfprintf(stdout, ms, va);
144     va_end  (va);
145 }
146
147 /*
148  * Endianess swapping, all data must be stored little-endian.  This
149  * reorders by stride and length, much nicer than other functions for
150  * certian-sized types like short or int.
151  */
152 void util_endianswap(void *m, int s, int l) {
153         size_t w = 0;
154         size_t i = 0;
155         
156         /* ignore if we're already LE */
157     if(*((char *)&s))
158                 return;
159     
160     for(; w < l; w++) {
161                 for(;  i < s << 1; i++) {
162                         unsigned char *p = (unsigned char *)m+w*s;
163                         unsigned char  t = p[i];
164                         p[i]             = p[s-i-1];
165                         p[s-i-1]         = t;
166                 }
167         }
168 }
169
170
171 /*
172  * Implements libc getline for systems that don't have it, which is 
173  * assmed all.  This works the same as getline().
174  */
175 int util_getline(char **lineptr, size_t *n, FILE *stream) {
176     int   chr;
177     int   ret;
178     char *pos;    
179
180     if (!lineptr || !n || !stream)
181         return -1;
182     if (!*lineptr) {
183         if (!(*lineptr = mem_a((*n = 64))))
184             return -1;
185     }
186
187     chr = *n;
188     pos = *lineptr;
189
190     for (;;) {
191         int c = getc(stream);
192         
193         if (chr < 2) {
194             char *tmp = mem_a((*n+=(*n>16)?*n:64));
195             if  (!tmp)
196                 return -1;
197             
198             chr = *n + *lineptr - pos;
199             strcpy(tmp,*lineptr);
200             if (!(*lineptr = tmp)) {
201                                 mem_d (tmp);
202                 return -1;
203             } 
204             pos = *n - chr + *lineptr;
205         }
206
207         if (ferror(stream))
208             return -1;
209         if (c == EOF) {
210             if (pos == *lineptr)
211                 return -1;
212             else
213                 break;
214         }
215
216         *pos++ = c;
217          chr--;
218         if (c == '\n')
219             break;
220     }
221     *pos = '\0';
222     return (ret = pos - *lineptr);
223 }