Annotation of libelwix/src/str.c, revision 1.11.34.1

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.11.34.1! misho       6: * $Id: str.c,v 1.11 2024/10/28 09:58: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.11.34.1! 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.11.34.1! 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>