e16/src/string.c

464 lines
9.2 KiB
C

/*
* Copyright (C) 2008-2023 Kim Woelders
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <ctype.h>
#include "util.h"
#ifndef HAVE_STRCASECMP
int
Estrcasecmp(const char *s1, const char *s2)
{
char ch1, ch2;
for (;;)
{
ch1 = toupper(*s1++);
ch2 = toupper(*s2++);
if (ch1 == '\0' || ch1 != ch2)
break;
}
return ch1 - ch2;
}
#endif
#ifndef HAVE_STRCASESTR
const char *
Estrcasestr(const char *haystack, const char *needle)
{
const char *s1, *s2;
char ch1, ch2;
for (;; haystack++)
{
s1 = haystack;
s2 = needle;
if (*s1 == '\0')
break;
for (;;)
{
ch1 = toupper(*s1++);
ch2 = toupper(*s2++);
if (ch2 == '\0')
return haystack;
if (ch1 == '\0' || ch1 != ch2)
break;
}
}
return NULL;
}
#endif
/*
* Substitute $ENV_VAR and ${ENV_VAR} with the environment variable
* from str into bptr[blen].
*/
void
EnvSubst(const char *str, char *bptr, unsigned int blen)
{
char env[128];
int nw, len;
const char *si, *p1, *p2;
for (si = str, nw = 0;; si = p2)
{
p1 = strchr(si, '$');
if (!p1)
{
snprintf(bptr + nw, blen - nw, "%s", si);
break;
}
len = p1 - si;
nw += snprintf(bptr + nw, blen - nw, "%.*s", len, si);
p1 += 1;
p2 = *p1 == '{' ? p1 + 1 : p1;
/* $ENV_VAR - Name is validted */
for (; *p2 != '\0'; p2++)
{
if (!(isalnum(*p2) || *p2 == '_'))
break;
}
len = p2 - p1;
if (*p1 == '{')
{
if (*p2 != '}')
{
p2 = p1;
continue;
}
p1 += 1;
p2 += 1;
len -= 1;
}
if (len <= 0)
continue;
snprintf(env, sizeof(env), "%.*s", len, p1);
p1 = getenv(env);
if (p1)
nw += snprintf(bptr + nw, blen - nw, "%s", p1);
}
}
/*
* Trim leading and trailing whitespace
*/
char *
Estrtrim(char *s)
{
int l;
while (isspace(*s))
s++;
if (!*s)
return s;
l = strlen(s);
while (isspace(s[l - 1]))
l--;
s[l] = '\0';
return s;
}
/*
* Trim comments and trailing whitespace
*/
char *
Estrtrim2(char *s)
{
int len, len2, ch, quote;
while (isspace(*s))
s++;
quote = '\0';
for (len = len2 = 0;; len++)
{
ch = s[len];
switch (ch)
{
default:
break;
case '\0':
case '\n':
case '\r':
goto got_len;
case '\'':
case '"':
if (!quote)
quote = ch;
else if (ch == quote)
quote = '\0';
break;
case '#':
if (quote)
break;
goto got_len;
case ' ':
case '\t':
if (quote)
break;
continue;
}
len2 = len + 1;
}
got_len:
s[len2] = '\0';
return s;
}
#if 0 /* Unused */
char **
StrlistDup(char **lst, int num)
{
char **ss;
int i;
if (!lst || num <= 0)
return NULL;
ss = EMALLOC(char *, num + 1);
for (i = 0; i < num; i++)
ss[i] = Estrdup(lst[i]);
ss[i] = NULL;
return ss;
}
#endif
void
StrlistFree(char **lst, int num)
{
if (!lst)
return;
while (num--)
Efree(lst[num]);
Efree(lst);
}
#if 0 /* FIXME - Remove? */
char *
StrlistJoin(char **lst, int num)
{
int i, size;
char *s;
if (!lst || num <= 0)
return NULL;
s = NULL;
size = strlen(lst[0]) + 1;
s = EMALLOC(char, size);
strcpy(s, lst[0]);
for (i = 1; i < num; i++)
{
size += strlen(lst[i]) + 1;
s = EREALLOC(char, s, size);
strcat(s, " ");
strcat(s, lst[i]);
}
return s;
}
#endif
char *
StrlistEncodeEscaped(char *buf, int len, char **lst, int num)
{
int i, j, ch;
char *s, *p;
if (!lst || num <= 0)
return NULL;
j = 0;
s = buf;
p = lst[0];
for (i = 0; i < len - 2; i++)
{
if (!p) /* A string list should not contain NULL items */
break;
ch = *p++;
switch (ch)
{
default:
*s++ = ch;
break;
case '\0':
if (++j >= num)
goto done;
p = lst[j];
if (!p || !p[0])
goto done;
*s++ = ' ';
break;
case ' ':
*s++ = '\\';
*s++ = ' ';
i++;
break;
}
}
done:
*s = '\0';
return buf;
}
static int
_StrlistDecodeArgLen(const char *str, const char **pnext)
{
int len, ch, delim;
const char *s;
len = 0;
delim = '\0';
for (s = str;; s++)
{
ch = *s;
switch (ch)
{
default:
break;
case '\0':
len = s - str;
goto done;
case ' ':
if (delim)
break;
if (s > str && s[-1] == '\\')
break;
len = s - str;
s += 1;
goto done;
case '\'':
case '"':
if (ch == delim)
delim = '\0';
else
delim = ch;
break;
}
}
done:
*pnext = s;
return len;
}
static char *
_StrlistDecodeArgParse(const char *str, int len)
{
char *buf, *p;
int i, ch, ch_last, delim;
buf = EMALLOC(char, len + 1);
p = buf;
ch_last = '\0';
delim = '\0';
for (i = 0; i < len; i++)
{
ch = str[i];
switch (ch)
{
default:
if (ch_last == '\\' && ch != ' ')
*p++ = '\\'; /* TBD!!! */
*p++ = ch;
break;
case '\\':
break;
case '\'':
case '"':
if (!delim)
delim = ch; /* Quote start */
else if (delim == ch)
delim = '\0'; /* Quote end */
else
*p++ = ch;
break;
}
ch_last = ch;
}
*p++ = '\0';
return buf;
}
char **
StrlistDecodeEscaped(const char *str, int *pnum)
{
int num, len;
const char *s, *p;
char **lst;
if (!str)
return NULL;
lst = NULL;
num = 0;
s = str;
for (;; s = p)
{
/* Find next token */
while (*s == ' ')
s++;
if (*s == '\0')
break;
/* Find token extents (including quoting etc.) */
len = _StrlistDecodeArgLen(s, &p);
/* Add token */
lst = EREALLOC(char *, lst, num + 1);
lst[num++] = _StrlistDecodeArgParse(s, len);
}
/* Append NULL item */
lst = EREALLOC(char *, lst, num + 1);
lst[num] = NULL;
*pnum = num;
return lst;
}
char **
StrlistFromString(const char *str, int delim, int *num)
{
const char *s, *p;
char **lst;
int n, len;
lst = NULL;
n = 0;
for (s = str; s; s = p)
{
p = strchr(s, delim);
if (p)
{
len = p - s;
p++;
}
else
{
len = strlen(s);
}
if (len <= 0)
continue;
lst = EREALLOC(char *, lst, n + 2);
lst[n++] = Estrndup(s, len);
}
if (lst)
lst[n] = NULL;
*num = n;
return lst;
}
static int
_qsort_strcmp(const void *s1, const void *s2)
{
return strcmp(*(const char **)s1, *(const char **)s2);
}
void
StrlistSort(char **lst, int len)
{
qsort(lst, (unsigned int)len, sizeof(char *), _qsort_strcmp);
}