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.
8 * functions to dynamically allocate arrays.
9 * Copyright (c) 2005 Florian Westphal (westphal@foo.fh-furtwangen.de)
15 static char UNUSED id[] = "$Id: array.c,v 1.11 2006/07/01 22:11:48 fw Exp $";
24 /* Enable more Debug messages in alloc / append / memmove code. */
25 /* #define DEBUG_ARRAY */
29 #define array_UNUSABLE(x) ( !(x)->mem || (0 == (x)->allocated) )
31 #define ALIGN_32U(x) (((x)+31U ) & ~(31U))
32 #define ALIGN_1024U(x) (((x)+1023U) & ~(1023U))
33 #define ALIGN_4096U(x) (((x)+4095U) & ~(4095U))
37 safemult_sizet(size_t a, size_t b, size_t *res)
41 if (b && (tmp / b != a))
59 /* if realloc() fails, array_alloc return NULL. otherwise return pointer to elem pos in array */
61 array_alloc(array * a, size_t size, size_t pos)
63 size_t alloc, pos_plus1 = pos + 1;
72 if (!safemult_sizet(size, pos_plus1, &alloc))
75 if (a->allocated < alloc) {
77 aligned = ALIGN_32U(alloc);
80 aligned = ALIGN_1024U(alloc);
82 aligned = ALIGN_4096U(alloc);
86 Log(LOG_DEBUG, "array_alloc(): rounded %u to %u bytes.", alloc, aligned);
89 assert(aligned >= alloc);
91 if (aligned < alloc) /* rounding overflow */
96 Log(LOG_DEBUG, "array_alloc(): changing size from %u to %u bytes.",
97 a->allocated, aligned);
100 tmp = realloc(a->mem, alloc);
105 a->allocated = alloc;
107 assert(a->allocated > a->used);
109 memset(a->mem + a->used, 0, a->allocated - a->used);
113 return a->mem + (pos * size);
117 /*return number of initialized ELEMS in a. */
119 array_length(const array * const a, size_t membersize)
122 assert(membersize > 0);
124 if (array_UNUSABLE(a))
127 return membersize ? a->used / membersize : 0;
131 /* copy array src to array dest */
133 array_copy(array * dest, const array * const src)
135 if (array_UNUSABLE(src))
138 return array_copyb(dest, src->mem, src->used);
142 /* return false on failure (realloc failure, invalid src/dest array) */
144 array_copyb(array * dest, const char *src, size_t len)
146 assert(dest != NULL);
147 assert(src != NULL );
153 return array_catb(dest, src, len);
157 /* copy string to dest */
159 array_copys(array * dest, const char *src)
161 return array_copyb(dest, src, strlen(src));
165 /* append len bytes from src to the array dest.
166 return false if we could not append all bytes (realloc failure, invalid src/dest array) */
168 array_catb(array * dest, const char *src, size_t len)
174 assert(dest != NULL);
186 if (tmp < used || tmp < len) /* integer overflow */
189 if (!array_alloc(dest, 1, tmp))
198 "array_catb(): appending %u bytes to array (now %u bytes in array).",
201 memcpy(ptr + used, src, len);
207 /* append string to dest */
209 array_cats(array * dest, const char *src)
211 return array_catb(dest, src, strlen(src));
215 /* append trailing NUL byte to array */
217 array_cat0(array * a)
219 return array_catb(a, "", 1);
223 /* append trailing NUL byte to array, but do not count it. */
225 array_cat0_temporary(array * a)
227 char *endpos = array_alloc(a, 1, array_bytes(a));
235 /* add contents of array src to array dest. */
237 array_cat(array * dest, const array * const src)
239 if (array_UNUSABLE(src))
242 return array_catb(dest, src->mem, src->used);
246 /* return pointer to the element at pos.
247 return NULL if the array is unallocated, or if pos is larger than
248 the number of elements stored int the array. */
250 array_get(array * a, size_t membersize, size_t pos)
254 assert(membersize > 0);
257 if (array_UNUSABLE(a))
260 if (!safemult_sizet(pos, membersize, &totalsize))
263 if (a->allocated < totalsize)
266 return a->mem + pos * membersize;
271 array_free(array * a)
276 "array_free(): %u bytes free'd (%u bytes still used at time of free()).",
277 a->allocated, a->used);
287 array_free_wipe(array * a)
289 if (!array_UNUSABLE(a))
290 memset(a->mem, 0, a->allocated);
297 array_start(const array * const a)
305 array_trunc(array * a)
313 array_truncate(array * a, size_t membersize, size_t len)
317 if (!safemult_sizet(membersize, len, &newlen))
320 if (newlen <= a->allocated)
325 /* move elements starting at pos to beginning of array */
327 array_moveleft(array * a, size_t membersize, size_t pos)
332 assert(membersize > 0);
337 if (!safemult_sizet(membersize, pos, &bytepos)) {
343 return; /* nothing to do */
347 "array_moveleft(): %u bytes used in array, starting at position %u.",
350 if (a->used <= bytepos) {
356 memmove(a->mem, a->mem + bytepos, a->used);