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