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