svn commit: r326712 - in head/stand: . common

Warner Losh imp at FreeBSD.org
Fri Dec 8 19:57:20 UTC 2017


Author: imp
Date: Fri Dec  8 19:57:16 2017
New Revision: 326712
URL: https://svnweb.freebsd.org/changeset/base/326712

Log:
  Create interp class.
  
  Create an interp class. Use it to separate out the different types of
  interpreters: forth and simple with function pointers rather than
  via #ifdefs.
  
  Obtained from: lua boot loader project
      (via https://bsdimp@github.com/bsdimp/freebsd.git lua-bootloader)
  Sponsored by: Netflix

Added:
  head/stand/common/interp.h   (contents, props changed)
  head/stand/common/interp_simple.c   (contents, props changed)
Modified:
  head/stand/common/interp.c
  head/stand/common/interp_forth.c
  head/stand/loader.mk

Modified: head/stand/common/interp.c
==============================================================================
--- head/stand/common/interp.c	Fri Dec  8 19:57:11 2017	(r326711)
+++ head/stand/common/interp.c	Fri Dec  8 19:57:16 2017	(r326712)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 1998 Michael Smith <msmith at freebsd.org>
+ * Copyright (c) 2011 Wojciech A. Koszek <wkoszek at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,7 +24,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
@@ -36,112 +36,60 @@ __FBSDID("$FreeBSD$");
 #include <stand.h>
 #include <string.h>
 #include "bootstrap.h"
+#include "interp.h"
 
-#ifdef BOOT_FORTH
-#include "ficl.h"
-#define	RETURN(x)	stackPushINT(bf_vm->pStack,!x); return(x)
 
-extern FICL_VM *bf_vm;
+#define	MAXARGS	20			/* maximum number of arguments allowed */
+
+struct interp	*interp =
+#if defined(BOOT_FORTH)
+	&boot_interp_forth;
 #else
-#define	RETURN(x)	return(x)
+	&boot_interp_simple;
 #endif
 
-#define	MAXARGS	20			/* maximum number of arguments allowed */
-
-static void	prompt(void);
-
-#ifndef BOOT_FORTH
-static int	perform(int argc, char *argv[]);
-
-/*
- * Perform the command
- */
 int
-perform(int argc, char *argv[])
+default_load_config(void *ctx)
 {
-    int				result;
-    struct bootblk_command	**cmdp;
-    bootblk_cmd_t		*cmd;
-
-    if (argc < 1)
-	return(CMD_OK);
-
-    /* set return defaults; a successful command will override these */
-    command_errmsg = command_errbuf;
-    strcpy(command_errbuf, "no error message");
-    cmd = NULL;
-    result = CMD_ERROR;
-
-    /* search the command set for the command */
-    SET_FOREACH(cmdp, Xcommand_set) {
-	if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name))
-	    cmd = (*cmdp)->c_fn;
-    }
-    if (cmd != NULL) {
-	result = (cmd)(argc, argv);
-    } else {
-	command_errmsg = "unknown command";
-    }
-    RETURN(result);
+	return INTERP_INCL(interp, "/boot/loader.rc");
 }
-#endif	/* ! BOOT_FORTH */
 
 /*
  * Interactive mode
  */
 void
