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/*
1N/A * code for tree nodes and name walking
1N/A *
1N/A * David Korn
1N/A * AT&T Labs
1N/A *
1N/A */
1N/A/*
1N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
1N/A */
1N/A
1N/A#include "defs.h"
1N/A#include "name.h"
1N/A#include "argnod.h"
1N/A#include "lexstates.h"
1N/A
1N/Astruct nvdir
1N/A{
1N/A Dt_t *root;
1N/A Namval_t *hp;
1N/A Namval_t *table;
1N/A Namval_t *otable;
1N/A Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*);
1N/A Namfun_t *fun;
1N/A struct nvdir *prev;
1N/A int len;
1N/A char *data;
1N/A};
1N/A
1N/Astatic int Indent;
1N/Achar *nv_getvtree(Namval_t*, Namfun_t *);
1N/Astatic void put_tree(Namval_t*, const char*, int,Namfun_t*);
1N/Astatic char *walk_tree(Namval_t*, Namval_t*, int);
1N/A
1N/Astatic int read_tree(Namval_t* np, Sfio_t *iop, int n, Namfun_t *dp)
1N/A{
1N/A Sfio_t *sp;
1N/A char *cp;
1N/A int c;
1N/A if(n>=0)
1N/A return(-1);
1N/A while((c = sfgetc(iop)) && isblank(c));
1N/A sfungetc(iop,c);
1N/A sfprintf(sh.strbuf,"%s=%c",nv_name(np),0);
1N/A cp = sfstruse(sh.strbuf);
1N/A sp = sfopen((Sfio_t*)0,cp,"s");
1N/A sfstack(iop,sp);
1N/A c=sh_eval(iop,SH_READEVAL);
1N/A return(c);
1N/A}
1N/A
1N/Astatic Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp)
1N/A{
1N/A register Namfun_t *fp=dp;
1N/A fp->dsize = 0;
1N/A while(fp=fp->next)
1N/A {
1N/A if(fp->disc && fp->disc->createf)
1N/A {
1N/A if(np=(*fp->disc->createf)(np,name,flag,fp))
1N/A dp->last = fp->last;
1N/A return(np);
1N/A }
1N/A }
1N/A return((flag&NV_NOADD)?0:np);
1N/A}
1N/A
1N/Astatic Namfun_t *clone_tree(Namval_t *np, Namval_t *mp, int flags, Namfun_t *fp){
1N/A Namfun_t *dp;
1N/A if ((flags&NV_MOVE) && nv_type(np))
1N/A return(fp);
1N/A dp = nv_clone_disc(fp,flags);
1N/A if((flags&NV_COMVAR) && !(flags&NV_RAW))
1N/A {
1N/A walk_tree(np,mp,flags);
1N/A if((flags&NV_MOVE) && !(fp->nofree&1))
1N/A free((void*)fp);
1N/A }
1N/A return(dp);
1N/A}
1N/A
1N/Astatic const Namdisc_t treedisc =
1N/A{
1N/A 0,
1N/A put_tree,
1N/A nv_getvtree,
1N/A 0,
1N/A 0,
1N/A create_tree,
1N/A clone_tree
1N/A ,0,0,0,
1N/A read_tree
1N/A};
1N/A
1N/Astatic char *nextdot(const char *str)
1N/A{
1N/A register char *cp;
1N/A register int c;
1N/A if(*str=='.')
1N/A str++;
1N/A for(cp=(char*)str;c= *cp; cp++)
1N/A {
1N/A if(c=='[')
1N/A {
1N/A cp = nv_endsubscript((Namval_t*)0,(char*)cp,0);
1N/A return(*cp=='.'?cp:0);
1N/A }
1N/A if(c=='.')
1N/A return(cp);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/Astatic Namfun_t *nextdisc(Namval_t *np)
1N/A{
1N/A register Namfun_t *fp;
1N/A if(nv_isref(np))
1N/A return(0);
1N/A for(fp=np->nvfun;fp;fp=fp->next)
1N/A {
1N/A if(fp && fp->disc && fp->disc->nextf)
1N/A return(fp);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/Avoid *nv_diropen(Namval_t *np,const char *name)
1N/A{
1N/A char *next,*last;
1N/A int c,len=strlen(name);
1N/A struct nvdir *save, *dp = new_of(struct nvdir,len+1);
1N/A Namval_t *nq=0,fake;
1N/A Namfun_t *nfp=0;
1N/A if(!dp)
1N/A return(0);
1N/A memset((void*)dp, 0, sizeof(*dp));
1N/A dp->data = (char*)(dp+1);
1N/A if(name[len-1]=='*' || name[len-1]=='@')
1N/A len -= 1;
1N/A name = memcpy(dp->data,name,len);
1N/A dp->data[len] = 0;
1N/A dp->len = len;
1N/A dp->root = sh.last_root?sh.last_root:sh.var_tree;
1N/A#if 1
1N/A while(1)
1N/A {
1N/A dp->table = sh.last_table;
1N/A sh.last_table = 0;
1N/A if(*(last=(char*)name)==0)
1N/A break;
1N/A if(!(next=nextdot(last)))
1N/A break;
1N/A *next = 0;
1N/A np = nv_open(name, dp->root, NV_NOFAIL);
1N/A *next = '.';
1N/A if(!np || !nv_istable(np))
1N/A break;
1N/A dp->root = nv_dict(np);
1N/A name = next+1;
1N/A }
1N/A#else
1N/A dp->table = sh.last_table;
1N/A sh.last_table = 0;
1N/A last = dp->data;
1N/A#endif
1N/A if(*name)
1N/A {
1N/A fake.nvname = (char*)name;
1N/A if(dp->hp = (Namval_t*)dtprev(dp->root,&fake))
1N/A {
1N/A char *cp = nv_name(dp->hp);
1N/A c = strlen(cp);
1N/A if(strncmp(name,cp,c) || name[c]!='[')
1N/A dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
1N/A else
1N/A {
1N/A np = dp->hp;
1N/A last = 0;
1N/A }
1N/A }
1N/A else
1N/A dp->hp = (Namval_t*)dtfirst(dp->root);
1N/A }
1N/A else
1N/A dp->hp = (Namval_t*)dtfirst(dp->root);
1N/A while(1)
1N/A {
1N/A if(!last)
1N/A next = 0;
1N/A else if(next= nextdot(last))
1N/A {
1N/A c = *next;
1N/A *next = 0;
1N/A }
1N/A if(!np)
1N/A {
1N/A if(nfp && nfp->disc && nfp->disc->createf)
1N/A {
1N/A np = (*nfp->disc->createf)(nq,last,0,nfp);
1N/A if(*nfp->last == '[')
1N/A {
1N/A nv_endsubscript(np,nfp->last,NV_NOADD);
1N/A if(nq = nv_opensub(np))
1N/A np = nq;
1N/A }
1N/A }
1N/A else
1N/A np = nv_search(last,dp->root,0);
1N/A }
1N/A if(next)
1N/A *next = c;
1N/A if(np==dp->hp && !next)
1N/A dp->hp = (Namval_t*)dtnext(dp->root,dp->hp);
1N/A if(np && ((nfp=nextdisc(np)) || nv_istable(np)))
1N/A {
1N/A if(!(save = new_of(struct nvdir,0)))
1N/A return(0);
1N/A *save = *dp;
1N/A dp->prev = save;
1N/A if(nv_istable(np))
1N/A dp->root = nv_dict(np);
1N/A else
1N/A dp->root = (Dt_t*)np;
1N/A if(nfp)
1N/A {
1N/A dp->nextnode = nfp->disc->nextf;
1N/A dp->table = np;
1N/A dp->otable = sh.last_table;
1N/A dp->fun = nfp;
1N/A dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
1N/A }
1N/A else
1N/A dp->nextnode = 0;
1N/A }
1N/A else
1N/A break;
1N/A if(!next || next[1]==0)
1N/A break;
1N/A last = next+1;
1N/A nq = np;
1N/A np = 0;
1N/A }
1N/A return((void*)dp);
1N/A}
1N/A
1N/A
1N/Astatic Namval_t *nextnode(struct nvdir *dp)
1N/A{
1N/A if(dp->nextnode)
1N/A return((*dp->nextnode)(dp->hp,dp->root,dp->fun));
1N/A if(dp->len && strncmp(dp->data, dp->hp->nvname, dp->len))
1N/A return(0);
1N/A return((Namval_t*)dtnext(dp->root,dp->hp));
1N/A}
1N/A
1N/Achar *nv_dirnext(void *dir)
1N/A{
1N/A register struct nvdir *save, *dp = (struct nvdir*)dir;
1N/A register Namval_t *np, *last_table;
1N/A register char *cp;
1N/A Namfun_t *nfp;
1N/A Namval_t *nq;
1N/A while(1)
1N/A {
1N/A while(np=dp->hp)
1N/A {
1N/A#if 0
1N/A char *sptr;
1N/A#endif
1N/A if(nv_isarray(np))
1N/A nv_putsub(np,(char*)0, ARRAY_UNDEF);
1N/A dp->hp = nextnode(dp);
1N/A if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER))
1N/A continue;
1N/A last_table = sh.last_table;
1N/A#if 0
1N/A if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
1N/A {
1N/A sptr = dp->table->nvenv;
1N/A dp->table->nvenv = (char*)dp->otable;
1N/A }
1N/A#endif
1N/A sh.last_table = dp->table;
1N/A cp = nv_name(np);
1N/A#if 0
1N/A if(dp->table && dp->otable && !nv_isattr(dp->table,NV_MINIMAL))
1N/A dp->table->nvenv = sptr;
1N/A#endif
1N/A if(dp->nextnode && !dp->hp && (nq = (Namval_t*)dp->table))
1N/A {
1N/A Namarr_t *ap = nv_arrayptr(nq);
1N/A if(ap && (ap->nelem&ARRAY_SCAN) && nv_nextsub(nq))
1N/A dp->hp = (*dp->nextnode)(np,(Dt_t*)0,dp->fun);
1N/A }
1N/A sh.last_table = last_table;
1N/A if(!dp->len || strncmp(cp,dp->data,dp->len)==0)
1N/A {
1N/A if((nfp=nextdisc(np)) && (nfp->disc->getval||nfp->disc->getnum) && nv_isvtree(np) && strcmp(cp,dp->data))
1N/A nfp = 0;
1N/A if(nfp || nv_istable(np))
1N/A {
1N/A Dt_t *root;
1N/A int len;
1N/A if(nv_istable(np))
1N/A root = nv_dict(np);
1N/A else
1N/A root = (Dt_t*)np;
1N/A /* check for recursive walk */
1N/A for(save=dp; save; save=save->prev)
1N/A {
1N/A if(save->root==root)
1N/A break;
1N/A }
1N/A if(save)
1N/A return(cp);
1N/A len = strlen(cp);
1N/A if(!(save = new_of(struct nvdir,len+1)))
1N/A return(0);
1N/A *save = *dp;
1N/A dp->prev = save;
1N/A dp->root = root;
1N/A dp->len = len-1;
1N/A dp->data = (char*)(save+1);
1N/A memcpy(dp->data,cp,len+1);
1N/A if(nfp && np->nvfun)
1N/A {
1N/A#if 0
1N/A Namarr_t *ap = nv_arrayptr(np);
1N/A if(ap && (ap->nelem&ARRAY_UNDEF))
1N/A nv_putsub(np,(char*)0,ARRAY_SCAN);
1N/A#endif
1N/A dp->nextnode = nfp->disc->nextf;
1N/A dp->otable = dp->table;
1N/A dp->table = np;
1N/A dp->fun = nfp;
1N/A dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp);
1N/A }
1N/A else
1N/A dp->nextnode = 0;
1N/A }
1N/A return(cp);
1N/A }
1N/A }
1N/A if(!(save=dp->prev))
1N/A break;
1N/A *dp = *save;
1N/A free((void*)save);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/Avoid nv_dirclose(void *dir)
1N/A{
1N/A struct nvdir *dp = (struct nvdir*)dir;
1N/A if(dp->prev)
1N/A nv_dirclose((void*)dp->prev);
1N/A free(dir);
1N/A}
1N/A
1N/Astatic void outtype(Namval_t *np, Namfun_t *fp, Sfio_t* out, const char *prefix)
1N/A{
1N/A char *type=0;
1N/A Namval_t *tp = fp->type;
1N/A if(!tp && fp->disc && fp->disc->typef)
1N/A tp = (*fp->disc->typef)(np,fp);
1N/A for(fp=fp->next;fp;fp=fp->next)
1N/A {
1N/A if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp)))
1N/A {
1N/A outtype(np,fp,out,prefix);
1N/A break;
1N/A }
1N/A }
1N/A if(prefix && *prefix=='t')
1N/A type = "-T";
1N/A else if(!prefix)
1N/A type = "type";
1N/A if(type)
1N/A {
1N/A char *cp=tp->nvname;
1N/A if(cp=strrchr(cp,'.'))
1N/A cp++;
1N/A else
1N/A cp = tp->nvname;
1N/A sfprintf(out,"%s %s ",type,cp);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * print the attributes of name value pair give by <np>
1N/A */
1N/Avoid nv_attribute(register Namval_t *np,Sfio_t *out,char *prefix,int noname)
1N/A{
1N/A register const Shtable_t *tp;
1N/A register char *cp;
1N/A register unsigned val,mask,attr;
1N/A char *ip=0;
1N/A Namfun_t *fp=0;
1N/A Namval_t *typep=0;
1N/A#if SHOPT_FIXEDARRAY
1N/A int fixed=0;
1N/A#endif /* SHOPT_FIXEDARRAY */
1N/A for(fp=np->nvfun;fp;fp=fp->next)
1N/A {
1N/A if((typep=fp->type) || (fp->disc && fp->disc->typef && (typep=(*fp->disc->typef)(np,fp))))
1N/A break;
1N/A }
1N/A if(!fp && !nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)))
1N/A {
1N/A if(prefix && *prefix)
1N/A {
1N/A if(nv_isvtree(np))
1N/A sfprintf(out,"%s -C ",prefix);
1N/A else if((!np->nvalue.cp||np->nvalue.cp==Empty) && nv_isattr(np,~NV_NOFREE)==NV_MINIMAL && strcmp(np->nvname,"_"))
1N/A sfputr(out,prefix,' ');
1N/A }
1N/A return;
1N/A }
1N/A
1N/A if ((attr=nv_isattr(np,~NV_NOFREE)) || fp)
1N/A {
1N/A if((attr&NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
1N/A attr &= ~NV_NOPRINT;
1N/A if(!attr && !fp)
1N/A return;
1N/A if(fp)
1N/A {
1N/A prefix = Empty;
1N/A attr &= NV_RDONLY|NV_ARRAY;
1N/A if(nv_isattr(np,NV_REF|NV_TAGGED)==(NV_REF|NV_TAGGED))
1N/A attr |= (NV_REF|NV_TAGGED);
1N/A if(typep)
1N/A {
1N/A char *cp = typep->nvname;
1N/A if(cp = strrchr(cp,'.'))
1N/A cp++;
1N/A else
1N/A cp = typep->nvname;
1N/A sfputr(out,cp,' ');
1N/A fp = 0;
1N/A }
1N/A }
1N/A else if(prefix && *prefix)
1N/A sfputr(out,prefix,' ');
1N/A for(tp = shtab_attributes; *tp->sh_name;tp++)
1N/A {
1N/A val = tp->sh_number;
1N/A mask = val;
1N/A if(fp && (val&NV_INTEGER))
1N/A break;
1N/A /*
1N/A * the following test is needed to prevent variables
1N/A * with E attribute from being given the F
1N/A * attribute as well
1N/A */
1N/A if(val==NV_DOUBLE && (attr&(NV_EXPNOTE|NV_HEXFLOAT)))
1N/A continue;
1N/A if(val&NV_INTEGER)
1N/A mask |= NV_DOUBLE;
1N/A else if(val&NV_HOST)
1N/A mask = NV_HOST;
1N/A if((attr&mask)==val)
1N/A {
1N/A if(val==NV_ARRAY)
1N/A {
1N/A Namarr_t *ap = nv_arrayptr(np);
1N/A char **xp=0;
1N/A if(ap && array_assoc(ap))
1N/A {
1N/A if(tp->sh_name[1]!='A')
1N/A continue;
1N/A }
1N/A else if(tp->sh_name[1]=='A')
1N/A continue;
1N/A if((ap && (ap->nelem&ARRAY_TREE)) || (!ap && nv_isattr(np,NV_NOFREE)))
1N/A {
1N/A if(prefix && *prefix)
1N/A sfwrite(out,"-C ",3);
1N/A }
1N/A#if SHOPT_FIXEDARRAY
1N/A if(ap && ap->fixed)
1N/A fixed++;
1N/A else
1N/A#endif /* SHOPT_FIXEDARRAY */
1N/A if(ap && !array_assoc(ap) && (xp=(char**)(ap+1)) && *xp)
1N/A ip = nv_namptr(*xp,0)->nvname;
1N/A }
1N/A if(val==NV_UTOL || val==NV_LTOU)
1N/A {
1N/A if((cp = (char*)nv_mapchar(np,0)) && strcmp(cp,tp->sh_name+2))
1N/A {
1N/A sfprintf(out,"-M %s ",cp);
1N/A continue;
1N/A }
1N/A }
1N/A if(prefix)
1N/A {
1N/A if(*tp->sh_name=='-')
1N/A sfprintf(out,"%.2s ",tp->sh_name);
1N/A if(ip)
1N/A {
1N/A sfprintf(out,"[%s] ",ip);
1N/A ip = 0;
1N/A }
1N/A }
1N/A else
1N/A sfputr(out,tp->sh_name+2,' ');
1N/A if ((val&(NV_LJUST|NV_RJUST|NV_ZFILL)) && !(val&NV_INTEGER) && val!=NV_HOST)
1N/A sfprintf(out,"%d ",nv_size(np));
1N/A if(val==(NV_REF|NV_TAGGED))
1N/A attr &= ~(NV_REF|NV_TAGGED);
1N/A }
1N/A if(val==NV_INTEGER && nv_isattr(np,NV_INTEGER))
1N/A {
1N/A if(nv_size(np) != 10)
1N/A {
1N/A if(nv_isattr(np, NV_DOUBLE)== NV_DOUBLE)
1N/A cp = "precision";
1N/A else
1N/A cp = "base";
1N/A if(!prefix)
1N/A sfputr(out,cp,' ');
1N/A sfprintf(out,"%d ",nv_size(np));
1N/A }
1N/A break;
1N/A }
1N/A }
1N/A#if SHOPT_FIXEDARRAY
1N/A if(fixed)
1N/A {
1N/A sfprintf(out,"%s",nv_name(np));
1N/A nv_arrfixed(np,out,0,(char*)0);
1N/A sfputc(out,';');
1N/A }
1N/A#endif /* SHOPT_FIXEDARRAY */
1N/A if(fp)
1N/A outtype(np,fp,out,prefix);
1N/A if(noname)
1N/A return;
1N/A sfputr(out,nv_name(np),'\n');
1N/A }
1N/A}
1N/A
1N/Astruct Walk
1N/A{
1N/A Sfio_t *out;
1N/A Dt_t *root;
1N/A int noscope;
1N/A int indent;
1N/A int nofollow;
1N/A int array;
1N/A int flags;
1N/A};
1N/A
1N/Avoid nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special)
1N/A{
1N/A char *fmtq,*ep,*xp;
1N/A Namval_t *mp;
1N/A Namarr_t *ap = nv_arrayptr(np);
1N/A int tabs=0,c,more,associative = 0;
1N/A int saveI = Indent;
1N/A Indent = indent;
1N/A if(ap)
1N/A {
1N/A if(!(ap->nelem&ARRAY_SCAN))
1N/A nv_putsub(np,NIL(char*),ARRAY_SCAN);
1N/A sfputc(out,'(');
1N/A if(indent>=0)
1N/A {
1N/A sfputc(out,'\n');
1N/A tabs=1;
1N/A }
1N/A if(!(associative =(array_assoc(ap)!=0)))
1N/A {
1N/A if(array_elem(ap) < nv_aimax(np)+1)
1N/A associative=1;
1N/A }
1N/A }
1N/A mp = nv_opensub(np);
1N/A while(1)
1N/A {
1N/A if(mp && special && nv_isvtree(mp))
1N/A {
1N/A if(!nv_nextsub(np))
1N/A break;
1N/A mp = nv_opensub(np);
1N/A continue;
1N/A }
1N/A if(tabs)
1N/A sfnputc(out,'\t',Indent = ++indent);
1N/A tabs=0;
1N/A if(associative||special)
1N/A {
1N/A if(!(fmtq = nv_getsub(np)))
1N/A break;
1N/A sfprintf(out,"[%s]",sh_fmtq(fmtq));
1N/A sfputc(out,'=');
1N/A }
1N/A if(mp && nv_isarray(mp))
1N/A {
1N/A nv_outnode(mp, out, indent+(indent>=0),0);
1N/A if(indent>0)
1N/A sfnputc(out,'\t',indent);
1N/A sfputc(out,')');
1N/A sfputc(out,indent>=0?'\n':' ');
1N/A more = nv_nextsub(np);
1N/A goto skip;
1N/A }
1N/A if(mp && nv_isvtree(mp))
1N/A {
1N/A if(indent<0)
1N/A nv_onattr(mp,NV_EXPORT);
1N/A nv_onattr(mp,NV_TABLE);
1N/A }
1N/A ep = nv_getval(mp?mp:np);
1N/A if(ep==Empty)
1N/A ep = 0;
1N/A xp = 0;
1N/A if(!ap && nv_isattr(np,NV_INTEGER|NV_LJUST)==NV_LJUST)
1N/A {
1N/A xp = ep+nv_size(np);
1N/A while(--xp>ep && *xp==' ');
1N/A if(xp>ep || *xp!=' ')
1N/A xp++;
1N/A if(xp < (ep+nv_size(np)))
1N/A *xp = 0;
1N/A else
1N/A xp = 0;
1N/A }
1N/A if(mp && nv_isvtree(mp))
1N/A fmtq = ep;
1N/A else if(!(fmtq = sh_fmtq(ep)))
1N/A fmtq = "";
1N/A else if(!associative && (ep=strchr(fmtq,'=')))
1N/A {
1N/A char *qp = strchr(fmtq,'\'');
1N/A if(!qp || qp>ep)
1N/A {
1N/A sfwrite(out,fmtq,ep-fmtq);
1N/A sfputc(out,'\\');
1N/A fmtq = ep;
1N/A }
1N/A }
1N/A more = nv_nextsub(np);
1N/A c = '\n';
1N/A if(indent<0)
1N/A {
1N/A c = indent < -1?-1:';';
1N/A if(ap)
1N/A c = more?' ':-1;
1N/A }
1N/A sfputr(out,fmtq,c);
1N/A if(xp)
1N/A *xp = ' ';
1N/A skip:
1N/A if(!more)
1N/A break;
1N/A mp = nv_opensub(np);
1N/A if(indent>0 && !(mp && special && nv_isvtree(mp)))
1N/A sfnputc(out,'\t',indent);
1N/A }
1N/A Indent = saveI;
1N/A}
1N/A
1N/Astatic void outval(char *name, const char *vname, struct Walk *wp)
1N/A{
1N/A register Namval_t *np, *nq;
1N/A register Namfun_t *fp;
1N/A int isarray=0, special=0,mode=0;
1N/A if(*name!='.' || vname[strlen(vname)-1]==']')
1N/A mode = NV_ARRAY;
1N/A if(!(np=nv_open(vname,wp->root,mode|NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope)))
1N/A return;
1N/A fp = nv_hasdisc(np,&treedisc);
1N/A if(*name=='.')
1N/A {
1N/A if(nv_isattr(np,NV_BINARY))
1N/A return;
1N/A if(fp && np->nvalue.cp && np->nvalue.cp!=Empty)
1N/A {
1N/A nv_local = 1;
1N/A fp = 0;
1N/A }
1N/A if(fp)
1N/A return;
1N/A if(nv_isarray(np))
1N/A return;
1N/A }
1N/A if(!special && fp && !nv_isarray(np))
1N/A {
1N/A Namfun_t *xp;
1N/A if(!wp->out)
1N/A {
1N/A fp = nv_stack(np,fp);
1N/A if(fp = nv_stack(np,NIL(Namfun_t*)))
1N/A free((void*)fp);
1N/A np->nvfun = 0;
1N/A return;
1N/A }
1N/A for(xp=fp->next; xp; xp = xp->next)
1N/A {
1N/A if(xp->disc && (xp->disc->getval || xp->disc->getnum))
1N/A break;
1N/A }
1N/A if(!xp)
1N/A return;
1N/A }
1N/A if(nv_isnull(np) && !nv_isarray(np) && !nv_isattr(np,NV_INTEGER))
1N/A return;
1N/A if(special || (nv_isarray(np) && nv_arrayptr(np)))
1N/A {
1N/A isarray=1;
1N/A if(array_elem(nv_arrayptr(np))==0)
1N/A isarray=2;
1N/A else
1N/A nq = nv_putsub(np,NIL(char*),ARRAY_SCAN|(wp->out?ARRAY_NOCHILD:0));
1N/A }
1N/A if(!wp->out)
1N/A {
1N/A _nv_unset(np,NV_RDONLY);
1N/A nv_close(np);
1N/A#if 0
1N/A if(sh.subshell==0 && !(wp->flags&NV_RDONLY) && !nv_isattr(np,NV_MINIMAL|NV_NOFREE))
1N/A nv_delete(np,wp->root,0);
1N/A#endif
1N/A return;
1N/A }
1N/A if(isarray==1 && !nq)
1N/A {
1N/A sfputc(wp->out,'(');
1N/A if(wp->indent>=0)
1N/A sfputc(wp->out,'\n');
1N/A return;
1N/A }
1N/A if(isarray==0 && nv_isarray(np) && (nv_isnull(np)||np->nvalue.cp==Empty)) /* empty array */
1N/A isarray = 2;
1N/A special |= wp->nofollow;
1N/A if(!wp->array && wp->indent>0)
1N/A sfnputc(wp->out,'\t',wp->indent);
1N/A if(!special)
1N/A {
1N/A if(*name!='.')
1N/A nv_attribute(np,wp->out,"typeset",'=');
1N/A nv_outname(wp->out,name,-1);
1N/A if((np->nvalue.cp && np->nvalue.cp!=Empty) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np))
1N/A sfputc(wp->out,(isarray==2?(wp->indent>=0?'\n':';'):'='));
1N/A if(isarray==2)
1N/A return;
1N/A }
1N/A fp = np->nvfun;
1N/A if(*name=='.' && !isarray)
1N/A np->nvfun = 0;
1N/A nv_outnode(np, wp->out, wp->indent, special);
1N/A if(*name=='.' && !isarray)
1N/A np->nvfun = fp;
1N/A if(isarray && !special)
1N/A {
1N/A if(wp->indent>0)
1N/A {
1N/A sfnputc(wp->out,'\t',wp->indent);
1N/A sfwrite(wp->out,")\n",2);
1N/A }
1N/A else
1N/A sfwrite(wp->out,");",2);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * format initialization list given a list of assignments <argp>
1N/A */
1N/Astatic char **genvalue(char **argv, const char *prefix, int n, struct Walk *wp)
1N/A{
1N/A register char *cp,*nextcp,*arg;
1N/A register Sfio_t *outfile = wp->out;
1N/A register int m,r,l;
1N/A if(n==0)
1N/A m = strlen(prefix);
1N/A else if(cp=nextdot(prefix))
1N/A m = cp-prefix;
1N/A else
1N/A m = strlen(prefix)-1;
1N/A m++;
1N/A if(outfile && !wp->array)
1N/A {
1N/A sfputc(outfile,'(');
1N/A if(wp->indent>=0)
1N/A {
1N/A wp->indent++;
1N/A sfputc(outfile,'\n');
1N/A }
1N/A }
1N/A for(; arg= *argv; argv++)
1N/A {
1N/A cp = arg + n;
1N/A if(n==0 && cp[m-1]!='.')
1N/A continue;
1N/A if(n && cp[m-1]==0)
1N/A break;
1N/A if(n==0 || strncmp(arg,prefix-n,m+n)==0)
1N/A {
1N/A cp +=m;
1N/A r = 0;
1N/A if(*cp=='.')
1N/A cp++,r++;
1N/A if(wp->indent < 0 && argv[1]==0)
1N/A wp->indent--;
1N/A if(nextcp=nextdot(cp))
1N/A {
1N/A if(outfile)
1N/A {
1N/A Namval_t *np,*tp;
1N/A *nextcp = 0;
1N/A np=nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL|wp->noscope);
1N/A if(!np || (nv_isarray(np) && (!(tp=nv_opensub(np)) || !nv_isvtree(tp))))
1N/A {
1N/A *nextcp = '.';
1N/A continue;
1N/A }
1N/A if(wp->indent>=0)
1N/A sfnputc(outfile,'\t',wp->indent);
1N/A if(*cp!='[' && (tp = nv_type(np)))
1N/A {
1N/A char *sp;
1N/A if(sp = strrchr(tp->nvname,'.'))
1N/A sp++;
1N/A else
1N/A sp = tp->nvname;
1N/A sfputr(outfile,sp,' ');
1N/A }
1N/A nv_outname(outfile,cp,nextcp-cp);
1N/A sfputc(outfile,'=');
1N/A *nextcp = '.';
1N/A }
1N/A else
1N/A {
1N/A outval(cp,arg,wp);
1N/A continue;
1N/A }
1N/A argv = genvalue(argv,cp,n+m+r,wp);
1N/A if(wp->indent>=0)
1N/A sfputc(outfile,'\n');
1N/A if(*argv)
1N/A continue;
1N/A break;
1N/A }
1N/A else if(outfile && !wp->nofollow && argv[1] && strncmp(arg,argv[1],l=strlen(arg))==0 && argv[1][l]=='[')
1N/A {
1N/A int k=1;
1N/A Namarr_t *ap=0;
1N/A Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope);
1N/A if(!np)
1N/A continue;
1N/A if((wp->array = nv_isarray(np)) && (ap=nv_arrayptr(np)))
1N/A k = array_elem(ap);
1N/A
1N/A if(wp->indent>0)
1N/A sfnputc(outfile,'\t',wp->indent);
1N/A nv_attribute(np,outfile,"typeset",1);
1N/A nv_close(np);
1N/A sfputr(outfile,arg+m+r+(n?n:0),(k?'=':'\n'));
1N/A if(!k)
1N/A {
1N/A wp->array=0;
1N/A continue;
1N/A }
1N/A wp->nofollow=1;
1N/A argv = genvalue(argv,cp,cp-arg ,wp);
1N/A sfputc(outfile,wp->indent<0?';':'\n');
1N/A }
1N/A else if(outfile && *cp=='[')
1N/A {
1N/A /* skip multi-dimensional arrays */
1N/A if(*nv_endsubscript((Namval_t*)0,cp,0)=='[')
1N/A continue;
1N/A if(wp->indent>0)
1N/A sfnputc(outfile,'\t',wp->indent);
1N/A if(cp[-1]=='.')
1N/A cp--;
1N/A sfputr(outfile,cp,'=');
1N/A if(*cp=='.')
1N/A cp++;
1N/A argv = genvalue(++argv,cp,cp-arg ,wp);
1N/A sfputc(outfile,wp->indent>0?'\n':';');
1N/A }
1N/A else
1N/A {
1N/A outval(cp,arg,wp);
1N/A if(wp->array)
1N/A {
1N/A if(wp->indent>=0)
1N/A wp->indent++;
1N/A else
1N/A sfputc(outfile,' ');
1N/A wp->array = 0;
1N/A }
1N/A }
1N/A }
1N/A else
1N/A break;
1N/A wp->nofollow = 0;
1N/A }
1N/A wp->array = 0;
1N/A if(outfile)
1N/A {
1N/A int c = prefix[m-1];
1N/A cp = (char*)prefix;
1N/A if(c=='.')
1N/A cp[m-1] = 0;
1N/A outval(".",prefix-n,wp);
1N/A if(c=='.')
1N/A cp[m-1] = c;
1N/A if(wp->indent>0)
1N/A sfnputc(outfile,'\t',--wp->indent);
1N/A sfputc(outfile,')');
1N/A }
1N/A return(--argv);
1N/A}
1N/A
1N/A/*
1N/A * walk the virtual tree and print or delete name-value pairs
1N/A */
1N/Astatic char *walk_tree(register Namval_t *np, Namval_t *xp, int flags)
1N/A{
1N/A static Sfio_t *out;
1N/A struct Walk walk;
1N/A Sfio_t *outfile;
1N/A Sfoff_t off = 0;
1N/A int len, savtop = staktell();
1N/A char *savptr = stakfreeze(0);
1N/A register struct argnod *ap=0;
1N/A struct argnod *arglist=0;
1N/A char *name,*cp, **argv;
1N/A char *subscript=0;
1N/A void *dir;
1N/A int n=0, noscope=(flags&NV_NOSCOPE);
1N/A Namarr_t *arp = nv_arrayptr(np);
1N/A Dt_t *save_tree = sh.var_tree;
1N/A Namval_t *mp=0;
1N/A Shell_t *shp = sh_getinterp();
1N/A char *xpname = xp?stakcopy(nv_name(xp)):0;
1N/A if(xp)
1N/A {
1N/A shp->last_root = shp->prev_root;
1N/A shp->last_table = shp->prev_table;
1N/A }
1N/A if(shp->last_table)
1N/A shp->last_root = nv_dict(shp->last_table);
1N/A if(shp->last_root)
1N/A shp->var_tree = shp->last_root;
1N/A stakputs(nv_name(np));
1N/A if(arp && !(arp->nelem&ARRAY_SCAN) && (subscript = nv_getsub(np)))
1N/A {
1N/A mp = nv_opensub(np);
1N/A stakputc('[');
1N/A stakputs(subscript);
1N/A stakputc(']');
1N/A stakputc('.');
1N/A }
1N/A else if(*stakptr(staktell()-1) == ']')
1N/A mp = np;
1N/A name = stakfreeze(1);
1N/A len = strlen(name);
1N/A shp->last_root = 0;
1N/A dir = nv_diropen(mp,name);
1N/A walk.root = shp->last_root?shp->last_root:shp->var_tree;
1N/A if(subscript)
1N/A name[strlen(name)-1] = 0;
1N/A while(cp = nv_dirnext(dir))
1N/A {
1N/A if(cp[len]!='.')
1N/A continue;
1N/A if(xp)
1N/A {
1N/A Dt_t *dp = shp->var_tree;
1N/A Namval_t *nq, *mq;
1N/A if(strlen(cp)<=len)
1N/A continue;
1N/A nq = nv_open(cp,walk.root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_NOFAIL);
1N/A if(!nq && (flags&NV_MOVE))
1N/A nq = nv_search(cp,walk.root,NV_NOADD);
1N/A stakseek(0);
1N/A stakputs(xpname);
1N/A stakputs(cp+len);
1N/A stakputc(0);
1N/A shp->var_tree = save_tree;
1N/A mq = nv_open(stakptr(0),save_tree,NV_VARNAME|NV_NOASSIGN|NV_NOFAIL);
1N/A shp->var_tree = dp;
1N/A if(nq && mq)
1N/A {
1N/A nv_clone(nq,mq,flags|NV_RAW);
1N/A if(flags&NV_MOVE)
1N/A nv_delete(nq,walk.root,0);
1N/A }
1N/A continue;
1N/A }
1N/A stakseek(ARGVAL);
1N/A stakputs(cp);
1N/A ap = (struct argnod*)stakfreeze(1);
1N/A ap->argflag = ARG_RAW;
1N/A ap->argchn.ap = arglist;
1N/A n++;
1N/A arglist = ap;
1N/A }
1N/A nv_dirclose(dir);
1N/A if(xp)
1N/A {
1N/A shp->var_tree = save_tree;
1N/A return((char*)0);
1N/A }
1N/A argv = (char**)stakalloc((n+1)*sizeof(char*));
1N/A argv += n;
1N/A *argv = 0;
1N/A for(; ap; ap=ap->argchn.ap)
1N/A *--argv = ap->argval;
1N/A if(flags&1)
1N/A outfile = 0;
1N/A else if(!(outfile=out))
1N/A outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
1N/A else if(flags&NV_TABLE)
1N/A off = sftell(outfile);
1N/A else
1N/A sfseek(outfile,0L,SEEK_SET);
1N/A walk.out = outfile;
1N/A walk.indent = (flags&NV_EXPORT)?-1:Indent;
1N/A walk.nofollow = 0;
1N/A walk.noscope = noscope;
1N/A walk.array = 0;
1N/A walk.flags = flags;
1N/A genvalue(argv,name,0,&walk);
1N/A stakset(savptr,savtop);
1N/A shp->var_tree = save_tree;
1N/A if(!outfile)
1N/A return((char*)0);
1N/A sfputc(out,0);
1N/A sfseek(out,off,SEEK_SET);
1N/A return((char*)out->_data+off);
1N/A}
1N/A
1N/ANamfun_t *nv_isvtree(Namval_t *np)
1N/A{
1N/A if(np)
1N/A return(nv_hasdisc(np,&treedisc));
1N/A return(0);
1N/A}
1N/A
1N/A/*
1N/A * get discipline for compound initializations
1N/A */
1N/Achar *nv_getvtree(register Namval_t *np, Namfun_t *fp)
1N/A{
1N/A int flags=0, dsize=fp->dsize;
1N/A for(; fp && fp->next; fp=fp->next)
1N/A {
1N/A if(fp->next->disc && (fp->next->disc->getnum || fp->next->disc->getval))
1N/A return(nv_getv(np,fp));
1N/A }
1N/A if(nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
1N/A return(nv_getv(np,fp));
1N/A if(nv_isattr(np,NV_ARRAY) && !nv_type(np) && nv_arraychild(np,(Namval_t*)0,0)==np)
1N/A return(nv_getv(np,fp));
1N/A if(flags = nv_isattr(np,NV_EXPORT))
1N/A nv_offattr(np,NV_EXPORT);
1N/A if(flags |= nv_isattr(np,NV_TABLE))
1N/A nv_offattr(np,NV_TABLE);
1N/A if(dsize && (flags&NV_EXPORT))
1N/A return("()");
1N/A return(walk_tree(np,(Namval_t*)0,flags));
1N/A}
1N/A
1N/A/*
1N/A * put discipline for compound initializations
1N/A */
1N/Astatic void put_tree(register Namval_t *np, const char *val, int flags,Namfun_t *fp)
1N/A{
1N/A struct Namarray *ap;
1N/A int nleft = 0;
1N/A if(!val && !fp->next && nv_isattr(np,NV_NOFREE))
1N/A return;
1N/A if(!nv_isattr(np,(NV_INTEGER|NV_BINARY)))
1N/A {
1N/A Shell_t *shp = sh_getinterp();
1N/A Namval_t *last_table = shp->last_table;
1N/A Dt_t *last_root = shp->last_root;
1N/A Namval_t *mp = val?nv_open(val,shp->var_tree,NV_VARNAME|NV_NOADD|NV_NOASSIGN|NV_ARRAY|NV_NOFAIL):0;
1N/A if(mp && nv_isvtree(mp))
1N/A {
1N/A shp->prev_table = shp->last_table;
1N/A shp->prev_root = shp->last_root;
1N/A shp->last_table = last_table;
1N/A shp->last_root = last_root;
1N/A if(!(flags&NV_APPEND))
1N/A walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1N/A nv_clone(mp,np,NV_COMVAR);
1N/A return;
1N/A }
1N/A walk_tree(np,(Namval_t*)0,(flags&NV_NOSCOPE)|1);
1N/A }
1N/A nv_putv(np, val, flags,fp);
1N/A if(val && nv_isattr(np,(NV_INTEGER|NV_BINARY)))
1N/A return;
1N/A if(ap= nv_arrayptr(np))
1N/A nleft = array_elem(ap);
1N/A if(nleft==0)
1N/A {
1N/A fp = nv_stack(np,fp);
1N/A if(fp = nv_stack(np,NIL(Namfun_t*)))
1N/A free((void*)fp);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * Insert discipline to cause $x to print current tree
1N/A */
1N/Avoid nv_setvtree(register Namval_t *np)
1N/A{
1N/A register Namfun_t *nfp;
1N/A if(sh.subshell)
1N/A sh_assignok(np,1);
1N/A if(nv_hasdisc(np, &treedisc))
1N/A return;
1N/A nfp = newof(NIL(void*),Namfun_t,1,0);
1N/A nfp->disc = &treedisc;
1N/A nfp->dsize = sizeof(Namfun_t);
1N/A nv_stack(np, nfp);
1N/A}
1N/A