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! */
105 if (*p
== '#' && quote
== 0) {
111 * Check line continuation
113 if (*p
== '\\' && p
[1]) {
115 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
117 } else if (isquote(*p
)) {
118 quote
= quote
? 0 : *p
;
121 else if (isspace(*p
) && !quote
) {
125 PARSE_FAIL(insert(&ac
, buf
));
129 } else if (*p
== '$') {
130 token
= isdelim(*(p
+ 1));
137 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
151 PARSE_FAIL((q
= index(p
, token
)) == NULL
);
154 while (*q
&& !isspace(*q
))
159 if ((val
= variable_lookup(p
)) != NULL
) {
160 size_t len
= strlen(val
);
162 strncpy(buf
+ i
, val
, PARSE_BUFSIZE
- (i
+ 1));
163 i
+= min(len
, PARSE_BUFSIZE
- 1);
165 *q
= tmp
; /* restore value */
166 p
= q
+ (token
? 1 : 0);
171 /* If at end of token, add it */
172 if (i
&& state
== STR
) {
174 PARSE_FAIL(insert(&ac
, buf
));
178 *argv
= (char **)malloc(sizeof(char *) * (ac
+ 1));
179 bcopy(args
, *argv
, sizeof(char *) * (ac
+ 1));
187 /* Clean vector space */
193 for (i
= 0; i
< MAXARGS
; i
++) {
194 if (args
[i
] != NULL
) {
202 insert(int *argcp
, char *buf
)
204 if (*argcp
>= MAXARGS
)
206 args
[(*argcp
)++] = strdup(buf
);
211 variable_lookup(char *name
)
213 /* XXX search "special variable" space first? */
214 return (char *)getenv(name
);