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