diff options
Diffstat (limited to 'usr/src/lib/libshell/common/sh/nvtree.c')
-rw-r--r-- | usr/src/lib/libshell/common/sh/nvtree.c | 679 |
1 files changed, 679 insertions, 0 deletions
diff --git a/usr/src/lib/libshell/common/sh/nvtree.c b/usr/src/lib/libshell/common/sh/nvtree.c new file mode 100644 index 0000000000..82657e3a0c --- /dev/null +++ b/usr/src/lib/libshell/common/sh/nvtree.c @@ -0,0 +1,679 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +/* + * code for tree nodes and name walking + * + * David Korn + * AT&T Labs + * + */ + +#include "defs.h" +#include "name.h" +#include "argnod.h" + +struct nvdir +{ + Dt_t *root; + Namval_t *hp; + Namval_t *table; + Namval_t *(*nextnode)(Namval_t*,Dt_t*,Namfun_t*); + Namfun_t *fun; + struct nvdir *prev; + int len; + int offset; + char data[1]; +}; + +char *nv_getvtree(Namval_t*, Namfun_t *); +static void put_tree(Namval_t*, const char*, int,Namfun_t*); + +static Namval_t *create_tree(Namval_t *np,const char *name,int flag,Namfun_t *dp) +{ + register Namfun_t *fp=dp; + 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 const Namdisc_t treedisc = +{ + 0, + put_tree, + nv_getvtree, + 0, + 0, + create_tree +}; + +static char *nextdot(const char *str) +{ + register char *cp; + if(*str=='.') + str++; + if(*str =='[') + { + cp = nv_endsubscript((Namval_t*)0,(char*)str,0); + return(*cp=='.'?cp:0); + } + else + return(strchr(str,'.')); +} + +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(const char *name) +{ + char *next,*last; + int c,len=strlen(name); + struct nvdir *save, *dp = new_of(struct nvdir,len); + Namval_t *np, fake; + Namfun_t *nfp; + if(!dp) + return(0); + memset((void*)dp, 0, sizeof(*dp)); + last=dp->data; + if(name[len-1]=='*' || name[len-1]=='@') + len -= 1; + name = memcpy(last,name,len); + last[len] = 0; + dp->len = len; + dp->root = sh.var_tree; + dp->table = sh.last_table; + if(*name) + { + fake.nvname = (char*)name; + dp->hp = (Namval_t*)dtprev(dp->root,&fake); + dp->hp = (Namval_t*)dtnext(dp->root,dp->hp); + } + else + dp->hp = (Namval_t*)dtfirst(dp->root); + while(next= nextdot(last)) + { + c = *next; + *next = 0; + np = nv_search(last,dp->root,0); + *next = c; + if(np && ((nfp=nextdisc(np)) || nv_istable(np))) + { + if(!(save = new_of(struct nvdir,0))) + return(0); + *save = *dp; + dp->prev = save; + if(nv_istable(np)) + dp->root = nv_dict(np); + else + dp->root = (Dt_t*)dp; + dp->offset = last-(char*)name; + if(dp->offset<len) + dp->len = len-dp->offset; + else + dp->len = 0; + if(nfp) + { + dp->nextnode = nfp->disc->nextf; + dp->table = np; + dp->fun = nfp; + dp->hp = (*dp->nextnode)(np,(Dt_t*)0,nfp); + } + else + dp->nextnode = 0; + } + else + break; + last = next+1; + } + 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 && memcmp(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; + while(1) + { + while(np=dp->hp) + { + dp->hp = nextnode(dp); + if(nv_isnull(np)) + continue; + last_table = sh.last_table; + sh.last_table = dp->table; + cp = nv_name(np); + sh.last_table = last_table; + if(!dp->len || memcmp(cp+dp->offset,dp->data,dp->len)==0) + { + if((nfp=nextdisc(np)) || nv_istable(np)) + { + Dt_t *root; + if(nv_istable(np)) + root = nv_dict(np); + else + root = (Dt_t*)dp; + /* check for recursive walk */ + for(save=dp; save; save=save->prev) + { + if(save->root==root) + break; + } + if(save) + continue; + if(!(save = new_of(struct nvdir,0))) + return(0); + *save = *dp; + dp->prev = save; + dp->root = root; + dp->len = 0; + if(nfp && np->nvfun) + { + dp->nextnode = nfp->disc->nextf; + 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; +#if 0 + sh.last_table = dp->table; +#endif + *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) + sfprintf(out,"%s %s ",type,tp->nvname); +} + +/* + * 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; + register unsigned mask; + register unsigned attr; + Namfun_t *fp=0; + for(fp=np->nvfun;fp;fp=fp->next) + { + if(fp->type || (fp->disc && fp->disc->typef &&(*fp->disc->typef)(np,fp))) + break; + } +#if 0 + if(!fp && !nv_isattr(np,~NV_ARRAY)) + { + if(!nv_isattr(np,NV_ARRAY) || nv_aindex(np)>=0) + return; + } +#else + if(!fp && !nv_isattr(np,~NV_MINIMAL)) + return; +#endif + + if ((attr=nv_isattr(np,~NV_NOFREE)) || fp) + { + if((attr&NV_NOPRINT)==NV_NOPRINT) + attr &= ~NV_NOPRINT; + if(!attr && !fp) + return; + if(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_INTEGER|NV_DOUBLE) && (attr&NV_EXPNOTE)) + 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); + if(array_assoc(ap)) + { + if(tp->sh_name[1]!='A') + continue; + } + else if(tp->sh_name[1]=='A') + continue; +#if 0 + cp = "associative"; + else + cp = "indexed"; + if(!prefix) + sfputr(out,cp,' '); + else if(*cp=='i') + tp++; +#endif + } + if(prefix) + { + if(*tp->sh_name=='-') + sfprintf(out,"%.2s ",tp->sh_name); + } + 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_INTEGER && nv_isattr(np,NV_INTEGER)) + { + if(nv_size(np) != 10) + { + if(nv_isattr(np, 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; + sfputr(out,nv_name(np),'\n'); + } +} + +struct Walk +{ + Sfio_t *out; + Dt_t *root; + int noscope; + int indent; +}; + +static void outval(char *name, const char *vname, struct Walk *wp) +{ + register Namval_t *np, *nq; + register Namfun_t *fp; + int isarray=0, associative=0, special=0; + if(!(np=nv_open(vname,wp->root,NV_ARRAY|NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope))) + return; + if(nv_isarray(np) && *name=='.') + special = 1; + if(!special && (fp=nv_hasdisc(np,&treedisc))) + { + if(!wp->out) + { + fp = nv_stack(np,fp); + if(fp = nv_stack(np,NIL(Namfun_t*))) + free((void*)fp); + np->nvfun = 0; + } + return; + } + if(nv_isnull(np)) + return; + if(special || nv_isarray(np)) + { + isarray=1; + associative= nv_aindex(np)<0; + 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); + nv_close(np); + return; + } + if(isarray==1 && !nq) + return; + if(special) + { + associative = 1; + sfnputc(wp->out,'\t',wp->indent); + } + else + { + sfnputc(wp->out,'\t',wp->indent); + nv_attribute(np,wp->out,"typeset",'='); + nv_outname(wp->out,name,-1); + sfputc(wp->out,(isarray==2?'\n':'=')); + if(isarray) + { + if(isarray==2) + return; + sfwrite(wp->out,"(\n",2); + sfnputc(wp->out,'\t',++wp->indent); + } + } + while(1) + { + char *fmtq,*ep; + if(isarray && associative) + { + if(!(fmtq = nv_getsub(np))) + break; + sfprintf(wp->out,"[%s]",sh_fmtq(fmtq)); + sfputc(wp->out,'='); + } + if(!(fmtq = sh_fmtq(nv_getval(np)))) + fmtq = ""; + else if(!associative && (ep=strchr(fmtq,'='))) + { + char *qp = strchr(fmtq,'\''); + if(!qp || qp>ep) + { + sfwrite(wp->out,fmtq,ep-fmtq); + sfputc(wp->out,'\\'); + fmtq = ep; + } + } + if(*name=='[' && !isarray) + sfprintf(wp->out,"(%s)\n",fmtq); + else + sfputr(wp->out,fmtq,'\n'); + if(!nv_nextsub(np)) + break; + sfnputc(wp->out,'\t',wp->indent); + } + if(isarray && !special) + { + sfnputc(wp->out,'\t',--wp->indent); + sfwrite(wp->out,")\n",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 int m,r; + register Sfio_t *outfile = wp->out; + if(n==0) + m = strlen(prefix); + else if(cp=nextdot(prefix)) + m = cp-prefix; + else + m = strlen(prefix)-1; + m++; + if(outfile) + { + sfwrite(outfile,"(\n",2); + wp->indent++; + } + 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(nextcp=nextdot(cp)) + { + if(outfile) + { + sfnputc(outfile,'\t',wp->indent); + nv_outname(outfile,cp,nextcp-cp); + sfputc(outfile,'='); + } + argv = genvalue(argv,cp,n+m+r,wp); + if(outfile) + sfputc(outfile,'\n'); + if(*argv) + continue; + break; + } + else if(outfile && argv[1] && memcmp(arg,argv[1],r=strlen(arg))==0 && argv[1][r]=='[') + { + Namval_t *np = nv_open(arg,wp->root,NV_VARNAME|NV_NOADD|NV_NOASSIGN|wp->noscope); + if(!np) + continue; + sfnputc(outfile,'\t',wp->indent); + nv_attribute(np,outfile,"typeset",1); + nv_close(np); + sfputr(outfile,arg+m+(n?n+1:0),'='); + argv = genvalue(++argv,cp,cp-arg ,wp); + sfputc(outfile,'\n'); + } + else if(outfile && *cp=='[') + { + sfnputc(outfile,'\t',wp->indent); + sfputr(outfile,cp,'='); + argv = genvalue(++argv,cp,cp-arg ,wp); + sfputc(outfile,'\n'); + } + else + outval(cp,arg,wp); + } + else + break; + } + 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; + sfnputc(outfile,'\t',wp->indent-1); + sfputc(outfile,')'); + } + return(--argv); +} + +/* + * walk the virtual tree and print or delete name-value pairs + */ +static char *walk_tree(register Namval_t *np, int dlete) +{ + static Sfio_t *out; + struct Walk walk; + Sfio_t *outfile; + int 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=(dlete&NV_NOSCOPE); + stakputs(nv_name(np)); + if(subscript = nv_getsub(np)) + { + stakputc('['); + stakputs(subscript); + stakputc(']'); + stakputc('.'); + } + name = stakfreeze(1); + dir = nv_diropen(name); + if(subscript) + name[strlen(name)-1] = 0; + while(cp = nv_dirnext(dir)) + { + stakseek(ARGVAL); + stakputs(cp); + ap = (struct argnod*)stakfreeze(1); + ap->argflag = ARG_RAW; + ap->argchn.ap = arglist; + n++; + arglist = ap; + } + argv = (char**)stakalloc((n+1)*sizeof(char*)); + argv += n; + *argv = 0; + for(; ap; ap=ap->argchn.ap) + *--argv = ap->argval; + nv_dirclose(dir); + if(dlete&1) + outfile = 0; + else if(!(outfile=out)) + outfile = out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING); + else + sfseek(outfile,0L,SEEK_SET); + walk.out = outfile; + walk.root = sh.last_root; + walk.indent = 0; + walk.noscope = noscope; + genvalue(argv,name,0,&walk); + stakset(savptr,savtop); + if(!outfile) + return((char*)0); + sfputc(out,0); + return((char*)out->_data); +} + +/* + * get discipline for compound initializations + */ +char *nv_getvtree(register Namval_t *np, Namfun_t *fp) +{ + NOT_USED(fp); + if(nv_isattr(np,NV_BINARY) && nv_isattr(np,NV_RAW)) + return(nv_getv(np,fp)); + if(nv_isattr(np,NV_ARRAY) && nv_arraychild(np,(Namval_t*)0,0)==np) + return(nv_getv(np,fp)); + return(walk_tree(np,0)); +} + +/* + * 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(!nv_isattr(np,NV_INTEGER)) + walk_tree(np,(flags&NV_NOSCOPE)|1); + nv_putv(np, val, flags,fp); + if(nv_isattr(np,NV_INTEGER)) + 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(nv_hasdisc(np, &treedisc)) + return; + nfp = newof(NIL(void*),Namfun_t,1,0); + nfp->disc = &treedisc; + nv_stack(np, nfp); +} + |