1 /* argcv.c - simple functions for parsing input based on whitespace
2 Copyright (C) 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
23 * takes a string and splits it into several strings, breaking at ' '
24 * command is the string to split
25 * the number of strings is placed into argc
26 * the split strings are put into argv
27 * returns 0 on success, nonzero on failure
30 #define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n')
31 #define isdelim(c,delim) ((c)=='"'||strchr(delim,(c))!=NULL)
34 argcv_scan (int len, const char *command, const char *delim, const char* cmnt,
35 int *start, int *end, int *save)
46 /* Skip initial whitespace */
47 while (i < len && isws (command[i]))
56 && (command[i] != command[*start]
57 || command[i-1] == '\\'))
59 if (i < len) /* found matching quote */
62 if (isdelim (command[i], delim))
64 /* Skip until next whitespace character or end of line. Honor
65 escaped whitespace. */
67 !((isws (command[i]) && command[i-1] != '\\')
68 || isdelim (command[i], delim)));
76 /* If we have a token, and it starts with a comment character, skip
77 to the newline and restart the token search. */
80 if (cmnt && strchr (cmnt, command[*start]) != NULL)
83 while (i < len && command[i] != '\n')
95 static char escape_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t";
98 argcv_unescape_char (int c)
102 for (p = escape_transtab; *p; p += 2)
111 argcv_escape_char (int c)
115 for (p = escape_transtab + sizeof(escape_transtab) - 2;
116 p > escape_transtab; p -= 2)
126 xtonum (const char *src, int base, size_t cnt)
130 char tmp[4]; /* At most three characters + zero */
132 /* Notice: No use to check `cnt'. It should be either 2 or 3 */
133 memcpy (tmp, src, cnt);
135 val = strtoul (tmp, &p, base);
136 return (*p == 0) ? val : -1;
140 escaped_length (const char *str, int *quote)
151 else if (*str == '"')
156 else if (isprint (*str))
158 else if (argcv_escape_char (*str) != -1)
167 unescape_copy (char *dst, const char *src, size_t n)
189 c = xtonum(src, 16, 2);
214 c = xtonum(src, 8, 3);
230 *dst++ = argcv_unescape_char (*src++);
243 escape_copy (char *dst, const char *src)
252 else if (*src != '\t' && isprint(*src))
256 int c = argcv_escape_char (*src);
263 snprintf (tmp, sizeof tmp, "%03o", *(unsigned char*)src);
264 memcpy (dst, tmp, 3);
272 argcv_get (const char *command, const char *delim, const char* cmnt,
273 int *argc, char ***argv)
275 int len = strlen (command);
277 int start, end, save;
281 /* Count number of arguments */
285 while (argcv_scan (len, command, delim, cmnt, &start, &end, &save) <= len)
288 *argv = calloc ((*argc + 1), sizeof (char *));
292 for (i = 0; i < *argc; i++)
295 argcv_scan (len, command, delim, cmnt, &start, &end, &save);
297 if ((command[start] == '"' || command[end] == '\'')
298 && command[end] == command[start])
304 (*argv)[i] = calloc (n+1, sizeof (char));
305 if ((*argv)[i] == NULL)
307 unescape_copy ((*argv)[i], &command[start], n);
315 * frees all elements of an argv array
316 * argc is the number of elements
320 argcv_free (int argc, char **argv)
329 /* Take a argv an make string separated by ' '. */
332 argcv_string (int argc, char **argv, char **pstring)
346 for (len = i = j = 0; i < argc; i++)
351 toklen = escaped_length (argv[i], "e);
357 buffer = realloc (buffer, len);
365 escape_copy (buffer + j, argv[i]);
371 for (; j > 0 && isspace (buffer[j-1]); j--)
380 char *command = "set prompt=\"& \a\\\"\" \\x25\\0145\\098\\ta";
382 main(int xargc, char **xargv)
388 argcv_get (xargv[1] ? xargv[1]:command, "=", "#", &argc, &argv);
389 printf ("%d args:\n", argc);
390 for (i = 0; i < argc; i++)
391 printf ("%s\n", argv[i]);
393 argcv_string (argc, argv, &s);