Files
wmaker/WINGs/string.c
T
trurl 72a1f8cb9e Throw some comments around the FST table for tokenizing command line.
This is slated for replacement, but it will help to be better documented first.
2025-12-08 12:40:33 -05:00

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;
}