1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
6: * $Id: array.c,v 1.7.4.1 2012/03/27 21:37:56 misho Exp $
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:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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: * io_arrayInit() - Create and initialize dynamic array
51: *
52: * @numItems = Number of Items
53: * return: NULL error, != NULL allocated memory for array
54: */
55: inline array_t *
56: io_arrayInit(int numItems)
57: {
58: array_t *arr = NULL;
59:
60: arr = malloc(sizeof(array_t));
61: if (!arr) {
62: LOGERR;
63: return NULL;
64: }
65:
66: arr->arr_num = numItems;
67: arr->arr_data = calloc(io_arraySize(arr), sizeof(void*));
68: if (!arr->arr_data) {
69: LOGERR;
70: free(arr);
71: return NULL;
72: } else
73: io_arrayZero(arr);
74:
75: return arr;
76: }
77:
78: /*
79: * io_arrayFrom() - Create and fill array from array with pointers
80: *
81: * @pargv = Array with pointers
82: * @argc = Number of Items, if 0 walk through argv and stop when reach NULL item
83: * return: NULL error, != NULL allocated new array
84: */
85: inline array_t *
86: io_arrayFrom(const char *** __restrict pargv, int argc)
87: {
88: array_t *arr = NULL;
89: const char **a = NULL;
90: register int num = 0;
91:
92: assert(pargv);
93: if (!pargv || !*pargv || argc < 0)
94: return NULL;
95:
96: if (argc)
97: num = argc;
98: else
99: for (a = *pargv; *a; a++, num++);
100:
101: arr = malloc(sizeof(array_t));
102: if (!arr) {
103: LOGERR;
104: return NULL;
105: }
106:
107: arr->arr_num = num;
108: arr->arr_data = calloc(io_arraySize(arr), sizeof(void*));
109: if (!arr->arr_data) {
110: LOGERR;
111: free(arr);
112: return NULL;
113: } else
114: memcpy(arr->arr_data, *pargv, io_arraySize(arr) * sizeof(void*));
115:
116: return arr;
117: }
118:
119: /*
120: * io_arrayTo() - Create and fill array with pointers from dynamic array
121: *
122: * @arr = Array
123: * return: NULL error, != NULL allocated memory for array, NULL terminated
124: */
125: inline char **
126: io_arrayTo(array_t * __restrict arr)
127: {
128: char **args = NULL;
129:
130: assert(arr);
131: if (!arr || !io_arraySize(arr))
132: return NULL;
133:
134: args = (char **) calloc(io_arraySize(arr) + 1, sizeof(char*));
135: if (!args) {
136: LOGERR;
137: return NULL;
138: } else
139: memcpy(args, arr->arr_data, io_arraySize(arr) * sizeof(char*));
140: args[io_arraySize(arr)] = NULL;
141:
142: return args;
143: }
144:
145: /*
146: * io_arrayFree() - Free all data in dynamic array items
147: * (WARNING! If assign static array dont use this!!!)
148: *
149: * @arr = Array
150: * return: none
151: */
152: inline void
153: io_arrayFree(array_t * __restrict arr)
154: {
155: register int i;
156:
157: if (!arr)
158: return;
159:
160: for (i = 0; i < io_arraySize(arr); i++)
161: if (arr->arr_data[i]) {
162: free(arr->arr_data[i]);
163: arr->arr_data[i] = NULL;
164: }
165: }
166:
167: /*
168: * io_arrayDestroy() - Free and destroy dynamic array
169: *
170: * @parr = Array
171: * return: none
172: */
173: inline void
174: io_arrayDestroy(array_t ** __restrict parr)
175: {
176: if (!parr || !*parr)
177: return;
178:
179: if ((*parr)->arr_data)
180: free((*parr)->arr_data);
181: free(*parr);
182: *parr = NULL;
183: }
184:
185: /*
186: * io_arrayLen() - Get last used element in dynamic array (array Length)
187: *
188: * @arr = Array
189: * return: -1 error, 0 empty or >0 position of last used element
190: */
191: inline int
192: io_arrayLen(array_t * __restrict arr)
193: {
194: register int i;
195:
196: assert(arr);
197: if (!arr)
198: return -1;
199:
200: for (i = io_arraySize(arr); i && !arr->arr_data[i - 1]; i--);
201:
202: return i;
203: }
204:
205: /*
206: * io_arrayGrow() - Grow/Shrink dynamic array, Use with care when it shrink!!!
207: *
208: * @arr = Array
209: * @newNumItems = Number of Items
210: * @freeShrink = Free elements before shrink array
211: * return: -1 error, 0 ok
212: */
213: int
214: io_arrayGrow(array_t * __restrict arr, int newNumItems, int freeShrink)
215: {
216: void **data;
217: int n = 0;
218: register int i;
219:
220: if (!arr)
221: return -1;
222:
223: if (arr->arr_num == newNumItems)
224: return 0;
225: if (io_arraySize(arr) < newNumItems) {
226: n = newNumItems - io_arraySize(arr);
227: } else if (freeShrink)
228: for (i = newNumItems; i < arr->arr_num; i++)
229: if (arr->arr_data[i])
230: free(arr->arr_data[i]);
231:
232: arr->arr_num = newNumItems;
233: if (io_arraySize(arr)) {
234: data = realloc(arr->arr_data, io_arraySize(arr) * sizeof(void*));
235: if (!data) {
236: LOGERR;
237: return -1;
238: } else
239: arr->arr_data = data;
240:
241: memset(arr->arr_data + (io_arraySize(arr) - n), 0, n * sizeof(void*));
242: } else {
243: if (arr->arr_data)
244: free(arr->arr_data);
245: arr->arr_data = NULL;
246: }
247:
248: return 0;
249: }
250:
251: /*
252: * io_arrayVacuum() - Vacuum dynamic array, empty elements will be deleted
253: *
254: * @arr = Array
255: * @fromWhere = 1 begin, 2 ALL empty elements
256: * return: -1 error, 0 ok
257: */
258: int
259: io_arrayVacuum(array_t * __restrict arr, int fromWhere)
260: {
261: register int i, j, num;
262: int cx = 0;
263:
264: if (!arr)
265: return -1;
266: else
267: fromWhere &= 0x7;
268:
269: num = io_arraySize(arr);
270: /*
271: if (fromWhere & VACUUM_RIGHT) {
272: for (cx = 0, i = num - 1; i && !arr->arr_data[i]; i--, cx++);
273: num -= cx;
274: }
275: */
276: if (fromWhere & VACUUM_LEFT) {
277: for (i = 0; i < num && !arr->arr_data[i]; i++);
278: if (i) {
279: memmove(arr->arr_data, arr->arr_data + i, (num - i) * sizeof(void*));
280: memset(arr->arr_data + (num - i), 0, i * sizeof(void*));
281:
282: num -= i;
283: cx += i;
284: }
285: }
286: if (fromWhere & VACUUM_BETWEEN) {
287: for (i = 0; i < num; i++) {
288: if (arr->arr_data[i])
289: continue;
290:
291: for (j = i; j < num && !arr->arr_data[j]; j++);
292:
293: memmove(arr->arr_data + i, arr->arr_data + j, (num - j) * sizeof(void*));
294: memset(arr->arr_data + i + (num - j), 0, (j - i) * sizeof(void*));
295:
296: num -= j - i;
297: cx += j - i;
298: }
299: }
300:
301: return cx;
302: }
303:
304: /*
305: * io_arrayElem() - Always GET/PUT element into dynamic array, if not enough elements grow array
306: *
307: * @arr = Array
308: * @n = Position
309: * @data = Element, if set NULL GET element at position or !=NULL PUT element at position
310: * return: -1 error or !=-1 return element at position
311: */
312: inline void *
313: io_arrayElem(array_t * __restrict arr, int n, void *data)
314: {
315: void *dat = NULL;
316:
317: if (!arr)
318: return (void*) -1;
319:
320: if (n > io_arraySize(arr) && io_arrayGrow(arr, n + 1, 0))
321: return (void*) -1;
322:
323: dat = io_arrayGet(arr, n);
324: if (data)
325: io_arraySet(arr, n, data);
326:
327: return dat;
328: }
329:
330: /*
331: * io_arrayPush() - Push element into dynamic array like stack manner, place at first empty position
332: *
333: * @arr = Array
334: * @data = Element, if set NULL return only first empty position
335: * return: -1 not found empty position, array is full!, >-1 return position of stored element into array
336: */
337: inline int
338: io_arrayPush(array_t * __restrict arr, void **data)
339: {
340: register int i;
341: int ret = -1;
342:
343: if (!arr)
344: return -1;
345:
346: for (i = 0; i < io_arraySize(arr); i++)
347: if (!arr->arr_data[i]) {
348: if (data)
349: arr->arr_data[i] = *data;
350: ret = i;
351: break;
352: }
353:
354: return ret;
355: }
356:
357: /*
358: * io_arrayPop() - Pop element from dynamic array like stack manner, last used position
359: *
360: * @arr = Array
361: * @data = Element, if set NULL return only last used position
362: * @delAfter = Delete after Pop element, !=0 delete element from array after return data
363: * return: -1 not found used position, array is empty!, >-1 return element position
364: */
365: inline int
366: io_arrayPop(array_t * __restrict arr, void ** __restrict data, int delAfter)
367: {
368: register int i;
369: int ret = -1;
370:
371: if (!arr)
372: return -1;
373:
374: for (i = io_arraySize(arr) - 1; i >= 0; i--)
375: if (arr->arr_data[i]) {
376: if (data)
377: *data = arr->arr_data[i];
378: if (delAfter)
379: arr->arr_data[i] = NULL;
380: ret = i;
381: break;
382: }
383:
384: return ret;
385: }
386:
387: /*
388: * io_arrayConcat() Concat source array to destination array
389: *
390: * @dest = Destination array
391: * @src = Source array
392: * return: -1 error; >0 new count of destination array
393: */
394: int
395: io_arrayConcat(array_t * __restrict dest, array_t * __restrict src)
396: {
397: int n;
398:
399: assert(dest);
400: assert(src);
401: if (!dest || !src)
402: return -1;
403:
404: n = io_arraySize(dest);
405: if (io_arrayGrow(dest, n + io_arraySize(src), 0))
406: return -1;
407: memcpy(dest->arr_data + n, src->arr_data, io_arraySize(src) * sizeof(void*));
408:
409: return io_arraySize(dest);
410: }
411:
412: /*
413: * io_arrayCopy() Copy source array to destination array
414: *
415: * @dest = Destination array, after use free with io_arrayDestroy()
416: * @src = Source array
417: * return: -1 error; >0 count of destination array
418: */
419: int
420: io_arrayCopy(array_t ** __restrict dest, array_t * __restrict src)
421: {
422: assert(dest);
423: assert(src);
424: if (!dest || !src)
425: return -1;
426:
427: *dest = io_arrayInit(io_arraySize(src));
428: if (!*dest)
429: return -1;
430:
431: memcpy((*dest)->arr_data, src->arr_data, io_arraySize(*dest) * sizeof(void*));
432: return io_arraySize(*dest);
433: }
434:
435: /*
436: * io_argsNum() Parse and calculate number of arguments
437: *
438: * @csArgs = Input arguments line
439: * @csDelim = Delimiter(s) for separate
440: * return: 0 error format; -1 error:: can`t read; >0 ok, number of items
441: */
442: inline int
443: io_argsNum(const char *csArgs, const char *csDelim)
444: {
445: register int res;
446: char *pos;
447:
448: assert(csArgs);
449: assert(csDelim);
450: if (!csArgs || !csDelim)
451: return -1;
452:
453: for (res = 1, pos = (char*) csArgs; (pos = strpbrk(pos, csDelim)); res++, pos++);
454: return res;
455: }
456:
457: /*
458: * io_arrayMake() Parse and make array from arguments ... (input string will be modified!!!
459: * and output array must be free with io_arrayDestroy() after use!)
460: *
461: * @psArgs = Input arguments line, after execute string is modified!!!
462: * @nargs = Maximum requested count of arguments from input string psArgs, if 0 all psArgs
463: * @csDelim = Delimiter(s) for separate
464: * @parr = Output array of arguments ... (must be free with io_arrayDestroy() after use!)
465: * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
466: */
467: int
468: io_arrayMake(char * __restrict psArgs, int nargs, const char *csDelim, array_t ** __restrict parr)
469: {
470: char **app;
471: register int i;
472:
473: assert(psArgs);
474: assert(csDelim);
475: assert(parr);
476: if (!psArgs || !csDelim || !parr)
477: return -1;
478:
479: if (nargs)
480: i = nargs;
481: else
482: i = io_argsNum(psArgs, csDelim);
483: *parr = io_arrayInit(i);
484: if (!*parr)
485: return -1;
486:
487: for (i = 0, app = (char**) (*parr)->arr_data;
488: app < (char**) (*parr)->arr_data + (*parr)->arr_num &&
489: (*app = strsep((char **) &psArgs, csDelim));
490: **app ? i++ : i, **app ? app++ : app);
491: return i;
492: }
493:
494: /*
495: * io_MakeAV() Parse and make attribute/value pair
496: *
497: * @csArgs = Input argument line
498: * @csDelim = Delimiter for separate
499: * @psAttr = Output Attribute
500: * @attrLen = Size of attribute array
501: * @psValue = Output Value, if ==NULL this element not present value or not wanted for return
502: * @valLen = Size of value array
503: * return: 0 error format; -1 error:: can`t read; >0 ok, number of readed items
504: */
505: int
506: io_MakeAV(const char * __restrict csArgs, const char *csDelim,
507: char * __restrict psAttr, int attrLen, char * __restrict psValue, int valLen)
508: {
509: register int ret = 0;
510: char *pos, *psBuf;
511:
512: if (!csArgs || !csDelim || !psAttr || !attrLen)
513: return -1;
514: if (psValue && !valLen)
515: return -1;
516: else
517: memset(psValue, 0, valLen);
518: psBuf = strdup(csArgs);
519: if (!psBuf) {
520: LOGERR;
521: return -1;
522: }
523:
524: pos = strpbrk(psBuf, csDelim);
525: if (pos)
526: *pos++ = 0;
527: ret++;
528: strlcpy(psAttr, psBuf, attrLen);
529:
530: if (pos && *pos) {
531: ret++;
532: if (psValue)
533: strlcpy(psValue, pos, valLen);
534: }
535:
536: free(psBuf);
537: return ret;
538: }
539:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>