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