interp.c revision 38764
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 * $Id: interp.c,v 1.2 1998/09/01 00:41:24 msmith Exp $ 27 */ 28/* 29 * Simple commandline interpreter, toplevel and misc. 30 * 31 * XXX may be obsoleted by BootFORTH 32 */ 33 34#include <stand.h> 35#include <string.h> 36#include "bootstrap.h" 37 38#define MAXARGS 20 /* maximum number of arguments allowed */ 39 40extern int parse(int *argc, char ***argv, char *str); /* interp_parse.c */ 41 42static void prompt(void); 43 44/* 45 * Perform the command 46 */ 47static int 48perform(int argc, char *argv[]) 49{ 50 int i, result; 51 struct bootblk_command **cmdp; 52 bootblk_cmd_t *cmd; 53 54 if (argc < 1) 55 return(CMD_OK); 56 57 /* set return defaults; a successful command will override these */ 58 command_errmsg = command_errbuf; 59 strcpy(command_errbuf, "no error message"); 60 cmd = NULL; 61 result = CMD_ERROR; 62 63 cmdp = (struct bootblk_command **)Xcommand_set.ls_items; 64 for (i = 0; i < Xcommand_set.ls_length; i++) { 65 if ((cmdp[i]->c_name != NULL) && !strcmp(argv[0], cmdp[i]->c_name)) 66 cmd = cmdp[i]->c_fn; 67 } 68 if (cmd != NULL) { 69 result = (cmd)(argc, argv); 70 } else { 71 command_errmsg = "unknown command"; 72 } 73 return(result); 74} 75 76/* 77 * Interactive mode 78 */ 79void 80interact(void) 81{ 82 char input[256]; /* big enough? */ 83 int argc; 84 char **argv; 85 86 /* 87 * Read our default configuration 88 */ 89 source("/boot/boot.conf"); 90 printf("\n"); 91 /* 92 * Before interacting, we might want to autoboot 93 */ 94 if (getenv("no_autoboot") == NULL) 95 autoboot(10, NULL); /* try to boot automatically */ 96 97 /* 98 * Not autobooting, go manual 99 */ 100 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 101 setenv("prompt", "${currdev}>", 1); 102 103 104 for (;;) { 105 input[0] = '\0'; 106 prompt(); 107 ngets(input, sizeof(input)); 108 if (!parse(&argc, &argv, input)) { 109 if (perform(argc, argv)) 110 printf("%s: %s\n", argv[0], command_errmsg); 111 free(argv); 112 } else { 113 printf("parse error\n"); 114 } 115 } 116} 117 118/* 119 * Read command from a file 120 */ 121COMMAND_SET(source, "source", "read commands from a file", command_source); 122 123static int 124command_source(int argc, char *argv[]) 125{ 126 int i; 127 128 for (i = 1; i < argc; i++) 129 source(argv[i]); 130 return(CMD_OK); 131} 132 133void 134source(char *filename) 135{ 136 char input[256]; /* big enough? */ 137 int argc; 138 char **argv, *cp; 139 int fd; 140 141 if (((fd = open(filename, O_RDONLY)) == -1)) { 142 printf("can't open '%s': %s\n", filename, strerror(errno)); 143 } else { 144 while (fgetstr(input, sizeof(input), fd) > 0) { 145 146 /* Discard comments */ 147 if (input[0] == '#') 148 continue; 149 cp = input; 150 /* Echo? */ 151 if (input[0] == '@') { 152 cp++; 153 } else { 154 prompt(); 155 printf("%s\n", input); 156 } 157 158 if (!parse(&argc, &argv, cp)) { 159 if ((argc > 0) && 160 (perform(argc, argv) != 0)) 161 printf("%s: %s\n", argv[0], command_errmsg); 162 free(argv); 163 } 164 } 165 close(fd); 166 } 167} 168 169/* 170 * Emit the current prompt; use the same syntax as the parser 171 * for embedding environment variables. 172 */ 173static void 174prompt(void) 175{ 176 char *p, *cp, *ev; 177 178 if ((cp = getenv("prompt")) == NULL) 179 cp = ">"; 180 p = strdup(cp); 181 182 while (*p != 0) { 183 if ((*p == '$') && (*(p+1) == '{')) { 184 for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 185 ; 186 *cp = 0; 187 ev = getenv(p + 2); 188 189 if (ev != NULL) 190 printf(ev); 191 p = cp + 1; 192 continue; 193 } 194 putchar(*p++); 195 } 196 putchar(' '); 197} 198