Annotation of libelwix/src/str.c, revision 1.12
1.1 misho 1: /*************************************************************************
2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.12 ! misho 6: * $Id: str.c,v 1.11.34.1 2026/07/22 10:39:11 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.12 ! misho 15: Copyright 2004 - 2026
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: * str_FreeNullTerm() - Free dynamic allocated null terminated array with strings
51: *
52: * @arr = Pointer to array for free
53: * return: none
54: */
1.3 misho 55: void
1.1 misho 56: str_FreeNullTerm(char *** __restrict arr)
57: {
58: char **a;
59:
60: if (arr && *arr) {
61: a = *arr;
62: while (a && *a)
63: e_free(*a++);
64: e_free(*arr);
65: *arr = NULL;
66: }
67: }
68:
69: /*
70: * str_ArgsNum() Parse and calculate number of arguments
71: *
72: * @csArgs = Input arguments line
73: * @csDelim = Delimiter(s) for separate
74: * return: 0 error format; -1 error:: can`t read; >0 ok, number of items
75: */
1.3 misho 76: int
1.1 misho 77: str_ArgsNum(const char *csArgs, const char *csDelim)
78: {
79: register int res;
80: char *pos;
81:
82: if (!csArgs || !csDelim)
83: return -1;
84:
85: for (res = 1, pos = (char*) csArgs; (pos = strpbrk(pos, csDelim)); res++, pos++);
86:
87: return res;
88: }
89:
90: /*
91: * str_ExecArgs() - Build exec arguments from other array
92: *
93: * @psProg = Program name for execute
94: * @oldarg = Arguments array
95: * return: NULL error; !=NULL Allocated execution array(must be e_free)
96: */
97: char **
98: str_ExecArgs(const char *psProg, const char **oldarg)
99: {
100: char **newarg, **el;
101: register int i, num;
102:
103: if (!psProg || !oldarg)
104: return NULL;
105: else
106: newarg = el = NULL;
107:
108: /* count items arguments */
109: for (num = 0; oldarg[num]; num++);
110:
111: /* create and copy new arguments */
112: newarg = e_calloc(num + 2, sizeof(char*));
113: if (!newarg)
114: return NULL;
115: else
116: el = newarg;
117:
118: *el = e_strdup(psProg);
119: el++;
120:
121: for (i = 0; oldarg[i]; i++, el++)
122: *el = e_strdup(oldarg[i]);
123: *el = NULL;
124:
125: return newarg;
126: }
127:
128: /*
129: * str_CopyEnv() - Copy environment to new environment array;
130: *
131: * @oldenv = Environment array
132: * return: NULL error; !=NULL Allocated new environment array(must be e_free)
133: */
134: char **
135: str_CopyEnv(const char **oldenv)
136: {
137: char **newenv, **el;
138: register int i, num;
139:
140: if (!oldenv)
141: return NULL;
142: else
143: newenv = el = NULL;
144:
145: /* count items environment */
146: for (i = num = 0; oldenv[i]; i++)
147: if (*strchr(oldenv[i], '='))
148: num++;
149:
150: /* create and copy new environment */
151: newenv = e_calloc(num + 1, sizeof(char*));
152: if (!newenv)
153: return NULL;
154: else
155: el = newenv;
156:
157: for (i = 0; oldenv[i]; i++)
158: if (*strchr(oldenv[i], '=')) {
159: *el = e_strdup(oldenv[i]);
160: el++;
161: }
162: *el = NULL;
163:
164: return newenv;
165: }
166:
167: /*
168: * str_Ast() - Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}"
169: *
170: * @csString = Input string
171: * return: NULL error, !=NULL Allocated new string evaluated from input string,
172: * must be ait_freeVar()
173: */
174: ait_val_t *
175: str_Ast(const char *csString)
176: {
177: char *ext, *str, *eb;
178: int e[2] = { 0, 0 };
179: ait_val_t *out = NULL;
180:
181: if (!csString)
182: return NULL;
183:
184: if (!strchr(csString, '{') || !strrchr(csString, '}')) {
185: elwix_SetErr(EINVAL, "Invalid input string format ... must be like "
186: "{text[:[-]#[:#]]}");
187: return NULL;
188: } else if (!(out = ait_allocVar()))
189: return NULL;
190: else {
191: AIT_INIT_VAL2(out, string);
192:
193: str = e_strdup(strchr(csString, '{') + 1);
194: *strrchr(str, '}') = 0;
195: }
196:
197: if ((ext = strchr(str, ':'))) {
198: *ext++ = 0;
199: e[0] = strtol(ext, &eb, 0);
200: if ((ext = strchr(eb, ':')))
201: e[1] = strtol(++ext, NULL, 0);
202:
203: /* make cut prefix */
204: if (e[0] >= 0)
205: ext = str + MIN(e[0], strlen(str));
206: else
207: ext = str + MAX(strlen(str) + e[0], 0);
208: /* make cut suffix */
209: if (e[1] > 0)
210: *(ext + MIN(e[1], strlen(ext))) = 0;
211: } else
212: /* ok, clear show */
213: ext = str;
214:
215: AIT_SET_STR(out, ext);
216: e_free(str);
217:
218: return out;
219: }
220:
221: /*
222: * str_Hex2Dig() - Convert from Hex string to digit array
223: *
224: * @psLine = Text string
225: * return: NULL nothing to do or error;
226: * !=0 Allocated new converted data (must be ait_freeVar())
227: */
228: ait_val_t *
229: str_Hex2Dig(const char *psLine)
230: {
231: register int i, j;
232: char *str, szWork[3] = { 0, 0, 0 };
1.7 misho 233: ait_val_t *v, s = AIT_VAL_INIT;
1.1 misho 234: u_char *b;
235: int n;
236:
237: if (!psLine || !*psLine)
238: return NULL;
239: else {
240: v = ait_allocVar();
241: if (!v)
242: return NULL;
243:
244: /* normalize input string if not even */
245: n = strlen(psLine);
246: if (n % 2)
247: n++;
248: AIT_SET_STRSIZ(&s, n);
249: for (i = strlen(psLine) - 1, j = n - 1, str = AIT_GET_STR(&s), *str = '0';
250: i > -1; i--, j--)
251: str[j] = psLine[i];
252: }
253:
254: AIT_SET_BUFSIZ(v, 0, n / 2);
255: for (i = 0, b = AIT_GET_BUF(v); i < n && str[i * 2]; i++) {
256: strncpy(szWork, &str[i * 2], 2);
257: b[i] = (u_char) strtol(szWork, NULL, 16);
258: }
259:
260: AIT_FREE_VAL(&s);
261: return v;
262: }
263:
264: /*
265: * str_Dig2Hex() - Convert from digit array to Hex string
266: *
267: * @digz = Digits
268: * return: NULL nothing to do or error;
269: * !=0 Allocated new converted string (must be e_free())
270: */
271: char *
272: str_Dig2Hex(ait_val_t *digz)
273: {
274: register int i;
275: char szWork[3] = { 0, 0, 0 }, *str;
276: u_char *b;
277:
278: if (!digz || AIT_ISEMPTY(digz))
279: return NULL;
280:
281: str = e_malloc(AIT_LEN(digz) * 2 + 1);
282: if (!str)
283: return NULL;
284: else
285: memset(str, 0, AIT_LEN(digz) * 2 + 1);
286:
287: for (i = 0, b = AIT_GET_BUF(digz); i < AIT_LEN(digz); i++) {
1.9 misho 288: snprintf(szWork, sizeof szWork, "%02hhX", b[i]);
1.10 misho 289: strcat(str, szWork);
1.9 misho 290: }
291:
292: return str;
293: }
294:
295: /*
296: * str_Dig2Hex2() - Convert from digit array to Hex string
297: *
298: * @digz = Digits array
299: * @diglen = Array length
300: * return: NULL nothing to do or error;
301: * !=0 Allocated new converted string (must be e_free())
302: */
303: char *
304: str_Dig2Hex2(u_char * __restrict digz, int diglen)
305: {
306: register int i;
307: char szWork[3] = { 0, 0, 0 }, *str;
308: u_char *b;
309:
310: if (!digz || !diglen)
311: return NULL;
312:
313: str = e_malloc(diglen * 2 + 1);
314: if (!str)
315: return NULL;
316: else
317: memset(str, 0, diglen * 2 + 1);
318:
319: for (i = 0, b = digz; i < diglen; i++) {
1.1 misho 320: snprintf(szWork, sizeof szWork, "%02hhX", b[i]);
1.10 misho 321: strcat(str, szWork);
1.1 misho 322: }
323:
324: return str;
325: }
326:
327: /*
1.12 ! misho 328: * str_makeup() - Makeup the string, delete character or replace it
! 329: *
! 330: * @str = String for makeup
! 331: * @ch = Find character
! 332: * @replace = Replace found character with this one if it !=0
! 333: * return: how many replaces are done or -1 error
! 334: */
! 335: int
! 336: str_makeup(char * __restrict str, char ch, char replace)
! 337: {
! 338: int ret = 0;
! 339: char *p, *c;
! 340:
! 341: if (!str)
! 342: return -1;
! 343:
! 344: for (p = c = str; *c; c++)
! 345: if (*c != ch)
! 346: *p++ = *c;
! 347: else {
! 348: if (replace)
! 349: *p++ = replace;
! 350: ret++;
! 351: }
! 352: *p = 0;
! 353:
! 354: return ret;
! 355: }
! 356:
! 357: /*
1.1 misho 358: * str_LTrim() - Remove left whitespaces from text string
359: *
360: * @psLine = Text string
361: * return: 0 nothing to do; !=0 Removed bytes
362: */
1.3 misho 363: int
1.1 misho 364: str_LTrim(char * __restrict psLine)
365: {
366: int pos = 0;
367: char *s;
368:
369: if (!psLine || !*psLine)
370: return 0;
371:
372: for (s = psLine; isspace((u_char) *s); s++);
373: pos = s - psLine;
374:
375: memmove(psLine, s, (strlen(psLine) - pos) + 1);
376: return pos;
377: }
378:
379: /*
380: * str_RTrim() - Remove right whitespaces from text string
381: *
382: * @psLine = Text string
383: * return: 0 nothing to do; !=0 Removed bytes
384: */
1.3 misho 385: int
1.1 misho 386: str_RTrim(char * __restrict psLine)
387: {
388: char *t, *pos;
389:
390: if (!psLine || !*psLine)
391: return 0;
392:
393: pos = psLine + strlen(psLine);
394: for (t = pos - 1; t > psLine && isspace((u_char) *t); t--);
395: *++t = 0;
396:
397: return pos - t;
398: }
399:
400: /*
401: * str_Trim() - Remove left and right whitespaces from text string
402: *
403: * @psLine = Text string
404: * return: 0 nothing to do; !=0 Removed bytes
405: */
1.3 misho 406: int
1.1 misho 407: str_Trim(char * __restrict psLine)
408: {
409: int ret = 0;
410:
411: ret = str_LTrim(psLine);
412: ret += str_RTrim(psLine);
413:
414: return ret;
415: }
416:
417: /*
418: * str_Unquot() - Remove quots from input text string
419: *
420: * @psLine = Text string
421: * return: 0 nothing to do; 1 successful unquoted string
422: */
1.3 misho 423: int
1.1 misho 424: str_Unquot(char * __restrict psLine)
425: {
426: char *pos, *str = NULL;
427: int flg;
428:
429: if (!psLine || !*psLine)
430: return 0;
431:
432: if (*psLine == '"' || *psLine == '\'') {
433: str = e_strdup(psLine + 1);
434: for (pos = str, flg = 0; *pos; flg = ('\\' == *pos), pos++) {
435: if (!flg && *pos == *psLine) {
436: *pos = 0;
437: strlcpy(psLine, str, strlen(psLine) + 1);
438: break;
439: }
440: }
441: e_free(str);
442: return 1;
443: }
444:
445: return 0;
446: }
447:
1.2 misho 448: /*
449: * str_Upper() - Convert all lower characters to upper
450: *
451: * @psLine = Text string
452: * return: 0 nothing to do; !=0 converted chars
453: */
1.3 misho 454: int
1.2 misho 455: str_Upper(char * __restrict psLine)
456: {
457: char *s;
458: register int cx = 0;
459:
460: if (!psLine || !*psLine)
461: return 0;
462:
463: for (s = psLine; *s; s++)
464: if (islower(*s)) {
465: *s = toupper(*s);
466: cx++;
467: }
468:
469: return cx;
470: }
471:
472: /*
473: * str_Lower() - Convert all upper characters to lower
474: *
475: * @psLine = Text string
476: * return: 0 nothing to do; !=0 converted chars
477: */
1.3 misho 478: int
1.2 misho 479: str_Lower(char * __restrict psLine)
480: {
481: char *s;
482: register int cx = 0;
483:
484: if (!psLine || !*psLine)
485: return 0;
486:
487: for (s = psLine; *s; s++)
488: if (isupper(*s)) {
489: *s = tolower(*s);
490: cx++;
491: }
492:
493: return cx;
494: }
1.5 misho 495:
496: /*
1.8 misho 497: * str_getString() - Get NULL delimited string from data buffer
1.5 misho 498: *
1.8 misho 499: * @data = Const data buffer
1.5 misho 500: * @dlen = Data length
501: * @next = Return next position after string if !=NULL
502: * return: -1 error or size of string
503: */
504: int
505: str_getString(const u_char * __restrict data, int dlen, char ** __restrict next)
506: {
507: const u_char *pos;
508:
509: if (!data || !dlen)
510: return -1;
511:
512: for (pos = data; pos < data + dlen; pos++)
513: if (!*pos)
514: break;
515: if (*pos) {
516: elwix_SetErr(ENOEXEC, "Not found null-terminated string");
517: return -1;
518: }
519:
520: if (next)
521: *next = (char*) pos + 1;
522: return pos - data + 1;
1.8 misho 523: }
524:
525: /*
526: * str_getString2() - Get string from data buffer with delimiter
527: *
528: * @data = Data buffer
529: * @dlen = Data length
530: * @delim = Data delimiter
531: * @next = Return next position after delimited string if !=NULL
532: * return: -1 error or size of string
533: */
534: int
535: str_getString2(char * __restrict data, int dlen, char delim, char ** __restrict next)
536: {
537: char *pos;
538:
539: if (!data || !dlen)
540: return -1;
541:
542: for (pos = data; pos < data + dlen; pos++)
543: if (!*pos || *pos == (u_char) delim) {
544: *pos = 0;
545: break;
546: }
547: if (*pos) {
548: elwix_SetErr(ENOEXEC, "Not found null-terminated string");
549: return -1;
550: }
551:
552: if (next)
553: *next = (char*) pos + 1;
554: return pos - data;
1.5 misho 555: }
1.11 misho 556:
557: /*
558: * str_find2replace() - Search find string into data and replace
559: *
560: * @data = input string
561: * @find = search for string
562: * @replace = replace to string. If it is NULL then deletes found search string
563: * @str = new produced allocate string. If it is NULL then just return found occurances of find
564: * @mlen = allocated memory size for new string
565: * return: -1 error, 0 not found or >0 how many occurances we have for find string
566: */
567: int
568: str_find2replace(const char *data, const char *find, const char *replace, char **str, int *mlen)
569: {
570: int cnt = 0, data_len, slen, find_len, replace_len = 0;
571: const char *pos, *s;
572:
573: if (!data || !find)
574: return -1;
575:
576: find_len = strlen(find);
577: data_len = strlen(data);
578: for (pos = data; (pos = strstr(pos, find)); pos += find_len, cnt++);
579:
580: /* just count occurances */
581: if (!str || !mlen)
582: return cnt;
583:
584: slen = data_len - find_len * cnt;
585: if (replace) {
586: replace_len = strlen(replace);
587: slen += replace_len * cnt;
588: }
589: /* alloc exports string */
590: *mlen = slen + 1;
591: *str = e_malloc(*mlen);
592: if (!*str)
593: return -1;
594: else
595: memset(*str, 0, *mlen);
596:
597: /* search & replace */
598: for (pos = data; *pos;) {
599: s = strstr(pos, find);
600: if (s)
601: slen = s - pos;
602: else
603: slen = strlen(pos);
604: /*
605: * This hack was made due to behaviour of compiler against strncat(*str, pos, slen)!
606: */
607: memcpy(*str + strlen(*str), pos, slen);
608: if (s) {
609: if (replace)
610: strncat(*str, replace, replace_len);
611: pos += find_len;
612: }
613: pos += slen;
614: }
615:
616: return cnt;
617: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>