Index: head/stand/common/interp.c =================================================================== --- head/stand/common/interp.c (revision 328998) +++ head/stand/common/interp.c (revision 328999) @@ -1,141 +1,141 @@ /*- * Copyright (c) 1998 Michael Smith * 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 __FBSDID("$FreeBSD$"); /* * Simple commandline interpreter, toplevel and misc. * * XXX may be obsoleted by BootFORTH or some other, better, interpreter. */ #include #include #include "bootstrap.h" #define MAXARGS 20 /* maximum number of arguments allowed */ /* * Interactive mode */ void interact(void) { - static char input[256]; /* big enough? */ + static char input[256]; /* big enough? */ - interp_init(); + interp_init(); - printf("\n"); + printf("\n"); - /* - * Before interacting, we might want to autoboot. - */ - autoboot_maybe(); + /* + * 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); + /* + * 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'; - interp_emit_prompt(); - ngets(input, sizeof(input)); - interp_run(input); - } + for (;;) { + input[0] = '\0'; + interp_emit_prompt(); + ngets(input, sizeof(input)); + interp_run(input); + } } /* * Read commands from a file, then execute them. * * We store the commands in memory and close the source file so that the media * holding it can safely go away while we are executing. * * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so * that the script won't stop if they fail). */ COMMAND_SET(include, "include", "read commands from a file", command_include); 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 = interp_include(argvbuf[i]); + res=CMD_OK; + for (i = 1; (i < argc) && (res == CMD_OK); i++) + res = interp_include(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); } /* * Emit the current prompt; use the same syntax as the parser * for embedding environment variables. Does not accept input. */ void interp_emit_prompt(void) { - char *pr, *p, *cp, *ev; + char *pr, *p, *cp, *ev; - if ((cp = getenv("prompt")) == NULL) - cp = ">"; - pr = p = strdup(cp); + 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); + 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 (ev != NULL) + printf("%s", ev); + p = cp + 1; + continue; + } + putchar(*p++); } - putchar(*p++); - } - putchar(' '); - free(pr); + putchar(' '); + free(pr); } Index: head/stand/common/interp_forth.c =================================================================== --- head/stand/common/interp_forth.c (revision 328998) +++ head/stand/common/interp_forth.c (revision 328999) @@ -1,443 +1,442 @@ /*- * Copyright (c) 1998 Michael Smith * 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 __FBSDID("$FreeBSD$"); #include /* to pick up __FreeBSD_version */ #include #include #include "bootstrap.h" #include "ficl.h" extern unsigned bootprog_rev; /* #define BFORTH_DEBUG */ #ifdef BFORTH_DEBUG #define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else #define DEBUG(fmt, args...) #endif /* * Eventually, all builtin commands throw codes must be defined * elsewhere, possibly bootstrap.h. For now, just this code, used * just in this file, it is getting defined. */ #define BF_PARSE 100 /* * FreeBSD loader default dictionary cells */ #ifndef BF_DICTSIZE #define BF_DICTSIZE 10000 #endif /* * BootForth Interface to Ficl Forth interpreter. */ FICL_SYSTEM *bf_sys; FICL_VM *bf_vm; /* * Shim for taking commands from BF and passing them out to 'standard' * argv/argc command functions. */ 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; + /* 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); + /* 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); + /* 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); - 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++) - ; + 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); + 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); + 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; - } + command_errmsg = command_errbuf; + command_errbuf[0] = 0; + if (!parse(&argc, &argv, line)) { + result = (cmd)(argc, argv); + free(argv); + } else { + result=BF_PARSE; + } - switch (result) { - case CMD_CRIT: - printf("%s\n", command_errmsg); - break; - case CMD_FATAL: - panic("%s\n", command_errmsg); - } + 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); + 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); + /* This is going to be thrown!!! */ + stackPushINT(vm->pStack,result); } /* * Replace a word definition (a builtin command) with another * one that: * * - Throw error results instead of returning them on the stack * - Pass a flag indicating whether the word was compiled or is * being interpreted. * * There is one major problem with builtins that cannot be overcome * in anyway, except by outlawing it. We want builtins to behave * differently depending on whether they have been compiled or they * are being interpreted. Notice that this is *not* the interpreter's * current state. For example: * * : example ls ; immediate * : problem example ; \ "ls" gets executed while compiling * example \ "ls" gets executed while interpreting * * Notice that, though the current state is different in the two * invocations of "example", in both cases "ls" has been * *compiled in*, which is what we really want. * * The problem arises when you tick the builtin. For example: * * : example-1 ['] ls postpone literal ; immediate * : example-2 example-1 execute ; immediate * : problem example-2 ; * example-2 * * We have no way, when we get EXECUTEd, of knowing what our behavior * should be. Thus, our only alternative is to "outlaw" this. See RFI * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related * problem, concerning compile semantics. * * The problem is compounded by the fact that "' builtin CATCH" is valid * and desirable. The only solution is to create an intermediary word. * For example: * * : my-ls ls ; * : example ['] my-ls catch ; * * So, with the below implementation, here is a summary of the behavior * of builtins: * * ls -l \ "interpret" behavior, ie, * \ takes parameters from TIB * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie, * \ takes parameters from the stack * : ex-2 ['] ls catch ; immediate \ undefined behavior * : ex-3 ['] ls catch ; \ undefined behavior * ex-2 ex-3 \ "interpret" behavior, * \ catch works * : ex-4 ex-2 ; \ "compile" behavior, * \ catch does not work * : ex-5 ex-3 ; immediate \ same as ex-2 * : ex-6 ex-3 ; \ same as ex-3 * : ex-7 ['] ex-1 catch ; \ "compile" behavior, * \ catch works * : ex-8 postpone ls ; immediate \ same as ex-2 * : ex-9 postpone ls ; \ same as ex-3 * * As the definition below is particularly tricky, and it's side effects * must be well understood by those playing with it, I'll be heavy on * the comments. * * (if you edit this definition, pay attention to trailing spaces after * each word -- I warned you! :-) ) */ -#define BUILTIN_CONSTRUCTOR \ -": builtin: " \ - ">in @ " /* save the tib index pointer */ \ - "' " /* get next word's xt */ \ - "swap >in ! " /* point again to next word */ \ - "create " /* create a new definition of the next word */ \ - ", " /* save previous definition's xt */ \ - "immediate " /* make the new definition an immediate word */ \ - \ - "does> " /* Now, the *new* definition will: */ \ - "state @ if " /* if in compiling state: */ \ - "1 postpone literal " /* pass 1 flag to indicate compile */ \ - "@ compile, " /* compile in previous definition */ \ - "postpone throw " /* throw stack-returned result */ \ - "else " /* if in interpreting state: */ \ - "0 swap " /* pass 0 flag to indicate interpret */ \ - "@ execute " /* call previous definition */ \ - "throw " /* throw stack-returned result */ \ - "then ; " +#define BUILTIN_CONSTRUCTOR \ + ": builtin: " \ + ">in @ " /* save the tib index pointer */ \ + "' " /* get next word's xt */ \ + "swap >in ! " /* point again to next word */ \ + "create " /* create a new definition of the next word */ \ + ", " /* save previous definition's xt */ \ + "immediate " /* make the new definition an immediate word */ \ + \ + "does> " /* Now, the *new* definition will: */ \ + "state @ if " /* if in compiling state: */ \ + "1 postpone literal " /* pass 1 flag to indicate compile */ \ + "@ compile, " /* compile in previous definition */ \ + "postpone throw " /* throw stack-returned result */ \ + "else " /* if in interpreting state: */ \ + "0 swap " /* pass 0 flag to indicate interpret */ \ + "@ execute " /* call previous definition */ \ + "throw " /* throw stack-returned result */ \ + "then ; " /* * Initialise the Forth interpreter, create all our commands as words. */ void bf_init(void) { - struct bootblk_command **cmdp; - char create_buf[41]; /* 31 characters-long builtins */ - int fd; + struct bootblk_command **cmdp; + char create_buf[41]; /* 31 characters-long builtins */ + int fd; - bf_sys = ficlInitSystem(BF_DICTSIZE); - bf_vm = ficlNewVM(bf_sys); + bf_sys = ficlInitSystem(BF_DICTSIZE); + bf_vm = ficlNewVM(bf_sys); - /* Put all private definitions in a "builtins" vocabulary */ - ficlExec(bf_vm, "vocabulary builtins also builtins definitions"); + /* Put all private definitions in a "builtins" vocabulary */ + ficlExec(bf_vm, "vocabulary builtins also builtins definitions"); - /* Builtin constructor word */ - ficlExec(bf_vm, BUILTIN_CONSTRUCTOR); + /* Builtin constructor word */ + ficlExec(bf_vm, BUILTIN_CONSTRUCTOR); - /* make all commands appear as Forth words */ - SET_FOREACH(cmdp, Xcommand_set) { - ficlBuild(bf_sys, (char *)(*cmdp)->c_name, bf_command, FW_DEFAULT); - ficlExec(bf_vm, "forth definitions builtins"); - sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); - ficlExec(bf_vm, create_buf); - ficlExec(bf_vm, "builtins definitions"); - } - ficlExec(bf_vm, "only forth definitions"); + /* make all commands appear as Forth words */ + SET_FOREACH(cmdp, Xcommand_set) { + ficlBuild(bf_sys, (char *)(*cmdp)->c_name, bf_command, FW_DEFAULT); + ficlExec(bf_vm, "forth definitions builtins"); + sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); + ficlExec(bf_vm, create_buf); + ficlExec(bf_vm, "builtins definitions"); + } + ficlExec(bf_vm, "only forth definitions"); - /* Export some version numbers so that code can detect the loader/host version */ - ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version); - ficlSetEnv(bf_sys, "loader_version", bootprog_rev); + /* Export some version numbers so that code can detect the loader/host version */ + ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version); + ficlSetEnv(bf_sys, "loader_version", bootprog_rev); - /* try to load and run init file if present */ - if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { - (void)ficlExecFD(bf_vm, fd); - close(fd); - } + /* try to load and run init file if present */ + if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { + (void)ficlExecFD(bf_vm, fd); + close(fd); + } } /* * Feed a line of user input to the Forth interpreter */ static int bf_run(const char *line) { - int result; + int result; - /* - * ficl would require extensive changes to accept a const char * - * interface. Instead, cast it away here and hope for the best. - * We know at the present time the caller for us in the boot - * forth loader can tolerate the string being modified because - * the string is passed in here and then not touched again. - */ - result = ficlExec(bf_vm, __DECONST(char *, line)); + /* + * ficl would require extensive changes to accept a const char * + * interface. Instead, cast it away here and hope for the best. + * We know at the present time the caller for us in the boot + * forth loader can tolerate the string being modified because + * the string is passed in here and then not touched again. + */ + result = ficlExec(bf_vm, __DECONST(char *, line)); - DEBUG("ficlExec '%s' = %d", line, result); - switch (result) { - case VM_OUTOFTEXT: - case VM_ABORTQ: - case VM_QUIT: - case VM_ERREXIT: - break; - case VM_USEREXIT: - printf("No where to leave to!\n"); - break; - case VM_ABORT: - printf("Aborted!\n"); - break; - case BF_PARSE: - printf("Parse error!\n"); - break; - default: - if (command_errmsg != NULL) { - printf("%s\n", command_errmsg); - command_errmsg = NULL; + DEBUG("ficlExec '%s' = %d", line, result); + switch (result) { + case VM_OUTOFTEXT: + case VM_ABORTQ: + case VM_QUIT: + case VM_ERREXIT: + break; + case VM_USEREXIT: + printf("No where to leave to!\n"); + break; + case VM_ABORT: + printf("Aborted!\n"); + break; + case BF_PARSE: + printf("Parse error!\n"); + break; + default: + if (command_errmsg != NULL) { + printf("%s\n", command_errmsg); + command_errmsg = NULL; + } } - } - if (result == VM_USEREXIT) - panic("interpreter exit"); - setenv("interpret", bf_vm->state ? "" : "OK", 1); + if (result == VM_USEREXIT) + panic("interpreter exit"); + setenv("interpret", bf_vm->state ? "" : "OK", 1); - return (result); + return (result); } void interp_init(void) { bf_init(); /* Read our default configuration. */ interp_include("/boot/loader.rc"); } int interp_run(const char *input) { bf_vm->sourceID.i = 0; return bf_run(input); } /* * 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. */ struct includeline { - struct includeline *next; - char text[0]; + struct includeline *next; + char text[0]; }; int interp_include(const char *filename) { - struct includeline *script, *se, *sp; - char input[256]; /* big enough? */ - int res; - char *cp; - int prevsrcid, fd, line; + struct includeline *script, *se, *sp; + char input[256]; /* big enough? */ + int res; + char *cp; + int prevsrcid, fd, line; - 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 (((fd = open(filename, O_RDONLY)) == -1)) { + snprintf(command_errbuf, sizeof(command_errbuf), + "can't open '%s': %s", filename, strerror(errno)); + return(CMD_ERROR); + } - /* - * Read the script into memory. - */ - script = se = NULL; - line = 0; - - while (fgetstr(input, sizeof(input), fd) >= 0) { - line++; - cp = input; - /* 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); + /* + * Read the script into memory. + */ + script = se = NULL; + line = 0; + + while (fgetstr(input, sizeof(input), fd) >= 0) { + line++; + cp = input; + /* 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); + close(fd); + return (CMD_ERROR); } - snprintf(command_errbuf, sizeof(command_errbuf), - "file '%s' line %d: memory allocation failure - aborting", - filename, line); - close(fd); - return (CMD_ERROR); + strcpy(sp->text, cp); + sp->next = NULL; + + if (script == NULL) { + script = sp; + } else { + se->next = sp; + } + se = sp; } - strcpy(sp->text, cp); - sp->next = NULL; + close(fd); - if (script == NULL) { - script = sp; - } else { - se->next = sp; + /* + * Execute the script + */ + prevsrcid = bf_vm->sourceID.i; + bf_vm->sourceID.i = fd; + res = CMD_OK; + for (sp = script; sp != NULL; sp = sp->next) { + 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; } - se = sp; - } - close(fd); + bf_vm->sourceID.i = prevsrcid; - /* - * Execute the script - */ - prevsrcid = bf_vm->sourceID.i; - bf_vm->sourceID.i = fd; - res = CMD_OK; - for (sp = script; sp != NULL; sp = sp->next) { - - 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; - } - bf_vm->sourceID.i = prevsrcid; - - while (script != NULL) { - se = script; - script = script->next; - free(se); - } - return(res); + while (script != NULL) { + se = script; + script = script->next; + free(se); + } + return(res); } Index: head/stand/common/interp_simple.c =================================================================== --- head/stand/common/interp_simple.c (revision 328998) +++ head/stand/common/interp_simple.c (revision 328999) @@ -1,223 +1,223 @@ /*- * Copyright (c) 1998 Michael Smith * 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 __FBSDID("$FreeBSD$"); /* * Simple commandline interpreter, toplevel and misc. */ #include #include #include "bootstrap.h" /* * Perform the command */ static int perform(int argc, char *argv[]) { - int result; + 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); } void interp_init(void) { /* Read our default configuration. */ interp_include("/boot/loader.rc"); } int interp_run(const char *input) { - int argc; - char **argv; + int argc; + char **argv; if (parse(&argc, &argv, input)) { printf("parse error\n"); return CMD_ERROR; } if (perform(argc, argv)) { printf("%s: %s\n", argv[0], command_errmsg); free(argv); return CMD_ERROR; } free(argv); return CMD_OK; } /* * 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. */ struct includeline { struct includeline *next; int flags; int line; #define SL_QUIET (1<<0) #define SL_IGNOREERR (1<<1) char text[0]; }; int interp_include(const char *filename) { struct includeline *script, *se, *sp; char input[256]; /* big enough? */ int argc,res; char **argv, *cp; int fd, flags, line; if (((fd = open(filename, O_RDONLY)) == -1)) { snprintf(command_errbuf, sizeof(command_errbuf), "can't open '%s': %s", 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); } snprintf(command_errbuf, sizeof(command_errbuf), "file '%s' line %d: memory allocation failure - aborting", filename, line); close(fd); 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)) { interp_emit_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; } } if (argv != NULL) free(argv); while (script != NULL) { se = script; script = script->next; free(se); } return(res); }