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