1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/cmd/ksh93/sh/nvtree.c
Martijn Dekker 172becffea Some more accumulated minor tweaks and cleanups
Notable changes:

src/cmd/ksh93/include/fault.h:
- Get rid of the superflous sh pointer argument in the
  sh_pushcontext() and sh_popcontext() macros. (re: 2d3ec8b6)

src/cmd/ksh93/tests/io.sh:
- Tweak a process substitution test to allow up to a second for
  unused process substitution processes to disappear. On the Alpine
  Linux console (at least the musl libc version), this is needed to
  avoid a test failure as long as no GUI is active. As soon as you
  start X11, this phenomenon disappears, even on the console. Very
  strange, but also very probably not ksh's fault.

src/cmd/ksh93/tests/shtests:
- Instead of just SIGCONT and SIGPIPE, set all signals to default,
  just to be sure to avoid spurious test failures due to signals
  that were ignored on entry. (It made no difference to the
  aforementioned Alpine Linux test failure, so ignored signals had
  nothing to do with that -- but still a good idea.)

.github/workflows/ci.yml:
- On the GitHub CI runs, when testing with SHOPTs disabled, disable
  SHOPT_SPAWN as well, which tests that everything still works
  correctly with the regular fork(2) method.

COPYRIGHT:
- Remove duplicate of BSD license.
2022-01-25 16:13:15 +00:00

1139 lines
24 KiB
C

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