14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * UNIX shell 234887Schin * 244887Schin * S. R. Bourne 254887Schin * Rewritten by David Korn 264887Schin * AT&T Labs 274887Schin * 284887Schin */ 294887Schin 304887Schin #include "defs.h" 314887Schin #include "path.h" 324887Schin #include "builtins.h" 334887Schin #include "terminal.h" 344887Schin #include "edit.h" 354887Schin #include "FEATURE/poll" 364887Schin #if SHOPT_KIA 374887Schin # include "shlex.h" 384887Schin # include "io.h" 394887Schin #endif /* SHOPT_KIA */ 404887Schin #if SHOPT_PFSH 414887Schin # define PFSHOPT "P" 424887Schin #else 434887Schin # define PFSHOPT 444887Schin #endif 454887Schin #if SHOPT_BASH 46*8462SApril.Chin@Sun.COM # define BASHOPT "\374" 474887Schin #else 484887Schin # define BASHOPT 494887Schin #endif 504887Schin #if SHOPT_HISTEXPAND 514887Schin # define HFLAG "H" 524887Schin #else 534887Schin # define HFLAG "" 544887Schin #endif 554887Schin 564887Schin #define SORT 1 574887Schin #define PRINT 2 584887Schin 594887Schin static char *null; 604887Schin 614887Schin /* The following order is determined by sh_optset */ 624887Schin static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; 634887Schin static const int flagval[] = 644887Schin { 654887Schin #if SHOPT_PFSH 664887Schin SH_PFSH, 674887Schin #endif 684887Schin #if SHOPT_BASH 69*8462SApril.Chin@Sun.COM SH_POSIX, 704887Schin #endif 714887Schin SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG, 724887Schin SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL, 734887Schin SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG, 744887Schin SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER, 754887Schin SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, 764887Schin #if SHOPT_HISTEXPAND 774887Schin SH_HISTEXPAND, 784887Schin #endif 794887Schin 0 804887Schin }; 814887Schin 824887Schin #define NUM_OPTS (sizeof(flagval)/sizeof(*flagval)) 834887Schin 844887Schin typedef struct _arg_ 854887Schin { 86*8462SApril.Chin@Sun.COM Shell_t *sh; 874887Schin struct dolnod *argfor; /* linked list of blocks to be cleaned up */ 884887Schin struct dolnod *dolh; 894887Schin char flagadr[NUM_OPTS+1]; 904887Schin #if SHOPT_KIA 914887Schin char *kiafile; 924887Schin #endif /* SHOPT_KIA */ 934887Schin } Arg_t; 944887Schin 95*8462SApril.Chin@Sun.COM static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int); 96*8462SApril.Chin@Sun.COM static void sh_argset(Arg_t*, char *[]); 97*8462SApril.Chin@Sun.COM 984887Schin 994887Schin /* ======== option handling ======== */ 1004887Schin 1014887Schin void *sh_argopen(Shell_t *shp) 1024887Schin { 1034887Schin void *addr = newof(0,Arg_t,1,0); 1044887Schin Arg_t *ap = (Arg_t*)addr; 105*8462SApril.Chin@Sun.COM ap->sh = shp; 1064887Schin return(addr); 1074887Schin } 1084887Schin 1094887Schin static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) 1104887Schin { 1114887Schin #if SHOPT_BASH 1124887Schin extern const char sh_bash1[], sh_bash2[]; 1134887Schin if(strcmp(s,"bash1")==0) 1144887Schin { 1154887Schin if(sh_isoption(SH_BASH)) 1164887Schin sfputr(sp,sh_bash1,-1); 1174887Schin } 1184887Schin else if(strcmp(s,"bash2")==0) 1194887Schin { 1204887Schin if(sh_isoption(SH_BASH)) 1214887Schin sfputr(sp,sh_bash2,-1); 1224887Schin } 1234887Schin else if(*s==':' && sh_isoption(SH_BASH)) 1244887Schin sfputr(sp,s,-1); 1254887Schin else 1264887Schin #endif 1274887Schin if(*s!=':') 1284887Schin sfputr(sp,sh_set,-1); 1294887Schin return(1); 1304887Schin } 1314887Schin 1324887Schin /* 1334887Schin * This routine turns options on and off 1344887Schin * The options "PDicr" are illegal from set command. 1354887Schin * The -o option is used to set option by name 1364887Schin * This routine returns the number of non-option arguments 1374887Schin */ 138*8462SApril.Chin@Sun.COM int sh_argopts(int argc,register char *argv[], void *context) 1394887Schin { 140*8462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)context; 141*8462SApril.Chin@Sun.COM register int n,o; 142*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)(shp->arg_context); 143*8462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)(shp->lex_context); 144*8462SApril.Chin@Sun.COM Shopt_t newflags; 1454887Schin int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE); 1464887Schin Namval_t *np = NIL(Namval_t*); 1474887Schin const char *cp; 1484887Schin int verbose,f; 1494887Schin Optdisc_t disc; 150*8462SApril.Chin@Sun.COM newflags=ap->sh->options; 1514887Schin memset(&disc, 0, sizeof(disc)); 1524887Schin disc.version = OPT_VERSION; 1534887Schin disc.infof = infof; 1544887Schin opt_info.disc = &disc; 1554887Schin 1564887Schin if(argc>0) 1574887Schin setflag = 4; 1584887Schin else 1594887Schin argc = -argc; 1604887Schin while((n = optget(argv,setflag?sh_optset:sh_optksh))) 1614887Schin { 1624887Schin o=0; 163*8462SApril.Chin@Sun.COM f=*opt_info.option=='-' && (opt_info.num || opt_info.arg); 1644887Schin switch(n) 1654887Schin { 1664887Schin case 'A': 167*8462SApril.Chin@Sun.COM np = nv_open(opt_info.arg,ap->sh->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME); 1684887Schin if(f) 1694887Schin nv_unset(np); 1704887Schin continue; 1714887Schin #if SHOPT_BASH 1724887Schin case 'O': /* shopt options, only in bash mode */ 1734887Schin if(!sh_isoption(SH_BASH)) 1744887Schin errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name); 1754887Schin #endif 1764887Schin case 'o': /* set options */ 1774887Schin byname: 1784887Schin if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-') 1794887Schin { 1804887Schin action = PRINT; 1814887Schin /* print style: -O => shopt options 1824887Schin * bash => print unset options also, no heading 1834887Schin */ 1844887Schin verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)| 1854887Schin (n=='O'?PRINT_SHOPT:0)| 1864887Schin (sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)| 1874887Schin ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0); 1884887Schin continue; 1894887Schin } 1904887Schin o = sh_lookopt(opt_info.arg,&f); 1914887Schin if(o<=0 1924887Schin || (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA)) 1934887Schin || ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT)) 1944887Schin 1954887Schin || (setflag && (o&SH_COMMANDLINE))) 1964887Schin { 1974887Schin errormsg(SH_DICT,2, e_option, opt_info.arg); 1984887Schin error_info.errors++; 1994887Schin } 2004887Schin o &= 0xff; 2014887Schin if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED) 2024887Schin errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg); 2034887Schin break; 2044887Schin #if SHOPT_BASH 2054887Schin case -1: /* --rcfile */ 206*8462SApril.Chin@Sun.COM ap->sh->rcfile = opt_info.arg; 2074887Schin continue; 2084887Schin case -2: /* --noediting */ 209*8462SApril.Chin@Sun.COM if (!f) 210*8462SApril.Chin@Sun.COM { 211*8462SApril.Chin@Sun.COM off_option(&newflags,SH_VI); 212*8462SApril.Chin@Sun.COM off_option(&newflags,SH_EMACS); 213*8462SApril.Chin@Sun.COM off_option(&newflags,SH_GMACS); 214*8462SApril.Chin@Sun.COM } 2154887Schin continue; 2164887Schin case -3: /* --profile */ 217*8462SApril.Chin@Sun.COM n = 'l'; 218*8462SApril.Chin@Sun.COM goto skip; 219*8462SApril.Chin@Sun.COM case -4: /* --posix */ 2204887Schin /* mask lower 8 bits to find char in optksh string */ 2214887Schin n&=0xff; 2224887Schin goto skip; 223*8462SApril.Chin@Sun.COM case -5: /* --version */ 224*8462SApril.Chin@Sun.COM sfputr(sfstdout, "ksh bash emulation, version ",-1); 225*8462SApril.Chin@Sun.COM np = nv_open("BASH_VERSION",ap->sh->var_tree,0); 226*8462SApril.Chin@Sun.COM sfputr(sfstdout, nv_getval(np),-1); 227*8462SApril.Chin@Sun.COM np = nv_open("MACHTYPE",ap->sh->var_tree,0); 228*8462SApril.Chin@Sun.COM sfprintf(sfstdout, " (%s)\n", nv_getval(np)); 229*8462SApril.Chin@Sun.COM sh_exit(0); 2304887Schin #endif 231*8462SApril.Chin@Sun.COM case -6: /* --default */ 232*8462SApril.Chin@Sun.COM { 233*8462SApril.Chin@Sun.COM register const Shtable_t *tp; 234*8462SApril.Chin@Sun.COM for(tp=shtab_options; o = tp->sh_number; tp++) 235*8462SApril.Chin@Sun.COM if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff)) 236*8462SApril.Chin@Sun.COM off_option(&newflags,o&0xff); 237*8462SApril.Chin@Sun.COM } 238*8462SApril.Chin@Sun.COM continue; 239*8462SApril.Chin@Sun.COM case -7: 240*8462SApril.Chin@Sun.COM f = 0; 241*8462SApril.Chin@Sun.COM goto byname; 2424887Schin case 'D': 2434887Schin on_option(&newflags,SH_NOEXEC); 2444887Schin goto skip; 245*8462SApril.Chin@Sun.COM case 'T': 246*8462SApril.Chin@Sun.COM if (opt_info.num) 247*8462SApril.Chin@Sun.COM ap->sh->test |= opt_info.num; 248*8462SApril.Chin@Sun.COM else 249*8462SApril.Chin@Sun.COM ap->sh->test = 0; 250*8462SApril.Chin@Sun.COM continue; 2514887Schin case 's': 2524887Schin if(setflag) 2534887Schin { 2544887Schin action = SORT; 2554887Schin continue; 2564887Schin } 2574887Schin #if SHOPT_KIA 2584887Schin goto skip; 2594887Schin case 'R': 2604887Schin if(setflag) 2614887Schin n = ':'; 2624887Schin else 2634887Schin { 2644887Schin ap->kiafile = opt_info.arg; 2654887Schin n = 'n'; 2664887Schin } 2674887Schin /* FALL THRU */ 2684887Schin #endif /* SHOPT_KIA */ 2694887Schin skip: 2704887Schin default: 2714887Schin if(cp=strchr(optksh,n)) 2724887Schin o = flagval[cp-optksh]; 2734887Schin break; 2744887Schin case ':': 2754887Schin if(opt_info.name[0]=='-'&&opt_info.name[1]=='-') 2764887Schin { 2774887Schin opt_info.arg = argv[opt_info.index-1] + 2; 2784887Schin f = 1; 2794887Schin goto byname; 2804887Schin } 2814887Schin errormsg(SH_DICT,2, "%s", opt_info.arg); 2824887Schin continue; 2834887Schin case '?': 2844887Schin errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); 2854887Schin return(-1); 2864887Schin } 2874887Schin if(f) 2884887Schin { 2894887Schin if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) 2904887Schin { 2914887Schin off_option(&newflags,SH_VI); 2924887Schin off_option(&newflags,SH_EMACS); 2934887Schin off_option(&newflags,SH_GMACS); 2944887Schin } 2954887Schin on_option(&newflags,o); 296*8462SApril.Chin@Sun.COM off_option(&ap->sh->offoptions,o); 2974887Schin } 2984887Schin else 2994887Schin { 3004887Schin if(o==SH_XTRACE) 3014887Schin trace = 0; 3024887Schin off_option(&newflags,o); 3034887Schin if(setflag==0) 304*8462SApril.Chin@Sun.COM on_option(&ap->sh->offoptions,o); 3054887Schin } 3064887Schin } 3074887Schin if(error_info.errors) 3084887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 3094887Schin /* check for '-' or '+' argument */ 3104887Schin if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') && 3114887Schin strcmp(argv[opt_info.index-1],"--")) 3124887Schin { 3134887Schin opt_info.index++; 3144887Schin off_option(&newflags,SH_XTRACE); 3154887Schin off_option(&newflags,SH_VERBOSE); 3164887Schin trace = 0; 3174887Schin } 3184887Schin if(trace) 3194887Schin sh_trace(argv,1); 3204887Schin argc -= opt_info.index; 3214887Schin argv += opt_info.index; 3224887Schin if(action==PRINT) 3234887Schin sh_printopts(newflags,verbose,0); 3244887Schin if(setflag) 3254887Schin { 3264887Schin if(action==SORT) 3274887Schin { 3284887Schin if(argc>0) 3294887Schin strsort(argv,argc,strcoll); 3304887Schin else 331*8462SApril.Chin@Sun.COM strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll); 3324887Schin } 3334887Schin if(np) 3344887Schin { 3354887Schin nv_setvec(np,0,argc,argv); 3364887Schin nv_close(np); 3374887Schin } 3384887Schin else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0)) 339*8462SApril.Chin@Sun.COM sh_argset(ap,argv-1); 3404887Schin } 3414887Schin else if(is_option(&newflags,SH_CFLAG)) 3424887Schin { 343*8462SApril.Chin@Sun.COM if(!(ap->sh->comdiv = *argv++)) 3444887Schin { 3454887Schin errormsg(SH_DICT,2,e_cneedsarg); 3464887Schin errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); 3474887Schin } 3484887Schin argc--; 3494887Schin } 3504887Schin /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to 3514887Schin * sh_applyopts(), so that the code can be reused from b_shopt(), too 3524887Schin */ 353*8462SApril.Chin@Sun.COM sh_applyopts(ap->sh,newflags); 3544887Schin #if SHOPT_KIA 3554887Schin if(ap->kiafile) 3564887Schin { 357*8462SApril.Chin@Sun.COM if(!argv[0]) 358*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname"); 359*8462SApril.Chin@Sun.COM if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+"))) 3604887Schin errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile); 361*8462SApril.Chin@Sun.COM if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE))) 3624887Schin errormsg(SH_DICT,ERROR_system(3),e_tmpcreate); 363*8462SApril.Chin@Sun.COM sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n'); 364*8462SApril.Chin@Sun.COM lp->kiabegin = sftell(lp->kiafile); 365*8462SApril.Chin@Sun.COM lp->entity_tree = dtopen(&_Nvdisc,Dtbag); 366*8462SApril.Chin@Sun.COM lp->scriptname = strdup(sh_fmtq(argv[0])); 367*8462SApril.Chin@Sun.COM lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,""); 368*8462SApril.Chin@Sun.COM lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,""); 369*8462SApril.Chin@Sun.COM lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,""); 370*8462SApril.Chin@Sun.COM kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,""); 371*8462SApril.Chin@Sun.COM lp->current = lp->script; 3724887Schin ap->kiafile = 0; 3734887Schin } 3744887Schin #endif /* SHOPT_KIA */ 3754887Schin return(argc); 3764887Schin } 3774887Schin 3784887Schin /* apply new options */ 3794887Schin 380*8462SApril.Chin@Sun.COM void sh_applyopts(Shell_t* shp,Shopt_t newflags) 3814887Schin { 3824887Schin /* cannot set -n for interactive shells since there is no way out */ 3834887Schin if(sh_isoption(SH_INTERACTIVE)) 3844887Schin off_option(&newflags,SH_NOEXEC); 3854887Schin if(is_option(&newflags,SH_PRIVILEGED)) 3864887Schin on_option(&newflags,SH_NOUSRPROFILE); 3874887Schin if(is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED)) 3884887Schin { 3894887Schin if(sh_isoption(SH_PRIVILEGED)) 3904887Schin { 391*8462SApril.Chin@Sun.COM setuid(shp->userid); 392*8462SApril.Chin@Sun.COM setgid(shp->groupid); 393*8462SApril.Chin@Sun.COM if(shp->euserid==0) 3944887Schin { 395*8462SApril.Chin@Sun.COM shp->euserid = shp->userid; 396*8462SApril.Chin@Sun.COM shp->egroupid = shp->groupid; 3974887Schin } 3984887Schin } 399*8462SApril.Chin@Sun.COM else if((shp->userid!=shp->euserid && setuid(shp->euserid)<0) || 400*8462SApril.Chin@Sun.COM (shp->groupid!=shp->egroupid && setgid(shp->egroupid)<0) || 401*8462SApril.Chin@Sun.COM (shp->userid==shp->euserid && shp->groupid==shp->egroupid)) 4024887Schin off_option(&newflags,SH_PRIVILEGED); 4034887Schin } 4044887Schin #if SHOPT_BASH 4054887Schin on_option(&newflags,SH_CMDHIST); 4064887Schin on_option(&newflags,SH_CHECKHASH); 4074887Schin on_option(&newflags,SH_EXECFAIL); 4084887Schin on_option(&newflags,SH_EXPAND_ALIASES); 4094887Schin on_option(&newflags,SH_HISTAPPEND); 4104887Schin on_option(&newflags,SH_INTERACTIVE_COMM); 4114887Schin on_option(&newflags,SH_LITHIST); 4124887Schin on_option(&newflags,SH_NOEMPTYCMDCOMPL); 4134887Schin 4144887Schin if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO)) 4154887Schin astconf("UNIVERSE", 0, "ucb"); 4164887Schin if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO)) 4174887Schin astconf("UNIVERSE", 0, "att"); 4184887Schin if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL)) 4194887Schin astconf("PATH_RESOLVE", 0, "metaphysical"); 4204887Schin if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL)) 4214887Schin astconf("PATH_RESOLVE", 0, "physical"); 4224887Schin if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2)) 4234887Schin { 4244887Schin sh_onstate(SH_HISTORY); 4254887Schin sh_onoption(SH_HISTORY); 4264887Schin } 4274887Schin if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2)) 4284887Schin { 4294887Schin sh_offstate(SH_HISTORY); 4304887Schin sh_offoption(SH_HISTORY); 4314887Schin } 4324887Schin #endif 433*8462SApril.Chin@Sun.COM shp->options = newflags; 4344887Schin } 435*8462SApril.Chin@Sun.COM 4364887Schin /* 4374887Schin * returns the value of $- 4384887Schin */ 439*8462SApril.Chin@Sun.COM char *sh_argdolminus(void* context) 4404887Schin { 441*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)context; 4424887Schin register const char *cp=optksh; 4434887Schin register char *flagp=ap->flagadr; 4444887Schin while(cp< &optksh[NUM_OPTS]) 4454887Schin { 4464887Schin int n = flagval[cp-optksh]; 4474887Schin if(sh_isoption(n)) 4484887Schin *flagp++ = *cp; 4494887Schin cp++; 4504887Schin } 4514887Schin *flagp = 0; 4524887Schin return(ap->flagadr); 4534887Schin } 4544887Schin 4554887Schin /* 4564887Schin * set up positional parameters 4574887Schin */ 458*8462SApril.Chin@Sun.COM static void sh_argset(Arg_t *ap,char *argv[]) 4594887Schin { 460*8462SApril.Chin@Sun.COM sh_argfree(ap->sh,ap->dolh,0); 4614887Schin ap->dolh = sh_argcreate(argv); 4624887Schin /* link into chain */ 4634887Schin ap->dolh->dolnxt = ap->argfor; 4644887Schin ap->argfor = ap->dolh; 465*8462SApril.Chin@Sun.COM ap->sh->st.dolc = ap->dolh->dolnum-1; 466*8462SApril.Chin@Sun.COM ap->sh->st.dolv = ap->dolh->dolval; 4674887Schin } 4684887Schin 4694887Schin /* 4704887Schin * free the argument list if the use count is 1 4714887Schin * If count is greater than 1 decrement count and return same blk 4724887Schin * Free the argument list if the use count is 1 and return next blk 4734887Schin * Delete the blk from the argfor chain 4744887Schin * If flag is set, then the block dolh is not freed 4754887Schin */ 476*8462SApril.Chin@Sun.COM struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag) 4774887Schin { 4784887Schin register struct dolnod* argr=blk; 4794887Schin register struct dolnod* argblk; 480*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 4814887Schin if(argblk=argr) 4824887Schin { 4834887Schin if((--argblk->dolrefcnt)==0) 4844887Schin { 4854887Schin argr = argblk->dolnxt; 4864887Schin if(flag && argblk==ap->dolh) 4874887Schin ap->dolh->dolrefcnt = 1; 4884887Schin else 4894887Schin { 4904887Schin /* delete from chain */ 4914887Schin if(ap->argfor == argblk) 4924887Schin ap->argfor = argblk->dolnxt; 4934887Schin else 4944887Schin { 4954887Schin for(argr=ap->argfor;argr;argr=argr->dolnxt) 4964887Schin if(argr->dolnxt==argblk) 4974887Schin break; 4984887Schin if(!argr) 4994887Schin return(NIL(struct dolnod*)); 5004887Schin argr->dolnxt = argblk->dolnxt; 5014887Schin argr = argblk->dolnxt; 5024887Schin } 5034887Schin free((void*)argblk); 5044887Schin } 5054887Schin } 5064887Schin } 5074887Schin return(argr); 5084887Schin } 5094887Schin 5104887Schin /* 5114887Schin * grab space for arglist and copy args 5124887Schin * The strings are copied after the argment vector 5134887Schin */ 5144887Schin struct dolnod *sh_argcreate(register char *argv[]) 5154887Schin { 5164887Schin register struct dolnod *dp; 5174887Schin register char **pp=argv, *sp; 5184887Schin register int size=0,n; 5194887Schin /* count args and number of bytes of arglist */ 5204887Schin while(sp= *pp++) 5214887Schin size += strlen(sp); 5224887Schin n = (pp - argv)-1; 5234887Schin dp=new_of(struct dolnod,n*sizeof(char*)+size+n); 5244887Schin dp->dolrefcnt=1; /* use count */ 5254887Schin dp->dolnum = n; 5264887Schin dp->dolnxt = 0; 5274887Schin pp = dp->dolval; 5284887Schin sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*); 5294887Schin while(n--) 5304887Schin { 5314887Schin *pp++ = sp; 5324887Schin sp = strcopy(sp, *argv++) + 1; 5334887Schin } 5344887Schin *pp = NIL(char*); 5354887Schin return(dp); 5364887Schin } 5374887Schin 5384887Schin /* 5394887Schin * used to set new arguments for functions 5404887Schin */ 541*8462SApril.Chin@Sun.COM struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor) 5424887Schin { 543*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 5444887Schin register struct dolnod *olddolh = ap->dolh; 5454887Schin *savargfor = ap->argfor; 5464887Schin ap->dolh = 0; 5474887Schin ap->argfor = 0; 548*8462SApril.Chin@Sun.COM sh_argset(ap,argi); 5494887Schin return(olddolh); 5504887Schin } 5514887Schin 5524887Schin /* 5534887Schin * reset arguments as they were before function 5544887Schin */ 555*8462SApril.Chin@Sun.COM void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor) 5564887Schin { 557*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 558*8462SApril.Chin@Sun.COM while(ap->argfor=sh_argfree(shp,ap->argfor,0)); 5594887Schin ap->argfor = afor; 5604887Schin if(ap->dolh = blk) 5614887Schin { 562*8462SApril.Chin@Sun.COM shp->st.dolc = ap->dolh->dolnum-1; 563*8462SApril.Chin@Sun.COM shp->st.dolv = ap->dolh->dolval; 5644887Schin } 5654887Schin } 5664887Schin 5674887Schin /* 5684887Schin * increase the use count so that an sh_argset will not make it go away 5694887Schin */ 570*8462SApril.Chin@Sun.COM struct dolnod *sh_arguse(Shell_t* shp) 5714887Schin { 5724887Schin register struct dolnod *dh; 573*8462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context; 5744887Schin if(dh=ap->dolh) 5754887Schin dh->dolrefcnt++; 5764887Schin return(dh); 5774887Schin } 5784887Schin 5794887Schin /* 5804887Schin * Print option settings on standard output 5814887Schin * if mode is inclusive or of PRINT_* 5824887Schin * if <mask> is set, only options with this mask value are displayed 5834887Schin */ 5844887Schin void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask) 5854887Schin { 5864887Schin register const Shtable_t *tp; 5874887Schin const char *name; 5884887Schin int on; 5894887Schin int value; 5904887Schin if(!(mode&PRINT_NO_HEADER)) 5914887Schin sfputr(sfstdout,sh_translate(e_heading),'\n'); 5924887Schin if(mode&PRINT_TABLE) 5934887Schin { 5944887Schin int w; 5954887Schin int c; 5964887Schin int r; 5974887Schin int i; 5984887Schin 5994887Schin c = 0; 6004887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6014887Schin { 6024887Schin if(mask && !is_option(mask,value&0xff)) 6034887Schin continue; 6044887Schin name = tp->sh_name; 6054887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6064887Schin name += 2; 6074887Schin if(c<(w=strlen(name))) 6084887Schin c = w; 6094887Schin } 6104887Schin c += 4; 6114887Schin if((w = ed_window()) < (2*c)) 6124887Schin w = 2*c; 6134887Schin r = w / c; 6144887Schin i = 0; 6154887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6164887Schin { 6174887Schin if(mask && !is_option(mask,value&0xff)) 6184887Schin continue; 6194887Schin on = !!is_option(&oflags,value); 6204887Schin value &= 0xff; 6214887Schin name = tp->sh_name; 6224887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6234887Schin { 6244887Schin name += 2; 6254887Schin on = !on; 6264887Schin } 6274887Schin if(++i>=r) 6284887Schin { 6294887Schin i = 0; 6304887Schin sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name); 6314887Schin } 6324887Schin else 6334887Schin sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name); 6344887Schin } 6354887Schin if(i) 6364887Schin sfputc(sfstdout,'\n'); 6374887Schin return; 6384887Schin } 6394887Schin #if SHOPT_RAWONLY 6404887Schin on_option(&oflags,SH_VIRAW); 6414887Schin #endif 6424887Schin if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */ 6434887Schin { 6444887Schin if(mode&PRINT_SHOPT) 6454887Schin sfwrite(sfstdout,"shopt -s",3); 6464887Schin else 647*8462SApril.Chin@Sun.COM sfwrite(sfstdout,"set --default",13); 6484887Schin } 6494887Schin for(tp=shtab_options; value=tp->sh_number; tp++) 6504887Schin { 6514887Schin if(mask && !is_option(mask,value&0xff)) 6524887Schin continue; 6534887Schin if(sh_isoption(SH_BASH)) 6544887Schin { 6554887Schin if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT)) 6564887Schin continue; 6574887Schin } 6584887Schin else if (value&(SH_BASHEXTRA|SH_BASHOPT)) 6594887Schin continue; 6604887Schin on = !!is_option(&oflags,value); 6614887Schin name = tp->sh_name; 6624887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') 6634887Schin { 6644887Schin name += 2; 6654887Schin on = !on; 6664887Schin } 6674887Schin if(mode&PRINT_VERBOSE) 6684887Schin { 6694887Schin sfputr(sfstdout,name,' '); 6704887Schin sfnputc(sfstdout,' ',24-strlen(name)); 6714887Schin sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n'); 6724887Schin } 6734887Schin else if(mode&PRINT_ALL) /* print unset options also */ 6744887Schin { 6754887Schin if(mode&PRINT_SHOPT) 6764887Schin sfprintf(sfstdout, "shopt -%c %s\n", 6774887Schin on?'s':'u', 6784887Schin name); 6794887Schin else 6804887Schin sfprintf(sfstdout, "set %co %s\n", 6814887Schin on?'-':'+', 6824887Schin name); 6834887Schin } 6844887Schin else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff)) 6854887Schin sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name); 6864887Schin } 6874887Schin if(!(mode&(PRINT_VERBOSE|PRINT_ALL))) 6884887Schin sfputc(sfstdout,'\n'); 6894887Schin } 6904887Schin 6914887Schin /* 6924887Schin * build an argument list 6934887Schin */ 694*8462SApril.Chin@Sun.COM char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag) 6954887Schin { 6964887Schin register struct argnod *argp; 6974887Schin struct argnod *arghead=0; 698*8462SApril.Chin@Sun.COM shp->xargmin = 0; 6994887Schin { 7004887Schin register const struct comnod *ac = comptr; 7014887Schin register int n; 7024887Schin /* see if the arguments have already been expanded */ 7034887Schin if(!ac->comarg) 7044887Schin { 7054887Schin *nargs = 0; 7064887Schin return(&null); 7074887Schin } 7084887Schin else if(!(ac->comtyp&COMSCAN)) 7094887Schin { 7104887Schin register struct dolnod *ap = (struct dolnod*)ac->comarg; 7114887Schin *nargs = ap->dolnum; 7124887Schin return(ap->dolval+ap->dolbot); 7134887Schin } 714*8462SApril.Chin@Sun.COM shp->lastpath = 0; 7154887Schin *nargs = 0; 7164887Schin if(ac) 7174887Schin { 7184887Schin if(ac->comnamp == SYSLET) 7194887Schin flag |= ARG_LET; 7204887Schin argp = ac->comarg; 7214887Schin while(argp) 7224887Schin { 723*8462SApril.Chin@Sun.COM n = arg_expand(shp,argp,&arghead,flag); 7244887Schin if(n>1) 7254887Schin { 726*8462SApril.Chin@Sun.COM if(shp->xargmin==0) 727*8462SApril.Chin@Sun.COM shp->xargmin = *nargs; 728*8462SApril.Chin@Sun.COM shp->xargmax = *nargs+n; 7294887Schin } 7304887Schin *nargs += n; 7314887Schin argp = argp->argnxt.ap; 7324887Schin } 7334887Schin argp = arghead; 7344887Schin } 7354887Schin } 7364887Schin { 7374887Schin register char **comargn; 7384887Schin register int argn; 7394887Schin register char **comargm; 7404887Schin argn = *nargs; 7414887Schin /* allow room to prepend args */ 7424887Schin argn += 1; 7434887Schin 744*8462SApril.Chin@Sun.COM comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*)); 7454887Schin comargm = comargn += argn; 7464887Schin *comargn = NIL(char*); 7474887Schin if(!argp) 7484887Schin { 7494887Schin /* reserve an extra null pointer */ 7504887Schin *--comargn = 0; 7514887Schin return(comargn); 7524887Schin } 7534887Schin while(argp) 7544887Schin { 7554887Schin struct argnod *nextarg = argp->argchn.ap; 7564887Schin argp->argchn.ap = 0; 7574887Schin *--comargn = argp->argval; 7584887Schin if(!(argp->argflag&ARG_RAW)) 7594887Schin sh_trim(*comargn); 7604887Schin if(!(argp=nextarg) || (argp->argflag&ARG_MAKE)) 7614887Schin { 7624887Schin if((argn=comargm-comargn)>1) 7634887Schin strsort(comargn,argn,strcoll); 7644887Schin comargm = comargn; 7654887Schin } 7664887Schin } 767*8462SApril.Chin@Sun.COM shp->last_table = 0; 7684887Schin return(comargn); 7694887Schin } 7704887Schin } 7714887Schin 7724887Schin #if _pipe_socketpair && !_socketpair_devfd 7734887Schin # define sh_pipe arg_pipe 7744887Schin /* 7754887Schin * create a real pipe (not a socket) and print message on failure 7764887Schin */ 7774887Schin static int arg_pipe(register int pv[]) 7784887Schin { 7794887Schin int fd[2]; 7804887Schin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0) 7814887Schin errormsg(SH_DICT,ERROR_system(1),e_pipe); 7824887Schin pv[0] = sh_iomovefd(pv[0]); 7834887Schin pv[1] = sh_iomovefd(pv[1]); 7844887Schin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD; 7854887Schin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE; 7864887Schin sh_subsavefd(pv[0]); 7874887Schin sh_subsavefd(pv[1]); 7884887Schin return(0); 7894887Schin } 7904887Schin #endif 7914887Schin 7924887Schin /* Argument expansion */ 793*8462SApril.Chin@Sun.COM static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag) 7944887Schin { 7954887Schin register int count = 0; 7964887Schin argp->argflag &= ~ARG_MAKE; 7974887Schin #if SHOPT_DEVFD 7984887Schin if(*argp->argval==0 && (argp->argflag&ARG_EXP)) 7994887Schin { 8004887Schin /* argument of the form (cmd) */ 8014887Schin register struct argnod *ap; 8024887Schin int monitor, fd, pv[2]; 803*8462SApril.Chin@Sun.COM ap = (struct argnod*)stkseek(shp->stk,ARGVAL); 8044887Schin ap->argflag |= ARG_MAKE; 8054887Schin ap->argflag &= ~ARG_RAW; 8064887Schin ap->argchn.ap = *argchain; 8074887Schin *argchain = ap; 8084887Schin count++; 809*8462SApril.Chin@Sun.COM sfwrite(shp->stk,e_devfdNN,8); 8104887Schin sh_pipe(pv); 8114887Schin fd = argp->argflag&ARG_RAW; 812*8462SApril.Chin@Sun.COM sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); 813*8462SApril.Chin@Sun.COM ap = (struct argnod*)stkfreeze(shp->stk,0); 814*8462SApril.Chin@Sun.COM shp->inpipe = shp->outpipe = 0; 8154887Schin if(monitor = (sh_isstate(SH_MONITOR)!=0)) 8164887Schin sh_offstate(SH_MONITOR); 8174887Schin if(fd) 8184887Schin { 819*8462SApril.Chin@Sun.COM shp->inpipe = pv; 8204887Schin sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 8214887Schin } 8224887Schin else 8234887Schin { 824*8462SApril.Chin@Sun.COM shp->outpipe = pv; 8254887Schin sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); 8264887Schin } 8274887Schin if(monitor) 8284887Schin sh_onstate(SH_MONITOR); 8294887Schin close(pv[1-fd]); 830*8462SApril.Chin@Sun.COM sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); 8314887Schin } 8324887Schin else 8334887Schin #endif /* SHOPT_DEVFD */ 8344887Schin if(!(argp->argflag&ARG_RAW)) 8354887Schin { 8364887Schin #if SHOPT_OPTIMIZE 8374887Schin struct argnod *ap; 838*8462SApril.Chin@Sun.COM sh_stats(STAT_ARGEXPAND); 8394887Schin if(flag&ARG_OPTIMIZE) 8404887Schin argp->argchn.ap=0; 8414887Schin if(ap=argp->argchn.ap) 8424887Schin { 843*8462SApril.Chin@Sun.COM sh_stats(STAT_ARGHITS); 8444887Schin count = 1; 8454887Schin ap->argchn.ap = *argchain; 8464887Schin ap->argflag |= ARG_RAW; 8474887Schin ap->argflag &= ~ARG_EXP; 8484887Schin *argchain = ap; 8494887Schin } 8504887Schin else 8514887Schin #endif /* SHOPT_OPTIMIZE */ 852*8462SApril.Chin@Sun.COM count = sh_macexpand(shp,argp,argchain,flag); 8534887Schin } 8544887Schin else 8554887Schin { 8564887Schin argp->argchn.ap = *argchain; 8574887Schin *argchain = argp; 8584887Schin argp->argflag |= ARG_MAKE; 8594887Schin count++; 8604887Schin } 8614887Schin return(count); 8624887Schin } 8634887Schin 864