xref: /netbsd-src/sys/arch/ia64/stand/common/interp_parse.c (revision b5d131ffdbeee49e21191ba2e27539a16994f3b0)
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