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
21 /*
22 * AT&T Labs
23 *
24 */
25
26 #define putenv ___putenv
27
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"
35
36 #define NVCACHE 8 /* must be a power of 2 */
37 #define Empty ((char*)(e_sptbnl+3))
38 static char *savesub = 0;
39
40 #if !_lib_pathnative && _lib_uwin_path
41
42 #define _lib_pathnative 1
43
44 extern int uwin_path(const char*, char*, int);
45
46 size_t
pathnative(const char * path,char * buf,size_t siz)47 pathnative(const char* path, char* buf, size_t siz)
48 {
49 return uwin_path(path, buf, siz);
50 }
51
52 #endif /* _lib_pathnative */
53
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);
63
64 struct adata
65 {
66 Shell_t *sh;
67 Namval_t *tp;
68 char **argnam;
69 int attsize;
70 char *attval;
71 };
72
73 #if SHOPT_TYPEDEF
74 struct sh_type
75 {
76 void *previous;
77 Namval_t **nodes;
78 Namval_t *rp;
79 short numnodes;
80 short maxnodes;
81 };
82 #endif /*SHOPT_TYPEDEF */
83
84 #if NVCACHE
85 struct Namcache
86 {
87 struct Cache_entry
88 {
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;
100 };
101 static struct Namcache nvcache;
102 #endif
103
104 char nv_local = 0;
105 #ifndef _ENV_H
106 static void(*nullscan)(Namval_t*,void*);
107 #endif
108
109 #if ( SFIO_VERSION <= 20010201L )
110 # define _data data
111 #endif
112
113 #if !SHOPT_MULTIBYTE
114 # define mbchar(p) (*(unsigned char*)p++)
115 #endif /* SHOPT_MULTIBYTE */
116
117 /* ======== name value pair routines ======== */
118
119 #include "shnodes.h"
120 #include "builtins.h"
121
getbuf(size_t len)122 static char *getbuf(size_t len)
123 {
124 static char *buf;
125 static size_t buflen;
126 if(buflen < len)
127 {
128 if(buflen==0)
129 buf = (char*)malloc(len);
130 else
131 buf = (char*)realloc(buf,len);
132 buflen = len;
133 }
134 return(buf);
135 }
136
137 #ifdef _ENV_H
sh_envput(Env_t * ep,Namval_t * np)138 void sh_envput(Env_t* ep,Namval_t *np)
139 {
140 int offset = staktell();
141 Namarr_t *ap = nv_arrayptr(np);
142 char *val;
143 if(ap)
144 {
145 if(ap->nelem&ARRAY_UNDEF)
146 nv_putsub(np,"0",0L);
147 else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
148 return;
149 }
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);
157 }
158 #endif
159
160 /*
161 * output variable name in format for re-input
162 */
nv_outname(Sfio_t * out,char * name,int len)163 void nv_outname(Sfio_t *out, char *name, int len)
164 {
165 const char *cp=name, *sp;
166 int c, offset = staktell();
167 while(sp= strchr(cp,'['))
168 {
169 if(len>0 && cp+len <= sp)
170 break;
171 sfwrite(out,cp,++sp-cp);
172 stakseek(offset);
173 while(c= *sp++)
174 {
175 if(c==']')
176 break;
177 else if(c=='\\')
178 {
179 if(*sp=='[' || *sp==']' || *sp=='\\')
180 c = *sp++;
181 }
182 stakputc(c);
183 }
184 stakputc(0);
185 sfputr(out,sh_fmtq(stakptr(offset)),-1);
186 if(len>0)
187 {
188 sfputc(out,']');
189 return;
190 }
191 cp = sp-1;
192 }
193 if(*cp)
194 {
195 if(len>0)
196 sfwrite(out,cp,len);
197 else
198 sfputr(out,cp,-1);
199 }
200 stakseek(offset);
201 }
202
203 #if SHOPT_TYPEDEF
nv_addnode(Namval_t * np,int remove)204 Namval_t *nv_addnode(Namval_t* np, int remove)
205 {
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)
210 {
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);
216 }
217 if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
218 {
219 name = (sp->nodes[0])->nvname;
220 i = strlen(name);
221 if(memcmp(np->nvname,name,i))
222 return(np);
223 }
224 if(sp->rp && sp->numnodes)
225 {
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
230 {
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);
235 }
236 }
237 for(i=0; i < sp->numnodes; i++)
238 {
239 if(np == sp->nodes[i])
240 {
241 if(remove)
242 {
243 while(++i < sp->numnodes)
244 sp->nodes[i-1] = sp->nodes[i];
245 sp->numnodes--;
246 }
247 return(np);
248 }
249 }
250 if(remove)
251 return(np);
252 if(sp->numnodes==sp->maxnodes)
253 {
254 sp->maxnodes += 20;
255 sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
256 }
257 sp->nodes[sp->numnodes++] = np;
258 return(np);
259 }
260 #endif /* SHOPT_TYPEDEF */
261
262 /*
263 * given a list of assignments, determine <name> is on the list
264 returns a pointer to the argnod on the list or NULL
265 */
nv_onlist(struct argnod * arg,const char * name)266 struct argnod *nv_onlist(struct argnod *arg, const char *name)
267 {
268 char *cp;
269 int len = strlen(name);
270 for(;arg; arg=arg->argnxt.ap)
271 {
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);
278 }
279 return(0);
280 }
281
282 /*
283 * Perform parameter assignment for a linked list of parameters
284 * <flags> contains attributes for the parameters
285 */
nv_setlist(register struct argnod * arg,register int flags,Namval_t * typ)286 void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
287 {
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)
302 {
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*));
309 }
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)
315 {
316 flags &= ~(NV_IDENT|NV_EXPORT);
317 flags |= NV_VARNAME;
318 }
319 for(;arg; arg=arg->argnxt.ap)
320 {
321 shp->used_pos = 0;
322 if(arg->argflag&ARG_MAC)
323 {
324 shp->prefix = 0;
325 cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
326 shp->prefix = prefix;
327 }
328 else
329 {
330 stakseek(0);
331 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
332 {
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=='[')
348 {
349 shp->prefix = 0;
350 np = nv_open(prefix,shp->var_tree,flag);
351 shp->prefix = prefix;
352 if(np)
353 {
354 if(nv_isvtree(np) && !nv_isarray(np))
355 {
356 stakputc('.');
357 stakputs(cp);
358 cp = stakfreeze(1);
359 }
360 nv_close(np);
361 }
362 }
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))
373 {
374 if(!(arg->argflag&ARG_APPEND))
375 nv_unset(np);
376 if(array&NV_ARRAY)
377 {
378 nv_setarray(np,nv_associative);
379 }
380 else
381 {
382 nv_onattr(np,NV_ARRAY);
383 }
384 }
385 if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg)
386 {
387 #if SHOPT_TYPEDEF
388 goto check_type;
389 #else
390 continue;
391 #endif /* SHOPT_TYPEDEF */
392 }
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)))
395 {
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])
402 {
403 shp->mktype = 0;
404 errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]);
405 }
406 #endif /* SHOPT_TYPEDEF */
407 if(!(arg->argflag&ARG_APPEND))
408 {
409 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK)))
410 nv_unset(np);
411 }
412 nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
413 if(traceon || trap)
414 {
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)
422 {
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);
429 }
430 }
431 #if SHOPT_TYPEDEF
432 goto check_type;
433 #else
434 continue;
435 #endif /* SHOPT_TYPEDEF */
436 }
437 if((tp->tre.tretyp&COMMSK)==TFUN)
438 goto skip;
439 if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
440 {
441 if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap)
442 {
443 if(prefix)
444 cp = stakcopy(nv_name(np));
445 shp->prefix = cp;
446 if(tp->com.comset->argval[1]=='[')
447 {
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);
452 }
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 */
463 }
464 if(*cp!='.' && *cp!='[' && strchr(cp,'['))
465 {
466 nv_close(np);
467 np = nv_open(cp,shp->var_tree,flag);
468 }
469 if(arg->argflag&ARG_APPEND)
470 {
471 if(nv_isarray(np))
472 {
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++;
477 }
478 if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np))
479 sub=1;
480 }
481 else if(np->nvalue.cp && np->nvalue.cp!=Empty && !nv_type(np))
482 {
483 _nv_unset(np,NV_EXPORT);
484 }
485 }
486 else
487 {
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);
492 }
493 skip:
494 if(sub>0)
495 {
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);
499 }
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)
506 {
507 if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD))
508 {
509 sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1);
510 shp->prefix = stkfreeze(stkstd,1);
511 }
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;
520 }
521 sh_exec(tp,sh_isstate(SH_ERREXIT));
522 #if SHOPT_TYPEDEF
523 if(shp->prefix)
524 #endif
525 {
526 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
527 L_ARGNOD->nvflag = node.nvflag;
528 L_ARGNOD->nvfun = node.nvfun;
529 }
530 shp->prefix = prefix;
531 if(nv_isarray(np) && (mp=nv_opensub(np)))
532 np = mp;
533 while(tp->tre.tretyp==TLST)
534 {
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;
538
539 }
540 if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='['))
541 {
542 nv_setvtree(np);
543 if(tp->com.comarg || tp->com.comset)
544 np->nvfun->dsize = 0;
545 }
546 #if SHOPT_TYPEDEF
547 goto check_type;
548 #else
549 continue;
550 #endif /* SHOPT_TYPEDEF */
551 }
552 cp = arg->argval;
553 mp = 0;
554 }
555 np = nv_open(cp,shp->var_tree,flags);
556 if(!np->nvfun && (flags&NV_NOREF))
557 {
558 if(shp->used_pos)
559 nv_onattr(np,NV_PARAM);
560 else
561 nv_offattr(np,NV_PARAM);
562 }
563 if(traceon || trap)
564 {
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,'='))
572 {
573 if(cp[-1]=='+')
574 append = ARG_APPEND;
575 cp++;
576 }
577 if(traceon)
578 {
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)
584 {
585 if(append)
586 sfputc(sfstderr,'+');
587 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
588 }
589 }
590 if(trap)
591 {
592 char *av[2];
593 av[0] = cp;
594 av[1] = 0;
595 sh_debug(shp,trap,name,sub,av,append);
596 }
597 }
598 #if SHOPT_TYPEDEF
599 check_type:
600 if(maketype)
601 {
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)
609 {
610 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
611 L_ARGNOD->nvflag = node.nvflag;
612 L_ARGNOD->nvfun = node.nvfun;
613 }
614 }
615 #endif /* SHOPT_TYPEDEF */
616 }
617 }
618
619 /*
620 * copy the subscript onto the stack
621 */
stak_subscript(const char * sub,int last)622 static void stak_subscript(const char *sub, int last)
623 {
624 register int c;
625 stakputc('[');
626 while(c= *sub++)
627 {
628 if(c=='[' || c==']' || c=='\\')
629 stakputc('\\');
630 stakputc(c);
631 }
632 stakputc(last);
633 }
634
635 /*
636 * construct a new name from a prefix and base name on the stack
637 */
copystack(const char * prefix,register const char * name,const char * sub)638 static char *copystack(const char *prefix, register const char *name, const char *sub)
639 {
640 register int last=0,offset = staktell();
641 if(prefix)
642 {
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('.');
652 }
653 if(last)
654 {
655 stakputs(name);
656 if(sh_checkid(stakptr(last),(char*)0))
657 stakseek(staktell()-2);
658 }
659 if(sub)
660 stak_subscript(sub,']');
661 if(!last)
662 stakputs(name);
663 stakputc(0);
664 return(stakptr(offset));
665 }
666
667 /*
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
670 */
stack_extend(const char * cname,char * cp,int n)671 static char *stack_extend(const char *cname, char *cp, int n)
672 {
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);
683 }
684
nv_create(const char * name,Dt_t * root,int flags,Namfun_t * dp)685 Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp)
686 {
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)
695 {
696 if(dtvnext(root))
697 top = 1;
698 else
699 flags &= ~NV_NOSCOPE;
700 }
701 if(!dp->disc)
702 copy = dp->nofree&1;
703 if(*cp=='.')
704 cp++;
705 while(1)
706 {
707 switch(c = *(unsigned char*)(sp = cp))
708 {
709 case '[':
710 if(flags&NV_NOARRAY)
711 {
712 dp->last = cp;
713 return(np);
714 }
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))
725 {
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 = '.';
733 }
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)
746 {
747 struct Ufunction *rp;
748 if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC))
749 {
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);
754 }
755 if(np = nv_search(name,shp->var_tree,0))
756 {
757 if(shp->var_tree->walk == shp->var_base)
758 {
759 nq = np;
760 if((flags&NV_NOSCOPE) && *cp!='.')
761 {
762 if(mode==0)
763 root = shp->var_base;
764 else
765 {
766 nv_delete(np,(Dt_t*)0,0);
767 np = 0;
768 }
769 }
770 }
771 else
772 {
773 root = shp->var_tree->walk;
774 flags |= NV_NOSCOPE;
775 noscope = 1;
776 }
777 }
778 if(rp && rp->sdict && (flags&NV_STATIC))
779 {
780 root = rp->sdict;
781 if(np && shp->var_tree->walk==shp->var_tree)
782 {
783 _nv_unset(np,0);
784 nv_delete(np,shp->var_tree,0);
785 np = 0;
786 }
787 if(!np || shp->var_tree->walk!=root)
788 np = nv_search(name,root,HASH_NOSCOPE|NV_ADD);
789 }
790 }
791 if(np || (np = nv_search(name,root,mode)))
792 {
793 isref = nv_isref(np);
794 if(top)
795 {
796 if(nq==np)
797 {
798 flags &= ~NV_NOSCOPE;
799 root = shp->var_base;
800 }
801 else if(nq)
802 {
803 if(nv_isnull(np) && c!='.' && (np->nvfun=nv_cover(nq)))
804 np->nvname = nq->nvname;
805 flags |= NV_NOSCOPE;
806 }
807 }
808 else if(add && nv_isnull(np) && c=='.' && cp[1]!='.')
809 nv_setvtree(np);
810 }
811 if(c)
812 *sp = c;
813 top = 0;
814 if(isref)
815 {
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!='.'))
823 {
824 if(c && !(flags&NV_NOADD))
825 nv_unref(np);
826 return(np);
827 }
828 while(nv_isref(np) && np->nvalue.cp)
829 {
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;
839 }
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)
847 {
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;
857 }
858 flags |= NV_NOREF;
859 if(nv_isnull(np))
860 nv_onattr(np,NV_NOFREE);
861
862 }
863 shp->last_root = root;
864 if(*cp && cp[1]=='.')
865 cp++;
866 if(c=='.' && (cp[1]==0 || cp[1]=='=' || cp[1]=='+'))
867 {
868 nv_local = 1;
869 return(np);
870 }
871 if(cp[-1]=='.')
872 cp--;
873 do
874 {
875 if(!np)
876 {
877 if(!nq && *sp=='[' && *cp==0 && cp[-1]==']')
878 {
879 /*
880 * for backward compatibility
881 * evaluate subscript for
882 * possible side effects
883 */
884 cp[-1] = 0;
885 sh_arith(sp+1);
886 cp[-1] = ']';
887 }
888 return(np);
889 }
890 if(c=='[' || (c=='.' && nv_isarray(np)))
891 {
892 char *sub=0;
893 int n = 0;
894 mode &= ~HASH_NOSCOPE;
895 if(c=='[')
896 {
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]==']')
903 {
904 /* not implemented yet */
905 dp->last = cp;
906 return(np);
907 }
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
917 }
918 else
919 cp = sp;
920 if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || (flags&NV_ARRAY))
921
922 {
923 int m = cp-sp;
924 sub = m?nv_getsub(np):0;
925 if(!sub)
926 {
927 if(m && !(n&NV_ADD))
928 return(0);
929 sub = "0";
930 }
931 n = strlen(sub)+2;
932 if(!copy)
933 {
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;
939 }
940 if(n <= m)
941 {
942 if(n)
943 {
944 memcpy(sp+1,sub,n-2);
945 sp[n-1] = ']';
946 }
947 if(n < m)
948 cp=strcpy(sp+n,cp);
949 }
950 else
951 {
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;
960
961 }
962 }
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))))
966 {
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;
975 }
976 dp->last = cp;
977 if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
978 {
979 sp = cp;
980 if(!(nq = nv_opensub(np)))
981 {
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))
987 {
988 nv_putsub(np,sub,ARRAY_FILL);
989 ap = nv_arrayptr(np);
990 }
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);
997 }
998 if(nq)
999 {
1000 if(c=='.' && !nv_isvtree(nq))
1001 {
1002 if(flags&NV_NOADD)
1003 return(0);
1004 nv_setvtree(nq);
1005 }
1006 np = nq;
1007 }
1008 else if(memcmp(cp,"[0]",3))
1009 return(nq);
1010 else
1011 {
1012 /* ignore [0] */
1013 dp->last = cp += 3;
1014 c = *cp;
1015 }
1016 }
1017 }
1018 else if(nv_isarray(np))
1019 {
1020 if(c==0 && (flags&NV_MOVE))
1021 return(np);
1022 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1023 }
1024 if(c=='.' && (fp=np->nvfun))
1025 {
1026 for(; fp; fp=fp->next)
1027 {
1028 if(fp->disc && fp->disc->createf)
1029 break;
1030 }
1031 if(fp)
1032 {
1033 if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
1034 {
1035 add = NV_ADD;
1036 shp->last_table = 0;
1037 break;
1038 }
1039 else if(np=nq)
1040 {
1041 if((c = *(sp=cp=dp->last=fp->last))==0)
1042 {
1043 if(nv_isarray(np) && sp[-1]!=']')
1044 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1045 return(np);
1046 }
1047 }
1048 }
1049 }
1050 }
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;
1062 }
1063 }
1064 return(np);
1065 }
1066
1067 /*
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
1071 */
nv_delete(Namval_t * np,Dt_t * root,int flags)1072 void nv_delete(Namval_t* np, Dt_t *root, int flags)
1073 {
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])
1078 {
1079 if(xp->np==np)
1080 xp->root = 0;
1081 }
1082 #endif
1083 if(root)
1084 {
1085 if(dtdelete(root,np))
1086 {
1087 if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
1088 free((void*)np);
1089 }
1090 #if 0
1091 else
1092 {
1093 sfprintf(sfstderr,"%s not deleted\n",nv_name(np));
1094 sfsync(sfstderr);
1095 }
1096 #endif
1097 }
1098 }
1099
1100 /*
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
1114 */
nv_open(const char * name,Dt_t * root,int flags)1115 Namval_t *nv_open(const char *name, Dt_t *root, int flags)
1116 {
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
1130
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)
1138 {
1139 flags |= NV_NOREF;
1140 msg = e_badfun;
1141 if((np=shp->namespace) || strchr(name,'.'))
1142 {
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;
1150 }
1151 }
1152 else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
1153 {
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))
1159 {
1160 while(nv_isref(np))
1161 {
1162 shp->last_table = nv_reftable(np);
1163 np = nv_refnode(np);
1164 }
1165 }
1166 return(np);
1167 }
1168 else if(shp->prefix && (flags&NV_ASSIGN))
1169 {
1170 name = cp = copystack(shp->prefix,name,(const char*)0);
1171 fun.nofree |= 1;
1172 }
1173 c = *(unsigned char*)cp;
1174 if(root==shp->alias_tree)
1175 {
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;
1187 }
1188 else if(flags&NV_IDENT)
1189 msg = e_ident;
1190 else if(c=='.')
1191 {
1192 c = *++cp;
1193 flags |= NV_NOREF;
1194 if(root==shp->var_tree)
1195 root = shp->var_base;
1196 shp->last_table = 0;
1197 }
1198 if(c= !isaletter(c))
1199 goto skip;
1200 #if NVCACHE
1201 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
1202 {
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]=='+'))
1206 {
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;
1215 }
1216 }
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]!=']')
1223 {
1224 xp = &nvcache.entries[nvcache.index];
1225 if(*cp)
1226 {
1227 char *sp = strchr(name,*cp);
1228 if(!sp)
1229 goto nocache;
1230 xp->len = sp-name;
1231 }
1232 else
1233 xp->len = strlen(name);
1234 c = roundof(xp->len+1,32);
1235 if(c > xp->size)
1236 {
1237 if(xp->size==0)
1238 xp->name = malloc(c);
1239 else
1240 xp->name = realloc(xp->name,c);
1241 xp->size = c;
1242 }
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);
1251 }
1252 nocache:
1253 nvcache.ok = 0;
1254 #endif
1255 if(fname)
1256 {
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;
1261 }
1262 else
1263 {
1264 if(*cp=='.' && cp[1]=='.')
1265 {
1266 append |= NV_NODISC;
1267 cp+=2;
1268 }
1269 if(*cp=='+' && cp[1]=='=')
1270 {
1271 append |= NV_APPEND;
1272 cp++;
1273 }
1274 }
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))
1282 {
1283 cp++;
1284 if(sh_isstate(SH_INIT))
1285 {
1286 nv_putval(np, cp, NV_RDONLY);
1287 if(np==PWDNOD)
1288 nv_onattr(np,NV_TAGGED);
1289 }
1290 else
1291 {
1292 char *sub=0, *prefix= shp->prefix;
1293 int isref;
1294 shp->prefix = 0;
1295 if((flags&NV_STATIC) && !shp->mktype)
1296 {
1297 if(!nv_isnull(np))
1298 {
1299 shp->prefix = prefix;
1300 return(np);
1301 }
1302 }
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))
1310 {
1311 nv_offattr(np,NV_LJUST|NV_RJUST|NV_ZFILL);
1312 np->nvsize = 0;
1313 }
1314 nv_putval(np, cp, c);
1315 if(isref)
1316 {
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);
1320 }
1321 savesub = sub;
1322 shp->prefix = prefix;
1323 }
1324 nv_onattr(np, flags&NV_ATTRIBUTES);
1325 }
1326 else if(c)
1327 {
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);
1335 }
1336 if(fun.nofree&1)
1337 stakseek(offset);
1338 return(np);
1339 }
1340
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 */
1347
1348 /*
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
1356 */
nv_putval(register Namval_t * np,const char * string,int flags)1357 void nv_putval(register Namval_t *np, const char *string, int flags)
1358 {
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
1370 */
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))
1375 {
1376 /* This function contains disc */
1377 if(!nv_local)
1378 {
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;
1384 }
1385 /* called from disc, assign the actual value */
1386 }
1387 flags &= ~NV_NODISC;
1388 nv_local=0;
1389 if(flags&(NV_NOREF|NV_NOFREE))
1390 {
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;
1396 }
1397 up= &np->nvalue;
1398 if(nv_isattr(np,NV_INT16P) == NV_INT16)
1399 {
1400 if(!np->nvalue.up || !nv_isarray(np))
1401 {
1402 up = &u;
1403 up->up = &np->nvalue;
1404 }
1405 }
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))
1413 {
1414 if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE)
1415 {
1416 if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
1417 {
1418 Sfdouble_t ld, old=0;
1419 if(flags&NV_INTEGER)
1420 {
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);
1427 }
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;
1435 }
1436 else
1437 {
1438 double d,od=0;
1439 if(flags&NV_INTEGER)
1440 {
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;
1447 }
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;
1455 }
1456 }
1457 else
1458 {
1459 if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
1460 {
1461 Sflong_t ll=0,oll=0;
1462 if(flags&NV_INTEGER)
1463 {
1464 if((flags&NV_DOUBLE) == NV_DOUBLE)
1465 {
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);
1472 }
1473 else if(nv_isattr(np,NV_UNSIGN))
1474 {
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);
1481 }
1482 else
1483 {
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);
1490 }
1491 }
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;
1499 }
1500 else
1501 {
1502 int32_t l=0,ol=0;
1503 if(flags&NV_INTEGER)
1504 {
1505 if((flags&NV_DOUBLE) == NV_DOUBLE)
1506 {
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;
1515 }
1516 else if(nv_isattr(np,NV_UNSIGN))
1517 {
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;
1524 }
1525 else
1526 {
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;
1533 }
1534 }
1535 else if(sp)
1536 {
1537 Sfdouble_t ld = sh_arith(sp);
1538 if(ld<0)
1539 l = (int32_t)ld;
1540 else
1541 l = (uint32_t)ld;
1542 }
1543 if(nv_size(np) <= 1)
1544 nv_setsize(np,10);
1545 if(nv_isattr (np, NV_SHORT))
1546 {
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);
1552 }
1553 else
1554 {
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;
1560 }
1561 }
1562 }
1563 }
1564 else
1565 {
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)
1572 {
1573 if((flags&NV_DOUBLE)==NV_DOUBLE)
1574 {
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));
1579 }
1580 else if(flags&NV_UNSIGN)
1581 {
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)));
1586 }
1587 else
1588 {
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)));
1593 }
1594 sp = sfstruse(sh.strbuf);
1595 }
1596 if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp)
1597 {
1598 #ifdef _lib_pathnative
1599 /*
1600 * return the host file name given the UNIX name
1601 */
1602 pathnative(sp,buff,sizeof(buff));
1603 if(buff[1]==':' && buff[2]=='/')
1604 {
1605 buff[2] = '\\';
1606 if(*buff>='A' && *buff<='Z')
1607 *buff += 'a'-'A';
1608 }
1609 sp = buff;
1610 #else
1611 ;
1612 #endif /* _lib_pathnative */
1613 }
1614 else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
1615 {
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 */
1624 }
1625 if(!up->cp)
1626 flags &= ~NV_APPEND;
1627 if((flags&NV_APPEND) && !nv_isattr(np,NV_BINARY))
1628 {
1629 offset = staktell();
1630 stakputs(up->cp);
1631 stakputs(sp);
1632 stakputc(0);
1633 sp = stakptr(offset);
1634 }
1635 if(!nv_isattr(np, NV_NOFREE))
1636 {
1637 /* delay free in case <sp> points into free region */
1638 tofree = up->cp;
1639 }
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)
1645 {
1646 dot = strlen(sp);
1647 #if (_AST_VERSION>=20030127L)
1648 if(nv_isattr(np,NV_BINARY))
1649 {
1650 int oldsize = (flags&NV_APPEND)?nv_size(np):0;
1651 if(flags&NV_RAW)
1652 {
1653 if(tofree)
1654 {
1655 free((void*)tofree);
1656 nv_offattr(np,NV_NOFREE);
1657 }
1658 up->cp = sp;
1659 return;
1660 }
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((void*)&cp[dot],0,size-dot);
1679 return;
1680 }
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))
1690 {
1691 cp = (char*)malloc(((unsigned)dot+1));
1692 cp[dot] = 0;
1693 nv_offattr(np,NV_NOFREE);
1694 }
1695
1696 }
1697 else
1698 cp = 0;
1699 up->cp = cp;
1700 if(sp)
1701 {
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)
1715 {
1716 register char *dp;
1717 dp = strlen (cp) + cp;
1718 cp = cp+size;
1719 for (; dp < cp; *dp++ = ' ');
1720 }
1721 #if SHOPT_MULTIBYTE
1722 /* restore original string */
1723 if(savep)
1724 ja_restore();
1725 #endif /* SHOPT_MULTIBYTE */
1726 }
1727 if(flags&NV_APPEND)
1728 stakseek(offset);
1729 if(tofree && tofree!=Empty)
1730 free((void*)tofree);
1731 }
1732 if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1733 sh_envput(sh.env,np);
1734 return;
1735 }
1736
1737 /*
1738 *
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.
1743 *
1744 * If the leftmost digit in <str> is not a digit, <fill>
1745 * will default to a blank.
1746 */
rightjust(char * str,int size,int fill)1747 static void rightjust(char *str, int size, int fill)
1748 {
1749 register int n;
1750 register char *cp,*sp;
1751 n = strlen(str);
1752
1753 /* ignore trailing blanks */
1754 for(cp=str+n;n && *--cp == ' ';n--);
1755 if (n == size)
1756 return;
1757 if(n > size)
1758 {
1759 *(str+n) = 0;
1760 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
1761 return;
1762 }
1763 else *(sp = str+size) = 0;
1764 if (n == 0)
1765 {
1766 while (sp > str)
1767 *--sp = ' ';
1768 return;
1769 }
1770 while(n--)
1771 {
1772 sp--;
1773 *sp = *cp--;
1774 }
1775 if(!isdigit(*str))
1776 fill = ' ';
1777 while(sp>str)
1778 *--sp = fill;
1779 return;
1780 }
1781
1782 #if SHOPT_MULTIBYTE
1783 /*
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
1789 */
1790
ja_size(char * str,int size,int type)1791 static int ja_size(char *str,int size,int type)
1792 {
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)
1800 {
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;
1810 }
1811 /* check for right justified fields that need truncating */
1812 if(size <0)
1813 {
1814 if(type==0)
1815 {
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--)
1822 {
1823 savechars[size] = cp[size];
1824 cp[size] = ' ';
1825 }
1826 savep = cp;
1827 }
1828 size = -size;
1829 if(type)
1830 n -= (ja_size(str,size,0)-size);
1831 }
1832 return(n);
1833 }
1834
ja_restore(void)1835 static void ja_restore(void)
1836 {
1837 register char *cp = savechars;
1838 while(*cp)
1839 *savep++ = *cp++;
1840 savep = 0;
1841 }
1842 #endif /* SHOPT_MULTIBYTE */
1843
1844 #ifndef _ENV_H
staknam(register Namval_t * np,char * value)1845 static char *staknam(register Namval_t *np, char *value)
1846 {
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)
1851 {
1852 *p++ = '=';
1853 strcpy(p,value);
1854 }
1855 return(q);
1856 }
1857 #endif
1858
1859 /*
1860 * put the name and attribute into value of attributes variable
1861 */
1862 #ifdef _ENV_H
attstore(register Namval_t * np,void * data)1863 static void attstore(register Namval_t *np, void *data)
1864 {
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)
1872 {
1873 /* export doubles as integers for ksh88 compatibility */
1874 stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)));
1875 }
1876 else
1877 {
1878 stakputc(c+flag);
1879 if(flag&NV_INTEGER)
1880 c += nv_size(np);
1881 }
1882 stakputc(c);
1883 stakputs(nv_name(np));
1884 }
1885 #else
attstore(register Namval_t * np,void * data)1886 static void attstore(register Namval_t *np, void *data)
1887 {
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)
1897 {
1898 /* export doubles as integers for ksh88 compatibility */
1899 *ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE));
1900 *ap->attval = ' ';
1901 }
1902 else
1903 {
1904 *ap->attval++ = ' '+flag;
1905 if(flag&NV_INTEGER)
1906 *ap->attval = ' ' + nv_size(np);
1907 else
1908 *ap->attval = ' ';
1909 }
1910 ap->attval = strcopy(++ap->attval,nv_name(np));
1911 }
1912 #endif
1913
1914 #ifndef _ENV_H
pushnam(Namval_t * np,void * data)1915 static void pushnam(Namval_t *np, void *data)
1916 {
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);
1927 }
1928 #endif
1929
1930 /*
1931 * Generate the environment list for the child.
1932 */
1933
1934 #ifdef _ENV_H
sh_envgen(void)1935 char **sh_envgen(void)
1936 {
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);
1950 }
1951 #else
sh_envgen(void)1952 char **sh_envgen(void)
1953 {
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);
1979 }
1980 #endif
1981
1982 struct scan
1983 {
1984 void (*scanfn)(Namval_t*, void*);
1985 int scanmask;
1986 int scanflags;
1987 int scancount;
1988 void *scandata;
1989 };
1990
scanfilter(Dt_t * dict,void * arg,void * data)1991 static int scanfilter(Dt_t *dict, void *arg, void *data)
1992 {
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)))
2003 {
2004 if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT))
2005 return(0);
2006 if(sp->scanfn)
2007 {
2008 if(nv_isarray(np))
2009 nv_putsub(np,NIL(char*),0L);
2010 (*sp->scanfn)(np,sp->scandata);
2011 }
2012 sp->scancount++;
2013 }
2014 return(0);
2015 }
2016
2017 /*
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
2024 */
nv_scan(Dt_t * root,void (* fn)(Namval_t *,void *),void * data,int mask,int flags)2025 int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
2026 {
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);
2042 }
2043
2044 /*
2045 * create a new environment scope
2046 */
sh_scope(Shell_t * shp,struct argnod * envlist,int fun)2047 void sh_scope(Shell_t *shp, struct argnod *envlist, int fun)
2048 {
2049 register Dt_t *newscope, *newroot=shp->var_base;
2050 struct Ufunction *rp;
2051 newscope = dtopen(&_Nvdisc,Dtoset);
2052 if(envlist)
2053 {
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);
2060 }
2061 if((rp=shp->st.real_fun) && rp->sdict)
2062 {
2063 dtview(rp->sdict,newroot);
2064 newroot = rp->sdict;
2065
2066 }
2067 dtview(newscope,(Dt_t*)newroot);
2068 shp->var_tree = newscope;
2069 }
2070
2071 /*
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.
2075 */
2076
sh_envnolocal(register Namval_t * np,void * data)2077 void sh_envnolocal (register Namval_t *np, void *data)
2078 {
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))
2086 {
2087 nv_putsub(np,NIL(char*),0);
2088 if(cp = nv_getval(np))
2089 cp = strdup(cp);
2090 }
2091 if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
2092 {
2093 if(nv_isref(np) && np!=VERSIONNOD)
2094 {
2095 nv_offattr(np,NV_NOFREE|NV_REF);
2096 free((void*)np->nvalue.nrp);
2097 np->nvalue.cp = 0;
2098 }
2099 if(!cp)
2100 return;
2101 }
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)
2107 {
2108 nv_putval(np,cp,0);
2109 free((void*)cp);
2110 }
2111 }
2112
2113 /*
2114 * Currently this is a dummy, but someday will be needed
2115 * for reference counting
2116 */
nv_close(Namval_t * np)2117 void nv_close(Namval_t *np)
2118 {
2119 NOT_USED(np);
2120 }
2121
table_unset(Shell_t * shp,register Dt_t * root,int flags,Dt_t * oroot)2122 static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot)
2123 {
2124 register Namval_t *np,*nq, *npnext;
2125 for(np=(Namval_t*)dtfirst(root);np;np=npnext)
2126 {
2127 if(nv_isref(np))
2128 {
2129 free((void*)np->nvalue.nrp);
2130 np->nvalue.cp = 0;
2131 np->nvflag = 0;
2132 }
2133 if(nq=dtsearch(oroot,np))
2134 {
2135 if(nv_cover(nq))
2136 {
2137 int subshell = shp->subshell;
2138 shp->subshell = 0;
2139 if(nv_isattr(nq, NV_INTEGER))
2140 {
2141 Sfdouble_t d = nv_getnum(nq);
2142 nv_putval(nq,(char*)&d,NV_LDOUBLE);
2143 }
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;
2150 }
2151 if(nv_isattr(nq,NV_EXPORT))
2152 sh_envput(shp->env,nq);
2153 }
2154 npnext = (Namval_t*)dtnext(root,np);
2155 shp->last_root = root;
2156 shp->last_table = 0;
2157 if(nv_isvtree(np))
2158 {
2159 int len = strlen(np->nvname);
2160 while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.')
2161
2162 {
2163 npnext = (Namval_t*)dtnext(root,nq);
2164 _nv_unset(nq,flags);
2165 nv_delete(nq,root,0);
2166 }
2167 }
2168 _nv_unset(np,flags);
2169 nv_delete(np,root,0);
2170 }
2171 }
2172
2173 /*
2174 *
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
2182 */
_nv_unset(register Namval_t * np,int flags)2183 void _nv_unset(register Namval_t *np,int flags)
2184 {
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)
2190 {
2191 register struct slnod *slp = (struct slnod*)(np->nvenv);
2192 if(slp && !nv_isattr(np,NV_NOFREE))
2193 {
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)
2198 {
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);
2205 }
2206 if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0)))
2207 {
2208 do
2209 {
2210 if(rq->np != np)
2211 continue;
2212 dtdelete(shp->fpathdict,rq);
2213 break;
2214 }
2215 while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq));
2216 }
2217 if(rp->sdict)
2218 {
2219 Namval_t *mp, *nq;
2220 for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq)
2221 {
2222 nq = dtnext(rp->sdict,mp);
2223 _nv_unset(mp,NV_RDONLY);
2224 nv_delete(mp,rp->sdict,0);
2225 }
2226 dtclose(rp->sdict);
2227 }
2228 stakdelete(slp->slptr);
2229 free((void*)np->nvalue.ip);
2230 np->nvalue.ip = 0;
2231 }
2232 goto done;
2233 }
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))
2238 {
2239 /* This function contains disc */
2240 if(!nv_local)
2241 {
2242 nv_local=1;
2243 nv_putv(np,NIL(char*),flags,np->nvfun);
2244 nv_local=0;
2245 return;
2246 }
2247 /* called from disc, assign the actual value */
2248 nv_local=0;
2249 }
2250 if(nv_isattr(np,NV_INT16P) == NV_INT16)
2251 {
2252 np->nvalue.cp = nv_isarray(np)?Empty:0;
2253 goto done;
2254 }
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)
2260 {
2261 if(up->cp!=Empty && !nv_isattr(np, NV_NOFREE))
2262 free((void*)up->cp);
2263 up->cp = 0;
2264 }
2265 done:
2266 if(!nv_isarray(np) || !nv_arrayptr(np))
2267 {
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))
2272 {
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);
2278 }
2279 else
2280 {
2281 nv_setattr(np,NV_MINIMAL);
2282 nv_delete(np,(Dt_t*)0,0);
2283 }
2284 }
2285 }
2286
2287 /*
2288 * return the node pointer in the highest level scope
2289 */
sh_scoped(Shell_t * shp,register Namval_t * np)2290 Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np)
2291 {
2292 if(!dtvnext(shp->var_tree))
2293 return(np);
2294 return(dtsearch(shp->var_tree,np));
2295 }
2296
2297 #if 1
2298 /*
2299 * return space separated list of names of variables in given tree
2300 */
tableval(Dt_t * root)2301 static char *tableval(Dt_t *root)
2302 {
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))
2312 {
2313 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
2314 {
2315 if(!first)
2316 sfputc(out,' ');
2317 else
2318 first = 0;
2319 sfputr(out,np->nvname,-1);
2320 }
2321 }
2322 sfputc(out,0);
2323 if(base)
2324 dtview(root,base);
2325 return((char*)out->_data);
2326 }
2327 #endif
2328
2329 #if SHOPT_OPTIMIZE
2330 struct optimize
2331 {
2332 Namfun_t hdr;
2333 Shell_t *sh;
2334 char **ptr;
2335 struct optimize *next;
2336 Namval_t *np;
2337 };
2338
2339 static struct optimize *opt_free;
2340
optimize_clear(Namval_t * np,Namfun_t * fp)2341 static void optimize_clear(Namval_t* np, Namfun_t *fp)
2342 {
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)
2347 {
2348 if(op->ptr)
2349 {
2350 *op->ptr = 0;
2351 op->ptr = 0;
2352 }
2353 }
2354 }
2355
put_optimize(Namval_t * np,const char * val,int flags,Namfun_t * fp)2356 static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
2357 {
2358 nv_putv(np,val,flags,fp);
2359 optimize_clear(np,fp);
2360 }
2361
clone_optimize(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)2362 static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
2363 {
2364 return((Namfun_t*)0);
2365 }
2366
2367 static const Namdisc_t optimize_disc = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize};
2368
nv_optimize(Namval_t * np)2369 void nv_optimize(Namval_t *np)
2370 {
2371 register Namfun_t *fp;
2372 register struct optimize *op, *xp;
2373 if(sh.argaddr)
2374 {
2375 if(np==SH_LINENO)
2376 {
2377 sh.argaddr = 0;
2378 return;
2379 }
2380 for(fp=np->nvfun; fp; fp = fp->next)
2381 {
2382 if(fp->disc && (fp->disc->getnum || fp->disc->getval))
2383 {
2384 sh.argaddr = 0;
2385 return;
2386 }
2387 if(fp->disc== &optimize_disc)
2388 break;
2389 }
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)
2399 {
2400 op->hdr.disc = 0;
2401 op->next = xp->next;
2402 xp->next = op;
2403 }
2404 else
2405 {
2406 op->hdr.disc = &optimize_disc;
2407 op->next = (struct optimize*)sh.optlist;
2408 sh.optlist = (void*)op;
2409 nv_stack(np,&op->hdr);
2410 }
2411 }
2412 }
2413
sh_optclear(Shell_t * shp,void * old)2414 void sh_optclear(Shell_t *shp, void *old)
2415 {
2416 register struct optimize *op,*opnext;
2417 for(op=(struct optimize*)shp->optlist; op; op = opnext)
2418 {
2419 opnext = op->next;
2420 if(op->ptr && op->hdr.disc)
2421 {
2422 nv_stack(op->np,&op->hdr);
2423 nv_stack(op->np,(Namfun_t*)0);
2424 }
2425 op->next = opt_free;
2426 opt_free = op;
2427 }
2428 shp->optlist = old;
2429 }
2430
2431 #else
2432 # define optimize_clear(np,fp)
2433 #endif /* SHOPT_OPTIMIZE */
2434
2435 /*
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.
2439 *
2440 * If the value of <np> is an integer, the string returned will
2441 * be overwritten by the next call to nv_getval.
2442 *
2443 * If <np> has no value, 0 is returned.
2444 */
2445
nv_getval(register Namval_t * np)2446 char *nv_getval(register Namval_t *np)
2447 {
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))
2457 {
2458 if(!np->nvalue.cp)
2459 return(0);
2460 sh.last_table = nv_reftable(np);
2461 return(nv_name(nv_refnode(np)));
2462 }
2463 if(np->nvfun && np->nvfun->disc)
2464 {
2465 if(!nv_local)
2466 {
2467 nv_local=1;
2468 return(nv_getv(np, np->nvfun));
2469 }
2470 nv_local=0;
2471 }
2472 numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
2473 if(numeric)
2474 {
2475 Sflong_t ll;
2476 if(!up->cp)
2477 return("0");
2478 if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
2479 {
2480 Sfdouble_t ld;
2481 double d;
2482 char *format;
2483 if(nv_isattr(np,NV_LONG))
2484 {
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);
2493 }
2494 else
2495 {
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);
2504 }
2505 return(sfstruse(sh.strbuf));
2506 }
2507 else if(nv_isattr(np,NV_UNSIGN))
2508 {
2509 if(nv_isattr (np,NV_LONG))
2510 ll = *(Sfulong_t*)up->llp;
2511 else if(nv_isattr (np,NV_SHORT))
2512 {
2513 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2514 ll = *(uint16_t*)(up->sp);
2515 else
2516 ll = (uint16_t)up->s;
2517 }
2518 else
2519 ll = *(uint32_t*)(up->lp);
2520 }
2521 else if(nv_isattr (np,NV_LONG))
2522 ll = *up->llp;
2523 else if(nv_isattr (np,NV_SHORT))
2524 {
2525 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2526 ll = *up->sp;
2527 else
2528 ll = up->s;
2529 }
2530 else
2531 ll = *(up->lp);
2532 if((numeric=nv_size(np))==10)
2533 {
2534 if(nv_isattr(np,NV_UNSIGN))
2535 {
2536 sfprintf(sh.strbuf,"%I*u",sizeof(ll),ll);
2537 return(sfstruse(sh.strbuf));
2538 }
2539 numeric = 0;
2540 }
2541 return(fmtbasell(ll,numeric, numeric&&numeric!=10));
2542 }
2543 done:
2544 #if (_AST_VERSION>=20030127L)
2545 /*
2546 * if NV_RAW flag is on, return pointer to binary data
2547 * otherwise, base64 encode the data and return this string
2548 */
2549 if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
2550 {
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);
2557 }
2558 #endif
2559 if((numeric=nv_size(np)) && up->cp && up->cp[numeric])
2560 {
2561 char *cp = getbuf(numeric+1);
2562 memcpy(cp,up->cp,numeric);
2563 cp[numeric]=0;
2564 return(cp);
2565 }
2566 return ((char*)up->cp);
2567 }
2568
nv_getnum(register Namval_t * np)2569 Sfdouble_t nv_getnum(register Namval_t *np)
2570 {
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)
2581 {
2582 if(!nv_local)
2583 {
2584 nv_local=1;
2585 return(nv_getn(np, np->nvfun));
2586 }
2587 nv_local=0;
2588 }
2589 if(nv_isref(np))
2590 {
2591 str = nv_refsub(np);
2592 np = nv_refnode(np);
2593 if(str)
2594 nv_putsub(np,str,0L);
2595 }
2596 if(nv_isattr (np, NV_INTEGER))
2597 {
2598 up= &np->nvalue;
2599 if(!up->lp || up->cp==Empty)
2600 r = 0;
2601 else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE)
2602 {
2603 if(nv_isattr(np, NV_LONG))
2604 r = *up->ldp;
2605 else
2606 r = *up->dp;
2607 }
2608 else if(nv_isattr(np, NV_UNSIGN))
2609 {
2610 if(nv_isattr(np, NV_LONG))
2611 r = (Sflong_t)*((Sfulong_t*)up->llp);
2612 else if(nv_isattr(np, NV_SHORT))
2613 {
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);
2618 }
2619 else
2620 r = *((uint32_t*)up->lp);
2621 }
2622 else
2623 {
2624 if(nv_isattr(np, NV_LONG))
2625 r = *up->llp;
2626 else if(nv_isattr(np, NV_SHORT))
2627 {
2628 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2629 r = *up->sp;
2630 else
2631 r = up->s;
2632 }
2633 else
2634 r = *up->lp;
2635 }
2636 }
2637 else if((str=nv_getval(np)) && *str!=0)
2638 {
2639 if(np->nvfun || nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
2640 {
2641 while(*str=='0')
2642 str++;
2643 }
2644 r = sh_arith(str);
2645 }
2646 return(r);
2647 }
2648 /*
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.
2652 */
nv_newattr(register Namval_t * np,unsigned newatts,int size)2653 void nv_newattr (register Namval_t *np, unsigned newatts, int size)
2654 {
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;
2663
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))
2672 {
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);
2678 }
2679 oldsize = nv_size(np);
2680 if((size==oldsize|| (n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
2681 {
2682 if(size)
2683 nv_setsize(np,size);
2684 nv_offattr(np, ~NV_NOFREE);
2685 nv_onattr(np, newatts);
2686 return;
2687 }
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++;
2697 do
2698 {
2699 nv_setsize(np,oldsize);
2700 np->nvflag = oldatts;
2701 if (sp = nv_getval(np))
2702 {
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)
2708 {
2709 Namval_t *mp;
2710 ap->nelem &= ~ARRAY_SCAN;
2711 if(mp=nv_opensub(np))
2712 {
2713 nv_unset(mp);
2714 mp->nvalue.cp = Empty;
2715 }
2716 else
2717 nv_unset(np);
2718 ap->nelem |= ARRAY_SCAN;
2719 }
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;
2724 }
2725 else
2726 nv_unset(np);
2727 nv_setsize(np,size);
2728 np->nvflag &= NV_ARRAY;
2729 np->nvflag |= newatts;
2730 if (cp)
2731 {
2732 nv_putval (np, cp, NV_RDONLY);
2733 free(cp);
2734 }
2735 }
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;
2743 }
2744
oldgetenv(const char * string)2745 static char *oldgetenv(const char *string)
2746 {
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++)
2755 {
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));
2762 }
2763 return(0);
2764 }
2765
2766 /*
2767 * This version of getenv uses the hash storage to access environment values
2768 */
sh_getenv(const char * name)2769 char *sh_getenv(const char *name)
2770 /*@
2771 assume name!=0;
2772 @*/
2773 {
2774 register Namval_t *np;
2775 if(!sh.var_tree)
2776 {
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));
2781 }
2782 else if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
2783 return(nv_getval(np));
2784 return(0);
2785 }
2786
2787 #ifndef _NEXT_SOURCE
2788 /*
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.
2792 */
getenv(const char * name)2793 char *getenv(const char *name)
2794 {
2795 return sh_getenv(name);
2796 }
2797 #endif /* _NEXT_SOURCE */
2798
2799 #undef putenv
2800 /*
2801 * This version of putenv uses the hash storage to assign environment values
2802 */
putenv(const char * name)2803 int putenv(const char *name)
2804 {
2805 register Namval_t *np;
2806 if(name)
2807 {
2808 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
2809 if(!strchr(name,'='))
2810 nv_unset(np);
2811 }
2812 return(0);
2813 }
2814
2815 /*
2816 * Override libast setenviron().
2817 */
sh_setenviron(const char * name)2818 char* sh_setenviron(const char *name)
2819 {
2820 register Namval_t *np;
2821 if(name)
2822 {
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);
2827 }
2828 return("");
2829 }
2830
2831 /*
2832 * Same linker dance as with getenv() above.
2833 */
setenviron(const char * name)2834 char* setenviron(const char *name)
2835 {
2836 return sh_setenviron(name);
2837 }
2838
2839 /*
2840 * convert <str> to upper case
2841 */
ltou(register char * str)2842 static void ltou(register char *str)
2843 {
2844 register int c;
2845 for(; c= *((unsigned char*)str); str++)
2846 {
2847 if(islower(c))
2848 *str = toupper(c);
2849 }
2850 }
2851
2852 /*
2853 * convert <str> to lower case
2854 */
utol(register char * str)2855 static void utol(register char *str)
2856 {
2857 register int c;
2858 for(; c= *((unsigned char*)str); str++)
2859 {
2860 if(isupper(c))
2861 *str = tolower(c);
2862 }
2863 }
2864
2865 /*
2866 * normalize <cp> and return pointer to subscript if any
2867 * if <eq> is specified, return pointer to first = not in a subscript
2868 */
lastdot(register char * cp,int eq)2869 static char *lastdot(register char *cp, int eq)
2870 {
2871 register char *ep=0;
2872 register int c;
2873 if(eq)
2874 cp++;
2875 while(c= *cp++)
2876 {
2877 if(c=='[')
2878 {
2879 if(*cp==']')
2880 cp++;
2881 else
2882 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2883 }
2884 else if(c=='.')
2885 {
2886 if(*cp=='[')
2887 {
2888 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
2889 if((ep=sh_checkid(ep+1,cp)) < cp)
2890 cp=strcpy(ep,cp);
2891 }
2892 ep = 0;
2893 }
2894 else if(eq && c == '=')
2895 return(cp-1);
2896 }
2897 return(eq?0:ep);
2898 }
2899
nv_rename(register Namval_t * np,int flags)2900 int nv_rename(register Namval_t *np, int flags)
2901 {
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)
2911 {
2912 if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
2913 hp = dtvnext(shp->var_tree);
2914 }
2915 if(!(cp=nv_getval(np)))
2916 {
2917 if(flags&NV_MOVE)
2918 errormsg(SH_DICT,ERROR_exit(1),e_varname,"");
2919 return(0);
2920 }
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)
2936 {
2937 if(!nv_isvtree(np))
2938 _nv_unset(np,0);
2939 return(0);
2940 }
2941 if(!mp && index>=0 && nv_isvtree(nr))
2942 {
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;
2947 }
2948 if(mp)
2949 {
2950 nvenv = (char*)np;
2951 np = mp;
2952 }
2953 if(nr==np)
2954 {
2955 if(index<0)
2956 return(0);
2957 if(cp = nv_getval(np))
2958 cp = strdup(cp);
2959 }
2960 _nv_unset(np,0);
2961 if(!nv_isattr(np,NV_MINIMAL))
2962 np->nvenv = nvenv;
2963 if(nr==np)
2964 {
2965 nv_putsub(np,(char*)0, index);
2966 nv_putval(np,cp,0);
2967 free((void*)cp);
2968 return(1);
2969 }
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);
2978 }
2979
2980 /*
2981 * Create a reference node from <np> to $np in dictionary <hp>
2982 */
nv_setref(register Namval_t * np,Dt_t * hp,int flags)2983 void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
2984 {
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)))
2995 {
2996 nv_unset(np);
2997 nv_onattr(np,NV_REF);
2998 return;
2999 }
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)
3011 {
3012 nr= nq = nv_open(cp, hp, flags);
3013 hp = shp->last_root;
3014 }
3015 if(shp->last_root == shp->var_tree && root!=shp->var_tree)
3016 {
3017 _nv_unset(np,NV_RDONLY);
3018 nv_onattr(np,NV_REF);
3019 errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np));
3020 }
3021 if(nr==np)
3022 {
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));
3028 }
3029 if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN)))
3030 ep = nv_getsub(nq);
3031 if(ep)
3032 {
3033 /* cause subscript evaluation and return result */
3034 if(nv_isarray(nq))
3035 ep = nv_getsub(nq);
3036 else
3037 {
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;
3045 }
3046 }
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);
3056 }
3057
3058 /*
3059 * get the scope corresponding to <index>
3060 * whence uses the same values as lseeek()
3061 */
sh_getscope(int index,int whence)3062 Shscope_t *sh_getscope(int index, int whence)
3063 {
3064 register struct sh_scoped *sp, *topmost;
3065 if(whence==SEEK_CUR)
3066 sp = &sh.st;
3067 else
3068 {
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)
3075 {
3076 int n =0;
3077 while(sp = sp->prevst)
3078 n++;
3079 index = n - index;
3080 sp = topmost;
3081 }
3082 }
3083 if(index < 0)
3084 return((Shscope_t*)0);
3085 while(index-- && (sp = sp->prevst));
3086 return((Shscope_t*)sp);
3087 }
3088
3089 /*
3090 * make <scoped> the top scope and return previous scope
3091 */
sh_setscope(Shscope_t * scope)3092 Shscope_t *sh_setscope(Shscope_t *scope)
3093 {
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);
3101 }
3102
sh_unscope(Shell_t * shp)3103 void sh_unscope(Shell_t *shp)
3104 {
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)
3109 {
3110 dp = dtview(dp,(Dt_t*)0);
3111 shp->st.real_fun->sdict->view = dp;
3112 }
3113 shp->var_tree=dp;
3114 dtclose(root);
3115 }
3116
3117 /*
3118 * The inverse of creating a reference node
3119 */
nv_unref(register Namval_t * np)3120 void nv_unref(register Namval_t *np)
3121 {
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
3132 {
3133 Namfun_t *fp;
3134 for(fp=nq->nvfun; fp; fp = fp->next)
3135 {
3136 if(fp->disc== &optimize_disc)
3137 {
3138 optimize_clear(nq,fp);
3139 return;
3140 }
3141 }
3142 }
3143 #endif
3144 }
3145
3146 /*
3147 * These following are for binary compatibility with the old hash library
3148 * They will be removed someday
3149 */
3150
3151 #if defined(__IMPORT__) && defined(__EXPORT__)
3152 # define extern __EXPORT__
3153 #endif
3154
3155 #undef hashscope
3156
hashscope(Dt_t * root)3157 extern Dt_t *hashscope(Dt_t *root)
3158 {
3159 return(dtvnext(root));
3160 }
3161
3162 #undef hashfree
3163
hashfree(Dt_t * root)3164 extern Dt_t *hashfree(Dt_t *root)
3165 {
3166 Dt_t *dp = dtvnext(root);
3167 dtclose(root);
3168 return(dp);
3169 }
3170
3171 #undef hashname
3172
hashname(void * obj)3173 extern char *hashname(void *obj)
3174 {
3175 Namval_t *np = (Namval_t*)obj;
3176 return(np->nvname);
3177 }
3178
3179 #undef hashlook
3180
hashlook(Dt_t * root,const char * name,int mode,int size)3181 extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
3182 {
3183 NOT_USED(size);
3184 return((void*)nv_search(name,root,mode));
3185 }
3186
nv_name(register Namval_t * np)3187 char *nv_name(register Namval_t *np)
3188 {
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)
3195 {
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));
3205 }
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))
3213 {
3214 for(fp= np->nvfun ; fp; fp=fp->next)
3215 if(fp->disc && fp->disc->namef)
3216 {
3217 if(np==sh.last_table)
3218 sh.last_table = 0;
3219 return((*fp->disc->namef)(np,fp));
3220 }
3221 }
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));
3227 }
3228
nv_lastdict(void)3229 Namval_t *nv_lastdict(void)
3230 {
3231 return(sh.last_table);
3232 }
3233
3234 #undef nv_context
3235 /*
3236 * returns the data context for a builtin
3237 */
nv_context(Namval_t * np)3238 void *nv_context(Namval_t *np)
3239 {
3240 return((void*)np->nvfun);
3241 }
3242
3243 #define DISABLE /* proto workaround */
3244
DISABLE(register Namval_t * np)3245 int nv_isnull DISABLE (register Namval_t *np)
3246 {
3247 return(nv_isnull(np));
3248 }
3249
3250 #undef nv_setsize
nv_setsize(register Namval_t * np,int size)3251 int nv_setsize(register Namval_t *np, int size)
3252 {
3253 int oldsize = nv_size(np);
3254 if(size>=0)
3255 np->nvsize = size;
3256 return(oldsize);
3257 }
3258
nv_shell(Namval_t * np)3259 Shell_t *nv_shell(Namval_t *np)
3260 {
3261 Namfun_t *fp;
3262 for(fp=np->nvfun;fp;fp=fp->next)
3263 {
3264 if(!fp->disc)
3265 return((Shell_t*)fp->last);
3266 }
3267 return(0);
3268 }
3269
3270 #undef nv_unset
3271
nv_unset(register Namval_t * np)3272 void nv_unset(register Namval_t *np)
3273 {
3274 _nv_unset(np,0);
3275 return;
3276 }
3277