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  * exec [arg...]
23*4887Schin  * eval [arg...]
24*4887Schin  * jobs [-lnp] [job...]
25*4887Schin  * login [arg...]
26*4887Schin  * let expr...
27*4887Schin  * . file [arg...]
28*4887Schin  * :, true, false
29*4887Schin  * vpath [top] [base]
30*4887Schin  * vmap [top] [base]
31*4887Schin  * wait [job...]
32*4887Schin  * shift [n]
33*4887Schin  *
34*4887Schin  *   David Korn
35*4887Schin  *   AT&T Labs
36*4887Schin  *
37*4887Schin  */
38*4887Schin 
39*4887Schin #include	"defs.h"
40*4887Schin #include	"variables.h"
41*4887Schin #include	"shnodes.h"
42*4887Schin #include	"path.h"
43*4887Schin #include	"io.h"
44*4887Schin #include	"name.h"
45*4887Schin #include	"history.h"
46*4887Schin #include	"builtins.h"
47*4887Schin #include	"jobs.h"
48*4887Schin 
49*4887Schin #define DOTMAX	MAXDEPTH	/* maximum level of . nesting */
50*4887Schin 
51*4887Schin static void     noexport(Namval_t*,void*);
52*4887Schin 
53*4887Schin struct login
54*4887Schin {
55*4887Schin 	Shell_t *sh;
56*4887Schin 	int     clear;
57*4887Schin 	char    *arg0;
58*4887Schin };
59*4887Schin 
60*4887Schin int    b_exec(int argc,char *argv[], void *extra)
61*4887Schin {
62*4887Schin 	struct login logdata;
63*4887Schin 	register int n;
64*4887Schin 	logdata.clear = 0;
65*4887Schin 	logdata.arg0 = 0;
66*4887Schin 	logdata.sh = (Shell_t*)extra;
67*4887Schin         logdata.sh->st.ioset = 0;
68*4887Schin 	while (n = optget(argv, sh_optexec)) switch (n)
69*4887Schin 	{
70*4887Schin 	    case 'a':
71*4887Schin 		logdata.arg0 = opt_info.arg;
72*4887Schin 		argc = 0;
73*4887Schin 		break;
74*4887Schin 	    case 'c':
75*4887Schin 		logdata.clear=1;
76*4887Schin 		break;
77*4887Schin 	    case ':':
78*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
79*4887Schin 		break;
80*4887Schin 	    case '?':
81*4887Schin 		errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
82*4887Schin 		return(2);
83*4887Schin 	}
84*4887Schin 	argv += opt_info.index;
85*4887Schin 	if(error_info.errors)
86*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
87*4887Schin 	if(*argv)
88*4887Schin                 B_login(0,argv,(void*)&logdata);
89*4887Schin 	return(0);
90*4887Schin }
91*4887Schin 
92*4887Schin static void     noexport(register Namval_t* np, void *data)
93*4887Schin {
94*4887Schin 	NOT_USED(data);
95*4887Schin 	nv_offattr(np,NV_EXPORT);
96*4887Schin }
97*4887Schin 
98*4887Schin int    B_login(int argc,char *argv[],void *extra)
99*4887Schin {
100*4887Schin 	struct checkpt *pp;
101*4887Schin 	register struct login *logp=0;
102*4887Schin 	register Shell_t *shp;
103*4887Schin 	const char *pname;
104*4887Schin 	if(argc)
105*4887Schin 		shp = (Shell_t*)extra;
106*4887Schin 	else
107*4887Schin 	{
108*4887Schin 		logp = (struct login*)extra;
109*4887Schin 		shp = logp->sh;
110*4887Schin 	}
111*4887Schin 	pp = (struct checkpt*)shp->jmplist;
112*4887Schin 	if(sh_isoption(SH_RESTRICTED))
113*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[0]);
114*4887Schin 	else
115*4887Schin         {
116*4887Schin 		register struct argnod *arg=shp->envlist;
117*4887Schin 		register Namval_t* np;
118*4887Schin 		register char *cp;
119*4887Schin 		if(shp->subshell)
120*4887Schin 			sh_subfork();
121*4887Schin 		if(logp && logp->clear)
122*4887Schin 		{
123*4887Schin #ifdef _ENV_H
124*4887Schin 			env_close(shp->env);
125*4887Schin 			shp->env = env_open((char**)0,3);
126*4887Schin #else
127*4887Schin 			nv_scan(shp->var_tree,noexport,0,NV_EXPORT,NV_EXPORT);
128*4887Schin #endif
129*4887Schin 		}
130*4887Schin 		while(arg)
131*4887Schin 		{
132*4887Schin 			if((cp=strchr(arg->argval,'=')) &&
133*4887Schin 				(*cp=0,np=nv_search(arg->argval,shp->var_tree,0)))
134*4887Schin 			{
135*4887Schin 				nv_onattr(np,NV_EXPORT);
136*4887Schin 				sh_envput(shp->env,np);
137*4887Schin 			}
138*4887Schin 			if(cp)
139*4887Schin 				*cp = '=';
140*4887Schin 			arg=arg->argnxt.ap;
141*4887Schin 		}
142*4887Schin 		pname = argv[0];
143*4887Schin 		if(logp && logp->arg0)
144*4887Schin 			argv[0] = logp->arg0;
145*4887Schin #ifdef JOBS
146*4887Schin 		if(job_close() < 0)
147*4887Schin 			return(1);
148*4887Schin #endif /* JOBS */
149*4887Schin 		/* force bad exec to terminate shell */
150*4887Schin 		pp->mode = SH_JMPEXIT;
151*4887Schin 		sh_sigreset(2);
152*4887Schin 		sh_freeup();
153*4887Schin 		path_exec(pname,argv,NIL(struct argnod*));
154*4887Schin 		sh_done(0);
155*4887Schin         }
156*4887Schin 	return(1);
157*4887Schin }
158*4887Schin 
159*4887Schin int    b_let(int argc,char *argv[],void *extra)
160*4887Schin {
161*4887Schin 	register int r;
162*4887Schin 	register char *arg;
163*4887Schin 	NOT_USED(argc);
164*4887Schin 	NOT_USED(extra);
165*4887Schin 	while (r = optget(argv,sh_optlet)) switch (r)
166*4887Schin 	{
167*4887Schin 	    case ':':
168*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
169*4887Schin 		break;
170*4887Schin 	    case '?':
171*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
172*4887Schin 		break;
173*4887Schin 	}
174*4887Schin 	argv += opt_info.index;
175*4887Schin 	if(error_info.errors || !*argv)
176*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
177*4887Schin 	while(arg= *argv++)
178*4887Schin 		r = !sh_arith(arg);
179*4887Schin 	return(r);
180*4887Schin }
181*4887Schin 
182*4887Schin int    b_eval(int argc,char *argv[], void *extra)
183*4887Schin {
184*4887Schin 	register int r;
185*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
186*4887Schin 	NOT_USED(argc);
187*4887Schin 	while (r = optget(argv,sh_opteval)) switch (r)
188*4887Schin 	{
189*4887Schin 	    case ':':
190*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
191*4887Schin 		break;
192*4887Schin 	    case '?':
193*4887Schin 		errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
194*4887Schin 		return(2);
195*4887Schin 	}
196*4887Schin 	if(error_info.errors)
197*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
198*4887Schin 	argv += opt_info.index;
199*4887Schin 	if(*argv && **argv)
200*4887Schin 	{
201*4887Schin 		sh_offstate(SH_MONITOR);
202*4887Schin 		sh_eval(sh_sfeval(argv),0);
203*4887Schin 	}
204*4887Schin 	return(shp->exitval);
205*4887Schin }
206*4887Schin 
207*4887Schin int    b_dot_cmd(register int n,char *argv[],void* extra)
208*4887Schin {
209*4887Schin 	register char *script;
210*4887Schin 	register Namval_t *np;
211*4887Schin 	register int jmpval;
212*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
213*4887Schin 	struct sh_scoped savst, *prevscope = shp->st.self;
214*4887Schin 	char *filename=0;
215*4887Schin 	int	fd;
216*4887Schin 	struct dolnod   *argsave=0, *saveargfor;
217*4887Schin 	struct checkpt buff;
218*4887Schin 	Sfio_t *iop=0;
219*4887Schin 	NOT_USED(extra);
220*4887Schin 	while (n = optget(argv,sh_optdot)) switch (n)
221*4887Schin 	{
222*4887Schin 	    case ':':
223*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
224*4887Schin 		break;
225*4887Schin 	    case '?':
226*4887Schin 		errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
227*4887Schin 		return(2);
228*4887Schin 	}
229*4887Schin 	argv += opt_info.index;
230*4887Schin 	script = *argv;
231*4887Schin 	if(error_info.errors || !script)
232*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
233*4887Schin 	if(shp->dot_depth++ > DOTMAX)
234*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script);
235*4887Schin 	shp->st.lineno = error_info.line;
236*4887Schin 	if(!(np=shp->posix_fun))
237*4887Schin 	{
238*4887Schin 		/* check for KornShell style function first */
239*4887Schin 		np = nv_search(script,shp->fun_tree,0);
240*4887Schin 		if(np && is_afunction(np) && !nv_isattr(np,NV_FPOSIX))
241*4887Schin 		{
242*4887Schin 			if(!np->nvalue.ip)
243*4887Schin 			{
244*4887Schin #ifdef PATH_BFPATH
245*4887Schin 				path_search(script,NIL(Pathcomp_t*),0);
246*4887Schin #else
247*4887Schin 				path_search(script,NIL(char*),0);
248*4887Schin #endif
249*4887Schin 				if(np->nvalue.ip)
250*4887Schin 				{
251*4887Schin 					if(nv_isattr(np,NV_FPOSIX))
252*4887Schin 						np = 0;
253*4887Schin 				}
254*4887Schin 				else
255*4887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_found,script);
256*4887Schin 			}
257*4887Schin 		}
258*4887Schin 		else
259*4887Schin 			np = 0;
260*4887Schin 		if(!np)
261*4887Schin 		{
262*4887Schin 			if((fd=path_open(script,path_get(script))) < 0)
263*4887Schin 				errormsg(SH_DICT,ERROR_system(1),e_open,script);
264*4887Schin 			filename = path_fullname(stakptr(PATH_OFFSET));
265*4887Schin 		}
266*4887Schin 	}
267*4887Schin 	*prevscope = shp->st;
268*4887Schin 	if(filename)
269*4887Schin 		shp->st.filename = filename;
270*4887Schin 	shp->st.prevst = prevscope;
271*4887Schin 	shp->st.self = &savst;
272*4887Schin 	shp->topscope = (Shscope_t*)shp->st.self;
273*4887Schin 	prevscope->save_tree = shp->var_tree;
274*4887Schin 	shp->st.cmdname = argv[0];
275*4887Schin 	if(np)
276*4887Schin 		shp->st.filename = np->nvalue.rp->fname;
277*4887Schin 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
278*4887Schin 	shp->posix_fun = 0;
279*4887Schin 	if(np || argv[1])
280*4887Schin 		argsave = sh_argnew(argv,&saveargfor);
281*4887Schin 	sh_pushcontext(&buff,SH_JMPDOT);
282*4887Schin 	jmpval = sigsetjmp(buff.buff,0);
283*4887Schin 	if(jmpval == 0)
284*4887Schin 	{
285*4887Schin 		if(np)
286*4887Schin 			sh_exec((Shnode_t*)(nv_funtree(np)),sh_isstate(SH_ERREXIT));
287*4887Schin 		else
288*4887Schin 		{
289*4887Schin 			char buff[IOBSIZE+1];
290*4887Schin 			iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fd,SF_READ);
291*4887Schin 			sh_eval(iop,0);
292*4887Schin 		}
293*4887Schin 	}
294*4887Schin 	sh_popcontext(&buff);
295*4887Schin 	if(!np)
296*4887Schin 		free((void*)shp->st.filename);
297*4887Schin 	shp->dot_depth--;
298*4887Schin 	if((np || argv[1]) && jmpval!=SH_JMPSCRIPT)
299*4887Schin 		sh_argreset(argsave,saveargfor);
300*4887Schin 	else
301*4887Schin 	{
302*4887Schin 		prevscope->dolc = shp->st.dolc;
303*4887Schin 		prevscope->dolv = shp->st.dolv;
304*4887Schin 	}
305*4887Schin 	if (shp->st.self != &savst)
306*4887Schin 		*shp->st.self = shp->st;
307*4887Schin 	/* only restore the top Shscope_t portion for posix functions */
308*4887Schin 	memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t));
309*4887Schin 	shp->topscope = (Shscope_t*)prevscope;
310*4887Schin 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
311*4887Schin 	if(shp->exitval > SH_EXITSIG)
312*4887Schin 		sh_fault(shp->exitval&SH_EXITMASK);
313*4887Schin 	if(jmpval && jmpval!=SH_JMPFUN)
314*4887Schin 		siglongjmp(*shp->jmplist,jmpval);
315*4887Schin 	return(shp->exitval);
316*4887Schin }
317*4887Schin 
318*4887Schin /*
319*4887Schin  * null, true  command
320*4887Schin  */
321*4887Schin int    b_true(int argc,register char *argv[],void *extra)
322*4887Schin {
323*4887Schin 	NOT_USED(argc);
324*4887Schin 	NOT_USED(argv[0]);
325*4887Schin 	NOT_USED(extra);
326*4887Schin 	return(0);
327*4887Schin }
328*4887Schin 
329*4887Schin /*
330*4887Schin  * false  command
331*4887Schin  */
332*4887Schin int    b_false(int argc,register char *argv[], void *extra)
333*4887Schin {
334*4887Schin 	NOT_USED(argc);
335*4887Schin 	NOT_USED(argv[0]);
336*4887Schin 	NOT_USED(extra);
337*4887Schin 	return(1);
338*4887Schin }
339*4887Schin 
340*4887Schin int    b_shift(register int n, register char *argv[], void *extra)
341*4887Schin {
342*4887Schin 	register char *arg;
343*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
344*4887Schin 	while((n = optget(argv,sh_optshift))) switch(n)
345*4887Schin 	{
346*4887Schin 		case ':':
347*4887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
348*4887Schin 			break;
349*4887Schin 		case '?':
350*4887Schin 			errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
351*4887Schin 			return(2);
352*4887Schin 	}
353*4887Schin 	if(error_info.errors)
354*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
355*4887Schin 	argv += opt_info.index;
356*4887Schin 	n = ((arg= *argv)?(int)sh_arith(arg):1);
357*4887Schin 	if(n<0 || shp->st.dolc<n)
358*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_number,arg);
359*4887Schin 	else
360*4887Schin 	{
361*4887Schin 		shp->st.dolv += n;
362*4887Schin 		shp->st.dolc -= n;
363*4887Schin 	}
364*4887Schin 	return(0);
365*4887Schin }
366*4887Schin 
367*4887Schin int    b_wait(int n,register char *argv[],void *extra)
368*4887Schin {
369*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
370*4887Schin 	while((n = optget(argv,sh_optwait))) switch(n)
371*4887Schin 	{
372*4887Schin 		case ':':
373*4887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
374*4887Schin 			break;
375*4887Schin 		case '?':
376*4887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
377*4887Schin 			break;
378*4887Schin 	}
379*4887Schin 	if(error_info.errors)
380*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
381*4887Schin 	argv += opt_info.index;
382*4887Schin 	job_bwait(argv);
383*4887Schin 	return(shp->exitval);
384*4887Schin }
385*4887Schin 
386*4887Schin #ifdef JOBS
387*4887Schin #   if 0
388*4887Schin     /* for the dictionary generator */
389*4887Schin 	int    b_fg(int n,char *argv[],void *extra){}
390*4887Schin 	int    b_disown(int n,char *argv[],void *extra){}
391*4887Schin #   endif
392*4887Schin int    b_bg(register int n,register char *argv[],void *extra)
393*4887Schin {
394*4887Schin 	register int flag = **argv;
395*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
396*4887Schin 	register const char *optstr = sh_optbg;
397*4887Schin 	if(*argv[0]=='f')
398*4887Schin 		optstr = sh_optfg;
399*4887Schin 	else if(*argv[0]=='d')
400*4887Schin 		optstr = sh_optdisown;
401*4887Schin 	while((n = optget(argv,optstr))) switch(n)
402*4887Schin 	{
403*4887Schin 	    case ':':
404*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
405*4887Schin 		break;
406*4887Schin 	    case '?':
407*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
408*4887Schin 		break;
409*4887Schin 	}
410*4887Schin 	if(error_info.errors)
411*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
412*4887Schin 	argv += opt_info.index;
413*4887Schin 	if(!sh_isoption(SH_MONITOR) || !job.jobcontrol)
414*4887Schin 	{
415*4887Schin 		if(sh_isstate(SH_INTERACTIVE))
416*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_no_jctl);
417*4887Schin 		return(1);
418*4887Schin 	}
419*4887Schin 	if(flag=='d' && *argv==0)
420*4887Schin 		argv = (char**)0;
421*4887Schin 	if(job_walk(sfstdout,job_switch,flag,argv))
422*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_no_job);
423*4887Schin 	return(shp->exitval);
424*4887Schin }
425*4887Schin 
426*4887Schin int    b_jobs(register int n,char *argv[],void *extra)
427*4887Schin {
428*4887Schin 	register int flag = 0;
429*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
430*4887Schin 	while((n = optget(argv,sh_optjobs))) switch(n)
431*4887Schin 	{
432*4887Schin 	    case 'l':
433*4887Schin 		flag = JOB_LFLAG;
434*4887Schin 		break;
435*4887Schin 	    case 'n':
436*4887Schin 		flag = JOB_NFLAG;
437*4887Schin 		break;
438*4887Schin 	    case 'p':
439*4887Schin 		flag = JOB_PFLAG;
440*4887Schin 		break;
441*4887Schin 	    case ':':
442*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
443*4887Schin 		break;
444*4887Schin 	    case '?':
445*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
446*4887Schin 		break;
447*4887Schin 	}
448*4887Schin 	argv += opt_info.index;
449*4887Schin 	if(error_info.errors)
450*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
451*4887Schin 	if(*argv==0)
452*4887Schin 		argv = (char**)0;
453*4887Schin 	if(job_walk(sfstdout,job_list,flag,argv))
454*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_no_job);
455*4887Schin 	job_wait((pid_t)0);
456*4887Schin 	return(shp->exitval);
457*4887Schin }
458*4887Schin #endif
459*4887Schin 
460*4887Schin #ifdef _cmd_universe
461*4887Schin /*
462*4887Schin  * There are several universe styles that are masked by the getuniv(),
463*4887Schin  * setuniv() calls.
464*4887Schin  */
465*4887Schin int	b_universe(int argc, char *argv[],void *extra)
466*4887Schin {
467*4887Schin 	register char *arg;
468*4887Schin 	register int n;
469*4887Schin 	NOT_USED(extra);
470*4887Schin 	while((n = optget(argv,sh_optuniverse))) switch(n)
471*4887Schin 	{
472*4887Schin 	    case ':':
473*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
474*4887Schin 		break;
475*4887Schin 	    case '?':
476*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
477*4887Schin 		break;
478*4887Schin 	}
479*4887Schin 	argv += opt_info.index;
480*4887Schin 	argc -= opt_info.index;
481*4887Schin 	if(error_info.errors || argc>1)
482*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
483*4887Schin 	if(arg = argv[0])
484*4887Schin 	{
485*4887Schin 		if(!astconf("UNIVERSE",0,arg))
486*4887Schin 			errormsg(SH_DICT,ERROR_exit(1), e_badname,arg);
487*4887Schin 	}
488*4887Schin 	else
489*4887Schin 	{
490*4887Schin 		if(!(arg=astconf("UNIVERSE",0,0)))
491*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_nouniverse);
492*4887Schin 		else
493*4887Schin 			sfputr(sfstdout,arg,'\n');
494*4887Schin 	}
495*4887Schin 	return(0);
496*4887Schin }
497*4887Schin #endif /* cmd_universe */
498*4887Schin 
499*4887Schin #if SHOPT_FS_3D
500*4887Schin #   if 0
501*4887Schin     /* for the dictionary generator */
502*4887Schin     int	b_vmap(int argc,char *argv[], void *extra){}
503*4887Schin #   endif
504*4887Schin     int	b_vpath(register int argc,char *argv[], void *extra)
505*4887Schin     {
506*4887Schin 	register int flag, n;
507*4887Schin 	register const char *optstr;
508*4887Schin 	register char *vend;
509*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
510*4887Schin 	if(argv[0][1]=='p')
511*4887Schin 	{
512*4887Schin 		optstr = sh_optvpath;
513*4887Schin 		flag = FS3D_VIEW;
514*4887Schin 	}
515*4887Schin 	else
516*4887Schin 	{
517*4887Schin 		optstr = sh_optvmap;
518*4887Schin 		flag = FS3D_VERSION;
519*4887Schin 	}
520*4887Schin 	while(n = optget(argv, optstr)) switch(n)
521*4887Schin 	{
522*4887Schin 	    case ':':
523*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
524*4887Schin 		break;
525*4887Schin 	    case '?':
526*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
527*4887Schin 		break;
528*4887Schin 	}
529*4887Schin 	if(error_info.errors)
530*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
531*4887Schin 	if(!shp->lim.fs3d)
532*4887Schin 		goto failed;
533*4887Schin 	argv += opt_info.index;
534*4887Schin 	argc -= opt_info.index;
535*4887Schin 	switch(argc)
536*4887Schin 	{
537*4887Schin 	    case 0:
538*4887Schin 	    case 1:
539*4887Schin 		flag |= FS3D_GET;
540*4887Schin 		if((n = mount(*argv,(char*)0,flag,0)) >= 0)
541*4887Schin 		{
542*4887Schin 			vend = stakalloc(++n);
543*4887Schin 			n = mount(*argv,vend,flag|FS3D_SIZE(n),0);
544*4887Schin 		}
545*4887Schin 		if(n < 0)
546*4887Schin 			goto failed;
547*4887Schin 		if(argc==1)
548*4887Schin 		{
549*4887Schin 			sfprintf(sfstdout,"%s\n",vend);
550*4887Schin 			break;
551*4887Schin 		}
552*4887Schin 		n = 0;
553*4887Schin 		while(flag = *vend++)
554*4887Schin 		{
555*4887Schin 			if(flag==' ')
556*4887Schin 			{
557*4887Schin 				flag  = e_sptbnl[n+1];
558*4887Schin 				n = !n;
559*4887Schin 			}
560*4887Schin 			sfputc(sfstdout,flag);
561*4887Schin 		}
562*4887Schin 		if(n)
563*4887Schin 			sfputc(sfstdout,'\n');
564*4887Schin 		break;
565*4887Schin 	     default:
566*4887Schin 		if((argc&1))
567*4887Schin 			errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
568*4887Schin 		/*FALLTHROUGH*/
569*4887Schin 	     case 2:
570*4887Schin 		if(!shp->lim.fs3d)
571*4887Schin 			goto failed;
572*4887Schin 		if(shp->subshell)
573*4887Schin 			sh_subfork();
574*4887Schin  		for(n=0;n<argc;n+=2)
575*4887Schin 		{
576*4887Schin 			if(mount(argv[n+1],argv[n],flag,0)<0)
577*4887Schin 				goto failed;
578*4887Schin 		}
579*4887Schin 	}
580*4887Schin 	return(0);
581*4887Schin failed:
582*4887Schin 	if(argc>1)
583*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_cantset,flag==2?e_mapping:e_versions);
584*4887Schin 	else
585*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_cantget,flag==2?e_mapping:e_versions);
586*4887Schin 	return(1);
587*4887Schin     }
588*4887Schin #endif /* SHOPT_FS_3D */
589*4887Schin 
590