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$ 37 */ 38 39 #ifndef lint 40 static char sccsid[] = "@(#)options.c 8.1 (Berkeley) 5/31/93"; 41 #endif /* not lint */ 42 43 #include "shell.h" 44 #define DEFINE_OPTIONS 45 #include "options.h" 46 #undef DEFINE_OPTIONS 47 #include "nodes.h" /* for other header files */ 48 #include "eval.h" 49 #include "jobs.h" 50 #include "input.h" 51 #include "output.h" 52 #include "trap.h" 53 #include "var.h" 54 #include "memalloc.h" 55 #include "error.h" 56 #include "mystring.h" 57 58 char *arg0; /* value of $0 */ 59 struct shparam shellparam; /* current positional parameters */ 60 char **argptr; /* argument list for builtin commands */ 61 char *optarg; /* set by nextopt (like getopt) */ 62 char *optptr; /* used by nextopt */ 63 64 char *minusc; /* argument to -c option */ 65 66 67 #ifdef __STDC__ 68 STATIC void options(int); 69 STATIC void setoption(int, int); 70 STATIC void minus_o(char *, int); 71 #else 72 STATIC void options(); 73 STATIC void setoption(); 74 STATIC void minus_o(); 75 #endif 76 77 78 79 /* 80 * Process the shell command line arguments. 81 */ 82 83 void 84 procargs(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 119 optschanged() { 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 130 STATIC void 131 options(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 183 STATIC void 184 minus_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 206 STATIC void 207 setoption(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 231 INCLUDE "options.h" 232 233 SHELLPROC { 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 248 void 249 setparam(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 274 void 275 freeparam(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 293 shiftcmd(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 321 setcmd(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 342 getoptscmd(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') { 356 atend: 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 shellparam.optnext++; 383 setvar("OPTARG", p, 0); 384 p = NULL; 385 } 386 out: 387 shellparam.optptr = p; 388 s[0] = c; 389 s[1] = '\0'; 390 setvar(argv[2], s, 0); 391 return 0; 392 } 393 394 /* 395 * XXX - should get rid of. have all builtins use getopt(3). the 396 * library getopt must have the BSD extension static variable "optreset" 397 * otherwise it can't be used within the shell safely. 398 * 399 * Standard option processing (a la getopt) for builtin routines. The 400 * only argument that is passed to nextopt is the option string; the 401 * other arguments are unnecessary. It return the character, or '\0' on 402 * end of input. 403 */ 404 405 int 406 nextopt(optstring) 407 char *optstring; 408 { 409 register char *p, *q; 410 char c; 411 412 if ((p = optptr) == NULL || *p == '\0') { 413 p = *argptr; 414 if (p == NULL || *p != '-' || *++p == '\0') 415 return '\0'; 416 argptr++; 417 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 418 return '\0'; 419 } 420 c = *p++; 421 for (q = optstring ; *q != c ; ) { 422 if (*q == '\0') 423 error("Illegal option -%c", c); 424 if (*++q == ':') 425 q++; 426 } 427 if (*++q == ':') { 428 if (*p == '\0' && (p = *argptr++) == NULL) 429 error("No arg for -%c option", c); 430 optarg = p; 431 p = NULL; 432 } 433 optptr = p; 434 return c; 435 } 436