2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions
5 * 1. Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * 2. Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
14 * The meat of the simple parser.
16 * $FreeBSD: src/sys/boot/common/interp_parse.c,v 1.10 2003/08/25 23:30:41 obrien Exp $
17 * $DragonFly: src/sys/boot/common/interp_parse.c,v 1.3 2003/11/10 06:08:31 dillon Exp $
22 #include "bootstrap.h"
24 static void clean(void);
25 static int insert(int *argcp
, char *buf
);
26 static char *variable_lookup(char *name
);
28 #define PARSE_BUFSIZE 1024 /* maximum size of one element */
29 #define MAXARGS 20 /* maximum number of elements */
30 static char *args
[MAXARGS
];
33 * parse: accept a string of input and "parse" it for backslash
34 * substitutions and environment variable expansions (${var}),
35 * returning an argc/argv style vector of whitespace separated
36 * arguments. Returns 0 on success, 1 on failure (ok, ok, so I
37 * wimped-out on the error codes! :).
39 * Note that the argv array returned must be freed by the caller, but
40 * we own the space allocated for arguments and will free that on next
41 * invocation. This allows argv consumers to modify the array if
44 * NB: environment variables that expand to more than one whitespace
45 * separated token will be returned as a single argv[] element, not
46 * split in turn. Expanded text is also immune to further backslash
47 * elimination or expansion since this is a one-pass, non-recursive
48 * parser. You didn't specify more than this so if you want more, ask
52 #define PARSE_FAIL(expr) \
54 printf("fail at line %d\n", __LINE__); \
61 /* Accept the usual delimiters for a variable, returning counterpart */
75 return (ch
== '\'' || ch
== '"');
79 parse(int *argc
, char ***argv
, char *str
)
82 char *val
, *p
, *q
, *copy
= NULL
;
84 char token
, tmp
, quote
, *buf
;
85 enum { STR
, VAR
, WHITE
} state
;
89 if (!str
|| (p
= copy
= backslash(str
)) == NULL
)
92 /* Initialize vector and state */
95 buf
= (char *)malloc(PARSE_BUFSIZE
);
98 /* And awaaaaaaaaay we go! */
102 if ((*p
== '\\') && p
[1]) {
104 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
106 } else if (isquote(*p
)) {
107 quote
= quote
? 0 : *p
;
110 else if (isspace(*p
) && !quote
) {
114 PARSE_FAIL(insert(&ac
, buf
));
118 } else if (*p
== '$') {
119 token
= isdelim(*(p
+ 1));
126 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
140 PARSE_FAIL((q
= index(p
, token
)) == NULL
);
143 while (*q
&& !isspace(*q
))
148 if ((val
= variable_lookup(p
)) != NULL
) {
149 size_t len
= strlen(val
);
151 strncpy(buf
+ i
, val
, PARSE_BUFSIZE
- (i
+ 1));
152 i
+= min(len
, PARSE_BUFSIZE
- 1);
154 *q
= tmp
; /* restore value */
155 p
= q
+ (token
? 1 : 0);
160 /* If at end of token, add it */
161 if (i
&& state
== STR
) {
163 PARSE_FAIL(insert(&ac
, buf
));
167 *argv
= (char **)malloc((sizeof(char *) * ac
+ 1));
168 bcopy(args
, *argv
, sizeof(char *) * ac
+ 1);
176 /* Clean vector space */
182 for (i
= 0; i
< MAXARGS
; i
++) {
183 if (args
[i
] != NULL
) {
191 insert(int *argcp
, char *buf
)
193 if (*argcp
>= MAXARGS
)
195 args
[(*argcp
)++] = strdup(buf
);
200 variable_lookup(char *name
)
202 /* XXX search "special variable" space first? */
203 return (char *)getenv(name
);