241 lines
4.6 KiB
C
241 lines
4.6 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] = {
|
|
/* Ctype: ALPHA BLANK ESCAPE DQUOTE EOS SQUOTE
|
|
/* State 0: Start */ {{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
|
|
/* State 1: In dquote */ {{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
|
|
/* State 2: Escape in dquote */ {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
|
|
/* State 3: In token */ {{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
|
|
/* State 4: Escaping */ {{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
|
|
/* State 5: End of string */ {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
|
|
/* State 6: In squote */ {{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
|
|
/* State 7: Escape in squote */ {{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
|
|
/* State 8: End of string */ {{-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;
|
|
}
|