1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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 const char *wctname;
50 Sfio_t *outfile;
51 char *prefix;
52 char *tname;
53 char *help;
54 short aflag;
55 short pflag;
56 int argnum;
57 int scanmask;
58 Dt_t *scanroot;
59 char **argnam;
60 int indent;
61 int noref;
62 };
63
64
65 static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*);
66 static void print_attribute(Namval_t*,void*);
67 static void print_all(Sfio_t*, Dt_t*, struct tdata*);
68 static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*);
69 static int unall(int, char**, Dt_t*, Shell_t*);
70 static int setall(char**, int, Dt_t*, struct tdata*);
71 static void pushname(Namval_t*,void*);
72 static void(*nullscan)(Namval_t*,void*);
73
load_class(const char * name)74 static Namval_t *load_class(const char *name)
75 {
76 errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name);
77 return(0);
78 }
79
80 /*
81 * Note export and readonly are the same
82 */
83 #if 0
84 /* for the dictionary generator */
85 int b_export(int argc,char *argv[],Shbltin_t *context){}
86 #endif
b_readonly(int argc,char * argv[],Shbltin_t * context)87 int b_readonly(int argc,char *argv[],Shbltin_t *context)
88 {
89 register int flag;
90 char *command = argv[0];
91 struct tdata tdata;
92 NOT_USED(argc);
93 memset((void*)&tdata,0,sizeof(tdata));
94 tdata.sh = context->shp;
95 tdata.aflag = '-';
96 while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag)
97 {
98 case 'p':
99 tdata.prefix = command;
100 break;
101 case ':':
102 errormsg(SH_DICT,2, "%s", opt_info.arg);
103 break;
104 case '?':
105 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
106 return(2);
107 }
108 if(error_info.errors)
109 errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
110 argv += (opt_info.index-1);
111 if(*command=='r')
112 flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME);
113 #ifdef _ENV_H
114 else if(!argv[1])
115 {
116 char *cp,**env=env_get(tdata.sh->env);
117 while(cp = *env++)
118 {
119 if(tdata.prefix)
120 sfputr(sfstdout,tdata.prefix,' ');
121 sfprintf(sfstdout,"%s\n",sh_fmtq(cp));
122 }
123 return(0);
124 }
125 #endif
126 else
127 {
128 flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT);
129 if(!tdata.sh->prefix)
130 tdata.sh->prefix = "";
131 }
132 return(setall(argv,flag,tdata.sh->var_tree, &tdata));
133 }
134
135
b_alias(int argc,register char * argv[],Shbltin_t * context)136 int b_alias(int argc,register char *argv[],Shbltin_t *context)
137 {
138 register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN;
139 register Dt_t *troot;
140 register int n;
141 struct tdata tdata;
142 NOT_USED(argc);
143 memset((void*)&tdata,0,sizeof(tdata));
144 tdata.sh = context->shp;
145 troot = tdata.sh->alias_tree;
146 if(*argv[0]=='h')
147 flag = NV_TAGGED;
148 if(argv[1])
149 {
150 opt_info.offset = 0;
151 opt_info.index = 1;
152 *opt_info.option = 0;
153 tdata.argnum = 0;
154 tdata.aflag = *argv[1];
155 while((n = optget(argv,sh_optalias))) switch(n)
156 {
157 case 'p':
158 tdata.prefix = argv[0];
159 break;
160 case 't':
161 flag |= NV_TAGGED;
162 break;
163 case 'x':
164 flag |= NV_EXPORT;
165 break;
166 case ':':
167 errormsg(SH_DICT,2, "%s", opt_info.arg);
168 break;
169 case '?':
170 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
171 return(2);
172 }
173 if(error_info.errors)
174 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
175 argv += (opt_info.index-1);
176 if(flag&NV_TAGGED)
177 {
178 /* hacks to handle hash -r | -- */
179 if(argv[1] && argv[1][0]=='-')
180 {
181 if(argv[1][1]=='r' && argv[1][2]==0)
182 {
183 Namval_t *np = nv_search((char*)PATHNOD,tdata.sh->var_tree,HASH_BUCKET);
184 nv_putval(np,nv_getval(np),NV_RDONLY);
185 argv++;
186 if(!argv[1])
187 return(0);
188 }
189 if(argv[1][0]=='-')
190 {
191 if(argv[1][1]=='-' && argv[1][2]==0)
192 argv++;
193 else
194 errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]);
195 }
196 }
197 troot = tdata.sh->track_tree;
198 }
199 }
200 return(setall(argv,flag,troot,&tdata));
201 }
202
203
204 #if 0
205 /* for the dictionary generator */
206 int b_local(int argc,char *argv[],Shbltin_t *context){}
207 #endif
b_typeset(int argc,register char * argv[],Shbltin_t * context)208 int b_typeset(int argc,register char *argv[],Shbltin_t *context)
209 {
210 register int n, flag = NV_VARNAME|NV_ASSIGN;
211 struct tdata tdata;
212 const char *optstring = sh_opttypeset;
213 Namdecl_t *ntp = (Namdecl_t*)context->ptr;
214 Dt_t *troot;
215 int isfloat=0, shortint=0, sflag=0;
216 NOT_USED(argc);
217 memset((void*)&tdata,0,sizeof(tdata));
218 tdata.sh = context->shp;
219 if(ntp)
220 {
221 tdata.tp = ntp->tp;
222 opt_info.disc = (Optdisc_t*)ntp->optinfof;
223 optstring = ntp->optstring;
224 }
225 troot = tdata.sh->var_tree;
226 while((n = optget(argv,optstring)))
227 {
228 if(tdata.aflag==0)
229 tdata.aflag = *opt_info.option;
230 switch(n)
231 {
232 case 'a':
233 flag |= NV_IARRAY;
234 if(opt_info.arg && *opt_info.arg!='[')
235 {
236 opt_info.index--;
237 goto endargs;
238 }
239 tdata.tname = opt_info.arg;
240 break;
241 case 'A':
242 flag |= NV_ARRAY;
243 break;
244 case 'C':
245 flag |= NV_COMVAR;
246 break;
247 case 'E':
248 /* The following is for ksh88 compatibility */
249 if(opt_info.offset && !strchr(argv[opt_info.index],'E'))
250 {
251 tdata.argnum = (int)opt_info.num;
252 break;
253 }
254 /* FALLTHROUGH */
255 case 'F':
256 case 'X':
257 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
258 tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10);
259 isfloat = 1;
260 if(n=='E')
261 {
262 flag &= ~NV_HEXFLOAT;
263 flag |= NV_EXPNOTE;
264 }
265 else if(n=='X')
266 {
267 flag &= ~NV_EXPNOTE;
268 flag |= NV_HEXFLOAT;
269 }
270 break;
271 case 'b':
272 flag |= NV_BINARY;
273 break;
274 case 'm':
275 flag |= NV_MOVE;
276 break;
277 case 'n':
278 flag &= ~NV_VARNAME;
279 flag |= (NV_REF|NV_IDENT);
280 break;
281 case 'H':
282 flag |= NV_HOST;
283 break;
284 case 'T':
285 flag |= NV_TYPE;
286 tdata.prefix = opt_info.arg;
287 break;
288 case 'L': case 'Z': case 'R':
289 if(tdata.argnum==0)
290 tdata.argnum = (int)opt_info.num;
291 if(tdata.argnum < 0)
292 errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum);
293 if(n=='Z')
294 flag |= NV_ZFILL;
295 else
296 {
297 flag &= ~(NV_LJUST|NV_RJUST);
298 flag |= (n=='L'?NV_LJUST:NV_RJUST);
299 }
300 break;
301 case 'M':
302 if((tdata.wctname = opt_info.arg) && !nv_mapchar((Namval_t*)0,tdata.wctname))
303 errormsg(SH_DICT, ERROR_exit(1),e_unknownmap, tdata.wctname);
304 if(tdata.wctname && strcmp(tdata.wctname,e_tolower)==0)
305 flag |= NV_UTOL;
306 else
307 flag |= NV_LTOU;
308 if(!tdata.wctname)
309 flag |= NV_UTOL;
310 break;
311 case 'f':
312 flag &= ~(NV_VARNAME|NV_ASSIGN);
313 troot = tdata.sh->fun_tree;
314 break;
315 case 'i':
316 if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
317 tdata.argnum = 10;
318 flag |= NV_INTEGER;
319 break;
320 case 'l':
321 tdata.wctname = e_tolower;
322 flag |= NV_UTOL;
323 break;
324 case 'p':
325 tdata.prefix = argv[0];
326 tdata.pflag = 1;
327 flag &= ~NV_ASSIGN;
328 break;
329 case 'r':
330 flag |= NV_RDONLY;
331 break;
332 #ifdef SHOPT_TYPEDEF
333 case 'S':
334 sflag=1;
335 break;
336 case 'h':
337 tdata.help = opt_info.arg;
338 break;
339 #endif /*SHOPT_TYPEDEF*/
340 case 's':
341 shortint=1;
342 break;
343 case 't':
344 flag |= NV_TAGGED;
345 break;
346 case 'u':
347 tdata.wctname = e_toupper;
348 flag |= NV_LTOU;
349 break;
350 case 'x':
351 flag &= ~NV_VARNAME;
352 flag |= (NV_EXPORT|NV_IDENT);
353 break;
354 case ':':
355 errormsg(SH_DICT,2, "%s", opt_info.arg);
356 break;
357 case '?':
358 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
359 opt_info.disc = 0;
360 return(2);
361 }
362 }
363 endargs:
364 argv += opt_info.index;
365 opt_info.disc = 0;
366 /* handle argument of + and - specially */
367 if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-'))
368 tdata.aflag = *argv[0];
369 else
370 argv--;
371 if((flag&NV_ZFILL) && !(flag&NV_LJUST))
372 flag |= NV_RJUST;
373 if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL)))
374 error_info.errors++;
375 if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU)))
376 error_info.errors++;
377 if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN)))
378 error_info.errors++;
379 if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN)))
380 error_info.errors++;
381 if((flag&NV_TYPE) && (flag&~(NV_TYPE|NV_VARNAME|NV_ASSIGN)))
382 error_info.errors++;
383 if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU))))
384 error_info.errors++;
385 if(sflag && troot==tdata.sh->fun_tree)
386 {
387 /* static function */
388 sflag = 0;
389 flag |= NV_STATICF;
390 }
391 if(error_info.errors)
392 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
393 if(sizeof(char*)<8 && tdata.argnum > SHRT_MAX)
394 errormsg(SH_DICT,ERROR_exit(2),"option argument cannot be greater than %d",SHRT_MAX);
395 if(isfloat)
396 flag |= NV_DOUBLE;
397 if(shortint)
398 {
399 flag &= ~NV_LONG;
400 flag |= NV_SHORT|NV_INTEGER;
401 }
402 if(sflag)
403 {
404 if(tdata.sh->mktype)
405 flag |= NV_REF|NV_TAGGED;
406 else if(!tdata.sh->typeinit)
407 flag |= NV_STATIC|NV_IDENT;
408 }
409 if(tdata.sh->fn_depth && !tdata.pflag)
410 flag |= NV_NOSCOPE;
411 if(tdata.help)
412 tdata.help = strdup(tdata.help);
413 if(flag&NV_TYPE)
414 {
415 Stk_t *stkp = tdata.sh->stk;
416 int off=0,offset = stktell(stkp);
417 if(!tdata.prefix)
418 return(sh_outtype(tdata.sh,sfstdout));
419 sfputr(stkp,NV_CLASS,-1);
420 #if SHOPT_NAMESPACE
421 if(tdata.sh->namespace)
422 {
423 off = stktell(stkp)+1;
424 sfputr(stkp,nv_name(tdata.sh->namespace),'.');
425 }
426 else
427 #endif /* SHOPT_NAMESPACE */
428 if(NV_CLASS[sizeof(NV_CLASS)-2]!='.')
429 sfputc(stkp,'.');
430 sfputr(stkp,tdata.prefix,0);
431 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN);
432 #if SHOPT_NAMESPACE
433 if(!tdata.tp && off)
434 {
435 *stkptr(stkp,off)=0;
436 tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN);
437 }
438 #endif /* SHOPT_NAMESPACE */
439 stkseek(stkp,offset);
440 if(!tdata.tp)
441 errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix);
442 else if(nv_isnull(tdata.tp))
443 nv_newtype(tdata.tp);
444 tdata.tp->nvenv = tdata.help;
445 flag &= ~NV_TYPE;
446 if(nv_isattr(tdata.tp,NV_TAGGED))
447 {
448 nv_offattr(tdata.tp,NV_TAGGED);
449 return(0);
450 }
451 }
452 else if(tdata.aflag==0 && ntp && ntp->tp)
453 tdata.aflag = '-';
454 if(!tdata.sh->mktype)
455 tdata.help = 0;
456 if(tdata.aflag=='+' && (flag&(NV_ARRAY|NV_IARRAY|NV_COMVAR)) && argv[1])
457 errormsg(SH_DICT,ERROR_exit(1),e_nounattr);
458 return(setall(argv,flag,troot,&tdata));
459 }
460
print_value(Sfio_t * iop,Namval_t * np,struct tdata * tp)461 static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp)
462 {
463 char *name;
464 int aflag=tp->aflag;
465 if(nv_isnull(np))
466 {
467 if(!np->nvflag)
468 return;
469 aflag = '+';
470 }
471 else if(nv_istable(np))
472 {
473 Dt_t *root = tp->sh->last_root;
474 Namval_t *nsp = tp->sh->namespace;
475 char *cp;
476 if(!tp->pflag)
477 return;
478 cp = name = nv_name(np);
479 if(*name=='.')
480 name++;
481 if(tp->indent)
482 sfnputc(iop,'\t',tp->indent);
483 sfprintf(iop,"namespace %s\n", name);
484 if(tp->indent)
485 sfnputc(iop,'\t',tp->indent);
486 sfprintf(iop,"{\n", name);
487 tp->indent++;
488 /* output types from namespace */
489 tp->sh->namespace = 0;
490 tp->sh->prefix = nv_name(np)+1;
491 sh_outtype(tp->sh,iop);
492 tp->sh->prefix = 0;
493 tp->sh->namespace = np;
494 tp->sh->last_root = root;
495 /* output variables from namespace */
496 print_scan(iop,NV_NOSCOPE,nv_dict(np),aflag=='+',tp);
497 tp->wctname = cp;
498 tp->sh->namespace = 0;
499 /* output functions from namespace */
500 print_scan(iop,NV_FUNCTION|NV_NOSCOPE,tp->sh->fun_tree,aflag=='+',tp);
501 tp->wctname = 0;
502 tp->sh->namespace = nsp;
503 if(--tp->indent)
504 sfnputc(iop,'\t',tp->indent);
505 sfwrite(iop,"}\n",2);
506 return;
507 }
508 sfputr(iop,nv_name(np),aflag=='+'?'\n':'=');
509 if(aflag=='+')
510 return;
511 if(nv_isarray(np) && nv_arrayptr(np))
512 {
513 nv_outnode(np,iop,-1,0);
514 sfwrite(iop,")\n",2);
515 }
516 else
517 {
518 if(nv_isvtree(np))
519 nv_onattr(np,NV_EXPORT);
520 if(!(name = nv_getval(np)))
521 name = Empty;
522 if(!nv_isvtree(np))
523 name = sh_fmtq(name);
524 sfputr(iop,name,'\n');
525 }
526 }
527
setall(char ** argv,register int flag,Dt_t * troot,struct tdata * tp)528 static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp)
529 {
530 register char *name;
531 char *last = 0;
532 int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE));
533 int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY);
534 Shell_t *shp =tp->sh;
535 if(!shp->prefix)
536 {
537 if(!tp->pflag)
538 nvflags |= NV_NOSCOPE;
539 }
540 else if(*shp->prefix==0)
541 shp->prefix = 0;
542 if(*argv[0]=='+')
543 nvflags |= NV_NOADD;
544 flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY);
545 if(argv[1])
546 {
547 if(flag&NV_REF)
548 {
549 flag &= ~NV_REF;
550 ref=1;
551 if(tp->aflag!='-')
552 nvflags |= NV_NOREF;
553 }
554 if(tp->pflag)
555 nvflags |= (NV_NOREF|NV_NOADD|NV_NOFAIL);
556 while(name = *++argv)
557 {
558 register unsigned newflag;
559 register Namval_t *np;
560 Namarr_t *ap;
561 Namval_t *mp;
562 unsigned curflag;
563 if(troot == shp->fun_tree)
564 {
565 /*
566 *functions can be exported or
567 * traced but not set
568 */
569 flag &= ~NV_ASSIGN;
570 if(flag&NV_LTOU)
571 {
572 /* Function names cannot be special builtin */
573 if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
574 errormsg(SH_DICT,ERROR_exit(1),e_badfun,name);
575 #if SHOPT_NAMESPACE
576 if(shp->namespace)
577 np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE);
578 else
579 #endif /* SHOPT_NAMESPACE */
580 np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE);
581 }
582 else
583 {
584 if(shp->prefix)
585 {
586 sfprintf(shp->strbuf,"%s.%s%c",shp->prefix,name,0);
587 name = sfstruse(shp->strbuf);
588 }
589 #if SHOPT_NAMESPACE
590 np = 0;
591 if(shp->namespace)
592 np = sh_fsearch(shp,name,HASH_NOSCOPE);
593 if(!np)
594 #endif /* SHOPT_NAMESPACE */
595 if(np=nv_search(name,troot,0))
596 {
597 if(!is_afunction(np))
598 np = 0;
599 }
600 else if(memcmp(name,".sh.math.",9)==0 && sh_mathstd(name+9))
601 continue;
602 }
603 if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU)))
604 {
605 if(flag==0 && !tp->help)
606 {
607 print_namval(sfstdout,np,tp->aflag=='+',tp);
608 continue;
609 }
610 if(shp->subshell && !shp->subshare)
611 sh_subfork();
612 if(tp->aflag=='-')
613 nv_onattr(np,flag|NV_FUNCTION);
614 else if(tp->aflag=='+')
615 nv_offattr(np,flag);
616 }
617 else
618 r++;
619 if(tp->help)
620 {
621 int offset = stktell(shp->stk);
622 if(!np)
623 {
624 sfputr(shp->stk,shp->prefix,'.');
625 sfputr(shp->stk,name,0);
626 np = nv_search(stkptr(shp->stk,offset),troot,0);
627 stkseek(shp->stk,offset);
628 }
629 if(np && np->nvalue.cp)
630 np->nvalue.rp->help = tp->help;
631 }
632 continue;
633 }
634 /* tracked alias */
635 if(troot==shp->track_tree && tp->aflag=='-')
636 {
637 np = nv_search(name,troot,NV_ADD);
638 path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*)));
639 continue;
640 }
641 np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0));
642 if(!np)
643 continue;
644 if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE))
645 nv_offattr(np,NV_NOFREE);
646 else if(tp->tp && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp)) && (ap->nelem&ARRAY_TREE))
647 errormsg(SH_DICT,ERROR_exit(1),e_typecompat,nv_name(np));
648 else if((ap=nv_arrayptr(np)) && nv_aindex(np)>0 && ap->nelem==1 && nv_getval(np)==Empty)
649 {
650 ap->nelem++;
651 _nv_unset(np,0);
652 ap->nelem--;
653 }
654 else if(iarray && ap && ap->fun)
655 errormsg(SH_DICT,ERROR_exit(1),"cannot change associative array %s to index array",nv_name(np));
656 else if( (iarray||(flag&NV_ARRAY)) && nv_isvtree(np) && !nv_type(np))
657 _nv_unset(np,NV_EXPORT);
658 if(tp->pflag)
659 {
660 if(!nv_istable(np))
661 nv_attribute(np,sfstdout,tp->prefix,1);
662 print_value(sfstdout,np,tp);
663 continue;
664 }
665 if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'='))
666 {
667 if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp)))
668 {
669 sfprintf(sfstderr,sh_translate(e_noalias),name);
670 r++;
671 }
672 if(!comvar && !iarray)
673 continue;
674 }
675 if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name)))
676 {
677 if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT)))))
678 {
679 _nv_unset(np,0);
680 }
681 }
682 if(troot==shp->var_tree)
683 {
684 if(iarray)
685 {
686 if(tp->tname)
687 nv_atypeindex(np,tp->tname+1);
688 else if(nv_isnull(np))
689 nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0));
690 else
691 {
692 if(ap && comvar)
693 ap->nelem |= ARRAY_TREE;
694 nv_putsub(np, (char*)0, 0);
695 }
696 }
697 else if(nvflags&NV_ARRAY)
698 {
699 if(comvar)
700 {
701 Namarr_t *ap=nv_arrayptr(np);
702 if(ap)
703 ap->nelem |= ARRAY_TREE;
704 else
705 {
706 _nv_unset(np,NV_RDONLY);
707 nv_onattr(np,NV_NOFREE);
708 }
709 }
710 nv_setarray(np,nv_associative);
711 }
712 else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR))
713 nv_setvtree(np);
714 }
715 if(flag&NV_MOVE)
716 {
717 nv_rename(np, flag);
718 nv_close(np);
719 continue;
720 }
721 if(tp->tp && nv_type(np)!=tp->tp)
722 {
723 nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND);
724 flag = (np->nvflag&NV_NOCHANGE);
725 }
726 flag &= ~NV_ASSIGN;
727 if(last=strchr(name,'='))
728 *last = 0;
729 if (shp->typeinit)
730 continue;
731 curflag = np->nvflag;
732 if(!(flag&NV_INTEGER) && (flag&(NV_LTOU|NV_UTOL)))
733 {
734 Namfun_t *fp;
735 char *cp;
736 if(!tp->wctname)
737 errormsg(SH_DICT,ERROR_exit(1),e_mapchararg,nv_name(np));
738 cp = (char*)nv_mapchar(np,0);
739 if(fp=nv_mapchar(np,tp->wctname))
740 {
741 if(tp->aflag=='+')
742 {
743 if(cp && strcmp(cp,tp->wctname)==0)
744 {
745 nv_disc(np,fp,NV_POP);
746 if(!(fp->nofree&1))
747 free((void*)fp);
748 nv_offattr(np,flag&(NV_LTOU|NV_UTOL));
749 }
750 }
751 else if(!cp || strcmp(cp,tp->wctname))
752 {
753 nv_disc(np,fp,NV_LAST);
754 nv_onattr(np,flag&(NV_LTOU|NV_UTOL));
755 }
756 }
757 }
758 if (tp->aflag == '-')
759 {
760 if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np)))
761 errormsg(SH_DICT,ERROR_exit(1),e_badexport,name);
762 #if SHOPT_BSH
763 if(flag&NV_EXPORT)
764 nv_offattr(np,NV_IMPORT);
765 #endif /* SHOPT_BSH */
766 newflag = curflag;
767 if(flag&~NV_NOCHANGE)
768 newflag &= NV_NOCHANGE;
769 newflag |= flag;
770 if (flag & (NV_LJUST|NV_RJUST))
771 {
772 if(!(flag&NV_RJUST))
773 newflag &= ~NV_RJUST;
774
775 else if(!(flag&NV_LJUST))
776 newflag &= ~NV_LJUST;
777 }
778 }
779 else
780 {
781 if((flag&NV_RDONLY) && (curflag&NV_RDONLY))
782 errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np));
783 newflag = curflag & ~flag;
784 }
785 if (tp->aflag && (tp->argnum>0 || (curflag!=newflag)))
786 {
787 if(shp->subshell)
788 sh_assignok(np,1);
789 if(troot!=shp->var_tree)
790 nv_setattr(np,newflag&~NV_ASSIGN);
791 else
792 {
793 char *oldname=0;
794 int len=strlen(name);
795 if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER))
796 tp->argnum = 10;
797 if(np->nvfun && !nv_isarray(np) && name[len-1]=='.')
798 newflag |= NV_NODISC;
799 nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum);
800 if(oldname)
801 np->nvname = oldname;
802 }
803 }
804 if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT))
805 {
806 np->nvenv = tp->help;
807 nv_onattr(np,NV_EXPORT);
808 }
809 if(last)
810 *last = '=';
811 /* set or unset references */
812 if(ref)
813 {
814 if(tp->aflag=='-')
815 {
816 Dt_t *hp=0;
817 if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
818 {
819 if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
820 hp = dtvnext(shp->var_tree);
821 }
822 if(tp->sh->mktype)
823 nv_onattr(np,NV_REF|NV_FUNCT);
824 else
825 nv_setref(np,hp,NV_VARNAME);
826 }
827 else
828 nv_unref(np);
829 }
830 nv_close(np);
831 }
832 }
833 else
834 {
835 if(shp->prefix)
836 errormsg(SH_DICT,2, e_subcomvar,shp->prefix);
837 if(tp->aflag)
838 {
839 if(troot==shp->fun_tree)
840 {
841 flag |= NV_FUNCTION;
842 tp->prefix = 0;
843 }
844 else if(troot==shp->var_tree)
845 {
846 flag |= (nvflags&NV_ARRAY);
847 if(iarray)
848 flag |= NV_ARRAY|NV_IARRAY;
849 if(comvar)
850 flag |= NV_TABLE;
851 if(!(flag&~NV_ASSIGN))
852 tp->noref = 1;
853 }
854 if((flag&(NV_UTOL|NV_LTOU)) ==(NV_UTOL|NV_LTOU))
855 {
856 print_scan(sfstdout,flag&~NV_UTOL,troot,tp->aflag=='+',tp);
857 flag &= ~NV_LTOU;
858 }
859 print_scan(sfstdout,flag,troot,tp->aflag=='+',tp);
860 if(tp->noref)
861 {
862 tp->noref = 0;
863 print_scan(sfstdout,flag|NV_REF,troot,tp->aflag=='+',tp);
864 }
865 }
866 else if(troot==shp->alias_tree)
867 print_scan(sfstdout,0,troot,0,tp);
868 else
869 print_all(sfstdout,troot,tp);
870 sfsync(sfstdout);
871 }
872 return(r);
873 }
874
875 #if SHOPT_DYNAMIC
876
877 typedef void (*Libinit_f)(int,void*);
878
879 typedef struct Libcomp_s
880 {
881 void* dll;
882 char* lib;
883 dev_t dev;
884 ino_t ino;
885 unsigned int attr;
886 } Libcomp_t;
887
888 #define GROWLIB 4
889
890 static Libcomp_t *liblist;
891 static int nlib;
892 static int maxlib;
893
894 /*
895 * add library to loaded list
896 * call (*lib_init)() on first load if defined
897 * always move to head of search list
898 * return: 0: already loaded 1: first load
899 */
900
sh_addlib(Shell_t * shp,void * dll,char * name,Pathcomp_t * pp)901 int sh_addlib(Shell_t* shp, void* dll, char* name, Pathcomp_t* pp)
902 {
903 register int n;
904 register int r;
905 Libinit_f initfn;
906 Shbltin_t *sp = &shp->bltindata;
907
908 sp->nosfio = 0;
909 for (n = r = 0; n < nlib; n++)
910 {
911 if (r)
912 liblist[n-1] = liblist[n];
913 else if (liblist[n].dll == dll)
914 r++;
915 }
916 if (r)
917 nlib--;
918 else if ((initfn = (Libinit_f)dlllook(dll, "lib_init")))
919 (*initfn)(0,sp);
920 if (nlib >= maxlib)
921 {
922 maxlib += GROWLIB;
923 liblist = newof(liblist, Libcomp_t, maxlib+1, 0);
924 }
925 liblist[nlib].dll = dll;
926 liblist[nlib].attr = (sp->nosfio?BLT_NOSFIO:0);
927 if (name)
928 liblist[nlib].lib = strdup(name);
929 if (pp)
930 {
931 liblist[nlib].dev = pp->dev;
932 liblist[nlib].ino = pp->ino;
933 }
934 nlib++;
935 return !r;
936 }
937
sh_getlib(Shell_t * shp,char * sym,Pathcomp_t * pp)938 Shbltin_f sh_getlib(Shell_t* shp, char* sym, Pathcomp_t* pp)
939 {
940 register int n;
941
942 for (n = 0; n < nlib; n++)
943 if (liblist[n].ino == pp->ino && liblist[n].dev == pp->dev)
944 return (Shbltin_f)dlllook(liblist[n].dll, sym);
945 return 0;
946 }
947
948 #else
949
sh_addlib(Shell_t * shp,void * library,char * name,Pathcomp_t * pp)950 int sh_addlib(Shell_t* shp, void* library, char* name, Pathcomp_t* pp)
951 {
952 return 0;
953 }
954
sh_getlib(Shell_t * shp,char * name,Pathcomp_t * pp)955 Shbltin_f sh_getlib(Shell_t* shp, char* name, Pathcomp_t* pp)
956 {
957 return 0;
958 }
959
960 #endif /* SHOPT_DYNAMIC */
961
962 /*
963 * add change or list built-ins
964 * adding builtins requires dlopen() interface
965 */
b_builtin(int argc,char * argv[],Shbltin_t * context)966 int b_builtin(int argc,char *argv[],Shbltin_t *context)
967 {
968 register char *arg=0, *name;
969 register int n, r=0, flag=0;
970 register Namval_t *np;
971 long dlete=0;
972 struct tdata tdata;
973 Shbltin_f addr;
974 Stk_t *stkp;
975 void *library=0;
976 char *errmsg;
977 #ifdef SH_PLUGIN_VERSION
978 unsigned long ver;
979 int list = 0;
980 char path[1024];
981 #endif
982 NOT_USED(argc);
983 memset(&tdata,0,sizeof(tdata));
984 tdata.sh = context->shp;
985 stkp = tdata.sh->stk;
986 if(!tdata.sh->pathlist)
987 path_absolute(tdata.sh,argv[0],NIL(Pathcomp_t*));
988 while (n = optget(argv,sh_optbuiltin)) switch (n)
989 {
990 case 's':
991 flag = BLT_SPC;
992 break;
993 case 'd':
994 dlete=1;
995 break;
996 case 'f':
997 #if SHOPT_DYNAMIC
998 arg = opt_info.arg;
999 #else
1000 errormsg(SH_DICT,2, "adding built-ins not supported");
1001 error_info.errors++;
1002 #endif /* SHOPT_DYNAMIC */
1003 break;
1004 case 'l':
1005 #ifdef SH_PLUGIN_VERSION
1006 list = 1;
1007 #endif
1008 break;
1009 case ':':
1010 errormsg(SH_DICT,2, "%s", opt_info.arg);
1011 break;
1012 case '?':
1013 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1014 break;
1015 }
1016 argv += opt_info.index;
1017 if(error_info.errors)
1018 errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
1019 if(arg || *argv)
1020 {
1021 if(sh_isoption(SH_RESTRICTED))
1022 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]);
1023 if(sh_isoption(SH_PFSH))
1024 errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]);
1025 if(tdata.sh->subshell && !tdata.sh->subshare)
1026 sh_subfork();
1027 }
1028 #if SHOPT_DYNAMIC
1029 if(arg)
1030 {
1031 #ifdef SH_PLUGIN_VERSION
1032 if(!(library = dllplugin(SH_ID, arg, NiL, SH_PLUGIN_VERSION, &ver, RTLD_LAZY, path, sizeof(path))))
1033 {
1034 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dllerror(0));
1035 return(1);
1036 }
1037 if(list)
1038 sfprintf(sfstdout, "%s %08lu %s\n", arg, ver, path);
1039 #else
1040 #if (_AST_VERSION>=20040404)
1041 if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
1042 #else
1043 if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
1044 #endif
1045 {
1046 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror());
1047 return(1);
1048 }
1049 #endif
1050 sh_addlib(tdata.sh,library,arg,NiL);
1051 }
1052 else
1053 #endif /* SHOPT_DYNAMIC */
1054 if(*argv==0 && !dlete)
1055 {
1056 print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata);
1057 return(0);
1058 }
1059 r = 0;
1060 flag = stktell(stkp);
1061 while(arg = *argv)
1062 {
1063 name = path_basename(arg);
1064 sfwrite(stkp,"b_",2);
1065 sfputr(stkp,name,0);
1066 errmsg = 0;
1067 addr = 0;
1068 if(dlete || liblist)
1069 for(n=(nlib?nlib:dlete); --n>=0;)
1070 {
1071 #if SHOPT_DYNAMIC
1072 if(!dlete && !liblist[n].dll)
1073 continue;
1074 if(dlete || (addr = (Shbltin_f)dlllook(liblist[n].dll,stkptr(stkp,flag))))
1075 #else
1076 if(dlete)
1077 #endif /* SHOPT_DYNAMIC */
1078 {
1079 if(np = sh_addbuiltin(arg, addr,pointerof(dlete)))
1080 {
1081 if(dlete || nv_isattr(np,BLT_SPC))
1082 errmsg = "restricted name";
1083 #if SHOPT_DYNAMIC
1084 else
1085 nv_onattr(np,liblist[n].attr);
1086 #endif /* SHOPT_DYNAMIC */
1087 }
1088 break;
1089 }
1090 }
1091 if(!addr && (np = nv_search(arg,context->shp->bltin_tree,0)))
1092 {
1093 if(nv_isattr(np,BLT_SPC))
1094 errmsg = "restricted name";
1095 addr = (Shbltin_f)np->nvalue.bfp;
1096 }
1097 if(!dlete && !addr && !(np=sh_addbuiltin(arg,(Shbltin_f)0 ,0)))
1098 errmsg = "not found";
1099 if(errmsg)
1100 {
1101 errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg);
1102 r = 1;
1103 }
1104 stkseek(stkp,flag);
1105 argv++;
1106 }
1107 return(r);
1108 }
1109
b_set(int argc,register char * argv[],Shbltin_t * context)1110 int b_set(int argc,register char *argv[],Shbltin_t *context)
1111 {
1112 struct tdata tdata;
1113 int was_monitor = sh_isoption(SH_MONITOR);
1114 memset(&tdata,0,sizeof(tdata));
1115 tdata.sh = context->shp;
1116 tdata.prefix=0;
1117 if(argv[1])
1118 {
1119 if(sh_argopts(argc,argv,tdata.sh) < 0)
1120 return(2);
1121 if(sh_isoption(SH_VERBOSE))
1122 sh_onstate(SH_VERBOSE);
1123 else
1124 sh_offstate(SH_VERBOSE);
1125 if(sh_isoption(SH_MONITOR) && !was_monitor)
1126 sh_onstate(SH_MONITOR);
1127 else if(!sh_isoption(SH_MONITOR) && was_monitor)
1128 sh_offstate(SH_MONITOR);
1129 }
1130 else
1131 /*scan name chain and print*/
1132 print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata);
1133 return(0);
1134 }
1135
1136 /*
1137 * The removing of Shell variable names, aliases, and functions
1138 * is performed here.
1139 * Unset functions with unset -f
1140 * Non-existent items being deleted give non-zero exit status
1141 */
1142
b_unalias(int argc,register char * argv[],Shbltin_t * context)1143 int b_unalias(int argc,register char *argv[],Shbltin_t *context)
1144 {
1145 Shell_t *shp = context->shp;
1146 return(unall(argc,argv,shp->alias_tree,shp));
1147 }
1148
b_unset(int argc,register char * argv[],Shbltin_t * context)1149 int b_unset(int argc,register char *argv[],Shbltin_t *context)
1150 {
1151 Shell_t *shp = context->shp;
1152 return(unall(argc,argv,shp->var_tree,shp));
1153 }
1154
unall(int argc,char ** argv,register Dt_t * troot,Shell_t * shp)1155 static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp)
1156 {
1157 register Namval_t *np;
1158 register const char *name;
1159 volatile int r;
1160 Dt_t *dp;
1161 int nflag=0,all=0,isfun,jmpval;
1162 struct checkpt buff;
1163 NOT_USED(argc);
1164 if(troot==shp->alias_tree)
1165 {
1166 name = sh_optunalias;
1167 if(shp->subshell)
1168 troot = sh_subaliastree(0);
1169 }
1170 else
1171 name = sh_optunset;
1172 while(r = optget(argv,name)) switch(r)
1173 {
1174 case 'f':
1175 troot = sh_subfuntree(1);
1176 break;
1177 case 'a':
1178 all=1;
1179 break;
1180 case 'n':
1181 nflag = NV_NOREF;
1182 /* FALLTHROUGH */
1183 case 'v':
1184 troot = shp->var_tree;
1185 break;
1186 case ':':
1187 errormsg(SH_DICT,2, "%s", opt_info.arg);
1188 break;
1189 case '?':
1190 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
1191 return(2);
1192 }
1193 argv += opt_info.index;
1194 if(error_info.errors || (*argv==0 &&!all))
1195 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
1196 if(!troot)
1197 return(1);
1198 r = 0;
1199 if(troot==shp->var_tree)
1200 nflag |= NV_VARNAME;
1201 else
1202 nflag = NV_NOSCOPE;
1203 if(all)
1204 {
1205 dtclear(troot);
1206 return(r);
1207 }
1208 sh_pushcontext(shp,&buff,1);
1209 while(name = *argv++)
1210 {
1211 jmpval = sigsetjmp(buff.buff,0);
1212 np = 0;
1213 if(jmpval==0)
1214 {
1215 #if SHOPT_NAMESPACE
1216 if(shp->namespace && troot!=shp->var_tree)
1217 np = sh_fsearch(shp,name,nflag?HASH_NOSCOPE:0);
1218 if(!np)
1219 #endif /* SHOPT_NAMESPACE */
1220 np=nv_open(name,troot,NV_NOADD|nflag);
1221 }
1222 else
1223 {
1224 r = 1;
1225 continue;
1226 }
1227 if(np)
1228 {
1229 if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY))
1230 {
1231 if(nv_isattr(np,NV_RDONLY))
1232 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
1233 r = 1;
1234 continue;
1235 }
1236 isfun = is_afunction(np);
1237 if(troot==shp->var_tree)
1238 {
1239 Namarr_t *ap;
1240 #if SHOPT_FIXEDARRAY
1241 if((ap=nv_arrayptr(np)) && !ap->fixed && name[strlen(name)-1]==']' && !nv_getsub(np))
1242 #else
1243 if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np))
1244 #endif /* SHOPT_FIXEDARRAY */
1245 {
1246 r=1;
1247 continue;
1248 }
1249
1250 if(shp->subshell)
1251 np=sh_assignok(np,0);
1252 }
1253 if(!nv_isnull(np) || nv_size(np) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)))
1254 _nv_unset(np,0);
1255 if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict)
1256 nv_delete(np,dp,NV_NOFREE);
1257 else if(isfun && !(np->nvalue.rp && np->nvalue.rp->running))
1258 nv_delete(np,troot,0);
1259 #if 0
1260 /* causes unsetting local variable to expose global */
1261 else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE))
1262 nv_delete(np,shp->var_tree,0);
1263 #endif
1264 else
1265 nv_close(np);
1266
1267 }
1268 else if(troot==shp->alias_tree)
1269 r = 1;
1270 }
1271 sh_popcontext(shp,&buff);
1272 return(r);
1273 }
1274
1275 /*
1276 * print out the name and value of a name-value pair <np>
1277 */
1278
print_namval(Sfio_t * file,register Namval_t * np,register int flag,struct tdata * tp)1279 static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp)
1280 {
1281 register char *cp;
1282 int indent=tp->indent, outname=0, isfun;
1283 sh_sigcheck(tp->sh);
1284 if(flag)
1285 flag = '\n';
1286 if(tp->noref && nv_isref(np))
1287 return(0);
1288 if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
1289 {
1290 if(is_abuiltin(np) && strcmp(np->nvname,".sh.tilde"))
1291 sfputr(file,nv_name(np),'\n');
1292 return(0);
1293 }
1294 if(nv_istable(np))
1295 {
1296 print_value(file,np,tp);
1297 return(0);
1298 }
1299 isfun = is_afunction(np);
1300 if(tp->prefix)
1301 {
1302 outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT)));
1303 if(indent && (isfun || outname || *tp->prefix!='t'))
1304 {
1305 sfnputc(file,'\t',indent);
1306 indent = 0;
1307 }
1308 if(!isfun)
1309 {
1310 if(*tp->prefix=='t')
1311 nv_attribute(np,tp->outfile,tp->prefix,tp->aflag);
1312 else
1313 sfputr(file,tp->prefix,' ');
1314 }
1315 }
1316 if(isfun)
1317 {
1318 Sfio_t *iop=0;
1319 char *fname=0;
1320 if(nv_isattr(np,NV_NOFREE))
1321 return(0);
1322 if(!flag && !np->nvalue.ip)
1323 sfputr(file,"typeset -fu",' ');
1324 else if(!flag && !nv_isattr(np,NV_FPOSIX))
1325 sfputr(file,"function",' ');
1326 cp = nv_name(np);
1327 if(tp->wctname)
1328 cp += strlen(tp->wctname)+1;
1329 sfputr(file,cp,-1);
1330 if(nv_isattr(np,NV_FPOSIX))
1331 sfwrite(file,"()",2);
1332 if(np->nvalue.ip && np->nvalue.rp->hoffset>=0)
1333 fname = np->nvalue.rp->fname;
1334 else
1335 flag = '\n';
1336 if(flag)
1337 {
1338 if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0)
1339 sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):"");
1340 else
1341 sfputc(file, '\n');
1342 }
1343 else
1344 {
1345 if(nv_isattr(np,NV_FTMP))
1346 {
1347 fname = 0;
1348 iop = tp->sh->heredocs;
1349 }
1350 else if(fname)
1351 iop = sfopen(iop,fname,"r");
1352 else if(tp->sh->gd->hist_ptr)
1353 iop = (tp->sh->gd->hist_ptr)->histfp;
1354 if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0)
1355 sfmove(iop,file, nv_size(np), -1);
1356 else
1357 flag = '\n';
1358 if(fname)
1359 sfclose(iop);
1360 }
1361 return(nv_size(np)+1);
1362 }
1363 if(nv_arrayptr(np))
1364 {
1365 if(indent)
1366 sfnputc(file,'\t',indent);
1367 print_value(file,np,tp);
1368 return(0);
1369 }
1370 if(nv_isvtree(np))
1371 nv_onattr(np,NV_EXPORT);
1372 if(cp=nv_getval(np))
1373 {
1374 if(indent)
1375 sfnputc(file,'\t',indent);
1376 sfputr(file,nv_name(np),-1);
1377 if(!flag)
1378 flag = '=';
1379 sfputc(file,flag);
1380 if(flag != '\n')
1381 {
1382 if(nv_isref(np) && nv_refsub(np))
1383 {
1384 sfputr(file,sh_fmtq(cp),-1);
1385 sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np)));
1386 }
1387 else
1388 #if SHOPT_TYPEDEF
1389 sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n');
1390 #else
1391 sfputr(file,sh_fmtq(cp),'\n');
1392 #endif /* SHOPT_TYPEDEF */
1393 }
1394 return(1);
1395 }
1396 else if(outname || (tp->scanmask && tp->scanroot==tp->sh->var_tree))
1397 sfputr(file,nv_name(np),'\n');
1398 return(0);
1399 }
1400
1401 /*
1402 * print attributes at all nodes
1403 */
print_all(Sfio_t * file,Dt_t * root,struct tdata * tp)1404 static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp)
1405 {
1406 tp->outfile = file;
1407 nv_scan(root, print_attribute, (void*)tp, 0, 0);
1408 }
1409
1410 /*
1411 * print the attributes of name value pair give by <np>
1412 */
print_attribute(register Namval_t * np,void * data)1413 static void print_attribute(register Namval_t *np,void *data)
1414 {
1415 register struct tdata *dp = (struct tdata*)data;
1416 nv_attribute(np,dp->outfile,dp->prefix,dp->aflag);
1417 }
1418
1419 /*
1420 * print the nodes in tree <root> which have attributes <flag> set
1421 * of <option> is non-zero, no subscript or value is printed.
1422 */
1423
print_scan(Sfio_t * file,int flag,Dt_t * root,int option,struct tdata * tp)1424 static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp)
1425 {
1426 register char **argv;
1427 register Namval_t *np;
1428 register int namec;
1429 Namval_t *onp = 0;
1430 char *name=0;
1431 int len;
1432 tp->sh->last_table=0;
1433 flag &= ~NV_ASSIGN;
1434 tp->scanmask = flag&~NV_NOSCOPE;
1435 tp->scanroot = root;
1436 tp->outfile = file;
1437 #if SHOPT_TYPEDEF
1438 if(!tp->prefix && tp->tp)
1439 tp->prefix = nv_name(tp->tp);
1440 #endif /* SHOPT_TYPEDEF */
1441 if(flag&NV_INTEGER)
1442 tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE);
1443 if(flag==NV_LTOU || flag==NV_UTOL)
1444 tp->scanmask |= NV_UTOL|NV_LTOU;
1445 namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag);
1446 argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*));
1447 namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY);
1448 if(mbcoll())
1449 strsort(argv,namec,strcoll);
1450 if(namec==0 && tp->sh->namespace && nv_dict(tp->sh->namespace)==root)
1451 {
1452 sfnputc(file,'\t',tp->indent);
1453 sfwrite(file,":\n",2);
1454 }
1455 else while(namec--)
1456 {
1457 if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)))
1458 {
1459 onp = np;
1460 if(name)
1461 {
1462 char *newname = nv_name(np);
1463 if(memcmp(name,newname,len)==0 && newname[len]== '.')
1464 continue;
1465 name = 0;
1466 }
1467 if(flag&NV_ARRAY)
1468 {
1469 if(nv_aindex(np)>=0)
1470 {
1471 if(!(flag&NV_IARRAY))
1472 continue;
1473 }
1474 else if((flag&NV_IARRAY))
1475 continue;
1476
1477 }
1478 tp->scanmask = flag&~NV_NOSCOPE;
1479 tp->scanroot = root;
1480 print_namval(file,np,option,tp);
1481 if(!is_abuiltin(np) && nv_isvtree(np))
1482 {
1483 name = nv_name(np);
1484 len = strlen(name);
1485 }
1486 }
1487 }
1488 }
1489
1490 /*
1491 * add the name of the node to the argument list argnam
1492 */
1493
pushname(Namval_t * np,void * data)1494 static void pushname(Namval_t *np,void *data)
1495 {
1496 struct tdata *tp = (struct tdata*)data;
1497 *tp->argnam++ = nv_name(np);
1498 }
1499
1500