4cc793f18c02b3f4bea6dd1f46ed2914441740a5
[ngircd-alex.git] / src / ngircd / array.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  * Please read the file COPYING, README and AUTHORS for more information.
7  *
8  * libarray - dynamically allocate arrays.
9  * Copyright (c) 2005 Florian Westphal (westphal@foo.fh-furtwangen.de)
10  */
11
12 /**
13  * @file
14  * Functions to dynamically allocate arrays.
15  */
16
17 /* Additionan debug messages related to array handling: 0=off / 1=on */
18 #define DEBUG_ARRAY 0
19
20 #include "array.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #if DEBUG_ARRAY
28 # include "log.h"
29 #endif
30
31 #define array_UNUSABLE(x)       ( !(x)->mem )
32
33
34 static bool
35 safemult_sizet(size_t a, size_t b, size_t *res)
36 {
37         size_t tmp = a * b;
38
39         if (b && (tmp / b != a))
40                 return false;
41
42         *res = tmp;
43         return true;
44 }
45
46
47 void
48 array_init(array *a)
49 {
50         assert(a != NULL);
51         a->mem = NULL;
52         a->allocated = 0;
53         a->used = 0;
54 }
55
56
57 /* if realloc() fails, array_alloc return NULL. otherwise return pointer to elem pos in array */
58 void *
59 array_alloc(array * a, size_t size, size_t pos)
60 {
61         size_t alloc, pos_plus1 = pos + 1;
62         char *tmp;
63
64         assert(size > 0);
65
66         if (pos_plus1 == 0 || !safemult_sizet(size, pos_plus1, &alloc))
67                 return NULL;
68
69         if (a->allocated < alloc) {
70 #if DEBUG_ARRAY
71                 Log(LOG_DEBUG, "array_alloc(): changing size from %u to %u bytes.",
72                     a->allocated, alloc);
73 #endif
74                 tmp = realloc(a->mem, alloc);
75                 if (!tmp)
76                         return NULL;
77
78                 a->mem = tmp;
79                 a->allocated = alloc;
80                 memset(a->mem + a->used, 0, a->allocated - a->used);
81                 a->used = alloc;
82         }
83
84         assert(a->allocated >= a->used);
85
86         return a->mem + (pos * size);
87 }
88
89
90 /*return number of initialized ELEMS in a. */
91 size_t
92 array_length(const array * const a, size_t membersize)
93 {
94         assert(a != NULL);
95         assert(membersize > 0);
96
97         if (array_UNUSABLE(a))
98                 return 0;
99
100         assert(a->allocated);
101         return membersize ? a->used / membersize : 0;
102 }
103
104
105 /* copy array src to array dest */
106 bool
107 array_copy(array * dest, const array * const src)
108 {
109         if (array_UNUSABLE(src))
110                 return false;
111
112         assert(src->allocated);
113         return array_copyb(dest, src->mem, src->used);
114 }
115
116
117 /* return false on failure (realloc failure, invalid src/dest array) */
118 bool
119 array_copyb(array * dest, const char *src, size_t len)
120 {
121         assert(dest != NULL);
122         assert(src != NULL );
123
124         if (!src || !dest)
125                 return false;
126
127         array_trunc(dest);
128         return array_catb(dest, src, len);
129 }
130
131
132 /* copy string to dest */
133 bool
134 array_copys(array * dest, const char *src)
135 {
136         return array_copyb(dest, src, strlen(src));
137 }
138
139
140 /* append len bytes from src to the array dest.
141 return false if we could not append all bytes (realloc failure, invalid src/dest array) */
142 bool
143 array_catb(array * dest, const char *src, size_t len)
144 {
145         size_t tmp;
146         size_t used;
147         char *ptr;
148
149         assert(dest != NULL);
150         assert(src != NULL);
151
152         if (!len)
153                 return true;
154
155         if (!src || !dest)
156                 return false;
157
158         used = dest->used;
159         tmp = used + len;
160
161         if (tmp < used || tmp < len)    /* integer overflow */
162                 return false;
163
164         if (!array_alloc(dest, 1, tmp))
165                 return false;
166
167         ptr = dest->mem;
168
169         assert(ptr != NULL);
170
171 #if DEBUG_ARRAY
172         Log(LOG_DEBUG,
173             "array_catb(): appending %u bytes to array (now %u bytes in array).",
174             len, tmp);
175 #endif
176         memcpy(ptr + used, src, len);
177         dest->used = tmp;
178         return true;
179 }
180
181
182 /* append string to dest */
183 bool
184 array_cats(array * dest, const char *src)
185 {
186         return array_catb(dest, src, strlen(src));
187 }
188
189
190 /* append trailing NUL byte to array */
191 bool
192 array_cat0(array * a)
193 {
194         return array_catb(a, "", 1);
195 }
196
197
198 /* append trailing NUL byte to array, but do not count it. */
199 bool
200 array_cat0_temporary(array * a)
201 {
202         char *endpos = array_alloc(a, 1, array_bytes(a));
203         if (!endpos)
204                 return false;
205
206         *endpos = '\0';
207         return true;
208 }
209
210 /* add contents of array src to array dest. */
211 bool
212 array_cat(array * dest, const array * const src)
213 {
214         if (array_UNUSABLE(src))
215                 return false;
216
217         return array_catb(dest, src->mem, src->used);
218 }
219
220
221 /* return pointer to the element at pos.
222    return NULL if the array is unallocated, or if pos is larger than
223    the number of elements stored int the array. */
224 void *
225 array_get(array * a, size_t membersize, size_t pos)
226 {
227         size_t totalsize;
228         size_t posplus1 = pos + 1;
229
230         assert(membersize > 0);
231         assert(a != NULL);
232
233         if (!posplus1 || array_UNUSABLE(a))
234                 return NULL;
235
236         if (!safemult_sizet(posplus1, membersize, &totalsize))
237                 return NULL;
238
239         if (a->allocated < totalsize)
240                 return NULL;
241
242         totalsize = pos * membersize;
243         return a->mem + totalsize;
244 }
245
246
247 void
248 array_free(array * a)
249 {
250         assert(a != NULL);
251 #if DEBUG_ARRAY
252         Log(LOG_DEBUG,
253             "array_free(): %u bytes free'd (%u bytes still used at time of free()).",
254             a->allocated, a->used);
255 #endif
256         free(a->mem);
257         a->mem = NULL;
258         a->allocated = 0;
259         a->used = 0;
260 }
261
262 void
263 array_free_wipe(array *a)
264 {
265         size_t bytes = a->allocated;
266         if (bytes)
267                 memset(a->mem, 0, bytes);
268         array_free(a);
269 }
270
271 void *
272 array_start(const array * const a)
273 {
274         assert(a != NULL);
275         return a->mem;
276 }
277
278
279 void
280 array_trunc(array * a)
281 {
282         assert(a != NULL);
283         a->used = 0;
284 }
285
286
287 void
288 array_truncate(array * a, size_t membersize, size_t len)
289 {
290         size_t newlen;
291         assert(a != NULL);
292         if (!safemult_sizet(membersize, len, &newlen))
293                 return;
294
295         if (newlen <= a->allocated)
296                 a->used = newlen;
297 }
298
299
300 /* move elements starting at pos to beginning of array */
301 void
302 array_moveleft(array * a, size_t membersize, size_t pos)
303 {
304         size_t bytepos;
305
306         assert(a != NULL);
307         assert(membersize > 0);
308
309         if (!safemult_sizet(membersize, pos, &bytepos)) {
310                 a->used = 0;
311                 return;
312         }
313
314         if (!bytepos)
315                 return; /* nothing to do */
316
317 #if DEBUG_ARRAY
318         Log(LOG_DEBUG,
319             "array_moveleft(): %u bytes used in array, starting at position %u.",
320             a->used, bytepos);
321 #endif
322         if (a->used <= bytepos) {
323                 a->used = 0;
324                 return;
325         }
326
327         a->used -= bytepos;
328         memmove(a->mem, a->mem + bytepos, a->used);
329 }
330
331 /* -eof- */