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