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 37 #ifndef lint 38 /*static char sccsid[] = "from: @(#)options.c 8.1 (Berkeley) 5/31/93";*/ 39 static char *rcsid = "$Id: options.c,v 1.10 1994/12/05 19:07:46 cgd Exp $"; 40 #endif /* not lint */ 41 42 #include "shell.h" 43 #define DEFINE_OPTIONS 44 #include "options.h" 45 #undef DEFINE_OPTIONS 46 #include "nodes.h" /* for other header files */ 47 #include "eval.h" 48 #include "jobs.h" 49 #include "input.h" 50 #include "output.h" 51 #include "trap.h" 52 #include "var.h" 53 #include "memalloc.h" 54 #include "error.h" 55 #include "mystring.h" 56 #include "extern.h" 57 #include <unistd.h> 58 59 char *arg0; /* value of $0 */ 60 struct shparam shellparam; /* current positional parameters */ 61 char **argptr; /* argument list for builtin commands */ 62 char *optarg; /* set by nextopt (like getopt) */ 63 char *optptr; /* used by nextopt */ 64 65 char *minusc; /* argument to -c option */ 66 67 68 #ifdef __STDC__ 69 STATIC void options(int); 70 STATIC void setoption(int, int); 71 STATIC void minus_o(char *, int); 72 #else 73 STATIC void options(); 74 STATIC void setoption(); 75 STATIC void minus_o(); 76 #endif 77 78 79 80 /* 81 * Process the shell command line arguments. 82 */ 83 84 void 85 procargs(argc, argv) 86 int argc; 87 char **argv; 88 { 89 int i; 90 91 argptr = argv; 92 if (argc > 0) 93 argptr++; 94 for (i = 0; i < NOPTS; i++) 95 optlist[i].val = 2; 96 options(1); 97 if (*argptr == NULL && minusc == NULL) 98 sflag = 1; 99 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 100 iflag = 1; 101 if (mflag == 2) 102 mflag = iflag; 103 for (i = 0; i < NOPTS; i++) 104 if (optlist[i].val == 2) 105 optlist[i].val = 0; 106 arg0 = argv[0]; 107 if (sflag == 0 && minusc == NULL) { 108 commandname = arg0 = *argptr++; 109 setinputfile(commandname, 0); 110 } 111 shellparam.p = argptr; 112 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 113 while (*argptr) { 114 shellparam.nparam++; 115 argptr++; 116 } 117 optschanged(); 118 } 119 120 121 void 122 optschanged() 123 { 124 setinteractive(iflag); 125 #ifndef NO_HISTORY 126 histedit(); 127 #endif 128 setjobctl(mflag); 129 } 130 131 /* 132 * Process shell options. The global variable argptr contains a pointer 133 * to the argument list; we advance it past the options. 134 */ 135 136 STATIC void 137 options(cmdline) 138 int cmdline; 139 { 140 register char *p; 141 int val; 142 int c; 143 144 if (cmdline) 145 minusc = NULL; 146 while ((p = *argptr) != NULL) { 147 argptr++; 148 if ((c = *p++) == '-') { 149 val = 1; 150 if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 151 if (!cmdline) { 152 /* "-" means turn off -x and -v */ 153 if (p[0] == '\0') 154 xflag = vflag = 0; 155 /* "--" means reset params */ 156 else if (*argptr == NULL) 157 setparam(argptr); 158 } 159 break; /* "-" or "--" terminates options */ 160 } 161 } else if (c == '+') { 162 val = 0; 163 } else { 164 argptr--; 165 break; 166 } 167 while ((c = *p++) != '\0') { 168 if (c == 'c' && cmdline) { 169 char *q; 170 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 171 if (*p == '\0') 172 #endif 173 q = *argptr++; 174 if (q == NULL || minusc != NULL) 175 error("Bad -c option"); 176 minusc = q; 177 #ifdef NOHACK 178 break; 179 #endif 180 } else if (c == 'o') { 181 minus_o(*argptr, val); 182 if (*argptr) 183 argptr++; 184 } else { 185 setoption(c, val); 186 } 187 } 188 } 189 } 190 191 STATIC void 192 minus_o(name, val) 193 char *name; 194 int val; 195 { 196 int i; 197 198 if (name == NULL) { 199 out1str("Current option settings\n"); 200 for (i = 0; i < NOPTS; i++) 201 out1fmt("%-16s%s\n", optlist[i].name, 202 optlist[i].val ? "on" : "off"); 203 } else { 204 for (i = 0; i < NOPTS; i++) 205 if (equal(name, optlist[i].name)) { 206 setoption(optlist[i].letter, val); 207 return; 208 } 209 error("Illegal option -o %s", name); 210 } 211 } 212 213 214 STATIC void 215 setoption(flag, val) 216 char flag; 217 int val; 218 { 219 int i; 220 221 for (i = 0; i < NOPTS; i++) 222 if (optlist[i].letter == flag) { 223 optlist[i].val = val; 224 if (val) { 225 /* #%$ hack for ksh semantics */ 226 if (flag == 'V') 227 Eflag = 0; 228 else if (flag == 'E') 229 Vflag = 0; 230 } 231 return; 232 } 233 error("Illegal option -%c", flag); 234 } 235 236 237 238 #ifdef mkinit 239 INCLUDE "options.h" 240 INCLUDE "extern.h" 241 242 SHELLPROC { 243 int i; 244 245 for (i = 0; i < NOPTS; i++) 246 optlist[i].val = 0; 247 optschanged(); 248 249 } 250 #endif 251 252 253 /* 254 * Set the shell parameters. 255 */ 256 257 void 258 setparam(argv) 259 char **argv; 260 { 261 char **newparam; 262 char **ap; 263 int nparam; 264 265 for (nparam = 0 ; argv[nparam] ; nparam++); 266 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 267 while (*argv) { 268 *ap++ = savestr(*argv++); 269 } 270 *ap = NULL; 271 freeparam(&shellparam); 272 shellparam.malloc = 1; 273 shellparam.nparam = nparam; 274 shellparam.p = newparam; 275 shellparam.optnext = NULL; 276 } 277 278 279 /* 280 * Free the list of positional parameters. 281 */ 282 283 void 284 freeparam(param) 285 struct shparam *param; 286 { 287 char **ap; 288 289 if (param->malloc) { 290 for (ap = param->p ; *ap ; ap++) 291 ckfree(*ap); 292 ckfree(param->p); 293 } 294 } 295 296 297 298 /* 299 * The shift builtin command. 300 */ 301 302 int 303 shiftcmd(argc, argv) 304 int argc; 305 char **argv; 306 { 307 int n; 308 char **ap1, **ap2; 309 310 n = 1; 311 if (argc > 1) 312 n = number(argv[1]); 313 if (n > shellparam.nparam) 314 error("can't shift that many"); 315 INTOFF; 316 shellparam.nparam -= n; 317 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 318 if (shellparam.malloc) 319 ckfree(*ap1); 320 } 321 ap2 = shellparam.p; 322 while ((*ap2++ = *ap1++) != NULL); 323 shellparam.optnext = NULL; 324 INTON; 325 return 0; 326 } 327 328 329 330 /* 331 * The set command builtin. 332 */ 333 334 int 335 setcmd(argc, argv) 336 int argc; 337 char **argv; 338 { 339 if (argc == 1) 340 return showvarscmd(argc, argv); 341 INTOFF; 342 options(0); 343 optschanged(); 344 if (*argptr != NULL) { 345 setparam(argptr); 346 } 347 INTON; 348 return 0; 349 } 350 351 352 /* 353 * The getopts builtin. Shellparam.optnext points to the next argument 354 * to be processed. Shellparam.optptr points to the next character to 355 * be processed in the current argument. If shellparam.optnext is NULL, 356 * then it's the first time getopts has been called. 357 */ 358 359 int 360 getoptscmd(argc, argv) 361 int argc; 362 char **argv; 363 { 364 register char *p, *q; 365 char c; 366 char s[10]; 367 368 if (argc != 3) 369 error("Usage: getopts optstring var"); 370 if (shellparam.optnext == NULL) { 371 shellparam.optnext = shellparam.p; 372 shellparam.optptr = NULL; 373 } 374 if ((p = shellparam.optptr) == NULL || *p == '\0') { 375 p = *shellparam.optnext; 376 if (p == NULL || *p != '-' || *++p == '\0') { 377 atend: 378 fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 379 setvar("OPTIND", s, 0); 380 shellparam.optnext = NULL; 381 return 1; 382 } 383 shellparam.optnext++; 384 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 385 goto atend; 386 } 387 c = *p++; 388 for (q = argv[1] ; *q != c ; ) { 389 if (*q == '\0') { 390 out1fmt("Illegal option -%c\n", c); 391 c = '?'; 392 goto out; 393 } 394 if (*++q == ':') 395 q++; 396 } 397 if (*++q == ':') { 398 if (*p == '\0' && (p = *shellparam.optnext) == NULL) { 399 out1fmt("No arg for -%c option\n", c); 400 c = '?'; 401 goto out; 402 } 403 shellparam.optnext++; 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