1 /* 2 3 * Copyright (c) 1984, 1985, 1986 AT&T 4 * All Rights Reserved 5 6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE 7 * CODE OF AT&T. 8 * The copyright notice above does not 9 * evidence any actual or intended 10 * publication of such source code. 11 12 */ 13 /* @(#)args.c 1.1 */ 14 /* 15 * UNIX shell 16 * 17 * S. R. Bourne 18 * Rewritten by David Korn 19 * AT&T Bell Laboratories 20 * 21 */ 22 23 #include "flags.h" 24 #include "defs.h" 25 #include "sym.h" 26 #include "mode.h" 27 #include "name.h" 28 #include "io.h" 29 #include "builtins.h" 30 #include "brkincr.h" 31 #include "stak.h" 32 #ifdef DEVFD 33 # ifdef JOBS 34 #include "jobs.h" 35 # endif /* JOBS */ 36 #endif /* DEVFD */ 37 38 39 void arg_set(); 40 void arg_reset(); 41 void arg_clear(); 42 DOLPTR arg_free(); 43 DOLPTR arg_use(); 44 DOLPTR arg_new(); 45 int arg_opts(); 46 char **arg_build(); 47 char *arg_dolminus(); 48 #ifdef DEVFD 49 void close_pipes(); 50 #endif /* DEVFD */ 51 52 extern char *malloc(); 53 extern char *macro(); 54 extern char *movstr(); 55 extern char *strchr(); 56 extern char *itos(); 57 extern void assign(); 58 extern void failed(); 59 extern void chkpipe(); 60 extern void exitsh(); 61 extern void free(); 62 extern void gsort(); 63 extern void trim(); 64 extern void p_str(); 65 extern void p_nchr(); 66 extern void p_setout(); 67 extern char *qvalup(); 68 69 static int arg_expand(); 70 static DOLPTR copyargs(); 71 static void print_opts(); 72 static int split(); 73 74 static char *null; 75 static DOLPTR argfor; /* linked list of blocks to be cleaned up */ 76 static DOLPTR dolh; 77 static char flagadr[12]; 78 static const char flagchar[] = 79 { 80 'i', 'n', 'v', 't', 's', 'x', 'e', 'r', 'k', 81 'u', 'f', 'a', 'm', 'h', 'p', 'c', 0 82 }; 83 static const optflag flagval[] = 84 { 85 INTFLG, NOEXEC, READPR, ONEFLG, STDFLG, EXECPR, ERRFLG, RSHFLG, KEYFLG, 86 NOSET, NOGLOB, ALLEXP, MONITOR, HASHALL, PRIVM, CFLAG, 0 87 }; 88 89 /* ======== option handling ======== */ 90 91 /* 92 * This routine turns options on and off 93 * The options "sicr" are illegal from set command. 94 * The -o option is used to set option by name 95 * This routine returns the number of non-option arguments 96 */ 97 98 int arg_opts(argc,argv) 99 char **argv; 100 int argc; 101 { 102 register char *cp; 103 register int c; 104 register char **argp=argv; 105 register char *flagc; 106 register optflag newflags=flags; 107 register optflag opt; 108 char minus; 109 int sort = 0; 110 int setflag = eq(*argp,bset); 111 while((cp= *++argp) && ((c= *cp) == '-' || c=='+')) 112 { 113 minus = (c == '-'); 114 argc--; 115 if((c= *++cp)==0) 116 { 117 newflags &= ~(EXECPR|READPR); 118 argp++; 119 break; 120 } 121 else if(c == '-') 122 { 123 if(setflag) 124 states |= RWAIT; 125 argp++; 126 break; 127 } 128 while(c= *cp++) 129 { 130 if(setflag) 131 { 132 if(c=='s') 133 { 134 sort++; 135 continue; 136 } 137 else if(strchr("icr",c)) 138 failed(argv[1], badopt); 139 } 140 if(c=='c' && minus && argc>=2 && comdiv==0) 141 { 142 comdiv= *++argp; 143 argc--; 144 newflags |= CFLAG; 145 continue; 146 } 147 if(flagc=strchr(flagchar,c)) 148 opt = flagval[flagc-flagchar]; 149 else if(c != 'o') 150 failed(argv[1],badopt); 151 else 152 { 153 argp++; 154 if(*argp==NULL) 155 { 156 print_opts(newflags); 157 argp--; 158 continue; 159 } 160 else 161 { 162 argc--; 163 c=syslook(*argp,option_flags); 164 opt = 1L<<c; 165 if(opt&(1|INTFLG|RSHFLG)) 166 failed(*argp,badopt); 167 } 168 } 169 if(minus) 170 { 171 #if ESH || VSH 172 if(opt&(EDITVI|EMACS|GMACS)) 173 newflags &= ~ (EDITVI|EMACS|GMACS); 174 #endif 175 newflags |= opt; 176 } 177 else 178 newflags &= ~opt; 179 } 180 } 181 /* cannot set -n for interactive shells since there is no way out */ 182 if(is_option(INTFLG)) 183 newflags &= ~NOEXEC; 184 #ifdef RAWONLY 185 if(is_option(EDITVI)) 186 newflags |= VIRAW; 187 #endif /* RAWONLY */ 188 if(sort) 189 { 190 if(argc>1) 191 gsort(argp,argc-1); 192 else 193 gsort(dolv+1,dolc); 194 } 195 if((newflags&PRIVM) && !is_option(PRIVM)) 196 assign(PATHNOD,defpath); 197 flags = newflags; 198 return(argc); 199 } 200 201 /* 202 * returns the value of $- 203 */ 204 205 char *arg_dolminus() 206 { 207 register char *flagc=flagchar; 208 register char *flagp=flagadr; 209 while(*flagc) 210 { 211 if(flags&flagval[flagc-flagchar]) 212 *flagp++ = *flagc; 213 flagc++; 214 } 215 *flagp++=0; 216 return(flagadr); 217 } 218 219 /* 220 * set up positional parameters 221 */ 222 223 void arg_set(argi) 224 char *argi[]; 225 { 226 register char **argp=argi; 227 register int size = 0; /* count number of bytes needed for strings */ 228 register int argn=0; 229 register char *cp; 230 /* count args and number of bytes of arglist */ 231 while((cp=(char*)*argp++) != ENDARGS) 232 { 233 size += strlen(cp); 234 } 235 /* free old ones unless on for loop chain */ 236 argn = argp - argi; 237 arg_free(dolh,0); 238 dolh=copyargs(argi, --argn, size); 239 dolc=argn-1; 240 } 241 242 /* 243 * free the argument list if the use count is 1 244 * If count is greater than 1 decrement count and return same blk 245 * Free the argument list if the use count is 1 and return next blk 246 * Delete the blk from the argfor chain 247 * If flag is set, then the block dolh is not freed 248 */ 249 250 DOLPTR arg_free(blk,flag) 251 DOLPTR blk; 252 { 253 register DOLPTR argr=blk; 254 register DOLPTR argblk; 255 if(argblk=argr) 256 { 257 if((--argblk->doluse)==0) 258 { 259 if(flag && argblk==dolh) 260 dolh->doluse = 1; 261 else 262 { 263 /* delete from chain */ 264 if(argfor == argblk) 265 argfor = argblk->dolnxt; 266 else 267 { 268 for(argr=argfor;argr;argr=argr->dolnxt) 269 if(argr->dolnxt==argblk) 270 break; 271 if(argr==0) 272 { 273 return(NULL); 274 } 275 argr->dolnxt = argblk->dolnxt; 276 } 277 free((char*)argblk); 278 } 279 argr = argblk->dolnxt; 280 } 281 } 282 return(argr); 283 } 284 285 /* 286 * grab space for arglist and link argblock for cleanup 287 * The strings are copied after the argment vector 288 */ 289 290 static DOLPTR copyargs(from, n, size) 291 char *from[]; 292 { 293 register DOLPTR dp=(DOLPTR)malloc((unsigned)(DOLTYPE + n*sizeof(char*) + size + n)); 294 register char **pp; 295 register char *sp; 296 dp->doluse=1; /* use count */ 297 /* link into chain */ 298 dp->dolnxt = argfor; 299 argfor = dp; 300 pp= dp->dolarg; 301 dolv=pp; 302 sp = (char*)dp + DOLTYPE + n*sizeof(char*); 303 while(n--) 304 { 305 *pp++ = sp; 306 sp = movstr(*from++,sp) + 1; 307 } 308 *pp = ENDARGS; 309 return(dp); 310 } 311 312 /* 313 * used to set new argument chain for functions 314 */ 315 316 DOLPTR arg_new(argi,savargfor) 317 char *argi[]; 318 DOLPTR *savargfor; 319 { 320 register DOLPTR olddolh = dolh; 321 *savargfor = argfor; 322 dolh = NULL; 323 argfor = NULL; 324 arg_set(argi); 325 return(olddolh); 326 } 327 328 /* 329 * reset arguments as they were before function 330 */ 331 332 void arg_reset(blk,afor) 333 DOLPTR blk; 334 DOLPTR afor; 335 { 336 while(argfor=arg_free(argfor,0)); 337 dolh = blk; 338 argfor = afor; 339 } 340 341 void arg_clear() 342 { 343 /* force `for' $* lists to go away */ 344 while(argfor=arg_free(argfor,1)); 345 /* clean up io files */ 346 argfor = dolh; 347 while(pop(0)); 348 #ifdef DEVFD 349 close_pipes(); 350 #endif /* DEVFD */ 351 } 352 353 /* 354 * increase the use count so that an arg_set will not make it go away 355 */ 356 357 DOLPTR arg_use() 358 { 359 register DOLPTR dh; 360 if(dh=dolh) 361 dh->doluse++; 362 return(dh); 363 } 364 365 /* 366 * Print option settings on standard output 367 */ 368 369 static void print_opts(oflags) 370 #ifndef pdp11 371 register 372 #endif /* pdp11 */ 373 optflag oflags; 374 { 375 register SYSPTR syscan = option_flags; 376 #ifndef pdp11 377 register 378 #endif /* pdp11 */ 379 optflag value; 380 p_setout(standout); 381 p_str(opt_heading,NL); 382 while(value=syscan->sysval) 383 { 384 value = 1<<value; 385 p_str(syscan->sysnam,SP); 386 p_nchr(SP,16-strlen(syscan->sysnam)); 387 if(oflags&value) 388 p_str(on_,NL); 389 else 390 p_str(off_,NL); 391 syscan++; 392 } 393 } 394 395 396 /* 397 * build an argument list 398 */ 399 400 char **arg_build(nargs,comptr) 401 int *nargs; 402 COMPTR comptr; 403 { 404 register ARGPTR argp; 405 { 406 register COMPTR ac = comptr; 407 register ARGPTR schain; 408 /* see if the arguments have already been expanded */ 409 if(ac->comarg==NULL) 410 { 411 *nargs = 0; 412 return(&null); 413 } 414 else if((ac->comtyp&COMSCAN)==0) 415 { 416 *nargs = ((DOLPTR)ac->comarg)->doluse; 417 return(((DOLPTR)ac->comarg)->dolarg+1); 418 } 419 schain = gchain; 420 gchain = NULL; 421 *nargs = arg_expand(ac); 422 argp = gchain; 423 gchain = schain; 424 } 425 { 426 register char **comargn; 427 register int argn; 428 register char **comargm; 429 argn = *nargs; 430 argn++; /* allow room to prepend interpreter name */ 431 comargn=(char **) getstak(BYTESPERWORD*argn+BYTESPERWORD); 432 comargm = comargn += argn; 433 *comargn = ENDARGS; 434 while(argp) 435 { 436 *--comargn = argp->argval; 437 if((argp->argflag&A_RAW)==0) 438 trim(*comargn); 439 if((argp=argp->argchn)==0 || (argp->argflag&A_MAKE)) 440 { 441 if((argn=comargm-comargn)>1) 442 gsort(comargn,argn); 443 comargm = comargn; 444 } 445 } 446 return(comargn); 447 } 448 } 449 450 #ifdef DEVFD 451 static FILE *to_close[15]; 452 453 void close_pipes() 454 { 455 register FILE **fd = to_close; 456 while(*fd) 457 { 458 fclose(*fd); 459 *fd++ = NULL; 460 } 461 } 462 #endif /* DEVFD */ 463 464 /* Argument list generation */ 465 466 static int arg_expand(ac) 467 COMPTR ac; 468 { 469 register ARGPTR argp; 470 register int count=0; 471 #ifdef DEVFD 472 int indx = 0; 473 close_pipes(); 474 #endif /* DEVFD */ 475 if(ac) 476 { 477 argp = ac->comarg; 478 while(argp) 479 { 480 argp->argflag &= ~A_MAKE; 481 #ifdef DEVFD 482 if(*argp->argval==0 && (argp->argflag&A_EXP)) 483 { 484 /* argument of the form (cmd) */ 485 register ARGPTR ap; 486 char *cp; 487 FILE *pv[2]; 488 int fd; 489 ap = (ARGPTR)locstak(); 490 ap->argflag |= A_MAKE; 491 ap->argflag &= ~A_RAW; 492 ap->argchn= gchain; 493 gchain = ap; 494 count++; 495 cp = movstr(devfd,ap->argval); 496 chkpipe(pv); 497 fd = argp->argflag&A_RAW; 498 endstak(movstr(itos(fileno(pv[fd])),cp)); 499 if(fd) 500 execute((TREPTR)argp->argchn,states&ERRFLG,pv,(FILE**)0); 501 else 502 execute((TREPTR)argp->argchn,states&ERRFLG,(FILE**)0,pv); 503 #ifdef JOBS 504 jobstat.j_flag++; 505 #endif /* JOBS */ 506 fclose(pv[1-fd]); 507 to_close[indx++] = pv[fd]; 508 } 509 else 510 #endif /* DEVFD */ 511 if((argp->argflag&A_RAW)==0) 512 { 513 register char *ap; ap = argp->argval; 514 if(argp->argflag&A_MAC) 515 ap = macro(ap); 516 count += split(ap,argp->argflag&A_MAC); 517 } 518 else 519 { 520 argp->argchn= gchain; 521 gchain = argp; 522 argp->argflag |= A_MAKE; 523 count++; 524 } 525 argp = argp->argnxt; 526 } 527 } 528 return(count); 529 } 530 531 static int split(s,macflg) /* blank interpretation routine */ 532 char *s; 533 { 534 register char *argp; 535 register int c; 536 register ARGPTR ap; 537 int count=0; 538 int expflag = (is_option(NOGLOB)==0); 539 char *seps = (macflg?qvalup(IFSNOD):NULL); 540 if(seps==NULL || *seps==0) 541 seps = sptbnl; 542 while(1) 543 { 544 if(trapnote&SIGSET) 545 exitsh(SIGFAIL); 546 ap = (ARGPTR)locstak(); 547 argp = ap->argval; 548 while(c= *s++) 549 { 550 if(c == ESCAPE) 551 { 552 c = *s++; 553 if(c!='/') 554 *argp++ = ESCAPE; 555 } 556 else if(strchr(seps,c)) 557 break; 558 if(argp >= brkend) 559 setbrk(BRKINCR); 560 *argp++ = c; 561 } 562 /* This allows contiguous visible delimiters to count as delimiters */ 563 if(argp==ap->argval) 564 { 565 if(c==0) 566 return(count); 567 if(macflg==0 || strchr(sptbnl,c)) 568 continue; 569 } 570 else if(c==0) 571 { 572 s--; 573 } 574 /* file name generation */ 575 endstak(argp); 576 ap->argflag &= ~(A_RAW|A_MAKE); 577 if(expflag && (c=expand(ap->argval,0))) 578 count += c; 579 else 580 { 581 count++; 582 ap->argchn= gchain; 583 gchain = ap; 584 } 585 gchain->argflag |= A_MAKE; 586 } 587 } 588