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
, const char *file
,
63 u_int line
, char **cause
)
66 int ch
, i
, argc
, rval
;
67 char **argv
, *buf
, *t
;
68 const char *whitespace
, *equals
;
84 ch
= cmd_string_getc(s
, &p
);
87 if ((t
= cmd_string_string(s
, &p
, '\'', 0)) == NULL
)
89 cmd_string_copy(&buf
, t
, &len
);
92 if ((t
= cmd_string_string(s
, &p
, '"', 1)) == NULL
)
94 cmd_string_copy(&buf
, t
, &len
);
97 if ((t
= cmd_string_variable(s
, &p
)) == NULL
)
99 cmd_string_copy(&buf
, t
, &len
);
102 /* Comment: discard rest of line. */
103 while ((ch
= cmd_string_getc(s
, &p
)) != EOF
)
110 buf
= xrealloc(buf
, 1, len
+ 1);
113 argv
= xrealloc(argv
, argc
+ 1, sizeof *argv
);
124 equals
= strchr(argv
[0], '=');
125 whitespace
= argv
[0] + strcspn(argv
[0], " \t");
126 if (equals
== NULL
|| equals
> whitespace
)
128 environ_put(&global_environ
, argv
[0]);
130 memmove(argv
, argv
+ 1, argc
* (sizeof *argv
));
135 *cmdlist
= cmd_list_parse(argc
, argv
, file
, line
, cause
);
136 if (*cmdlist
== NULL
)
143 t
= cmd_string_expand_tilde(s
, &p
);
146 cmd_string_copy(&buf
, t
, &len
);
151 if (len
>= SIZE_MAX
- 2)
154 buf
= xrealloc(buf
, 1, len
+ 1);
161 xasprintf(cause
, "invalid or unknown command: %s", s
);
167 for (i
= 0; i
< argc
; i
++)
176 cmd_string_copy(char **dst
, char *src
, size_t *len
)
180 srclen
= strlen(src
);
182 *dst
= xrealloc(*dst
, 1, *len
+ srclen
+ 1);
183 strlcpy(*dst
+ *len
, src
, srclen
+ 1);
190 cmd_string_string(const char *s
, size_t *p
, char endch
, int esc
)
199 while ((ch
= cmd_string_getc(s
, p
)) != endch
) {
206 switch (ch
= cmd_string_getc(s
, p
)) {
226 if ((t
= cmd_string_variable(s
, p
)) == NULL
)
228 cmd_string_copy(&buf
, t
, &len
);
232 if (len
>= SIZE_MAX
- 2)
234 buf
= xrealloc(buf
, 1, len
+ 1);
238 buf
= xrealloc(buf
, 1, len
+ 1);
248 cmd_string_variable(const char *s
, size_t *p
)
253 struct environ_entry
*envent
;
255 #define cmd_string_first(ch) ((ch) == '_' || \
256 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
257 #define cmd_string_other(ch) ((ch) == '_' || \
258 ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
259 ((ch) >= '0' && (ch) <= '9'))
265 switch (ch
= cmd_string_getc(s
, p
)) {
271 ch
= cmd_string_getc(s
, p
);
272 if (!cmd_string_first(ch
))
276 if (!cmd_string_first(ch
)) {
277 xasprintf(&t
, "$%c", ch
);
281 buf
= xrealloc(buf
, 1, len
+ 1);
285 ch
= cmd_string_getc(s
, p
);
286 if (ch
== EOF
|| !cmd_string_other(ch
))
289 if (len
>= SIZE_MAX
- 3)
291 buf
= xrealloc(buf
, 1, len
+ 1);
297 if (fch
== '{' && ch
!= '}')
299 if (ch
!= EOF
&& fch
!= '{')
300 cmd_string_ungetc(p
); /* ch */
302 buf
= xrealloc(buf
, 1, len
+ 1);
305 envent
= environ_find(&global_environ
, buf
);
308 return (xstrdup(""));
309 return (xstrdup(envent
->value
));
317 cmd_string_expand_tilde(const char *s
, size_t *p
)
320 struct environ_entry
*envent
;
321 char *home
, *path
, *username
;
324 if (cmd_string_getc(s
, p
) == '/') {
325 envent
= environ_find(&global_environ
, "HOME");
326 if (envent
!= NULL
&& *envent
->value
!= '\0')
327 home
= envent
->value
;
328 else if ((pw
= getpwuid(getuid())) != NULL
)
331 cmd_string_ungetc(p
);
332 if ((username
= cmd_string_string(s
, p
, '/', 0)) == NULL
)
334 if ((pw
= getpwnam(username
)) != NULL
)
341 xasprintf(&path
, "%s/", home
);