1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Simple commandline interpreter, toplevel and misc.
29 */
30
31#include <stand.h>
32#include <string.h>
33#include "bootstrap.h"
34
35INTERP_DEFINE("simp");
36
37void
38interp_preinit(void)
39{
40}
41
42void
43interp_init(void)
44{
45
46	setenv("script.lang", "simple", 1);
47	/* Read our default configuration. */
48	interp_include("/boot/loader.rc");
49}
50
51int
52interp_run(const char *input)
53{
54	int			argc;
55	char			**argv;
56
57	if (parse(&argc, &argv, input)) {
58		printf("parse error\n");
59		return CMD_ERROR;
60	}
61
62	if (interp_builtin_cmd(argc, argv)) {
63		printf("%s: %s\n", argv[0], command_errmsg);
64		free(argv);
65		return CMD_ERROR;
66	}
67	free(argv);
68	return CMD_OK;
69}
70
71/*
72 * Header prepended to each line. The text immediately follows the header.
73 * We try to make this short in order to save memory -- the loader has
74 * limited memory available, and some of the forth files are very long.
75 */
76struct includeline
77{
78	struct includeline	*next;
79	int			flags;
80	int			line;
81#define SL_QUIET	(1<<0)
82#define SL_IGNOREERR	(1<<1)
83	char			text[0];
84};
85
86int
87interp_include(const char *filename)
88{
89	struct includeline	*script, *se, *sp;
90	char			input[256];			/* big enough? */
91	int			argc,res;
92	char			**argv, *cp;
93	int			fd, flags, line;
94
95	if (((fd = open(filename, O_RDONLY)) == -1)) {
96		snprintf(command_errbuf, sizeof(command_errbuf),
97		    "can't open '%s': %s", filename, strerror(errno));
98		return(CMD_ERROR);
99	}
100
101#ifdef LOADER_VERIEXEC
102	if (verify_file(fd, filename, 0, VE_GUESS, __func__) < 0) {
103		close(fd);
104		sprintf(command_errbuf,"can't verify '%s'", filename);
105		return(CMD_ERROR);
106	}
107#endif
108
109	/*
110	 * Read the script into memory.
111	 */
112	script = se = NULL;
113	line = 0;
114
115	while (fgetstr(input, sizeof(input), fd) >= 0) {
116		line++;
117		flags = 0;
118		/* Discard comments */
119		if (strncmp(input+strspn(input, " "), "\\", 1) == 0)
120			continue;
121		cp = input;
122		/* Echo? */
123		if (input[0] == '@') {
124			cp++;
125			flags |= SL_QUIET;
126		}
127		/* Error OK? */
128		if (input[0] == '-') {
129			cp++;
130			flags |= SL_IGNOREERR;
131		}
132
133		/* Allocate script line structure and copy line, flags */
134		if (*cp == '\0')
135			continue;	/* ignore empty line, save memory */
136		sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
137		/* On malloc failure (it happens!), free as much as possible and exit */
138		if (sp == NULL) {
139			while (script != NULL) {
140				se = script;
141				script = script->next;
142				free(se);
143			}
144			snprintf(command_errbuf, sizeof(command_errbuf),
145			    "file '%s' line %d: memory allocation failure - aborting",
146			    filename, line);
147			close(fd);
148			return (CMD_ERROR);
149		}
150		strcpy(sp->text, cp);
151		sp->flags = flags;
152		sp->line = line;
153		sp->next = NULL;
154
155		if (script == NULL) {
156			script = sp;
157		} else {
158			se->next = sp;
159		}
160		se = sp;
161	}
162	close(fd);
163
164	/*
165	 * Execute the script
166	 */
167	argv = NULL;
168	res = CMD_OK;
169	for (sp = script; sp != NULL; sp = sp->next) {
170
171		/* print if not being quiet */
172		if (!(sp->flags & SL_QUIET)) {
173			interp_emit_prompt();
174			printf("%s\n", sp->text);
175		}
176
177		/* Parse the command */
178		if (!parse(&argc, &argv, sp->text)) {
179			if ((argc > 0) && (interp_builtin_cmd(argc, argv) != 0)) {
180				/* normal command */
181				printf("%s: %s\n", argv[0], command_errmsg);
182				if (!(sp->flags & SL_IGNOREERR)) {
183					res=CMD_ERROR;
184					break;
185				}
186			}
187			free(argv);
188			argv = NULL;
189		} else {
190			printf("%s line %d: parse error\n", filename, sp->line);
191			res=CMD_ERROR;
192			break;
193		}
194	}
195	if (argv != NULL)
196		free(argv);
197
198	while (script != NULL) {
199		se = script;
200		script = script->next;
201		free(se);
202	}
203	return(res);
204}
205
206/*
207 * There's no graphics commands for the simple interpreter.
208 */
209void
210gfx_interp_ref(void)
211{
212}
213