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