-interact(const char *rc)
+interact(const char * rc)
 {
-    static char	input[256];			/* big enough? */
-#ifndef BOOT_FORTH
-    int		argc;
-    char	**argv;
-#endif
+	static char	input[256];			/* big enough? */
 
-#ifdef BOOT_FORTH
-    bf_init((rc) ? "" : NULL);
-#endif
+	INTERP_INIT(interp);
 
-    if (rc == NULL) {
-	/* Read our default configuration. */
-	include("/boot/loader.rc");
-    } else if (*rc != '\0')
-	include(rc);
+	/*
+	 * Read our default configuration
+	 */
+	INTERP_LOAD_DEF_CONFIG(interp);
+	printf("\n");
+	/*
+	 * Before interacting, we might want to autoboot.
+	 */
+	autoboot_maybe();
 
-    printf("\n");
+	/*
+	 * Not autobooting, go manual
+	 */
+	printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");
+	if (getenv("prompt") == NULL)
+		setenv("prompt", "${interpret}", 1);
+	if (getenv("interpret") == NULL)
+		setenv("interpret", "OK", 1);
 
-    /*
-     * Before interacting, we might want to autoboot.
-     */
-    autoboot_maybe();
-    
-    /*
-     * Not autobooting, go manual
-     */
-    printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");
-    if (getenv("prompt") == NULL)
-	setenv("prompt", "${interpret}", 1);
-    if (getenv("interpret") == NULL)
-        setenv("interpret", "OK", 1);
-    
 
-    for (;;) {
-	input[0] = '\0';
-	prompt();
-	ngets(input, sizeof(input));
-#ifdef BOOT_FORTH
-	bf_vm->sourceID.i = 0;
-	bf_run(input);
-#else
-	if (!parse(&argc, &argv, input)) {
-	    if (perform(argc, argv))
-		printf("%s: %s\n", argv[0], command_errmsg);
-	    free(argv);
-	} else {
-	    printf("parse error\n");
+	for (;;) {
+		input[0] = '\0';
+		prompt();
+		ngets(input, sizeof(input));
+		INTERP_RUN(interp, input);
 	}
-#endif
-    }
 }
 
 /*
@@ -158,214 +106,87 @@ COMMAND_SET(include, "include", "read commands from a 
 static int
 command_include(int argc, char *argv[])
 {
-    int		i;
-    int		res;
-    char	**argvbuf;
+	int		i;
+	int		res;
+	char	**argvbuf;
 
-    /* 
-     * Since argv is static, we need to save it here.
-     */
-    argvbuf = (char**) calloc((u_int)argc, sizeof(char*));
-    for (i = 0; i < argc; i++)
-	argvbuf[i] = strdup(argv[i]);
+	/*
+	 * Since argv is static, we need to save it here.
+	 */
+	argvbuf = (char**) calloc((u_int)argc, sizeof(char*));
+	for (i = 0; i < argc; i++)
+		argvbuf[i] = strdup(argv[i]);
 
-    res=CMD_OK;
-    for (i = 1; (i < argc) && (res == CMD_OK); i++)
-	res = include(argvbuf[i]);
+	res=CMD_OK;
+	for (i = 1; (i < argc) && (res == CMD_OK); i++)
+		res = INTERP_INCL(interp, argvbuf[i]);
 
-    for (i = 0; i < argc; i++)
-	free(argvbuf[i]);
-    free(argvbuf);
+	for (i = 0; i < argc; i++)
+		free(argvbuf[i]);
+	free(argvbuf);
 
-    return(res);
+	return(res);
 }
 
 /*
- * Header prepended to each line. The text immediately follows the header.
- * We try to make this short in order to save memory -- the loader has
- * limited memory available, and some of the forth files are very long.
+ * Perform the command
  */
-struct includeline 
-{
-    struct includeline	*next;
-#ifndef BOOT_FORTH
-    int			flags;
-    int			line;
-#define SL_QUIET	(1<<0)
-#define SL_IGNOREERR	(1<<1)
-#endif
-    char		text[0];
-};
-
 int
