2 ======================================================================
4 CREATOR: eric 30 June 1999
6 $Id: icalmemory.c,v 1.12 2008-02-03 16:10:46 dothebart Exp $
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/
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.
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of either:
23 The LGPL as published by the Free Software Foundation, version
24 2.1, available at: http://www.fsf.org/copyleft/lesser.html
28 The Mozilla Public License Version 1.0. You may obtain a copy of
29 the License at http://www.mozilla.org/MPL/
31 The Original Code is icalmemory.h
33 ======================================================================*/
37 * @brief Common memory management routines.
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.
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.
61 #include "icalmemory.h"
62 #include "icalerror.h"
64 #include <stdio.h> /* for printf (debugging) */
65 #include <stdlib.h> /* for malloc, realloc */
66 #include <string.h> /* for memset(), strdup */
72 #define BUFFER_RING_SIZE 2500
73 #define MIN_BUFFER_SIZE 200
76 /* HACK. Not threadsafe */
80 void *ring[BUFFER_RING_SIZE];
83 void icalmemory_free_tmp_buffer (void* buf);
84 void icalmemory_free_ring_byval(buffer_ring *br);
87 static buffer_ring* global_buffer_ring = 0;
93 static pthread_key_t ring_key;
94 static pthread_once_t ring_key_once = PTHREAD_ONCE_INIT;
96 static void ring_destroy(void * buf) {
97 if (buf) icalmemory_free_ring_byval((buffer_ring *) buf);
98 pthread_setspecific(ring_key, NULL);
101 static void ring_key_alloc(void) {
102 pthread_key_create(&ring_key, ring_destroy);
107 static buffer_ring * buffer_ring_new(void) {
111 br = (buffer_ring *)malloc(sizeof(buffer_ring));
113 for(i=0; i<BUFFER_RING_SIZE; i++){
122 static buffer_ring* get_buffer_ring_pthread(void) {
125 pthread_once(&ring_key_once, ring_key_alloc);
127 br = pthread_getspecific(ring_key);
130 br = buffer_ring_new();
131 pthread_setspecific(ring_key, br);
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();
141 return(global_buffer_ring);
145 static buffer_ring *get_buffer_ring(void) {
147 return(get_buffer_ring_pthread());
149 return get_buffer_ring_global();
154 /** Add an existing buffer to the buffer ring */
155 void icalmemory_add_tmp_buffer(void* buf)
157 buffer_ring *br = get_buffer_ring();
160 /* Wrap around the ring */
161 if(++(br->pos) == BUFFER_RING_SIZE){
165 /* Free buffers as their slots are overwritten */
166 if ( br->ring[br->pos] != 0){
167 free( br->ring[br->pos]);
170 /* Assign the buffer to a slot */
171 br->ring[br->pos] = buf;
176 * Create a new temporary buffer on the ring. Libical owns these and
177 * will deallocate them.
181 icalmemory_tmp_buffer (size_t size)
185 if (size < MIN_BUFFER_SIZE){
186 size = MIN_BUFFER_SIZE;
189 buf = (void*)malloc(size);
192 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
198 icalmemory_add_tmp_buffer(buf);
203 /** get rid of this buffer ring */
204 void icalmemory_free_ring_byval(buffer_ring *br) {
206 for(i=0; i<BUFFER_RING_SIZE; i++){
207 if ( br->ring[i] != 0){
214 void icalmemory_free_ring()
217 br = get_buffer_ring();
219 icalmemory_free_ring_byval(br);
221 pthread_setspecific(ring_key, 0);
223 global_buffer_ring = 0;
230 /** Like strdup, but the buffer is on the ring. */
232 icalmemory_tmp_copy(const char* str)
234 char* b = icalmemory_tmp_buffer(strlen(str)+1);
242 char* icalmemory_strdup(const char *s)
248 icalmemory_free_tmp_buffer (void* buf)
260 * These buffer routines create memory the old fashioned way -- so the
261 * caller will have to deallocate the new memory
264 void* icalmemory_new_buffer(size_t size)
266 void *b = malloc(size);
269 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
278 void* icalmemory_resize_buffer(void* buf, size_t size)
280 void *b = realloc(buf, size);
283 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
290 void icalmemory_free_buffer(void* buf)
296 icalmemory_append_string(char** buf, char** pos, size_t* buf_size,
302 size_t data_length, final_length, string_length;
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");
314 string_length = strlen(string);
315 data_length = (size_t)*pos - (size_t)*buf;
316 final_length = data_length + string_length;
318 if ( final_length >= (size_t) *buf_size) {
321 *buf_size = (*buf_size) * 2 + final_length;
323 new_buf = realloc(*buf,*buf_size);
325 new_pos = (void*)((size_t)new_buf + data_length);
331 strcpy(*pos, string);
333 *pos += string_length;
338 icalmemory_append_char(char** buf, char** pos, size_t* buf_size,
344 size_t data_length, final_length;
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");
355 data_length = (size_t)*pos - (size_t)*buf;
357 final_length = data_length + 2;
359 if ( final_length > (size_t) *buf_size ) {
362 *buf_size = (*buf_size) * 2 + final_length +1;
364 new_buf = realloc(*buf,*buf_size);
366 new_pos = (void*)((size_t)new_buf + data_length);