1*b5d131ffSriastradh /* $NetBSD: interp_parse.c,v 1.6 2018/09/04 15:08:30 riastradh Exp $ */
2ba7cbe76Scherry
3ba7cbe76Scherry /*-
4ba7cbe76Scherry * Redistribution and use in source and binary forms, with or without
5ba7cbe76Scherry * modification, are permitted provided that the following conditions
6ba7cbe76Scherry * are met:
7ba7cbe76Scherry * 1. Redistributions of source code must retain the above copyright
8ba7cbe76Scherry * notice, this list of conditions and the following disclaimer.
9ba7cbe76Scherry * 2. Redistributions in binary form must reproduce the above copyright
10ba7cbe76Scherry * notice, this list of conditions and the following disclaimer in the
11ba7cbe76Scherry * documentation and/or other materials provided with the distribution.
12ba7cbe76Scherry *
13ba7cbe76Scherry * Jordan K. Hubbard
14ba7cbe76Scherry * 29 August 1998
15ba7cbe76Scherry *
16ba7cbe76Scherry * The meat of the simple parser.
17ba7cbe76Scherry */
18ba7cbe76Scherry
19ba7cbe76Scherry #include <sys/cdefs.h>
2040d4f67eScherry /* __FBSDID("$FreeBSD: src/sys/boot/common/interp_parse.c,v 1.10 2003/08/25 23:30:41 obrien Exp $"); */
21ba7cbe76Scherry
22ba7cbe76Scherry #include <lib/libsa/stand.h>
2393b81f4cSkiyohara #include <lib/libsa/loadfile.h>
24ba7cbe76Scherry #include <lib/libkern/libkern.h>
25ba7cbe76Scherry
26ba7cbe76Scherry #include "bootstrap.h"
27ba7cbe76Scherry
28ba7cbe76Scherry static void clean(void);
29ba7cbe76Scherry static int insert(int *argcp, char *buf);
30ba7cbe76Scherry static char *variable_lookup(char *name);
31ba7cbe76Scherry
32ba7cbe76Scherry #define PARSE_BUFSIZE 1024 /* maximum size of one element */
33ba7cbe76Scherry #define MAXARGS 20 /* maximum number of elements */
34ba7cbe76Scherry static char *args[MAXARGS];
35ba7cbe76Scherry
36ba7cbe76Scherry /*
37ba7cbe76Scherry * parse: accept a string of input and "parse" it for backslash
38ba7cbe76Scherry * substitutions and environment variable expansions (${var}),
39ba7cbe76Scherry * returning an argc/argv style vector of whitespace separated
40ba7cbe76Scherry * arguments. Returns 0 on success, 1 on failure (ok, ok, so I
41ba7cbe76Scherry * wimped-out on the error codes! :).
42ba7cbe76Scherry *
43ba7cbe76Scherry * Note that the argv array returned must be freed by the caller, but
44ba7cbe76Scherry * we own the space allocated for arguments and will free that on next
45ba7cbe76Scherry * invocation. This allows argv consumers to modify the array if
46ba7cbe76Scherry * required.
47ba7cbe76Scherry *
48ba7cbe76Scherry * NB: environment variables that expand to more than one whitespace
49ba7cbe76Scherry * separated token will be returned as a single argv[] element, not
50ba7cbe76Scherry * split in turn. Expanded text is also immune to further backslash
51ba7cbe76Scherry * elimination or expansion since this is a one-pass, non-recursive
52ba7cbe76Scherry * parser. You didn't specify more than this so if you want more, ask
53ba7cbe76Scherry * me. - jkh
54ba7cbe76Scherry */
55ba7cbe76Scherry
56ba7cbe76Scherry #define PARSE_FAIL(expr) \
57ba7cbe76Scherry if (expr) { \
58ba7cbe76Scherry printf("fail at line %d\n", __LINE__); \
59ba7cbe76Scherry clean(); \
60ba7cbe76Scherry free(copy); \
61ba7cbe76Scherry free(buf); \
62ba7cbe76Scherry return 1; \
63ba7cbe76Scherry }
64ba7cbe76Scherry
65ba7cbe76Scherry /* Accept the usual delimiters for a variable, returning counterpart */
66ba7cbe76Scherry static char
isdelim(int ch)67ba7cbe76Scherry isdelim(int ch)
68ba7cbe76Scherry {
69ba7cbe76Scherry if (ch == '{')
70ba7cbe76Scherry return '}';
71ba7cbe76Scherry else if (ch == '(')
72ba7cbe76Scherry return ')';
73ba7cbe76Scherry return '\0';
74ba7cbe76Scherry }
75ba7cbe76Scherry
76ba7cbe76Scherry static int
isquote(int ch)77ba7cbe76Scherry isquote(int ch)
78ba7cbe76Scherry {
79ba7cbe76Scherry return (ch == '\'' || ch == '"');
80ba7cbe76Scherry }
81ba7cbe76Scherry
82ba7cbe76Scherry int
parse(int * argc,char *** argv,char * str)83ba7cbe76Scherry parse(int *argc, char ***argv, char *str)
84ba7cbe76Scherry {
85ba7cbe76Scherry int ac;
86ba7cbe76Scherry char *val, *p, *q, *copy = NULL;
87ba7cbe76Scherry size_t i = 0;
88ba7cbe76Scherry char token, tmp, quote, *buf;
89ba7cbe76Scherry enum { STR, VAR, WHITE } state;
90ba7cbe76Scherry
91ba7cbe76Scherry ac = *argc = 0;
92ba7cbe76Scherry quote = 0;
93ba7cbe76Scherry if (!str || (p = copy = backslash(str)) == NULL)
94ba7cbe76Scherry return 1;
95ba7cbe76Scherry
96ba7cbe76Scherry /* Initialize vector and state */
97ba7cbe76Scherry clean();
98ba7cbe76Scherry state = STR;
99ba7cbe76Scherry buf = (char *)alloc(PARSE_BUFSIZE);
100ba7cbe76Scherry token = 0;
101ba7cbe76Scherry
102ba7cbe76Scherry /* And awaaaaaaaaay we go! */
103ba7cbe76Scherry while (*p) {
104ba7cbe76Scherry switch (state) {
105ba7cbe76Scherry case STR:
106ba7cbe76Scherry if ((*p == '\\') && p[1]) {
107ba7cbe76Scherry p++;
108ba7cbe76Scherry PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
109ba7cbe76Scherry buf[i++] = *p++;
110ba7cbe76Scherry } else if (isquote(*p)) {
111ba7cbe76Scherry quote = quote ? 0 : *p;
112ba7cbe76Scherry ++p;
113ba7cbe76Scherry }
114ba7cbe76Scherry else if (isspace(*p) && !quote) {
115ba7cbe76Scherry state = WHITE;
116ba7cbe76Scherry if (i) {
117ba7cbe76Scherry buf[i] = '\0';
118ba7cbe76Scherry PARSE_FAIL(insert(&ac, buf));
119ba7cbe76Scherry i = 0;
120ba7cbe76Scherry }
121ba7cbe76Scherry ++p;
122ba7cbe76Scherry } else if (*p == '$') {
123ba7cbe76Scherry token = isdelim(*(p + 1));
124ba7cbe76Scherry if (token)
125ba7cbe76Scherry p += 2;
126ba7cbe76Scherry else
127ba7cbe76Scherry ++p;
128ba7cbe76Scherry state = VAR;
129ba7cbe76Scherry } else {
130ba7cbe76Scherry PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
131ba7cbe76Scherry buf[i++] = *p++;
132ba7cbe76Scherry }
133ba7cbe76Scherry break;
134ba7cbe76Scherry
135ba7cbe76Scherry case WHITE:
136ba7cbe76Scherry if (isspace(*p))
137ba7cbe76Scherry ++p;
138ba7cbe76Scherry else
139ba7cbe76Scherry state = STR;
140ba7cbe76Scherry break;
141ba7cbe76Scherry
142ba7cbe76Scherry case VAR:
143ba7cbe76Scherry if (token) {
144ba7cbe76Scherry PARSE_FAIL((q = strchr(p, token)) == NULL);
145ba7cbe76Scherry } else {
146ba7cbe76Scherry q = p;
147ba7cbe76Scherry while (*q && !isspace(*q))
148ba7cbe76Scherry ++q;
149ba7cbe76Scherry }
150ba7cbe76Scherry tmp = *q;
151ba7cbe76Scherry *q = '\0';
152ba7cbe76Scherry if ((val = variable_lookup(p)) != NULL) {
153ba7cbe76Scherry size_t len = strlen(val);
154ba7cbe76Scherry
155ba7cbe76Scherry strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1));
156*b5d131ffSriastradh i += uimin(len, PARSE_BUFSIZE - 1);
157ba7cbe76Scherry }
158ba7cbe76Scherry *q = tmp; /* restore value */
159ba7cbe76Scherry p = q + (token ? 1 : 0);
160ba7cbe76Scherry state = STR;
161ba7cbe76Scherry break;
162ba7cbe76Scherry }
163ba7cbe76Scherry }
164ba7cbe76Scherry /* If at end of token, add it */
165ba7cbe76Scherry if (i && state == STR) {
166ba7cbe76Scherry buf[i] = '\0';
167ba7cbe76Scherry PARSE_FAIL(insert(&ac, buf));
168ba7cbe76Scherry }
169ba7cbe76Scherry args[ac] = NULL;
170ba7cbe76Scherry *argc = ac;
171ba7cbe76Scherry *argv = (char **)alloc((sizeof(char *) * ac + 1));
172e2cb8590Scegger memcpy(*argv, args, sizeof(char *) * ac + 1);
173ba7cbe76Scherry free(buf);
174ba7cbe76Scherry free(copy);
175ba7cbe76Scherry return 0;
176ba7cbe76Scherry }
177ba7cbe76Scherry
178ba7cbe76Scherry #define MAXARGS 20
179ba7cbe76Scherry
180ba7cbe76Scherry /* Clean vector space */
181ba7cbe76Scherry static void
clean(void)182ba7cbe76Scherry clean(void)
183ba7cbe76Scherry {
184ba7cbe76Scherry int i;
185ba7cbe76Scherry
186ba7cbe76Scherry for (i = 0; i < MAXARGS; i++) {
187ba7cbe76Scherry if (args[i] != NULL) {
188ba7cbe76Scherry free(args[i]);
189ba7cbe76Scherry args[i] = NULL;
190ba7cbe76Scherry }
191ba7cbe76Scherry }
192ba7cbe76Scherry }
193ba7cbe76Scherry
194ba7cbe76Scherry static int
insert(int * argcp,char * buf)195ba7cbe76Scherry insert(int *argcp, char *buf)
196ba7cbe76Scherry {
197ba7cbe76Scherry if (*argcp >= MAXARGS)
198ba7cbe76Scherry return 1;
199ba7cbe76Scherry args[(*argcp)++] = strdup(buf);
200ba7cbe76Scherry return 0;
201ba7cbe76Scherry }
202ba7cbe76Scherry
203ba7cbe76Scherry static char *
variable_lookup(char * name)204ba7cbe76Scherry variable_lookup(char *name)
205ba7cbe76Scherry {
206ba7cbe76Scherry /* XXX search "special variable" space first? */
207ba7cbe76Scherry return (char *)getenv(name);
208ba7cbe76Scherry }
209