new functions:
[metze/wireshark/wip.git] / epan / emem.c
1 /* emem.c
2  * Ethereal memory management and garbage collection functions
3  * Ronnie Sahlberg 2005
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <glib.h>
34 #include <proto.h>
35 #include "emem.h"
36
37 /* When required, allocate more memory from the OS in this size chunks */
38 #define EMEM_PACKET_CHUNK_SIZE 10485760
39
40 typedef struct _emem_chunk_t {
41         struct _emem_chunk_t *next;
42         unsigned int    amount_free;
43         unsigned int    free_offset;
44         char *buf;
45 } emem_chunk_t;
46
47 typedef struct _emem_header_t {
48   emem_chunk_t *free_list;
49   emem_chunk_t *used_list;
50 } emem_header_t;
51
52 static emem_header_t emem_packet_mem;
53
54 /* Initialize the packet-lifetime memory allocation pool.
55  * This function should be called only once when Etehreal or Tethereal starts
56  * up.
57  */
58 void
59 ep_init_chunk(void)
60 {
61         emem_packet_mem.free_list=NULL; 
62         emem_packet_mem.used_list=NULL; 
63 }
64
65 /* allocate 'size' amount of memory with an allocation lifetime until the
66  * next packet.
67  */
68 void *
69 ep_alloc(size_t size)
70 {
71         void *buf;
72
73         /* round up to 8 byte boundary */
74         if(size&0x07){
75                 size=(size+7)&0xfffffff8;
76         }
77
78         /* make sure we dont try to allocate too much (arbitrary limit) */
79         DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
80
81         /* we dont have any free data, so we must allocate a new one */
82         if(!emem_packet_mem.free_list){
83                 emem_chunk_t *npc;
84                 npc=g_malloc(sizeof(emem_chunk_t));
85                 npc->next=NULL;
86                 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
87                 npc->free_offset=0;
88                 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
89                 emem_packet_mem.free_list=npc;
90         }
91
92         /* oops, we need to allocate more memory to serve this request
93          * than we have free. move this node to the used list and try again
94          */
95         if(size>emem_packet_mem.free_list->amount_free){
96                 emem_chunk_t *npc;
97                 npc=emem_packet_mem.free_list;
98                 emem_packet_mem.free_list=emem_packet_mem.free_list->next;
99                 npc->next=emem_packet_mem.used_list;
100                 emem_packet_mem.used_list=npc;
101         }
102
103         /* we dont have any free data, so we must allocate a new one */
104         if(!emem_packet_mem.free_list){
105                 emem_chunk_t *npc;
106                 npc=g_malloc(sizeof(emem_chunk_t));
107                 npc->next=NULL;
108                 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
109                 npc->free_offset=0;
110                 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
111                 emem_packet_mem.free_list=npc;
112         }
113
114
115         buf=emem_packet_mem.free_list->buf+emem_packet_mem.free_list->free_offset;
116
117         emem_packet_mem.free_list->amount_free-=size;
118         emem_packet_mem.free_list->free_offset+=size;
119
120         return buf;
121 }
122
123 void* ep_alloc0(size_t size) {
124         return memset(ep_alloc(size),'\0',size);
125 }
126
127 gchar* ep_strdup(const gchar* src) {
128         guint len = strlen(src);
129         gchar* dst;
130         
131         dst = strncpy(ep_alloc(len+1), src, len);
132
133         dst[len] = '\0';
134         
135         return dst;
136 }
137
138 gchar* ep_strndup(const gchar* src, size_t len) {
139         guint actual_len = strlen(src);
140         gchar* dst;
141         
142         if (len > actual_len)
143                 len = actual_len;
144         
145         dst = strncpy(ep_alloc(len+1), src, len);
146         
147         dst[len] = '\0';
148         
149         return dst;
150 }
151
152 guint8* ep_memdup(const guint8* src, size_t len) {
153         return memcpy(ep_alloc(len), src, len);
154 }
155
156 gchar* ep_strdup_printf(const gchar* fmt, ...) {
157         va_list ap;
158         guint len;
159         gchar* dst;
160         
161         va_start(ap,fmt);
162         len = g_printf_string_upper_bound (fmt, ap);
163         
164         dst = ep_alloc(len+1);
165         g_vsnprintf (dst, len, fmt, ap);
166         
167         va_end(ap);
168         return dst;
169 }
170
171 gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) {
172         gchar* splitted;
173         gchar* s;
174         guint tokens;
175         guint str_len = strlen(splitted);
176         guint sep_len = strlen(sep);
177         guint i;
178         gchar** vec;
179         enum { AT_START, IN_PAD, IN_TOKEN } state;
180         guint curr_tok = 0;
181         
182         if ( ! string 
183                  || ! sep
184                  || ! sep[0])
185                 return NULL;
186         
187         s = splitted = ep_strdup(string);
188         str_len = strlen(splitted);
189         sep_len = strlen(sep);
190         
191         if (max_tokens < 1) max_tokens = INT_MAX;
192
193         tokens = 1;
194         
195                 
196         while (tokens <= (guint)max_tokens && ( s = strstr(s,sep) )) {
197                 tokens++;
198                 
199                 for(i=0; i < sep_len; i++ )
200                         s[i] = '\0';
201                 
202                 s += sep_len;
203                 
204         } 
205         
206         vec = ep_alloc_array(gchar,tokens+1);
207         state = AT_START;
208         
209         for (i=0; i< str_len; i++) {
210                 switch(state) {
211                         case AT_START:
212                                 switch(splitted[i]) {
213                                         case '\0':
214                                                 state  = IN_PAD;
215                                                 continue;
216                                         default:
217                                                 vec[curr_tok] = &(splitted[i]);
218                                                 curr_tok++;
219                                                 state = IN_TOKEN;
220                                                 continue;
221                                 }
222                         case IN_TOKEN:
223                                 switch(splitted[i]) {
224                                         case '\0':
225                                                 state = IN_PAD;
226                                         default:
227                                                 continue;
228                                 }
229                         case IN_PAD:
230                                 switch(splitted[i]) {
231                                         default:
232                                                 vec[curr_tok] = &(splitted[i]);
233                                                 curr_tok++;
234                                                 state = IN_TOKEN;
235                                         case '\0':
236                                                 continue;
237                                 }
238                 }
239         }
240         
241         vec[curr_tok] = NULL;
242         
243         return vec;
244 }
245
246 /* release all allocated memory back to the pool.
247  */
248 void
249 ep_free_all(void)
250 {
251         emem_chunk_t *npc;
252
253         /* move all used chunks ove to the free list */
254         while(emem_packet_mem.used_list){
255                 npc=emem_packet_mem.used_list;
256                 emem_packet_mem.used_list=emem_packet_mem.used_list->next;
257                 npc->next=emem_packet_mem.free_list;
258                 emem_packet_mem.free_list=npc;
259         }
260
261         /* clear them all out */
262         for(npc=emem_packet_mem.free_list;npc;npc=npc->next){
263                 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
264                 npc->free_offset=0;
265         }
266 }
267                 
268
269