xref: /titanic_50/usr/src/lib/libshell/common/bltins/typeset.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * export [-p] [arg...]
23  * readonly [-p] [arg...]
24  * typeset [options]  [arg...]
25  * alias [-ptx] [arg...]
26  * unalias [arg...]
27  * builtin [-sd] [-f file] [name...]
28  * set [options] [name...]
29  * unset [-fnv] [name...]
30  *
31  *   David Korn
32  *   AT&T Labs
33  *
34  */
35 
36 #include	"defs.h"
37 #include	<error.h>
38 #include	"path.h"
39 #include	"name.h"
40 #include	"history.h"
41 #include	"builtins.h"
42 #include	"variables.h"
43 #include	"FEATURE/dynamic"
44 
45 struct tdata
46 {
47 	Shell_t 	*sh;
48 	Namval_t	*tp;
49 	Sfio_t  	*outfile;
50 	char    	*prefix;
51 	char    	*tname;
52 	char		*help;
53 	short     	aflag;
54 	short     	pflag;
55 	int     	argnum;
56 	int     	scanmask;
57 	Dt_t 		*scanroot;
58 	char    	**argnam;
59 };
60 
61 
62 static int	print_namval(Sfio_t*, Namval_t*, int, struct tdata*);
63 static void	print_attribute(Namval_t*,void*);
64 static void	print_all(Sfio_t*, Dt_t*, struct tdata*);
65 static void	print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*);
66 static int	b_unall(int, char**, Dt_t*, Shell_t*);
67 static int	b_common(char**, int, Dt_t*, struct tdata*);
68 static void	pushname(Namval_t*,void*);
69 static void(*nullscan)(Namval_t*,void*);
70 
load_class(const char * name)71 static Namval_t *load_class(const char *name)
72 {
73 	errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name);
74 	return(0);
75 }
76 
77 /*
78  * Note export and readonly are the same
79  */
80 #if 0
81     /* for the dictionary generator */
82     int    b_export(int argc,char *argv[],void *extra){}
83 #endif
b_readonly(int argc,char * argv[],void * extra)84 int    b_readonly(int argc,char *argv[],void *extra)
85 {
86 	register int flag;
87 	char *command = argv[0];
88 	struct tdata tdata;
89 	NOT_USED(argc);
90 	memset((void*)&tdata,0,sizeof(tdata));
91 	tdata.sh = ((Shbltin_t*)extra)->shp;
92 	tdata.aflag = '-';
93 	while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag)
94 	{
95 		case 'p':
96 			tdata.prefix = command;
97 			break;
98 		case ':':
99 			errormsg(SH_DICT,2, "%s", opt_info.arg);
100 			break;
101 		case '?':
102 			errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
103 			return(2);
104 	}
105 	if(error_info.errors)
106 		errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
107 	argv += (opt_info.index-1);
108 	if(*command=='r')
109 		flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME);
110 #ifdef _ENV_H
111 	else if(!argv[1])
112 	{
113 		char *cp,**env=env_get(tdata.sh->env);
114 		while(cp = *env++)
115 		{
116 			if(tdata.prefix)
117 				sfputr(sfstdout,tdata.prefix,' ');
118 			sfprintf(sfstdout,"%s\n",sh_fmtq(cp));
119 		}
120 		return(0);
121 	}
122 #endif
123 	else
124 	{
125 		flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT);
126 		if(!tdata.sh->prefix)
127 			tdata.sh->prefix = "";
128 	}
129 	return(b_common(argv,flag,tdata.sh->var_tree, &tdata));
130 }
131 
132 
b_alias(int argc,register char * argv[],void * extra)133 int    b_alias(int argc,register char *argv[],void *extra)
134 {
135 	register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN;
136 	register Dt_t *troot;
137 	register int n;
138 	struct tdata tdata;
139 	NOT_USED(argc);
140 	memset((void*)&tdata,0,sizeof(tdata));
141 	tdata.sh = ((Shbltin_t*)extra)->shp;
142 	troot = tdata.sh->alias_tree;
143 	if(*argv[0]=='h')
144 		flag = NV_TAGGED;
145 	if(argv[1])
146 	{
147 		opt_info.offset = 0;
148 		opt_info.index = 1;
149 		*opt_info.option = 0;
150 		tdata.argnum = 0;
151 		tdata.aflag = *argv[1];
152 		while((n = optget(argv,sh_optalias))) switch(n)
153 		{
154 		    case 'p':
155 			tdata.prefix = argv[0];
156 			break;
157 		    case 't':
158 			flag |= NV_TAGGED;
159 			break;
160 		    case 'x':
161 			flag |= NV_EXPORT;
162 			break;
163 		    case ':':
164 			errormsg(SH_DICT,2, "%s", opt_info.arg);
165 			break;
166 		    case '?':
167 			errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
168 			return(2);
169 		}
170 		if(error_info.errors)
171 			errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
172 		argv += (opt_info.index-1);
173 		if(flag&NV_TAGGED)
174 		{
175 			/* hacks to handle hash -r | -- */
176 			if(argv[1] && argv[1][0]=='-')
177 			{
178 				if(argv[1][1]=='r' && argv[1][2]==0)
179 				{
180 					nv_putval(PATHNOD,nv_getval(PATHNOD),NV_RDONLY);
181 					argv++;
182 					if(!argv[1])
183 						return(0);
184 				}
185 				if(argv[1][0]=='-')
186 				{
187 					if(argv[1][1]=='-' && argv[1][2]==0)
188 						argv++;
189 					else
190 						errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]);
191 		}
192 			}
193 			troot = tdata.sh->track_tree;
194 		}
195 	}
196 	return(b_common(argv,flag,troot,&tdata));
197 }
198 
199 
200 #if 0
201     /* for the dictionary generator */
202     int    b_local(int argc,char *argv[],void *extra){}
203 #endif
b_typeset(int argc,register char * argv[],void * extra)204 int    b_typeset(int argc,register char *argv[],void *extra)
205 {
206 	register int	n, flag = NV_VARNAME|NV_ASSIGN;
207 	struct tdata	tdata;
208 	const char	*optstring = sh_opttypeset;
209 	Namdecl_t 	*ntp = (Namdecl_t*)((Shbltin_t*)extra)->ptr;
210 	Dt_t		*troot;
211 	int		isfloat=0, shortint=0, sflag=0;
212 	NOT_USED(argc);
213 	memset((void*)&tdata,0,sizeof(tdata));
214 	tdata.sh = ((Shbltin_t*)extra)->shp;
215 	if(ntp)
216 	{
217 		tdata.tp = ntp->tp;
218 		opt_info.disc = (Optdisc_t*)ntp->optinfof;
219 		optstring = ntp->optstring;
220 	}
221 	troot = tdata.sh->var_tree;
222 	while((n = optget(argv,optstring)))
223 	{
224 		switch(n)
225 		{
226 			case 'a':
227 				flag |= NV_IARRAY;
228 				if(opt_info.arg && *opt_info.arg!='[')
229 				{
230 					opt_info.index--;
231 					goto endargs;
232 				}
233 				tdata.tname = opt_info.arg;
234 				break;
235 			case 'A':
236 				flag |= NV_ARRAY;
237 				break;
238 			case 'C':
239 				flag |= NV_COMVAR;
240 				break;
241 			case 'E':
242 				/* The following is for ksh88 compatibility */
243 				if(opt_info.offset && !strchr(argv[opt_info.index],'E'))
244 				{
245 					tdata.argnum = (int)opt_info.num;
246 					break;
247 				}
248 			case 'F':
249 			case 'X':
250 				if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
251 					tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10);
252 				isfloat = 1;
253 				if(n=='E')
254 				{
255 					flag &= ~NV_HEXFLOAT;
256 					flag |= NV_EXPNOTE;
257 				}
258 				else if(n=='X')
259 				{
260 					flag &= ~NV_EXPNOTE;
261 					flag |= NV_HEXFLOAT;
262 				}
263 				break;
264 			case 'b':
265 				flag |= NV_BINARY;
266 				break;
267 			case 'm':
268 				flag |= NV_MOVE;
269 				break;
270 			case 'n':
271 				flag &= ~NV_VARNAME;
272 				flag |= (NV_REF|NV_IDENT);
273 				break;
274 			case 'H':
275 				flag |= NV_HOST;
276 				break;
277 			case 'T':
278 				flag |= NV_TYPE;
279 				tdata.prefix = opt_info.arg;
280 				break;
281 			case 'L': case 'Z': case 'R':
282 				if(tdata.argnum==0)
283 					tdata.argnum = (int)opt_info.num;
284 				if(tdata.argnum < 0)
285 					errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum);
286 				if(n=='Z')
287 					flag |= NV_ZFILL;
288 				else
289 				{
290 					flag &= ~(NV_LJUST|NV_RJUST);
291 					flag |= (n=='L'?NV_LJUST:NV_RJUST);
292 				}
293 				break;
294 			case 'f':
295 				flag &= ~(NV_VARNAME|NV_ASSIGN);
296 				troot = tdata.sh->fun_tree;
297 				break;
298 			case 'i':
299 				if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
300 					tdata.argnum = 10;
301 				flag |= NV_INTEGER;
302 				break;
303 			case 'l':
304 				flag |= NV_UTOL;
305 				break;
306 			case 'p':
307 				tdata.prefix = argv[0];
308 				tdata.pflag = 1;
309 				break;
310 			case 'r':
311 				flag |= NV_RDONLY;
312 				break;
313 #ifdef SHOPT_TYPEDEF
314 			case 'S':
315 				sflag=1;
316 				break;
317 			case 'h':
318 				tdata.help = opt_info.arg;
319 				break;
320 #endif /*SHOPT_TYPEDEF*/
321 			case 's':
322 				shortint=1;
323 				break;
324 			case 't':
325 				flag |= NV_TAGGED;
326 				break;
327 			case 'u':
328 				flag |= NV_LTOU;
329 				break;
330 			case 'x':
331 				flag &= ~NV_VARNAME;
332 				flag |= (NV_EXPORT|NV_IDENT);
333 				break;
334 			case ':':
335 				errormsg(SH_DICT,2, "%s", opt_info.arg);
336 				break;
337 			case '?':
338 				errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
339 				opt_info.disc = 0;
340 				return(2);
341 		}
342 		if(tdata.aflag==0)
343 			tdata.aflag = *opt_info.option;
344 	}
345 endargs:
346 	argv += opt_info.index;
347 	opt_info.disc = 0;
348 	/* handle argument of + and - specially */
349 	if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-'))
350 		tdata.aflag = *argv[0];
351 	else
352 		argv--;
353 	if((flag&NV_ZFILL) && !(flag&NV_LJUST))
354 		flag |= NV_RJUST;
355 	if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL)))
356 		error_info.errors++;
357 	if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU)))
358 		error_info.errors++;
359 	if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN)))
360 		error_info.errors++;
361 	if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN)))
362 		error_info.errors++;
363 	if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU))))
364 		error_info.errors++;
365 	if(error_info.errors)
366 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
367 	if(isfloat)
368 		flag |= NV_DOUBLE;
369 	if(shortint)
370 		flag |= NV_SHORT|NV_INTEGER;
371 	if(sflag)
372 	{
373 		if(tdata.sh->mktype)
374 			flag |= NV_REF|NV_TAGGED;
375 		else if(!tdata.sh->typeinit)
376 			flag |= NV_STATIC|NV_IDENT;
377 	}
378 	if(tdata.sh->fn_depth && !tdata.pflag)
379 		flag |= NV_NOSCOPE;
380 	if(flag&NV_TYPE)
381 	{
382 		Stk_t *stkp = tdata.sh->stk;
383 		int offset = stktell(stkp);
384 		sfputr(stkp,NV_CLASS,-1);
385 		if(NV_CLASS[sizeof(NV_CLASS)-2]!='.')
386 			sfputc(stkp,'.');
387 		sfputr(stkp,tdata.prefix,0);
388 		tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN);
389 		stkseek(stkp,offset);
390 		if(!tdata.tp)
391 			errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix);
392 		else if(nv_isnull(tdata.tp))
393 			nv_newtype(tdata.tp);
394 		tdata.tp->nvenv = tdata.help;
395 		flag &= ~NV_TYPE;
396 	}
397 	else if(tdata.aflag==0 && ntp && ntp->tp)
398 		tdata.aflag = '-';
399 	if(!tdata.sh->mktype)
400 		tdata.help = 0;
401 	return(b_common(argv,flag,troot,&tdata));
402 }
403 
print_value(Sfio_t * iop,Namval_t * np,struct tdata * tp)404 static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp)
405 {
406 	char	 *name;
407 	int	aflag=tp->aflag;
408 	if(nv_isnull(np))
409 	{
410 		if(!np->nvflag)
411 			return;
412 		aflag = '+';
413 	}
414 	sfputr(iop,nv_name(np),aflag=='+'?'\n':'=');
415 	if(aflag=='+')
416 		return;
417 	if(nv_isarray(np) && nv_arrayptr(np))
418 	{
419 		nv_outnode(np,iop,-1,0);
420 		sfwrite(iop,")\n",2);
421 	}
422 	else
423 	{
424 		if(nv_isvtree(np))
425 			nv_onattr(np,NV_EXPORT);
426 		if(!(name = nv_getval(np)))
427 			name = Empty;
428 		if(!nv_isvtree(np))
429 			name = sh_fmtq(name);
430 		sfputr(iop,name,'\n');
431 	}
432 }
433 
b_common(char ** argv,register int flag,Dt_t * troot,struct tdata * tp)434 static int     b_common(char **argv,register int flag,Dt_t *troot,struct tdata *tp)
435 {
436 	register char *name;
437 	char *last = 0;
438 	int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE));
439 	int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY);
440 	Shell_t *shp =tp->sh;
441 	if(!shp->prefix)
442 	{
443 		if(!tp->pflag)
444 			nvflags |= NV_NOSCOPE;
445 	}
446 	else if(*shp->prefix==0)
447 		shp->prefix = 0;
448 	flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY);
449 	if(argv[1])
450 	{
451 		if(flag&NV_REF)
452 		{
453 			flag &= ~NV_REF;
454 			ref=1;
455 			if(tp->aflag!='-')
456 				nvflags |= NV_NOREF;
457 		}
458 		if(tp->pflag)
459 			nvflags |= NV_NOREF;
460 		while(name = *++argv)
461 		{
462 			register unsigned newflag;
463 			register Namval_t *np;
464 			unsigned curflag;
465 			if(troot == shp->fun_tree)
466 			{
467 				/*
468 				 *functions can be exported or
469 				 * traced but not set
470 				 */
471 				flag &= ~NV_ASSIGN;
472 				if(flag&NV_LTOU)
473 				{
474 					/* Function names cannot be special builtin */
475 					if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
476 						errormsg(SH_DICT,ERROR_exit(1),e_badfun,name);
477 					np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE);
478 				}
479 				else  if((np=nv_search(name,troot,0)) && !is_afunction(np))
480 					np = 0;
481 				if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU)))
482 				{
483 					if(flag==0)
484 					{
485 						print_namval(sfstdout,np,tp->aflag=='+',tp);
486 						continue;
487 					}
488 					if(shp->subshell && !shp->subshare)
489 						sh_subfork();
490 					if(tp->aflag=='-')
491 						nv_onattr(np,flag|NV_FUNCTION);
492 					else if(tp->aflag=='+')
493 						nv_offattr(np,flag);
494 				}
495 				else
496 					r++;
497 				if(tp->help)
498 				{
499 					int offset = stktell(shp->stk);
500 					sfputr(shp->stk,shp->prefix,'.');
501 					sfputr(shp->stk,name,0);
502 					if((np=nv_search(stkptr(shp->stk,offset),troot,0)) && np->nvalue.cp)
503 						np->nvalue.rp->help = tp->help;
504 					stkseek(shp->stk,offset);
505 				}
506 				continue;
507 			}
508 			/* tracked alias */
509 			if(troot==shp->track_tree && tp->aflag=='-')
510 			{
511 				np = nv_search(name,troot,NV_ADD);
512 				path_alias(np,path_absolute(nv_name(np),NIL(Pathcomp_t*)));
513 				continue;
514 			}
515 			np = nv_open(name,troot,nvflags|NV_ARRAY);
516 			if(tp->pflag)
517 			{
518 				nv_attribute(np,sfstdout,tp->prefix,1);
519 				print_value(sfstdout,np,tp);
520 				continue;
521 			}
522 			if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'='))
523 			{
524 				if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp)))
525 				{
526 					sfprintf(sfstderr,sh_translate(e_noalias),name);
527 					r++;
528 				}
529 				if(!comvar && !iarray)
530 					continue;
531 			}
532 			if(troot==shp->var_tree && ((tp->tp && !nv_isarray(np)) || !shp->st.real_fun && (nvflags&NV_STATIC)) && !strchr(name,'=') && !(shp->envlist  && nv_onlist(shp->envlist,name)))
533 				_nv_unset(np,0);
534 			if(troot==shp->var_tree)
535 			{
536 				if(iarray)
537 				{
538 					if(tp->tname)
539 						nv_atypeindex(np,tp->tname+1);
540 					else if(nv_isnull(np))
541 						nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0));
542 					else
543 					{
544 						Namarr_t *ap=nv_arrayptr(np);
545 						if(ap && comvar)
546 							ap->nelem |= ARRAY_TREE;
547 						nv_putsub(np, (char*)0, 0);
548 					}
549 				}
550 				else if(nvflags&NV_ARRAY)
551 				{
552 					if(comvar)
553 					{
554 						Namarr_t *ap=nv_arrayptr(np);
555 						if(ap)
556 							ap->nelem |= ARRAY_TREE;
557 						else
558 						{
559 							_nv_unset(np,NV_RDONLY);
560 							nv_onattr(np,NV_NOFREE);
561 						}
562 					}
563 					nv_setarray(np,nv_associative);
564 				}
565 				else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR))
566 					nv_setvtree(np);
567 			}
568 			if(flag&NV_MOVE)
569 			{
570 				nv_rename(np, flag);
571 				nv_close(np);
572 				continue;
573 			}
574 			if(tp->tp && nv_type(np)!=tp->tp)
575 			{
576 				nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND);
577 				flag = (np->nvflag&NV_NOCHANGE);
578 			}
579 			curflag = np->nvflag;
580 			flag &= ~NV_ASSIGN;
581 			if(last=strchr(name,'='))
582 				*last = 0;
583 			if (shp->typeinit)
584 				continue;
585 			if (tp->aflag == '-')
586 			{
587 				if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np)))
588 					errormsg(SH_DICT,ERROR_exit(1),e_badexport,name);
589 #if SHOPT_BSH
590 				if(flag&NV_EXPORT)
591 					nv_offattr(np,NV_IMPORT);
592 #endif /* SHOPT_BSH */
593 				newflag = curflag;
594 				if(flag&~NV_NOCHANGE)
595 					newflag &= NV_NOCHANGE;
596 				newflag |= flag;
597 				if (flag & (NV_LJUST|NV_RJUST))
598 				{
599 					if(!(flag&NV_RJUST))
600 						newflag &= ~NV_RJUST;
601 
602 					else if(!(flag&NV_LJUST))
603 						newflag &= ~NV_LJUST;
604 				}
605 				if(!(flag&NV_INTEGER))
606 				{
607 					if (flag & NV_UTOL)
608 						newflag &= ~NV_LTOU;
609 					else if (flag & NV_LTOU)
610 						newflag &= ~NV_UTOL;
611 				}
612 			}
613 			else
614 			{
615 				if((flag&NV_RDONLY) && (curflag&NV_RDONLY))
616 					errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np));
617 				newflag = curflag & ~flag;
618 			}
619 			if (tp->aflag && (tp->argnum>0 || (curflag!=newflag)))
620 			{
621 				if(shp->subshell)
622 					sh_assignok(np,1);
623 				if(troot!=shp->var_tree)
624 					nv_setattr(np,newflag&~NV_ASSIGN);
625 				else
626 				{
627 					char *oldname=0;
628 					int len=strlen(name);
629 					if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER))
630 						tp->argnum = 10;
631 					/* use reference name for export */
632 					if((newflag^curflag)&NV_EXPORT)
633 					{
634 						oldname = np->nvname;
635 						np->nvname = name;
636 					}
637 					if(np->nvfun && !nv_isarray(np) && name[len-1]=='.')
638 						newflag |= NV_NODISC;
639 					nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum);
640 					if(oldname)
641 						np->nvname = oldname;
642 				}
643 			}
644 			if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT))
645 			{
646 				np->nvenv = tp->help;
647 				nv_onattr(np,NV_EXPORT);
648 			}
649 			if(last)
650 				*last = '=';
651 			/* set or unset references */
652 			if(ref)
653 			{
654 				if(tp->aflag=='-')
655 				{
656 					Dt_t *hp=0;
657 					if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
658 					{
659 						if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
660 							hp = dtvnext(shp->var_tree);
661 					}
662 					if(tp->sh->mktype)
663 						nv_onattr(np,NV_REF|NV_FUNCT);
664 					else
665 						nv_setref(np,hp,NV_VARNAME);
666 				}
667 				else
668 					nv_unref(np);
669 			}
670 			nv_close(np);
671 		}
672 	}
673 	else if(!tp->sh->envlist)
674 	{
675 		if(shp->prefix)
676 			errormsg(SH_DICT,2, "%s: compound assignment requires sub-variable name",shp->prefix);
677 		if(tp->aflag)
678 		{
679 			if(troot==shp->fun_tree)
680 			{
681 				flag |= NV_FUNCTION;
682 				tp->prefix = 0;
683 			}
684 			else if(troot==shp->var_tree)
685 			{
686 				flag |= (nvflags&NV_ARRAY);
687 				if(flag&NV_IARRAY)
688 					flag |= NV_ARRAY;
689 			}
690 			print_scan(sfstdout,flag,troot,tp->aflag=='+',tp);
691 		}
692 		else if(troot==shp->alias_tree)
693 			print_scan(sfstdout,0,troot,0,tp);
694 		else
695 			print_all(sfstdout,troot,tp);
696 		sfsync(sfstdout);
697 	}
698 	return(r);
699 }
700 
701 typedef void (*Iptr_t)(int,void*);
702 typedef int (*Fptr_t)(int, char*[], void*);
703 
704 #define GROWLIB	4
705 
706 static void		**liblist;
707 static unsigned short	*libattr;
708 static int		nlib;
709 static int		maxlib;
710 
711 /*
712  * This allows external routines to load from the same library */
sh_getliblist(void)713 void **sh_getliblist(void)
714 {
715 	return(liblist);
716 }
717 
718 /*
719  * add library to loaded list
720  * call (*lib_init)() on first load if defined
721  * always move to head of search list
722  * return: 0: already loaded 1: first load
723  */
724 #if SHOPT_DYNAMIC
sh_addlib(void * library)725 int sh_addlib(void* library)
726 {
727 	register int	n;
728 	register int	r;
729 	Iptr_t		initfn;
730 	Shbltin_t	*sp = &sh.bltindata;
731 
732 	sp->nosfio = 0;
733 	for (n = r = 0; n < nlib; n++)
734 	{
735 		if (r)
736 		{
737 			liblist[n-1] = liblist[n];
738 			libattr[n-1] = libattr[n];
739 		}
740 		else if (liblist[n] == library)
741 			r++;
742 	}
743 	if (r)
744 		nlib--;
745 	else if ((initfn = (Iptr_t)dlllook(library, "lib_init")))
746 		(*initfn)(0,sp);
747 	if (nlib >= maxlib)
748 	{
749 		maxlib += GROWLIB;
750 		if (liblist)
751 		{
752 			liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void**));
753 			libattr = (unsigned short*)realloc((void*)liblist, (maxlib+1)*sizeof(unsigned short*));
754 		}
755 		else
756 		{
757 			liblist = (void**)malloc((maxlib+1)*sizeof(void**));
758 			libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short*));
759 		}
760 	}
761 	libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0);
762 	liblist[nlib++] = library;
763 	liblist[nlib] = 0;
764 	return !r;
765 }
766 #else
sh_addlib(void * library)767 int sh_addlib(void* library)
768 {
769 	return 0;
770 }
771 #endif /* SHOPT_DYNAMIC */
772 
773 /*
774  * add change or list built-ins
775  * adding builtins requires dlopen() interface
776  */
b_builtin(int argc,char * argv[],void * extra)777 int	b_builtin(int argc,char *argv[],void *extra)
778 {
779 	register char *arg=0, *name;
780 	register int n, r=0, flag=0;
781 	register Namval_t *np;
782 	long dlete=0;
783 	struct tdata tdata;
784 	Fptr_t addr;
785 	Stk_t	*stkp;
786 	void *library=0;
787 	char *errmsg;
788 	NOT_USED(argc);
789 	memset(&tdata,0,sizeof(tdata));
790 	tdata.sh = ((Shbltin_t*)extra)->shp;
791 	stkp = tdata.sh->stk;
792 	if(!tdata.sh->pathlist)
793 		path_absolute(argv[0],NIL(Pathcomp_t*));
794 	while (n = optget(argv,sh_optbuiltin)) switch (n)
795 	{
796 	    case 's':
797 		flag = BLT_SPC;
798 		break;
799 	    case 'd':
800 		dlete=1;
801 		break;
802 	    case 'f':
803 #if SHOPT_DYNAMIC
804 		arg = opt_info.arg;
805 #else
806 		errormsg(SH_DICT,2, "adding built-ins not supported");
807 		error_info.errors++;
808 #endif /* SHOPT_DYNAMIC */
809 		break;
810 	    case ':':
811 		errormsg(SH_DICT,2, "%s", opt_info.arg);
812 		break;
813 	    case '?':
814 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
815 		break;
816 	}
817 	argv += opt_info.index;
818 	if(error_info.errors)
819 		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
820 	if(arg || *argv)
821 	{
822 		if(sh_isoption(SH_RESTRICTED))
823 			errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]);
824 		if(sh_isoption(SH_PFSH))
825 			errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]);
826 		if(tdata.sh->subshell && !tdata.sh->subshare)
827 			sh_subfork();
828 	}
829 #if SHOPT_DYNAMIC
830 	if(arg)
831 	{
832 #if (_AST_VERSION>=20040404)
833 		if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
834 #else
835 		if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
836 #endif
837 		{
838 			errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror());
839 			return(1);
840 		}
841 		sh_addlib(library);
842 	}
843 	else
844 #endif /* SHOPT_DYNAMIC */
845 	if(*argv==0 && !dlete)
846 	{
847 		print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata);
848 		return(0);
849 	}
850 	r = 0;
851 	flag = stktell(stkp);
852 	while(arg = *argv)
853 	{
854 		name = path_basename(arg);
855 		sfwrite(stkp,"b_",2);
856 		sfputr(stkp,name,0);
857 		errmsg = 0;
858 		addr = 0;
859 		for(n=(nlib?nlib:dlete); --n>=0;)
860 		{
861 			/* (char*) added for some sgi-mips compilers */
862 #if SHOPT_DYNAMIC
863 			if(dlete || (addr = (Fptr_t)dlllook(liblist[n],stkptr(stkp,flag))))
864 #else
865 			if(dlete)
866 #endif /* SHOPT_DYNAMIC */
867 			{
868 				if(np = sh_addbuiltin(arg, addr,pointerof(dlete)))
869 				{
870 					if(dlete || nv_isattr(np,BLT_SPC))
871 						errmsg = "restricted name";
872 					else
873 						nv_onattr(np,libattr[n]);
874 				}
875 				break;
876 			}
877 		}
878 		if(!dlete && !addr)
879 		{
880 			np = sh_addbuiltin(arg, 0 ,0);
881 			if(np && nv_isattr(np,BLT_SPC))
882 				errmsg = "restricted name";
883 			else if(!np)
884 				errmsg = "not found";
885 		}
886 		if(errmsg)
887 		{
888 			errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg);
889 			r = 1;
890 		}
891 		stkseek(stkp,flag);
892 		argv++;
893 	}
894 	return(r);
895 }
896 
b_set(int argc,register char * argv[],void * extra)897 int    b_set(int argc,register char *argv[],void *extra)
898 {
899 	struct tdata tdata;
900 	memset(&tdata,0,sizeof(tdata));
901 	tdata.sh = ((Shbltin_t*)extra)->shp;
902 	tdata.prefix=0;
903 	if(argv[1])
904 	{
905 		if(sh_argopts(argc,argv,tdata.sh) < 0)
906 			return(2);
907 		if(sh_isoption(SH_VERBOSE))
908 			sh_onstate(SH_VERBOSE);
909 		else
910 			sh_offstate(SH_VERBOSE);
911 		if(sh_isoption(SH_MONITOR))
912 			sh_onstate(SH_MONITOR);
913 		else
914 			sh_offstate(SH_MONITOR);
915 	}
916 	else
917 		/*scan name chain and print*/
918 		print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata);
919 	return(0);
920 }
921 
922 /*
923  * The removing of Shell variable names, aliases, and functions
924  * is performed here.
925  * Unset functions with unset -f
926  * Non-existent items being deleted give non-zero exit status
927  */
928 
b_unalias(int argc,register char * argv[],void * extra)929 int    b_unalias(int argc,register char *argv[],void *extra)
930 {
931 	Shell_t *shp = ((Shbltin_t*)extra)->shp;
932 	return(b_unall(argc,argv,shp->alias_tree,shp));
933 }
934 
b_unset(int argc,register char * argv[],void * extra)935 int    b_unset(int argc,register char *argv[],void *extra)
936 {
937 	Shell_t *shp = ((Shbltin_t*)extra)->shp;
938 	return(b_unall(argc,argv,shp->var_tree,shp));
939 }
940 
b_unall(int argc,char ** argv,register Dt_t * troot,Shell_t * shp)941 static int b_unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp)
942 {
943 	register Namval_t *np;
944 	register const char *name;
945 	register int r;
946 	Dt_t	*dp;
947 	int nflag=0,all=0,isfun,jmpval;
948 	struct checkpt buff;
949 	NOT_USED(argc);
950 	if(troot==shp->alias_tree)
951 	{
952 		name = sh_optunalias;
953 		if(shp->subshell)
954 			troot = sh_subaliastree(0);
955 	}
956 	else
957 		name = sh_optunset;
958 	while(r = optget(argv,name)) switch(r)
959 	{
960 		case 'f':
961 			troot = sh_subfuntree(1);
962 			break;
963 		case 'a':
964 			all=1;
965 			break;
966 		case 'n':
967 			nflag = NV_NOREF;
968 		case 'v':
969 			troot = shp->var_tree;
970 			break;
971 		case ':':
972 			errormsg(SH_DICT,2, "%s", opt_info.arg);
973 			break;
974 		case '?':
975 			errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
976 			return(2);
977 	}
978 	argv += opt_info.index;
979 	if(error_info.errors || (*argv==0 &&!all))
980 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
981 	if(!troot)
982 		return(1);
983 	r = 0;
984 	if(troot==shp->var_tree)
985 		nflag |= NV_VARNAME;
986 	else
987 		nflag = NV_NOSCOPE;
988 	if(all)
989 	{
990 		dtclear(troot);
991 		return(r);
992 	}
993 	sh_pushcontext(&buff,1);
994 	while(name = *argv++)
995 	{
996 		jmpval = sigsetjmp(buff.buff,0);
997 		np = 0;
998 		if(jmpval==0)
999 			np=nv_open(name,troot,NV_NOADD|nflag);
1000 		else
1001 		{
1002 			r = 1;
1003 			continue;
1004 		}
1005 		if(np)
1006 		{
1007 			if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY))
1008 			{
1009 				if(nv_isattr(np,NV_RDONLY))
1010 					errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
1011 				r = 1;
1012 				continue;
1013 			}
1014 			isfun = is_afunction(np);
1015 			if(troot==shp->var_tree)
1016 			{
1017 				if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np))
1018 				{
1019 					r=1;
1020 					continue;
1021 				}
1022 
1023 				if(shp->subshell)
1024 					np=sh_assignok(np,0);
1025 			}
1026 			if(!nv_isnull(np))
1027 				nv_unset(np);
1028 			nv_close(np);
1029 			if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict)
1030 				nv_delete(np,dp,NV_NOFREE);
1031 			else if(isfun)
1032 				nv_delete(np,troot,NV_NOFREE);
1033 		}
1034 	}
1035 	sh_popcontext(&buff);
1036 	return(r);
1037 }
1038 
1039 /*
1040  * print out the name and value of a name-value pair <np>
1041  */
1042 
print_namval(Sfio_t * file,register Namval_t * np,register int flag,struct tdata * tp)1043 static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp)
1044 {
1045 	register char *cp;
1046 	sh_sigcheck();
1047 	if(flag)
1048 		flag = '\n';
1049 	if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
1050 	{
1051 		if(is_abuiltin(np))
1052 			sfputr(file,nv_name(np),'\n');
1053 		return(0);
1054 	}
1055 	if(tp->prefix)
1056 	{
1057 		if(*tp->prefix=='t')
1058 			nv_attribute(np,tp->outfile,tp->prefix,tp->aflag);
1059 		else
1060 			sfputr(file,tp->prefix,' ');
1061 	}
1062 	if(is_afunction(np))
1063 	{
1064 		Sfio_t *iop=0;
1065 		char *fname=0;
1066 		if(!flag && !np->nvalue.ip)
1067 			sfputr(file,"typeset -fu",' ');
1068 		else if(!flag && !nv_isattr(np,NV_FPOSIX))
1069 			sfputr(file,"function",' ');
1070 		sfputr(file,nv_name(np),-1);
1071 		if(nv_isattr(np,NV_FPOSIX))
1072 			sfwrite(file,"()",2);
1073 		if(np->nvalue.ip && np->nvalue.rp->hoffset>=0)
1074 			fname = np->nvalue.rp->fname;
1075 		else
1076 			flag = '\n';
1077 		if(flag)
1078 		{
1079 			if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0)
1080 				sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):"");
1081 			else
1082 				sfputc(file, '\n');
1083 		}
1084 		else
1085 		{
1086 			if(nv_isattr(np,NV_FTMP))
1087 			{
1088 				fname = 0;
1089 				iop = tp->sh->heredocs;
1090 			}
1091 			else if(fname)
1092 				iop = sfopen(iop,fname,"r");
1093 			else if(tp->sh->hist_ptr)
1094 				iop = (tp->sh->hist_ptr)->histfp;
1095 			if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0)
1096 				sfmove(iop,file, nv_size(np), -1);
1097 			else
1098 				flag = '\n';
1099 			if(fname)
1100 				sfclose(iop);
1101 		}
1102 		return(nv_size(np)+1);
1103 	}
1104 	if(nv_arrayptr(np))
1105 	{
1106 		print_value(file,np,tp);
1107 		return(0);
1108 	}
1109 	if(nv_isvtree(np))
1110 		nv_onattr(np,NV_EXPORT);
1111 	if(cp=nv_getval(np))
1112 	{
1113 		sfputr(file,nv_name(np),-1);
1114 		if(!flag)
1115 			flag = '=';
1116 		sfputc(file,flag);
1117 		if(flag != '\n')
1118 		{
1119 			if(nv_isref(np) && nv_refsub(np))
1120 			{
1121 				sfputr(file,sh_fmtq(cp),-1);
1122 				sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np)));
1123 			}
1124 			else
1125 #if SHOPT_TYPEDEF
1126 				sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n');
1127 #else
1128 				sfputr(file,sh_fmtq(cp),'\n');
1129 #endif /* SHOPT_TYPEDEF */
1130 		}
1131 		return(1);
1132 	}
1133 	else if(tp->scanmask && tp->scanroot==tp->sh->var_tree)
1134 		sfputr(file,nv_name(np),'\n');
1135 	return(0);
1136 }
1137 
1138 /*
1139  * print attributes at all nodes
1140  */
print_all(Sfio_t * file,Dt_t * root,struct tdata * tp)1141 static void	print_all(Sfio_t *file,Dt_t *root, struct tdata *tp)
1142 {
1143 	tp->outfile = file;
1144 	nv_scan(root, print_attribute, (void*)tp, 0, 0);
1145 }
1146 
1147 /*
1148  * print the attributes of name value pair give by <np>
1149  */
print_attribute(register Namval_t * np,void * data)1150 static void	print_attribute(register Namval_t *np,void *data)
1151 {
1152 	register struct tdata *dp = (struct tdata*)data;
1153 	nv_attribute(np,dp->outfile,dp->prefix,dp->aflag);
1154 }
1155 
1156 /*
1157  * print the nodes in tree <root> which have attributes <flag> set
1158  * of <option> is non-zero, no subscript or value is printed.
1159  */
1160 
print_scan(Sfio_t * file,int flag,Dt_t * root,int option,struct tdata * tp)1161 static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp)
1162 {
1163 	register char **argv;
1164 	register Namval_t *np;
1165 	register int namec;
1166 	Namval_t *onp = 0;
1167 	tp->sh->last_table=0;
1168 	flag &= ~NV_ASSIGN;
1169 	tp->scanmask = flag&~NV_NOSCOPE;
1170 	tp->scanroot = root;
1171 	tp->outfile = file;
1172 #if SHOPT_TYPEDEF
1173 	if(!tp->prefix && tp->tp)
1174 		tp->prefix = nv_name(tp->tp);
1175 #endif /* SHOPT_TYPEDEF */
1176 	if(flag&NV_INTEGER)
1177 		tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE);
1178 	namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag);
1179 	argv = tp->argnam  = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*));
1180 	namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY);
1181 	if(mbcoll())
1182 		strsort(argv,namec,strcoll);
1183 	while(namec--)
1184 	{
1185 		if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)))
1186 		{
1187 			onp = np;
1188 			if(flag&NV_ARRAY)
1189 			{
1190 				if(nv_aindex(np)>=0)
1191 				{
1192 					if(!(flag&NV_IARRAY))
1193 						continue;
1194 				}
1195 				else if((flag&NV_IARRAY))
1196 					continue;
1197 
1198 			}
1199 			print_namval(file,np,option,tp);
1200 		}
1201 	}
1202 }
1203 
1204 /*
1205  * add the name of the node to the argument list argnam
1206  */
1207 
pushname(Namval_t * np,void * data)1208 static void pushname(Namval_t *np,void *data)
1209 {
1210 	struct tdata *tp = (struct tdata*)data;
1211 	*tp->argnam++ = nv_name(np);
1212 }
1213 
1214