xref: /netbsd-src/sys/arch/ia64/stand/common/interp.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: interp.c,v 1.3 2006/07/02 17:28:11 cherry Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 /* __FBSDID("$FreeBSD: src/sys/boot/common/interp.c,v 1.29 2003/08/25 23:30:41 obrien Exp $"); */
31 
32 /*
33  * Simple commandline interpreter, toplevel and misc.
34  *
35  * XXX may be obsoleted by BootFORTH or some other, better, interpreter.
36  */
37 
38 #include <lib/libsa/stand.h>
39 
40 #include "bootstrap.h"
41 
42 #ifdef BOOT_FORTH
43 #include "ficl.h"
44 #define	RETURN(x)	stackPushINT(bf_vm->pStack,!x); return(x)
45 
46 extern FICL_VM *bf_vm;
47 #else
48 #define	RETURN(x)	return(x)
49 #endif
50 
51 #define	MAXARGS	20			/* maximum number of arguments allowed */
52 
53 static void	prompt(void);
54 
55 #ifndef BOOT_FORTH
56 static int	perform(int argc, char *argv[]);
57 
58 /*
59  * Perform the command
60  */
61 int
62 perform(int argc, char *argv[])
63 {
64     int				result;
65     struct bootblk_command	*cmdp;
66     bootblk_cmd_t		*cmd;
67 
68     int i;
69 
70     if (argc < 1)
71 	return(CMD_OK);
72 
73     /* set return defaults; a successful command will override these */
74     command_errmsg = command_errbuf;
75     strcpy(command_errbuf, "no error message");
76     cmd = NULL;
77     result = CMD_ERROR;
78 
79     /* search the command set for the command */
80     for (i = 0, cmdp = commands; (cmdp->c_name != NULL) && (cmdp->c_desc != NULL ); i++, cmdp = commands + i) {
81 	if ((cmdp->c_name != NULL) && !strcmp(argv[0], cmdp->c_name))
82 	    cmd = cmdp->c_fn;
83     }
84     if (cmd != NULL) {
85 	result = (cmd)(argc, argv);
86     } else {
87 	command_errmsg = "unknown command";
88     }
89     RETURN(result);
90 }
91 #endif	/* ! BOOT_FORTH */
92 
93 /*
94  * Interactive mode
95  */
96 void
97 interact(void)
98 {
99     char	input[256];			/* big enough? */
100 #ifndef BOOT_FORTH
101     int		argc;
102     char	**argv;
103 #endif
104 
105 #ifdef BOOT_FORTH
106     bf_init();
107 #endif
108 
109     /*
110      * Read our default configuration
111      */
112     if(include("/boot/loader.rc")!=CMD_OK)
113 	include("/boot/boot.conf");
114     printf("\n");
115 
116     /*
117      * XXX: Before interacting, we might want to autoboot.
118      */
119 
120 
121     /*
122      * Not autobooting, go manual
123      */
124     printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");
125     if (getenv("prompt") == NULL)
126 	setenv("prompt", "${interpret}", 1);
127     if (getenv("interpret") == NULL)
128         setenv("interpret", "OK", 1);
129 
130 
131     for (;;) {
132 	input[0] = '\0';
133 	prompt();
134 	ngets(input, sizeof(input));
135 #ifdef BOOT_FORTH
136 	bf_vm->sourceID.i = 0;
137 	bf_run(input);
138 #else
139 	if (!parse(&argc, &argv, input)) {
140 	    if (perform(argc, argv))
141 		printf("%s: %s\n", argv[0], command_errmsg);
142 	    free(argv);
143 	} else {
144 	    printf("parse error\n");
145 	}
146 #endif
147     }
148 }
149 
150 /*
151  * Read commands from a file, then execute them.
152  *
153  * We store the commands in memory and close the source file so that the media
154  * holding it can safely go away while we are executing.
155  *
156  * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so
157  * that the script won't stop if they fail).
158  */
159 
160 int
161 command_include(int argc, char *argv[])
162 {
163     int		i;
164     int		res;
165     char	**argvbuf;
166 
167     /*
168      * Since argv is static, we need to save it here.
169      */
170     argvbuf = (char**) calloc((u_int)argc, sizeof(char*));
171     for (i = 0; i < argc; i++)
172 	argvbuf[i] = strdup(argv[i]);
173 
174     res=CMD_OK;
175     for (i = 1; (i < argc) && (res == CMD_OK); i++)
176 	res = include(argvbuf[i]);
177 
178     for (i = 0; i < argc; i++)
179 	free(argvbuf[i]);
180     free(argvbuf);
181 
182     return(res);
183 }
184 
185 struct includeline
186 {
187     char		*text;
188     int			flags;
189     int			line;
190 #define SL_QUIET	(1<<0)
191 #define SL_IGNOREERR	(1<<1)
192     struct includeline	*next;
193 };
194 
195 int
196 include(const char *filename)
197 {
198     struct includeline	*script, *se, *sp;
199     char		input[256];			/* big enough? */
200 #ifdef BOOT_FORTH
201     int			res;
202     char		*cp;
203     int			prevsrcid, fd, line;
204 #else
205     int			argc,res;
206     char		**argv, *cp;
207     int			fd, flags, line;
208 #endif
209 
210     if (((fd = open(filename, O_RDONLY)) == -1)) {
211 	sprintf(command_errbuf,"can't open '%s': %s\n", filename, strerror(errno));
212 	return(CMD_ERROR);
213     }
214 
215     /*
216      * Read the script into memory.
217      */
218     script = se = NULL;
219     line = 0;
220 
221     while (fgetstr(input, sizeof(input), fd) >= 0) {
222 	line++;
223 #ifdef BOOT_FORTH
224 	cp = input;
225 #else
226 	flags = 0;
227 	/* Discard comments */
228 	if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
229 	    continue;
230 	cp = input;
231 	/* Echo? */
232 	if (input[0] == '@') {
233 	    cp++;
234 	    flags |= SL_QUIET;
235 	}
236 	/* Error OK? */
237 	if (input[0] == '-') {
238 	    cp++;
239 	    flags |= SL_IGNOREERR;
240 	}
241 #endif
242 	/* Allocate script line structure and copy line, flags */
243 	sp = alloc(sizeof(struct includeline) + strlen(cp) + 1);
244 	sp->text = (char *)sp + sizeof(struct includeline);
245 	strcpy(sp->text, cp);
246 #ifndef BOOT_FORTH
247 	sp->flags = flags;
248 #endif
249 	sp->line = line;
250 	sp->next = NULL;
251 
252 	if (script == NULL) {
253 	    script = sp;
254 	} else {
255 	    se->next = sp;
256 	}
257 	se = sp;
258     }
259     close(fd);
260 
261     /*
262      * Execute the script
263      */
264 #ifndef BOOT_FORTH
265     argv = NULL;
266 #else
267     prevsrcid = bf_vm->sourceID.i;
268     bf_vm->sourceID.i = fd;
269 #endif
270     res = CMD_OK;
271     for (sp = script; sp != NULL; sp = sp->next) {
272 
273 #ifdef BOOT_FORTH
274 	res = bf_run(sp->text);
275 	if (res != VM_OUTOFTEXT) {
276 		sprintf(command_errbuf, "Error while including %s, in the line:\n%s", filename, sp->text);
277 		res = CMD_ERROR;
278 		break;
279 	} else
280 		res = CMD_OK;
281 #else
282 	/* print if not being quiet */
283 	if (!(sp->flags & SL_QUIET)) {
284 	    prompt();
285 	    printf("%s\n", sp->text);
286 	}
287 
288 	/* Parse the command */
289 	if (!parse(&argc, &argv, sp->text)) {
290 	    if ((argc > 0) && (perform(argc, argv) != 0)) {
291 		/* normal command */
292 		printf("%s: %s\n", argv[0], command_errmsg);
293 		if (!(sp->flags & SL_IGNOREERR)) {
294 		    res=CMD_ERROR;
295 		    break;
296 		}
297 	    }
298 	    free(argv);
299 	    argv = NULL;
300 	} else {
301 	    printf("%s line %d: parse error\n", filename, sp->line);
302 	    res=CMD_ERROR;
303 	    break;
304 	}
305 #endif
306     }
307 #ifndef BOOT_FORTH
308     if (argv != NULL)
309 	free(argv);
310 #else
311     bf_vm->sourceID.i = prevsrcid;
312 #endif
313     while(script != NULL) {
314 	se = script;
315 	script = script->next;
316 	free(se);
317     }
318     return(res);
319 }
320 
321 /*
322  * Emit the current prompt; use the same syntax as the parser
323  * for embedding environment variables.
324  */
325 static void
326 prompt(void)
327 {
328     char	*pr, *p, *cp, *ev;
329 
330     if ((cp = getenv("prompt")) == NULL)
331 	cp = ">";
332     pr = p = strdup(cp);
333 
334     while (*p != 0) {
335 	if ((*p == '$') && (*(p+1) == '{')) {
336 	    for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++)
337 		;
338 	    *cp = 0;
339 	    ev = getenv(p + 2);
340 
341 	    if (ev != NULL)
342 		printf("%s", ev);
343 	    p = cp + 1;
344 	    continue;
345 	}
346 	putchar(*p++);
347     }
348     putchar(' ');
349     free(pr);
350 }
351