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