-include(const char *filename)
+perform(int argc, char *argv[])
 {
-    struct includeline	*script, *se, *sp;
-    char		input[256];			/* big enough? */
-#ifdef BOOT_FORTH
-    int			res;
-    char		*cp;
-    int			prevsrcid, fd, line;
-#else
-    int			argc,res;
-    char		**argv, *cp;
-    int			fd, flags, line;
-#endif
+	int				result;
+	struct bootblk_command	**cmdp;
+	bootblk_cmd_t		*cmd;
 
-    if (((fd = open(filename, O_RDONLY)) == -1)) {
-	snprintf(command_errbuf, sizeof(command_errbuf),
-	    "can't open '%s': %s", filename, strerror(errno));
-	return(CMD_ERROR);
-    }
+	if (argc < 1)
+		return(CMD_OK);
 
-    /*
-     * Read the script into memory.
-     */
-    script = se = NULL;
-    line = 0;
-	
-    while (fgetstr(input, sizeof(input), fd) >= 0) {
-	line++;
-#ifdef BOOT_FORTH
-	cp = input;
-#else
-	flags = 0;
-	/* Discard comments */
-	if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
-	    continue;
-	cp = input;
-	/* Echo? */
-	if (input[0] == '@') {
-	    cp++;
-	    flags |= SL_QUIET;
+	/* set return defaults; a successful command will override these */
+	command_errmsg = command_errbuf;
+	strcpy(command_errbuf, "no error message");
+	cmd = NULL;
+	result = CMD_ERROR;
+
+	/* search the command set for the command */
+	SET_FOREACH(cmdp, Xcommand_set) {
+		if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name))
+			cmd = (*cmdp)->c_fn;
 	}
-	/* Error OK? */
-	if (input[0] == '-') {
-	    cp++;
-	    flags |= SL_IGNOREERR;
-	}
-#endif
-	/* Allocate script line structure and copy line, flags */
-	if (*cp == '\0')
-		continue;	/* ignore empty line, save memory */
-	sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
-	/* On malloc failure (it happens!), free as much as possible and exit */
-	if (sp == NULL) {
-		while (script != NULL) {
-			se = script;
-			script = script->next;
-			free(se);
-		}
-		snprintf(command_errbuf, sizeof(command_errbuf),
-		    "file '%s' line %d: memory allocation failure - aborting",
-		    filename, line);
-		return (CMD_ERROR);
-	}
-	strcpy(sp->text, cp);
-#ifndef BOOT_FORTH
-	sp->flags = flags;
-	sp->line = line;
-#endif
-	sp->next = NULL;
-	    
-	if (script == NULL) {
-	    script = sp;
+	if (cmd != NULL) {
+		result = (cmd)(argc, argv);
 	} else {
-	    se->next = sp;
+		command_errmsg = "unknown command";
 	}
-	se = sp;
-    }
-    close(fd);
-    
-    /*
-     * Execute the script
-     */
-#ifndef BOOT_FORTH
-    argv = NULL;
-#else
-    prevsrcid = bf_vm->sourceID.i;
-    bf_vm->sourceID.i = fd;
-#endif
-    res = CMD_OK;
-    for (sp = script; sp != NULL; sp = sp->next) {
-	
-#ifdef BOOT_FORTH
-	res = bf_run(sp->text);
-	if (res != VM_OUTOFTEXT) {
-		snprintf(command_errbuf, sizeof(command_errbuf),
-		    "Error while including %s, in the line:\n%s",
-		    filename, sp->text);
-		res = CMD_ERROR;
-		break;
-	} else
-		res = CMD_OK;
-#else
-	/* print if not being quiet */
-	if (!(sp->flags & SL_QUIET)) {
-	    prompt();
-	    printf("%s\n", sp->text);
-	}
-
-	/* Parse the command */
-	if (!parse(&argc, &argv, sp->text)) {
-	    if ((argc > 0) && (perform(argc, argv) != 0)) {
-		/* normal command */
-		printf("%s: %s\n", argv[0], command_errmsg);
-		if (!(sp->flags & SL_IGNOREERR)) {
-		    res=CMD_ERROR;
-		    break;
-		}
-	    }
-	    free(argv);
-	    argv = NULL;
-	} else {
-	    printf("%s line %d: parse error\n", filename, sp->line);
-	    res=CMD_ERROR;
-	    break;
-	}
-#endif
-    }
-#ifndef BOOT_FORTH
-    if (argv != NULL)
-	free(argv);
-#else
-    bf_vm->sourceID.i = prevsrcid;
-#endif
-    while(script != NULL) {
-	se = script;
-	script = script->next;
-	free(se);
-    }
-    return(res);
+	return result;
 }
 
 /*
  * Emit the current prompt; use the same syntax as the parser
  * for embedding environment variables.
  */
