1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 5.2 (Berkeley) 3/13/91";*/ 39 static char rcsid[] = "$Id: options.c,v 1.4 1993/08/01 18:58:04 mycroft 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 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 #else 70 STATIC void options(); 71 STATIC void setoption(); 72 #endif 73 74 75 76 /* 77 * Process the shell command line arguments. 78 */ 79 80 void 81 procargs(argc, argv) 82 char **argv; 83 { 84 char *p; 85 86 argptr = argv; 87 if (argc > 0) 88 argptr++; 89 for (p = optval ; p < optval + sizeof optval - 1 ; p++) 90 *p = 2; 91 options(1); 92 if (*argptr == NULL && minusc == NULL) 93 sflag = 1; 94 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 95 iflag = 1; 96 if (jflag == 2) 97 jflag = iflag; 98 for (p = optval ; p < optval + sizeof optval - 1 ; p++) 99 if (*p == 2) 100 *p = 0; 101 arg0 = argv[0]; 102 if (sflag == 0 && minusc == NULL) { 103 commandname = arg0 = *argptr++; 104 setinputfile(commandname, 0); 105 } 106 shellparam.p = argptr; 107 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 108 while (*argptr) { 109 shellparam.nparam++; 110 argptr++; 111 } 112 setinteractive(iflag); 113 setjobctl(jflag); 114 } 115 116 117 118 /* 119 * Process shell options. The global variable argptr contains a pointer 120 * to the argument list; we advance it past the options. 121 */ 122 123 STATIC void 124 options(cmdline) { 125 register char *p; 126 int val; 127 int c; 128 129 if (cmdline) 130 minusc = NULL; 131 while ((p = *argptr) != NULL) { 132 argptr++; 133 if ((c = *p++) == '-') { 134 val = 1; 135 if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { 136 if (!cmdline) { 137 /* "-" means turn off -x and -v */ 138 if (p[0] == '\0') 139 xflag = vflag = 0; 140 /* "--" means reset params */ 141 else if (*argptr == NULL) 142 setparam(argptr); 143 } 144 break; /* "-" or "--" terminates options */ 145 } 146 } else if (c == '+') { 147 val = 0; 148 } else { 149 argptr--; 150 break; 151 } 152 while ((c = *p++) != '\0') { 153 if (c == 'c' && cmdline) { 154 char *q; 155 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 156 if (*p == '\0') 157 #endif 158 q = *argptr++; 159 if (q == NULL || minusc != NULL) 160 error("Bad -c option"); 161 minusc = q; 162 #ifdef NOHACK 163 break; 164 #endif 165 } else { 166 setoption(c, val); 167 } 168 } 169 if (! cmdline) 170 break; 171 } 172 } 173 174 175 STATIC void 176 setoption(flag, val) 177 char flag; 178 int val; 179 { 180 register char *p; 181 182 if ((p = strchr(optchar, flag)) == NULL) 183 error("Illegal option -%c", flag); 184 optval[p - optchar] = val; 185 } 186 187 188 189 #ifdef mkinit 190 INCLUDE "options.h" 191 192 SHELLPROC { 193 char *p; 194 195 for (p = optval ; p < optval + sizeof optval ; p++) 196 *p = 0; 197 } 198 #endif 199 200 201 /* 202 * Set the shell parameters. 203 */ 204 205 void 206 setparam(argv) 207 char **argv; 208 { 209 char **newparam; 210 char **ap; 211 int nparam; 212 213 for (nparam = 0 ; argv[nparam] ; nparam++); 214 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 215 while (*argv) { 216 *ap++ = savestr(*argv++); 217 } 218 *ap = NULL; 219 freeparam(&shellparam); 220 shellparam.malloc = 1; 221 shellparam.nparam = nparam; 222 shellparam.p = newparam; 223 shellparam.optnext = NULL; 224 } 225 226 227 /* 228 * Free the list of positional parameters. 229 */ 230 231 void 232 freeparam(param) 233 struct shparam *param; 234 { 235 char **ap; 236 237 if (param->malloc) { 238 for (ap = param->p ; *ap ; ap++) 239 ckfree(*ap); 240 ckfree(param->p); 241 } 242 } 243 244 245 246 /* 247 * The shift builtin command. 248 */ 249 250 shiftcmd(argc, argv) char **argv; { 251 int n; 252 char **ap1, **ap2; 253 254 n = 1; 255 if (argc > 1) 256 n = number(argv[1]); 257 if (n > shellparam.nparam) 258 n = shellparam.nparam; 259 INTOFF; 260 shellparam.nparam -= n; 261 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 262 if (shellparam.malloc) 263 ckfree(*ap1); 264 } 265 ap2 = shellparam.p; 266 while ((*ap2++ = *ap1++) != NULL); 267 shellparam.optnext = NULL; 268 INTON; 269 return 0; 270 } 271 272 273 274 /* 275 * The set command builtin. 276 */ 277 278 setcmd(argc, argv) char **argv; { 279 if (argc == 1) 280 return showvarscmd(argc, argv); 281 INTOFF; 282 options(0); 283 setinteractive(iflag); 284 setjobctl(jflag); 285 if (*argptr != NULL) { 286 setparam(argptr); 287 } 288 INTON; 289 return 0; 290 } 291 292 293 /* 294 * The getopts builtin. Shellparam.optnext points to the next argument 295 * to be processed. Shellparam.optptr points to the next character to 296 * be processed in the current argument. If shellparam.optnext is NULL, 297 * then it's the first time getopts has been called. 298 */ 299 300 getoptscmd(argc, argv) char **argv; { 301 register char *p, *q; 302 char c; 303 char s[10]; 304 305 if (argc != 3) 306 error("Usage: getopts optstring var"); 307 if (shellparam.optnext == NULL) { 308 shellparam.optnext = shellparam.p; 309 shellparam.optptr = NULL; 310 } 311 if ((p = shellparam.optptr) == NULL || *p == '\0') { 312 p = *shellparam.optnext; 313 if (p == NULL || *p != '-' || *++p == '\0') { 314 atend: 315 fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 316 setvar("OPTIND", s, 0); 317 shellparam.optnext = NULL; 318 return 1; 319 } 320 shellparam.optnext++; 321 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 322 goto atend; 323 } 324 c = *p++; 325 for (q = argv[1] ; *q != c ; ) { 326 if (*q == '\0') { 327 out1fmt("Illegal option -%c\n", c); 328 c = '?'; 329 goto out; 330 } 331 if (*++q == ':') 332 q++; 333 } 334 if (*++q == ':') { 335 if (*p == '\0' && (p = *shellparam.optnext) == NULL) { 336 out1fmt("No arg for -%c option\n", c); 337 c = '?'; 338 goto out; 339 } 340 shellparam.optnext++; 341 setvar("OPTARG", p, 0); 342 p = NULL; 343 } 344 out: 345 shellparam.optptr = p; 346 s[0] = c; 347 s[1] = '\0'; 348 setvar(argv[2], s, 0); 349 return 0; 350 } 351 352 /* 353 * Standard option processing (a la getopt) for builtin routines. The 354 * only argument that is passed to nextopt is the option string; the 355 * other arguments are unnecessary. It return the character, or '\0' on 356 * end of input. 357 */ 358 359 int 360 nextopt(optstring) 361 char *optstring; 362 { 363 register char *p, *q; 364 char c; 365 366 if ((p = optptr) == NULL || *p == '\0') { 367 p = *argptr; 368 if (p == NULL || *p != '-' || *++p == '\0') 369 return '\0'; 370 argptr++; 371 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 372 return '\0'; 373 } 374 c = *p++; 375 for (q = optstring ; *q != c ; ) { 376 if (*q == '\0') 377 error("Illegal option -%c", c); 378 if (*++q == ':') 379 q++; 380 } 381 if (*++q == ':') { 382 if (*p == '\0' && (p = *argptr++) == NULL) 383 error("No arg for -%c option", c); 384 optarg = p; 385 p = NULL; 386 } 387 optptr = p; 388 return c; 389 } 390