X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/48d198f1e1fc22a5dadadd70a261996d4f01ac39..d4efbcd93c940ad522fcf8c601ec1829d2e0b10d:/str.c diff --git a/str.c b/str.c index 0defaa7..8e3f43a 100644 --- a/str.c +++ b/str.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: str.c,v 1.3 1999/12/22 15:41:14 mdw Exp $ + * $Id: str.c,v 1.6 2004/04/08 01:36:13 mdw Exp $ * * Functions for hacking with strings * * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of the mLib utilities library. * @@ -15,32 +15,18 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * mLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with mLib; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: str.c,v $ - * Revision 1.3 1999/12/22 15:41:14 mdw - * Skip past trailing whitespace in str_getword. - * - * Revision 1.2 1999/05/26 20:52:57 mdw - * Add new `rest' argument for `str_split'. - * - * Revision 1.1 1999/05/17 20:37:01 mdw - * Some trivial string hacks. - * - */ - /*----- Header files ------------------------------------------------------*/ #include @@ -52,48 +38,89 @@ /*----- Main code ---------------------------------------------------------*/ -/* --- @str_getword@ --- * +/* --- @str_qword@ --- * * * Arguments: @char **pp@ = address of pointer into string + * @unsigned f@ = various flags * - * Returns: Pointer to the next space-separated word from the string, - * or null. + * Returns: Pointer to the next space-separated possibly-quoted word from + * the string, or null. * - * Use: Parses off space-separated words from a string. + * Use: Fetches the next word from a string. If the flag + * @STRF_QUOTE@ is set, the `\' character acts as an escape, and + * single and double quotes protect whitespace. */ -char *str_getword(char **pp) +char *str_qword(char **pp, unsigned f) { - char *p = *pp, *q; + char *p = *pp, *q, *qq; + int st = 0, pst = 0; + + /* --- Preliminaries --- */ if (!p) return (0); - while (isspace((unsigned char)*p)) p++; + if (!*p) { + *pp = 0; + return (0); + } - for (q = p; *q; q++) { - if (isspace((unsigned char)*q)) { - *q++ = 0; - while (*q && isspace((unsigned char)*q)) - q++; - if (!*q) - q = 0; - *pp = q; - return (p); + /* --- Main work --- */ + + for (q = qq = p; *q; q++) { + switch (st) { + case '\\': + *qq++ = *q; + st = pst; + break; + case '\'': + case '\"': + if (*q == st) + st = pst = 0; + else if (*q == '\\') + st = '\\'; + else + *qq++ = *q; + break; + default: + if (isspace((unsigned char)*q)) { + do q++; while (*q && isspace((unsigned char)*q)); + goto done; + } else if (!(f & STRF_QUOTE)) + goto stdchar; + switch (*q) { + case '\\': + st = '\\'; + break; + case '\'': + case '\"': + st = pst = *q; + break; + default: + stdchar: + *qq++ = *q; + break; + } } } - *pp = 0; + /* --- Finished --- */ + +done: + *pp = *q ? q : 0; + *qq++ = 0; return (p); } -/* --- @str_split@ --- * +/* --- @str_qsplit@ --- * * * Arguments: @char *p@ = pointer to string * @char *v[]@ = pointer to array to fill in * @size_t c@ = count of strings to fill in * @char **rest@ = where to store the remainder of the string + * @unsigned f@ = flags for @str_qword@ * * Returns: Number of strings filled in. * @@ -108,12 +135,12 @@ char *str_getword(char **pp) * @rest@ is set to a null pointer. */ -size_t str_split(char *p, char *v[], size_t c, char **rest) +size_t str_qsplit(char *p, char *v[], size_t c, char **rest, unsigned f) { size_t n = 0; char *q; - while (c && (q = str_getword(&p)) != 0) { + while (c && (q = str_qword(&p, f)) != 0) { *v++ = q; c--; n++; @@ -127,6 +154,146 @@ size_t str_split(char *p, char *v[], size_t c, char **rest) return (n); } +/* --- @str_getword@ --- * + * + * Arguments: @char **pp@ = address of pointer into string + * + * Returns: Pointer to the next space-separated word from the string, + * or null. + * + * Use: Parses off space-separated words from a string. This is a + * compatibility veneer over @str_qword@. + */ + +char *str_getword(char **pp) { return (str_qword(pp, 0)); } + +/* --- @str_split@ --- * + * + * Arguments: @char *p@ = pointer to string + * @char *v[]@ = pointer to array to fill in + * @size_t c@ = count of strings to fill in + * @char **rest@ = where to store the remainder of the string + * + * Returns: Number of strings filled in. + * + * Use: Fills an array with pointers to the individual words of a + * string. This is a compatibility veneer over @str_qsplit@. + */ + +size_t str_split(char *p, char *v[], size_t c, char **rest) + { return (str_qsplit(p, v, c, rest, 0)); } + +/* --- @str_matchx@ --- * + * + * Arguments: @const char *p@ = pointer to pattern string + * @const char *s@ = string to compare with + * @unsigned f@ = various flags + * + * Returns: Nonzero if the pattern matches the string. + * + * Use: Does simple wildcard matching. This is quite nasty and more + * than a little slow. Supports metacharacters `*', `?' and + * '['. + */ + +int str_matchx(const char *p, const char *s, unsigned f) +{ + for (;;) { + char pch = *p++, pche, sch; + int sense; + + if ((f & STRF_PREFIX) && !*s) + return (1); + switch (pch) { + case '?': + if (!*s) + return (0); + s++; + break; + case '*': + if (!*p || (f & STRF_PREFIX)) + return (1); + while (*s) { + if (str_match(p, s)) + return (1); + s++; + } + return (0); + case '[': + if (!*s) + return (0); + sch = *s++; + pch = *p++; + sense = 1; + if (pch == '^' || pch == '!') { + sense = !sense; + pch = *p++; + } + if (pch == ']') { + if (*p == '-' && p[1] && p[1] != ']') { + pche = p[1]; + p += 2; + if (pch <= sch && sch <= pche) + goto class_match; + } else if (pch == sch) + goto class_match; + pch = *p++; + } + for (;; pch = *p++) { + if (!pch || pch == ']') + goto class_nomatch; + if (*p == '-' && p[1] && p[1] != ']') { + pche = p[1]; + p += 2; + if (pch <= sch && sch <= pche) + goto class_match; + } else if (pch == sch) + goto class_match; + } + class_match: + if (!sense) + return (0); + for (;;) { + pch = *p++; + if (!pch) + return (0); + if (pch == ']') + break; + if (*p == '-' && p[1] && p[1] != ']') + p += 2; + } + break; + class_nomatch: + if (sense) + return (0); + break; + case '\\': + pch = *p++; + default: + if (pch != *s) + return (0); + if (!pch) + return (1); + s++; + break; + } + } +} + +/* --- @str_match@ --- * + * + * Arguments: @const char *p@ = pointer to pattern string + * @const char *s@ = string to compare with + * + * Returns: Nonzero if the pattern matches the string. + * + * Use: Does simple wildcard matching. Equivalent to @str_matchx@ + * with zero flags word. + */ + +int str_match(const char *p, const char *s) + { return (str_matchx(p, s, 0)); } + /* --- @str_sanitize@ --- * * * Arguments: @char *d@ = destination buffer