Annotation of libelwix/src/array.c, revision 1.10
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.10 ! misho 6: * $Id: array.c,v 1.9.46.1 2024/10/27 04:27:51 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.10 ! misho 15: Copyright 2004 - 2024
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * array_Init() - Create and initialize dynamic array
51: *
52: * @numItems = Number of Items
53: * return: NULL error, != NULL allocated memory for array
54: */
1.2 misho 55: array_t *
1.1 misho 56: array_Init(int numItems)
57: {
58: array_t *arr = NULL;
59:
60: arr = e_malloc(sizeof(array_t));
61: if (!arr)
62: return NULL;
63:
64: arr->arr_last = -1;
65: arr->arr_num = numItems;
66: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
67: if (!arr->arr_data) {
68: e_free(arr);
69: return NULL;
70: } else
1.9 misho 71: memset(arr->arr_data, 0, array_Size(arr) * sizeof(intptr_t));
1.1 misho 72:
73: return arr;
74: }
1.8 misho 75:
76: /*
77: * array_Init2() - Initialize dynamic array
78: *
79: * @arr = Allocated array variable
80: * @numItems = Number of Items
81: * return: NULL error, != NULL allocated memory for array
82: */
83: array_t *
84: array_Init2(array_t * __restrict arr, int numItems)
85: {
86: if (!arr)
87: return array_Init(numItems);
88:
89: if (array_Size(arr))
90: return NULL; /* already allocated array! */
91:
92: arr->arr_last = -1;
93: arr->arr_num = numItems;
94: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
95: if (!arr->arr_data) {
96: e_free(arr);
97: return NULL;
98: } else
1.9 misho 99: memset(arr->arr_data, 0, array_Size(arr) * sizeof(intptr_t));
1.8 misho 100:
101: return arr;
102: }
103:
1.1 misho 104:
105: /*
106: * array_From() - Create and fill array from array with pointers
107: *
108: * @pargv = Array with pointers
109: * @argc = Number of Items, if 0 walk through argv and stop when reach NULL item
110: * return: NULL error, != NULL allocated new array
111: */
112: array_t *
113: array_From(const char *** __restrict pargv, int argc)
114: {
115: array_t *arr = NULL;
116: const char **a = NULL;
117: register int num = 0;
118:
119: if (!pargv || !*pargv || argc < 0)
120: return NULL;
121:
122: if (argc)
123: num = argc;
124: else
125: for (a = *pargv; *a; a++, num++);
126:
127: arr = array_Init(num);
128: if (!arr)
129: return NULL;
130: else {
131: memcpy(arr->arr_data, *pargv, array_Size(arr) * sizeof(intptr_t));
132: arr->arr_last = array_Size(arr) - 1;
133: }
134:
135: return arr;
136: }
137:
138: /*
139: * array_To() - Create and fill array with pointers from dynamic array
140: *
141: * @arr = Array
142: * return: NULL error, != NULL allocated memory for array, NULL terminated
143: */
144: char **
145: array_To(array_t * __restrict arr)
146: {
147: char **args = NULL;
148:
149: if (!arr || !array_Size(arr))
150: return NULL;
151:
152: args = (char **) e_calloc(array_Size(arr) + 1, sizeof(char*));
153: if (!args)
154: return NULL;
155: else
156: memcpy(args, arr->arr_data, array_Size(arr) * sizeof(char*));
157: args[array_Size(arr)] = NULL;
158:
159: return args;
160: }
161:
162: /*
163: * array_Free() - Free all data in dynamic array items
164: * (WARNING! If assign static array dont use this!!!)
165: *
166: * @arr = Array
167: * return: none
168: */
1.2 misho 169: void
1.1 misho 170: array_Free(array_t * __restrict arr)
171: {
172: register int i;
173:
174: if (!arr)
175: return;
176:
177: for (i = 0; i < array_Size(arr); i++)
1.9 misho 178: if (arr->arr_data[i])
1.1 misho 179: e_free(arr->arr_data[i]);
180:
1.9 misho 181: array_Zero(arr);
1.1 misho 182: }
183:
184: /*
185: * array_Destroy() - Free and destroy dynamic array
186: *
187: * @parr = Array
188: * return: none
189: */
1.2 misho 190: void
1.1 misho 191: array_Destroy(array_t ** __restrict parr)
192: {
193: if (!parr || !*parr)
194: return;
195:
196: if ((*parr)->arr_data)
197: e_free((*parr)->arr_data);
198: e_free(*parr);
199: *parr = NULL;
1.6 misho 200: }
201:
202: /*
1.9 misho 203: * array_Destroy2() - Free data in dynamic array
204: *
205: * @parr = Array
206: * return: none
207: */
208: void
209: array_Destroy2(array_t * __restrict arr)
210: {
211: if (!arr)
212: return;
213:
214: if (arr->arr_data)
215: e_free(arr->arr_data);
216: memset(arr, 0, sizeof(array_t));
217: }
218: /*
1.6 misho 219: * array_Reset() - Reset array to initial state
220: *
221: * @parr = Array
1.9 misho 222: * @purge = Purge all data, if <>0 then will be free entire data memory
1.6 misho 223: * return: none
224: */
225: void
226: array_Reset(array_t * __restrict arr, int purge)
227: {
228: if (!arr)
229: return;
230:
231: if (purge && arr->arr_data) {
232: e_free(arr->arr_data);
1.7 misho 233: arr->arr_num = 0;
1.6 misho 234: arr->arr_data = e_calloc(array_Size(arr), sizeof(intptr_t));
235: }
236:
1.10 ! misho 237: if (arr->arr_data)
! 238: array_Zero(arr);
1.1 misho 239: }
240:
241: /*
242: * array_Len() - Get last used element in dynamic array (array Length)
243: *
244: * @arr = Array
245: * return: -1 empty or >-1 position of last used element
246: */
1.2 misho 247: int
1.1 misho 248: array_Len(array_t * __restrict arr)
249: {
250: register int i;
251:
252: if (!arr)
253: return -1;
254:
255: for (i = array_Size(arr); i && !arr->arr_data[i - 1]; i--);
256:
257: return --i;
258: }
259:
260: /*
261: * array_Grow() - Grow/Shrink dynamic array, Use with care when it shrink!!!
262: *
263: * @arr = Array
264: * @newNumItems = Number of Items
265: * @freeShrink = Free elements before shrink array
266: * return: -1 error, 0 ok
267: */
268: int
269: array_Grow(array_t * __restrict arr, int newNumItems, int freeShrink)
270: {
271: void **data;
272: int n = 0;
273: register int i;
274:
275: if (!arr)
276: return -1;
277:
278: if (arr->arr_num == newNumItems)
279: return 0;
280: if (array_Size(arr) < newNumItems) {
281: n = newNumItems - array_Size(arr);
282: } else if (freeShrink)
283: for (i = newNumItems; i < arr->arr_num; i++)
284: if (arr->arr_data[i])
285: e_free(arr->arr_data[i]);
286:
287: arr->arr_num = newNumItems;
288: if (array_Size(arr)) {
289: data = e_realloc(arr->arr_data, array_Size(arr) * sizeof(intptr_t));
290: if (!data)
291: return -1;
292: else
293: arr->arr_data = data;
294:
295: memset(arr->arr_data + (array_Size(arr) - n), 0, n * sizeof(intptr_t));
296: arr->arr_last = array_Len(arr);
297: } else {
298: if (arr->arr_data)
299: e_free(arr->arr_data);
300: arr->arr_data = NULL;
301: arr->arr_last = -1;
302: }
303:
304: return 0;
305: }
306:
307: /*
308: * array_Vacuum() - Vacuum dynamic array, empty elements will be deleted
309: *
310: * @arr = Array
311: * @fromWhere = 1 begin, 2 ALL empty elements
312: * return: -1 error, 0 ok
313: */
314: int
315: array_Vacuum(array_t * __restrict arr, int fromWhere)
316: {
317: register int i, j, num;
318: int cx = 0;
319:
320: if (!arr)
321: return -1;
322: else
323: fromWhere &= 0x7;
324:
325: num = array_Size(arr);
326: #ifdef VACUUM_RIGHT
327: if (fromWhere & VACUUM_RIGHT) {
328: for (cx = 0, i = num - 1; i && !arr->arr_data[i]; i--, cx++);
329: num -= cx;
330: }
331: #endif
332: if (fromWhere & VACUUM_LEFT) {
333: for (i = 0; i < num && !arr->arr_data[i]; i++);
334: if (i) {
335: memmove(arr->arr_data, arr->arr_data + i, (num - i) * sizeof(intptr_t));
336: memset(arr->arr_data + (num - i), 0, i * sizeof(intptr_t));
337:
338: num -= i;
339: cx += i;
340: }
341: }
342: if (fromWhere & VACUUM_BETWEEN) {
343: for (i = 0; i < num; i++) {
344: if (arr->arr_data[i])
345: continue;
346:
347: for (j = i; j < num && !arr->arr_data[j]; j++);
348:
349: memmove(arr->arr_data + i, arr->arr_data + j, (num - j) * sizeof(intptr_t));
350: memset(arr->arr_data + i + (num - j), 0, (j - i) * sizeof(intptr_t));
351:
352: num -= j - i;
353: cx += j - i;
354: }
355: }
356:
357: arr->arr_last = array_Len(arr);
358: return cx;
359: }
360:
361: /*
362: * array_Concat() Concat source array to destination array
363: *
364: * @dest = Destination array
365: * @src = Source array
366: * return: -1 error; >0 new count of destination array
367: */
368: int
369: array_Concat(array_t * __restrict dest, array_t * __restrict src)
370: {
371: int n;
372:
373: if (!dest || !src)
374: return -1;
375:
376: n = array_Size(dest);
377: if (array_Grow(dest, n + array_Size(src), 0))
378: return -1;
1.10 ! misho 379: if (!dest->arr_data)
! 380: return -1;
1.1 misho 381: memcpy(dest->arr_data + n, src->arr_data, array_Size(src) * sizeof(intptr_t));
382:
383: dest->arr_last = array_Len(dest);
384: return array_Size(dest);
385: }
386:
387: /*
388: * array_Copy() Copy source array to destination array
389: *
1.3 misho 390: * @dest = Destination array, after use free with array_Destroy()
1.1 misho 391: * @src = Source array
392: * return: -1 error; >0 count of destination array
393: */
394: int
395: array_Copy(array_t ** __restrict dest, array_t * __restrict src)
396: {
397: if (!dest || !src)
398: return -1;
399:
400: *dest = array_Init(array_Size(src));
401: if (!*dest)
402: return -1;
403: else
404: (*dest)->arr_last = src->arr_last;
405:
406: memcpy((*dest)->arr_data, src->arr_data, array_Size(*dest) * sizeof(intptr_t));
407: return array_Size(*dest);
408: }
409:
410: /*
411: * array_Elem() - Always GET/PUT element into dynamic array, if not enough elements grow array
412: *
413: * @arr = Array
414: * @n = Position
415: * @data = Element, if set NULL GET element at position or !=NULL PUT element at position
416: * return: -1 error or !=-1 return element at position
417: */
1.2 misho 418: void *
1.1 misho 419: array_Elem(array_t * __restrict arr, int n, void *data)
420: {
421: void *dat = NULL;
422:
423: if (!arr)
424: return (void*) -1;
425:
426: if (n >= array_Size(arr) && array_Grow(arr, n + 1, 0))
427: return (void*) -1;
1.10 ! misho 428: if (!arr->arr_data)
! 429: return (void*) -1;
1.1 misho 430:
431: dat = array_Get(arr, n);
432: if (data)
433: array_Set(arr, n, data);
434:
435: return dat;
436: }
437:
438: /*
439: * array_Push() - Push element into dynamic array like stack manner, place at first empty position
440: *
441: * @arr = Array
442: * @data = Element, if set NULL return only first empty position
443: * @nogrow = Don't grow array if not enough space
444: * return: -1 not found empty position, array is full!, >-1 return position of stored element into array
445: */
1.2 misho 446: int
447: array_Push(array_t * __restrict arr, void *data, int nogrow)
1.1 misho 448: {
449: int ret = -1;
450:
451: if (!arr)
452: return -1;
453: else
454: ret = array_Last(arr) + 1;
455: if (nogrow && ret >= array_Size(arr))
456: return -1;
457: if (!nogrow && ret >= array_Size(arr) && array_Grow(arr, ret + 1, 0))
458: return -1;
1.10 ! misho 459: if (!arr->arr_data)
! 460: return -1;
1.1 misho 461:
1.2 misho 462: ret = ++arr->arr_last;
463: arr->arr_data[arr->arr_last] = data;
1.1 misho 464:
465: return ret;
466: }
467:
468: /*
469: * array_Pop() - Pop element from dynamic array like stack manner, last used position
470: *
471: * @arr = Array
472: * @data = Element, if set NULL return only last used position
473: * @nodel = Don't delete after Pop element
474: * return: -1 not found used position, array is empty!, >-1 return element position
475: */
1.2 misho 476: int
1.1 misho 477: array_Pop(array_t * __restrict arr, void ** __restrict data, int nodel)
478: {
479: int ret = -1;
480:
481: if (!arr)
482: return -1;
483:
1.2 misho 484: if ((ret = array_Last(arr)) != -1) {
485: if (data)
486: *data = arr->arr_data[arr->arr_last];
487: if (!nodel)
488: arr->arr_data[arr->arr_last] = NULL;
489: arr->arr_last--;
490: }
1.1 misho 491:
492: return ret;
493: }
494:
495: /*
496: * array_Args() Parse and make array from arguments ... (input string will be modified!!!
1.3 misho 497: * and output array must be free with array_Destroy() after use!)
1.1 misho 498: *
499: * @psArgs = Input arguments line, after execute string is modified!!!
500: * @nargs = Maximum requested count of arguments from input string psArgs, if 0 all psArgs
501: * @csDelim = Delimiter(s) for separate
502: * @parr = Output array of arguments ... (must be free with array_Destroy() after use!)
503: * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
504: */
505: int
506: array_Args(char * __restrict psArgs, int nargs, const char *csDelim, array_t ** __restrict parr)
507: {
508: char **app;
509: register int i;
510:
511: if (!psArgs || !csDelim || !parr)
512: return -1;
513:
514: if (nargs)
515: i = nargs;
516: else
517: i = str_ArgsNum(psArgs, csDelim);
518:
519: *parr = array_Init(i);
520: if (!*parr)
521: return -1;
522:
523: for (i = 0, app = (char**) (*parr)->arr_data;
524: app < (char**) (*parr)->arr_data + (*parr)->arr_num &&
525: (*app = strsep((char **) &psArgs, csDelim));
526: **app ? i++ : i, **app ? app++ : app);
527:
528: (*parr)->arr_last = i - 1;
529: return i;
530: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>