-static void
-prompt(void) 
+void
+prompt(void)
 {
-    char	*pr, *p, *cp, *ev;
-    
-    if ((cp = getenv("prompt")) == NULL)
-	cp = ">";
-    pr = p = strdup(cp);
+	char	*pr, *p, *cp, *ev;
 
-    while (*p != 0) {
-	if ((*p == '$') && (*(p+1) == '{')) {
-	    for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++)
-		;
-	    *cp = 0;
-	    ev = getenv(p + 2);
-	    
-	    if (ev != NULL)
-		printf("%s", ev);
-	    p = cp + 1;
-	    continue;
+	if ((cp = getenv("prompt")) == NULL)
+		cp = ">";
+	pr = p = strdup(cp);
+
+	while (*p != 0) {
+		if ((*p == '$') && (*(p+1) == '{')) {
+			for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++)
+				;
+			*cp = 0;
+			ev = getenv(p + 2);
+
+			if (ev != NULL)
+				printf("%s", ev);
+			p = cp + 1;
+			continue;
+		}
+		putchar(*p++);
 	}
-	putchar(*p++);
-    }
-    putchar(' ');
-    free(pr);
+	putchar(' ');
+	free(pr);
 }

Added: head/stand/common/interp.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/stand/common/interp.h	Fri Dec  8 19:57:16 2017	(r326712)
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2011 Wojciech A. Koszek <wkoszek at FreeBSD.org>
+ * Copyright (c) 2014 Pedro Souza <pedrosouza at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+typedef void	interp_init_t(void *ctx);
+typedef int	interp_run_t(void *ctx, const char *input);
+typedef int	interp_incl_t(void *ctx, const char *filename);
+typedef int	interp_load_def_t(void *ctx);		// load default configuration files
+
+struct interp {
+	interp_init_t	*init;
+	interp_run_t	*run;
+	interp_incl_t	*incl;
+	interp_load_def_t *load_configs;
+	void		*context;
+};
+
+#define	INTERP_INIT(i)		do {			\
+	if (((i) != NULL) && ((i)->init != NULL)) {	\
+		((i)->init((i)->context));		\
+	}						\
+} while (0)
+
+#define	INTERP_RUN(i, input)	\
+	((i)->run(((i)->context), input))
+
+#define	INTERP_INCL(i, filename)	\
+	((i)->incl(((i)->context), filename))
+
+#define	INTERP_LOAD_DEF_CONFIG(i)	\
+	((i)->load_configs(((i)->context)))
+
+
+
+extern struct interp	boot_interp_simple;
+extern struct interp	boot_interp_forth;
+extern struct interp    boot_interp_lua;
+
+
+extern struct interp	*interp;
+
+int perform(int argc, char *argv[]);
+void prompt(void);
+
+/*
+ * Default config loader for interp_simple & intep_forth
+ * Use it if your interpreter does not use a custom config
+ * file.
+ *
+ * Calls interp->include with 'loader.rc' or 'boot.conf'
+ */
+int default_load_config(void *ctx);
+
+struct includeline
+{
+    struct includeline	*next;
+    int			flags;
+    int			line;
+#define SL_QUIET	(1<<0)
+#define SL_IGNOREERR	(1<<1)
+    char		text[0];
+};

Modified: head/stand/common/interp_forth.c
==============================================================================
--- head/stand/common/interp_forth.c	Fri Dec  8 19:57:11 2017	(r326711)
+++ head/stand/common/interp_forth.c	Fri Dec  8 19:57:16 2017	(r326712)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 1998 Michael Smith <msmith at freebsd.org>
+ * Copyright (c) 2011 Wojciech A. Koszek <wkoszek at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <stand.h>
 #include "bootstrap.h"
 #include "ficl.h"
+#include "interp.h"
 
 extern unsigned bootprog_rev;
 
@@ -60,9 +62,14 @@ extern unsigned bootprog_rev;
 /*
  * BootForth   Interface to Ficl Forth interpreter.
  */
+struct interp_forth_softc {
+	FICL_SYSTEM *bf_sys;
+	FICL_VM	*bf_vm;
+	FICL_WORD *pInterp;
+};
+struct interp_forth_softc	forth_softc = { NULL, NULL, NULL };
 
