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