/* * 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 #include #include #include #ifdef HAVE_BSD_STRING_H #include #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; }