1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * UNIX shell 23 * 24 * S. R. Bourne 25 * Rewritten by David Korn 26 * AT&T Labs 27 * 28 */ 29 30 #include "defs.h" 31 #include "path.h" 32 #include "builtins.h" 33 #include "terminal.h" 34 #include "edit.h" 35 #include "FEATURE/poll" 36 #if SHOPT_KIA 37 # include "shlex.h" 38 # include "io.h" 39 #endif /* SHOPT_KIA */ 40 #if SHOPT_PFSH 41 # define PFSHOPT "P" 42 #else 43 # define PFSHOPT 44 #endif 45 #if SHOPT_BASH 46 # define BASHOPT "\375\374\373" 47 #else 48 # define BASHOPT 49 #endif 50 #if SHOPT_HISTEXPAND 51 # define HFLAG "H" 52 #else 53 # define HFLAG "" 54 #endif 55 56 #define SORT 1 57 #define PRINT 2 58 59 void sh_applyopts(Shopt_t); 60 61 static int arg_expand(struct argnod*,struct argnod**,int); 62 63 static char *null; 64 65 /* The following order is determined by sh_optset */ 66 static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; 67 static const int flagval[] = 68 { 69 #if SHOPT_PFSH 70 SH_PFSH, 71 #endif 72 #if SHOPT_BASH 73 SH_NOPROFILE, SH_RC, SH_POSIX, 74 #endif 75 SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG, 76 SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL, 77 SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG, 78 SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER, 79 SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, 80 #if SHOPT_HISTEXPAND 81 SH_HISTEXPAND, 82 #endif 83 0 84 }; 85 86 #define NUM_OPTS (sizeof(flagval)/sizeof(*flagval)) 87 88 typedef struct _arg_ 89 { 90 Shell_t *shp; 91 struct dolnod *argfor; /* linked list of blocks to be cleaned up */ 92 struct dolnod *dolh; 93 char flagadr[NUM_OPTS+1]; 94 #if SHOPT_KIA 95 char *kiafile; 96 #endif /* SHOPT_KIA */ 97 } Arg_t; 98 99 100 /* ======== option handling ======== */ 101 102 void *sh_argopen(Shell_t *shp) 103 { 104 void *addr = newof(0,Arg_t,1,0); 105 Arg_t *ap = (Arg_t*)addr; 106 ap->shp = shp; 107 return(addr); 108 } 109 110 static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) 111 { 112 #if SHOPT_BASH 113 extern const char sh_bash1[], sh_bash2[]; 114 if(strcmp(s,"bash1")==0) 115 { 116 if(sh_isoption(SH_BASH)) 117 sfputr(sp,sh_bash1,-1); 118 } 119 else if(strcmp(s,"bash2")==0) 120 { 121 if(sh_isoption(SH_BASH)) 122 sfputr(sp,sh_bash2,-1); 123 } 124 else if(*s==':' && sh_isoption(SH_BASH)) 125 sfputr(sp,s,-1); 126 else 127 #endif 128 if(*s!=':') 129 sfputr(sp,sh_set,-1); 130 return(1); 131 } 132 133 /* 134 * This routine turns options on and off 135 * The options "PDicr" are illegal from set command. 136 * The -o option is used to set option by name 137 * This routine returns the number of non-option arguments 138 */ 139 int sh_argopts(int argc,register char *argv[]) 140 { 141 register int n,o; 142 register Arg_t *ap = (Arg_t*)sh.arg_context; 143 Shopt_t newflags; 144 int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE); 145 Namval_t *np = NIL(Namval_t*); 146 const char *cp; 147 int verbose,f; 148 Optdisc_t disc; 149 newflags=sh.options; 150 memset(&disc, 0, sizeof(disc)); 151 disc.version = OPT_VERSION; 152 disc.infof = infof; 153 opt_info.disc = &disc; 154 155 if(argc>0) 156 setflag = 4; 157 else 158 argc = -argc; 159 while((n = optget(argv,setflag?sh_optset:sh_optksh))) 160 { 161 o=0; 162 f=*opt_info.option=='-'; 163 switch(n) 164 { 165 case 'A': 166 np = nv_open(opt_info.arg,sh.var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME); 167 if(f) 168 nv_unset(np); 169 continue; 170 #if SHOPT_BASH 171 case 'O': /* shopt options, only in bash mode */ 172 if(!sh_isoption(SH_BASH)) 173 errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name); 174 #endif 175 case 'o': /* set options */ 176 byname: 177 if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-') 178 { 179 action = PRINT; 180 /* print style: -O => shopt options 181 * bash => print unset options also, no heading 182 */ 183 verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)| 184 (n=='O'?PRINT_SHOPT:0)| 185 (sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)| 186 ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0); 187 continue; 188 } 189 o = sh_lookopt(opt_info.arg,&f); 190 if(o<=0 191 || (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA)) 192 || ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT)) 193 194 || (setflag && (o&SH_COMMANDLINE))) 195 { 196 errormsg(SH_DICT,2, e_option, opt_info.arg); 197 error_info.errors++; 198 } 199 o &= 0xff; 200 if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED) 201 errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg); 202 break; 203 #if SHOPT_BASH 204 case -1: /* --rcfile */ 205 sh.rcfile = opt_info.arg; 206 continue; 207 case -6: /* --version */ 208 sfputr(sfstdout, "ksh bash emulation, version ",-1); 209 np = nv_open("BASH_VERSION",sh.var_tree,0); 210 sfputr(sfstdout, nv_getval(np),-1); 211 np = nv_open("MACHTYPE",sh.var_tree,0); 212 sfprintf(sfstdout, " (%s)\n", nv_getval(np)); 213 sh_exit(0); 214 215 case -2: /* --noediting */ 216 off_option(&newflags,SH_VI); 217 off_option(&newflags,SH_EMACS); 218 off_option(&newflags,SH_GMACS); 219 continue; 220 221 case -3: /* --profile */ 222 f = !f; 223 /*FALLTHROUGH*/ 224 case -4: /* --rc */ 225 case -5: /* --posix */ 226 /* mask lower 8 bits to find char in optksh string */ 227 n&=0xff; 228 goto skip; 229 #endif 230 case 'D': 231 on_option(&newflags,SH_NOEXEC); 232 goto skip; 233 case 's': 234 if(setflag) 235 { 236 action = SORT; 237 continue; 238 } 239 #if SHOPT_KIA 240 goto skip; 241 case 'R': 242 if(setflag) 243 n = ':'; 244 else 245 { 246 ap->kiafile = opt_info.arg; 247 n = 'n'; 248 } 249 /* FALL THRU */ 250 #endif /* SHOPT_KIA */ 251 skip: 252 default: 253 if(cp=strchr(optksh,n)) 254 o = flagval[cp-optksh]; 255 break; 256 case ':': 257 if(opt_info.name[0]=='-'&&opt_info.name[1]=='-') 258 { 259 opt_info.arg = argv[opt_info.index-1] + 2; 260 f = 1; 261 goto byname; 262 } 263 errormsg(SH_DICT,2, "%s", opt_info.arg); 264 continue; 265 case '?': 266 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 267 return(-1); 268 } 269 if(f) 270 { 271 if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) 272 { 273 off_option(&newflags,SH_VI); 274 off_option(&newflags,SH_EMACS); 275 off_option(&newflags,SH_GMACS); 276 } 277 on_option(&newflags,o); 278 off_option(&sh.offoptions,o); 279 } 280 else 281 { 282 if(o==SH_XTRACE) 283 trace = 0; 284 off_option(&newflags,o); 285 if(setflag==0) 286 on_option(&sh.offoptions,o); 287 } 288 } 289 if(error_info.errors) 290 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 291 /* check for '-' or '+' argument */ 292 if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') && 293 strcmp(argv[opt_info.index-1],"--")) 294 { 295 opt_info.index++; 296 off_option(&newflags,SH_XTRACE); 297 off_option(&newflags,SH_VERBOSE); 298 trace = 0; 299 } 300 if(trace) 301 sh_trace(argv,1); 302 argc -= opt_info.index; 303 argv += opt_info.index; 304 if(action==PRINT) 305 sh_printopts(newflags,verbose,0); 306 if(setflag) 307 { 308 if(action==SORT) 309 { 310 if(argc>0) 311 strsort(argv,argc,strcoll); 312 else 313 strsort(sh.st.dolv+1,sh.st.dolc,strcoll); 314 } 315 if(np) 316 { 317 nv_setvec(np,0,argc,argv); 318 nv_close(np); 319 } 320 else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0)) 321 sh_argset(argv-1); 322 } 323 else if(is_option(&newflags,SH_CFLAG)) 324 { 325 if(!(sh.comdiv = *argv++)) 326 { 327 errormsg(SH_DICT,2,e_cneedsarg); 328 errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); 329 } 330 argc--; 331 } 332 /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to 333 * sh_applyopts(), so that the code can be reused from b_shopt(), too 334 */ 335 sh_applyopts(newflags); 336 #if SHOPT_KIA 337 if(ap->kiafile) 338 { 339 if(!(shlex.kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+"))) 340 errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile); 341 if(!(shlex.kiatmp=sftmp(2*SF_BUFSIZE))) 342 errormsg(SH_DICT,ERROR_system(3),e_tmpcreate); 343 sfputr(shlex.kiafile,";vdb;CIAO/ksh",'\n'); 344 shlex.kiabegin = sftell(shlex.kiafile); 345 shlex.entity_tree = dtopen(&_Nvdisc,Dtbag); 346 shlex.scriptname = strdup(sh_fmtq(argv[0])); 347 shlex.script=kiaentity(shlex.scriptname,-1,'p',-1,0,0,'s',0,""); 348 shlex.fscript=kiaentity(shlex.scriptname,-1,'f',-1,0,0,'s',0,""); 349 shlex.unknown=kiaentity("<unknown>",-1,'p',-1,0,0,'0',0,""); 350 kiaentity("<unknown>",-1,'p',0,0,shlex.unknown,'0',0,""); 351 shlex.current = shlex.script; 352 ap->kiafile = 0; 353 } 354 #endif /* SHOPT_KIA */ 355 return(argc); 356 } 357 358 /* apply new options */ 359 360 void sh_applyopts(Shopt_t newflags) 361 { 362 /* cannot set -n for interactive shells since there is no way out */ 363 if(sh_isoption(SH_INTERACTIVE)) 364 off_option(&newflags,SH_NOEXEC); 365 if(is_option(&newflags,SH_PRIVILEGED)) 366 on_option(&newflags,SH_NOUSRPROFILE); 367 if(is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED)) 368 { 369 if(sh_isoption(SH_PRIVILEGED)) 370 { 371 setuid(sh.userid); 372 setgid(sh.groupid); 373 if(sh.euserid==0) 374 { 375 sh.euserid = sh.userid; 376 sh.egroupid = sh.groupid; 377 } 378 } 379 else if((sh.userid!=sh.euserid && setuid(sh.euserid)<0) || 380 (sh.groupid!=sh.egroupid && setgid(sh.egroupid)<0) || 381 (sh.userid==sh.euserid && sh.groupid==sh.egroupid)) 382 off_option(&newflags,SH_PRIVILEGED); 383 } 384 #if SHOPT_BASH 385 on_option(&newflags,SH_CMDHIST); 386 on_option(&newflags,SH_CHECKHASH); 387 on_option(&newflags,SH_EXECFAIL); 388 on_option(&newflags,SH_EXPAND_ALIASES); 389 on_option(&newflags,SH_HISTAPPEND); 390 on_option(&newflags,SH_INTERACTIVE_COMM); 391 on_option(&newflags,SH_LITHIST); 392 on_option(&newflags,SH_NOEMPTYCMDCOMPL); 393 394 if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO)) 395 astconf("UNIVERSE", 0, "ucb"); 396 if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO)) 397 astconf("UNIVERSE", 0, "att"); 398 if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL)) 399 astconf("PATH_RESOLVE", 0, "metaphysical"); 400 if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL)) 401 astconf("PATH_RESOLVE", 0, "physical"); 402 if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2)) 403 { 404 sh_onstate(SH_HISTORY); 405 sh_onoption(SH_HISTORY); 406 } 407 if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2)) 408 { 409 sh_offstate(SH_HISTORY); 410 sh_offoption(SH_HISTORY); 411 } 412 #endif 413 sh.options = newflags; 414 } 415 /* 416 * returns the value of $- 417 */ 418 char *sh_argdolminus(void) 419 { 420 register const char *cp=optksh; 421 register Arg_t *ap = (Arg_t*)sh.arg_context; 422 register char *flagp=ap->flagadr; 423 while(cp< &optksh[NUM_OPTS]) 424 { 425 int n = flagval[cp-optksh]; 426 if(sh_isoption(n)) 427 *flagp++ = *cp; 428 cp++; 429 } 430 *flagp = 0; 431 return(ap->flagadr); 432 } 433 434 /* 435 * set up positional parameters 436 */ 437 void sh_argset(char *argv[]) 438 { 439 register Arg_t *ap = (Arg_t*)sh.arg_context; 440 sh_argfree(ap->dolh,0); 441 ap->dolh = sh_argcreate(argv); 442 /* link into chain */ 443 ap->dolh->dolnxt = ap->argfor; 444 ap->argfor = ap->dolh; 445 sh.st.dolc = ap->dolh->dolnum-1; 446 sh.st.dolv = ap->dolh->dolval; 447 } 448 449 /* 450 * free the argument list if the use count is 1 451 * If count is greater than 1 decrement count and return same blk 452 * Free the argument list if the use count is 1 and return next blk 453 * Delete the blk from the argfor chain 454 * If flag is set, then the block dolh is not freed 455 */ 456 struct dolnod *sh_argfree(struct dolnod *blk,int flag) 457 { 458 register struct dolnod* argr=blk; 459 register struct dolnod* argblk; 460 register Arg_t *ap = (Arg_t*)sh.arg_context; 461 if(argblk=argr) 462 { 463 if((--argblk->dolrefcnt)==0) 464 { 465 argr = argblk->dolnxt; 466 if(flag && argblk==ap->dolh) 467 ap->dolh->dolrefcnt = 1; 468 else 469 { 470 /* delete from chain */ 471 if(ap->argfor == argblk) 472 ap->argfor = argblk->dolnxt; 473 else 474 { 475 for(argr=ap->argfor;argr;argr=argr->dolnxt) 476 if(argr->dolnxt==argblk) 477 break; 478 if(!argr) 479 return(NIL(struct dolnod*)); 480 argr->dolnxt = argblk->dolnxt; 481 argr = argblk->dolnxt; 482 } 483 free((void*)argblk); 484 } 485 } 486 } 487 return(argr); 488 } 489 490 /* 491 * grab space for arglist and copy args 492 * The strings are copied after the argment vector 493 */ 494 struct dolnod *sh_argcreate(register char *argv[]) 495 { 496 register struct dolnod *dp; 497 register char **pp=argv, *sp; 498 register int size=0,n; 499 /* count args and number of bytes of arglist */ 500 while(sp= *pp++) 501 size += strlen(sp); 502 n = (pp - argv)-1; 503 dp=new_of(struct dolnod,n*sizeof(char*)+size+n); 504 dp->dolrefcnt=1; /* use count */ 505 dp->dolnum = n; 506 dp->dolnxt = 0; 507 pp = dp->dolval; 508 sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*); 509 while(n--) 510 { 511 *pp++ = sp; 512 sp = strcopy(sp, *argv++) + 1; 513 } 514 *pp = NIL(char*); 515 return(dp); 516 } 517 518 /* 519 * used to set new arguments for functions 520 */ 521 struct dolnod *sh_argnew(char *argi[], struct dolnod **savargfor) 522 { 523 register Arg_t *ap = (Arg_t*)sh.arg_context; 524 register struct dolnod *olddolh = ap->dolh; 525 *savargfor = ap->argfor; 526 ap->dolh = 0; 527 ap->argfor = 0; 528 sh_argset(argi); 529 return(olddolh); 530 } 531 532 /* 533 * reset arguments as they were before function 534 */ 535 void sh_argreset(struct dolnod *blk, struct dolnod *afor) 536 { 537 register Arg_t *ap = (Arg_t*)sh.arg_context; 538 while(ap->argfor=sh_argfree(ap->argfor,0)); 539 ap->argfor = afor; 540 if(ap->dolh = blk) 541 { 542 sh.st.dolc = ap->dolh->dolnum-1; 543 sh.st.dolv = ap->dolh->dolval; 544 } 545 } 546 547 /* 548 * increase the use count so that an sh_argset will not make it go away 549 */ 550 struct dolnod *sh_arguse(void) 551 { 552 register struct dolnod *dh; 553 register Arg_t *ap = (Arg_t*)sh.arg_context; 554 if(dh=ap->dolh) 555 dh->dolrefcnt++; 556 return(dh); 557 } 558 559 /* 560 * Print option settings on standard output 561 * if mode is inclusive or of PRINT_* 562 * if <mask> is set, only options with this mask value are displayed 563 */ 564 void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask) 565 { 566 register const Shtable_t *tp; 567 const char *name; 568 int on; 569 int value; 570 if(!(mode&PRINT_NO_HEADER)) 571 sfputr(sfstdout,sh_translate(e_heading),'\n'); 572 if(mode&PRINT_TABLE) 573 { 574 int w; 575 int c; 576 int r; 577 int i; 578 579 c = 0; 580 for(tp=shtab_options; value=tp->sh_number; tp++) 581 { 582 if(mask && !is_option(mask,value&0xff)) 583 continue; 584 name = tp->sh_name; 585 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 586 name += 2; 587 if(c<(w=strlen(name))) 588 c = w; 589 } 590 c += 4; 591 if((w = ed_window()) < (2*c)) 592 w = 2*c; 593 r = w / c; 594 i = 0; 595 for(tp=shtab_options; value=tp->sh_number; tp++) 596 { 597 if(mask && !is_option(mask,value&0xff)) 598 continue; 599 on = !!is_option(&oflags,value); 600 value &= 0xff; 601 name = tp->sh_name; 602 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 603 { 604 name += 2; 605 on = !on; 606 } 607 if(++i>=r) 608 { 609 i = 0; 610 sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name); 611 } 612 else 613 sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name); 614 } 615 if(i) 616 sfputc(sfstdout,'\n'); 617 return; 618 } 619 #if SHOPT_RAWONLY 620 on_option(&oflags,SH_VIRAW); 621 #endif 622 if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */ 623 { 624 if(mode&PRINT_SHOPT) 625 sfwrite(sfstdout,"shopt -s",3); 626 else 627 sfwrite(sfstdout,"set",3); 628 } 629 for(tp=shtab_options; value=tp->sh_number; tp++) 630 { 631 if(mask && !is_option(mask,value&0xff)) 632 continue; 633 if(sh_isoption(SH_BASH)) 634 { 635 if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT)) 636 continue; 637 } 638 else if (value&(SH_BASHEXTRA|SH_BASHOPT)) 639 continue; 640 on = !!is_option(&oflags,value); 641 name = tp->sh_name; 642 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 643 { 644 name += 2; 645 on = !on; 646 } 647 if(mode&PRINT_VERBOSE) 648 { 649 sfputr(sfstdout,name,' '); 650 sfnputc(sfstdout,' ',24-strlen(name)); 651 sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n'); 652 } 653 else if(mode&PRINT_ALL) /* print unset options also */ 654 { 655 if(mode&PRINT_SHOPT) 656 sfprintf(sfstdout, "shopt -%c %s\n", 657 on?'s':'u', 658 name); 659 else 660 sfprintf(sfstdout, "set %co %s\n", 661 on?'-':'+', 662 name); 663 } 664 else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff)) 665 sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name); 666 } 667 if(!(mode&(PRINT_VERBOSE|PRINT_ALL))) 668 sfputc(sfstdout,'\n'); 669 } 670 671 /* 672 * build an argument list 673 */ 674 char **sh_argbuild(int *nargs, const struct comnod *comptr,int flag) 675 { 676 register struct argnod *argp; 677 struct argnod *arghead=0; 678 sh.xargmin = 0; 679 { 680 register const struct comnod *ac = comptr; 681 register int n; 682 /* see if the arguments have already been expanded */ 683 if(!ac->comarg) 684 { 685 *nargs = 0; 686 return(&null); 687 } 688 else if(!(ac->comtyp&COMSCAN)) 689 { 690 register struct dolnod *ap = (struct dolnod*)ac->comarg; 691 *nargs = ap->dolnum; 692 ((struct comnod*)ac)->comtyp |= COMFIXED; 693 return(ap->dolval+ap->dolbot); 694 } 695 sh.lastpath = 0; 696 *nargs = 0; 697 if(ac) 698 { 699 if(ac->comnamp == SYSLET) 700 flag |= ARG_LET; 701 argp = ac->comarg; 702 while(argp) 703 { 704 n = arg_expand(argp,&arghead,flag); 705 if(n>1) 706 { 707 if(sh.xargmin==0) 708 sh.xargmin = *nargs; 709 sh.xargmax = *nargs+n; 710 } 711 *nargs += n; 712 argp = argp->argnxt.ap; 713 } 714 argp = arghead; 715 } 716 } 717 { 718 register char **comargn; 719 register int argn; 720 register char **comargm; 721 int argfixed = COMFIXED; 722 argn = *nargs; 723 /* allow room to prepend args */ 724 argn += 1; 725 726 comargn=(char**)stakalloc((unsigned)(argn+1)*sizeof(char*)); 727 comargm = comargn += argn; 728 *comargn = NIL(char*); 729 if(!argp) 730 { 731 /* reserve an extra null pointer */ 732 *--comargn = 0; 733 return(comargn); 734 } 735 while(argp) 736 { 737 struct argnod *nextarg = argp->argchn.ap; 738 argp->argchn.ap = 0; 739 *--comargn = argp->argval; 740 if(!(argp->argflag&ARG_RAW) || (argp->argflag&ARG_EXP)) 741 argfixed = 0; 742 if(!(argp->argflag&ARG_RAW)) 743 sh_trim(*comargn); 744 if(!(argp=nextarg) || (argp->argflag&ARG_MAKE)) 745 { 746 if((argn=comargm-comargn)>1) 747 strsort(comargn,argn,strcoll); 748 comargm = comargn; 749 } 750 } 751 ((struct comnod*)comptr)->comtyp |= argfixed; 752 return(comargn); 753 } 754 } 755 756 #if _pipe_socketpair && !_socketpair_devfd 757 # define sh_pipe arg_pipe 758 /* 759 * create a real pipe (not a socket) and print message on failure 760 */ 761 static int arg_pipe(register int pv[]) 762 { 763 int fd[2]; 764 if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0) 765 errormsg(SH_DICT,ERROR_system(1),e_pipe); 766 pv[0] = sh_iomovefd(pv[0]); 767 pv[1] = sh_iomovefd(pv[1]); 768 sh.fdstatus[pv[0]] = IONOSEEK|IOREAD; 769 sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE; 770 sh_subsavefd(pv[0]); 771 sh_subsavefd(pv[1]); 772 return(0); 773 } 774 #endif 775 776 /* Argument expansion */ 777 static int arg_expand(register struct argnod *argp, struct argnod **argchain,int flag) 778 { 779 register int count = 0; 780 argp->argflag &= ~ARG_MAKE; 781 #if SHOPT_DEVFD 782 if(*argp->argval==0 && (argp->argflag&ARG_EXP)) 783 { 784 /* argument of the form (cmd) */ 785 register struct argnod *ap; 786 int monitor, fd, pv[2]; 787 ap = (struct argnod*)stakseek(ARGVAL); 788 ap->argflag |= ARG_MAKE; 789 ap->argflag &= ~ARG_RAW; 790 ap->argchn.ap = *argchain; 791 *argchain = ap; 792 count++; 793 stakwrite(e_devfdNN,8); 794 sh_pipe(pv); 795 fd = argp->argflag&ARG_RAW; 796 stakputs(fmtbase((long)pv[fd],10,0)); 797 ap = (struct argnod*)stakfreeze(1); 798 sh.inpipe = sh.outpipe = 0; 799 if(monitor = (sh_isstate(SH_MONITOR)!=0)) 800 sh_offstate(SH_MONITOR); 801 if(fd) 802 { 803 sh.inpipe = pv; 804 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 805 } 806 else 807 { 808 sh.outpipe = pv; 809 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 810 } 811 if(monitor) 812 sh_onstate(SH_MONITOR); 813 close(pv[1-fd]); 814 sh_iosave(-pv[fd], sh.topfd); 815 } 816 else 817 #endif /* SHOPT_DEVFD */ 818 if(!(argp->argflag&ARG_RAW)) 819 { 820 #if SHOPT_OPTIMIZE 821 struct argnod *ap; 822 if(flag&ARG_OPTIMIZE) 823 argp->argchn.ap=0; 824 if(ap=argp->argchn.ap) 825 { 826 sh.optcount++; 827 count = 1; 828 ap->argchn.ap = *argchain; 829 ap->argflag |= ARG_RAW; 830 ap->argflag &= ~ARG_EXP; 831 *argchain = ap; 832 } 833 else 834 #endif /* SHOPT_OPTIMIZE */ 835 count = sh_macexpand(argp,argchain,flag); 836 } 837 else 838 { 839 argp->argchn.ap = *argchain; 840 *argchain = argp; 841 argp->argflag |= ARG_MAKE; 842 count++; 843 } 844 return(count); 845 } 846 847