forked from vitrine/wmaker
These functions were added to glibc 2.38, so we don't even need to check for libbsd. There isn't a strong need to worry about supporting older systems because use of these functions should go away as we rewrite string.c in Rust. And, apparently, they are not held in high regard historically. That's at least 2 reasons to be rid of them.
240 lines
4.3 KiB
C
240 lines
4.3 KiB
C
/*
|
|
* Until FreeBSD gets their act together;
|
|
* http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
|
|
*/
|
|
#if defined( FREEBSD )
|
|
# undef _XOPEN_SOURCE
|
|
#endif
|
|
|
|
#include "wconfig.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#ifdef HAVE_BSD_STRING_H
|
|
#include <bsd/string.h>
|
|
#endif
|
|
|
|
#include "WUtil.h"
|
|
|
|
#define PRC_ALPHA 0
|
|
#define PRC_BLANK 1
|
|
#define PRC_ESCAPE 2
|
|
#define PRC_DQUOTE 3
|
|
#define PRC_EOS 4
|
|
#define PRC_SQUOTE 5
|
|
|
|
typedef struct {
|
|
short nstate;
|
|
short output;
|
|
} DFA;
|
|
|
|
static DFA mtable[9][6] = {
|
|
{{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
|
|
{{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
|
|
{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
|
|
{{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
|
|
{{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
|
|
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
|
|
{{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
|
|
{{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
|
|
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
|
|
};
|
|
|
|
char *wtokennext(char *word, char **next)
|
|
{
|
|
char *ptr;
|
|
char *ret, *t;
|
|
int state, ctype;
|
|
|
|
t = ret = wmalloc(strlen(word) + 1);
|
|
ptr = word;
|
|
|
|
state = 0;
|
|
while (1) {
|
|
if (*ptr == 0)
|
|
ctype = PRC_EOS;
|
|
else if (*ptr == '\\')
|
|
ctype = PRC_ESCAPE;
|
|
else if (*ptr == '"')
|
|
ctype = PRC_DQUOTE;
|
|
else if (*ptr == '\'')
|
|
ctype = PRC_SQUOTE;
|
|
else if (*ptr == ' ' || *ptr == '\t')
|
|
ctype = PRC_BLANK;
|
|
else
|
|
ctype = PRC_ALPHA;
|
|
|
|
if (mtable[state][ctype].output) {
|
|
*t = *ptr;
|
|
t++;
|
|
*t = 0;
|
|
}
|
|
state = mtable[state][ctype].nstate;
|
|
ptr++;
|
|
if (mtable[state][0].output < 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*ret == 0) {
|
|
wfree(ret);
|
|
ret = NULL;
|
|
}
|
|
|
|
if (ctype == PRC_EOS)
|
|
*next = NULL;
|
|
else
|
|
*next = ptr;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* separate a string in tokens, taking " and ' into account */
|
|
void wtokensplit(char *command, char ***argv, int *argc)
|
|
{
|
|
char *token, *line;
|
|
int count;
|
|
|
|
count = 0;
|
|
line = command;
|
|
do {
|
|
token = wtokennext(line, &line);
|
|
if (token) {
|
|
if (count == 0)
|
|
*argv = wmalloc(sizeof(**argv));
|
|
else
|
|
*argv = wrealloc(*argv, (count + 1) * sizeof(**argv));
|
|
(*argv)[count++] = token;
|
|
}
|
|
} while (token != NULL && line != NULL);
|
|
|
|
*argc = count;
|
|
}
|
|
|
|
char *wtokenjoin(char **list, int count)
|
|
{
|
|
int i, j;
|
|
char *flat_string, *wspace;
|
|
|
|
j = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (list[i] != NULL && list[i][0] != 0) {
|
|
j += strlen(list[i]);
|
|
if (strpbrk(list[i], " \t"))
|
|
j += 2;
|
|
}
|
|
}
|
|
|
|
flat_string = wmalloc(j + count + 1);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (list[i] != NULL && list[i][0] != 0) {
|
|
if (i > 0 &&
|
|
strlcat(flat_string, " ", j + count + 1) >= j + count + 1)
|
|
goto error;
|
|
|
|
wspace = strpbrk(list[i], " \t");
|
|
|
|
if (wspace &&
|
|
strlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
|
|
goto error;
|
|
|
|
if (strlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
|
|
goto error;
|
|
|
|
if (wspace &&
|
|
strlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
return flat_string;
|
|
|
|
error:
|
|
wfree(flat_string);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void wtokenfree(char **tokens, int count)
|
|
{
|
|
while (count--)
|
|
wfree(tokens[count]);
|
|
wfree(tokens);
|
|
}
|
|
|
|
char *wtrimspace(const char *s)
|
|
{
|
|
const char *t;
|
|
|
|
if (s == NULL)
|
|
return NULL;
|
|
|
|
while (isspace(*s) && *s)
|
|
s++;
|
|
t = s + strlen(s) - 1;
|
|
while (t > s && isspace(*t))
|
|
t--;
|
|
|
|
return wstrndup(s, t - s + 1);
|
|
}
|
|
|
|
char *wstrdup(const char *str)
|
|
{
|
|
assert(str != NULL);
|
|
|
|
return strcpy(wmalloc(strlen(str) + 1), str);
|
|
}
|
|
|
|
char *wstrndup(const char *str, size_t len)
|
|
{
|
|
char *copy;
|
|
|
|
assert(str != NULL);
|
|
|
|
len = WMIN(len, strlen(str));
|
|
copy = strncpy(wmalloc(len + 1), str, len);
|
|
copy[len] = 0;
|
|
|
|
return copy;
|
|
}
|
|
|
|
char *wstrconcat(const char *str1, const char *str2)
|
|
{
|
|
char *str;
|
|
size_t slen, slen1;
|
|
|
|
if (!str1 && str2)
|
|
return wstrdup(str2);
|
|
else if (str1 && !str2)
|
|
return wstrdup(str1);
|
|
else if (!str1 && !str2)
|
|
return NULL;
|
|
|
|
slen1 = strlen(str1);
|
|
slen = slen1 + strlen(str2) + 1;
|
|
str = wmalloc(slen);
|
|
strcpy(str, str1);
|
|
strcpy(str + slen1, str2);
|
|
|
|
return str;
|
|
}
|
|
|
|
char *wstrappend(char *dst, const char *src)
|
|
{
|
|
size_t slen;
|
|
|
|
if (!src || *src == 0)
|
|
return dst;
|
|
else if (!dst)
|
|
return wstrdup(src);
|
|
|
|
slen = strlen(dst) + strlen(src) + 1;
|
|
dst = wrealloc(dst, slen);
|
|
strcat(dst, src);
|
|
|
|
return dst;
|
|
}
|