bump to 1.0.0 and clean up spec file
[platform/upstream/libical.git] / src / libical / icalmemory.c
1 /* -*- Mode: C -*-
2   ======================================================================
3   FILE: icalmemory.c
4   CREATOR: eric 30 June 1999
5   
6   $Id: icalmemory.c,v 1.12 2008-02-03 16:10:46 dothebart Exp $
7   $Locker:  $
8     
9  The contents of this file are subject to the Mozilla Public License
10  Version 1.0 (the "License"); you may not use this file except in
11  compliance with the License. You may obtain a copy of the License at
12  http://www.mozilla.org/MPL/
13  
14  Software distributed under the License is distributed on an "AS IS"
15  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16  the License for the specific language governing rights and
17  limitations under the License.
18  
19
20  This program is free software; you can redistribute it and/or modify
21  it under the terms of either: 
22
23     The LGPL as published by the Free Software Foundation, version
24     2.1, available at: http://www.fsf.org/copyleft/lesser.html
25
26   Or:
27
28     The Mozilla Public License Version 1.0. You may obtain a copy of
29     the License at http://www.mozilla.org/MPL/
30
31  The Original Code is icalmemory.h
32
33  ======================================================================*/
34
35 /**
36  * @file icalmemory.c
37  * @brief Common memory management routines.
38  *
39  * libical often passes strings back to the caller. To make these
40  * interfaces simple, I did not want the caller to have to pass in a
41  * memory buffer, but having libical pass out newly allocated memory
42  * makes it difficult to de-allocate the memory.
43  * 
44  * The ring buffer in this scheme makes it possible for libical to pass
45  * out references to memory which the caller does not own, and be able
46  * to de-allocate the memory later. The ring allows libical to have
47  * several buffers active simultaneously, which is handy when creating
48  * string representations of components. 
49  */
50
51 #define ICALMEMORY_C
52
53 #ifdef HAVE_CONFIG_H
54 #include "config.h"
55 #endif
56
57 #ifdef DMALLOC
58 #include "dmalloc.h"
59 #endif
60
61 #include "icalmemory.h"
62 #include "icalerror.h"
63
64 #include <stdio.h> /* for printf (debugging) */
65 #include <stdlib.h> /* for malloc, realloc */
66 #include <string.h> /* for memset(), strdup */
67
68 #ifdef WIN32
69 #include <windows.h>
70 #endif
71
72 #define BUFFER_RING_SIZE 2500
73 #define MIN_BUFFER_SIZE 200
74
75
76 /* HACK. Not threadsafe */
77
78 typedef struct {
79         int pos;
80         void *ring[BUFFER_RING_SIZE];
81 } buffer_ring;
82
83 void icalmemory_free_tmp_buffer (void* buf);
84 void icalmemory_free_ring_byval(buffer_ring *br);
85
86 #ifndef HAVE_PTHREAD
87 static buffer_ring* global_buffer_ring = 0;
88 #endif
89
90 #ifdef HAVE_PTHREAD
91 #include <pthread.h>
92
93 static pthread_key_t  ring_key;
94 static pthread_once_t ring_key_once = PTHREAD_ONCE_INIT;
95
96 static void ring_destroy(void * buf) {
97     if (buf) icalmemory_free_ring_byval((buffer_ring *) buf);
98     pthread_setspecific(ring_key, NULL);
99 }
100
101 static void ring_key_alloc(void) {  
102     pthread_key_create(&ring_key, ring_destroy);
103 }
104 #endif
105
106
107 static buffer_ring * buffer_ring_new(void) {
108         buffer_ring *br;
109         int i;
110
111         br = (buffer_ring *)malloc(sizeof(buffer_ring));
112
113         for(i=0; i<BUFFER_RING_SIZE; i++){
114             br->ring[i]  = 0;
115         }
116         br->pos = 0;
117         return(br);
118 }
119
120
121 #ifdef HAVE_PTHREAD
122 static buffer_ring* get_buffer_ring_pthread(void) {
123     buffer_ring *br;
124
125     pthread_once(&ring_key_once, ring_key_alloc);
126
127     br = pthread_getspecific(ring_key);
128
129     if (!br) {
130         br = buffer_ring_new();
131         pthread_setspecific(ring_key, br);
132     }
133     return(br);
134 }
135 #else
136 /* get buffer ring via a single global for a non-threaded program */
137 static buffer_ring* get_buffer_ring_global(void) {
138     if (global_buffer_ring == 0) {
139         global_buffer_ring = buffer_ring_new();
140     }
141     return(global_buffer_ring);
142 }
143 #endif
144
145 static buffer_ring *get_buffer_ring(void) {
146 #ifdef HAVE_PTHREAD
147         return(get_buffer_ring_pthread());
148 #else
149         return get_buffer_ring_global();
150 #endif
151 }
152
153
154 /** Add an existing buffer to the buffer ring */
155 void  icalmemory_add_tmp_buffer(void* buf)
156 {
157     buffer_ring *br = get_buffer_ring();
158
159
160     /* Wrap around the ring */
161     if(++(br->pos) == BUFFER_RING_SIZE){
162         br->pos = 0;
163     }
164
165     /* Free buffers as their slots are overwritten */
166     if ( br->ring[br->pos] != 0){
167         free( br->ring[br->pos]);
168     }
169
170     /* Assign the buffer to a slot */
171     br->ring[br->pos] = buf; 
172 }
173
174
175 /**
176  * Create a new temporary buffer on the ring. Libical owns these and
177  * will deallocate them. 
178  */
179
180 void*
181 icalmemory_tmp_buffer (size_t size)
182 {
183     char *buf;
184
185     if (size < MIN_BUFFER_SIZE){
186         size = MIN_BUFFER_SIZE;
187     }
188     
189     buf = (void*)malloc(size);
190
191     if( buf == 0){
192         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
193         return 0;
194     }
195
196     memset(buf,0,size); 
197
198     icalmemory_add_tmp_buffer(buf);
199
200     return buf;
201 }
202
203 /** get rid of this buffer ring */
204 void icalmemory_free_ring_byval(buffer_ring *br) {
205    int i;
206    for(i=0; i<BUFFER_RING_SIZE; i++){
207     if ( br->ring[i] != 0){
208        free( br->ring[i]);
209     }
210     }
211    free(br);
212 }
213
214 void icalmemory_free_ring()
215 {
216    buffer_ring *br;
217    br = get_buffer_ring();
218
219    icalmemory_free_ring_byval(br);
220 #ifdef HAVE_PTHREAD
221   pthread_setspecific(ring_key, 0);
222 #else
223   global_buffer_ring = 0;
224 #endif
225
226 }
227
228
229
230 /** Like strdup, but the buffer is on the ring. */
231 char*
232 icalmemory_tmp_copy(const char* str)
233 {
234     char* b = icalmemory_tmp_buffer(strlen(str)+1);
235
236     strcpy(b,str);
237
238     return b;
239 }
240     
241
242 char* icalmemory_strdup(const char *s)
243 {
244     return strdup(s);
245 }
246
247 void
248 icalmemory_free_tmp_buffer (void* buf)
249 {
250    if(buf == 0)
251    {
252        return;
253    }
254
255    free(buf);
256 }
257
258
259 /*
260  * These buffer routines create memory the old fashioned way -- so the
261  * caller will have to deallocate the new memory 
262  */
263
264 void* icalmemory_new_buffer(size_t size)
265 {
266     void *b = malloc(size);
267
268     if( b == 0){
269         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
270         return 0;
271     }
272
273     memset(b,0,size); 
274
275     return b;
276 }
277
278 void* icalmemory_resize_buffer(void* buf, size_t size)
279 {
280     void *b = realloc(buf, size);
281
282     if( b == 0){
283         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
284         return 0;
285     }
286
287    return b;
288 }
289
290 void icalmemory_free_buffer(void* buf)
291 {
292     free(buf);
293 }
294
295 void 
296 icalmemory_append_string(char** buf, char** pos, size_t* buf_size, 
297                               const char* string)
298 {
299     char *new_buf;
300     char *new_pos;
301
302     size_t data_length, final_length, string_length;
303
304 #ifndef ICAL_NO_INTERNAL_DEBUG
305     icalerror_check_arg_rv( (buf!=0),"buf");
306     icalerror_check_arg_rv( (*buf!=0),"*buf");
307     icalerror_check_arg_rv( (pos!=0),"pos");
308     icalerror_check_arg_rv( (*pos!=0),"*pos");
309     icalerror_check_arg_rv( (buf_size!=0),"buf_size");
310     icalerror_check_arg_rv( (*buf_size!=0),"*buf_size");
311     icalerror_check_arg_rv( (string!=0),"string");
312 #endif 
313
314     string_length = strlen(string);
315     data_length = (size_t)*pos - (size_t)*buf;    
316     final_length = data_length + string_length; 
317
318     if ( final_length >= (size_t) *buf_size) {
319
320         
321         *buf_size  = (*buf_size) * 2  + final_length;
322
323         new_buf = realloc(*buf,*buf_size);
324
325         new_pos = (void*)((size_t)new_buf + data_length);
326         
327         *pos = new_pos;
328         *buf = new_buf;
329     }
330     
331     strcpy(*pos, string);
332
333     *pos += string_length;
334 }
335
336
337 void 
338 icalmemory_append_char(char** buf, char** pos, size_t* buf_size, 
339                               char ch)
340 {
341     char *new_buf;
342     char *new_pos;
343
344     size_t data_length, final_length;
345
346 #ifndef ICAL_NO_INTERNAL_DEBUG
347     icalerror_check_arg_rv( (buf!=0),"buf");
348     icalerror_check_arg_rv( (*buf!=0),"*buf");
349     icalerror_check_arg_rv( (pos!=0),"pos");
350     icalerror_check_arg_rv( (*pos!=0),"*pos");
351     icalerror_check_arg_rv( (buf_size!=0),"buf_size");
352     icalerror_check_arg_rv( (*buf_size!=0),"*buf_size");
353 #endif
354
355     data_length = (size_t)*pos - (size_t)*buf;
356
357     final_length = data_length + 2; 
358
359     if ( final_length > (size_t) *buf_size ) {
360
361         
362         *buf_size  = (*buf_size) * 2  + final_length +1;
363
364         new_buf = realloc(*buf,*buf_size);
365
366         new_pos = (void*)((size_t)new_buf + data_length);
367         
368         *pos = new_pos;
369         *buf = new_buf;
370     }
371
372     **pos = ch;
373     *pos += 1;
374     **pos = 0;
375 }