1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7ca987d46SWarner Losh * are met: 8ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13ca987d46SWarner Losh * 14ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca987d46SWarner Losh * SUCH DAMAGE. 25ca987d46SWarner Losh */ 26ca987d46SWarner Losh 27ca987d46SWarner Losh #include <sys/cdefs.h> 28ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 29ca987d46SWarner Losh 30ca987d46SWarner Losh #include <sys/param.h> /* to pick up __FreeBSD_version */ 31ca987d46SWarner Losh #include <string.h> 32ca987d46SWarner Losh #include <stand.h> 33ca987d46SWarner Losh #include "bootstrap.h" 34ca987d46SWarner Losh #include "ficl.h" 35ca987d46SWarner Losh 36ca987d46SWarner Losh extern unsigned bootprog_rev; 37d3d381b2SKyle Evans INTERP_DEFINE("4th"); 38ca987d46SWarner Losh 39ca987d46SWarner Losh /* #define BFORTH_DEBUG */ 40ca987d46SWarner Losh 41ca987d46SWarner Losh #ifdef BFORTH_DEBUG 427325df02SKyle Evans #define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 43ca987d46SWarner Losh #else 447325df02SKyle Evans #define DPRINTF(fmt, args...) 45ca987d46SWarner Losh #endif 46ca987d46SWarner Losh 47ca987d46SWarner Losh /* 48ca987d46SWarner Losh * Eventually, all builtin commands throw codes must be defined 49ca987d46SWarner Losh * elsewhere, possibly bootstrap.h. For now, just this code, used 50ca987d46SWarner Losh * just in this file, it is getting defined. 51ca987d46SWarner Losh */ 52ca987d46SWarner Losh #define BF_PARSE 100 53ca987d46SWarner Losh 54ca987d46SWarner Losh /* 55ca987d46SWarner Losh * FreeBSD loader default dictionary cells 56ca987d46SWarner Losh */ 57ca987d46SWarner Losh #ifndef BF_DICTSIZE 58ca987d46SWarner Losh #define BF_DICTSIZE 10000 59ca987d46SWarner Losh #endif 60ca987d46SWarner Losh 61ca987d46SWarner Losh /* 62ca987d46SWarner Losh * BootForth Interface to Ficl Forth interpreter. 63ca987d46SWarner Losh */ 64ba25195eSWarner Losh 65ca987d46SWarner Losh FICL_SYSTEM *bf_sys; 66ca987d46SWarner Losh FICL_VM *bf_vm; 67ca987d46SWarner Losh 68ca987d46SWarner Losh /* 69ca987d46SWarner Losh * Shim for taking commands from BF and passing them out to 'standard' 70ca987d46SWarner Losh * argv/argc command functions. 71ca987d46SWarner Losh */ 72ca987d46SWarner Losh static void 73ca987d46SWarner Losh bf_command(FICL_VM *vm) 74ca987d46SWarner Losh { 75ca987d46SWarner Losh char *name, *line, *tail, *cp; 76ca987d46SWarner Losh size_t len; 77ca987d46SWarner Losh struct bootblk_command **cmdp; 78ca987d46SWarner Losh bootblk_cmd_t *cmd; 79ca987d46SWarner Losh int nstrings, i; 80ca987d46SWarner Losh int argc, result; 81ca987d46SWarner Losh char **argv; 82ca987d46SWarner Losh 83ca987d46SWarner Losh /* Get the name of the current word */ 84ca987d46SWarner Losh name = vm->runningWord->name; 85ca987d46SWarner Losh 86ca987d46SWarner Losh /* Find our command structure */ 87ca987d46SWarner Losh cmd = NULL; 88ca987d46SWarner Losh SET_FOREACH(cmdp, Xcommand_set) { 89ca987d46SWarner Losh if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name)) 90ca987d46SWarner Losh cmd = (*cmdp)->c_fn; 91ca987d46SWarner Losh } 92ca987d46SWarner Losh if (cmd == NULL) 93ca987d46SWarner Losh panic("callout for unknown command '%s'", name); 94ca987d46SWarner Losh 95ca987d46SWarner Losh /* Check whether we have been compiled or are being interpreted */ 96ca987d46SWarner Losh if (stackPopINT(vm->pStack)) { 97ca987d46SWarner Losh /* 98ca987d46SWarner Losh * Get parameters from stack, in the format: 99ca987d46SWarner Losh * an un ... a2 u2 a1 u1 n -- 100ca987d46SWarner Losh * Where n is the number of strings, a/u are pairs of 101ca987d46SWarner Losh * address/size for strings, and they will be concatenated 102ca987d46SWarner Losh * in LIFO order. 103ca987d46SWarner Losh */ 104ca987d46SWarner Losh nstrings = stackPopINT(vm->pStack); 105ca987d46SWarner Losh for (i = 0, len = 0; i < nstrings; i++) 106ca987d46SWarner Losh len += stackFetch(vm->pStack, i * 2).i + 1; 107ca987d46SWarner Losh line = malloc(strlen(name) + len + 1); 108ca987d46SWarner Losh strcpy(line, name); 109ca987d46SWarner Losh 110ca987d46SWarner Losh if (nstrings) 111ca987d46SWarner Losh for (i = 0; i < nstrings; i++) { 112ca987d46SWarner Losh len = stackPopINT(vm->pStack); 113ca987d46SWarner Losh cp = stackPopPtr(vm->pStack); 114ca987d46SWarner Losh strcat(line, " "); 115ca987d46SWarner Losh strncat(line, cp, len); 116ca987d46SWarner Losh } 117ca987d46SWarner Losh } else { 118ca987d46SWarner Losh /* Get remainder of invocation */ 119ca987d46SWarner Losh tail = vmGetInBuf(vm); 120ca987d46SWarner Losh for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++) 121ca987d46SWarner Losh ; 122ca987d46SWarner Losh 123ca987d46SWarner Losh line = malloc(strlen(name) + len + 2); 124ca987d46SWarner Losh strcpy(line, name); 125ca987d46SWarner Losh if (len > 0) { 126ca987d46SWarner Losh strcat(line, " "); 127ca987d46SWarner Losh strncat(line, tail, len); 128ca987d46SWarner Losh vmUpdateTib(vm, tail + len); 129ca987d46SWarner Losh } 130ca987d46SWarner Losh } 1317325df02SKyle Evans DPRINTF("cmd '%s'", line); 132ca987d46SWarner Losh 133ca987d46SWarner Losh command_errmsg = command_errbuf; 134ca987d46SWarner Losh command_errbuf[0] = 0; 135ca987d46SWarner Losh if (!parse(&argc, &argv, line)) { 136ca987d46SWarner Losh result = (cmd)(argc, argv); 137ca987d46SWarner Losh free(argv); 138ca987d46SWarner Losh } else { 139ca987d46SWarner Losh result=BF_PARSE; 140ca987d46SWarner Losh } 141ca987d46SWarner Losh 142ca987d46SWarner Losh switch (result) { 143ca987d46SWarner Losh case CMD_CRIT: 144ca987d46SWarner Losh printf("%s\n", command_errmsg); 145d92fb784SMaxim Sobolev command_errmsg = NULL; 146ca987d46SWarner Losh break; 147ca987d46SWarner Losh case CMD_FATAL: 14855d5c949SMaxim Sobolev panic("%s", command_errmsg); 149ca987d46SWarner Losh } 150ca987d46SWarner Losh 151ca987d46SWarner Losh free(line); 152ca987d46SWarner Losh /* 153ca987d46SWarner Losh * If there was error during nested ficlExec(), we may no longer have 154ca987d46SWarner Losh * valid environment to return. Throw all exceptions from here. 155ca987d46SWarner Losh */ 156ca987d46SWarner Losh if (result != CMD_OK) 157ca987d46SWarner Losh vmThrow(vm, result); 158ca987d46SWarner Losh 159ca987d46SWarner Losh /* This is going to be thrown!!! */ 160ca987d46SWarner Losh stackPushINT(vm->pStack,result); 161ca987d46SWarner Losh } 162ca987d46SWarner Losh 163ca987d46SWarner Losh /* 164ca987d46SWarner Losh * Replace a word definition (a builtin command) with another 165ca987d46SWarner Losh * one that: 166ca987d46SWarner Losh * 167ca987d46SWarner Losh * - Throw error results instead of returning them on the stack 168ca987d46SWarner Losh * - Pass a flag indicating whether the word was compiled or is 169ca987d46SWarner Losh * being interpreted. 170ca987d46SWarner Losh * 171ca987d46SWarner Losh * There is one major problem with builtins that cannot be overcome 172ca987d46SWarner Losh * in anyway, except by outlawing it. We want builtins to behave 173ca987d46SWarner Losh * differently depending on whether they have been compiled or they 174ca987d46SWarner Losh * are being interpreted. Notice that this is *not* the interpreter's 175ca987d46SWarner Losh * current state. For example: 176ca987d46SWarner Losh * 177ca987d46SWarner Losh * : example ls ; immediate 178ca987d46SWarner Losh * : problem example ; \ "ls" gets executed while compiling 179ca987d46SWarner Losh * example \ "ls" gets executed while interpreting 180ca987d46SWarner Losh * 181ca987d46SWarner Losh * Notice that, though the current state is different in the two 182ca987d46SWarner Losh * invocations of "example", in both cases "ls" has been 183ca987d46SWarner Losh * *compiled in*, which is what we really want. 184ca987d46SWarner Losh * 185ca987d46SWarner Losh * The problem arises when you tick the builtin. For example: 186ca987d46SWarner Losh * 187ca987d46SWarner Losh * : example-1 ['] ls postpone literal ; immediate 188ca987d46SWarner Losh * : example-2 example-1 execute ; immediate 189ca987d46SWarner Losh * : problem example-2 ; 190ca987d46SWarner Losh * example-2 191ca987d46SWarner Losh * 192ca987d46SWarner Losh * We have no way, when we get EXECUTEd, of knowing what our behavior 193ca987d46SWarner Losh * should be. Thus, our only alternative is to "outlaw" this. See RFI 194ca987d46SWarner Losh * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related 195ca987d46SWarner Losh * problem, concerning compile semantics. 196ca987d46SWarner Losh * 197ca987d46SWarner Losh * The problem is compounded by the fact that "' builtin CATCH" is valid 198ca987d46SWarner Losh * and desirable. The only solution is to create an intermediary word. 199ca987d46SWarner Losh * For example: 200ca987d46SWarner Losh * 201ca987d46SWarner Losh * : my-ls ls ; 202ca987d46SWarner Losh * : example ['] my-ls catch ; 203ca987d46SWarner Losh * 204ca987d46SWarner Losh * So, with the below implementation, here is a summary of the behavior 205ca987d46SWarner Losh * of builtins: 206ca987d46SWarner Losh * 207ca987d46SWarner Losh * ls -l \ "interpret" behavior, ie, 208ca987d46SWarner Losh * \ takes parameters from TIB 209ca987d46SWarner Losh * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie, 210ca987d46SWarner Losh * \ takes parameters from the stack 211ca987d46SWarner Losh * : ex-2 ['] ls catch ; immediate \ undefined behavior 212ca987d46SWarner Losh * : ex-3 ['] ls catch ; \ undefined behavior 213ca987d46SWarner Losh * ex-2 ex-3 \ "interpret" behavior, 214ca987d46SWarner Losh * \ catch works 215ca987d46SWarner Losh * : ex-4 ex-2 ; \ "compile" behavior, 216ca987d46SWarner Losh * \ catch does not work 217ca987d46SWarner Losh * : ex-5 ex-3 ; immediate \ same as ex-2 218ca987d46SWarner Losh * : ex-6 ex-3 ; \ same as ex-3 219ca987d46SWarner Losh * : ex-7 ['] ex-1 catch ; \ "compile" behavior, 220ca987d46SWarner Losh * \ catch works 221ca987d46SWarner Losh * : ex-8 postpone ls ; immediate \ same as ex-2 222ca987d46SWarner Losh * : ex-9 postpone ls ; \ same as ex-3 223ca987d46SWarner Losh * 224ca987d46SWarner Losh * As the definition below is particularly tricky, and it's side effects 225ca987d46SWarner Losh * must be well understood by those playing with it, I'll be heavy on 226ca987d46SWarner Losh * the comments. 227ca987d46SWarner Losh * 228ca987d46SWarner Losh * (if you edit this definition, pay attention to trailing spaces after 229ca987d46SWarner Losh * each word -- I warned you! :-) ) 230ca987d46SWarner Losh */ 231ca987d46SWarner Losh #define BUILTIN_CONSTRUCTOR \ 232ca987d46SWarner Losh ": builtin: " \ 233ca987d46SWarner Losh ">in @ " /* save the tib index pointer */ \ 234ca987d46SWarner Losh "' " /* get next word's xt */ \ 235ca987d46SWarner Losh "swap >in ! " /* point again to next word */ \ 236ca987d46SWarner Losh "create " /* create a new definition of the next word */ \ 237ca987d46SWarner Losh ", " /* save previous definition's xt */ \ 238ca987d46SWarner Losh "immediate " /* make the new definition an immediate word */ \ 239ca987d46SWarner Losh \ 240ca987d46SWarner Losh "does> " /* Now, the *new* definition will: */ \ 241ca987d46SWarner Losh "state @ if " /* if in compiling state: */ \ 242ca987d46SWarner Losh "1 postpone literal " /* pass 1 flag to indicate compile */ \ 243ca987d46SWarner Losh "@ compile, " /* compile in previous definition */ \ 244ca987d46SWarner Losh "postpone throw " /* throw stack-returned result */ \ 245ca987d46SWarner Losh "else " /* if in interpreting state: */ \ 246ca987d46SWarner Losh "0 swap " /* pass 0 flag to indicate interpret */ \ 247ca987d46SWarner Losh "@ execute " /* call previous definition */ \ 248ca987d46SWarner Losh "throw " /* throw stack-returned result */ \ 249ca987d46SWarner Losh "then ; " 250ca987d46SWarner Losh 251ca987d46SWarner Losh /* 252ca987d46SWarner Losh * Initialise the Forth interpreter, create all our commands as words. 253ca987d46SWarner Losh */ 254ba25195eSWarner Losh void 2556bc86037SWarner Losh bf_init(void) 256ca987d46SWarner Losh { 257ca987d46SWarner Losh struct bootblk_command **cmdp; 258ca987d46SWarner Losh char create_buf[41]; /* 31 characters-long builtins */ 259ba25195eSWarner Losh int fd; 260ca987d46SWarner Losh 261ba25195eSWarner Losh bf_sys = ficlInitSystem(BF_DICTSIZE); 262ba25195eSWarner Losh bf_vm = ficlNewVM(bf_sys); 263ca987d46SWarner Losh 264ca987d46SWarner Losh /* Put all private definitions in a "builtins" vocabulary */ 265ca987d46SWarner Losh ficlExec(bf_vm, "vocabulary builtins also builtins definitions"); 266ca987d46SWarner Losh 267ca987d46SWarner Losh /* Builtin constructor word */ 268ca987d46SWarner Losh ficlExec(bf_vm, BUILTIN_CONSTRUCTOR); 269ca987d46SWarner Losh 270ca987d46SWarner Losh /* make all commands appear as Forth words */ 271ca987d46SWarner Losh SET_FOREACH(cmdp, Xcommand_set) { 272ca987d46SWarner Losh ficlBuild(bf_sys, (char *)(*cmdp)->c_name, bf_command, FW_DEFAULT); 273ca987d46SWarner Losh ficlExec(bf_vm, "forth definitions builtins"); 274ca987d46SWarner Losh sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); 275ca987d46SWarner Losh ficlExec(bf_vm, create_buf); 276ca987d46SWarner Losh ficlExec(bf_vm, "builtins definitions"); 277ca987d46SWarner Losh } 278ca987d46SWarner Losh ficlExec(bf_vm, "only forth definitions"); 279ca987d46SWarner Losh 280ca987d46SWarner Losh /* Export some version numbers so that code can detect the loader/host version */ 281ca987d46SWarner Losh ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version); 282ca987d46SWarner Losh ficlSetEnv(bf_sys, "loader_version", bootprog_rev); 283ba25195eSWarner Losh 284ba25195eSWarner Losh /* try to load and run init file if present */ 2856bc86037SWarner Losh if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { 286*c42e554dSMarcin Wojtas #ifdef LOADER_VERIEXEC 287*c42e554dSMarcin Wojtas if (verify_file(fd, "/boot/boot.4th", 0, VE_GUESS) < 0) { 288*c42e554dSMarcin Wojtas close(fd); 289*c42e554dSMarcin Wojtas return; 290*c42e554dSMarcin Wojtas } 291*c42e554dSMarcin Wojtas #endif 292ba25195eSWarner Losh (void)ficlExecFD(bf_vm, fd); 293ba25195eSWarner Losh close(fd); 294ba25195eSWarner Losh } 295ba25195eSWarner Losh } 296ca987d46SWarner Losh 297ca987d46SWarner Losh /* 298ca987d46SWarner Losh * Feed a line of user input to the Forth interpreter 299ca987d46SWarner Losh */ 30079a6a17aSWarner Losh static int 30179a6a17aSWarner Losh bf_run(const char *line) 302ca987d46SWarner Losh { 303ca987d46SWarner Losh int result; 304ca987d46SWarner Losh 30579a6a17aSWarner Losh /* 30679a6a17aSWarner Losh * ficl would require extensive changes to accept a const char * 30779a6a17aSWarner Losh * interface. Instead, cast it away here and hope for the best. 30879a6a17aSWarner Losh * We know at the present time the caller for us in the boot 30979a6a17aSWarner Losh * forth loader can tolerate the string being modified because 31079a6a17aSWarner Losh * the string is passed in here and then not touched again. 31179a6a17aSWarner Losh */ 31279a6a17aSWarner Losh result = ficlExec(bf_vm, __DECONST(char *, line)); 313ca987d46SWarner Losh 3147325df02SKyle Evans DPRINTF("ficlExec '%s' = %d", line, result); 315ca987d46SWarner Losh switch (result) { 316ca987d46SWarner Losh case VM_OUTOFTEXT: 317ca987d46SWarner Losh case VM_ABORTQ: 318ca987d46SWarner Losh case VM_QUIT: 319ca987d46SWarner Losh case VM_ERREXIT: 320ca987d46SWarner Losh break; 321ca987d46SWarner Losh case VM_USEREXIT: 322ca987d46SWarner Losh printf("No where to leave to!\n"); 323ca987d46SWarner Losh break; 324ca987d46SWarner Losh case VM_ABORT: 325ca987d46SWarner Losh printf("Aborted!\n"); 326ca987d46SWarner Losh break; 327ca987d46SWarner Losh case BF_PARSE: 328ca987d46SWarner Losh printf("Parse error!\n"); 329ca987d46SWarner Losh break; 330ca987d46SWarner Losh default: 331ca987d46SWarner Losh if (command_errmsg != NULL) { 332ca987d46SWarner Losh printf("%s\n", command_errmsg); 333ca987d46SWarner Losh command_errmsg = NULL; 334ca987d46SWarner Losh } 335ca987d46SWarner Losh } 336ca987d46SWarner Losh 337ca987d46SWarner Losh if (result == VM_USEREXIT) 338ca987d46SWarner Losh panic("interpreter exit"); 339ba25195eSWarner Losh setenv("interpret", bf_vm->state ? "" : "OK", 1); 340ca987d46SWarner Losh 341ca987d46SWarner Losh return (result); 342ca987d46SWarner Losh } 34379a6a17aSWarner Losh 34479a6a17aSWarner Losh void 34579a6a17aSWarner Losh interp_init(void) 34679a6a17aSWarner Losh { 34779a6a17aSWarner Losh 34886411ec1SWarner Losh setenv("script.lang", "forth", 1); 34979a6a17aSWarner Losh bf_init(); 35079a6a17aSWarner Losh /* Read our default configuration. */ 35179a6a17aSWarner Losh interp_include("/boot/loader.rc"); 35279a6a17aSWarner Losh } 35379a6a17aSWarner Losh 35479a6a17aSWarner Losh int 35579a6a17aSWarner Losh interp_run(const char *input) 35679a6a17aSWarner Losh { 35779a6a17aSWarner Losh 35879a6a17aSWarner Losh bf_vm->sourceID.i = 0; 35979a6a17aSWarner Losh return bf_run(input); 36079a6a17aSWarner Losh } 36179a6a17aSWarner Losh 36279a6a17aSWarner Losh /* 36379a6a17aSWarner Losh * Header prepended to each line. The text immediately follows the header. 36479a6a17aSWarner Losh * We try to make this short in order to save memory -- the loader has 36579a6a17aSWarner Losh * limited memory available, and some of the forth files are very long. 36679a6a17aSWarner Losh */ 36779a6a17aSWarner Losh struct includeline 36879a6a17aSWarner Losh { 36979a6a17aSWarner Losh struct includeline *next; 37079a6a17aSWarner Losh char text[0]; 37179a6a17aSWarner Losh }; 37279a6a17aSWarner Losh 37379a6a17aSWarner Losh int 37479a6a17aSWarner Losh interp_include(const char *filename) 37579a6a17aSWarner Losh { 37679a6a17aSWarner Losh struct includeline *script, *se, *sp; 37779a6a17aSWarner Losh char input[256]; /* big enough? */ 37879a6a17aSWarner Losh int res; 37979a6a17aSWarner Losh char *cp; 38079a6a17aSWarner Losh int prevsrcid, fd, line; 38179a6a17aSWarner Losh 38279a6a17aSWarner Losh if (((fd = open(filename, O_RDONLY)) == -1)) { 38379a6a17aSWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 38479a6a17aSWarner Losh "can't open '%s': %s", filename, strerror(errno)); 38579a6a17aSWarner Losh return(CMD_ERROR); 38679a6a17aSWarner Losh } 38779a6a17aSWarner Losh 3888df8b2d3SSimon J. Gerraty #ifdef LOADER_VERIEXEC 3898df8b2d3SSimon J. Gerraty if (verify_file(fd, filename, 0, VE_GUESS) < 0) { 3908df8b2d3SSimon J. Gerraty close(fd); 3918df8b2d3SSimon J. Gerraty sprintf(command_errbuf,"can't verify '%s'", filename); 3928df8b2d3SSimon J. Gerraty return(CMD_ERROR); 3938df8b2d3SSimon J. Gerraty } 3948df8b2d3SSimon J. Gerraty #endif 39579a6a17aSWarner Losh /* 39679a6a17aSWarner Losh * Read the script into memory. 39779a6a17aSWarner Losh */ 39879a6a17aSWarner Losh script = se = NULL; 39979a6a17aSWarner Losh line = 0; 40079a6a17aSWarner Losh 40179a6a17aSWarner Losh while (fgetstr(input, sizeof(input), fd) >= 0) { 40279a6a17aSWarner Losh line++; 40379a6a17aSWarner Losh cp = input; 40479a6a17aSWarner Losh /* Allocate script line structure and copy line, flags */ 40579a6a17aSWarner Losh if (*cp == '\0') 40679a6a17aSWarner Losh continue; /* ignore empty line, save memory */ 40779a6a17aSWarner Losh sp = malloc(sizeof(struct includeline) + strlen(cp) + 1); 40879a6a17aSWarner Losh /* On malloc failure (it happens!), free as much as possible and exit */ 40979a6a17aSWarner Losh if (sp == NULL) { 41079a6a17aSWarner Losh while (script != NULL) { 41179a6a17aSWarner Losh se = script; 41279a6a17aSWarner Losh script = script->next; 41379a6a17aSWarner Losh free(se); 41479a6a17aSWarner Losh } 41579a6a17aSWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 41679a6a17aSWarner Losh "file '%s' line %d: memory allocation failure - aborting", 41779a6a17aSWarner Losh filename, line); 41879a6a17aSWarner Losh close(fd); 41979a6a17aSWarner Losh return (CMD_ERROR); 42079a6a17aSWarner Losh } 42179a6a17aSWarner Losh strcpy(sp->text, cp); 42279a6a17aSWarner Losh sp->next = NULL; 42379a6a17aSWarner Losh 42479a6a17aSWarner Losh if (script == NULL) { 42579a6a17aSWarner Losh script = sp; 42679a6a17aSWarner Losh } else { 42779a6a17aSWarner Losh se->next = sp; 42879a6a17aSWarner Losh } 42979a6a17aSWarner Losh se = sp; 43079a6a17aSWarner Losh } 43179a6a17aSWarner Losh close(fd); 43279a6a17aSWarner Losh 43379a6a17aSWarner Losh /* 43479a6a17aSWarner Losh * Execute the script 43579a6a17aSWarner Losh */ 43679a6a17aSWarner Losh prevsrcid = bf_vm->sourceID.i; 43779a6a17aSWarner Losh bf_vm->sourceID.i = fd; 43879a6a17aSWarner Losh res = CMD_OK; 43979a6a17aSWarner Losh for (sp = script; sp != NULL; sp = sp->next) { 44079a6a17aSWarner Losh res = bf_run(sp->text); 44179a6a17aSWarner Losh if (res != VM_OUTOFTEXT) { 44279a6a17aSWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 44379a6a17aSWarner Losh "Error while including %s, in the line:\n%s", 44479a6a17aSWarner Losh filename, sp->text); 44579a6a17aSWarner Losh res = CMD_ERROR; 44679a6a17aSWarner Losh break; 44779a6a17aSWarner Losh } else 44879a6a17aSWarner Losh res = CMD_OK; 44979a6a17aSWarner Losh } 45079a6a17aSWarner Losh bf_vm->sourceID.i = prevsrcid; 45179a6a17aSWarner Losh 45279a6a17aSWarner Losh while (script != NULL) { 45379a6a17aSWarner Losh se = script; 45479a6a17aSWarner Losh script = script->next; 45579a6a17aSWarner Losh free(se); 45679a6a17aSWarner Losh } 45779a6a17aSWarner Losh return(res); 45879a6a17aSWarner Losh } 459