1 /* argcv.c - simple functions for parsing input based on whitespace
2 Copyright (C) 1999, 2000, 2001, 2007, 2009, 2010 Free Software
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
27 * takes a string and splits it into several strings, breaking at ' '
28 * command is the string to split
29 * the number of strings is placed into argc
30 * the split strings are put into argv
31 * returns 0 on success, nonzero on failure
34 #define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n')
35 #define isdelim(c,delim) ((c)=='"'||strchr(delim,(c))!=NULL)
38 argcv_scan (int len, const char *command, const char *delim, const char* cmnt,
39 int *start, int *end, int *save)
50 /* Skip initial whitespace */
51 while (i < len && isws (command[i]))
60 && (command[i] != command[*start]
61 || command[i-1] == '\\'))
63 if (i < len) /* found matching quote */
66 if (isdelim (command[i], delim))
68 /* Skip until next whitespace character or end of line. Honor
69 escaped whitespace. */
71 !((isws (command[i]) && command[i-1] != '\\')
72 || isdelim (command[i], delim)));
80 /* If we have a token, and it starts with a comment character, skip
81 to the newline and restart the token search. */
84 if (cmnt && strchr (cmnt, command[*start]) != NULL)
87 while (i < len && command[i] != '\n')
99 static char escape_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t";
102 argcv_unescape_char (int c)
106 for (p = escape_transtab; *p; p += 2)
115 argcv_escape_char (int c)
119 for (p = escape_transtab + sizeof(escape_transtab) - 2;
120 p > escape_transtab; p -= 2)
130 xtonum (const char *src, int base, size_t cnt)
134 char tmp[4]; /* At most three characters + zero */
136 /* Notice: No use to check `cnt'. It should be either 2 or 3 */
137 memcpy (tmp, src, cnt);
139 val = strtoul (tmp, &p, base);
140 return (*p == 0) ? val : -1;
144 escaped_length (const char *str, int *quote)
155 else if (*str == '"')
160 else if (isprint ((unsigned char) *str))
162 else if (argcv_escape_char (*str) != -1)
171 unescape_copy (char *dst, const char *src, size_t n)
193 c = xtonum(src, 16, 2);
218 c = xtonum(src, 8, 3);
234 *dst++ = argcv_unescape_char (*src++);
247 escape_copy (char *dst, const char *src)
256 else if (*src != '\t' && isprint ((unsigned char) *src))
260 int c = argcv_escape_char (*src);
267 snprintf (tmp, sizeof tmp, "%03o", *(unsigned char*)src);
268 memcpy (dst, tmp, 3);
276 argcv_get (const char *command, const char *delim, const char* cmnt,
277 int *argc, char ***argv)
279 int len = strlen (command);
281 int start, end, save;
285 /* Count number of arguments */
289 while (argcv_scan (len, command, delim, cmnt, &start, &end, &save) <= len)
292 *argv = calloc ((*argc + 1), sizeof (char *));
296 for (i = 0; i < *argc; i++)
299 argcv_scan (len, command, delim, cmnt, &start, &end, &save);
301 if ((command[start] == '"' || command[end] == '\'')
302 && command[end] == command[start])
308 (*argv)[i] = calloc (n+1, sizeof (char));
309 if ((*argv)[i] == NULL)
311 unescape_copy ((*argv)[i], &command[start], n);
319 * frees all elements of an argv array
320 * argc is the number of elements
324 argcv_free (int argc, char **argv)
333 /* Take a argv an make string separated by ' '. */
336 argcv_string (int argc, char **argv, char **pstring)
350 for (len = i = j = 0; i < argc; i++)
355 toklen = escaped_length (argv[i], "e);
361 buffer = realloc (buffer, len);
369 escape_copy (buffer + j, argv[i]);
375 for (; j > 0 && isspace ((unsigned char) buffer[j - 1]); j--)
384 char *command = "set prompt=\"& \a\\\"\" \\x25\\0145\\098\\ta";
386 main(int xargc, char **xargv)
392 argcv_get (xargv[1] ? xargv[1]:command, "=", "#", &argc, &argv);
393 printf ("%d args:\n", argc);
394 for (i = 0; i < argc; i++)
395 printf ("%s\n", argv[i]);
397 argcv_string (argc, argv, &s);