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