summaryrefslogtreecommitdiff
path: root/src/cmd/ksh93/bltins/typeset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ksh93/bltins/typeset.c')
-rw-r--r--src/cmd/ksh93/bltins/typeset.c1471
1 files changed, 1471 insertions, 0 deletions
diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c
new file mode 100644
index 0000000..f5618a1
--- /dev/null
+++ b/src/cmd/ksh93/bltins/typeset.c
@@ -0,0 +1,1471 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* and is licensed under the *
+* Eclipse Public License, Version 1.0 *
+* by AT&T Intellectual Property *
+* *
+* A copy of the License is available at *
+* http://www.eclipse.org/org/documents/epl-v10.html *
+* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * export [-p] [arg...]
+ * readonly [-p] [arg...]
+ * typeset [options] [arg...]
+ * alias [-ptx] [arg...]
+ * unalias [arg...]
+ * builtin [-sd] [-f file] [name...]
+ * set [options] [name...]
+ * unset [-fnv] [name...]
+ *
+ * David Korn
+ * AT&T Labs
+ *
+ */
+
+#include "defs.h"
+#include <error.h>
+#include "path.h"
+#include "name.h"
+#include "history.h"
+#include "builtins.h"
+#include "variables.h"
+#include "FEATURE/dynamic"
+
+struct tdata
+{
+ Shell_t *sh;
+ Namval_t *tp;
+ const char *wctname;
+ Sfio_t *outfile;
+ char *prefix;
+ char *tname;
+ char *help;
+ short aflag;
+ short pflag;
+ int argnum;
+ int scanmask;
+ Dt_t *scanroot;
+ char **argnam;
+ int indent;
+ int noref;
+};
+
+
+static int print_namval(Sfio_t*, Namval_t*, int, struct tdata*);
+static void print_attribute(Namval_t*,void*);
+static void print_all(Sfio_t*, Dt_t*, struct tdata*);
+static void print_scan(Sfio_t*, int, Dt_t*, int, struct tdata*);
+static int unall(int, char**, Dt_t*, Shell_t*);
+static int setall(char**, int, Dt_t*, struct tdata*);
+static void pushname(Namval_t*,void*);
+static void(*nullscan)(Namval_t*,void*);
+
+static Namval_t *load_class(const char *name)
+{
+ errormsg(SH_DICT,ERROR_exit(1),"%s: type not loadable",name);
+ return(0);
+}
+
+/*
+ * Note export and readonly are the same
+ */
+#if 0
+ /* for the dictionary generator */
+ int b_export(int argc,char *argv[],Shbltin_t *context){}
+#endif
+int b_readonly(int argc,char *argv[],Shbltin_t *context)
+{
+ register int flag;
+ char *command = argv[0];
+ struct tdata tdata;
+ NOT_USED(argc);
+ memset((void*)&tdata,0,sizeof(tdata));
+ tdata.sh = context->shp;
+ tdata.aflag = '-';
+ while((flag = optget(argv,*command=='e'?sh_optexport:sh_optreadonly))) switch(flag)
+ {
+ case 'p':
+ tdata.prefix = command;
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
+ return(2);
+ }
+ if(error_info.errors)
+ errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
+ argv += (opt_info.index-1);
+ if(*command=='r')
+ flag = (NV_ASSIGN|NV_RDONLY|NV_VARNAME);
+#ifdef _ENV_H
+ else if(!argv[1])
+ {
+ char *cp,**env=env_get(tdata.sh->env);
+ while(cp = *env++)
+ {
+ if(tdata.prefix)
+ sfputr(sfstdout,tdata.prefix,' ');
+ sfprintf(sfstdout,"%s\n",sh_fmtq(cp));
+ }
+ return(0);
+ }
+#endif
+ else
+ {
+ flag = (NV_ASSIGN|NV_EXPORT|NV_IDENT);
+ if(!tdata.sh->prefix)
+ tdata.sh->prefix = "";
+ }
+ return(setall(argv,flag,tdata.sh->var_tree, &tdata));
+}
+
+
+int b_alias(int argc,register char *argv[],Shbltin_t *context)
+{
+ register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN;
+ register Dt_t *troot;
+ register int n;
+ struct tdata tdata;
+ NOT_USED(argc);
+ memset((void*)&tdata,0,sizeof(tdata));
+ tdata.sh = context->shp;
+ troot = tdata.sh->alias_tree;
+ if(*argv[0]=='h')
+ flag = NV_TAGGED;
+ if(argv[1])
+ {
+ opt_info.offset = 0;
+ opt_info.index = 1;
+ *opt_info.option = 0;
+ tdata.argnum = 0;
+ tdata.aflag = *argv[1];
+ while((n = optget(argv,sh_optalias))) switch(n)
+ {
+ case 'p':
+ tdata.prefix = argv[0];
+ break;
+ case 't':
+ flag |= NV_TAGGED;
+ break;
+ case 'x':
+ flag |= NV_EXPORT;
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
+ return(2);
+ }
+ if(error_info.errors)
+ errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
+ argv += (opt_info.index-1);
+ if(flag&NV_TAGGED)
+ {
+ /* hacks to handle hash -r | -- */
+ if(argv[1] && argv[1][0]=='-')
+ {
+ if(argv[1][1]=='r' && argv[1][2]==0)
+ {
+ Namval_t *np = nv_search((char*)PATHNOD,tdata.sh->var_tree,HASH_BUCKET);
+ nv_putval(np,nv_getval(np),NV_RDONLY);
+ argv++;
+ if(!argv[1])
+ return(0);
+ }
+ if(argv[1][0]=='-')
+ {
+ if(argv[1][1]=='-' && argv[1][2]==0)
+ argv++;
+ else
+ errormsg(SH_DICT, ERROR_exit(1), e_option, argv[1]);
+ }
+ }
+ troot = tdata.sh->track_tree;
+ }
+ }
+ return(setall(argv,flag,troot,&tdata));
+}
+
+
+#if 0
+ /* for the dictionary generator */
+ int b_local(int argc,char *argv[],Shbltin_t *context){}
+#endif
+int b_typeset(int argc,register char *argv[],Shbltin_t *context)
+{
+ register int n, flag = NV_VARNAME|NV_ASSIGN;
+ struct tdata tdata;
+ const char *optstring = sh_opttypeset;
+ Namdecl_t *ntp = (Namdecl_t*)context->ptr;
+ Dt_t *troot;
+ int isfloat=0, shortint=0, sflag=0;
+ NOT_USED(argc);
+ memset((void*)&tdata,0,sizeof(tdata));
+ tdata.sh = context->shp;
+ if(ntp)
+ {
+ tdata.tp = ntp->tp;
+ opt_info.disc = (Optdisc_t*)ntp->optinfof;
+ optstring = ntp->optstring;
+ }
+ troot = tdata.sh->var_tree;
+ while((n = optget(argv,optstring)))
+ {
+ if(tdata.aflag==0)
+ tdata.aflag = *opt_info.option;
+ switch(n)
+ {
+ case 'a':
+ flag |= NV_IARRAY;
+ if(opt_info.arg && *opt_info.arg!='[')
+ {
+ opt_info.index--;
+ goto endargs;
+ }
+ tdata.tname = opt_info.arg;
+ break;
+ case 'A':
+ flag |= NV_ARRAY;
+ break;
+ case 'C':
+ flag |= NV_COMVAR;
+ break;
+ case 'E':
+ /* The following is for ksh88 compatibility */
+ if(opt_info.offset && !strchr(argv[opt_info.index],'E'))
+ {
+ tdata.argnum = (int)opt_info.num;
+ break;
+ }
+ case 'F':
+ case 'X':
+ if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
+ tdata.argnum = (n=='X'?2*sizeof(Sfdouble_t):10);
+ isfloat = 1;
+ if(n=='E')
+ {
+ flag &= ~NV_HEXFLOAT;
+ flag |= NV_EXPNOTE;
+ }
+ else if(n=='X')
+ {
+ flag &= ~NV_EXPNOTE;
+ flag |= NV_HEXFLOAT;
+ }
+ break;
+ case 'b':
+ flag |= NV_BINARY;
+ break;
+ case 'm':
+ flag |= NV_MOVE;
+ break;
+ case 'n':
+ flag &= ~NV_VARNAME;
+ flag |= (NV_REF|NV_IDENT);
+ break;
+ case 'H':
+ flag |= NV_HOST;
+ break;
+ case 'T':
+ flag |= NV_TYPE;
+ tdata.prefix = opt_info.arg;
+ break;
+ case 'L': case 'Z': case 'R':
+ if(tdata.argnum==0)
+ tdata.argnum = (int)opt_info.num;
+ if(tdata.argnum < 0)
+ errormsg(SH_DICT,ERROR_exit(1), e_badfield, tdata.argnum);
+ if(n=='Z')
+ flag |= NV_ZFILL;
+ else
+ {
+ flag &= ~(NV_LJUST|NV_RJUST);
+ flag |= (n=='L'?NV_LJUST:NV_RJUST);
+ }
+ break;
+ case 'M':
+ if((tdata.wctname = opt_info.arg) && !nv_mapchar((Namval_t*)0,tdata.wctname))
+ errormsg(SH_DICT, ERROR_exit(1),e_unknownmap, tdata.wctname);
+ if(tdata.wctname && strcmp(tdata.wctname,e_tolower)==0)
+ flag |= NV_UTOL;
+ else
+ flag |= NV_LTOU;
+ if(!tdata.wctname)
+ flag |= NV_UTOL;
+ break;
+ case 'f':
+ flag &= ~(NV_VARNAME|NV_ASSIGN);
+ troot = tdata.sh->fun_tree;
+ break;
+ case 'i':
+ if(!opt_info.arg || (tdata.argnum = opt_info.num) <0)
+ tdata.argnum = 10;
+ flag |= NV_INTEGER;
+ break;
+ case 'l':
+ tdata.wctname = e_tolower;
+ flag |= NV_UTOL;
+ break;
+ case 'p':
+ tdata.prefix = argv[0];
+ tdata.pflag = 1;
+ flag &= ~NV_ASSIGN;
+ break;
+ case 'r':
+ flag |= NV_RDONLY;
+ break;
+#ifdef SHOPT_TYPEDEF
+ case 'S':
+ sflag=1;
+ break;
+ case 'h':
+ tdata.help = opt_info.arg;
+ break;
+#endif /*SHOPT_TYPEDEF*/
+ case 's':
+ shortint=1;
+ break;
+ case 't':
+ flag |= NV_TAGGED;
+ break;
+ case 'u':
+ tdata.wctname = e_toupper;
+ flag |= NV_LTOU;
+ break;
+ case 'x':
+ flag &= ~NV_VARNAME;
+ flag |= (NV_EXPORT|NV_IDENT);
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
+ opt_info.disc = 0;
+ return(2);
+ }
+ }
+endargs:
+ argv += opt_info.index;
+ opt_info.disc = 0;
+ /* handle argument of + and - specially */
+ if(*argv && argv[0][1]==0 && (*argv[0]=='+' || *argv[0]=='-'))
+ tdata.aflag = *argv[0];
+ else
+ argv--;
+ if((flag&NV_ZFILL) && !(flag&NV_LJUST))
+ flag |= NV_RJUST;
+ if((flag&NV_INTEGER) && (flag&(NV_LJUST|NV_RJUST|NV_ZFILL)))
+ error_info.errors++;
+ if((flag&NV_BINARY) && (flag&(NV_LJUST|NV_UTOL|NV_LTOU)))
+ error_info.errors++;
+ if((flag&NV_MOVE) && (flag&~(NV_MOVE|NV_VARNAME|NV_ASSIGN)))
+ error_info.errors++;
+ if((flag&NV_REF) && (flag&~(NV_REF|NV_IDENT|NV_ASSIGN)))
+ error_info.errors++;
+ if((flag&NV_TYPE) && (flag&~(NV_TYPE|NV_VARNAME|NV_ASSIGN)))
+ error_info.errors++;
+ if(troot==tdata.sh->fun_tree && ((isfloat || flag&~(NV_FUNCT|NV_TAGGED|NV_EXPORT|NV_LTOU))))
+ error_info.errors++;
+ if(sflag && troot==tdata.sh->fun_tree)
+ {
+ /* static function */
+ sflag = 0;
+ flag |= NV_STATICF;
+ }
+ if(error_info.errors)
+ errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
+ if(isfloat)
+ flag |= NV_DOUBLE;
+ if(shortint)
+ {
+ flag &= ~NV_LONG;
+ flag |= NV_SHORT|NV_INTEGER;
+ }
+ if(sflag)
+ {
+ if(tdata.sh->mktype)
+ flag |= NV_REF|NV_TAGGED;
+ else if(!tdata.sh->typeinit)
+ flag |= NV_STATIC|NV_IDENT;
+ }
+ if(tdata.sh->fn_depth && !tdata.pflag)
+ flag |= NV_NOSCOPE;
+ if(tdata.help)
+ tdata.help = strdup(tdata.help);
+ if(flag&NV_TYPE)
+ {
+ Stk_t *stkp = tdata.sh->stk;
+ int off=0,offset = stktell(stkp);
+ if(!tdata.prefix)
+ return(sh_outtype(tdata.sh,sfstdout));
+ sfputr(stkp,NV_CLASS,-1);
+#if SHOPT_NAMESPACE
+ if(tdata.sh->namespace)
+ {
+ off = stktell(stkp)+1;
+ sfputr(stkp,nv_name(tdata.sh->namespace),'.');
+ }
+ else
+#endif /* SHOPT_NAMESPACE */
+ if(NV_CLASS[sizeof(NV_CLASS)-2]!='.')
+ sfputc(stkp,'.');
+ sfputr(stkp,tdata.prefix,0);
+ tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN);
+#if SHOPT_NAMESPACE
+ if(!tdata.tp && off)
+ {
+ *stkptr(stkp,off)=0;
+ tdata.tp = nv_open(stkptr(stkp,offset),tdata.sh->var_tree,NV_VARNAME|NV_NOARRAY|NV_NOASSIGN);
+ }
+#endif /* SHOPT_NAMESPACE */
+ stkseek(stkp,offset);
+ if(!tdata.tp)
+ errormsg(SH_DICT,ERROR_exit(1),"%s: unknown type",tdata.prefix);
+ else if(nv_isnull(tdata.tp))
+ nv_newtype(tdata.tp);
+ tdata.tp->nvenv = tdata.help;
+ flag &= ~NV_TYPE;
+ }
+ else if(tdata.aflag==0 && ntp && ntp->tp)
+ tdata.aflag = '-';
+ if(!tdata.sh->mktype)
+ tdata.help = 0;
+ if(tdata.aflag=='+' && (flag&(NV_ARRAY|NV_IARRAY|NV_COMVAR)))
+ errormsg(SH_DICT,ERROR_exit(1),e_nounattr);
+ return(setall(argv,flag,troot,&tdata));
+}
+
+static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp)
+{
+ char *name;
+ int aflag=tp->aflag;
+ if(nv_isnull(np))
+ {
+ if(!np->nvflag)
+ return;
+ aflag = '+';
+ }
+ else if(nv_istable(np))
+ {
+ Dt_t *root = tp->sh->last_root;
+ Namval_t *nsp = tp->sh->namespace;
+ char *cp = name = nv_name(np);
+ if(*name=='.')
+ name++;
+ if(tp->indent)
+ sfnputc(iop,'\t',tp->indent);
+ sfprintf(iop,"namespace %s\n", name);
+ if(tp->indent)
+ sfnputc(iop,'\t',tp->indent);
+ sfprintf(iop,"{\n", name);
+ tp->indent++;
+ /* output types from namespace */
+ tp->sh->namespace = 0;
+ tp->sh->prefix = nv_name(np)+1;
+ sh_outtype(tp->sh,iop);
+ tp->sh->prefix = 0;
+ tp->sh->namespace = np;
+ tp->sh->last_root = root;
+ /* output variables from namespace */
+ print_scan(iop,NV_NOSCOPE,nv_dict(np),aflag=='+',tp);
+ tp->wctname = cp;
+ tp->sh->namespace = 0;
+ /* output functions from namespace */
+ print_scan(iop,NV_FUNCTION|NV_NOSCOPE,tp->sh->fun_tree,aflag=='+',tp);
+ tp->wctname = 0;
+ tp->sh->namespace = nsp;
+ if(--tp->indent)
+ sfnputc(iop,'\t',tp->indent);
+ sfwrite(iop,"}\n",2);
+ return;
+ }
+ sfputr(iop,nv_name(np),aflag=='+'?'\n':'=');
+ if(aflag=='+')
+ return;
+ if(nv_isarray(np) && nv_arrayptr(np))
+ {
+ nv_outnode(np,iop,-1,0);
+ sfwrite(iop,")\n",2);
+ }
+ else
+ {
+ if(nv_isvtree(np))
+ nv_onattr(np,NV_EXPORT);
+ if(!(name = nv_getval(np)))
+ name = Empty;
+ if(!nv_isvtree(np))
+ name = sh_fmtq(name);
+ sfputr(iop,name,'\n');
+ }
+}
+
+static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp)
+{
+ register char *name;
+ char *last = 0;
+ int nvflags=(flag&(NV_ARRAY|NV_NOARRAY|NV_VARNAME|NV_IDENT|NV_ASSIGN|NV_STATIC|NV_MOVE));
+ int r=0, ref=0, comvar=(flag&NV_COMVAR),iarray=(flag&NV_IARRAY);
+ Shell_t *shp =tp->sh;
+ if(!shp->prefix)
+ {
+ if(!tp->pflag)
+ nvflags |= NV_NOSCOPE;
+ }
+ else if(*shp->prefix==0)
+ shp->prefix = 0;
+ if(*argv[0]=='+')
+ nvflags |= NV_NOADD;
+ flag &= ~(NV_NOARRAY|NV_NOSCOPE|NV_VARNAME|NV_IDENT|NV_STATIC|NV_COMVAR|NV_IARRAY);
+ if(argv[1])
+ {
+ if(flag&NV_REF)
+ {
+ flag &= ~NV_REF;
+ ref=1;
+ if(tp->aflag!='-')
+ nvflags |= NV_NOREF;
+ }
+ if(tp->pflag)
+ nvflags |= NV_NOREF;
+ while(name = *++argv)
+ {
+ register unsigned newflag;
+ register Namval_t *np;
+ Namarr_t *ap;
+ Namval_t *mp;
+ unsigned curflag;
+ if(troot == shp->fun_tree)
+ {
+ /*
+ *functions can be exported or
+ * traced but not set
+ */
+ flag &= ~NV_ASSIGN;
+ if(flag&NV_LTOU)
+ {
+ /* Function names cannot be special builtin */
+ if((np=nv_search(name,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))
+ errormsg(SH_DICT,ERROR_exit(1),e_badfun,name);
+#if SHOPT_NAMESPACE
+ if(shp->namespace)
+ np = sh_fsearch(shp,name,NV_ADD|HASH_NOSCOPE);
+ else
+#endif /* SHOPT_NAMESPACE */
+ np = nv_open(name,sh_subfuntree(1),NV_NOARRAY|NV_IDENT|NV_NOSCOPE);
+ }
+ else
+ {
+ if(shp->prefix)
+ {
+ sfprintf(shp->strbuf,"%s.%s%c",shp->prefix,name,0);
+ name = sfstruse(shp->strbuf);
+ }
+#if SHOPT_NAMESPACE
+ np = 0;
+ if(shp->namespace)
+ np = sh_fsearch(shp,name,HASH_NOSCOPE);
+ if(!np)
+#endif /* SHOPT_NAMESPACE */
+ if(np=nv_search(name,troot,0))
+ {
+ if(!is_afunction(np))
+ np = 0;
+ }
+ else if(memcmp(name,".sh.math.",9)==0 && sh_mathstd(name+9))
+ continue;
+ }
+ if(np && ((flag&NV_LTOU) || !nv_isnull(np) || nv_isattr(np,NV_LTOU)))
+ {
+ if(flag==0 && !tp->help)
+ {
+ print_namval(sfstdout,np,tp->aflag=='+',tp);
+ continue;
+ }
+ if(shp->subshell && !shp->subshare)
+ sh_subfork();
+ if(tp->aflag=='-')
+ nv_onattr(np,flag|NV_FUNCTION);
+ else if(tp->aflag=='+')
+ nv_offattr(np,flag);
+ }
+ else
+ r++;
+ if(tp->help)
+ {
+ int offset = stktell(shp->stk);
+ if(!np)
+ {
+ sfputr(shp->stk,shp->prefix,'.');
+ sfputr(shp->stk,name,0);
+ np = nv_search(stkptr(shp->stk,offset),troot,0);
+ stkseek(shp->stk,offset);
+ }
+ if(np && np->nvalue.cp)
+ np->nvalue.rp->help = tp->help;
+ }
+ continue;
+ }
+ /* tracked alias */
+ if(troot==shp->track_tree && tp->aflag=='-')
+ {
+ np = nv_search(name,troot,NV_ADD);
+ path_alias(np,path_absolute(shp,nv_name(np),NIL(Pathcomp_t*)));
+ continue;
+ }
+ np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&NV_REF))?NV_FARRAY:0));
+ if(!np)
+ continue;
+ if(nv_isnull(np) && !nv_isarray(np) && nv_isattr(np,NV_NOFREE))
+ nv_offattr(np,NV_NOFREE);
+ else if(tp->tp && !nv_isattr(np,NV_MINIMAL|NV_EXPORT) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp)) && (ap->nelem&ARRAY_TREE))
+#if 0
+ errormsg(SH_DICT,ERROR_exit(1),e_typecompat,nv_name(np));
+#else
+ errormsg(SH_DICT,ERROR_exit(1),"%s: typecompat",nv_name(np));
+#endif
+ else if((ap=nv_arrayptr(np)) && nv_aindex(np)>0 && ap->nelem==1 && nv_getval(np)==Empty)
+ {
+ ap->nelem++;
+ _nv_unset(np,0);
+ ap->nelem--;
+ }
+ if(tp->pflag)
+ {
+ if(!nv_istable(np))
+ nv_attribute(np,sfstdout,tp->prefix,1);
+ print_value(sfstdout,np,tp);
+ continue;
+ }
+ if(flag==NV_ASSIGN && !ref && tp->aflag!='-' && !strchr(name,'='))
+ {
+ if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp)))
+ {
+ sfprintf(sfstderr,sh_translate(e_noalias),name);
+ r++;
+ }
+ if(!comvar && !iarray)
+ continue;
+ }
+ if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name)))
+ {
+ 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)))))
+{
+ _nv_unset(np,0);
+}
+ }
+ if(troot==shp->var_tree)
+ {
+ if(iarray)
+ {
+ if(tp->tname)
+ nv_atypeindex(np,tp->tname+1);
+ else if(nv_isnull(np))
+ nv_onattr(np,NV_ARRAY|(comvar?NV_NOFREE:0));
+ else
+ {
+ if(ap && comvar)
+ ap->nelem |= ARRAY_TREE;
+ nv_putsub(np, (char*)0, 0);
+ }
+ }
+ else if(nvflags&NV_ARRAY)
+ {
+ if(comvar)
+ {
+ Namarr_t *ap=nv_arrayptr(np);
+ if(ap)
+ ap->nelem |= ARRAY_TREE;
+ else
+ {
+ _nv_unset(np,NV_RDONLY);
+ nv_onattr(np,NV_NOFREE);
+ }
+ }
+ nv_setarray(np,nv_associative);
+ }
+ else if(comvar && !nv_isvtree(np) && !nv_rename(np,flag|NV_COMVAR))
+ nv_setvtree(np);
+ }
+ if(flag&NV_MOVE)
+ {
+ nv_rename(np, flag);
+ nv_close(np);
+ continue;
+ }
+ if(tp->tp && nv_type(np)!=tp->tp)
+ {
+ nv_settype(np,tp->tp,tp->aflag=='-'?0:NV_APPEND);
+ flag = (np->nvflag&NV_NOCHANGE);
+ }
+ flag &= ~NV_ASSIGN;
+ if(last=strchr(name,'='))
+ *last = 0;
+ if (shp->typeinit)
+ continue;
+ curflag = np->nvflag;
+ if(!(flag&NV_INTEGER) && (flag&(NV_LTOU|NV_UTOL)))
+ {
+ Namfun_t *fp;
+ char *cp;
+ if(!tp->wctname)
+ errormsg(SH_DICT,ERROR_exit(1),e_mapchararg,nv_name(np));
+ cp = (char*)nv_mapchar(np,0);
+ if(fp=nv_mapchar(np,tp->wctname))
+ {
+ if(tp->aflag=='+')
+ {
+ if(cp && strcmp(cp,tp->wctname)==0)
+ {
+ nv_disc(np,fp,NV_POP);
+ if(!(fp->nofree&1))
+ free((void*)fp);
+ nv_offattr(np,flag&(NV_LTOU|NV_UTOL));
+ }
+ }
+ else if(!cp || strcmp(cp,tp->wctname))
+ {
+ nv_disc(np,fp,NV_LAST);
+ nv_onattr(np,flag&(NV_LTOU|NV_UTOL));
+ }
+ }
+ }
+ if (tp->aflag == '-')
+ {
+ if((flag&NV_EXPORT) && (strchr(name,'.') || nv_isvtree(np)))
+ errormsg(SH_DICT,ERROR_exit(1),e_badexport,name);
+#if SHOPT_BSH
+ if(flag&NV_EXPORT)
+ nv_offattr(np,NV_IMPORT);
+#endif /* SHOPT_BSH */
+ newflag = curflag;
+ if(flag&~NV_NOCHANGE)
+ newflag &= NV_NOCHANGE;
+ newflag |= flag;
+ if (flag & (NV_LJUST|NV_RJUST))
+ {
+ if(!(flag&NV_RJUST))
+ newflag &= ~NV_RJUST;
+
+ else if(!(flag&NV_LJUST))
+ newflag &= ~NV_LJUST;
+ }
+ }
+ else
+ {
+ if((flag&NV_RDONLY) && (curflag&NV_RDONLY))
+ errormsg(SH_DICT,ERROR_exit(1),e_readonly,nv_name(np));
+ newflag = curflag & ~flag;
+ }
+ if (tp->aflag && (tp->argnum>0 || (curflag!=newflag)))
+ {
+ if(shp->subshell)
+ sh_assignok(np,1);
+ if(troot!=shp->var_tree)
+ nv_setattr(np,newflag&~NV_ASSIGN);
+ else
+ {
+ char *oldname=0;
+ int len=strlen(name);
+ if(tp->argnum==1 && newflag==NV_INTEGER && nv_isattr(np,NV_INTEGER))
+ tp->argnum = 10;
+ /* use reference name for export */
+ if((newflag^curflag)&NV_EXPORT)
+ {
+ oldname = np->nvname;
+ np->nvname = name;
+ }
+ if(np->nvfun && !nv_isarray(np) && name[len-1]=='.')
+ newflag |= NV_NODISC;
+ nv_newattr (np, newflag&~NV_ASSIGN,tp->argnum);
+ if(oldname)
+ np->nvname = oldname;
+ }
+ }
+ if(tp->help && !nv_isattr(np,NV_MINIMAL|NV_EXPORT))
+ {
+ np->nvenv = tp->help;
+ nv_onattr(np,NV_EXPORT);
+ }
+ if(last)
+ *last = '=';
+ /* set or unset references */
+ if(ref)
+ {
+ if(tp->aflag=='-')
+ {
+ Dt_t *hp=0;
+ if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
+ {
+ if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
+ hp = dtvnext(shp->var_tree);
+ }
+ if(tp->sh->mktype)
+ nv_onattr(np,NV_REF|NV_FUNCT);
+ else
+ nv_setref(np,hp,NV_VARNAME);
+ }
+ else
+ nv_unref(np);
+ }
+ nv_close(np);
+ }
+ }
+ else
+ {
+ if(shp->prefix)
+ errormsg(SH_DICT,2, e_subcomvar,shp->prefix);
+ if(tp->aflag)
+ {
+ if(troot==shp->fun_tree)
+ {
+ flag |= NV_FUNCTION;
+ tp->prefix = 0;
+ }
+ else if(troot==shp->var_tree)
+ {
+ flag |= (nvflags&NV_ARRAY);
+ if(flag&NV_IARRAY)
+ flag |= NV_ARRAY;
+ if(!(flag&~NV_ASSIGN))
+ tp->noref = 1;
+ }
+ if((flag&(NV_UTOL|NV_LTOU)) ==(NV_UTOL|NV_LTOU))
+ {
+ print_scan(sfstdout,flag&~NV_UTOL,troot,tp->aflag=='+',tp);
+ flag &= ~NV_LTOU;
+ }
+ print_scan(sfstdout,flag,troot,tp->aflag=='+',tp);
+ if(tp->noref)
+ {
+ tp->noref = 0;
+ print_scan(sfstdout,flag|NV_REF,troot,tp->aflag=='+',tp);
+ }
+ }
+ else if(troot==shp->alias_tree)
+ print_scan(sfstdout,0,troot,0,tp);
+ else
+ print_all(sfstdout,troot,tp);
+ sfsync(sfstdout);
+ }
+ return(r);
+}
+
+typedef void (*Iptr_t)(int,void*);
+
+#define GROWLIB 4
+
+static void **liblist;
+static unsigned short *libattr;
+static int nlib;
+static int maxlib;
+
+/*
+ * This allows external routines to load from the same library */
+void **sh_getliblist(void)
+{
+ return(liblist);
+}
+
+/*
+ * add library to loaded list
+ * call (*lib_init)() on first load if defined
+ * always move to head of search list
+ * return: 0: already loaded 1: first load
+ */
+#if SHOPT_DYNAMIC
+int sh_addlib(Shell_t *shp,void* library)
+{
+ register int n;
+ register int r;
+ Iptr_t initfn;
+ Shbltin_t *sp = &shp->bltindata;
+
+ sp->nosfio = 0;
+ for (n = r = 0; n < nlib; n++)
+ {
+ if (r)
+ {
+ liblist[n-1] = liblist[n];
+ libattr[n-1] = libattr[n];
+ }
+ else if (liblist[n] == library)
+ r++;
+ }
+ if (r)
+ nlib--;
+ else if ((initfn = (Iptr_t)dlllook(library, "lib_init")))
+ (*initfn)(0,sp);
+ if (nlib >= maxlib)
+ {
+ maxlib += GROWLIB;
+ if (liblist)
+ {
+ liblist = (void**)realloc((void*)liblist, (maxlib+1)*sizeof(void*));
+ libattr = (unsigned short*)realloc((void*)libattr, (maxlib+1)*sizeof(unsigned short));
+ }
+ else
+ {
+ liblist = (void**)malloc((maxlib+1)*sizeof(void*));
+ libattr = (unsigned short*)malloc((maxlib+1)*sizeof(unsigned short));
+ }
+ }
+ libattr[nlib] = (sp->nosfio?BLT_NOSFIO:0);
+ liblist[nlib++] = library;
+ liblist[nlib] = 0;
+ return !r;
+}
+#else
+int sh_addlib(Shell_t *shp,void* library)
+{
+ return 0;
+}
+#endif /* SHOPT_DYNAMIC */
+
+/*
+ * add change or list built-ins
+ * adding builtins requires dlopen() interface
+ */
+int b_builtin(int argc,char *argv[],Shbltin_t *context)
+{
+ register char *arg=0, *name;
+ register int n, r=0, flag=0;
+ register Namval_t *np;
+ long dlete=0;
+ struct tdata tdata;
+ Shbltin_f addr;
+ Stk_t *stkp;
+ void *library=0;
+ char *errmsg;
+#ifdef SH_PLUGIN_VERSION
+ unsigned long ver;
+ int list = 0;
+ char path[1024];
+#endif
+ NOT_USED(argc);
+ memset(&tdata,0,sizeof(tdata));
+ tdata.sh = context->shp;
+ stkp = tdata.sh->stk;
+ if(!tdata.sh->pathlist)
+ path_absolute(tdata.sh,argv[0],NIL(Pathcomp_t*));
+ while (n = optget(argv,sh_optbuiltin)) switch (n)
+ {
+ case 's':
+ flag = BLT_SPC;
+ break;
+ case 'd':
+ dlete=1;
+ break;
+ case 'f':
+#if SHOPT_DYNAMIC
+ arg = opt_info.arg;
+#else
+ errormsg(SH_DICT,2, "adding built-ins not supported");
+ error_info.errors++;
+#endif /* SHOPT_DYNAMIC */
+ break;
+ case 'l':
+#ifdef SH_PLUGIN_VERSION
+ list = 1;
+#endif
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
+ break;
+ }
+ argv += opt_info.index;
+ if(error_info.errors)
+ errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NIL(char*)));
+ if(arg || *argv)
+ {
+ if(sh_isoption(SH_RESTRICTED))
+ errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[-opt_info.index]);
+ if(sh_isoption(SH_PFSH))
+ errormsg(SH_DICT,ERROR_exit(1),e_pfsh,argv[-opt_info.index]);
+ if(tdata.sh->subshell && !tdata.sh->subshare)
+ sh_subfork();
+ }
+#if SHOPT_DYNAMIC
+ if(arg)
+ {
+#ifdef SH_PLUGIN_VERSION
+ if(!(library = dllplugin(SH_ID, arg, NiL, SH_PLUGIN_VERSION, &ver, RTLD_LAZY, path, sizeof(path))))
+ {
+ errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dllerror(0));
+ return(1);
+ }
+ if(list)
+ sfprintf(sfstdout, "%s %08lu %s\n", arg, ver, path);
+#else
+#if (_AST_VERSION>=20040404)
+ if(!(library = dllplug(SH_ID,arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
+#else
+ if(!(library = dllfind(arg,NIL(char*),RTLD_LAZY,NIL(char*),0)))
+#endif
+ {
+ errormsg(SH_DICT,ERROR_exit(0),"%s: %s",arg,dlerror());
+ return(1);
+ }
+#endif
+ sh_addlib(tdata.sh,library);
+ }
+ else
+#endif /* SHOPT_DYNAMIC */
+ if(*argv==0 && !dlete)
+ {
+ print_scan(sfstdout, flag, tdata.sh->bltin_tree, 1, &tdata);
+ return(0);
+ }
+ r = 0;
+ flag = stktell(stkp);
+ while(arg = *argv)
+ {
+ name = path_basename(arg);
+ sfwrite(stkp,"b_",2);
+ sfputr(stkp,name,0);
+ errmsg = 0;
+ addr = 0;
+ for(n=(nlib?nlib:dlete); --n>=0;)
+ {
+ /* (char*) added for some sgi-mips compilers */
+#if SHOPT_DYNAMIC
+ if(dlete || (addr = (Shbltin_f)dlllook(liblist[n],stkptr(stkp,flag))))
+#else
+ if(dlete)
+#endif /* SHOPT_DYNAMIC */
+ {
+ if(np = sh_addbuiltin(arg, addr,pointerof(dlete)))
+ {
+ if(dlete || nv_isattr(np,BLT_SPC))
+ errmsg = "restricted name";
+ else
+ nv_onattr(np,libattr[n]);
+ }
+ break;
+ }
+ }
+ if(!dlete && !addr)
+ {
+ np = sh_addbuiltin(arg, 0 ,0);
+ if(np && nv_isattr(np,BLT_SPC))
+ errmsg = "restricted name";
+ else if(!np)
+ errmsg = "not found";
+ }
+ if(errmsg)
+ {
+ errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,errmsg);
+ r = 1;
+ }
+ stkseek(stkp,flag);
+ argv++;
+ }
+ return(r);
+}
+
+int b_set(int argc,register char *argv[],Shbltin_t *context)
+{
+ struct tdata tdata;
+ int was_monitor = sh_isoption(SH_MONITOR);
+ memset(&tdata,0,sizeof(tdata));
+ tdata.sh = context->shp;
+ tdata.prefix=0;
+ if(argv[1])
+ {
+ if(sh_argopts(argc,argv,tdata.sh) < 0)
+ return(2);
+ if(sh_isoption(SH_VERBOSE))
+ sh_onstate(SH_VERBOSE);
+ else
+ sh_offstate(SH_VERBOSE);
+ if(sh_isoption(SH_MONITOR) && !was_monitor)
+ sh_onstate(SH_MONITOR);
+ else if(!sh_isoption(SH_MONITOR) && was_monitor)
+ sh_offstate(SH_MONITOR);
+ }
+ else
+ /*scan name chain and print*/
+ print_scan(sfstdout,0,tdata.sh->var_tree,0,&tdata);
+ return(0);
+}
+
+/*
+ * The removing of Shell variable names, aliases, and functions
+ * is performed here.
+ * Unset functions with unset -f
+ * Non-existent items being deleted give non-zero exit status
+ */
+
+int b_unalias(int argc,register char *argv[],Shbltin_t *context)
+{
+ Shell_t *shp = context->shp;
+ return(unall(argc,argv,shp->alias_tree,shp));
+}
+
+int b_unset(int argc,register char *argv[],Shbltin_t *context)
+{
+ Shell_t *shp = context->shp;
+ return(unall(argc,argv,shp->var_tree,shp));
+}
+
+static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp)
+{
+ register Namval_t *np;
+ register const char *name;
+ register int r;
+ Dt_t *dp;
+ int nflag=0,all=0,isfun,jmpval;
+ struct checkpt buff;
+ NOT_USED(argc);
+ if(troot==shp->alias_tree)
+ {
+ name = sh_optunalias;
+ if(shp->subshell)
+ troot = sh_subaliastree(0);
+ }
+ else
+ name = sh_optunset;
+ while(r = optget(argv,name)) switch(r)
+ {
+ case 'f':
+ troot = sh_subfuntree(1);
+ break;
+ case 'a':
+ all=1;
+ break;
+ case 'n':
+ nflag = NV_NOREF;
+ case 'v':
+ troot = shp->var_tree;
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
+ return(2);
+ }
+ argv += opt_info.index;
+ if(error_info.errors || (*argv==0 &&!all))
+ errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
+ if(!troot)
+ return(1);
+ r = 0;
+ if(troot==shp->var_tree)
+ nflag |= NV_VARNAME;
+ else
+ nflag = NV_NOSCOPE;
+ if(all)
+ {
+ dtclear(troot);
+ return(r);
+ }
+ sh_pushcontext(shp,&buff,1);
+ while(name = *argv++)
+ {
+ jmpval = sigsetjmp(buff.buff,0);
+ np = 0;
+ if(jmpval==0)
+ {
+#if SHOPT_NAMESPACE
+ if(shp->namespace && troot!=shp->var_tree)
+ np = sh_fsearch(shp,name,nflag?HASH_NOSCOPE:0);
+ if(!np)
+#endif /* SHOPT_NAMESPACE */
+ np=nv_open(name,troot,NV_NOADD|nflag);
+ }
+ else
+ {
+ r = 1;
+ continue;
+ }
+ if(np)
+ {
+ if(is_abuiltin(np) || nv_isattr(np,NV_RDONLY))
+ {
+ if(nv_isattr(np,NV_RDONLY))
+ errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
+ r = 1;
+ continue;
+ }
+ isfun = is_afunction(np);
+ if(troot==shp->var_tree)
+ {
+ Namarr_t *ap;
+#if SHOPT_FIXEDARRAY
+ if((ap=nv_arrayptr(np)) && !ap->fixed && name[strlen(name)-1]==']' && !nv_getsub(np))
+#else
+ if(nv_isarray(np) && name[strlen(name)-1]==']' && !nv_getsub(np))
+#endif /* SHOPT_FIXEDARRAY */
+ {
+ r=1;
+ continue;
+ }
+
+ if(shp->subshell)
+ np=sh_assignok(np,0);
+ }
+ if(!nv_isnull(np))
+ _nv_unset(np,0);
+ if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict)
+ nv_delete(np,dp,NV_NOFREE);
+ else if(isfun)
+ nv_delete(np,troot,NV_NOFREE);
+#if 0
+ /* causes unsetting local variable to expose global */
+ else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE))
+ nv_delete(np,shp->var_tree,0);
+#endif
+ else
+ nv_close(np);
+
+ }
+ else if(troot==shp->alias_tree)
+ r = 1;
+ }
+ sh_popcontext(shp,&buff);
+ return(r);
+}
+
+/*
+ * print out the name and value of a name-value pair <np>
+ */
+
+static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, struct tdata *tp)
+{
+ register char *cp;
+ int indent=tp->indent, outname=0, isfun;
+ sh_sigcheck(tp->sh);
+ if(flag)
+ flag = '\n';
+ if(tp->noref && nv_isref(np))
+ return(0);
+ if(nv_istable(np))
+ {
+ print_value(file,np,tp);
+ return(0);
+ }
+ if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
+ {
+ if(is_abuiltin(np))
+ sfputr(file,nv_name(np),'\n');
+ return(0);
+ }
+ isfun = is_afunction(np);
+ if(tp->prefix)
+ {
+ outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT)));
+ if(indent && (isfun || outname || *tp->prefix!='t'))
+ {
+ sfnputc(file,'\t',indent);
+ indent = 0;
+ }
+ if(!isfun)
+ {
+ if(*tp->prefix=='t')
+ nv_attribute(np,tp->outfile,tp->prefix,tp->aflag);
+ else
+ sfputr(file,tp->prefix,' ');
+ }
+ }
+ if(isfun)
+ {
+ Sfio_t *iop=0;
+ char *fname=0;
+ if(nv_isattr(np,NV_NOFREE))
+ return(0);
+ if(!flag && !np->nvalue.ip)
+ sfputr(file,"typeset -fu",' ');
+ else if(!flag && !nv_isattr(np,NV_FPOSIX))
+ sfputr(file,"function",' ');
+ cp = nv_name(np);
+ if(tp->wctname)
+ cp += strlen(tp->wctname)+1;
+ sfputr(file,cp,-1);
+ if(nv_isattr(np,NV_FPOSIX))
+ sfwrite(file,"()",2);
+ if(np->nvalue.ip && np->nvalue.rp->hoffset>=0)
+ fname = np->nvalue.rp->fname;
+ else
+ flag = '\n';
+ if(flag)
+ {
+ if(tp->pflag && np->nvalue.ip && np->nvalue.rp->hoffset>=0)
+ sfprintf(file," #line %d %s\n",np->nvalue.rp->lineno,fname?sh_fmtq(fname):"");
+ else
+ sfputc(file, '\n');
+ }
+ else
+ {
+ if(nv_isattr(np,NV_FTMP))
+ {
+ fname = 0;
+ iop = tp->sh->heredocs;
+ }
+ else if(fname)
+ iop = sfopen(iop,fname,"r");
+ else if(tp->sh->gd->hist_ptr)
+ iop = (tp->sh->gd->hist_ptr)->histfp;
+ if(iop && sfseek(iop,(Sfoff_t)np->nvalue.rp->hoffset,SEEK_SET)>=0)
+ sfmove(iop,file, nv_size(np), -1);
+ else
+ flag = '\n';
+ if(fname)
+ sfclose(iop);
+ }
+ return(nv_size(np)+1);
+ }
+ if(nv_arrayptr(np))
+ {
+ if(indent)
+ sfnputc(file,'\t',indent);
+ print_value(file,np,tp);
+ return(0);
+ }
+ if(nv_isvtree(np))
+ nv_onattr(np,NV_EXPORT);
+ if(cp=nv_getval(np))
+ {
+ if(indent)
+ sfnputc(file,'\t',indent);
+ sfputr(file,nv_name(np),-1);
+ if(!flag)
+ flag = '=';
+ sfputc(file,flag);
+ if(flag != '\n')
+ {
+ if(nv_isref(np) && nv_refsub(np))
+ {
+ sfputr(file,sh_fmtq(cp),-1);
+ sfprintf(file,"[%s]\n", sh_fmtq(nv_refsub(np)));
+ }
+ else
+#if SHOPT_TYPEDEF
+ sfputr(file,nv_isvtree(np)?cp:sh_fmtq(cp),'\n');
+#else
+ sfputr(file,sh_fmtq(cp),'\n');
+#endif /* SHOPT_TYPEDEF */
+ }
+ return(1);
+ }
+ else if(outname || (tp->scanmask && tp->scanroot==tp->sh->var_tree))
+ sfputr(file,nv_name(np),'\n');
+ return(0);
+}
+
+/*
+ * print attributes at all nodes
+ */
+static void print_all(Sfio_t *file,Dt_t *root, struct tdata *tp)
+{
+ tp->outfile = file;
+ nv_scan(root, print_attribute, (void*)tp, 0, 0);
+}
+
+/*
+ * print the attributes of name value pair give by <np>
+ */
+static void print_attribute(register Namval_t *np,void *data)
+{
+ register struct tdata *dp = (struct tdata*)data;
+ nv_attribute(np,dp->outfile,dp->prefix,dp->aflag);
+}
+
+/*
+ * print the nodes in tree <root> which have attributes <flag> set
+ * of <option> is non-zero, no subscript or value is printed.
+ */
+
+static void print_scan(Sfio_t *file, int flag, Dt_t *root, int option,struct tdata *tp)
+{
+ register char **argv;
+ register Namval_t *np;
+ register int namec;
+ Namval_t *onp = 0;
+ char *name=0;
+ int len;
+ tp->sh->last_table=0;
+ flag &= ~NV_ASSIGN;
+ tp->scanmask = flag&~NV_NOSCOPE;
+ tp->scanroot = root;
+ tp->outfile = file;
+#if SHOPT_TYPEDEF
+ if(!tp->prefix && tp->tp)
+ tp->prefix = nv_name(tp->tp);
+#endif /* SHOPT_TYPEDEF */
+ if(flag&NV_INTEGER)
+ tp->scanmask |= (NV_DOUBLE|NV_EXPNOTE);
+ if(flag==NV_LTOU || flag==NV_UTOL)
+ tp->scanmask |= NV_UTOL|NV_LTOU;
+ namec = nv_scan(root,nullscan,(void*)tp,tp->scanmask,flag);
+ argv = tp->argnam = (char**)stkalloc(tp->sh->stk,(namec+1)*sizeof(char*));
+ namec = nv_scan(root, pushname, (void*)tp, tp->scanmask, flag&~NV_IARRAY);
+ if(mbcoll())
+ strsort(argv,namec,strcoll);
+ if(namec==0 && tp->sh->namespace && nv_dict(tp->sh->namespace)==root)
+ {
+ sfnputc(file,'\t',tp->indent);
+ sfwrite(file,":\n",2);
+ }
+ else while(namec--)
+ {
+ if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)))
+ {
+ onp = np;
+ if(name)
+ {
+ char *newname = nv_name(np);
+ if(memcmp(name,newname,len)==0 && newname[len]== '.')
+ continue;
+ name = 0;
+ }
+ if(flag&NV_ARRAY)
+ {
+ if(nv_aindex(np)>=0)
+ {
+ if(!(flag&NV_IARRAY))
+ continue;
+ }
+ else if((flag&NV_IARRAY))
+ continue;
+
+ }
+ tp->scanmask = flag&~NV_NOSCOPE;
+ tp->scanroot = root;
+ print_namval(file,np,option,tp);
+ if(nv_isvtree(np))
+ {
+ name = nv_name(np);
+ len = strlen(name);
+ }
+ }
+ }
+}
+
+/*
+ * add the name of the node to the argument list argnam
+ */
+
+static void pushname(Namval_t *np,void *data)
+{
+ struct tdata *tp = (struct tdata*)data;
+ *tp->argnam++ = nv_name(np);
+}
+