-FICL_SYSTEM *bf_sys;
-FICL_VM	*bf_vm;
+#define	RETURN(x)	stackPushINT(bf_vm->pStack,!x); return(x)
 
 /*
  * Shim for taking commands from BF and passing them out to 'standard'
@@ -71,91 +78,93 @@ FICL_VM	*bf_vm;
 static void
 bf_command(FICL_VM *vm)
 {
-    char			*name, *line, *tail, *cp;
-    size_t			len;
-    struct bootblk_command	**cmdp;
-    bootblk_cmd_t		*cmd;
-    int				nstrings, i;
-    int				argc, result;
-    char			**argv;
+	char			*name, *line, *tail, *cp;
+	size_t			len;
+	struct bootblk_command	**cmdp;
+	bootblk_cmd_t		*cmd;
+	int			nstrings, i;
+	int			argc, result;
+	char			**argv;
 
-    /* Get the name of the current word */
-    name = vm->runningWord->name;
-    
-    /* Find our command structure */
-    cmd = NULL;
-    SET_FOREACH(cmdp, Xcommand_set) {
-	if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name))
-	    cmd = (*cmdp)->c_fn;
-    }
-    if (cmd == NULL)
-	panic("callout for unknown command '%s'", name);
-   
-    /* Check whether we have been compiled or are being interpreted */
-    if (stackPopINT(vm->pStack)) {
-	/*
-	 * Get parameters from stack, in the format:
-	 * an un ... a2 u2 a1 u1 n --
-	 * Where n is the number of strings, a/u are pairs of
-	 * address/size for strings, and they will be concatenated
-	 * in LIFO order.
-	 */
-	nstrings = stackPopINT(vm->pStack);
-	for (i = 0, len = 0; i < nstrings; i++)
-	    len += stackFetch(vm->pStack, i * 2).i + 1;
-	line = malloc(strlen(name) + len + 1);
-	strcpy(line, name);
+	/* Get the name of the current word */
+	name = vm->runningWord->name;
 
-	if (nstrings)
-	    for (i = 0; i < nstrings; i++) {
-		len = stackPopINT(vm->pStack);
-		cp = stackPopPtr(vm->pStack);
-		strcat(line, " ");
-		strncat(line, cp, len);
-	    }
-    } else {
-	/* Get remainder of invocation */
-	tail = vmGetInBuf(vm);
-	for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++)
-	    ;
-    
-	line = malloc(strlen(name) + len + 2);
-	strcpy(line, name);
-	if (len > 0) {
-	    strcat(line, " ");
-	    strncat(line, tail, len);
-	    vmUpdateTib(vm, tail + len);
+	/* Find our command structure */
+	cmd = NULL;
+	SET_FOREACH(cmdp, Xcommand_set) {
+		if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name))
+			cmd = (*cmdp)->c_fn;
 	}
-    }
-    DEBUG("cmd '%s'", line);
-    
-    command_errmsg = command_errbuf;
-    command_errbuf[0] = 0;
-    if (!parse(&argc, &argv, line)) {
-	result = (cmd)(argc, argv);
-	free(argv);
-    } else {
-	result=BF_PARSE;
-    }
+	if (cmd == NULL)
+		panic("callout for unknown command '%s'", name);
 
-    switch (result) {
-    case CMD_CRIT:
-	printf("%s\n", command_errmsg);
-	break;
-    case CMD_FATAL:
-	panic("%s\n", command_errmsg);
-    }
+	/* Check whether we have been compiled or are being interpreted */
+	if (stackPopINT(vm->pStack)) {
+		/*
+		* Get parameters from stack, in the format:
+		* an un ... a2 u2 a1 u1 n --
+		* Where n is the number of strings, a/u are pairs of
+		* address/size for strings, and they will be concatenated
+		* in LIFO order.
+		*/
+		nstrings = stackPopINT(vm->pStack);
+		for (i = 0, len = 0; i < nstrings; i++)
+			len += stackFetch(vm->pStack, i * 2).i + 1;
+		line = malloc(strlen(name) + len + 1);
+		strcpy(line, name);
 
-    free(line);
-    /*
-     * If there was error during nested ficlExec(), we may no longer have
-     * valid environment to return.  Throw all exceptions from here.
-     */
-    if (result != CMD_OK)
-	vmThrow(vm, result);
+		if (nstrings)
+			for (i = 0; i < nstrings; i++) {
+				len = stackPopINT(vm->pStack);
+				cp = stackPopPtr(vm->pStack);
+				strcat(line, " ");
+				strncat(line, cp, len);
+			}
+	} else {
+		/* Get remainder of invocation */
+		tail = vmGetInBuf(vm);
+		for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++)
+			;
 
