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>
31 * Parse a command from a string.
34 int cmd_string_getc(const char *, size_t *);
35 void cmd_string_ungetc(size_t *);
36 void cmd_string_copy(char **, char *, size_t *);
37 char *cmd_string_string(const char *, size_t *, char, int);
38 char *cmd_string_variable(const char *, size_t *);
39 char *cmd_string_expand_tilde(const char *, size_t *);
42 cmd_string_getc(const char *s
, size_t *p
)
44 const u_char
*ucs
= s
;
52 cmd_string_ungetc(size_t *p
)
58 * Parse command string. Returns -1 on error. If returning -1, cause is error
59 * string, or NULL for empty command.
62 cmd_string_parse(const char *s
, struct cmd_list
**cmdlist
, char **cause
)
65 int ch
, i
, argc
, rval
;
66 char **argv
, *buf
, *t
;
67 const char *whitespace
, *equals
;
83 ch
= cmd_string_getc(s
, &p
);
86 if ((t
= cmd_string_string(s
, &p
, '\'', 0)) == NULL
)
88 cmd_string_copy(&buf
, t
, &len
);
91 if ((t
= cmd_string_string(s
, &p
, '"', 1)) == NULL
)
93 cmd_string_copy(&buf
, t
, &len
);
96 if ((t
= cmd_string_variable(s
, &p
)) == NULL
)
98 cmd_string_copy(&buf
, t
, &len
);
101 /* Comment: discard rest of line. */
102 while ((ch
= cmd_string_getc(s
, &p
)) != EOF
)
109 buf
= xrealloc(buf
, 1, len
+ 1);
112 argv
= xrealloc(argv
, argc
+ 1, sizeof *argv
);
123 equals
= strchr(argv
[0], '=');
124 whitespace
= argv
[0] + strcspn(argv
[0], " \t");
125 if (equals
== NULL
|| equals
> whitespace
)
127 environ_put(&global_environ
, argv
[0]);
129 memmove(argv
, argv
+ 1, argc
* (sizeof *argv
));
134 *cmdlist
= cmd_list_parse(argc
, argv
, cause
);
135 if (*cmdlist
== NULL
)
142 t
= cmd_string_expand_tilde(s
, &p
);
145 cmd_string_copy(&buf
, t
, &len
);
150 if (len
>= SIZE_MAX
- 2)
153 buf
= xrealloc(buf
, 1, len
+ 1);
160 xasprintf(cause
, "invalid or unknown command: %s", s
);
166 for (i
= 0; i
< argc
; i
++)
175 cmd_string_copy(char **dst
, char *src
, size_t *len
)
179 srclen
= strlen(src
);
181 *dst
= xrealloc(*dst
, 1, *len
+ srclen
+ 1);
182 strlcpy(*dst
+ *len
, src
, srclen
+ 1);
189 cmd_string_string(const char *s
, size_t *p
, char endch
, int esc
)
198 while ((ch
= cmd_string_getc(s
, p
)) != endch
) {
205 switch (ch
= cmd_string_getc(s
, p
)) {
225 if ((t
= cmd_string_variable(s
, p
)) == NULL
)
227 cmd_string_copy(&buf
, t
, &len
);
231 if (len
>= SIZE_MAX
- 2)
233 buf
= xrealloc(buf
, 1, len
+ 1);
237 buf
= xrealloc(buf
, 1, len
+ 1);
247 cmd_string_variable(const char *s
, size_t *p
)
252 struct environ_entry
*envent
;
254 #define cmd_string_first(ch) ((ch) == '_' || \
255 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
256 #define cmd_string_other(ch) ((ch) == '_' || \
257 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
258 ((ch) >= '0' && (ch) <= '9'))
264 switch (ch
= cmd_string_getc(s
, p
)) {
270 ch
= cmd_string_getc(s
, p
);
271 if (!cmd_string_first(ch
))
275 if (!cmd_string_first(ch
)) {
276 xasprintf(&t
, "$%c", ch
);
280 buf
= xrealloc(buf
, 1, len
+ 1);
284 ch
= cmd_string_getc(s
, p
);
285 if (ch
== EOF
|| !cmd_string_other(ch
))
288 if (len
>= SIZE_MAX
- 3)
290 buf
= xrealloc(buf
, 1, len
+ 1);
296 if (fch
== '{' && ch
!= '}')
298 if (ch
!= EOF
&& fch
!= '{')
299 cmd_string_ungetc(p
); /* ch */
301 buf
= xrealloc(buf
, 1, len
+ 1);
304 envent
= environ_find(&global_environ
, buf
);
307 return (xstrdup(""));
308 return (xstrdup(envent
->value
));
316 cmd_string_expand_tilde(const char *s
, size_t *p
)
319 struct environ_entry
*envent
;
320 char *home
, *path
, *username
;
323 if (cmd_string_getc(s
, p
) == '/') {
324 envent
= environ_find(&global_environ
, "HOME");
325 if (envent
!= NULL
&& *envent
->value
!= '\0')
326 home
= envent
->value
;
327 else if ((pw
= getpwuid(getuid())) != NULL
)
330 cmd_string_ungetc(p
);
331 if ((username
= cmd_string_string(s
, p
, '/', 0)) == NULL
)
333 if ((pw
= getpwnam(username
)) != NULL
)
340 xasprintf(&path
, "%s/", home
);