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