options.c revision 9974
1139815Simp/*- 21541Srgrimes * Copyright (c) 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Kenneth Almquist. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30116189Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31116189Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32116189Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3353492Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3453492Speter * SUCH DAMAGE. 351541Srgrimes * 361541Srgrimes * $Id: options.c,v 1.3 1995/05/30 00:07:21 rgrimes Exp $ 37229366Sed */ 381541Srgrimes 3954411Speter#ifndef lint 4054411Speterstatic char sccsid[] = "@(#)options.c 8.1 (Berkeley) 5/31/93"; 4154411Speter#endif /* not lint */ 4254411Speter 4353492Speter#include "shell.h" 441541Srgrimes#define DEFINE_OPTIONS 4554411Speter#include "options.h" 4654411Speter#undef DEFINE_OPTIONS 4754411Speter#include "nodes.h" /* for other header files */ 4854411Speter#include "eval.h" 49127586Srobert#include "jobs.h" 501541Srgrimes#include "input.h" 511541Srgrimes#include "output.h" 521541Srgrimes#include "trap.h" 531541Srgrimes#include "var.h" 54#include "memalloc.h" 55#include "error.h" 56#include "mystring.h" 57 58char *arg0; /* value of $0 */ 59struct shparam shellparam; /* current positional parameters */ 60char **argptr; /* argument list for builtin commands */ 61char *optarg; /* set by nextopt (like getopt) */ 62char *optptr; /* used by nextopt */ 63 64char *minusc; /* argument to -c option */ 65 66 67#ifdef __STDC__ 68STATIC void options(int); 69STATIC void setoption(int, int); 70STATIC void minus_o(char *, int); 71#else 72STATIC void options(); 73STATIC void setoption(); 74STATIC void minus_o(); 75#endif 76 77 78 79/* 80 * Process the shell command line arguments. 81 */ 82 83void 84procargs(argc, argv) 85 char **argv; 86 { 87 int i; 88 89 argptr = argv; 90 if (argc > 0) 91 argptr++; 92 for (i = 0; i < NOPTS; i++) 93 optlist[i].val = 2; 94 options(1); 95 if (*argptr == NULL && minusc == NULL) 96 sflag = 1; 97 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 98 iflag = 1; 99 if (mflag == 2) 100 mflag = iflag; 101 for (i = 0; i < NOPTS; i++) 102 if (optlist[i].val == 2) 103 optlist[i].val = 0; 104 arg0 = argv[0]; 105 if (sflag == 0 && minusc == NULL) { 106 commandname = arg0 = *argptr++; 107 setinputfile(commandname, 0); 108 } 109 shellparam.p = argptr; 110 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 111 while (*argptr) { 112 shellparam.nparam++; 113 argptr++; 114 } 115 optschanged(); 116} 117 118 119optschanged() { 120 setinteractive(iflag); 121 histedit(); 122 setjobctl(mflag); 123} 124 125/* 126 * Process shell options. The global variable argptr contains a pointer 127 * to the argument list; we advance it past the options. 128 */ 129 130STATIC void 131options(cmdline) { 132 register char *p; 133 int val; 134 int c; 135 136 if (cmdline) 137 minusc = NULL; 138 while ((p = *argptr) != NULL) { 139 argptr++; 140 if ((c = *p++) == '-') { 141 val = 1; 142 if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 143 if (!cmdline) { 144 /* "-" means turn off -x and -v */ 145 if (p[0] == '\0') 146 xflag = vflag = 0; 147 /* "--" means reset params */ 148 else if (*argptr == NULL) 149 setparam(argptr); 150 } 151 break; /* "-" or "--" terminates options */ 152 } 153 } else if (c == '+') { 154 val = 0; 155 } else { 156 argptr--; 157 break; 158 } 159 while ((c = *p++) != '\0') { 160 if (c == 'c' && cmdline) { 161 char *q; 162#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 163 if (*p == '\0') 164#endif 165 q = *argptr++; 166 if (q == NULL || minusc != NULL) 167 error("Bad -c option"); 168 minusc = q; 169#ifdef NOHACK 170 break; 171#endif 172 } else if (c == 'o') { 173 minus_o(*argptr, val); 174 if (*argptr) 175 argptr++; 176 } else { 177 setoption(c, val); 178 } 179 } 180 } 181} 182 183STATIC void 184minus_o(name, val) 185 char *name; 186 int val; 187{ 188 int i; 189 190 if (name == NULL) { 191 out1str("Current option settings\n"); 192 for (i = 0; i < NOPTS; i++) 193 out1fmt("%-16s%s\n", optlist[i].name, 194 optlist[i].val ? "on" : "off"); 195 } else { 196 for (i = 0; i < NOPTS; i++) 197 if (equal(name, optlist[i].name)) { 198 setoption(optlist[i].letter, val); 199 return; 200 } 201 error("Illegal option -o %s", name); 202 } 203} 204 205 206STATIC void 207setoption(flag, val) 208 char flag; 209 int val; 210 { 211 int i; 212 213 for (i = 0; i < NOPTS; i++) 214 if (optlist[i].letter == flag) { 215 optlist[i].val = val; 216 if (val) { 217 /* #%$ hack for ksh semantics */ 218 if (flag == 'V') 219 Eflag = 0; 220 else if (flag == 'E') 221 Vflag = 0; 222 } 223 return; 224 } 225 error("Illegal option -%c", flag); 226} 227 228 229 230#ifdef mkinit 231INCLUDE "options.h" 232 233SHELLPROC { 234 int i; 235 236 for (i = 0; i < NOPTS; i++) 237 optlist[i].val = 0; 238 optschanged(); 239 240} 241#endif 242 243 244/* 245 * Set the shell parameters. 246 */ 247 248void 249setparam(argv) 250 char **argv; 251 { 252 char **newparam; 253 char **ap; 254 int nparam; 255 256 for (nparam = 0 ; argv[nparam] ; nparam++); 257 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 258 while (*argv) { 259 *ap++ = savestr(*argv++); 260 } 261 *ap = NULL; 262 freeparam(&shellparam); 263 shellparam.malloc = 1; 264 shellparam.nparam = nparam; 265 shellparam.p = newparam; 266 shellparam.optnext = NULL; 267} 268 269 270/* 271 * Free the list of positional parameters. 272 */ 273 274void 275freeparam(param) 276 struct shparam *param; 277 { 278 char **ap; 279 280 if (param->malloc) { 281 for (ap = param->p ; *ap ; ap++) 282 ckfree(*ap); 283 ckfree(param->p); 284 } 285} 286 287 288 289/* 290 * The shift builtin command. 291 */ 292 293shiftcmd(argc, argv) char **argv; { 294 int n; 295 char **ap1, **ap2; 296 297 n = 1; 298 if (argc > 1) 299 n = number(argv[1]); 300 if (n > shellparam.nparam) 301 error("can't shift that many"); 302 INTOFF; 303 shellparam.nparam -= n; 304 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 305 if (shellparam.malloc) 306 ckfree(*ap1); 307 } 308 ap2 = shellparam.p; 309 while ((*ap2++ = *ap1++) != NULL); 310 shellparam.optnext = NULL; 311 INTON; 312 return 0; 313} 314 315 316 317/* 318 * The set command builtin. 319 */ 320 321setcmd(argc, argv) char **argv; { 322 if (argc == 1) 323 return showvarscmd(argc, argv); 324 INTOFF; 325 options(0); 326 optschanged(); 327 if (*argptr != NULL) { 328 setparam(argptr); 329 } 330 INTON; 331 return 0; 332} 333 334 335/* 336 * The getopts builtin. Shellparam.optnext points to the next argument 337 * to be processed. Shellparam.optptr points to the next character to 338 * be processed in the current argument. If shellparam.optnext is NULL, 339 * then it's the first time getopts has been called. 340 */ 341 342getoptscmd(argc, argv) char **argv; { 343 register char *p, *q; 344 char c; 345 char s[10]; 346 347 if (argc != 3) 348 error("Usage: getopts optstring var"); 349 if (shellparam.optnext == NULL) { 350 shellparam.optnext = shellparam.p; 351 shellparam.optptr = NULL; 352 } 353 if ((p = shellparam.optptr) == NULL || *p == '\0') { 354 p = *shellparam.optnext; 355 if (p == NULL || *p != '-' || *++p == '\0') { 356atend: 357 fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 358 setvar("OPTIND", s, 0); 359 shellparam.optnext = NULL; 360 return 1; 361 } 362 shellparam.optnext++; 363 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 364 goto atend; 365 } 366 c = *p++; 367 for (q = argv[1] ; *q != c ; ) { 368 if (*q == '\0') { 369 out1fmt("Illegal option -%c\n", c); 370 c = '?'; 371 goto out; 372 } 373 if (*++q == ':') 374 q++; 375 } 376 if (*++q == ':') { 377 if (*p == '\0' && (p = *shellparam.optnext++) == NULL) { 378 out1fmt("No arg for -%c option\n", c); 379 c = '?'; 380 goto out; 381 } 382 setvar("OPTARG", p, 0); 383 p = NULL; 384 } 385out: 386 shellparam.optptr = p; 387 s[0] = c; 388 s[1] = '\0'; 389 setvar(argv[2], s, 0); 390 return 0; 391} 392 393/* 394 * XXX - should get rid of. have all builtins use getopt(3). the 395 * library getopt must have the BSD extension static variable "optreset" 396 * otherwise it can't be used within the shell safely. 397 * 398 * Standard option processing (a la getopt) for builtin routines. The 399 * only argument that is passed to nextopt is the option string; the 400 * other arguments are unnecessary. It return the character, or '\0' on 401 * end of input. 402 */ 403 404int 405nextopt(optstring) 406 char *optstring; 407 { 408 register char *p, *q; 409 char c; 410 411 if ((p = optptr) == NULL || *p == '\0') { 412 p = *argptr; 413 if (p == NULL || *p != '-' || *++p == '\0') 414 return '\0'; 415 argptr++; 416 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 417 return '\0'; 418 } 419 c = *p++; 420 for (q = optstring ; *q != c ; ) { 421 if (*q == '\0') 422 error("Illegal option -%c", c); 423 if (*++q == ':') 424 q++; 425 } 426 if (*++q == ':') { 427 if (*p == '\0' && (p = *argptr++) == NULL) 428 error("No arg for -%c option", c); 429 optarg = p; 430 p = NULL; 431 } 432 optptr = p; 433 return c; 434} 435