add .gitignore
[tedtools.git] / tmalloc.c
1 /*
2  * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *        notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *        notice, this list of conditions and the following disclaimer in the
12  *        documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *        may be used to endorse or promote products derived from this software
15  *        without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdarg.h>
34
35 #include "tlog.h"
36 #include "tmalloc.h"
37
38 void *
39 tmalloc(size_t size) {
40         void *ptr = malloc(size);
41         if (!ptr)
42                 tlog(TL_CRIT|TL_EXIT, "Can't allocate %d bytes", size);
43         return ptr;
44 }
45
46 void *
47 t0malloc(size_t size) {
48         void *ptr = tmalloc(size);
49         memset(ptr,0,size);
50         return ptr;
51 }
52
53 void *
54 trealloc(void * ptr, size_t size) {
55         if (ptr) {
56                 ptr = realloc(ptr,size);
57                 if (!ptr)
58                         tlog(TL_CRIT|TL_EXIT, "Can't reallocate to %d bytes", size);
59         } else
60                 ptr = tmalloc(size);    
61         return ptr;
62 }
63
64 void
65 tfree(void * ptr) {
66         free(ptr);
67 }
68
69 char * 
70 tstrdup(char * src) {
71         char * dest = strdup(src);
72         if (!dest) 
73                 tlog(TL_CRIT|TL_EXIT, "Can't strdup %d bytes", strlen(src)+1);
74         return dest;
75 }
76
77 char *
78 tnstrdup(char *src, int len) {
79         char *dest=(char*)tmalloc(len+1);
80         memcpy(dest, src, len);
81         dest[len]='\0';
82         return dest;
83 }
84
85 char *
86 strlower(char * src) {
87         char *ptr = src;
88         if (!src) return src;
89         while(*ptr) {
90                 *ptr = tolower(*(unsigned char *) ptr);
91                 ptr++; 
92         }
93         return src;
94 }
95
96 char *
97 strupper(char * src) {
98         char *ptr = src;
99         if (!src) return src;
100         while(*ptr) {
101                 *ptr = toupper(*(unsigned char *) ptr);
102                 ptr++; 
103         }
104         return src;
105 }
106
107 int
108 clrspace(char *buf) {
109         char *ptr=buf, *ptrc=buf;
110         while(*ptr) {
111                 if (!isspace(*ptr)) {
112                         *ptrc=*ptr;
113                         ptrc++;
114                 }
115                 ptr++;
116         }
117         *ptrc='\0';
118         return ptrc - buf;
119 }
120
121
122 MemoryContext *
123 allocMemoryContext(MemoryContext* parent, int flags) {
124         MemoryContext *res;
125
126         res = (MemoryContext*)tmalloc( sizeof(MemoryContext) );
127         res->flags = flags;
128         res->parent = parent;
129         if ( parent ) {
130                 res->child = parent->child;
131                 parent->child = res;
132         } else
133                 res->child = NULL;
134
135         res->chunk = (MemoryChunk*)tmalloc( MEMCHNKHDRSZ + CNTXCHUNK );
136         res->chunk->size = res->chunk->freesize = CNTXCHUNK;
137         res->chunk->next = NULL;
138
139         return res;
140 }
141
142 void
143 freeMemoryContext(MemoryContext *cntx) {
144         MemoryContext   *ptr=cntx;
145         MemoryChunk     *chunk, *chunkptr;
146
147         if ( cntx->parent )
148                 cntx->parent->child=NULL;
149
150         while( ptr ) {
151                 cntx=ptr->child;
152
153                 chunkptr=ptr->chunk;
154                 while( chunkptr ) {
155                         chunk=chunkptr->next;
156                         tfree(chunkptr);
157                         chunkptr=chunk;
158                 }
159                 
160                 tfree(ptr);
161                 ptr=cntx;
162         }
163 }
164
165 void
166 resetMemoryContext(MemoryContext *cntx) {
167         MemoryChunk *chunk, *chunkptr;
168
169         while( cntx ) {
170                 chunkptr = cntx->chunk;
171                 chunkptr->freesize = chunkptr->size;
172                 chunkptr = chunkptr->next;
173                 cntx->chunk->next = NULL;
174
175                 while( chunkptr ) {
176                         chunk=chunkptr->next;
177                         tfree(chunkptr);
178                         chunkptr=chunk;
179                 }
180                 cntx=cntx->child;
181         }
182 }
183
184 void*   
185 mcalloc(MemoryContext *cntx, size_t size) {
186         MemoryChunk     *chunk = cntx->chunk;
187         MCAllocatedSpace *alloc;
188
189         size = PTRALIGN(size) + MCASHDRSZ;
190         if ( cntx->flags & MC_DEBUG )
191                 size += sizeof(u_int32_t);
192
193         if ( chunk->freesize < size ) {
194                 MemoryChunk     *newchunk;
195
196                 if ( size >= CNTXCHUNK ) {
197                         newchunk = (MemoryChunk*)tmalloc(MEMCHNKHDRSZ + size);
198                         newchunk->size = newchunk->freesize = size;
199                         newchunk->next = chunk->next;
200                         chunk->next = newchunk;
201                 } else {
202                         newchunk = (MemoryChunk*)tmalloc(MEMCHNKHDRSZ + CNTXCHUNK);
203                         newchunk->size = newchunk->freesize = CNTXCHUNK;
204                         newchunk->next = chunk;
205                         cntx->chunk = newchunk; 
206                 }
207
208                 chunk = newchunk;
209         }
210
211         alloc = (MCAllocatedSpace*)( chunk->data + chunk->size - chunk->freesize );
212         alloc->size = size; 
213         alloc->cntx = cntx;
214         chunk->freesize -= size;
215  
216         if ( cntx->flags & MC_DEBUG ) {
217                 *(u_int32_t*)((char*)alloc + alloc->size - sizeof(u_int32_t) ) = MCMAGICKNUMBER;
218                 memset( alloc->data, 0xc3, size - MCASHDRSZ - sizeof(u_int32_t) ); 
219         }
220
221         return (void*)(alloc->data);
222 }
223
224 void *
225 mc0alloc(MemoryContext *cntx, size_t size) {
226         void *res = mcalloc(cntx, size);
227         memset( res, 0, size );
228         return res;
229 }
230
231 void *
232 mcrealloc(void * ptr, size_t size) {
233         MCAllocatedSpace        *alloc = (MCAllocatedSpace*)( (char*)ptr - MCASHDRSZ );
234         size_t realsize;
235
236         if ( ptr==NULL )
237                 tlog(TL_CRIT|TL_EXIT, "mcrealloc: realloc null pointer");
238
239         if ( alloc->cntx->flags & MC_DEBUG ) {
240                 tassert(  *(u_int32_t*)( (char*)alloc + alloc->size - sizeof(u_int32_t) ) == MCMAGICKNUMBER );
241                 realsize = alloc->size - MCASHDRSZ - sizeof(u_int32_t); 
242         } else
243                 realsize = alloc->size - MCASHDRSZ;
244
245         if ( size > realsize ) {
246                 MemoryChunk *chunk = alloc->cntx->chunk;
247                 if ( (char*)alloc == chunk->data + chunk->size - chunk->freesize - alloc->size &&
248                                 PTRALIGN(size)-realsize <= alloc->cntx->chunk->freesize ) {
249                         /* just enlarge */
250                         alloc->cntx->chunk->freesize -= PTRALIGN(size)-realsize;
251                         alloc->size+=PTRALIGN(size)-realsize;
252                         if ( alloc->cntx->flags & MC_DEBUG ) {
253                                 memset( (char*)(alloc->data) + realsize,  0xc3, PTRALIGN(size)-realsize );
254                                 *(u_int32_t*)((char*)alloc + alloc->size - sizeof(u_int32_t) ) = MCMAGICKNUMBER;
255                         }
256                 } else {  
257                         void *newptr = mcalloc(alloc->cntx, size);
258                         memcpy( newptr, ptr, realsize );
259                         ptr = newptr;
260                         if ( alloc->cntx->flags & MC_DEBUG ) 
261                                 memset( (char*)ptr + realsize, 0xc3, PTRALIGN(size)-realsize );
262                 }
263         }
264  
265         return ptr;
266 }
267
268
269 void    
270 mcfree(void * ptr) {
271         MCAllocatedSpace        *alloc = (MCAllocatedSpace*)( (char*)ptr - MCASHDRSZ );
272         MemoryChunk *chunk;
273
274         if ( ptr==NULL )
275                 tlog(TL_CRIT|TL_EXIT, "mcfree: free null pointer");
276
277         if ( alloc->cntx->flags & MC_DEBUG ) 
278                 tassert(  *(u_int32_t*)((char*)alloc + alloc->size - sizeof(u_int32_t) ) == MCMAGICKNUMBER );
279
280         chunk = alloc->cntx->chunk;
281         if ( (char*)alloc == chunk->data + chunk->size - chunk->freesize - alloc->size ) /* last allocated value */
282                 alloc->cntx->chunk->freesize+=alloc->size;
283
284         alloc->cntx=NULL;
285 }
286
287 char * 
288 mcstrdup(MemoryContext *cntx, char * src) {
289         return mcnstrdup(cntx, src, strlen(src));
290 }
291
292 char *
293 mcnstrdup(MemoryContext *cntx, char *src, int len) {
294         char *dest=(char*)mcalloc(cntx, len+1);
295         memcpy(dest, src, len);
296         dest[len]='\0';
297         return dest;
298 }
299
300 /*********StringBuffer********/
301
302 static inline void*
303 StringBufferAlloc(StringBuffer* state, void *ptr, size_t size) {
304         if (state->mc)
305                 return (ptr) ? mcrealloc(ptr, size) : mcalloc(state->mc, size);
306         else if (state->memalloc)
307                 return state->memalloc(ptr, size);
308         else
309                 return (ptr) ? trealloc(ptr, size) : tmalloc(size);
310 }
311
312 static StringBuffer*
313 initStringBufferInternal(StringBuffer* state, int initsize) {
314     state->len = (initsize>0) ? initsize : 1024;
315         state->ptr = state->buf = (char*)StringBufferAlloc(state, NULL, initsize);
316         if (!state->ptr)
317                 return NULL;
318
319         *(state->ptr) ='\0';
320
321         return state;
322 }
323
324 StringBuffer*
325 initStringBuffer(StringBuffer* state, int initsize) {
326         memset(state, 0, sizeof(*state));
327         
328         return initStringBufferInternal(state, initsize);
329 }
330
331 StringBuffer*
332 initStringBufferMC(StringBuffer* state, MemoryContext *mc, int initsize) {
333         memset(state, 0, sizeof(*state));
334         state->mc = mc;
335
336         return initStringBufferInternal(state, initsize);
337 }
338
339 StringBuffer*
340 initStringBufferMA(StringBuffer* state, MemAlloc memalloc, int initsize) {
341         memset(state, 0, sizeof(*state));
342         state->memalloc = memalloc;
343
344         return initStringBufferInternal(state, initsize);
345 }
346
347 StringBuffer*
348 appendStringBuffer( StringBuffer *state, char *string, int stringlen) {
349     if ( string ) {
350                         if ( stringlen <= 0 )
351                                 stringlen = strlen(string);
352         } else
353                 stringlen = 0;
354                                                                            
355         if ( stringlen == 0 )
356                 return state;
357                                                                                                           
358         while ( state->len - ( state->ptr - state->buf ) < stringlen + 1 ) {
359                         int     diff = state->ptr - state->buf;
360
361                         state->len *= 2;
362                         state->buf = (char*)StringBufferAlloc(state, state->buf, state->len);
363                         state->ptr = state->buf + diff;
364         }
365
366         memcpy(state->ptr, string, stringlen);
367         state->ptr += stringlen;
368         *state->ptr = '\0';
369         return state;
370 }
371
372 StringBuffer*
373 printStringBuffer( StringBuffer *state, const char *format, ...) {
374     va_list args;
375         int     printedlen;
376         int     buffreelen;
377
378         buffreelen = state->len - ( state->ptr - state->buf ) - 1;
379
380         va_start(args, format);
381         printedlen = vsnprintf(state->ptr, buffreelen, format, args);
382         va_end(args);
383         /*
384         * if buffer too short, resize buffer and
385         * print it again
386         */
387         if ( buffreelen<=printedlen ) {
388                 u_int32_t curlen = state->ptr - state->buf;
389                 do {
390                         state->len *= 2;
391                 } while( state->ptr - state->buf + printedlen >= state->len );
392
393                 state->buf = (char*)StringBufferAlloc(state, state->buf, state->len);
394                 state->ptr = state->buf + curlen;
395                 va_start(args, format);
396                 printedlen = vsnprintf(state->ptr, printedlen+1, format, args);
397                 va_end(args);
398         }
399         state->ptr += printedlen;
400         return state;
401 }
402