1 /* $Id: cmd-string.c,v 1.13 2009-02-16 19:29:17 nicm Exp $ */
4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
29 * Parse a command from a string.
32 int cmd_string_getc(const char *, size_t *);
33 void cmd_string_ungetc(const char *, size_t *);
34 char *cmd_string_string(const char *, size_t *, char, int);
35 char *cmd_string_variable(const char *, size_t *);
38 cmd_string_getc(const char *s
, size_t *p
)
46 cmd_string_ungetc(unused
const char *s
, size_t *p
)
52 * Parse command string. Returns -1 on error. If returning -1, cause is error
53 * string, or NULL for empty command.
56 cmd_string_parse(const char *s
, struct cmd_list
**cmdlist
, char **cause
)
59 int ch
, argc
, rval
, have_arg
;
60 char **argv
, *buf
, *t
, *u
;
63 if ((t
= strchr(s
, ' ')) == NULL
&& (t
= strchr(s
, '\t')) == NULL
)
65 if ((u
= strchr(s
, '=')) != NULL
&& u
< t
) {
67 xasprintf(cause
, "assignment failed: %s", s
);
89 ch
= cmd_string_getc(s
, &p
);
92 if ((t
= cmd_string_string(s
, &p
, '\'', 0)) == NULL
)
94 buf
= xrealloc(buf
, 1, len
+ strlen(t
) + 1);
95 strlcpy(buf
+ len
, t
, strlen(t
) + 1);
102 if ((t
= cmd_string_string(s
, &p
, '"', 1)) == NULL
)
104 buf
= xrealloc(buf
, 1, len
+ strlen(t
) + 1);
105 strlcpy(buf
+ len
, t
, strlen(t
) + 1);
112 if ((t
= cmd_string_variable(s
, &p
)) == NULL
)
114 buf
= xrealloc(buf
, 1, len
+ strlen(t
) + 1);
115 strlcpy(buf
+ len
, t
, strlen(t
) + 1);
121 /* Comment: discard rest of line. */
122 while ((ch
= cmd_string_getc(s
, &p
)) != EOF
)
129 buf
= xrealloc(buf
, 1, len
+ 1);
132 argv
= xrealloc(argv
, argc
+ 1, sizeof *argv
);
146 *cmdlist
= cmd_list_parse(argc
, argv
, cause
);
147 if (*cmdlist
== NULL
)
151 xfree(argv
[argc
- 1]);
157 if (len
>= SIZE_MAX
- 2)
160 buf
= xrealloc(buf
, 1, len
+ 1);
169 xasprintf(cause
, "invalid or unknown command: %s", s
);
184 cmd_string_string(const char *s
, size_t *p
, char endch
, int esc
)
193 while ((ch
= cmd_string_getc(s
, p
)) != endch
) {
200 switch (ch
= cmd_string_getc(s
, p
)) {
217 if ((t
= cmd_string_variable(s
, p
)) == NULL
)
219 buf
= xrealloc(buf
, 1, len
+ strlen(t
) + 1);
220 strlcpy(buf
+ len
, t
, strlen(t
) + 1);
225 if (len
>= SIZE_MAX
- 2)
227 buf
= xrealloc(buf
, 1, len
+ 1);
231 buf
= xrealloc(buf
, 1, len
+ 1);
242 cmd_string_variable(const char *s
, size_t *p
)
248 #define cmd_string_first(ch) ((ch) == '_' || \
249 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
250 #define cmd_string_other(ch) ((ch) == '_' || \
251 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
252 ((ch) >= '0' && (ch) <= '9'))
258 switch (ch
= cmd_string_getc(s
, p
)) {
264 ch
= cmd_string_getc(s
, p
);
265 if (!cmd_string_first(ch
))
269 if (!cmd_string_first(ch
)) {
270 xasprintf(&t
, "$%c", ch
);
274 buf
= xrealloc(buf
, 1, len
+ 1);
278 ch
= cmd_string_getc(s
, p
);
279 if (ch
== EOF
|| !cmd_string_other(ch
))
282 if (len
>= SIZE_MAX
- 3)
284 buf
= xrealloc(buf
, 1, len
+ 1);
290 if (fch
== '{' && ch
!= '}')
292 if (ch
!= EOF
&& fch
!= '{')
293 cmd_string_ungetc(s
, p
); /* ch */
295 buf
= xrealloc(buf
, 1, len
+ 1);
298 if ((t
= getenv(buf
)) == NULL
) {
300 return (xstrdup(""));