-    /* This is going to be thrown!!! */
-    stackPushINT(vm->pStack,result);
+		line = malloc(strlen(name) + len + 2);
+		strcpy(line, name);
+		if (len > 0) {
+			strcat(line, " ");
+			strncat(line, tail, len);
+			vmUpdateTib(vm, tail + len);
+		}
+	}
+	DEBUG("cmd '%s'", line);
+
+	command_errmsg = command_errbuf;
+	command_errbuf[0] = 0;
+	if (!parse(&argc, &argv, line)) {
+		result = (cmd)(argc, argv);
+		free(argv);
+	} else {
+		result=BF_PARSE;
+	}
+
+	/* XXX Not sure about the rest of this -- imp */
+
+	switch (result) {
+	case CMD_CRIT:
+		printf("%s\n", command_errmsg);
+		break;
+	case CMD_FATAL:
+		panic("%s\n", command_errmsg);
+	}
+
+	free(line);
+	/*
+	 * If there was error during nested ficlExec(), we may no longer have
+	 * valid environment to return.  Throw all exceptions from here.
+	 */
+	if (result != CMD_OK)
+		vmThrow(vm, result);
+
+	/* This is going to be thrown!!! */
+	stackPushINT(vm->pStack,result);
 }
 
 /*
@@ -249,16 +258,23 @@ bf_command(FICL_VM *vm)
 /*
  * Initialise the Forth interpreter, create all our commands as words.
  */
-void
-bf_init(const char *rc)
+static void
+interp_forth_init(void *ctx)
 {
+    struct interp_forth_softc   *softc;
     struct bootblk_command	**cmdp;
     char create_buf[41];	/* 31 characters-long builtins */
-    int fd;
+    FICL_SYSTEM *bf_sys;
+    FICL_VM	*bf_vm;
 
-    bf_sys = ficlInitSystem(BF_DICTSIZE);
-    bf_vm = ficlNewVM(bf_sys);
+    softc = ctx;
 
+    assert((softc->bf_sys == NULL) && (softc->bf_vm == NULL) &&
+	(softc->pInterp == NULL));	/* No Forth context at this stage */
+
+    bf_sys = softc->bf_sys = ficlInitSystem(BF_DICTSIZE);
+    bf_vm = softc->bf_vm = ficlNewVM(bf_sys);
+
     /* Put all private definitions in a "builtins" vocabulary */
     ficlExec(bf_vm, "vocabulary builtins also builtins definitions");
 
@@ -279,28 +295,35 @@ bf_init(const char *rc)
     ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version);
     ficlSetEnv(bf_sys, "loader_version", bootprog_rev);
 
+#if 0 /* XXX lost functionality -- imp */
     /* try to load and run init file if present */
     if (rc == NULL)
 	rc = "/boot/boot.4th";
     if (*rc != '\0') {
+        int fd;
+
 	fd = open(rc, O_RDONLY);
 	if (fd != -1) {
 	    (void)ficlExecFD(bf_vm, fd);
 	    close(fd);
 	}
     }
+#endif
 }
 
 /*
  * Feed a line of user input to the Forth interpreter
  */
