14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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
468462SApril.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
698462SApril.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 {
868462SApril.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
958462SApril.Chin@Sun.COM static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int);
968462SApril.Chin@Sun.COM static void sh_argset(Arg_t*, char *[]);
978462SApril.Chin@Sun.COM
984887Schin
994887Schin /* ======== option handling ======== */
1004887Schin
sh_argopen(Shell_t * shp)1014887Schin void *sh_argopen(Shell_t *shp)
1024887Schin {
1034887Schin void *addr = newof(0,Arg_t,1,0);
1044887Schin Arg_t *ap = (Arg_t*)addr;
1058462SApril.Chin@Sun.COM ap->sh = shp;
1064887Schin return(addr);
1074887Schin }
1084887Schin
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)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 */
sh_argopts(int argc,register char * argv[],void * context)1388462SApril.Chin@Sun.COM int sh_argopts(int argc,register char *argv[], void *context)
1394887Schin {
1408462SApril.Chin@Sun.COM Shell_t *shp = (Shell_t*)context;
1418462SApril.Chin@Sun.COM register int n,o;
1428462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)(shp->arg_context);
1438462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)(shp->lex_context);
1448462SApril.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;
1508462SApril.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;
1638462SApril.Chin@Sun.COM f=*opt_info.option=='-' && (opt_info.num || opt_info.arg);
1644887Schin switch(n)
1654887Schin {
1664887Schin case 'A':
1678462SApril.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 */
2068462SApril.Chin@Sun.COM ap->sh->rcfile = opt_info.arg;
2074887Schin continue;
2084887Schin case -2: /* --noediting */
2098462SApril.Chin@Sun.COM if (!f)
2108462SApril.Chin@Sun.COM {
2118462SApril.Chin@Sun.COM off_option(&newflags,SH_VI);
2128462SApril.Chin@Sun.COM off_option(&newflags,SH_EMACS);
2138462SApril.Chin@Sun.COM off_option(&newflags,SH_GMACS);
2148462SApril.Chin@Sun.COM }
2154887Schin continue;
2164887Schin case -3: /* --profile */
2178462SApril.Chin@Sun.COM n = 'l';
2188462SApril.Chin@Sun.COM goto skip;
2198462SApril.Chin@Sun.COM case -4: /* --posix */
2204887Schin /* mask lower 8 bits to find char in optksh string */
2214887Schin n&=0xff;
2224887Schin goto skip;
2238462SApril.Chin@Sun.COM case -5: /* --version */
2248462SApril.Chin@Sun.COM sfputr(sfstdout, "ksh bash emulation, version ",-1);
2258462SApril.Chin@Sun.COM np = nv_open("BASH_VERSION",ap->sh->var_tree,0);
2268462SApril.Chin@Sun.COM sfputr(sfstdout, nv_getval(np),-1);
2278462SApril.Chin@Sun.COM np = nv_open("MACHTYPE",ap->sh->var_tree,0);
2288462SApril.Chin@Sun.COM sfprintf(sfstdout, " (%s)\n", nv_getval(np));
2298462SApril.Chin@Sun.COM sh_exit(0);
2304887Schin #endif
2318462SApril.Chin@Sun.COM case -6: /* --default */
2328462SApril.Chin@Sun.COM {
2338462SApril.Chin@Sun.COM register const Shtable_t *tp;
2348462SApril.Chin@Sun.COM for(tp=shtab_options; o = tp->sh_number; tp++)
2358462SApril.Chin@Sun.COM if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff))
2368462SApril.Chin@Sun.COM off_option(&newflags,o&0xff);
2378462SApril.Chin@Sun.COM }
2388462SApril.Chin@Sun.COM continue;
2398462SApril.Chin@Sun.COM case -7:
2408462SApril.Chin@Sun.COM f = 0;
2418462SApril.Chin@Sun.COM goto byname;
2424887Schin case 'D':
2434887Schin on_option(&newflags,SH_NOEXEC);
2444887Schin goto skip;
2458462SApril.Chin@Sun.COM case 'T':
2468462SApril.Chin@Sun.COM if (opt_info.num)
2478462SApril.Chin@Sun.COM ap->sh->test |= opt_info.num;
2488462SApril.Chin@Sun.COM else
2498462SApril.Chin@Sun.COM ap->sh->test = 0;
2508462SApril.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 }
26710898Sroland.mainz@nrubsig.org /*FALLTHROUGH*/
2684887Schin #endif /* SHOPT_KIA */
26910898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS
27010898Sroland.mainz@nrubsig.org goto skip;
27110898Sroland.mainz@nrubsig.org case 'I':
27210898Sroland.mainz@nrubsig.org continue;
27310898Sroland.mainz@nrubsig.org #endif /* SHOPT_REGRESS */
2744887Schin skip:
2754887Schin default:
2764887Schin if(cp=strchr(optksh,n))
2774887Schin o = flagval[cp-optksh];
2784887Schin break;
2794887Schin case ':':
2804887Schin if(opt_info.name[0]=='-'&&opt_info.name[1]=='-')
2814887Schin {
2824887Schin opt_info.arg = argv[opt_info.index-1] + 2;
2834887Schin f = 1;
2844887Schin goto byname;
2854887Schin }
2864887Schin errormsg(SH_DICT,2, "%s", opt_info.arg);
2874887Schin continue;
2884887Schin case '?':
2894887Schin errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
2904887Schin return(-1);
2914887Schin }
2924887Schin if(f)
2934887Schin {
2944887Schin if(o==SH_VI || o==SH_EMACS || o==SH_GMACS)
2954887Schin {
2964887Schin off_option(&newflags,SH_VI);
2974887Schin off_option(&newflags,SH_EMACS);
2984887Schin off_option(&newflags,SH_GMACS);
2994887Schin }
3004887Schin on_option(&newflags,o);
3018462SApril.Chin@Sun.COM off_option(&ap->sh->offoptions,o);
3024887Schin }
3034887Schin else
3044887Schin {
3054887Schin if(o==SH_XTRACE)
3064887Schin trace = 0;
3074887Schin off_option(&newflags,o);
3084887Schin if(setflag==0)
3098462SApril.Chin@Sun.COM on_option(&ap->sh->offoptions,o);
3104887Schin }
3114887Schin }
3124887Schin if(error_info.errors)
3134887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
3144887Schin /* check for '-' or '+' argument */
3154887Schin if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') &&
3164887Schin strcmp(argv[opt_info.index-1],"--"))
3174887Schin {
3184887Schin opt_info.index++;
3194887Schin off_option(&newflags,SH_XTRACE);
3204887Schin off_option(&newflags,SH_VERBOSE);
3214887Schin trace = 0;
3224887Schin }
3234887Schin if(trace)
3244887Schin sh_trace(argv,1);
3254887Schin argc -= opt_info.index;
3264887Schin argv += opt_info.index;
3274887Schin if(action==PRINT)
3284887Schin sh_printopts(newflags,verbose,0);
3294887Schin if(setflag)
3304887Schin {
3314887Schin if(action==SORT)
3324887Schin {
3334887Schin if(argc>0)
3344887Schin strsort(argv,argc,strcoll);
3354887Schin else
3368462SApril.Chin@Sun.COM strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll);
3374887Schin }
3384887Schin if(np)
3394887Schin {
3404887Schin nv_setvec(np,0,argc,argv);
3414887Schin nv_close(np);
3424887Schin }
3434887Schin else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0))
3448462SApril.Chin@Sun.COM sh_argset(ap,argv-1);
3454887Schin }
3464887Schin else if(is_option(&newflags,SH_CFLAG))
3474887Schin {
3488462SApril.Chin@Sun.COM if(!(ap->sh->comdiv = *argv++))
3494887Schin {
3504887Schin errormsg(SH_DICT,2,e_cneedsarg);
3514887Schin errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
3524887Schin }
3534887Schin argc--;
3544887Schin }
3554887Schin /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to
3564887Schin * sh_applyopts(), so that the code can be reused from b_shopt(), too
3574887Schin */
3588462SApril.Chin@Sun.COM sh_applyopts(ap->sh,newflags);
3594887Schin #if SHOPT_KIA
3604887Schin if(ap->kiafile)
3614887Schin {
3628462SApril.Chin@Sun.COM if(!argv[0])
3638462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname");
3648462SApril.Chin@Sun.COM if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+")))
3654887Schin errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile);
3668462SApril.Chin@Sun.COM if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE)))
3674887Schin errormsg(SH_DICT,ERROR_system(3),e_tmpcreate);
3688462SApril.Chin@Sun.COM sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n');
3698462SApril.Chin@Sun.COM lp->kiabegin = sftell(lp->kiafile);
3708462SApril.Chin@Sun.COM lp->entity_tree = dtopen(&_Nvdisc,Dtbag);
3718462SApril.Chin@Sun.COM lp->scriptname = strdup(sh_fmtq(argv[0]));
3728462SApril.Chin@Sun.COM lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,"");
3738462SApril.Chin@Sun.COM lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,"");
3748462SApril.Chin@Sun.COM lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,"");
3758462SApril.Chin@Sun.COM kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,"");
3768462SApril.Chin@Sun.COM lp->current = lp->script;
3774887Schin ap->kiafile = 0;
3784887Schin }
3794887Schin #endif /* SHOPT_KIA */
3804887Schin return(argc);
3814887Schin }
3824887Schin
3834887Schin /* apply new options */
3844887Schin
sh_applyopts(Shell_t * shp,Shopt_t newflags)3858462SApril.Chin@Sun.COM void sh_applyopts(Shell_t* shp,Shopt_t newflags)
3864887Schin {
3874887Schin /* cannot set -n for interactive shells since there is no way out */
3884887Schin if(sh_isoption(SH_INTERACTIVE))
3894887Schin off_option(&newflags,SH_NOEXEC);
3904887Schin if(is_option(&newflags,SH_PRIVILEGED))
3914887Schin on_option(&newflags,SH_NOUSRPROFILE);
39210898Sroland.mainz@nrubsig.org 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->userid!=shp->euserid)
3934887Schin {
39410898Sroland.mainz@nrubsig.org if(!is_option(&newflags,SH_PRIVILEGED))
3954887Schin {
3968462SApril.Chin@Sun.COM setuid(shp->userid);
3978462SApril.Chin@Sun.COM setgid(shp->groupid);
3988462SApril.Chin@Sun.COM if(shp->euserid==0)
3994887Schin {
4008462SApril.Chin@Sun.COM shp->euserid = shp->userid;
4018462SApril.Chin@Sun.COM shp->egroupid = shp->groupid;
4024887Schin }
4034887Schin }
4048462SApril.Chin@Sun.COM else if((shp->userid!=shp->euserid && setuid(shp->euserid)<0) ||
4058462SApril.Chin@Sun.COM (shp->groupid!=shp->egroupid && setgid(shp->egroupid)<0) ||
4068462SApril.Chin@Sun.COM (shp->userid==shp->euserid && shp->groupid==shp->egroupid))
4074887Schin off_option(&newflags,SH_PRIVILEGED);
4084887Schin }
4094887Schin #if SHOPT_BASH
4104887Schin on_option(&newflags,SH_CMDHIST);
4114887Schin on_option(&newflags,SH_CHECKHASH);
4124887Schin on_option(&newflags,SH_EXECFAIL);
4134887Schin on_option(&newflags,SH_EXPAND_ALIASES);
4144887Schin on_option(&newflags,SH_HISTAPPEND);
4154887Schin on_option(&newflags,SH_INTERACTIVE_COMM);
4164887Schin on_option(&newflags,SH_LITHIST);
4174887Schin on_option(&newflags,SH_NOEMPTYCMDCOMPL);
4184887Schin
4194887Schin if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO))
4204887Schin astconf("UNIVERSE", 0, "ucb");
4214887Schin if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO))
4224887Schin astconf("UNIVERSE", 0, "att");
4234887Schin if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL))
4244887Schin astconf("PATH_RESOLVE", 0, "metaphysical");
4254887Schin if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL))
4264887Schin astconf("PATH_RESOLVE", 0, "physical");
4274887Schin if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2))
4284887Schin {
4294887Schin sh_onstate(SH_HISTORY);
4304887Schin sh_onoption(SH_HISTORY);
4314887Schin }
4324887Schin if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2))
4334887Schin {
4344887Schin sh_offstate(SH_HISTORY);
4354887Schin sh_offoption(SH_HISTORY);
4364887Schin }
4374887Schin #endif
4388462SApril.Chin@Sun.COM shp->options = newflags;
4394887Schin }
4408462SApril.Chin@Sun.COM
4414887Schin /*
4424887Schin * returns the value of $-
4434887Schin */
sh_argdolminus(void * context)4448462SApril.Chin@Sun.COM char *sh_argdolminus(void* context)
4454887Schin {
4468462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)context;
4474887Schin register const char *cp=optksh;
4484887Schin register char *flagp=ap->flagadr;
4494887Schin while(cp< &optksh[NUM_OPTS])
4504887Schin {
4514887Schin int n = flagval[cp-optksh];
4524887Schin if(sh_isoption(n))
4534887Schin *flagp++ = *cp;
4544887Schin cp++;
4554887Schin }
4564887Schin *flagp = 0;
4574887Schin return(ap->flagadr);
4584887Schin }
4594887Schin
4604887Schin /*
4614887Schin * set up positional parameters
4624887Schin */
sh_argset(Arg_t * ap,char * argv[])4638462SApril.Chin@Sun.COM static void sh_argset(Arg_t *ap,char *argv[])
4644887Schin {
4658462SApril.Chin@Sun.COM sh_argfree(ap->sh,ap->dolh,0);
4664887Schin ap->dolh = sh_argcreate(argv);
4674887Schin /* link into chain */
4684887Schin ap->dolh->dolnxt = ap->argfor;
4694887Schin ap->argfor = ap->dolh;
4708462SApril.Chin@Sun.COM ap->sh->st.dolc = ap->dolh->dolnum-1;
4718462SApril.Chin@Sun.COM ap->sh->st.dolv = ap->dolh->dolval;
4724887Schin }
4734887Schin
4744887Schin /*
4754887Schin * free the argument list if the use count is 1
4764887Schin * If count is greater than 1 decrement count and return same blk
4774887Schin * Free the argument list if the use count is 1 and return next blk
4784887Schin * Delete the blk from the argfor chain
4794887Schin * If flag is set, then the block dolh is not freed
4804887Schin */
sh_argfree(Shell_t * shp,struct dolnod * blk,int flag)4818462SApril.Chin@Sun.COM struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag)
4824887Schin {
4834887Schin register struct dolnod* argr=blk;
4844887Schin register struct dolnod* argblk;
4858462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context;
4864887Schin if(argblk=argr)
4874887Schin {
4884887Schin if((--argblk->dolrefcnt)==0)
4894887Schin {
4904887Schin argr = argblk->dolnxt;
4914887Schin if(flag && argblk==ap->dolh)
4924887Schin ap->dolh->dolrefcnt = 1;
4934887Schin else
4944887Schin {
4954887Schin /* delete from chain */
4964887Schin if(ap->argfor == argblk)
4974887Schin ap->argfor = argblk->dolnxt;
4984887Schin else
4994887Schin {
5004887Schin for(argr=ap->argfor;argr;argr=argr->dolnxt)
5014887Schin if(argr->dolnxt==argblk)
5024887Schin break;
5034887Schin if(!argr)
5044887Schin return(NIL(struct dolnod*));
5054887Schin argr->dolnxt = argblk->dolnxt;
5064887Schin argr = argblk->dolnxt;
5074887Schin }
5084887Schin free((void*)argblk);
5094887Schin }
5104887Schin }
5114887Schin }
5124887Schin return(argr);
5134887Schin }
5144887Schin
5154887Schin /*
5164887Schin * grab space for arglist and copy args
5174887Schin * The strings are copied after the argment vector
5184887Schin */
sh_argcreate(register char * argv[])5194887Schin struct dolnod *sh_argcreate(register char *argv[])
5204887Schin {
5214887Schin register struct dolnod *dp;
5224887Schin register char **pp=argv, *sp;
5234887Schin register int size=0,n;
5244887Schin /* count args and number of bytes of arglist */
5254887Schin while(sp= *pp++)
5264887Schin size += strlen(sp);
5274887Schin n = (pp - argv)-1;
5284887Schin dp=new_of(struct dolnod,n*sizeof(char*)+size+n);
5294887Schin dp->dolrefcnt=1; /* use count */
5304887Schin dp->dolnum = n;
5314887Schin dp->dolnxt = 0;
5324887Schin pp = dp->dolval;
5334887Schin sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*);
5344887Schin while(n--)
5354887Schin {
5364887Schin *pp++ = sp;
5374887Schin sp = strcopy(sp, *argv++) + 1;
5384887Schin }
5394887Schin *pp = NIL(char*);
5404887Schin return(dp);
5414887Schin }
5424887Schin
5434887Schin /*
5444887Schin * used to set new arguments for functions
5454887Schin */
sh_argnew(Shell_t * shp,char * argi[],struct dolnod ** savargfor)5468462SApril.Chin@Sun.COM struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor)
5474887Schin {
5488462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context;
5494887Schin register struct dolnod *olddolh = ap->dolh;
5504887Schin *savargfor = ap->argfor;
5514887Schin ap->dolh = 0;
5524887Schin ap->argfor = 0;
5538462SApril.Chin@Sun.COM sh_argset(ap,argi);
5544887Schin return(olddolh);
5554887Schin }
5564887Schin
5574887Schin /*
5584887Schin * reset arguments as they were before function
5594887Schin */
sh_argreset(Shell_t * shp,struct dolnod * blk,struct dolnod * afor)5608462SApril.Chin@Sun.COM void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor)
5614887Schin {
5628462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context;
5638462SApril.Chin@Sun.COM while(ap->argfor=sh_argfree(shp,ap->argfor,0));
5644887Schin ap->argfor = afor;
5654887Schin if(ap->dolh = blk)
5664887Schin {
5678462SApril.Chin@Sun.COM shp->st.dolc = ap->dolh->dolnum-1;
5688462SApril.Chin@Sun.COM shp->st.dolv = ap->dolh->dolval;
5694887Schin }
5704887Schin }
5714887Schin
5724887Schin /*
5734887Schin * increase the use count so that an sh_argset will not make it go away
5744887Schin */
sh_arguse(Shell_t * shp)5758462SApril.Chin@Sun.COM struct dolnod *sh_arguse(Shell_t* shp)
5764887Schin {
5774887Schin register struct dolnod *dh;
5788462SApril.Chin@Sun.COM register Arg_t *ap = (Arg_t*)shp->arg_context;
5794887Schin if(dh=ap->dolh)
5804887Schin dh->dolrefcnt++;
5814887Schin return(dh);
5824887Schin }
5834887Schin
5844887Schin /*
5854887Schin * Print option settings on standard output
5864887Schin * if mode is inclusive or of PRINT_*
5874887Schin * if <mask> is set, only options with this mask value are displayed
5884887Schin */
sh_printopts(Shopt_t oflags,register int mode,Shopt_t * mask)5894887Schin void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask)
5904887Schin {
5914887Schin register const Shtable_t *tp;
5924887Schin const char *name;
5934887Schin int on;
5944887Schin int value;
5954887Schin if(!(mode&PRINT_NO_HEADER))
5964887Schin sfputr(sfstdout,sh_translate(e_heading),'\n');
5974887Schin if(mode&PRINT_TABLE)
5984887Schin {
5994887Schin int w;
6004887Schin int c;
6014887Schin int r;
6024887Schin int i;
6034887Schin
6044887Schin c = 0;
6054887Schin for(tp=shtab_options; value=tp->sh_number; tp++)
6064887Schin {
6074887Schin if(mask && !is_option(mask,value&0xff))
6084887Schin continue;
6094887Schin name = tp->sh_name;
6104887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
6114887Schin name += 2;
6124887Schin if(c<(w=strlen(name)))
6134887Schin c = w;
6144887Schin }
6154887Schin c += 4;
6164887Schin if((w = ed_window()) < (2*c))
6174887Schin w = 2*c;
6184887Schin r = w / c;
6194887Schin i = 0;
6204887Schin for(tp=shtab_options; value=tp->sh_number; tp++)
6214887Schin {
6224887Schin if(mask && !is_option(mask,value&0xff))
6234887Schin continue;
6244887Schin on = !!is_option(&oflags,value);
6254887Schin value &= 0xff;
6264887Schin name = tp->sh_name;
6274887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
6284887Schin {
6294887Schin name += 2;
6304887Schin on = !on;
6314887Schin }
6324887Schin if(++i>=r)
6334887Schin {
6344887Schin i = 0;
6354887Schin sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name);
6364887Schin }
6374887Schin else
6384887Schin sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name);
6394887Schin }
6404887Schin if(i)
6414887Schin sfputc(sfstdout,'\n');
6424887Schin return;
6434887Schin }
6444887Schin #if SHOPT_RAWONLY
6454887Schin on_option(&oflags,SH_VIRAW);
6464887Schin #endif
6474887Schin if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */
6484887Schin {
6494887Schin if(mode&PRINT_SHOPT)
6504887Schin sfwrite(sfstdout,"shopt -s",3);
6514887Schin else
6528462SApril.Chin@Sun.COM sfwrite(sfstdout,"set --default",13);
6534887Schin }
6544887Schin for(tp=shtab_options; value=tp->sh_number; tp++)
6554887Schin {
6564887Schin if(mask && !is_option(mask,value&0xff))
6574887Schin continue;
6584887Schin if(sh_isoption(SH_BASH))
6594887Schin {
6604887Schin if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT))
6614887Schin continue;
6624887Schin }
6634887Schin else if (value&(SH_BASHEXTRA|SH_BASHOPT))
6644887Schin continue;
6654887Schin on = !!is_option(&oflags,value);
6664887Schin name = tp->sh_name;
6674887Schin if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
6684887Schin {
6694887Schin name += 2;
6704887Schin on = !on;
6714887Schin }
6724887Schin if(mode&PRINT_VERBOSE)
6734887Schin {
6744887Schin sfputr(sfstdout,name,' ');
6754887Schin sfnputc(sfstdout,' ',24-strlen(name));
6764887Schin sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n');
6774887Schin }
6784887Schin else if(mode&PRINT_ALL) /* print unset options also */
6794887Schin {
6804887Schin if(mode&PRINT_SHOPT)
6814887Schin sfprintf(sfstdout, "shopt -%c %s\n",
6824887Schin on?'s':'u',
6834887Schin name);
6844887Schin else
6854887Schin sfprintf(sfstdout, "set %co %s\n",
6864887Schin on?'-':'+',
6874887Schin name);
6884887Schin }
6894887Schin else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff))
6904887Schin sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name);
6914887Schin }
6924887Schin if(!(mode&(PRINT_VERBOSE|PRINT_ALL)))
6934887Schin sfputc(sfstdout,'\n');
6944887Schin }
6954887Schin
6964887Schin /*
6974887Schin * build an argument list
6984887Schin */
sh_argbuild(Shell_t * shp,int * nargs,const struct comnod * comptr,int flag)6998462SApril.Chin@Sun.COM char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag)
7004887Schin {
7014887Schin register struct argnod *argp;
7024887Schin struct argnod *arghead=0;
7038462SApril.Chin@Sun.COM shp->xargmin = 0;
7044887Schin {
7054887Schin register const struct comnod *ac = comptr;
7064887Schin register int n;
7074887Schin /* see if the arguments have already been expanded */
7084887Schin if(!ac->comarg)
7094887Schin {
7104887Schin *nargs = 0;
7114887Schin return(&null);
7124887Schin }
7134887Schin else if(!(ac->comtyp&COMSCAN))
7144887Schin {
7154887Schin register struct dolnod *ap = (struct dolnod*)ac->comarg;
7164887Schin *nargs = ap->dolnum;
7174887Schin return(ap->dolval+ap->dolbot);
7184887Schin }
7198462SApril.Chin@Sun.COM shp->lastpath = 0;
7204887Schin *nargs = 0;
7214887Schin if(ac)
7224887Schin {
7234887Schin if(ac->comnamp == SYSLET)
7244887Schin flag |= ARG_LET;
7254887Schin argp = ac->comarg;
7264887Schin while(argp)
7274887Schin {
7288462SApril.Chin@Sun.COM n = arg_expand(shp,argp,&arghead,flag);
7294887Schin if(n>1)
7304887Schin {
7318462SApril.Chin@Sun.COM if(shp->xargmin==0)
7328462SApril.Chin@Sun.COM shp->xargmin = *nargs;
7338462SApril.Chin@Sun.COM shp->xargmax = *nargs+n;
7344887Schin }
7354887Schin *nargs += n;
7364887Schin argp = argp->argnxt.ap;
7374887Schin }
7384887Schin argp = arghead;
7394887Schin }
7404887Schin }
7414887Schin {
7424887Schin register char **comargn;
7434887Schin register int argn;
7444887Schin register char **comargm;
7454887Schin argn = *nargs;
7464887Schin /* allow room to prepend args */
7474887Schin argn += 1;
7484887Schin
7498462SApril.Chin@Sun.COM comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*));
7504887Schin comargm = comargn += argn;
7514887Schin *comargn = NIL(char*);
7524887Schin if(!argp)
7534887Schin {
7544887Schin /* reserve an extra null pointer */
7554887Schin *--comargn = 0;
7564887Schin return(comargn);
7574887Schin }
7584887Schin while(argp)
7594887Schin {
7604887Schin struct argnod *nextarg = argp->argchn.ap;
7614887Schin argp->argchn.ap = 0;
7624887Schin *--comargn = argp->argval;
7634887Schin if(!(argp->argflag&ARG_RAW))
7644887Schin sh_trim(*comargn);
7654887Schin if(!(argp=nextarg) || (argp->argflag&ARG_MAKE))
7664887Schin {
7674887Schin if((argn=comargm-comargn)>1)
7684887Schin strsort(comargn,argn,strcoll);
7694887Schin comargm = comargn;
7704887Schin }
7714887Schin }
7728462SApril.Chin@Sun.COM shp->last_table = 0;
7734887Schin return(comargn);
7744887Schin }
7754887Schin }
7764887Schin
7774887Schin #if _pipe_socketpair && !_socketpair_devfd
7784887Schin # define sh_pipe arg_pipe
7794887Schin /*
7804887Schin * create a real pipe (not a socket) and print message on failure
7814887Schin */
arg_pipe(register int pv[])7824887Schin static int arg_pipe(register int pv[])
7834887Schin {
7844887Schin int fd[2];
7854887Schin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
7864887Schin errormsg(SH_DICT,ERROR_system(1),e_pipe);
7874887Schin pv[0] = sh_iomovefd(pv[0]);
7884887Schin pv[1] = sh_iomovefd(pv[1]);
7894887Schin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
7904887Schin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
7914887Schin sh_subsavefd(pv[0]);
7924887Schin sh_subsavefd(pv[1]);
7934887Schin return(0);
7944887Schin }
7954887Schin #endif
7964887Schin
sh_argprocsub(Shell_t * shp,struct argnod * argp)79710898Sroland.mainz@nrubsig.org struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
79810898Sroland.mainz@nrubsig.org {
79910898Sroland.mainz@nrubsig.org /* argument of the form <(cmd) or >(cmd) */
80010898Sroland.mainz@nrubsig.org register struct argnod *ap;
80110898Sroland.mainz@nrubsig.org int monitor, fd, pv[2];
80210898Sroland.mainz@nrubsig.org int subshell = shp->subshell;
80310898Sroland.mainz@nrubsig.org ap = (struct argnod*)stkseek(shp->stk,ARGVAL);
80410898Sroland.mainz@nrubsig.org ap->argflag |= ARG_MAKE;
80510898Sroland.mainz@nrubsig.org ap->argflag &= ~ARG_RAW;
80610898Sroland.mainz@nrubsig.org sfwrite(shp->stk,e_devfdNN,8);
80710898Sroland.mainz@nrubsig.org sh_pipe(pv);
80810898Sroland.mainz@nrubsig.org fd = argp->argflag&ARG_RAW;
80910898Sroland.mainz@nrubsig.org sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0);
81010898Sroland.mainz@nrubsig.org ap = (struct argnod*)stkfreeze(shp->stk,0);
81110898Sroland.mainz@nrubsig.org shp->inpipe = shp->outpipe = 0;
81210898Sroland.mainz@nrubsig.org if(monitor = (sh_isstate(SH_MONITOR)!=0))
81310898Sroland.mainz@nrubsig.org sh_offstate(SH_MONITOR);
81410898Sroland.mainz@nrubsig.org shp->subshell = 0;
81510898Sroland.mainz@nrubsig.org if(fd)
81610898Sroland.mainz@nrubsig.org {
81710898Sroland.mainz@nrubsig.org shp->inpipe = pv;
81810898Sroland.mainz@nrubsig.org sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
81910898Sroland.mainz@nrubsig.org }
82010898Sroland.mainz@nrubsig.org else
82110898Sroland.mainz@nrubsig.org {
82210898Sroland.mainz@nrubsig.org shp->outpipe = pv;
82310898Sroland.mainz@nrubsig.org sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
82410898Sroland.mainz@nrubsig.org }
82510898Sroland.mainz@nrubsig.org shp->subshell = subshell;
82610898Sroland.mainz@nrubsig.org if(monitor)
82710898Sroland.mainz@nrubsig.org sh_onstate(SH_MONITOR);
82810898Sroland.mainz@nrubsig.org close(pv[1-fd]);
82910898Sroland.mainz@nrubsig.org sh_iosave(shp,-pv[fd], shp->topfd, (char*)0);
83010898Sroland.mainz@nrubsig.org return(ap);
83110898Sroland.mainz@nrubsig.org }
83210898Sroland.mainz@nrubsig.org
8334887Schin /* Argument expansion */
arg_expand(Shell_t * shp,register struct argnod * argp,struct argnod ** argchain,int flag)8348462SApril.Chin@Sun.COM static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag)
8354887Schin {
8364887Schin register int count = 0;
8374887Schin argp->argflag &= ~ARG_MAKE;
8384887Schin #if SHOPT_DEVFD
8394887Schin if(*argp->argval==0 && (argp->argflag&ARG_EXP))
8404887Schin {
84110898Sroland.mainz@nrubsig.org struct argnod *ap;
84210898Sroland.mainz@nrubsig.org ap = sh_argprocsub(shp,argp);
8434887Schin ap->argchn.ap = *argchain;
8444887Schin *argchain = ap;
8454887Schin count++;
8464887Schin }
8474887Schin else
8484887Schin #endif /* SHOPT_DEVFD */
8494887Schin if(!(argp->argflag&ARG_RAW))
8504887Schin {
8514887Schin #if SHOPT_OPTIMIZE
8524887Schin struct argnod *ap;
8538462SApril.Chin@Sun.COM sh_stats(STAT_ARGEXPAND);
8544887Schin if(flag&ARG_OPTIMIZE)
8554887Schin argp->argchn.ap=0;
8564887Schin if(ap=argp->argchn.ap)
8574887Schin {
8588462SApril.Chin@Sun.COM sh_stats(STAT_ARGHITS);
8594887Schin count = 1;
8604887Schin ap->argchn.ap = *argchain;
8614887Schin ap->argflag |= ARG_RAW;
8624887Schin ap->argflag &= ~ARG_EXP;
8634887Schin *argchain = ap;
8644887Schin }
8654887Schin else
8664887Schin #endif /* SHOPT_OPTIMIZE */
8678462SApril.Chin@Sun.COM count = sh_macexpand(shp,argp,argchain,flag);
8684887Schin }
8694887Schin else
8704887Schin {
8714887Schin argp->argchn.ap = *argchain;
8724887Schin *argchain = argp;
8734887Schin argp->argflag |= ARG_MAKE;
8744887Schin count++;
8754887Schin }
8764887Schin return(count);
8774887Schin }
8784887Schin
879