1 /* $NetBSD: interp_parse.c,v 1.4 2009/07/20 04:59:03 kiyohara Exp $ */
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
16 * The meat of the simple parser.
19 #include <sys/cdefs.h>
20 /* __FBSDID("$FreeBSD: src/sys/boot/common/interp_parse.c,v 1.10 2003/08/25 23:30:41 obrien Exp $"); */
22 #include <lib/libsa/stand.h>
23 #include <lib/libsa/loadfile.h>
24 #include <lib/libkern/libkern.h>
26 #include "bootstrap.h"
28 static void clean(void);
29 static int insert(int *argcp
, char *buf
);
30 static char *variable_lookup(char *name
);
32 #define PARSE_BUFSIZE 1024 /* maximum size of one element */
33 #define MAXARGS 20 /* maximum number of elements */
34 static char *args
[MAXARGS
];
37 * parse: accept a string of input and "parse" it for backslash
38 * substitutions and environment variable expansions (${var}),
39 * returning an argc/argv style vector of whitespace separated
40 * arguments. Returns 0 on success, 1 on failure (ok, ok, so I
41 * wimped-out on the error codes! :).
43 * Note that the argv array returned must be freed by the caller, but
44 * we own the space allocated for arguments and will free that on next
45 * invocation. This allows argv consumers to modify the array if
48 * NB: environment variables that expand to more than one whitespace
49 * separated token will be returned as a single argv[] element, not
50 * split in turn. Expanded text is also immune to further backslash
51 * elimination or expansion since this is a one-pass, non-recursive
52 * parser. You didn't specify more than this so if you want more, ask
56 #define PARSE_FAIL(expr) \
58 printf("fail at line %d\n", __LINE__); \
65 /* Accept the usual delimiters for a variable, returning counterpart */
79 return (ch
== '\'' || ch
== '"');
83 parse(int *argc
, char ***argv
, char *str
)
86 char *val
, *p
, *q
, *copy
= NULL
;
88 char token
, tmp
, quote
, *buf
;
89 enum { STR
, VAR
, WHITE
} state
;
93 if (!str
|| (p
= copy
= backslash(str
)) == NULL
)
96 /* Initialize vector and state */
99 buf
= (char *)alloc(PARSE_BUFSIZE
);
102 /* And awaaaaaaaaay we go! */
106 if ((*p
== '\\') && p
[1]) {
108 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
110 } else if (isquote(*p
)) {
111 quote
= quote
? 0 : *p
;
114 else if (isspace(*p
) && !quote
) {
118 PARSE_FAIL(insert(&ac
, buf
));
122 } else if (*p
== '$') {
123 token
= isdelim(*(p
+ 1));
130 PARSE_FAIL(i
== (PARSE_BUFSIZE
- 1));
144 PARSE_FAIL((q
= strchr(p
, token
)) == NULL
);
147 while (*q
&& !isspace(*q
))
152 if ((val
= variable_lookup(p
)) != NULL
) {
153 size_t len
= strlen(val
);
155 strncpy(buf
+ i
, val
, PARSE_BUFSIZE
- (i
+ 1));
156 i
+= min(len
, PARSE_BUFSIZE
- 1);
158 *q
= tmp
; /* restore value */
159 p
= q
+ (token
? 1 : 0);
164 /* If at end of token, add it */
165 if (i
&& state
== STR
) {
167 PARSE_FAIL(insert(&ac
, buf
));
171 *argv
= (char **)alloc((sizeof(char *) * ac
+ 1));
172 memcpy(*argv
, args
, sizeof(char *) * ac
+ 1);
180 /* Clean vector space */
186 for (i
= 0; i
< MAXARGS
; i
++) {
187 if (args
[i
] != NULL
) {
195 insert(int *argcp
, char *buf
)
197 if (*argcp
>= MAXARGS
)
199 args
[(*argcp
)++] = strdup(buf
);
204 variable_lookup(char *name
)
206 /* XXX search "special variable" space first? */
207 return (char *)getenv(name
);