interp.c revision 38465
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$ 27 */ 28/* 29 * Simple commandline interpreter. 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 40static int parse(char *buf, int *argcp, char **argvp[]); 41static void prompt(void); 42/* 43 * Parse the supplied text into argv/argc form. 44 * XXX should perhaps learn about quotes, etc? 45 * XXX can also do alias expansion, variable substitution, etc. here 46 */ 47static int 48parse(char *buf, int *argcp, char **argvp[]) 49{ 50 static int argc; 51 static char *argv[MAXARGS], *cp; 52 53 argc = 0; 54 cp = buf; 55 while ((*cp != 0) && (argc < MAXARGS)) { 56 if (isspace(*cp)) { 57 *(cp++) = 0; 58 } else { 59 argv[argc++] = cp++; 60 while ((*cp != 0) && !isspace(*cp)) 61 cp++; 62 } 63 } 64 argv[argc] = NULL; 65 /* command too complex */ 66 if (argc >= MAXARGS) { 67 printf("too many arguments\n"); 68 return(1); 69 } 70 *argcp = argc; 71 *argvp = argv; 72 return(0); 73} 74 75/* 76 * Perform the command 77 */ 78static int 79perform(int argc, char *argv[]) 80{ 81 int i, result; 82 struct bootblk_command **cmdp; 83 bootblk_cmd_t *cmd; 84 85 if (argc < 1) 86 return(CMD_OK); 87 88 /* set return defaults; a successful command will override these */ 89 command_errmsg = command_errbuf; 90 strcpy(command_errbuf, "no error message"); 91 cmd = NULL; 92 result = CMD_ERROR; 93 94 cmdp = (struct bootblk_command **)Xcommand_set.ls_items; 95 for (i = 0; i < Xcommand_set.ls_length; i++) { 96 if ((cmdp[i]->c_name != NULL) && !strcmp(argv[0], cmdp[i]->c_name)) 97 cmd = cmdp[i]->c_fn; 98 } 99 if (cmd != NULL) { 100 result = (cmd)(argc, argv); 101 } else { 102 command_errmsg = "unknown command"; 103 } 104 return(result); 105} 106 107/* 108 * Interactive mode 109 */ 110void 111interact(void) 112{ 113 char input[256]; /* big enough? */ 114 int argc; 115 char **argv; 116 117 for (;;) { 118 input[0] = '\0'; 119 prompt(); 120 ngets(input, sizeof(input)); 121 if (!parse(input, &argc, &argv) && 122 (perform(argc, argv) != 0)) 123 printf("%s: %s\n", argv[0], command_errmsg); 124 } 125} 126 127/* 128 * Read command from a file 129 */ 130COMMAND_SET(source, "source", "read commands from a file", command_source); 131 132static int 133command_source(int argc, char *argv[]) 134{ 135 int i; 136 137 for (i = 1; i < argc; i++) 138 source(argv[i]); 139 return(CMD_OK); 140} 141 142void 143source(char *filename) 144{ 145 char input[256]; /* big enough? */ 146 int argc; 147 char **argv, *cp; 148 int fd; 149 150 if (((fd = open(filename, O_RDONLY)) == -1)) { 151 printf("can't open '%s': %s\n", filename, strerror(errno)); 152 } else { 153 while (fgetstr(input, sizeof(input), fd) > 0) { 154 155 /* Discard comments */ 156 if (input[0] == '#') 157 continue; 158 cp = input; 159 /* Echo? */ 160 if (input[0] == '@') { 161 cp++; 162 } else { 163 prompt(); 164 printf("%s\n", input); 165 } 166 167 if (!parse(cp, &argc, &argv) && 168 (argc > 0) && 169 (perform(argc, argv) != 0)) 170 printf("%s: %s\n", argv[0], command_errmsg); 171 } 172 close(fd); 173 } 174} 175 176/* 177 * Emit the current prompt; support primitive embedding of 178 * environment variables. 179 * We're a little rude here, modifying the return from getenv(). 180 */ 181static void 182prompt(void) 183{ 184 char *p, *cp, *ev, c; 185 186 if ((p = getenv("prompt")) == NULL) 187 p = ">"; 188 189 while (*p != 0) { 190 if (*p == '$') { 191 for (cp = p + 1; (*cp != 0) && isalpha(*cp); cp++) 192 ; 193 c = *cp; 194 *cp = 0; 195 ev = getenv(p + 1); 196 *cp = c; 197 198 if (ev != NULL) { 199 printf(ev); 200 p = cp; 201 continue; 202 } 203 } 204 putchar(*p++); 205 } 206 putchar(' '); 207} 208