-int
-bf_run(char *line)
+static int
+interp_forth_run(void *ctx, const char *line)
 {
+    struct interp_forth_softc *softc;
     int		result;
 
-    result = ficlExec(bf_vm, line);
+    softc = ctx;
 
+    result = ficlExec(softc->bf_vm, (char *)line);
+
     DEBUG("ficlExec '%s' = %d", line, result);
     switch (result) {
     case VM_OUTOFTEXT:
@@ -326,7 +349,32 @@ bf_run(char *line)
     
     if (result == VM_USEREXIT)
 	panic("interpreter exit");
-    setenv("interpret", bf_vm->state ? "" : "OK", 1);
+    setenv("interpret", softc->bf_vm->state ? "" : "OK", 1);
 
     return (result);
 }
+
+static int
+interp_forth_incl(void *ctx, const char *filename)
+{
+	struct interp_forth_softc *softc;
+	int	fd;
+
+	softc = ctx;
+
+	fd = open(filename, O_RDONLY);
+	if (fd == -1) {
+		printf("can't open %s\n", filename);
+		return (CMD_ERROR);
+	}
+	return (ficlExecFD(softc->bf_vm, fd));
+}
+
+
+struct interp boot_interp_forth = {
+	.init = interp_forth_init,
+	.run = interp_forth_run,
+	.incl = interp_forth_incl,
+	.load_configs = default_load_config,
+	.context = &forth_softc
+};

Added: head/stand/common/interp_simple.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/stand/common/interp_simple.c	Fri Dec  8 19:57:16 2017	(r326712)
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2011 Wojciech A. Koszek <wkoszek at FreeBSD.org>
+ * Copyright (c) 2014 Pedro Souza <pedrosouza at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#include "bootstrap.h"
+#include "interp.h"
+
+struct interp_simple_softc {
+	int	dummy;
+};
+
+static void
+interp_simple_init(void *ctx)
+{
+
+	(void)ctx; /* Silent the compiler */
+}
+
+static int
+interp_simple_run(void *ctx, const char *input)
+{
+	struct interp_simple_softc *softc;
+	int argc;
+	char **argv;
+
+	softc = ctx;
+	(void)softc;	/* Currently unused */
+
+	if (!parse(&argc, &argv, input)) {
+		if (perform(argc, argv))
+			printf("%s: %s\n", argv[0], command_errmsg);
+		free(argv);
+	} else {
+		printf("parse error\n");
+	}
+	return 0;
+}
+
+static int
+interp_simple_incl(void *ctx, const char *filename)
+{
+	struct includeline	*script, *se, *sp;
+	char		input[256];			/* big enough? */
+	int			argc,res;
+	char		**argv, *cp;
+	int			fd, flags, line;
+
+	(void)ctx; /* Silent the compiler */
+
+	if (((fd = open(filename, O_RDONLY)) == -1)) {
+		sprintf(command_errbuf,"can't open '%s': %s\n", filename, strerror(errno));
+		return(CMD_ERROR);
+	}
+
+	/*
+	 * Read the script into memory.
+	 */
+	script = se = NULL;
+	line = 0;
+
+	while (fgetstr(input, sizeof(input), fd) >= 0) {
+		line++;
+		flags = 0;
+		/* Discard comments */
+		if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
+			continue;
+		cp = input;
+		/* Echo? */
+		if (input[0] == '@') {
+			cp++;
+			flags |= SL_QUIET;
+		}
+		/* Error OK? */
+		if (input[0] == '-') {
+			cp++;
+			flags |= SL_IGNOREERR;
+		}
+		/* Allocate script line structure and copy line, flags */
+		if (*cp == '\0')
+			continue;	/* ignore empty line, save memory */
+		sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
+		/* On malloc failure (it happens!), free as much as possible and exit */
+		if (sp == NULL) {
+			while (script != NULL) {
+				se = script;
+				script = script->next;
+				free(se);
+			}
+			sprintf(command_errbuf, "file '%s' line %d: memory allocation "
+			    "failure - aborting\n", filename, line);
+			return (CMD_ERROR);
+		}
+		strcpy(sp->text, cp);
+		sp->flags = flags;
+		sp->line = line;
+		sp->next = NULL;
+
+		if (script == NULL) {
+			script = sp;
+		} else {
+			se->next = sp;
+		}
+		se = sp;
+	}
+	close(fd);
+
+	/*
+	 * Execute the script
+	 */
+	argv = NULL;
+	res = CMD_OK;
+	for (sp = script; sp != NULL; sp = sp->next) {
+
+		/* print if not being quiet */
+		if (!(sp->flags & SL_QUIET)) {
+			prompt();
+			printf("%s\n", sp->text);
+		}
+
+		/* Parse the command */
+		if (!parse(&argc, &argv, sp->text)) {
+			if ((argc > 0) && (perform(argc, argv) != 0)) {
+				/* normal command */
+				printf("%s: %s\n", argv[0], command_errmsg);
+				if (!(sp->flags & SL_IGNOREERR)) {
+					res=CMD_ERROR;
+					break;
+				}
+			}
+			free(argv);
+			argv = NULL;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list