sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / lib / libshell / common / sh / name.c
bloba8f6017c567b80b471f999b4caa1cf878509dc47
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
22 * AT&T Labs
26 #define putenv ___putenv
28 #include "defs.h"
29 #include "variables.h"
30 #include "path.h"
31 #include "lexstates.h"
32 #include "timeout.h"
33 #include "FEATURE/externs"
34 #include "streval.h"
36 #define NVCACHE 8 /* must be a power of 2 */
37 #define Empty ((char*)(e_sptbnl+3))
38 static char *savesub = 0;
40 #if !_lib_pathnative && _lib_uwin_path
42 #define _lib_pathnative 1
44 extern int uwin_path(const char*, char*, int);
46 size_t
47 pathnative(const char* path, char* buf, size_t siz)
49 return uwin_path(path, buf, siz);
52 #endif /* _lib_pathnative */
54 static void attstore(Namval_t*,void*);
55 #ifndef _ENV_H
56 static void pushnam(Namval_t*,void*);
57 static char *staknam(Namval_t*, char*);
58 #endif
59 static void ltou(char*);
60 static void utol(char*);
61 static void rightjust(char*, int, int);
62 static char *lastdot(char*, int);
64 struct adata
66 Shell_t *sh;
67 Namval_t *tp;
68 char **argnam;
69 int attsize;
70 char *attval;
73 #if SHOPT_TYPEDEF
74 struct sh_type
76 void *previous;
77 Namval_t **nodes;
78 Namval_t *rp;
79 short numnodes;
80 short maxnodes;
82 #endif /*SHOPT_TYPEDEF */
84 #if NVCACHE
85 struct Namcache
87 struct Cache_entry
89 Dt_t *root;
90 Dt_t *last_root;
91 char *name;
92 Namval_t *np;
93 Namval_t *last_table;
94 int flags;
95 short size;
96 short len;
97 } entries[NVCACHE];
98 short index;
99 short ok;
101 static struct Namcache nvcache;
102 #endif
104 char nv_local = 0;
105 #ifndef _ENV_H
106 static void(*nullscan)(Namval_t*,void*);
107 #endif
109 #if ( SFIO_VERSION <= 20010201L )
110 # define _data data
111 #endif
113 #if !SHOPT_MULTIBYTE
114 # define mbchar(p) (*(unsigned char*)p++)
115 #endif /* SHOPT_MULTIBYTE */
117 /* ======== name value pair routines ======== */
119 #include "shnodes.h"
120 #include "builtins.h"
122 static char *getbuf(size_t len)
124 static char *buf;
125 static size_t buflen;
126 if(buflen < len)
128 if(buflen==0)
129 buf = (char*)malloc(len);
130 else
131 buf = (char*)realloc(buf,len);
132 buflen = len;
134 return(buf);
137 #ifdef _ENV_H
138 void sh_envput(Env_t* ep,Namval_t *np)
140 int offset = staktell();
141 Namarr_t *ap = nv_arrayptr(np);
142 char *val;
143 if(ap)
145 if(ap->nelem&ARRAY_UNDEF)
146 nv_putsub(np,"0",0L);
147 else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
148 return;
150 if(!(val = nv_getval(np)))
151 return;
152 stakputs(nv_name(np));
153 stakputc('=');
154 stakputs(val);
155 stakseek(offset);
156 env_add(ep,stakptr(offset),ENV_STRDUP);
158 #endif
161 * output variable name in format for re-input
163 void nv_outname(Sfio_t *out, char *name, int len)
165 const char *cp=name, *sp;
166 int c, offset = staktell();
167 while(sp= strchr(cp,'['))
169 if(len>0 && cp+len <= sp)
170 break;
171 sfwrite(out,cp,++sp-cp);
172 stakseek(offset);
173 while(c= *sp++)
175 if(c==']')
176 break;
177 else if(c=='\\')
179 if(*sp=='[' || *sp==']' || *sp=='\\')
180 c = *sp++;
182 stakputc(c);
184 stakputc(0);
185 sfputr(out,sh_fmtq(stakptr(offset)),-1);
186 if(len>0)
188 sfputc(out,']');
189 return;
191 cp = sp-1;
193 if(*cp)
195 if(len>0)
196 sfwrite(out,cp,len);
197 else
198 sfputr(out,cp,-1);
200 stakseek(offset);
203 #if SHOPT_TYPEDEF
204 Namval_t *nv_addnode(Namval_t* np, int remove)
206 register struct sh_type *sp = (struct sh_type*)sh.mktype;
207 register int i;
208 register char *name=0;
209 if(sp->numnodes==0 && !nv_isnull(np) && sh.last_table)
211 /* could be an redefine */
212 Dt_t *root = nv_dict(sh.last_table);
213 sp->rp = np;
214 nv_delete(np,root,NV_NOFREE);
215 np = nv_search(sp->rp->nvname,root,NV_ADD);
217 if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
219 name = (sp->nodes[0])->nvname;
220 i = strlen(name);
221 if(memcmp(np->nvname,name,i))
222 return(np);
224 if(sp->rp && sp->numnodes)
226 /* check for a redefine */
227 if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0)
228 sp->rp = 0;
229 else
231 Dt_t *root = nv_dict(sh.last_table);
232 nv_delete(sp->nodes[0],root,NV_NOFREE);
233 dtinsert(root,sp->rp);
234 errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname);
237 for(i=0; i < sp->numnodes; i++)
239 if(np == sp->nodes[i])
241 if(remove)
243 while(++i < sp->numnodes)
244 sp->nodes[i-1] = sp->nodes[i];
245 sp->numnodes--;
247 return(np);
250 if(remove)
251 return(np);
252 if(sp->numnodes==sp->maxnodes)
254 sp->maxnodes += 20;
255 sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
257 sp->nodes[sp->numnodes++] = np;
258 return(np);
260 #endif /* SHOPT_TYPEDEF */
263 * given a list of assignments, determine <name> is on the list
264 returns a pointer to the argnod on the list or NULL
266 struct argnod *nv_onlist(struct argnod *arg, const char *name)
268 char *cp;
269 int len = strlen(name);
270 for(;arg; arg=arg->argnxt.ap)
272 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
273 cp = ((struct fornod*)arg->argchn.ap)->fornam;
274 else
275 cp = arg->argval;
276 if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='='))
277 return(arg);
279 return(0);
283 * Perform parameter assignment for a linked list of parameters
284 * <flags> contains attributes for the parameters
286 void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
288 Shell_t *shp = &sh;
289 register char *cp;
290 register Namval_t *np, *mp;
291 char *trap=shp->st.trap[SH_DEBUGTRAP];
292 char *prefix = shp->prefix;
293 int traceon = (sh_isoption(SH_XTRACE)!=0);
294 int array = (flags&(NV_ARRAY|NV_IARRAY));
295 Namarr_t *ap;
296 Namval_t node;
297 struct Namref nr;
298 #if SHOPT_TYPEDEF
299 int maketype = flags&NV_TYPE;
300 struct sh_type shtp;
301 if(maketype)
303 shtp.previous = shp->mktype;
304 shp->mktype=(void*)&shtp;
305 shtp.numnodes=0;
306 shtp.maxnodes = 20;
307 shtp.rp = 0;
308 shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*));
310 #endif /* SHOPT_TYPEDEF*/
311 flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY);
312 if(sh_isoption(SH_ALLEXPORT))
313 flags |= NV_EXPORT;
314 if(shp->prefix)
316 flags &= ~(NV_IDENT|NV_EXPORT);
317 flags |= NV_VARNAME;
319 for(;arg; arg=arg->argnxt.ap)
321 shp->used_pos = 0;
322 if(arg->argflag&ARG_MAC)
324 shp->prefix = 0;
325 cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
326 shp->prefix = prefix;
328 else
330 stakseek(0);
331 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
333 int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
334 int sub=0;
335 struct fornod *fp=(struct fornod*)arg->argchn.ap;
336 register Shnode_t *tp=fp->fortre;
337 flag |= (flags&(NV_NOSCOPE|NV_STATIC));
338 if(arg->argflag&ARG_QUOTED)
339 cp = sh_mactrim(shp,fp->fornam,-1);
340 else
341 cp = fp->fornam;
342 error_info.line = fp->fortyp-shp->st.firstline;
343 if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
344 array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;
345 if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
346 flag |= NV_NOSCOPE;
347 if(prefix && tp->com.comset && *cp=='[')
349 shp->prefix = 0;
350 np = nv_open(prefix,shp->var_tree,flag);
351 shp->prefix = prefix;
352 if(np)
354 if(nv_isvtree(np) && !nv_isarray(np))
356 stakputc('.');
357 stakputs(cp);
358 cp = stakfreeze(1);
360 nv_close(np);
363 np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN);
364 if(typ && !array && (nv_isnull(np) || nv_isarray(np)))
365 nv_settype(np,typ,0);
366 if((flags&NV_STATIC) && !nv_isnull(np))
367 #if SHOPT_TYPEDEF
368 goto check_type;
369 #else
370 continue;
371 #endif /* SHOPT_TYPEDEF */
372 if(array && (!(ap=nv_arrayptr(np)) || !ap->hdr.type))
374 if(!(arg->argflag&ARG_APPEND))
375 nv_unset(np);
376 if(array&NV_ARRAY)
378 nv_setarray(np,nv_associative);
380 else
382 nv_onattr(np,NV_ARRAY);
385 if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg)
387 #if SHOPT_TYPEDEF
388 goto check_type;
389 #else
390 continue;
391 #endif /* SHOPT_TYPEDEF */
393 /* check for array assignment */
394 if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL)))
396 int argc;
397 Dt_t *last_root = shp->last_root;
398 char **argv = sh_argbuild(shp,&argc,&tp->com,0);
399 shp->last_root = last_root;
400 #if SHOPT_TYPEDEF
401 if(shp->mktype && shp->dot_depth==0 && np==((struct sh_type*)shp->mktype)->nodes[0])
403 shp->mktype = 0;
404 errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]);
406 #endif /* SHOPT_TYPEDEF */
407 if(!(arg->argflag&ARG_APPEND))
409 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK)))
410 nv_unset(np);
412 nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
413 if(traceon || trap)
415 int n = -1;
416 char *name = nv_name(np);
417 if(arg->argflag&ARG_APPEND)
418 n = '+';
419 if(trap)
420 sh_debug(shp,trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN);
421 if(traceon)
423 sh_trace(NIL(char**),0);
424 sfputr(sfstderr,name,n);
425 sfwrite(sfstderr,"=( ",3);
426 while(cp= *argv++)
427 sfputr(sfstderr,sh_fmtq(cp),' ');
428 sfwrite(sfstderr,")\n",2);
431 #if SHOPT_TYPEDEF
432 goto check_type;
433 #else
434 continue;
435 #endif /* SHOPT_TYPEDEF */
437 if((tp->tre.tretyp&COMMSK)==TFUN)
438 goto skip;
439 if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
441 if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap)
443 if(prefix)
444 cp = stakcopy(nv_name(np));
445 shp->prefix = cp;
446 if(tp->com.comset->argval[1]=='[')
448 if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0)))
449 nv_unset(np);
450 if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE))
451 nv_setarray(np,nv_associative);
453 nv_setlist(tp->com.comset,flags,0);
454 shp->prefix = prefix;
455 if(tp->com.comset->argval[1]!='[')
456 nv_setvtree(np);
457 nv_close(np);
458 #if SHOPT_TYPEDEF
459 goto check_type;
460 #else
461 continue;
462 #endif /* SHOPT_TYPEDEF */
464 if(*cp!='.' && *cp!='[' && strchr(cp,'['))
466 nv_close(np);
467 np = nv_open(cp,shp->var_tree,flag);
469 if(arg->argflag&ARG_APPEND)
471 if(nv_isarray(np))
473 if((sub=nv_aimax(np)) < 0 && nv_arrayptr(np))
474 errormsg(SH_DICT,ERROR_exit(1),e_badappend,nv_name(np));
475 if(sub>=0)
476 sub++;
478 if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np))
479 sub=1;
481 else if(np->nvalue.cp && np->nvalue.cp!=Empty && !nv_type(np))
483 _nv_unset(np,NV_EXPORT);
486 else
488 if(!(arg->argflag&ARG_APPEND))
489 _nv_unset(np,NV_EXPORT);
490 if(!sh_isoption(SH_BASH) && !(array&NV_IARRAY) && !nv_isarray(np))
491 nv_setarray(np,nv_associative);
493 skip:
494 if(sub>0)
496 sfprintf(stkstd,"%s[%d]",prefix?nv_name(np):cp,sub);
497 shp->prefix = stakfreeze(1);
498 nv_putsub(np,(char*)0,ARRAY_ADD|ARRAY_FILL|sub);
500 else if(prefix)
501 shp->prefix = stakcopy(nv_name(np));
502 else
503 shp->prefix = cp;
504 shp->last_table = 0;
505 if(shp->prefix)
507 if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD))
509 sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1);
510 shp->prefix = stkfreeze(stkstd,1);
512 memset(&nr,0,sizeof(nr));
513 memcpy(&node,L_ARGNOD,sizeof(node));
514 L_ARGNOD->nvalue.nrp = &nr;
515 nr.np = np;
516 nr.root = shp->last_root;
517 nr.table = shp->last_table;
518 L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
519 L_ARGNOD->nvfun = 0;
521 sh_exec(tp,sh_isstate(SH_ERREXIT));
522 #if SHOPT_TYPEDEF
523 if(shp->prefix)
524 #endif
526 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
527 L_ARGNOD->nvflag = node.nvflag;
528 L_ARGNOD->nvfun = node.nvfun;
530 shp->prefix = prefix;
531 if(nv_isarray(np) && (mp=nv_opensub(np)))
532 np = mp;
533 while(tp->tre.tretyp==TLST)
535 if(!tp->lst.lstlef || !tp->lst.lstlef->tre.tretyp==TCOM || tp->lst.lstlef->com.comarg || tp->lst.lstlef->com.comset && tp->lst.lstlef->com.comset->argval[0]!='[')
536 break;
537 tp = tp->lst.lstrit;
540 if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='['))
542 nv_setvtree(np);
543 if(tp->com.comarg || tp->com.comset)
544 np->nvfun->dsize = 0;
546 #if SHOPT_TYPEDEF
547 goto check_type;
548 #else
549 continue;
550 #endif /* SHOPT_TYPEDEF */
552 cp = arg->argval;
553 mp = 0;
555 np = nv_open(cp,shp->var_tree,flags);
556 if(!np->nvfun && (flags&NV_NOREF))
558 if(shp->used_pos)
559 nv_onattr(np,NV_PARAM);
560 else
561 nv_offattr(np,NV_PARAM);
563 if(traceon || trap)
565 register char *sp=cp;
566 char *name=nv_name(np);
567 char *sub=0;
568 int append = 0;
569 if(nv_isarray(np))
570 sub = savesub;
571 if(cp=lastdot(sp,'='))
573 if(cp[-1]=='+')
574 append = ARG_APPEND;
575 cp++;
577 if(traceon)
579 sh_trace(NIL(char**),0);
580 nv_outname(sfstderr,name,-1);
581 if(sub)
582 sfprintf(sfstderr,"[%s]",sh_fmtq(sub));
583 if(cp)
585 if(append)
586 sfputc(sfstderr,'+');
587 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
590 if(trap)
592 char *av[2];
593 av[0] = cp;
594 av[1] = 0;
595 sh_debug(shp,trap,name,sub,av,append);
598 #if SHOPT_TYPEDEF
599 check_type:
600 if(maketype)
602 nv_open(shtp.nodes[0]->nvname,shp->var_tree,NV_ASSIGN|NV_VARNAME|NV_NOADD|NV_NOFAIL);
603 np = nv_mktype(shtp.nodes,shtp.numnodes);
604 free((void*)shtp.nodes);
605 shp->mktype = shtp.previous;
606 maketype = 0;
607 shp->prefix = 0;
608 if(nr.np == np)
610 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
611 L_ARGNOD->nvflag = node.nvflag;
612 L_ARGNOD->nvfun = node.nvfun;
615 #endif /* SHOPT_TYPEDEF */
620 * copy the subscript onto the stack
622 static void stak_subscript(const char *sub, int last)
624 register int c;
625 stakputc('[');
626 while(c= *sub++)
628 if(c=='[' || c==']' || c=='\\')
629 stakputc('\\');
630 stakputc(c);
632 stakputc(last);
636 * construct a new name from a prefix and base name on the stack
638 static char *copystack(const char *prefix, register const char *name, const char *sub)
640 register int last=0,offset = staktell();
641 if(prefix)
643 stakputs(prefix);
644 if(*stakptr(staktell()-1)=='.')
645 stakseek(staktell()-1);
646 if(*name=='.' && name[1]=='[')
647 last = staktell()+2;
648 if(*name!='[' && *name!='.' && *name!='=' && *name!='+')
649 stakputc('.');
650 if(*name=='.' && (name[1]=='=' || name[1]==0))
651 stakputc('.');
653 if(last)
655 stakputs(name);
656 if(sh_checkid(stakptr(last),(char*)0))
657 stakseek(staktell()-2);
659 if(sub)
660 stak_subscript(sub,']');
661 if(!last)
662 stakputs(name);
663 stakputc(0);
664 return(stakptr(offset));
668 * grow this stack string <name> by <n> bytes and move from cp-1 to end
669 * right by <n>. Returns beginning of string on the stack
671 static char *stack_extend(const char *cname, char *cp, int n)
673 register char *name = (char*)cname;
674 int offset = name - stakptr(0);
675 int m = cp-name;
676 stakseek(strlen(name)+n+1);
677 name = stakptr(offset);
678 cp = name + m;
679 m = strlen(cp)+1;
680 while(m-->0)
681 cp[n+m]=cp[m];
682 return((char*)name);
685 Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp)
687 Shell_t *shp = &sh;
688 char *cp=(char*)name, *sp, *xp;
689 register int c;
690 register Namval_t *np=0, *nq=0;
691 Namfun_t *fp=0;
692 long mode, add=0;
693 int copy=1,isref,top=0,noscope=(flags&NV_NOSCOPE);
694 if(root==shp->var_tree)
696 if(dtvnext(root))
697 top = 1;
698 else
699 flags &= ~NV_NOSCOPE;
701 if(!dp->disc)
702 copy = dp->nofree&1;
703 if(*cp=='.')
704 cp++;
705 while(1)
707 switch(c = *(unsigned char*)(sp = cp))
709 case '[':
710 if(flags&NV_NOARRAY)
712 dp->last = cp;
713 return(np);
715 cp = nv_endsubscript((Namval_t*)0,sp,0);
716 if(sp==name || sp[-1]=='.')
717 c = *(sp = cp);
718 goto skip;
719 case '.':
720 if(flags&NV_IDENT)
721 return(0);
722 if(root==shp->var_tree)
723 flags &= ~NV_EXPORT;
724 if(!copy && !(flags&NV_NOREF))
726 c = sp-name;
727 copy = cp-name;
728 dp->nofree |= 1;
729 name = copystack((const char*)0, name,(const char*)0);
730 cp = (char*)name+copy;
731 sp = (char*)name+c;
732 c = '.';
734 skip:
735 case '+':
736 case '=':
737 *sp = 0;
738 case 0:
739 isref = 0;
740 dp->last = cp;
741 mode = (c=='.' || (flags&NV_NOADD))?add:NV_ADD;
742 if((flags&NV_NOSCOPE) && c!='.')
743 mode |= HASH_NOSCOPE;
744 np=0;
745 if(top)
747 struct Ufunction *rp;
748 if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC))
750 Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0);
751 rp->sdict = dtopen(&_Nvdisc,Dtoset);
752 dtview(rp->sdict,shp->var_base);
753 dtview(shp->var_tree,rp->sdict);
755 if(np = nv_search(name,shp->var_tree,0))
757 if(shp->var_tree->walk == shp->var_base)
759 nq = np;
760 if((flags&NV_NOSCOPE) && *cp!='.')
762 if(mode==0)
763 root = shp->var_base;
764 else
766 nv_delete(np,(Dt_t*)0,0);
767 np = 0;
771 else
773 root = shp->var_tree->walk;
774 flags |= NV_NOSCOPE;
775 noscope = 1;
778 if(rp && rp->sdict && (flags&NV_STATIC))
780 root = rp->sdict;
781 if(np && shp->var_tree->walk==shp->var_tree)
783 _nv_unset(np,0);
784 nv_delete(np,shp->var_tree,0);
785 np = 0;
787 if(!np || shp->var_tree->walk!=root)
788 np = nv_search(name,root,HASH_NOSCOPE|NV_ADD);
791 if(np || (np = nv_search(name,root,mode)))
793 isref = nv_isref(np);
794 if(top)
796 if(nq==np)
798 flags &= ~NV_NOSCOPE;
799 root = shp->var_base;
801 else if(nq)
803 if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq)))
804 np->nvname = nq->nvname;
805 flags |= NV_NOSCOPE;
808 else if(add && nv_isnull(np) && c=='.' && cp[1]!='.')
809 nv_setvtree(np);
811 if(c)
812 *sp = c;
813 top = 0;
814 if(isref)
816 char *sub=0;
817 #if NVCACHE
818 nvcache.ok = 0;
819 #endif
820 if(c=='.') /* don't optimize */
821 shp->argaddr = 0;
822 else if((flags&NV_NOREF) && (c!='[' && *cp!='.'))
824 if(c && !(flags&NV_NOADD))
825 nv_unref(np);
826 return(np);
828 while(nv_isref(np) && np->nvalue.cp)
830 root = nv_reftree(np);
831 shp->last_root = root;
832 shp->last_table = nv_reftable(np);
833 sub = nv_refsub(np);
834 np = nv_refnode(np);
835 if(sub && c!='.')
836 nv_putsub(np,sub,0L);
837 flags |= NV_NOSCOPE;
838 noscope = 1;
840 if(nv_isref(np) && (c=='[' || c=='.' || !(flags&NV_ASSIGN)))
841 errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np));
842 if(sub && c==0)
843 return(np);
844 if(np==nq)
845 flags &= ~(noscope?0:NV_NOSCOPE);
846 else if(c)
848 c = (cp-sp);
849 copy = strlen(cp=nv_name(np));
850 dp->nofree |= 1;
851 name = copystack(cp,sp,sub);
852 sp = (char*)name + copy;
853 cp = sp+c;
854 c = *sp;
855 if(!noscope)
856 flags &= ~NV_NOSCOPE;
858 flags |= NV_NOREF;
859 if(nv_isnull(np))
860 nv_onattr(np,NV_NOFREE);
863 shp->last_root = root;
864 if(*cp && cp[1]=='.')
865 cp++;
866 if(c=='.' && (cp[1]==0 || cp[1]=='=' || cp[1]=='+'))
868 nv_local = 1;
869 return(np);
871 if(cp[-1]=='.')
872 cp--;
875 if(!np)
877 if(!nq && *sp=='[' && *cp==0 && cp[-1]==']')
880 * for backward compatibility
881 * evaluate subscript for
882 * possible side effects
884 cp[-1] = 0;
885 sh_arith(sp+1);
886 cp[-1] = ']';
888 return(np);
890 if(c=='[' || (c=='.' && nv_isarray(np)))
892 char *sub=0;
893 int n = 0;
894 mode &= ~HASH_NOSCOPE;
895 if(c=='[')
897 #if 0
898 Namarr_t *ap = nv_arrayptr(np);
899 int scan = ap?(ap->nelem&ARRAY_SCAN):0;
900 #endif
901 n = mode|nv_isarray(np);
902 if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']')
904 /* not implemented yet */
905 dp->last = cp;
906 return(np);
908 if((n&NV_ADD)&&(flags&NV_ARRAY))
909 n |= ARRAY_FILL;
910 if(flags&NV_ASSIGN)
911 n |= NV_ADD;
912 cp = nv_endsubscript(np,sp,n|(flags&NV_ASSIGN));
913 #if 0
914 if(scan)
915 nv_putsub(np,NIL(char*),ARRAY_SCAN);
916 #endif
918 else
919 cp = sp;
920 if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || (flags&NV_ARRAY))
923 int m = cp-sp;
924 sub = m?nv_getsub(np):0;
925 if(!sub)
927 if(m && !(n&NV_ADD))
928 return(0);
929 sub = "0";
931 n = strlen(sub)+2;
932 if(!copy)
934 copy = cp-name;
935 dp->nofree |= 1;
936 name = copystack((const char*)0, name,(const char*)0);
937 cp = (char*)name+copy;
938 sp = cp-m;
940 if(n <= m)
942 if(n)
944 memcpy(sp+1,sub,n-2);
945 sp[n-1] = ']';
947 if(n < m)
948 cp=strcpy(sp+n,cp);
950 else
952 int r = n-m;
953 m = sp-name;
954 name = stack_extend(name, cp-1, r);
955 sp = (char*)name + m;
956 *sp = '[';
957 memcpy(sp+1,sub,n-2);
958 sp[n-1] = ']';
959 cp = sp+n;
963 else if(c==0 && mode && (n=nv_aindex(np))>0)
964 nv_putsub(np,(char*)0,n);
965 else if(n==0 && (c==0 || (c=='[' && !nv_isarray(np))))
967 /* subscript must be 0*/
968 cp[-1] = 0;
969 n = sh_arith(sp+1);
970 cp[-1] = ']';
971 if(n)
972 return(0);
973 if(c)
974 sp = cp;
976 dp->last = cp;
977 if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
979 sp = cp;
980 if(!(nq = nv_opensub(np)))
982 Namarr_t *ap = nv_arrayptr(np);
983 if(!sub && (flags&NV_NOADD))
984 return(0);
985 n = mode|((flags&NV_NOADD)?0:NV_ADD);
986 if(!ap && (n&NV_ADD))
988 nv_putsub(np,sub,ARRAY_FILL);
989 ap = nv_arrayptr(np);
991 if(n && ap && !ap->table)
992 ap->table = dtopen(&_Nvdisc,Dtoset);
993 if(ap && ap->table && (nq=nv_search(sub,ap->table,n)))
994 nq->nvenv = (char*)np;
995 if(nq && nv_isnull(nq))
996 nq = nv_arraychild(np,nq,c);
998 if(nq)
1000 if(c=='.' && !nv_isvtree(nq))
1002 if(flags&NV_NOADD)
1003 return(0);
1004 nv_setvtree(nq);
1006 np = nq;
1008 else if(memcmp(cp,"[0]",3))
1009 return(nq);
1010 else
1012 /* ignore [0] */
1013 dp->last = cp += 3;
1014 c = *cp;
1018 else if(nv_isarray(np))
1020 if(c==0 && (flags&NV_MOVE))
1021 return(np);
1022 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1024 if(c=='.' && (fp=np->nvfun))
1026 for(; fp; fp=fp->next)
1028 if(fp->disc && fp->disc->createf)
1029 break;
1031 if(fp)
1033 if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
1035 add = NV_ADD;
1036 shp->last_table = 0;
1037 break;
1039 else if(np=nq)
1041 if((c = *(sp=cp=dp->last=fp->last))==0)
1043 if(nv_isarray(np) && sp[-1]!=']')
1044 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1045 return(np);
1051 while(c=='[');
1052 if(c!='.' || cp[1]=='.')
1053 return(np);
1054 cp++;
1055 break;
1056 default:
1057 dp->last = cp;
1058 if((c = mbchar(cp)) && !isaletter(c))
1059 return(np);
1060 while(xp=cp, c=mbchar(cp), isaname(c));
1061 cp = xp;
1064 return(np);
1068 * delete the node <np> from the dictionary <root> and clear from the cache
1069 * if <root> is NULL, only the cache is cleared
1070 * if flags does not contain NV_NOFREE, the node is freed
1072 void nv_delete(Namval_t* np, Dt_t *root, int flags)
1074 #if NVCACHE
1075 register int c;
1076 struct Cache_entry *xp;
1077 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
1079 if(xp->np==np)
1080 xp->root = 0;
1082 #endif
1083 if(root)
1085 if(dtdelete(root,np))
1087 if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
1088 free((void*)np);
1090 #if 0
1091 else
1093 sfprintf(sfstderr,"%s not deleted\n",nv_name(np));
1094 sfsync(sfstderr);
1096 #endif
1101 * Put <arg> into associative memory.
1102 * If <flags> & NV_ARRAY then follow array to next subscript
1103 * If <flags> & NV_NOARRAY then subscript is not allowed
1104 * If <flags> & NV_NOSCOPE then use the current scope only
1105 * If <flags> & NV_ASSIGN then assignment is allowed
1106 * If <flags> & NV_IDENT then name must be an identifier
1107 * If <flags> & NV_VARNAME then name must be a valid variable name
1108 * If <flags> & NV_NOADD then node will not be added if not found
1109 * If <flags> & NV_NOREF then don't follow reference
1110 * If <flags> & NV_NOFAIL then don't generate an error message on failure
1111 * If <flags> & NV_STATIC then unset before an assignment
1112 * If <flags> & NV_UNJUST then unset attributes before assignment
1113 * SH_INIT is only set while initializing the environment
1115 Namval_t *nv_open(const char *name, Dt_t *root, int flags)
1117 Shell_t *shp = &sh;
1118 register char *cp=(char*)name;
1119 register int c;
1120 register Namval_t *np;
1121 Namfun_t fun;
1122 int append=0;
1123 const char *msg = e_varname;
1124 char *fname = 0;
1125 int offset = staktell();
1126 Dt_t *funroot;
1127 #if NVCACHE
1128 struct Cache_entry *xp;
1129 #endif
1131 sh_stats(STAT_NVOPEN);
1132 memset(&fun,0,sizeof(fun));
1133 shp->last_table = shp->namespace;
1134 if(!root)
1135 root = shp->var_tree;
1136 shp->last_root = root;
1137 if(root==shp->fun_tree)
1139 flags |= NV_NOREF;
1140 msg = e_badfun;
1141 if((np=shp->namespace) || strchr(name,'.'))
1143 name = cp = copystack(np?nv_name(np):0,name,(const char*)0);
1144 fname = strrchr(cp,'.');
1145 *fname = 0;
1146 fun.nofree |= 1;
1147 flags &= ~NV_IDENT;
1148 funroot = root;
1149 root = shp->var_tree;
1152 else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
1154 long mode = ((flags&NV_NOADD)?0:NV_ADD);
1155 if(flags&NV_NOSCOPE)
1156 mode |= HASH_SCOPE|HASH_NOSCOPE;
1157 np = nv_search(name,root,mode);
1158 if(np && !(flags&NV_REF))
1160 while(nv_isref(np))
1162 shp->last_table = nv_reftable(np);
1163 np = nv_refnode(np);
1166 return(np);
1168 else if(shp->prefix && (flags&NV_ASSIGN))
1170 name = cp = copystack(shp->prefix,name,(const char*)0);
1171 fun.nofree |= 1;
1173 c = *(unsigned char*)cp;
1174 if(root==shp->alias_tree)
1176 msg = e_aliname;
1177 while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
1178 (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON));
1179 if(shp->subshell && c=='=')
1180 root = sh_subaliastree(1);
1181 if(c= *--cp)
1182 *cp = 0;
1183 np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
1184 if(c)
1185 *cp = c;
1186 goto skip;
1188 else if(flags&NV_IDENT)
1189 msg = e_ident;
1190 else if(c=='.')
1192 c = *++cp;
1193 flags |= NV_NOREF;
1194 if(root==shp->var_tree)
1195 root = shp->var_base;
1196 shp->last_table = 0;
1198 if(c= !isaletter(c))
1199 goto skip;
1200 #if NVCACHE
1201 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
1203 if(xp->root!=root)
1204 continue;
1205 if(*name==*xp->name && (flags&(NV_ARRAY|NV_NOSCOPE))==xp->flags && memcmp(xp->name,name,xp->len)==0 && (name[xp->len]==0 || name[xp->len]=='=' || name[xp->len]=='+'))
1207 sh_stats(STAT_NVHITS);
1208 np = xp->np;
1209 cp = (char*)name+xp->len;
1210 if(nv_isarray(np))
1211 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1212 shp->last_table = xp->last_table;
1213 shp->last_root = xp->last_root;
1214 goto nocache;
1217 nvcache.ok = 1;
1218 #endif
1219 np = nv_create(name, root, flags, &fun);
1220 cp = fun.last;
1221 #if NVCACHE
1222 if(np && nvcache.ok && cp[-1]!=']')
1224 xp = &nvcache.entries[nvcache.index];
1225 if(*cp)
1227 char *sp = strchr(name,*cp);
1228 if(!sp)
1229 goto nocache;
1230 xp->len = sp-name;
1232 else
1233 xp->len = strlen(name);
1234 c = roundof(xp->len+1,32);
1235 if(c > xp->size)
1237 if(xp->size==0)
1238 xp->name = malloc(c);
1239 else
1240 xp->name = realloc(xp->name,c);
1241 xp->size = c;
1243 memcpy(xp->name,name,xp->len);
1244 xp->name[xp->len] = 0;
1245 xp->root = root;
1246 xp->np = np;
1247 xp->last_table = shp->last_table;
1248 xp->last_root = shp->last_root;
1249 xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE));
1250 nvcache.index = (nvcache.index+1)&(NVCACHE-1);
1252 nocache:
1253 nvcache.ok = 0;
1254 #endif
1255 if(fname)
1257 c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD);
1258 *fname = '.';
1259 np = nv_search(name, funroot, c);
1260 *fname = 0;
1262 else
1264 if(*cp=='.' && cp[1]=='.')
1266 append |= NV_NODISC;
1267 cp+=2;
1269 if(*cp=='+' && cp[1]=='=')
1271 append |= NV_APPEND;
1272 cp++;
1275 c = *cp;
1276 skip:
1277 #if SHOPT_TYPEDEF
1278 if(np && shp->mktype)
1279 np = nv_addnode(np,0);
1280 #endif /* SHOPT_TYPEDEF */
1281 if(c=='=' && np && (flags&NV_ASSIGN))
1283 cp++;
1284 if(sh_isstate(SH_INIT))
1286 nv_putval(np, cp, NV_RDONLY);
1287 if(np==PWDNOD)
1288 nv_onattr(np,NV_TAGGED);
1290 else
1292 char *sub=0, *prefix= shp->prefix;
1293 int isref;
1294 shp->prefix = 0;
1295 if((flags&NV_STATIC) && !shp->mktype)
1297 if(!nv_isnull(np))
1299 shp->prefix = prefix;
1300 return(np);
1303 isref = nv_isref(np);
1304 if(sh_isoption(SH_XTRACE) && nv_isarray(np))
1305 sub = nv_getsub(np);
1306 c = msg==e_aliname? 0: (append | (flags&NV_EXPORT));
1307 if(isref)
1308 nv_offattr(np,NV_REF);
1309 if(!append && (flags&NV_UNJUST))
1311 nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL);
1312 np->nvsize = 0;
1314 nv_putval(np, cp, c);
1315 if(isref)
1317 if(nv_search((char*)np,shp->var_base,HASH_BUCKET))
1318 shp->last_root = shp->var_base;
1319 nv_setref(np,(Dt_t*)0,NV_VARNAME);
1321 savesub = sub;
1322 shp->prefix = prefix;
1324 nv_onattr(np, flags&NV_ATTRIBUTES);
1326 else if(c)
1328 if(flags&NV_NOFAIL)
1329 return(0);
1330 if(c=='.')
1331 msg = e_noparent;
1332 else if(c=='[')
1333 msg = e_noarray;
1334 errormsg(SH_DICT,ERROR_exit(1),msg,name);
1336 if(fun.nofree&1)
1337 stakseek(offset);
1338 return(np);
1341 #if SHOPT_MULTIBYTE
1342 static int ja_size(char*, int, int);
1343 static void ja_restore(void);
1344 static char *savep;
1345 static char savechars[8+1];
1346 #endif /* SHOPT_MULTIBYTE */
1349 * put value <string> into name-value node <np>.
1350 * If <np> is an array, then the element given by the
1351 * current index is assigned to.
1352 * If <flags> contains NV_RDONLY, readonly attribute is ignored
1353 * If <flags> contains NV_INTEGER, string is a pointer to a number
1354 * If <flags> contains NV_NOFREE, previous value is freed, and <string>
1355 * becomes value of node and <flags> becomes attributes
1357 void nv_putval(register Namval_t *np, const char *string, int flags)
1359 register const char *sp=string;
1360 register union Value *up;
1361 register char *cp;
1362 register int size = 0;
1363 register int dot;
1364 int was_local = nv_local;
1365 union Value u;
1366 if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
1367 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1368 /* The following could cause the shell to fork if assignment
1369 * would cause a side effect
1371 sh.argaddr = 0;
1372 if(sh.subshell && !nv_local)
1373 np = sh_assignok(np,1);
1374 if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np))
1376 /* This function contains disc */
1377 if(!nv_local)
1379 nv_local=1;
1380 nv_putv(np,sp,flags,np->nvfun);
1381 if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1382 sh_envput(sh.env,np);
1383 return;
1385 /* called from disc, assign the actual value */
1387 flags &= ~NV_NODISC;
1388 nv_local=0;
1389 if(flags&(NV_NOREF|NV_NOFREE))
1391 if(np->nvalue.cp && np->nvalue.cp!=sp && !nv_isattr(np,NV_NOFREE))
1392 free((void*)np->nvalue.cp);
1393 np->nvalue.cp = (char*)sp;
1394 nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE);
1395 return;
1397 up= &np->nvalue;
1398 if(nv_isattr(np,NV_INT16P) == NV_INT16)
1400 if(!np->nvalue.up || !nv_isarray(np))
1402 up = &u;
1403 up->up = &np->nvalue;
1406 else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np))
1407 up = np->nvalue.up;
1408 if(up && up->cp==Empty)
1409 up->cp = 0;
1410 if(nv_isattr(np,NV_EXPORT))
1411 nv_offattr(np,NV_IMPORT);
1412 if(nv_isattr (np, NV_INTEGER))
1414 if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE)
1416 if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
1418 Sfdouble_t ld, old=0;
1419 if(flags&NV_INTEGER)
1421 if(flags&NV_LONG)
1422 ld = *((Sfdouble_t*)sp);
1423 else if(flags&NV_SHORT)
1424 ld = *((float*)sp);
1425 else
1426 ld = *((double*)sp);
1428 else
1429 ld = sh_arith(sp);
1430 if(!up->ldp)
1431 up->ldp = new_of(Sfdouble_t,0);
1432 else if(flags&NV_APPEND)
1433 old = *(up->ldp);
1434 *(up->ldp) = old?ld+old:ld;
1436 else
1438 double d,od=0;
1439 if(flags&NV_INTEGER)
1441 if(flags&NV_LONG)
1442 d = (double)(*(Sfdouble_t*)sp);
1443 else if(flags&NV_SHORT)
1444 d = (double)(*(float*)sp);
1445 else
1446 d = *(double*)sp;
1448 else
1449 d = sh_arith(sp);
1450 if(!up->dp)
1451 up->dp = new_of(double,0);
1452 else if(flags&NV_APPEND)
1453 od = *(up->dp);
1454 *(up->dp) = od?d+od:d;
1457 else
1459 if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
1461 Sflong_t ll=0,oll=0;
1462 if(flags&NV_INTEGER)
1464 if((flags&NV_DOUBLE) == NV_DOUBLE)
1466 if(flags&NV_LONG)
1467 ll = *((Sfdouble_t*)sp);
1468 else if(flags&NV_SHORT)
1469 ll = *((float*)sp);
1470 else
1471 ll = *((double*)sp);
1473 else if(nv_isattr(np,NV_UNSIGN))
1475 if(flags&NV_LONG)
1476 ll = *((Sfulong_t*)sp);
1477 else if(flags&NV_SHORT)
1478 ll = *((uint16_t*)sp);
1479 else
1480 ll = *((uint32_t*)sp);
1482 else
1484 if(flags&NV_LONG)
1485 ll = *((Sflong_t*)sp);
1486 else if(flags&NV_SHORT)
1487 ll = *((uint16_t*)sp);
1488 else
1489 ll = *((uint32_t*)sp);
1492 else if(sp)
1493 ll = (Sflong_t)sh_arith(sp);
1494 if(!up->llp)
1495 up->llp = new_of(Sflong_t,0);
1496 else if(flags&NV_APPEND)
1497 oll = *(up->llp);
1498 *(up->llp) = ll+oll;
1500 else
1502 int32_t l=0,ol=0;
1503 if(flags&NV_INTEGER)
1505 if((flags&NV_DOUBLE) == NV_DOUBLE)
1507 Sflong_t ll;
1508 if(flags&NV_LONG)
1509 ll = *((Sfdouble_t*)sp);
1510 else if(flags&NV_SHORT)
1511 ll = *((float*)sp);
1512 else
1513 ll = *((double*)sp);
1514 l = (int32_t)ll;
1516 else if(nv_isattr(np,NV_UNSIGN))
1518 if(flags&NV_LONG)
1519 l = *((Sfulong_t*)sp);
1520 else if(flags&NV_SHORT)
1521 l = *((uint16_t*)sp);
1522 else
1523 l = *(uint32_t*)sp;
1525 else
1527 if(flags&NV_LONG)
1528 l = *((Sflong_t*)sp);
1529 else if(flags&NV_SHORT)
1530 l = *((int16_t*)sp);
1531 else
1532 l = *(int32_t*)sp;
1535 else if(sp)
1537 Sfdouble_t ld = sh_arith(sp);
1538 if(ld<0)
1539 l = (int32_t)ld;
1540 else
1541 l = (uint32_t)ld;
1543 if(nv_size(np) <= 1)
1544 nv_setsize(np,10);
1545 if(nv_isattr (np, NV_SHORT))
1547 int16_t s=0;
1548 if(flags&NV_APPEND)
1549 s = *up->sp;
1550 *(up->sp) = s+(int16_t)l;
1551 nv_onattr(np,NV_NOFREE);
1553 else
1555 if(!up->lp)
1556 up->lp = new_of(int32_t,0);
1557 else if(flags&NV_APPEND)
1558 ol = *(up->lp);
1559 *(up->lp) = l+ol;
1564 else
1566 const char *tofree=0;
1567 int offset;
1568 #if _lib_pathnative
1569 char buff[PATH_MAX];
1570 #endif /* _lib_pathnative */
1571 if(flags&NV_INTEGER)
1573 if((flags&NV_DOUBLE)==NV_DOUBLE)
1575 if(flags&NV_LONG)
1576 sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
1577 else
1578 sfprintf(sh.strbuf,"%.*g",DBL_DIG,*((double*)sp));
1580 else if(flags&NV_UNSIGN)
1582 if(flags&NV_LONG)
1583 sfprintf(sh.strbuf,"%I*lu",sizeof(Sfulong_t),*((Sfulong_t*)sp));
1584 else
1585 sfprintf(sh.strbuf,"%lu",(unsigned long)((flags&NV_SHORT)?*((uint16_t*)sp):*((uint32_t*)sp)));
1587 else
1589 if(flags&NV_LONG)
1590 sfprintf(sh.strbuf,"%I*ld",sizeof(Sflong_t),*((Sflong_t*)sp));
1591 else
1592 sfprintf(sh.strbuf,"%ld",(long)((flags&NV_SHORT)?*((int16_t*)sp):*((int32_t*)sp)));
1594 sp = sfstruse(sh.strbuf);
1596 if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp)
1598 #ifdef _lib_pathnative
1600 * return the host file name given the UNIX name
1602 pathnative(sp,buff,sizeof(buff));
1603 if(buff[1]==':' && buff[2]=='/')
1605 buff[2] = '\\';
1606 if(*buff>='A' && *buff<='Z')
1607 *buff += 'a'-'A';
1609 sp = buff;
1610 #else
1612 #endif /* _lib_pathnative */
1614 else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
1616 for(;*sp == ' '|| *sp=='\t';sp++);
1617 if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
1618 for(;*sp=='0';sp++);
1619 size = nv_size(np);
1620 #if SHOPT_MULTIBYTE
1621 if(size)
1622 size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
1623 #endif /* SHOPT_MULTIBYTE */
1625 if(!up->cp)
1626 flags &= ~NV_APPEND;
1627 if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY))
1629 offset = staktell();
1630 stakputs(up->cp);
1631 stakputs(sp);
1632 stakputc(0);
1633 sp = stakptr(offset);
1635 if(!nv_isattr(np, NV_NOFREE))
1637 /* delay free in case <sp> points into free region */
1638 tofree = up->cp;
1640 if(nv_isattr(np,NV_BINARY) && !(flags&NV_RAW))
1641 tofree = 0;
1642 if(nv_isattr(np,NV_LJUST|NV_RJUST) && nv_isattr(np,NV_LJUST|NV_RJUST)!=(NV_LJUST|NV_RJUST))
1643 tofree = 0;
1644 if (sp)
1646 dot = strlen(sp);
1647 #if (_AST_VERSION>=20030127L)
1648 if(nv_isattr(np,NV_BINARY))
1650 int oldsize = (flags&NV_APPEND)?nv_size(np):0;
1651 if(flags&NV_RAW)
1653 if(tofree)
1655 free((void*)tofree);
1656 nv_offattr(np,NV_NOFREE);
1658 up->cp = sp;
1659 return;
1661 size = 0;
1662 if(nv_isattr(np,NV_ZFILL))
1663 size = nv_size(np);
1664 if(size==0)
1665 size = oldsize + (3*dot/4);
1666 cp = (char*)malloc(size+1);
1667 nv_offattr(np,NV_NOFREE);
1668 if(oldsize)
1669 memcpy((void*)cp,(void*)up->cp,oldsize);
1670 up->cp = cp;
1671 if(size <= oldsize)
1672 return;
1673 dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0);
1674 dot += oldsize;
1675 if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0)
1676 nv_setsize(np,dot);
1677 else if(nv_isattr(np,NV_ZFILL) && (size>dot))
1678 memset(&cp[dot],0,size-dot);
1679 return;
1681 else
1682 #endif
1683 if(size==0 && nv_isattr(np,NV_HOST)!=NV_HOST &&nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
1684 nv_setsize(np,size=dot);
1685 else if(size > dot)
1686 dot = size;
1687 else if(nv_isattr(np,NV_LJUST|NV_RJUST)==NV_LJUST && dot>size)
1688 dot = size;
1689 if(size==0 || tofree || !(cp=(char*)up->cp))
1691 cp = (char*)malloc(((unsigned)dot+1));
1692 cp[dot] = 0;
1693 nv_offattr(np,NV_NOFREE);
1697 else
1698 cp = 0;
1699 up->cp = cp;
1700 if(sp)
1702 int c = cp[dot];
1703 memcpy(cp,sp,dot);
1704 cp[dot]=0;
1705 if(nv_isattr(np, NV_LTOU))
1706 ltou(cp);
1707 else if(nv_isattr (np, NV_UTOL))
1708 utol(cp);
1709 cp[dot] = c;
1710 if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
1711 rightjust(cp,size,'0');
1712 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_RJUST)
1713 rightjust(cp,size,' ');
1714 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_LJUST)
1716 register char *dp;
1717 dp = strlen (cp) + cp;
1718 cp = cp+size;
1719 for (; dp < cp; *dp++ = ' ');
1721 #if SHOPT_MULTIBYTE
1722 /* restore original string */
1723 if(savep)
1724 ja_restore();
1725 #endif /* SHOPT_MULTIBYTE */
1727 if(flags&NV_APPEND)
1728 stakseek(offset);
1729 if(tofree && tofree!=Empty)
1730 free((void*)tofree);
1732 if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1733 sh_envput(sh.env,np);
1734 return;
1739 * Right-justify <str> so that it contains no more than
1740 * <size> characters. If <str> contains fewer than <size>
1741 * characters, left-pad with <fill>. Trailing blanks
1742 * in <str> will be ignored.
1744 * If the leftmost digit in <str> is not a digit, <fill>
1745 * will default to a blank.
1747 static void rightjust(char *str, int size, int fill)
1749 register int n;
1750 register char *cp,*sp;
1751 n = strlen(str);
1753 /* ignore trailing blanks */
1754 for(cp=str+n;n && *--cp == ' ';n--);
1755 if (n == size)
1756 return;
1757 if(n > size)
1759 *(str+n) = 0;
1760 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
1761 return;
1763 else *(sp = str+size) = 0;
1764 if (n == 0)
1766 while (sp > str)
1767 *--sp = ' ';
1768 return;
1770 while(n--)
1772 sp--;
1773 *sp = *cp--;
1775 if(!isdigit(*str))
1776 fill = ' ';
1777 while(sp>str)
1778 *--sp = fill;
1779 return;
1782 #if SHOPT_MULTIBYTE
1784 * handle left and right justified fields for multi-byte chars
1785 * given physical size, return a logical size which reflects the
1786 * screen width of multi-byte characters
1787 * Multi-width characters replaced by spaces if they cross the boundary
1788 * <type> is non-zero for right justified fields
1791 static int ja_size(char *str,int size,int type)
1793 register char *cp = str;
1794 register int c, n=size;
1795 register int outsize;
1796 register char *oldcp=cp;
1797 int oldn;
1798 wchar_t w;
1799 while(*cp)
1801 oldn = n;
1802 w = mbchar(cp);
1803 outsize = mbwidth(w);
1804 size -= outsize;
1805 c = cp-oldcp;
1806 n += (c-outsize);
1807 oldcp = cp;
1808 if(size<=0 && type==0)
1809 break;
1811 /* check for right justified fields that need truncating */
1812 if(size <0)
1814 if(type==0)
1816 /* left justified and character crosses field boundary */
1817 n = oldn;
1818 /* save boundary char and replace with spaces */
1819 size = c;
1820 savechars[size] = 0;
1821 while(size--)
1823 savechars[size] = cp[size];
1824 cp[size] = ' ';
1826 savep = cp;
1828 size = -size;
1829 if(type)
1830 n -= (ja_size(str,size,0)-size);
1832 return(n);
1835 static void ja_restore(void)
1837 register char *cp = savechars;
1838 while(*cp)
1839 *savep++ = *cp++;
1840 savep = 0;
1842 #endif /* SHOPT_MULTIBYTE */
1844 #ifndef _ENV_H
1845 static char *staknam(register Namval_t *np, char *value)
1847 register char *p,*q;
1848 q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
1849 p=strcopy(q,nv_name(np));
1850 if(value)
1852 *p++ = '=';
1853 strcpy(p,value);
1855 return(q);
1857 #endif
1860 * put the name and attribute into value of attributes variable
1862 #ifdef _ENV_H
1863 static void attstore(register Namval_t *np, void *data)
1865 register int flag, c = ' ';
1866 NOT_USED(data);
1867 if(!(nv_isattr(np,NV_EXPORT)))
1868 return;
1869 flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1870 stakputc('=');
1871 if((flag&NV_DOUBLE) == NV_DOUBLE)
1873 /* export doubles as integers for ksh88 compatibility */
1874 stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)));
1876 else
1878 stakputc(c+flag);
1879 if(flag&NV_INTEGER)
1880 c += nv_size(np);
1882 stakputc(c);
1883 stakputs(nv_name(np));
1885 #else
1886 static void attstore(register Namval_t *np, void *data)
1888 register int flag = np->nvflag;
1889 register struct adata *ap = (struct adata*)data;
1890 ap->sh = &sh;
1891 ap->tp = 0;
1892 if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
1893 return;
1894 flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
1895 *ap->attval++ = '=';
1896 if((flag&NV_DOUBLE) == NV_DOUBLE)
1898 /* export doubles as integers for ksh88 compatibility */
1899 *ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE));
1900 *ap->attval = ' ';
1902 else
1904 *ap->attval++ = ' '+flag;
1905 if(flag&NV_INTEGER)
1906 *ap->attval = ' ' + nv_size(np);
1907 else
1908 *ap->attval = ' ';
1910 ap->attval = strcopy(++ap->attval,nv_name(np));
1912 #endif
1914 #ifndef _ENV_H
1915 static void pushnam(Namval_t *np, void *data)
1917 register char *value;
1918 register struct adata *ap = (struct adata*)data;
1919 ap->sh = &sh;
1920 ap->tp = 0;
1921 if(nv_isattr(np,NV_IMPORT) && np->nvenv)
1922 *ap->argnam++ = np->nvenv;
1923 else if(value=nv_getval(np))
1924 *ap->argnam++ = staknam(np,value);
1925 if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
1926 ap->attsize += (strlen(nv_name(np))+4);
1928 #endif
1931 * Generate the environment list for the child.
1934 #ifdef _ENV_H
1935 char **sh_envgen(void)
1937 int offset,tell;
1938 register char **er;
1939 env_delete(sh.env,"_");
1940 er = env_get(sh.env);
1941 offset = staktell();
1942 stakputs(e_envmarker);
1943 tell = staktell();
1944 nv_scan(sh.var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1945 if(tell ==staktell())
1946 stakseek(offset);
1947 else
1948 *--er = stakfreeze(1)+offset;
1949 return(er);
1951 #else
1952 char **sh_envgen(void)
1954 register char **er;
1955 register int namec;
1956 register char *cp;
1957 struct adata data;
1958 Shell_t *shp = sh_getinterp();
1959 data.sh = shp;
1960 data.tp = 0;
1961 /* L_ARGNOD gets generated automatically as full path name of command */
1962 nv_offattr(L_ARGNOD,NV_EXPORT);
1963 data.attsize = 6;
1964 namec = nv_scan(shp->var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT);
1965 namec += shp->nenv;
1966 er = (char**)stakalloc((namec+4)*sizeof(char*));
1967 data.argnam = (er+=2) + shp->nenv;
1968 if(shp->nenv)
1969 memcpy((void*)er,environ,shp->nenv*sizeof(char*));
1970 nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
1971 *data.argnam = (char*)stakalloc(data.attsize);
1972 cp = data.attval = strcopy(*data.argnam,e_envmarker);
1973 nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
1974 *data.attval = 0;
1975 if(cp!=data.attval)
1976 data.argnam++;
1977 *data.argnam = 0;
1978 return(er);
1980 #endif
1982 struct scan
1984 void (*scanfn)(Namval_t*, void*);
1985 int scanmask;
1986 int scanflags;
1987 int scancount;
1988 void *scandata;
1991 static int scanfilter(Dt_t *dict, void *arg, void *data)
1993 register Namval_t *np = (Namval_t*)arg;
1994 register int k=np->nvflag;
1995 register struct scan *sp = (struct scan*)data;
1996 register struct adata *tp = (struct adata*)sp->scandata;
1997 NOT_USED(dict);
1998 #if SHOPT_TYPEDEF
1999 if(!is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp)
2000 return(0);
2001 #endif /*SHOPT_TYPEDEF */
2002 if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags)))
2004 if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT))
2005 return(0);
2006 if(sp->scanfn)
2008 if(nv_isarray(np))
2009 nv_putsub(np,NIL(char*),0L);
2010 (*sp->scanfn)(np,sp->scandata);
2012 sp->scancount++;
2014 return(0);
2018 * Walk through the name-value pairs
2019 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
2020 * are visited
2021 * If <mask> is zero, and <flags> non-zero, then nodes with one or
2022 * more of <flags> is visited
2023 * If <mask> and <flags> are zero, then all nodes are visted
2025 int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
2027 Dt_t *base=0;
2028 struct scan sdata;
2029 int (*hashfn)(Dt_t*, void*, void*);
2030 sdata.scanmask = mask;
2031 sdata.scanflags = flags&~NV_NOSCOPE;
2032 sdata.scanfn = fn;
2033 sdata.scancount = 0;
2034 sdata.scandata = data;
2035 hashfn = scanfilter;
2036 if(flags&NV_NOSCOPE)
2037 base = dtview((Dt_t*)root,0);
2038 dtwalk(root, hashfn,&sdata);
2039 if(base)
2040 dtview((Dt_t*)root,base);
2041 return(sdata.scancount);
2045 * create a new environment scope
2047 void sh_scope(Shell_t *shp, struct argnod *envlist, int fun)
2049 register Dt_t *newscope, *newroot=shp->var_base;
2050 struct Ufunction *rp;
2051 newscope = dtopen(&_Nvdisc,Dtoset);
2052 if(envlist)
2054 dtview(newscope,(Dt_t*)shp->var_tree);
2055 shp->var_tree = newscope;
2056 nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0);
2057 if(!fun)
2058 return;
2059 shp->var_tree = dtview(newscope,0);
2061 if((rp=shp->st.real_fun) && rp->sdict)
2063 dtview(rp->sdict,newroot);
2064 newroot = rp->sdict;
2067 dtview(newscope,(Dt_t*)newroot);
2068 shp->var_tree = newscope;
2072 * Remove freeable local space associated with the nvalue field
2073 * of nnod. This includes any strings representing the value(s) of the
2074 * node, as well as its dope vector, if it is an array.
2077 void sh_envnolocal (register Namval_t *np, void *data)
2079 char *cp=0;
2080 NOT_USED(data);
2081 if(np==VERSIONNOD && nv_isref(np))
2082 return;
2083 if(np==L_ARGNOD)
2084 return;
2085 if(nv_isattr(np,NV_EXPORT) && nv_isarray(np))
2087 nv_putsub(np,NIL(char*),0);
2088 if(cp = nv_getval(np))
2089 cp = strdup(cp);
2091 if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
2093 if(nv_isref(np) && np!=VERSIONNOD)
2095 nv_offattr(np,NV_NOFREE|NV_REF);
2096 free((void*)np->nvalue.nrp);
2097 np->nvalue.cp = 0;
2099 if(!cp)
2100 return;
2102 if(nv_isarray(np))
2103 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
2104 _nv_unset(np,NV_RDONLY);
2105 nv_setattr(np,0);
2106 if(cp)
2108 nv_putval(np,cp,0);
2109 free((void*)cp);
2114 * Currently this is a dummy, but someday will be needed
2115 * for reference counting
2117 void nv_close(Namval_t *np)
2119 NOT_USED(np);
2122 static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot)
2124 register Namval_t *np,*nq, *npnext;
2125 for(np=(Namval_t*)dtfirst(root);np;np=npnext)
2127 if(nv_isref(np))
2129 free((void*)np->nvalue.nrp);
2130 np->nvalue.cp = 0;
2131 np->nvflag = 0;
2133 if(nq=dtsearch(oroot,np))
2135 if(nv_cover(nq))
2137 int subshell = shp->subshell;
2138 shp->subshell = 0;
2139 if(nv_isattr(nq, NV_INTEGER))
2141 Sfdouble_t d = nv_getnum(nq);
2142 nv_putval(nq,(char*)&d,NV_LDOUBLE);
2144 else if(shp->test&4)
2145 nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY);
2146 else
2147 nv_putval(nq, nv_getval(nq), NV_RDONLY);
2148 shp->subshell = subshell;
2149 np->nvfun = 0;
2151 if(nv_isattr(nq,NV_EXPORT))
2152 sh_envput(shp->env,nq);
2154 npnext = (Namval_t*)dtnext(root,np);
2155 shp->last_root = root;
2156 shp->last_table = 0;
2157 if(nv_isvtree(np))
2159 int len = strlen(np->nvname);
2160 while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.')
2163 npnext = (Namval_t*)dtnext(root,nq);
2164 _nv_unset(nq,flags);
2165 nv_delete(nq,root,0);
2168 _nv_unset(np,flags);
2169 nv_delete(np,root,0);
2175 * Set the value of <np> to 0, and nullify any attributes
2176 * that <np> may have had. Free any freeable space occupied
2177 * by the value of <np>. If <np> denotes an array member, it
2178 * will retain its attributes.
2179 * <flags> can contain NV_RDONLY to override the readonly attribute
2180 * being cleared.
2181 * <flags> can contain NV_EXPORT to override preserve nvenv
2183 void _nv_unset(register Namval_t *np,int flags)
2185 Shell_t *shp = &sh;
2186 register union Value *up;
2187 if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY))
2188 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
2189 if(is_afunction(np) && np->nvalue.ip)
2191 register struct slnod *slp = (struct slnod*)(np->nvenv);
2192 if(slp && !nv_isattr(np,NV_NOFREE))
2194 struct Ufunction *rq,*rp = np->nvalue.rp;
2195 /* free function definition */
2196 register char *name=nv_name(np),*cp= strrchr(name,'.');
2197 if(cp)
2199 Namval_t *npv;
2200 *cp = 0;
2201 npv = nv_open(name,shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD);
2202 *cp++ = '.';
2203 if(npv)
2204 nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv);
2206 if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0)))
2210 if(rq->np != np)
2211 continue;
2212 dtdelete(shp->fpathdict,rq);
2213 break;
2215 while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq));
2217 if(rp->sdict)
2219 Namval_t *mp, *nq;
2220 for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq)
2222 nq = dtnext(rp->sdict,mp);
2223 _nv_unset(mp,NV_RDONLY);
2224 nv_delete(mp,rp->sdict,0);
2226 dtclose(rp->sdict);
2228 stakdelete(slp->slptr);
2229 free((void*)np->nvalue.ip);
2230 np->nvalue.ip = 0;
2232 goto done;
2234 if(shp->subshell && !nv_isnull(np))
2235 np = sh_assignok(np,0);
2236 nv_offattr(np,NV_NODISC);
2237 if(np->nvfun && !nv_isref(np))
2239 /* This function contains disc */
2240 if(!nv_local)
2242 nv_local=1;
2243 nv_putv(np,NIL(char*),flags,np->nvfun);
2244 nv_local=0;
2245 return;
2247 /* called from disc, assign the actual value */
2248 nv_local=0;
2250 if(nv_isattr(np,NV_INT16P) == NV_INT16)
2252 np->nvalue.cp = nv_isarray(np)?Empty:0;
2253 goto done;
2255 if(nv_isarray(np) && np->nvalue.cp!=Empty && np->nvfun)
2256 up = np->nvalue.up;
2257 else
2258 up = &np->nvalue;
2259 if(up && up->cp)
2261 if(up->cp!=Empty && !nv_isattr(np, NV_NOFREE))
2262 free((void*)up->cp);
2263 up->cp = 0;
2265 done:
2266 if(!nv_isarray(np) || !nv_arrayptr(np))
2268 if(nv_isref(np) && !nv_isattr(np,NV_EXPORT))
2269 free((void*)np->nvalue.nrp);
2270 nv_setsize(np,0);
2271 if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
2273 if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'['))
2274 env_delete(shp->env,nv_name(np));
2275 if(!(flags&NV_EXPORT) || nv_isattr(np,NV_IMPORT|NV_EXPORT)==(NV_IMPORT|NV_EXPORT))
2276 np->nvenv = 0;
2277 nv_setattr(np,0);
2279 else
2281 nv_setattr(np,NV_MINIMAL);
2282 nv_delete(np,(Dt_t*)0,0);
2288 * return the node pointer in the highest level scope
2290 Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np)
2292 if(!dtvnext(shp->var_tree))
2293 return(np);
2294 return(dtsearch(shp->var_tree,np));
2297 #if 1
2299 * return space separated list of names of variables in given tree
2301 static char *tableval(Dt_t *root)
2303 static Sfio_t *out;
2304 register Namval_t *np;
2305 register int first=1;
2306 register Dt_t *base = dtview(root,0);
2307 if(out)
2308 sfseek(out,(Sfoff_t)0,SEEK_SET);
2309 else
2310 out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
2311 for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
2313 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
2315 if(!first)
2316 sfputc(out,' ');
2317 else
2318 first = 0;
2319 sfputr(out,np->nvname,-1);
2322 sfputc(out,0);
2323 if(base)
2324 dtview(root,base);
2325 return((char*)out->_data);
2327 #endif
2329 #if SHOPT_OPTIMIZE
2330 struct optimize
2332 Namfun_t hdr;
2333 Shell_t *sh;
2334 char **ptr;
2335 struct optimize *next;
2336 Namval_t *np;
2339 static struct optimize *opt_free;
2341 static void optimize_clear(Namval_t* np, Namfun_t *fp)
2343 struct optimize *op = (struct optimize*)fp;
2344 nv_stack(np,fp);
2345 nv_stack(np,(Namfun_t*)0);
2346 for(;op && op->np==np; op=op->next)
2348 if(op->ptr)
2350 *op->ptr = 0;
2351 op->ptr = 0;
2356 static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
2358 nv_putv(np,val,flags,fp);
2359 optimize_clear(np,fp);
2362 static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
2364 return((Namfun_t*)0);
2367 static const Namdisc_t optimize_disc = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize};
2369 void nv_optimize(Namval_t *np)
2371 register Namfun_t *fp;
2372 register struct optimize *op, *xp;
2373 if(sh.argaddr)
2375 if(np==SH_LINENO)
2377 sh.argaddr = 0;
2378 return;
2380 for(fp=np->nvfun; fp; fp = fp->next)
2382 if(fp->disc && (fp->disc->getnum || fp->disc->getval))
2384 sh.argaddr = 0;
2385 return;
2387 if(fp->disc== &optimize_disc)
2388 break;
2390 if((xp= (struct optimize*)fp) && xp->ptr==sh.argaddr)
2391 return;
2392 if(op = opt_free)
2393 opt_free = op->next;
2394 else
2395 op=(struct optimize*)calloc(1,sizeof(struct optimize));
2396 op->ptr = sh.argaddr;
2397 op->np = np;
2398 if(xp)
2400 op->hdr.disc = 0;
2401 op->next = xp->next;
2402 xp->next = op;
2404 else
2406 op->hdr.disc = &optimize_disc;
2407 op->next = (struct optimize*)sh.optlist;
2408 sh.optlist = (void*)op;
2409 nv_stack(np,&op->hdr);
2414 void sh_optclear(Shell_t *shp, void *old)
2416 register struct optimize *op,*opnext;
2417 for(op=(struct optimize*)shp->optlist; op; op = opnext)
2419 opnext = op->next;
2420 if(op->ptr && op->hdr.disc)
2422 nv_stack(op->np,&op->hdr);
2423 nv_stack(op->np,(Namfun_t*)0);
2425 op->next = opt_free;
2426 opt_free = op;
2428 shp->optlist = old;
2431 #else
2432 # define optimize_clear(np,fp)
2433 #endif /* SHOPT_OPTIMIZE */
2436 * Return a pointer to a character string that denotes the value
2437 * of <np>. If <np> refers to an array, return a pointer to
2438 * the value associated with the current index.
2440 * If the value of <np> is an integer, the string returned will
2441 * be overwritten by the next call to nv_getval.
2443 * If <np> has no value, 0 is returned.
2446 char *nv_getval(register Namval_t *np)
2448 register union Value *up= &np->nvalue;
2449 register int numeric;
2450 #if SHOPT_OPTIMIZE
2451 if(!nv_local && sh.argaddr)
2452 nv_optimize(np);
2453 #endif /* SHOPT_OPTIMIZE */
2454 if((!np->nvfun || !np->nvfun->disc) && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF|NV_TABLE))
2455 goto done;
2456 if(nv_isref(np))
2458 if(!np->nvalue.cp)
2459 return(0);
2460 sh.last_table = nv_reftable(np);
2461 return(nv_name(nv_refnode(np)));
2463 if(np->nvfun && np->nvfun->disc)
2465 if(!nv_local)
2467 nv_local=1;
2468 return(nv_getv(np, np->nvfun));
2470 nv_local=0;
2472 numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
2473 if(numeric)
2475 Sflong_t ll;
2476 if(!up->cp)
2477 return("0");
2478 if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
2480 Sfdouble_t ld;
2481 double d;
2482 char *format;
2483 if(nv_isattr(np,NV_LONG))
2485 ld = *up->ldp;
2486 if(nv_isattr (np,NV_EXPNOTE))
2487 format = "%.*Lg";
2488 else if(nv_isattr (np,NV_HEXFLOAT))
2489 format = "%.*La";
2490 else
2491 format = "%.*Lf";
2492 sfprintf(sh.strbuf,format,nv_size(np),ld);
2494 else
2496 d = *up->dp;
2497 if(nv_isattr (np,NV_EXPNOTE))
2498 format = "%.*g";
2499 else if(nv_isattr (np,NV_HEXFLOAT))
2500 format = "%.*a";
2501 else
2502 format = "%.*f";
2503 sfprintf(sh.strbuf,format,nv_size(np),d);
2505 return(sfstruse(sh.strbuf));
2507 else if(nv_isattr(np,NV_UNSIGN))
2509 if(nv_isattr (np,NV_LONG))
2510 ll = *(Sfulong_t*)up->llp;
2511 else if(nv_isattr (np,NV_SHORT))
2513 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2514 ll = *(uint16_t*)(up->sp);
2515 else
2516 ll = (uint16_t)up->s;
2518 else
2519 ll = *(uint32_t*)(up->lp);
2521 else if(nv_isattr (np,NV_LONG))
2522 ll = *up->llp;
2523 else if(nv_isattr (np,NV_SHORT))
2525 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2526 ll = *up->sp;
2527 else
2528 ll = up->s;
2530 else
2531 ll = *(up->lp);
2532 if((numeric=nv_size(np))==10)
2534 if(nv_isattr(np,NV_UNSIGN))
2536 sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll);
2537 return(sfstruse(sh.strbuf));
2539 numeric = 0;
2541 return(fmtbasell(ll,numeric, numeric&&numeric!=10));
2543 done:
2544 #if (_AST_VERSION>=20030127L)
2546 * if NV_RAW flag is on, return pointer to binary data
2547 * otherwise, base64 encode the data and return this string
2549 if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
2551 char *cp;
2552 char *ep;
2553 int size= nv_size(np), insize=(4*size)/3+size/45+8;
2554 base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)&ep);
2555 *ep = 0;
2556 return(cp);
2558 #endif
2559 if((numeric=nv_size(np)) && up->cp && up->cp[numeric])
2561 char *cp = getbuf(numeric+1);
2562 memcpy(cp,up->cp,numeric);
2563 cp[numeric]=0;
2564 return(cp);
2566 return ((char*)up->cp);
2569 Sfdouble_t nv_getnum(register Namval_t *np)
2571 register union Value *up;
2572 register Sfdouble_t r=0;
2573 register char *str;
2574 #if SHOPT_OPTIMIZE
2575 if(!nv_local && sh.argaddr)
2576 nv_optimize(np);
2577 #endif /* SHOPT_OPTIMIZE */
2578 if(nv_istable(np))
2579 errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np));
2580 if(np->nvfun && np->nvfun->disc)
2582 if(!nv_local)
2584 nv_local=1;
2585 return(nv_getn(np, np->nvfun));
2587 nv_local=0;
2589 if(nv_isref(np))
2591 str = nv_refsub(np);
2592 np = nv_refnode(np);
2593 if(str)
2594 nv_putsub(np,str,0L);
2596 if(nv_isattr (np, NV_INTEGER))
2598 up= &np->nvalue;
2599 if(!up->lp || up->cp==Empty)
2600 r = 0;
2601 else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE)
2603 if(nv_isattr(np, NV_LONG))
2604 r = *up->ldp;
2605 else
2606 r = *up->dp;
2608 else if(nv_isattr(np, NV_UNSIGN))
2610 if(nv_isattr(np, NV_LONG))
2611 r = (Sflong_t)*((Sfulong_t*)up->llp);
2612 else if(nv_isattr(np, NV_SHORT))
2614 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2615 r = (Sflong_t)(*(uint16_t*)up->sp);
2616 else
2617 r = (Sflong_t)((uint16_t)up->s);
2619 else
2620 r = *((uint32_t*)up->lp);
2622 else
2624 if(nv_isattr(np, NV_LONG))
2625 r = *up->llp;
2626 else if(nv_isattr(np, NV_SHORT))
2628 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2629 r = *up->sp;
2630 else
2631 r = up->s;
2633 else
2634 r = *up->lp;
2637 else if((str=nv_getval(np)) && *str!=0)
2639 if(np->nvfun || nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
2641 while(*str=='0')
2642 str++;
2644 r = sh_arith(str);
2646 return(r);
2649 * Give <np> the attributes <newatts,> and change its current
2650 * value to conform to <newatts>. The <size> of left and right
2651 * justified fields may be given.
2653 void nv_newattr (register Namval_t *np, unsigned newatts, int size)
2655 register char *sp;
2656 register char *cp = 0;
2657 register unsigned int n;
2658 Namarr_t *ap = 0;
2659 int oldsize,oldatts;
2660 Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0;
2661 char *prefix = sh.prefix;
2662 newatts &= ~NV_NODISC;
2664 /* check for restrictions */
2665 if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD)))
2666 errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
2667 /* handle attributes that do not change data separately */
2668 n = np->nvflag;
2669 if(newatts&NV_EXPORT)
2670 nv_offattr(np,NV_IMPORT);
2671 if(((n^newatts)&NV_EXPORT))
2673 /* record changes to the environment */
2674 if(n&NV_EXPORT)
2675 env_delete(sh.env,nv_name(np));
2676 else
2677 sh_envput(sh.env,np);
2679 oldsize = nv_size(np);
2680 if((size==oldsize|| (n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
2682 if(size)
2683 nv_setsize(np,size);
2684 nv_offattr(np, ~NV_NOFREE);
2685 nv_onattr(np, newatts);
2686 return;
2688 /* for an array, change all the elements */
2689 if((ap=nv_arrayptr(np)) && ap->nelem>0)
2690 nv_putsub(np,NIL(char*),ARRAY_SCAN);
2691 oldsize = nv_size(np);
2692 oldatts = np->nvflag;
2693 if(fp)
2694 np->nvfun = 0;
2695 if(ap) /* add element to prevent array deletion */
2696 ap->nelem++;
2699 nv_setsize(np,oldsize);
2700 np->nvflag = oldatts;
2701 if (sp = nv_getval(np))
2703 if(nv_isattr(np,NV_ZFILL))
2704 while(*sp=='0') sp++;
2705 cp = (char*)malloc((n=strlen (sp)) + 1);
2706 strcpy(cp, sp);
2707 if(ap)
2709 Namval_t *mp;
2710 ap->nelem &= ~ARRAY_SCAN;
2711 if(mp=nv_opensub(np))
2713 nv_unset(mp);
2714 mp->nvalue.cp = Empty;
2716 else
2717 nv_unset(np);
2718 ap->nelem |= ARRAY_SCAN;
2720 else
2721 nv_unset(np);
2722 if(size==0 && (newatts&NV_HOST)!=NV_HOST && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
2723 size = n;
2725 else
2726 nv_unset(np);
2727 nv_setsize(np,size);
2728 np->nvflag &= NV_ARRAY;
2729 np->nvflag |= newatts;
2730 if (cp)
2732 nv_putval (np, cp, NV_RDONLY);
2733 free(cp);
2736 while(ap && nv_nextsub(np));
2737 if(fp)
2738 np->nvfun = fp;
2739 if(ap)
2740 ap->nelem--;
2741 sh.prefix = prefix;
2742 return;
2745 static char *oldgetenv(const char *string)
2747 register char c0,c1;
2748 register const char *cp, *sp;
2749 register char **av = environ;
2750 if(!string || (c0= *string)==0)
2751 return(0);
2752 if((c1=*++string)==0)
2753 c1= '=';
2754 while(cp = *av++)
2756 if(cp[0]!=c0 || cp[1]!=c1)
2757 continue;
2758 sp = string;
2759 while(*sp && *sp++ == *++cp);
2760 if(*sp==0 && *++cp=='=')
2761 return((char*)(cp+1));
2763 return(0);
2767 * This version of getenv uses the hash storage to access environment values
2769 char *sh_getenv(const char *name)
2771 assume name!=0;
2772 @*/
2774 register Namval_t *np;
2775 if(!sh.var_tree)
2777 #if 0
2778 if(name[0] == 'P' && name[1] == 'A' && name[2] == 'T' && name[3] == 'H' && name[4] == 0 || name[0] == 'L' && ((name[1] == 'C' || name[1] == 'D') && name[2] == '_' || name[1] == 'A' && name[1] == 'N') || name[0] == 'V' && name[1] == 'P' && name[2] == 'A' && name[3] == 'T' && name[4] == 'H' && name[5] == 0 || name[0] == '_' && name[1] == 'R' && name[2] == 'L' && name[3] == 'D' || name[0] == '_' && name[1] == 'A' && name[2] == 'S' && name[3] == 'T' && name[4] == '_')
2779 #endif
2780 return(oldgetenv(name));
2782 else if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
2783 return(nv_getval(np));
2784 return(0);
2787 #ifndef _NEXT_SOURCE
2789 * Some dynamic linkers will make this file see the libc getenv(),
2790 * so sh_getenv() is used for the astintercept() callback. Plain
2791 * getenv() is provided for static links.
2793 char *getenv(const char *name)
2795 return sh_getenv(name);
2797 #endif /* _NEXT_SOURCE */
2799 #undef putenv
2801 * This version of putenv uses the hash storage to assign environment values
2803 int putenv(const char *name)
2805 register Namval_t *np;
2806 if(name)
2808 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2809 if(!strchr(name,'='))
2810 nv_unset(np);
2812 return(0);
2816 * Override libast setenviron().
2818 char* sh_setenviron(const char *name)
2820 register Namval_t *np;
2821 if(name)
2823 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2824 if(strchr(name,'='))
2825 return(nv_getval(np));
2826 nv_unset(np);
2828 return("");
2832 * Same linker dance as with getenv() above.
2834 char* setenviron(const char *name)
2836 return sh_setenviron(name);
2840 * convert <str> to upper case
2842 static void ltou(register char *str)
2844 register int c;
2845 for(; c= *((unsigned char*)str); str++)
2847 if(islower(c))
2848 *str = toupper(c);
2853 * convert <str> to lower case
2855 static void utol(register char *str)
2857 register int c;
2858 for(; c= *((unsigned char*)str); str++)
2860 if(isupper(c))
2861 *str = tolower(c);
2866 * normalize <cp> and return pointer to subscript if any
2867 * if <eq> is specified, return pointer to first = not in a subscript
2869 static char *lastdot(register char *cp, int eq)
2871 register char *ep=0;
2872 register int c;
2873 if(eq)
2874 cp++;
2875 while(c= *cp++)
2877 if(c=='[')
2879 if(*cp==']')
2880 cp++;
2881 else
2882 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2884 else if(c=='.')
2886 if(*cp=='[')
2888 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2889 if((ep=sh_checkid(ep+1,cp)) < cp)
2890 cp=strcpy(ep,cp);
2892 ep = 0;
2894 else if(eq && c == '=')
2895 return(cp-1);
2897 return(eq?0:ep);
2900 int nv_rename(register Namval_t *np, int flags)
2902 Shell_t *shp = &sh;
2903 register Namval_t *mp=0,*nr=0;
2904 register char *cp;
2905 int index= -1;
2906 Namval_t *last_table = shp->last_table;
2907 Dt_t *last_root = shp->last_root;
2908 Dt_t *hp = 0;
2909 char *prefix=shp->prefix,*nvenv = 0;
2910 if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
2912 if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
2913 hp = dtvnext(shp->var_tree);
2915 if(!(cp=nv_getval(np)))
2917 if(flags&NV_MOVE)
2918 errormsg(SH_DICT,ERROR_exit(1),e_varname,"");
2919 return(0);
2921 if(lastdot(cp,0) && nv_isattr(np,NV_MINIMAL))
2922 errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np));
2923 if(nv_isarray(np) && !(mp=nv_opensub(np)))
2924 index=nv_aindex(np);
2925 shp->prefix = 0;
2926 if(!hp)
2927 hp = shp->var_tree;
2928 if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOREF|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
2929 hp = shp->var_base;
2930 else if(shp->last_root)
2931 hp = shp->last_root;
2932 if(!nr)
2933 nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL));
2934 shp->prefix = prefix;
2935 if(!nr)
2937 if(!nv_isvtree(np))
2938 _nv_unset(np,0);
2939 return(0);
2941 if(!mp && index>=0 && nv_isvtree(nr))
2943 sfprintf(shp->strbuf,"%s[%d]%c",nv_name(np),index,0);
2944 /* create a virtual node */
2945 if(mp = nv_open(sfstruse(shp->strbuf),shp->var_tree,NV_VARNAME|NV_ADD|NV_ARRAY))
2946 mp->nvenv = (void*)np;
2948 if(mp)
2950 nvenv = (char*)np;
2951 np = mp;
2953 if(nr==np)
2955 if(index<0)
2956 return(0);
2957 if(cp = nv_getval(np))
2958 cp = strdup(cp);
2960 _nv_unset(np,0);
2961 if(!nv_isattr(np,NV_MINIMAL))
2962 np->nvenv = nvenv;
2963 if(nr==np)
2965 nv_putsub(np,(char*)0, index);
2966 nv_putval(np,cp,0);
2967 free((void*)cp);
2968 return(1);
2970 shp->prev_table = shp->last_table;
2971 shp->prev_root = shp->last_root;
2972 shp->last_table = last_table;
2973 shp->last_root = last_root;
2974 nv_clone(nr,np,(flags&NV_MOVE)|NV_COMVAR);
2975 if(flags&NV_MOVE)
2976 nv_delete(nr,(Dt_t*)0,NV_NOFREE);
2977 return(1);
2981 * Create a reference node from <np> to $np in dictionary <hp>
2983 void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
2985 Shell_t *shp = &sh;
2986 register Namval_t *nq, *nr=0;
2987 register char *ep,*cp;
2988 Dt_t *root = shp->last_root;
2989 Namarr_t *ap;
2990 if(nv_isref(np))
2991 return;
2992 if(nv_isarray(np))
2993 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
2994 if(!(cp=nv_getval(np)))
2996 nv_unset(np);
2997 nv_onattr(np,NV_REF);
2998 return;
3000 if((ep = lastdot(cp,0)) && nv_isattr(np,NV_MINIMAL))
3001 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
3002 if(!hp)
3003 hp = shp->var_tree;
3004 if(!(nr = nq = nv_open(cp, hp, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
3005 hp = shp->last_root==shp->var_tree?shp->var_tree:shp->var_base;
3006 else if(shp->last_root)
3007 hp = shp->last_root;
3008 if(nq && ep && nv_isarray(nq) && !nv_getsub(nq))
3009 nv_endsubscript(nq,ep-1,NV_ADD);
3010 if(!nr)
3012 nr= nq = nv_open(cp, hp, flags);
3013 hp = shp->last_root;
3015 if(shp->last_root == shp->var_tree && root!=shp->var_tree)
3017 _nv_unset(np,NV_RDONLY);
3018 nv_onattr(np,NV_REF);
3019 errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np));
3021 if(nr==np)
3023 if(shp->namespace && nv_dict(shp->namespace)==hp)
3024 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3025 /* bind to earlier scope, or add to global scope */
3026 if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np)
3027 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3029 if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN)))
3030 ep = nv_getsub(nq);
3031 if(ep)
3033 /* cause subscript evaluation and return result */
3034 if(nv_isarray(nq))
3035 ep = nv_getsub(nq);
3036 else
3038 ep[strlen(ep)-1] = 0;
3039 nv_putsub(nr, ep, 0);
3040 ep[strlen(ep)-1] = ']';
3041 if(nq = nv_opensub(nr))
3042 ep = 0;
3043 else
3044 nq = nr;
3047 nv_unset(np);
3048 nv_delete(np,(Dt_t*)0,0);
3049 np->nvalue.nrp = newof(0,struct Namref,1,0);
3050 np->nvalue.nrp->np = nq;
3051 np->nvalue.nrp->root = hp;
3052 if(ep)
3053 np->nvalue.nrp->sub = strdup(ep);
3054 np->nvalue.nrp->table = shp->last_table;
3055 nv_onattr(np,NV_REF|NV_NOFREE);
3059 * get the scope corresponding to <index>
3060 * whence uses the same values as lseeek()
3062 Shscope_t *sh_getscope(int index, int whence)
3064 register struct sh_scoped *sp, *topmost;
3065 if(whence==SEEK_CUR)
3066 sp = &sh.st;
3067 else
3069 if ((struct sh_scoped*)sh.topscope != sh.st.self)
3070 topmost = (struct sh_scoped*)sh.topscope;
3071 else
3072 topmost = &(sh.st);
3073 sp = topmost;
3074 if(whence==SEEK_SET)
3076 int n =0;
3077 while(sp = sp->prevst)
3078 n++;
3079 index = n - index;
3080 sp = topmost;
3083 if(index < 0)
3084 return((Shscope_t*)0);
3085 while(index-- && (sp = sp->prevst));
3086 return((Shscope_t*)sp);
3090 * make <scoped> the top scope and return previous scope
3092 Shscope_t *sh_setscope(Shscope_t *scope)
3094 Shscope_t *old = (Shscope_t*)sh.st.self;
3095 *sh.st.self = sh.st;
3096 sh.st = *((struct sh_scoped*)scope);
3097 sh.var_tree = scope->var_tree;
3098 SH_PATHNAMENOD->nvalue.cp = sh.st.filename;
3099 SH_FUNNAMENOD->nvalue.cp = sh.st.funname;
3100 return(old);
3103 void sh_unscope(Shell_t *shp)
3105 register Dt_t *root = shp->var_tree;
3106 register Dt_t *dp = dtview(root,(Dt_t*)0);
3107 table_unset(shp,root,NV_RDONLY|NV_NOSCOPE,dp);
3108 if(shp->st.real_fun && dp==shp->st.real_fun->sdict)
3110 dp = dtview(dp,(Dt_t*)0);
3111 shp->st.real_fun->sdict->view = dp;
3113 shp->var_tree=dp;
3114 dtclose(root);
3118 * The inverse of creating a reference node
3120 void nv_unref(register Namval_t *np)
3122 Namval_t *nq;
3123 if(!nv_isref(np))
3124 return;
3125 nv_offattr(np,NV_NOFREE|NV_REF);
3126 if(!np->nvalue.nrp)
3127 return;
3128 nq = nv_refnode(np);
3129 free((void*)np->nvalue.nrp);
3130 np->nvalue.cp = strdup(nv_name(nq));
3131 #if SHOPT_OPTIMIZE
3133 Namfun_t *fp;
3134 for(fp=nq->nvfun; fp; fp = fp->next)
3136 if(fp->disc== &optimize_disc)
3138 optimize_clear(nq,fp);
3139 return;
3143 #endif
3147 * These following are for binary compatibility with the old hash library
3148 * They will be removed someday
3151 #if defined(__IMPORT__) && defined(__EXPORT__)
3152 # define extern __EXPORT__
3153 #endif
3155 #undef hashscope
3157 extern Dt_t *hashscope(Dt_t *root)
3159 return(dtvnext(root));
3162 #undef hashfree
3164 extern Dt_t *hashfree(Dt_t *root)
3166 Dt_t *dp = dtvnext(root);
3167 dtclose(root);
3168 return(dp);
3171 #undef hashname
3173 extern char *hashname(void *obj)
3175 Namval_t *np = (Namval_t*)obj;
3176 return(np->nvname);
3179 #undef hashlook
3181 extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
3183 NOT_USED(size);
3184 return((void*)nv_search(name,root,mode));
3187 char *nv_name(register Namval_t *np)
3189 register Namval_t *table;
3190 register Namfun_t *fp;
3191 char *cp;
3192 if(is_abuiltin(np) || is_afunction(np))
3193 return(np->nvname);
3194 if(!nv_isattr(np,NV_MINIMAL|NV_EXPORT) && np->nvenv)
3196 Namval_t *nq= sh.last_table, *mp= (Namval_t*)np->nvenv;
3197 if(np==sh.last_table)
3198 sh.last_table = 0;
3199 if(nv_isarray(mp))
3200 sfprintf(sh.strbuf,"%s[%s]",nv_name(mp),np->nvname);
3201 else
3202 sfprintf(sh.strbuf,"%s.%s",nv_name(mp),np->nvname);
3203 sh.last_table = nq;
3204 return(sfstruse(sh.strbuf));
3206 if(nv_istable(np))
3207 #if 1
3208 sh.last_table = nv_parent(np);
3209 #else
3210 sh.last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0);
3211 #endif
3212 else if(!nv_isref(np))
3214 for(fp= np->nvfun ; fp; fp=fp->next)
3215 if(fp->disc && fp->disc->namef)
3217 if(np==sh.last_table)
3218 sh.last_table = 0;
3219 return((*fp->disc->namef)(np,fp));
3222 if(!(table=sh.last_table) || *np->nvname=='.' || table==sh.namespace || np==table)
3223 return(np->nvname);
3224 cp = nv_name(table);
3225 sfprintf(sh.strbuf,"%s.%s",cp,np->nvname);
3226 return(sfstruse(sh.strbuf));
3229 Namval_t *nv_lastdict(void)
3231 return(sh.last_table);
3234 #undef nv_context
3236 * returns the data context for a builtin
3238 void *nv_context(Namval_t *np)
3240 return((void*)np->nvfun);
3243 #define DISABLE /* proto workaround */
3245 int nv_isnull DISABLE (register Namval_t *np)
3247 return(nv_isnull(np));
3250 #undef nv_setsize
3251 int nv_setsize(register Namval_t *np, int size)
3253 int oldsize = nv_size(np);
3254 if(size>=0)
3255 np->nvsize = size;
3256 return(oldsize);
3259 Shell_t *nv_shell(Namval_t *np)
3261 Namfun_t *fp;
3262 for(fp=np->nvfun;fp;fp=fp->next)
3264 if(!fp->disc)
3265 return((Shell_t*)fp->last);
3267 return(0);
3270 #undef nv_unset
3272 void nv_unset(register Namval_t *np)
3274 _nv_unset(np,0);
3275 return;