1 /* $NetBSD: interp.c,v 1.3 2006/07/02 17:28:11 cherry Exp $ */
4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
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 $"); */
33 * Simple commandline interpreter, toplevel and misc.
35 * XXX may be obsoleted by BootFORTH or some other, better, interpreter.
38 #include <lib/libsa/stand.h>
39 #include <lib/libsa/loadfile.h>
41 #include "bootstrap.h"
45 #define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x)
47 extern FICL_VM
*bf_vm
;
49 #define RETURN(x) return(x)
52 #define MAXARGS 20 /* maximum number of arguments allowed */
54 static void prompt(void);
57 static int perform(int argc
, char *argv
[]);
63 perform(int argc
, char *argv
[])
66 struct bootblk_command
*cmdp
;
74 /* set return defaults; a successful command will override these */
75 command_errmsg
= command_errbuf
;
76 strcpy(command_errbuf
, "no error message");
80 /* search the command set for the command */
81 for (i
= 0, cmdp
= commands
; (cmdp
->c_name
!= NULL
) && (cmdp
->c_desc
!= NULL
); i
++, cmdp
= commands
+ i
) {
82 if ((cmdp
->c_name
!= NULL
) && !strcmp(argv
[0], cmdp
->c_name
))
86 result
= (cmd
)(argc
, argv
);
88 command_errmsg
= "unknown command";
92 #endif /* ! BOOT_FORTH */
100 char input
[256]; /* big enough? */
111 * Read our default configuration
113 if(include("/boot/loader.rc")!=CMD_OK
)
114 include("/boot/boot.conf");
118 * XXX: Before interacting, we might want to autoboot.
123 * Not autobooting, go manual
125 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");
126 if (getenv("prompt") == NULL
)
127 setenv("prompt", "${interpret}", 1);
128 if (getenv("interpret") == NULL
)
129 setenv("interpret", "OK", 1);
135 ngets(input
, sizeof(input
));
137 bf_vm
->sourceID
.i
= 0;
140 if (!parse(&argc
, &argv
, input
)) {
141 if (perform(argc
, argv
))
142 printf("%s: %s\n", argv
[0], command_errmsg
);
145 printf("parse error\n");
152 * Read commands from a file, then execute them.
154 * We store the commands in memory and close the source file so that the media
155 * holding it can safely go away while we are executing.
157 * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so
158 * that the script won't stop if they fail).
162 command_include(int argc
, char *argv
[])
169 * Since argv is static, we need to save it here.
171 argvbuf
= (char**) calloc((u_int
)argc
, sizeof(char*));
172 for (i
= 0; i
< argc
; i
++)
173 argvbuf
[i
] = strdup(argv
[i
]);
176 for (i
= 1; (i
< argc
) && (res
== CMD_OK
); i
++)
177 res
= include(argvbuf
[i
]);
179 for (i
= 0; i
< argc
; i
++)
191 #define SL_QUIET (1<<0)
192 #define SL_IGNOREERR (1<<1)
193 struct includeline
*next
;
197 include(const char *filename
)
199 struct includeline
*script
, *se
, *sp
;
200 char input
[256]; /* big enough? */
204 int prevsrcid
, fd
, line
;
211 if (((fd
= open(filename
, O_RDONLY
)) == -1)) {
212 sprintf(command_errbuf
,"can't open '%s': %s\n", filename
, strerror(errno
));
217 * Read the script into memory.
222 while (fgetstr(input
, sizeof(input
), fd
) >= 0) {
228 /* Discard comments */
229 if (strncmp(input
+strspn(input
, " "), "\\ ", 2) == 0)
233 if (input
[0] == '@') {
238 if (input
[0] == '-') {
240 flags
|= SL_IGNOREERR
;
243 /* Allocate script line structure and copy line, flags */
244 sp
= alloc(sizeof(struct includeline
) + strlen(cp
) + 1);
245 sp
->text
= (char *)sp
+ sizeof(struct includeline
);
246 strcpy(sp
->text
, cp
);
253 if (script
== NULL
) {
268 prevsrcid
= bf_vm
->sourceID
.i
;
269 bf_vm
->sourceID
.i
= fd
;
272 for (sp
= script
; sp
!= NULL
; sp
= sp
->next
) {
275 res
= bf_run(sp
->text
);
276 if (res
!= VM_OUTOFTEXT
) {
277 sprintf(command_errbuf
, "Error while including %s, in the line:\n%s", filename
, sp
->text
);
283 /* print if not being quiet */
284 if (!(sp
->flags
& SL_QUIET
)) {
286 printf("%s\n", sp
->text
);
289 /* Parse the command */
290 if (!parse(&argc
, &argv
, sp
->text
)) {
291 if ((argc
> 0) && (perform(argc
, argv
) != 0)) {
293 printf("%s: %s\n", argv
[0], command_errmsg
);
294 if (!(sp
->flags
& SL_IGNOREERR
)) {
302 printf("%s line %d: parse error\n", filename
, sp
->line
);
312 bf_vm
->sourceID
.i
= prevsrcid
;
314 while(script
!= NULL
) {
316 script
= script
->next
;
323 * Emit the current prompt; use the same syntax as the parser
324 * for embedding environment variables.
329 char *pr
, *p
, *cp
, *ev
;
331 if ((cp
= getenv("prompt")) == NULL
)
336 if ((*p
== '$') && (*(p
+1) == '{')) {
337 for (cp
= p
+ 2; (*cp
!= 0) && (*cp
!= '}'); cp
++)