1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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 * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
27 */
28
29 #define putenv ___putenv
30
31 #include "defs.h"
32 #include "variables.h"
33 #include "path.h"
34 #include "lexstates.h"
35 #include "timeout.h"
36 #include "FEATURE/externs"
37 #include "streval.h"
38
39 #define NVCACHE 8 /* must be a power of 2 */
40 #define Empty ((char*)(e_sptbnl+3))
41 static char *savesub = 0;
42 static char Null[1];
43 static Namval_t NullNode;
44 static Dt_t *Refdict;
45 static Dtdisc_t _Refdisc =
46 {
47 offsetof(struct Namref,np),sizeof(struct Namval_t*),sizeof(struct Namref)
48 };
49
50 #if !_lib_pathnative && _lib_uwin_path
51
52 #define _lib_pathnative 1
53
54 extern int uwin_path(const char*, char*, int);
55
56 size_t
pathnative(const char * path,char * buf,size_t siz)57 pathnative(const char* path, char* buf, size_t siz)
58 {
59 return uwin_path(path, buf, siz);
60 }
61
62 #endif /* _lib_pathnative */
63
64 static void attstore(Namval_t*,void*);
65 #ifndef _ENV_H
66 static void pushnam(Namval_t*,void*);
67 static char *staknam(Namval_t*, char*);
68 #endif
69 static void rightjust(char*, int, int);
70 static char *lastdot(char*, int);
71
72 struct adata
73 {
74 Shell_t *sh;
75 Namval_t *tp;
76 char *mapname;
77 char **argnam;
78 int attsize;
79 char *attval;
80 };
81
82 #if SHOPT_TYPEDEF
83 struct sh_type
84 {
85 void *previous;
86 Namval_t **nodes;
87 Namval_t *rp;
88 short numnodes;
89 short maxnodes;
90 };
91 #endif /*SHOPT_TYPEDEF */
92
93 #if NVCACHE
94 struct Namcache
95 {
96 struct Cache_entry
97 {
98 Dt_t *root;
99 Dt_t *last_root;
100 char *name;
101 Namval_t *np;
102 Namval_t *last_table;
103 Namval_t *namespace;
104 int flags;
105 short size;
106 short len;
107 } entries[NVCACHE];
108 short index;
109 short ok;
110 };
111 static struct Namcache nvcache;
112 #endif
113
114 char nv_local = 0;
115 #ifndef _ENV_H
116 static void(*nullscan)(Namval_t*,void*);
117 #endif
118
119 #if ( SFIO_VERSION <= 20010201L )
120 # define _data data
121 #endif
122
123 #if !SHOPT_MULTIBYTE
124 # define mbchar(p) (*(unsigned char*)p++)
125 #endif /* SHOPT_MULTIBYTE */
126
127 /* ======== name value pair routines ======== */
128
129 #include "shnodes.h"
130 #include "builtins.h"
131
getbuf(size_t len)132 static char *getbuf(size_t len)
133 {
134 static char *buf;
135 static size_t buflen;
136 if(buflen < len)
137 {
138 if(buflen==0)
139 buf = (char*)malloc(len);
140 else
141 buf = (char*)realloc(buf,len);
142 buflen = len;
143 }
144 return(buf);
145 }
146
147 #ifdef _ENV_H
sh_envput(Env_t * ep,Namval_t * np)148 void sh_envput(Env_t* ep,Namval_t *np)
149 {
150 int offset = staktell();
151 Namarr_t *ap = nv_arrayptr(np);
152 char *val;
153 if(ap)
154 {
155 if(ap->nelem&ARRAY_UNDEF)
156 nv_putsub(np,"0",0L);
157 else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
158 return;
159 }
160 if(!(val = nv_getval(np)))
161 return;
162 stakputs(nv_name(np));
163 stakputc('=');
164 stakputs(val);
165 stakseek(offset);
166 env_add(ep,stakptr(offset),ENV_STRDUP);
167 }
168 #endif
169
170 /*
171 * output variable name in format for re-input
172 */
nv_outname(Sfio_t * out,char * name,int len)173 void nv_outname(Sfio_t *out, char *name, int len)
174 {
175 const char *cp=name, *sp;
176 int c, offset = staktell();
177 while(sp= strchr(cp,'['))
178 {
179 if(len>0 && cp+len <= sp)
180 break;
181 sfwrite(out,cp,++sp-cp);
182 stakseek(offset);
183 while(c= *sp++)
184 {
185 if(c==']')
186 break;
187 else if(c=='\\')
188 {
189 if(*sp=='[' || *sp==']' || *sp=='\\')
190 c = *sp++;
191 }
192 stakputc(c);
193 }
194 stakputc(0);
195 sfputr(out,sh_fmtq(stakptr(offset)),-1);
196 if(len>0)
197 {
198 sfputc(out,']');
199 return;
200 }
201 cp = sp-1;
202 }
203 if(*cp)
204 {
205 if(len>0)
206 sfwrite(out,cp,len);
207 else
208 sfputr(out,cp,-1);
209 }
210 stakseek(offset);
211 }
212
213 #if SHOPT_TYPEDEF
nv_addnode(Namval_t * np,int remove)214 Namval_t *nv_addnode(Namval_t* np, int remove)
215 {
216 Shell_t *shp = sh_getinterp();
217 register struct sh_type *sp = (struct sh_type*)shp->mktype;
218 register int i;
219 register char *name=0;
220 if(sp->numnodes==0 && !nv_isnull(np) && shp->last_table)
221 {
222 /* could be an redefine */
223 Dt_t *root = nv_dict(shp->last_table);
224 sp->rp = np;
225 nv_delete(np,root,NV_NOFREE);
226 np = nv_search(sp->rp->nvname,root,NV_ADD);
227 }
228 if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
229 {
230 name = (sp->nodes[0])->nvname;
231 i = strlen(name);
232 if(memcmp(np->nvname,name,i))
233 return(np);
234 }
235 if(sp->rp && sp->numnodes)
236 {
237 /* check for a redefine */
238 if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0)
239 sp->rp = 0;
240 else
241 {
242 Dt_t *root = nv_dict(shp->last_table);
243 nv_delete(sp->nodes[0],root,NV_NOFREE);
244 dtinsert(root,sp->rp);
245 errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname);
246 }
247 }
248 for(i=0; i < sp->numnodes; i++)
249 {
250 if(np == sp->nodes[i])
251 {
252 if(remove)
253 {
254 while(++i < sp->numnodes)
255 sp->nodes[i-1] = sp->nodes[i];
256 sp->numnodes--;
257 }
258 return(np);
259 }
260 }
261 if(remove)
262 return(np);
263 if(sp->numnodes==sp->maxnodes)
264 {
265 sp->maxnodes += 20;
266 sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
267 }
268 sp->nodes[sp->numnodes++] = np;
269 return(np);
270 }
271 #endif /* SHOPT_TYPEDEF */
272
273 /*
274 * given a list of assignments, determine <name> is on the list
275 returns a pointer to the argnod on the list or NULL
276 */
nv_onlist(struct argnod * arg,const char * name)277 struct argnod *nv_onlist(struct argnod *arg, const char *name)
278 {
279 char *cp;
280 int len = strlen(name);
281 for(;arg; arg=arg->argnxt.ap)
282 {
283 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
284 cp = ((struct fornod*)arg->argchn.ap)->fornam;
285 else
286 cp = arg->argval;
287 if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='='))
288 return(arg);
289 }
290 return(0);
291 }
292
293 /*
294 * Perform parameter assignment for a linked list of parameters
295 * <flags> contains attributes for the parameters
296 */
nv_setlist(register struct argnod * arg,register int flags,Namval_t * typ)297 void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
298 {
299 Shell_t *shp = sh_getinterp();
300 register char *cp;
301 register Namval_t *np, *mp;
302 char *trap=shp->st.trap[SH_DEBUGTRAP];
303 char *prefix = shp->prefix;
304 int traceon = (sh_isoption(SH_XTRACE)!=0);
305 int array = (flags&(NV_ARRAY|NV_IARRAY));
306 Namarr_t *ap;
307 Namval_t node;
308 struct Namref nr;
309 #if SHOPT_TYPEDEF
310 int maketype = flags&NV_TYPE;
311 struct sh_type shtp;
312 if(maketype)
313 {
314 shtp.previous = shp->mktype;
315 shp->mktype=(void*)&shtp;
316 shtp.numnodes=0;
317 shtp.maxnodes = 20;
318 shtp.rp = 0;
319 shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*));
320 }
321 #endif /* SHOPT_TYPEDEF*/
322 #if SHOPT_NAMESPACE
323 if(shp->namespace && nv_dict(shp->namespace)==shp->var_tree)
324 flags |= NV_NOSCOPE;
325 #endif /* SHOPT_NAMESPACE */
326 flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY);
327 if(sh_isoption(SH_ALLEXPORT))
328 flags |= NV_EXPORT;
329 if(shp->prefix)
330 {
331 flags &= ~(NV_IDENT|NV_EXPORT);
332 flags |= NV_VARNAME;
333 }
334 else
335 shp->prefix_root = shp->first_root = 0;
336 for(;arg; arg=arg->argnxt.ap)
337 {
338 shp->used_pos = 0;
339 if(arg->argflag&ARG_MAC)
340 {
341 shp->prefix = 0;
342 cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
343 shp->prefix = prefix;
344 }
345 else
346 {
347 stakseek(0);
348 if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
349 {
350 int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
351 int sub=0;
352 struct fornod *fp=(struct fornod*)arg->argchn.ap;
353 register Shnode_t *tp=fp->fortre;
354 flag |= (flags&(NV_NOSCOPE|NV_STATIC|NV_FARRAY));
355 if(arg->argflag&ARG_QUOTED)
356 cp = sh_mactrim(shp,fp->fornam,-1);
357 else
358 cp = fp->fornam;
359 error_info.line = fp->fortyp-shp->st.firstline;
360 if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
361 array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;
362 if(prefix && tp->com.comset && *cp=='[')
363 {
364 shp->prefix = 0;
365 np = nv_open(prefix,shp->last_root,flag);
366 shp->prefix = prefix;
367 if(np)
368 {
369 if(nv_isvtree(np) && !nv_isarray(np))
370 {
371 stakputc('.');
372 stakputs(cp);
373 cp = stakfreeze(1);
374 }
375 nv_close(np);
376 }
377 }
378 np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN);
379 if((arg->argflag&ARG_APPEND) && (tp->tre.tretyp&COMMSK)==TCOM && tp->com.comset && !nv_isvtree(np) && (((ap=nv_arrayptr(np)) && !ap->fun && !nv_opensub(np)) || (!ap && nv_isarray(np) && tp->com.comarg && !((mp=nv_search(tp->com.comarg->argval,shp->fun_tree,0)) && nv_isattr(mp,BLT_DCL)))))
380 {
381 if(tp->com.comarg)
382 {
383 struct argnod *ap = tp->com.comset;
384 while(ap->argnxt.ap)
385 ap = ap->argnxt.ap;
386 ap->argnxt.ap = tp->com.comarg;
387
388 }
389 tp->com.comarg = tp->com.comset;
390 tp->com.comset = 0;
391 tp->com.comtyp = COMSCAN;
392 }
393 if(nv_isattr(np,NV_RDONLY) && np->nvfun && !(flags&NV_RDONLY))
394 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
395 if(nv_isattr(np,NV_NOFREE) && nv_isnull(np))
396 nv_offattr(np,NV_NOFREE);
397 if(nv_istable(np))
398 _nv_unset(np,0);
399 if(typ && !array && (!shp->prefix || nv_isnull(np) || nv_isarray(np)))
400 {
401 if(!(nv_isnull(np)) && !nv_isarray(np))
402 _nv_unset(np,0);
403 nv_settype(np,typ,0);
404 }
405 if((flags&NV_STATIC) && !nv_isattr(np,NV_EXPORT) && !nv_isnull(np))
406 #if SHOPT_TYPEDEF
407 goto check_type;
408 #else
409 continue;
410 #endif /* SHOPT_TYPEDEF */
411 ap=nv_arrayptr(np);
412 #if SHOPT_FIXEDARRAY
413 if(ap && ap->fixed)
414 flags |= NV_FARRAY;
415 #endif /* SHOPT_FIXEDARRAY */
416 if(array && (!ap || !ap->hdr.type))
417 {
418 #if SHOPT_FIXEDARRAY
419 if(!(arg->argflag&ARG_APPEND) && (!ap || !ap->fixed))
420 #else
421 if(!(arg->argflag&ARG_APPEND))
422 #endif /* SHOPT_FIXEDARRAY */
423 _nv_unset(np,NV_EXPORT);
424 if(array&NV_ARRAY)
425 {
426 nv_setarray(np,nv_associative);
427 }
428 else
429 {
430 nv_onattr(np,NV_ARRAY);
431 }
432 }
433 if(array && tp->tre.tretyp!=TLST && !tp->com.comset && !tp->com.comarg)
434 {
435 #if SHOPT_TYPEDEF
436 goto check_type;
437 #else
438 continue;
439 #endif /* SHOPT_TYPEDEF */
440 }
441 /* check for array assignment */
442 if(tp->tre.tretyp!=TLST && tp->com.comarg && !tp->com.comset && ((array&NV_IARRAY) || !((mp=tp->com.comnamp) && nv_isattr(mp,BLT_DCL))))
443 {
444 int argc;
445 Dt_t *last_root = shp->last_root;
446 char **argv = sh_argbuild(shp,&argc,&tp->com,0);
447 shp->last_root = last_root;
448 #if SHOPT_TYPEDEF
449 if(shp->mktype && shp->dot_depth==0 && np==((struct sh_type*)shp->mktype)->nodes[0])
450 {
451 shp->mktype = 0;
452 errormsg(SH_DICT,ERROR_exit(1),"%s: not a known type name",argv[0]);
453 }
454 #endif /* SHOPT_TYPEDEF */
455 if(!(arg->argflag&ARG_APPEND))
456 {
457 #if SHOPT_FIXEDARRAY
458 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && !ap->fixed && (ap->nelem&ARRAY_MASK)))
459 #else
460 if(!nv_isarray(np) || ((ap=nv_arrayptr(np)) && (ap->nelem&ARRAY_MASK)))
461 #endif /* SHOPT_FIXEDARRAY */
462 {
463 if(ap)
464 ap->nelem |= ARRAY_UNDEF;
465 _nv_unset(np,NV_EXPORT);
466 }
467 }
468 nv_setvec(np,(arg->argflag&ARG_APPEND),argc,argv);
469 if(traceon || trap)
470 {
471 int n = -1;
472 char *name = nv_name(np);
473 if(arg->argflag&ARG_APPEND)
474 n = '+';
475 if(trap)
476 sh_debug(shp,trap,name,(char*)0,argv,(arg->argflag&ARG_APPEND)|ARG_ASSIGN);
477 if(traceon)
478 {
479 sh_trace(shp,NIL(char**),0);
480 sfputr(sfstderr,name,n);
481 sfwrite(sfstderr,"=( ",3);
482 while(cp= *argv++)
483 sfputr(sfstderr,sh_fmtq(cp),' ');
484 sfwrite(sfstderr,")\n",2);
485 }
486 }
487 #if SHOPT_TYPEDEF
488 goto check_type;
489 #else
490 continue;
491 #endif /* SHOPT_TYPEDEF */
492 }
493 if((tp->tre.tretyp&COMMSK)==TFUN)
494 goto skip;
495 if(tp->tre.tretyp==0 && !tp->com.comset && !tp->com.comarg)
496 {
497 if(!(arg->argflag&ARG_APPEND) && nv_isattr(np,NV_BINARY|NV_NOFREE|NV_RAW)!=(NV_BINARY|NV_NOFREE|NV_RAW))
498 _nv_unset(np,NV_EXPORT);
499 goto skip;
500 }
501 if(tp->tre.tretyp==TLST || !tp->com.comset || tp->com.comset->argval[0]!='[')
502 {
503 if(tp->tre.tretyp!=TLST && !tp->com.comnamp && tp->com.comset && tp->com.comset->argval[0]==0 && tp->com.comset->argchn.ap)
504 {
505 if(prefix || np)
506 cp = stakcopy(nv_name(np));
507 shp->prefix = cp;
508 if(tp->com.comset->argval[1]=='[')
509 {
510 if((arg->argflag&ARG_APPEND) && (!nv_isarray(np) || (nv_aindex(np)>=0)))
511 _nv_unset(np,0);
512 if(!(array&NV_IARRAY) && !(tp->com.comset->argflag&ARG_MESSAGE))
513 nv_setarray(np,nv_associative);
514 }
515 nv_setlist(tp->com.comset,flags&~NV_STATIC,0);
516 shp->prefix = prefix;
517 if(tp->com.comset->argval[1]!='[')
518 nv_setvtree(np);
519 nv_close(np);
520 #if SHOPT_TYPEDEF
521 goto check_type;
522 #else
523 continue;
524 #endif /* SHOPT_TYPEDEF */
525 }
526 if(*cp!='.' && *cp!='[' && strchr(cp,'['))
527 {
528 cp = stakcopy(nv_name(np));
529 nv_close(np);
530 if(!(arg->argflag&ARG_APPEND))
531 flag &= ~NV_ARRAY;
532 shp->prefix_root = shp->first_root;
533 np = nv_open(cp,shp->prefix_root?shp->prefix_root:shp->var_tree,flag);
534 }
535 if(arg->argflag&ARG_APPEND)
536 {
537 if(nv_isarray(np))
538 {
539 if((sub=nv_aimax(np)) < 0 && nv_arrayptr(np))
540 errormsg(SH_DICT,ERROR_exit(1),e_badappend,nv_name(np));
541 if(sub>=0)
542 sub++;
543 }
544 if(!nv_isnull(np) && np->nvalue.cp!=Empty && !nv_isvtree(np))
545 sub=1;
546 }
547 else if(((np->nvalue.cp && np->nvalue.cp!=Empty)||nv_isvtree(np)|| nv_arrayptr(np)) && !nv_type(np))
548 {
549 _nv_unset(np,NV_EXPORT);
550 if(ap && ap->fun)
551 nv_setarray(np,nv_associative);
552
553 }
554 }
555 else
556 {
557 if(!(arg->argflag&ARG_APPEND))
558 _nv_unset(np,NV_EXPORT);
559 if(!sh_isoption(SH_BASH) && !(array&NV_IARRAY) && !nv_isarray(np))
560 nv_setarray(np,nv_associative);
561 }
562 skip:
563 if(sub>0)
564 {
565 sfprintf(stkstd,"%s[%d]",prefix?nv_name(np):cp,sub);
566 shp->prefix = stakfreeze(1);
567 nv_putsub(np,(char*)0,ARRAY_ADD|ARRAY_FILL|sub);
568 }
569 else if(prefix)
570 shp->prefix = stakcopy(nv_name(np));
571 else
572 shp->prefix = cp;
573 shp->last_table = 0;
574 if(shp->prefix)
575 {
576 if(*shp->prefix=='_' && shp->prefix[1]=='.' && nv_isref(L_ARGNOD))
577 {
578 sfprintf(stkstd,"%s%s",nv_name(L_ARGNOD->nvalue.nrp->np),shp->prefix+1);
579 shp->prefix = stkfreeze(stkstd,1);
580 }
581 memset(&nr,0,sizeof(nr));
582 memcpy(&node,L_ARGNOD,sizeof(node));
583 L_ARGNOD->nvalue.nrp = &nr;
584 nr.np = np;
585 nr.root = shp->last_root;
586 nr.table = shp->last_table;
587 L_ARGNOD->nvflag = NV_REF|NV_NOFREE;
588 L_ARGNOD->nvfun = 0;
589 }
590 sh_exec(tp,sh_isstate(SH_ERREXIT));
591 #if SHOPT_TYPEDEF
592 if(shp->prefix)
593 #endif
594 {
595 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
596 L_ARGNOD->nvflag = node.nvflag;
597 L_ARGNOD->nvfun = node.nvfun;
598 }
599 shp->prefix = prefix;
600 if(nv_isarray(np) && (mp=nv_opensub(np)))
601 np = mp;
602 while(tp->tre.tretyp==TLST)
603 {
604 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]!='[')
605 break;
606 tp = tp->lst.lstrit;
607
608 }
609 if(!nv_isarray(np) && !typ && (tp->com.comarg || !tp->com.comset || tp->com.comset->argval[0]!='['))
610 {
611 nv_setvtree(np);
612 if(tp->com.comarg || tp->com.comset)
613 np->nvfun->dsize = 0;
614 }
615 #if SHOPT_TYPEDEF
616 goto check_type;
617 #else
618 continue;
619 #endif /* SHOPT_TYPEDEF */
620 }
621 cp = arg->argval;
622 mp = 0;
623 }
624 np = nv_open(cp,shp->prefix_root?shp->prefix_root:shp->var_tree,flags);
625 if(!np->nvfun && (flags&NV_NOREF))
626 {
627 if(shp->used_pos)
628 nv_onattr(np,NV_PARAM);
629 else
630 nv_offattr(np,NV_PARAM);
631 }
632 if(traceon || trap)
633 {
634 register char *sp=cp;
635 char *name=nv_name(np);
636 char *sub=0;
637 int append = 0;
638 if(nv_isarray(np))
639 sub = savesub;
640 if(cp=lastdot(sp,'='))
641 {
642 if(cp[-1]=='+')
643 append = ARG_APPEND;
644 cp++;
645 }
646 if(traceon)
647 {
648 sh_trace(shp,NIL(char**),0);
649 nv_outname(sfstderr,name,-1);
650 if(sub)
651 sfprintf(sfstderr,"[%s]",sh_fmtq(sub));
652 if(cp)
653 {
654 if(append)
655 sfputc(sfstderr,'+');
656 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp));
657 }
658 }
659 if(trap)
660 {
661 char *av[2];
662 av[0] = cp;
663 av[1] = 0;
664 sh_debug(shp,trap,name,sub,av,append);
665 }
666 }
667 #if SHOPT_TYPEDEF
668 check_type:
669 if(maketype)
670 {
671 nv_open(shtp.nodes[0]->nvname,shp->var_tree,NV_ASSIGN|NV_VARNAME|NV_NOADD|NV_NOFAIL);
672 np = nv_mktype(shtp.nodes,shtp.numnodes);
673 free((void*)shtp.nodes);
674 shp->mktype = shtp.previous;
675 maketype = 0;
676 if(shp->namespace)
677 free(shp->prefix);
678 shp->prefix = 0;
679 if(nr.np == np)
680 {
681 L_ARGNOD->nvalue.nrp = node.nvalue.nrp;
682 L_ARGNOD->nvflag = node.nvflag;
683 L_ARGNOD->nvfun = node.nvfun;
684 }
685 }
686 #endif /* SHOPT_TYPEDEF */
687 }
688 }
689
690 /*
691 * copy the subscript onto the stack
692 */
stak_subscript(const char * sub,int last)693 static void stak_subscript(const char *sub, int last)
694 {
695 register int c;
696 stakputc('[');
697 while(c= *sub++)
698 {
699 if(c=='[' || c==']' || c=='\\')
700 stakputc('\\');
701 stakputc(c);
702 }
703 stakputc(last);
704 }
705
706 /*
707 * construct a new name from a prefix and base name on the stack
708 */
copystack(const char * prefix,register const char * name,const char * sub)709 static char *copystack(const char *prefix, register const char *name, const char *sub)
710 {
711 register int last=0,offset = staktell();
712 if(prefix)
713 {
714 stakputs(prefix);
715 if(*stakptr(staktell()-1)=='.')
716 stakseek(staktell()-1);
717 if(*name=='.' && name[1]=='[')
718 last = staktell()+2;
719 if(*name!='[' && *name!='.' && *name!='=' && *name!='+')
720 stakputc('.');
721 if(*name=='.' && (name[1]=='=' || name[1]==0))
722 stakputc('.');
723 }
724 if(last)
725 {
726 stakputs(name);
727 if(sh_checkid(stakptr(last),(char*)0))
728 stakseek(staktell()-2);
729 }
730 if(sub)
731 stak_subscript(sub,']');
732 if(!last)
733 stakputs(name);
734 stakputc(0);
735 return(stakptr(offset));
736 }
737
738 /*
739 * grow this stack string <name> by <n> bytes and move from cp-1 to end
740 * right by <n>. Returns beginning of string on the stack
741 */
stack_extend(const char * cname,char * cp,int n)742 static char *stack_extend(const char *cname, char *cp, int n)
743 {
744 register char *name = (char*)cname;
745 int offset = name - stakptr(0);
746 int m = cp-name;
747 stakseek(offset + strlen(name)+n+1);
748 name = stakptr(offset);
749 cp = name + m;
750 m = strlen(cp)+1;
751 while(m-->0)
752 cp[n+m]=cp[m];
753 return((char*)name);
754 }
755
nv_create(const char * name,Dt_t * root,int flags,Namfun_t * dp)756 Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp)
757 {
758 Shell_t *shp = sh_getinterp();
759 char *sub=0, *cp=(char*)name, *sp, *xp;
760 register int c;
761 register Namval_t *np=0, *nq=0;
762 Namfun_t *fp=0;
763 long mode, add=0;
764 int copy=0,isref,top=0,noscope=(flags&NV_NOSCOPE);
765 int nofree=0, level=0;
766 #if SHOPT_FIXEDARRAY
767 Namarr_t *ap;
768 #endif /* SHOPT_FIXEDARRAY */
769 if(root==shp->var_tree)
770 {
771 if(dtvnext(root))
772 top = 1;
773 else
774 flags &= ~NV_NOSCOPE;
775 }
776 if(!dp->disc)
777 copy = dp->nofree&1;
778 if(*cp=='.')
779 cp++;
780 while(1)
781 {
782 switch(c = *(unsigned char*)(sp = cp))
783 {
784 case '[':
785 if(flags&NV_NOARRAY)
786 {
787 dp->last = cp;
788 return(np);
789 }
790 cp = nv_endsubscript((Namval_t*)0,sp,0);
791 if(sp==name || sp[-1]=='.')
792 c = *(sp = cp);
793 goto skip;
794 case '.':
795 if(flags&NV_IDENT)
796 return(0);
797 if(root==shp->var_tree)
798 flags &= ~NV_EXPORT;
799 if(!copy && !(flags&NV_NOREF))
800 {
801 c = sp-name;
802 copy = cp-name;
803 dp->nofree |= 1;
804 name = copystack((const char*)0, name,(const char*)0);
805 cp = (char*)name+copy;
806 sp = (char*)name+c;
807 c = '.';
808 }
809 /* FALLTHROUGH */
810 skip:
811 case '+':
812 case '=':
813 *sp = 0;
814 /* FALLTHROUGH */
815 case 0:
816 isref = 0;
817 dp->last = cp;
818 mode = (c=='.' || (flags&NV_NOADD))?add:NV_ADD;
819 if(level++ || ((flags&NV_NOSCOPE) && c!='.'))
820 mode |= HASH_NOSCOPE;
821 np=0;
822 if(top)
823 {
824 struct Ufunction *rp;
825 if((rp=shp->st.real_fun) && !rp->sdict && (flags&NV_STATIC))
826 {
827 Dt_t *dp = dtview(shp->var_tree,(Dt_t*)0);
828 rp->sdict = dtopen(&_Nvdisc,Dtoset);
829 dtview(rp->sdict,dp);
830 dtview(shp->var_tree,rp->sdict);
831 }
832 if(np = nv_search(name,shp->var_tree,0))
833 {
834 #if SHOPT_NAMESPACE
835 if(shp->var_tree->walk==shp->var_base || (shp->var_tree->walk!=shp->var_tree && shp->namespace && nv_dict(shp->namespace)==shp->var_tree->walk))
836 #else
837 if(shp->var_tree->walk==shp->var_base)
838 #endif /* SHOPT_NAMESPACE */
839 {
840 #if SHOPT_NAMESPACE
841 if(!(nq = nv_search((char*)np,shp->var_base,HASH_BUCKET)))
842 #endif /* SHOPT_NAMESPACE */
843 nq = np;
844 shp->last_root = shp->var_tree->walk;
845 if((flags&NV_NOSCOPE) && *cp!='.')
846 {
847 if(mode==0)
848 root = shp->var_tree->walk;
849 else
850 {
851 nv_delete(np,(Dt_t*)0,NV_NOFREE);
852 np = 0;
853 }
854 }
855 }
856 else
857 {
858 if(shp->var_tree->walk)
859 root = shp->var_tree->walk;
860 flags |= NV_NOSCOPE;
861 noscope = 1;
862 }
863 }
864 if(rp && rp->sdict && (flags&NV_STATIC))
865 {
866 root = rp->sdict;
867 if(np && shp->var_tree->walk==shp->var_tree)
868 {
869 _nv_unset(np,0);
870 nv_delete(np,shp->var_tree,0);
871 np = 0;
872 }
873 if(!np || shp->var_tree->walk!=root)
874 np = nv_search(name,root,HASH_NOSCOPE|NV_ADD);
875 }
876 }
877 #if SHOPT_NAMESPACE
878 if(!np && !noscope && *name!='.' && shp->namespace && root==shp->var_tree)
879 root = nv_dict(shp->namespace);
880 #endif /* SHOPT_NAMESPACE */
881 if(np || (np = nv_search(name,root,mode)))
882 {
883 isref = nv_isref(np);
884 shp->openmatch = root->walk?root->walk:root;
885 if(top)
886 {
887 if(nq==np)
888 {
889 flags &= ~NV_NOSCOPE;
890 root = shp->last_root;
891 }
892 else if(nq)
893 {
894 if(nv_isnull(np) && c!='.' && ((np->nvfun=nv_cover(nq)) || nq==OPTINDNOD))
895 {
896 np->nvname = nq->nvname;
897 #if SHOPT_NAMESPACE
898 if(shp->namespace && nv_dict(shp->namespace)==shp->var_tree && nv_isattr(nq,NV_EXPORT))
899 nv_onattr(np,NV_EXPORT);
900 #endif /* SHOPT_NAMESPACE */
901 if(nq==OPTINDNOD)
902 {
903 np->nvfun = nq->nvfun;
904 np->nvalue.lp = (&shp->st.optindex);
905 nv_onattr(np,NV_INTEGER|NV_NOFREE);
906 }
907 }
908 flags |= NV_NOSCOPE;
909 }
910 }
911 else if(add && nv_isnull(np) && c=='.' && cp[1]!='.')
912 nv_setvtree(np);
913 #if SHOPT_NAMESPACE
914 if(shp->namespace && root==nv_dict(shp->namespace))
915 {
916 flags |= NV_NOSCOPE;
917 shp->last_table = shp->namespace;
918 }
919 #endif /* SHOPT_NAMESPACE */
920 }
921 if(c)
922 *sp = c;
923 top = 0;
924 if(isref)
925 {
926 #if SHOPT_FIXEDARRAY
927 int n=0,dim;
928 #endif /* SHOPT_FIXEDARRAY */
929 #if NVCACHE
930 nvcache.ok = 0;
931 #endif
932 if(c=='.') /* don't optimize */
933 shp->argaddr = 0;
934 else if((flags&NV_NOREF) && (c!='[' && *cp!='.'))
935 {
936 if(c && !(flags&NV_NOADD))
937 nv_unref(np);
938 return(np);
939 }
940 while(nv_isref(np) && np->nvalue.cp)
941 {
942 root = nv_reftree(np);
943 shp->last_root = root;
944 shp->last_table = nv_reftable(np);
945 sub = nv_refsub(np);
946 #if SHOPT_FIXEDARRAY
947 n = nv_refindex(np);
948 dim = nv_refdimen(np);
949 #endif /* SHOPT_FIXEDARRAY */
950 np = nv_refnode(np);
951 #if SHOPT_FIXEDARRAY
952 if(n)
953 {
954 ap = nv_arrayptr(np);
955 ap->nelem = dim;
956 nv_putsub(np,(char*)0,n);
957 }
958 else
959 #endif /* SHOPT_FIXEDARRAY */
960 if(sub && c!='.')
961 nv_putsub(np,sub,0L);
962 flags |= NV_NOSCOPE;
963 noscope = 1;
964 }
965 shp->first_root = root;
966 if(nv_isref(np) && (c=='[' || c=='.' || !(flags&NV_ASSIGN)))
967 errormsg(SH_DICT,ERROR_exit(1),e_noref,nv_name(np));
968 if(sub && c==0)
969 {
970 if(flags&NV_ARRAY)
971 {
972 Namarr_t *ap = nv_arrayptr(np);
973 nq = nv_opensub(np);
974 if((flags&NV_ASSIGN) && (!nq || nv_isnull(nq)))
975 ap->nelem++;
976 if(!nq)
977 goto addsub;
978 else
979 np = nq;
980 }
981 return(np);
982 }
983 if(np==nq)
984 flags &= ~(noscope?0:NV_NOSCOPE);
985 #if SHOPT_FIXEDARRAY
986 else if(c || n)
987 #else
988 else if(c)
989 #endif /* SHOPT_FIXEDARRAY */
990 {
991 #if SHOPT_FIXEDARRAY
992 static char null[1] = "";
993 #endif /* SHOPT_FIXEDARRAY */
994 c = (cp-sp);
995 copy = strlen(cp=nv_name(np));
996 dp->nofree |= 1;
997 #if SHOPT_FIXEDARRAY
998 if(*sp==0)
999 name = cp;
1000 else
1001 #endif /* SHOPT_FIXEDARRAY */
1002 name = copystack(cp,sp,sub);
1003 sp = (char*)name + copy;
1004 cp = sp+c;
1005 c = *sp;
1006 if(!noscope)
1007 flags &= ~NV_NOSCOPE;
1008 #if SHOPT_FIXEDARRAY
1009 if(c==0)
1010 nv_endsubscript(np,null,NV_ADD);
1011 #endif /* SHOPT_FIXEDARRAY */
1012 }
1013 flags |= NV_NOREF;
1014 if(*cp==0 && nv_isnull(np) && !nv_isarray(np))
1015 nofree = NV_NOFREE;
1016 }
1017 shp->last_root = root;
1018 if(*cp && cp[1]=='.')
1019 cp++;
1020 if(c=='.' && (cp[1]==0 || cp[1]=='=' || cp[1]=='+'))
1021 {
1022 nv_local = 1;
1023 if(np)
1024 nv_onattr(np,nofree);
1025 return(np);
1026 }
1027 if(cp[-1]=='.')
1028 cp--;
1029 do
1030 {
1031 #if SHOPT_FIXEDARRAY
1032 int fixed;
1033 #endif /* SHOPT_FIXEDARRAY */
1034 if(!np)
1035 {
1036 if(!nq && *sp=='[' && *cp==0 && cp[-1]==']')
1037 {
1038 /*
1039 * for backward compatibility
1040 * evaluate subscript for
1041 * possible side effects
1042 */
1043 cp[-1] = 0;
1044 sh_arith(shp,sp+1);
1045 cp[-1] = ']';
1046 }
1047 return(np);
1048 }
1049 #if SHOPT_FIXEDARRAY
1050 fixed = 0;
1051 if((ap=nv_arrayptr(np)) && ap->fixed)
1052 fixed = 1;
1053 #endif /* SHOPT_FIXEDARRAY */
1054 if(c=='[' || (c=='.' && nv_isarray(np)))
1055 {
1056 int n = 0;
1057 sub = 0;
1058 mode &= ~HASH_NOSCOPE;
1059 if(c=='[')
1060 {
1061 #if SHOPT_FIXEDARRAY
1062 Namarr_t *ap = nv_arrayptr(np);
1063 #endif /* SHOPT_FIXEDARRAY */
1064 #if 0
1065 int scan = ap?(ap->nelem&ARRAY_SCAN):0;
1066 #endif
1067 n = mode|nv_isarray(np);
1068 if(!mode && (flags&NV_ARRAY) && ((c=sp[1])=='*' || c=='@') && sp[2]==']')
1069 {
1070 /* not implemented yet */
1071 dp->last = cp;
1072 return(np);
1073 }
1074 #if SHOPT_FIXEDARRAY
1075 if(fixed)
1076 flags |= NV_FARRAY;
1077 else
1078 #endif /* SHOPT_FIXEDARRAY */
1079 if((n&NV_ADD)&&(flags&NV_ARRAY))
1080 n |= ARRAY_FILL;
1081 if(flags&NV_ASSIGN)
1082 n |= NV_ADD;
1083 cp = nv_endsubscript(np,sp,n|(flags&(NV_ASSIGN|NV_FARRAY)));
1084 #if SHOPT_FIXEDARRAY
1085 flags &= ~NV_FARRAY;
1086 if(fixed)
1087 flags &= ~NV_ARRAY;
1088
1089 #endif /* SHOPT_FIXEDARRAY */
1090 #if 0
1091 if(scan)
1092 nv_putsub(np,NIL(char*),ARRAY_SCAN);
1093 #endif
1094 }
1095 else
1096 cp = sp;
1097 if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || ((ap || (flags&NV_ASSIGN)) && (flags&NV_ARRAY)))
1098
1099 {
1100 int m = cp-sp;
1101 sub = m?nv_getsub(np):0;
1102 if(!sub)
1103 {
1104 if(m && !(n&NV_ADD))
1105 return(0);
1106 sub = "0";
1107 }
1108 n = strlen(sub)+2;
1109 if(!copy)
1110 {
1111 copy = cp-name;
1112 dp->nofree |= 1;
1113 name = copystack((const char*)0, name,(const char*)0);
1114 cp = (char*)name+copy;
1115 sp = cp-m;
1116 }
1117 if(n <= m)
1118 {
1119 if(n)
1120 {
1121 memcpy(sp+1,sub,n-2);
1122 sp[n-1] = ']';
1123 }
1124 if(n < m)
1125 {
1126 char *dp = sp+n;
1127 while(*dp++=*cp++);
1128 cp = sp+n;
1129 }
1130 }
1131 else
1132 {
1133 int r = n-m;
1134 m = sp-name;
1135 name = stack_extend(name, cp-1, r);
1136 sp = (char*)name + m;
1137 *sp = '[';
1138 memcpy(sp+1,sub,n-2);
1139 sp[n-1] = ']';
1140 cp = sp+n;
1141
1142 }
1143 }
1144 else if(c==0 && mode && (n=nv_aindex(np))>0)
1145 nv_putsub(np,(char*)0,n);
1146 #if SHOPT_FIXEDARRAY
1147 else if(n==0 && !fixed && (c==0 || (c=='[' && !nv_isarray(np))))
1148 #else
1149 else if(n==0 && (c==0 || (c=='[' && !nv_isarray(np))))
1150 #endif /* SHOPT_FIXEDARRAY */
1151 {
1152 /* subscript must be 0*/
1153 cp[-1] = 0;
1154 n = sh_arith(shp,sp+1);
1155 cp[-1] = ']';
1156 if(n)
1157 return(0);
1158 if(c)
1159 sp = cp;
1160 }
1161 dp->last = cp;
1162 if(nv_isarray(np) && (c=='[' || c=='.' || (flags&NV_ARRAY)))
1163 {
1164 addsub:
1165 sp = cp;
1166 if(!(nq = nv_opensub(np)))
1167 {
1168 Namarr_t *ap = nv_arrayptr(np);
1169 if(!sub && (flags&NV_NOADD))
1170 return(0);
1171 n = mode|((flags&NV_NOADD)?0:NV_ADD);
1172 if(!ap && (n&NV_ADD))
1173 {
1174 nv_putsub(np,sub,ARRAY_FILL);
1175 ap = nv_arrayptr(np);
1176 }
1177 if(n && ap && !ap->table)
1178 ap->table = dtopen(&_Nvdisc,Dtoset);
1179 if(ap && ap->table && (nq=nv_search(sub,ap->table,n)))
1180 nq->nvenv = (char*)np;
1181 if(nq && nv_isnull(nq))
1182 nq = nv_arraychild(np,nq,c);
1183 }
1184 if(nq)
1185 {
1186 if(c=='.' && !nv_isvtree(nq))
1187 {
1188 if(flags&NV_NOADD)
1189 return(0);
1190 nv_setvtree(nq);
1191 }
1192 nv_onattr(np,nofree);
1193 nofree = 0;
1194 np = nq;
1195 }
1196 else if(memcmp(cp,"[0]",3))
1197 return(nq);
1198 else
1199 {
1200 /* ignore [0] */
1201 dp->last = cp += 3;
1202 c = *cp;
1203 }
1204 }
1205 }
1206 #if SHOPT_FIXEDARRAY
1207 else if(nv_isarray(np) && (!fixed || cp[-1]!=']'))
1208 #else
1209 else if(nv_isarray(np))
1210 #endif /* SHOPT_FIXEDARRAY */
1211 {
1212 if(c==0 && (flags&NV_MOVE))
1213 return(np);
1214 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1215 }
1216 nv_onattr(np,nofree);
1217 nofree = 0;
1218 if(c=='.' && (fp=np->nvfun))
1219 {
1220 for(; fp; fp=fp->next)
1221 {
1222 if(fp->disc && fp->disc->createf)
1223 break;
1224 }
1225 if(fp)
1226 {
1227 if((nq = (*fp->disc->createf)(np,cp+1,flags,fp)) == np)
1228 {
1229 add = NV_ADD;
1230 shp->last_table = 0;
1231 break;
1232 }
1233 else if(np=nq)
1234 {
1235 if((c = *(sp=cp=dp->last=fp->last))==0)
1236 {
1237 if(nv_isarray(np) && sp[-1]!=']')
1238 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1239 return(np);
1240 }
1241 }
1242 }
1243 }
1244 }
1245 while(c=='[');
1246 if(c!='.' || cp[1]=='.')
1247 return(np);
1248 cp++;
1249 break;
1250 default:
1251 dp->last = cp;
1252 if((c = mbchar(cp)) && !isaletter(c))
1253 return(np);
1254 while(xp=cp, c=mbchar(cp), isaname(c));
1255 cp = xp;
1256 }
1257 }
1258 return(np);
1259 }
1260
1261 /*
1262 * delete the node <np> from the dictionary <root> and clear from the cache
1263 * if <root> is NULL, only the cache is cleared
1264 * if flags does not contain NV_NOFREE, the node is freed
1265 * if np==0 && !root && flags==0, delete the Refdict dictionary
1266 */
nv_delete(Namval_t * np,Dt_t * root,int flags)1267 void nv_delete(Namval_t* np, Dt_t *root, int flags)
1268 {
1269 #if NVCACHE
1270 register int c;
1271 struct Cache_entry *xp;
1272 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
1273 {
1274 if(xp->np==np)
1275 xp->root = 0;
1276 }
1277 #endif
1278 if(!np && !root && flags==0)
1279 {
1280 if(Refdict)
1281 dtclose(Refdict);
1282 Refdict = 0;
1283 return;
1284 }
1285 if(root || !(flags&NV_NOFREE))
1286 {
1287 if(!(flags&NV_FUNCTION) && Refdict)
1288 {
1289 Namval_t **key = &np;
1290 struct Namref *rp;
1291 while(rp = (struct Namref*)dtmatch(Refdict,(void*)key))
1292 {
1293 if(rp->sub)
1294 free(rp->sub);
1295 rp->sub = 0;
1296 rp = dtdelete(Refdict,(void*)rp);
1297 rp->np = &NullNode;
1298 }
1299 }
1300 }
1301 if(root)
1302 {
1303 if(dtdelete(root,np))
1304 {
1305 if(!(flags&NV_NOFREE) && ((flags&NV_FUNCTION) || !nv_subsaved(np)))
1306 {
1307 Namarr_t *ap;
1308 if(nv_isarray(np) && np->nvfun &&
1309 (ap=nv_arrayptr(np)) && array_assoc(ap)) {
1310 while(nv_associative(np,0,NV_ANEXT))
1311 nv_associative(np, 0, NV_ADELETE);
1312 nv_associative(np, 0, NV_AFREE);
1313 free((void*)np->nvfun);
1314 }
1315 free((void*)np);
1316 }
1317 }
1318 #if 0
1319 else
1320 {
1321 sfprintf(sfstderr,"%s not deleted\n",nv_name(np));
1322 sfsync(sfstderr);
1323 }
1324 #endif
1325 }
1326 }
1327
1328 /*
1329 * Put <arg> into associative memory.
1330 * If <flags> & NV_ARRAY then follow array to next subscript
1331 * If <flags> & NV_NOARRAY then subscript is not allowed
1332 * If <flags> & NV_NOSCOPE then use the current scope only
1333 * If <flags> & NV_ASSIGN then assignment is allowed
1334 * If <flags> & NV_IDENT then name must be an identifier
1335 * If <flags> & NV_VARNAME then name must be a valid variable name
1336 * If <flags> & NV_NOADD then node will not be added if not found
1337 * If <flags> & NV_NOREF then don't follow reference
1338 * If <flags> & NV_NOFAIL then don't generate an error message on failure
1339 * If <flags> & NV_STATIC then unset before an assignment
1340 * If <flags> & NV_UNJUST then unset attributes before assignment
1341 * SH_INIT is only set while initializing the environment
1342 */
nv_open(const char * name,Dt_t * root,int flags)1343 Namval_t *nv_open(const char *name, Dt_t *root, int flags)
1344 {
1345 Shell_t *shp = sh_getinterp();
1346 register char *cp=(char*)name;
1347 register int c;
1348 register Namval_t *np=0;
1349 Namfun_t fun;
1350 int append=0;
1351 const char *msg = e_varname;
1352 char *fname = 0;
1353 int offset = staktell();
1354 Dt_t *funroot;
1355 #if NVCACHE
1356 struct Cache_entry *xp;
1357 #endif
1358
1359 sh_stats(STAT_NVOPEN);
1360 memset(&fun,0,sizeof(fun));
1361 shp->openmatch = 0;
1362 shp->last_table = 0;
1363 if(!root)
1364 root = shp->var_tree;
1365 shp->last_root = root;
1366 if(root==shp->fun_tree)
1367 {
1368 flags |= NV_NOREF;
1369 msg = e_badfun;
1370 if(strchr(name,'.'))
1371 {
1372 name = cp = copystack(0,name,(const char*)0);
1373 fname = strrchr(cp,'.');
1374 *fname = 0;
1375 fun.nofree |= 1;
1376 flags &= ~NV_IDENT;
1377 funroot = root;
1378 root = shp->var_tree;
1379 }
1380 }
1381 else if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
1382 {
1383 long mode = ((flags&NV_NOADD)?0:NV_ADD);
1384 if(flags&NV_NOSCOPE)
1385 mode |= HASH_SCOPE|HASH_NOSCOPE;
1386 np = nv_search(name,root,mode);
1387 if(np && !(flags&NV_REF))
1388 {
1389 while(nv_isref(np))
1390 {
1391 shp->last_table = nv_reftable(np);
1392 np = nv_refnode(np);
1393 }
1394 }
1395 return(np);
1396 }
1397 else if(shp->prefix && (flags&NV_ASSIGN))
1398 {
1399 name = cp = copystack(shp->prefix,name,(const char*)0);
1400 fun.nofree |= 1;
1401 }
1402 c = *(unsigned char*)cp;
1403 if(root==shp->alias_tree)
1404 {
1405 msg = e_aliname;
1406 while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
1407 (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON));
1408 if(shp->subshell && c=='=')
1409 root = sh_subaliastree(1);
1410 if(c= *--cp)
1411 *cp = 0;
1412 np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
1413 if(c)
1414 *cp = c;
1415 goto skip;
1416 }
1417 else if(flags&NV_IDENT)
1418 msg = e_ident;
1419 else if(c=='.')
1420 {
1421 c = *++cp;
1422 flags |= NV_NOREF;
1423 if(root==shp->var_tree)
1424 root = shp->var_base;
1425 shp->last_table = 0;
1426 }
1427 if(c= !isaletter(c))
1428 goto skip;
1429 #if NVCACHE
1430 for(c=0,xp=nvcache.entries ; c < NVCACHE; xp= &nvcache.entries[++c])
1431 {
1432 if(xp->root!=root)
1433 continue;
1434 if(*name==*xp->name && xp->namespace==shp->namespace && (flags&(NV_ARRAY|NV_NOSCOPE))==xp->flags && memcmp(xp->name,name,xp->len)==0 && (name[xp->len]==0 || name[xp->len]=='=' || name[xp->len]=='+'))
1435 {
1436 sh_stats(STAT_NVHITS);
1437 np = xp->np;
1438 cp = (char*)name+xp->len;
1439 if(nv_isarray(np) && !(flags&NV_MOVE))
1440 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1441 shp->last_table = xp->last_table;
1442 shp->last_root = xp->last_root;
1443 goto nocache;
1444 }
1445 }
1446 nvcache.ok = 1;
1447 #endif
1448 np = nv_create(name, root, flags, &fun);
1449 cp = fun.last;
1450 #if NVCACHE
1451 if(np && nvcache.ok && cp[-1]!=']')
1452 {
1453 xp = &nvcache.entries[nvcache.index];
1454 if(*cp)
1455 {
1456 char *sp = strchr(name,*cp);
1457 if(!sp)
1458 goto nocache;
1459 xp->len = sp-name;
1460 }
1461 else
1462 xp->len = strlen(name);
1463 c = roundof(xp->len+1,32);
1464 if(c > xp->size)
1465 {
1466 if(xp->size==0)
1467 xp->name = malloc(c);
1468 else
1469 xp->name = realloc(xp->name,c);
1470 xp->size = c;
1471 }
1472 memcpy(xp->name,name,xp->len);
1473 xp->name[xp->len] = 0;
1474 xp->root = root;
1475 xp->np = np;
1476 xp->namespace = shp->namespace;
1477 xp->last_table = shp->last_table;
1478 xp->last_root = shp->last_root;
1479 xp->flags = (flags&(NV_ARRAY|NV_NOSCOPE));
1480 nvcache.index = (nvcache.index+1)&(NVCACHE-1);
1481 }
1482 nocache:
1483 nvcache.ok = 0;
1484 #endif
1485 if(fname)
1486 {
1487 c = ((flags&NV_NOSCOPE)?HASH_NOSCOPE:0)|((flags&NV_NOADD)?0:NV_ADD);
1488 *fname = '.';
1489 np = nv_search(name, funroot, c);
1490 *fname = 0;
1491 }
1492 else
1493 {
1494 if(*cp=='.' && cp[1]=='.')
1495 {
1496 append |= NV_NODISC;
1497 cp+=2;
1498 }
1499 if(*cp=='+' && cp[1]=='=')
1500 {
1501 append |= NV_APPEND;
1502 cp++;
1503 }
1504 }
1505 c = *cp;
1506 skip:
1507 #if SHOPT_TYPEDEF
1508 if(np && shp->mktype)
1509 np = nv_addnode(np,0);
1510 #endif /* SHOPT_TYPEDEF */
1511 if(c=='=' && np && (flags&NV_ASSIGN))
1512 {
1513 cp++;
1514 if(sh_isstate(SH_INIT))
1515 {
1516 nv_putval(np, cp, NV_RDONLY);
1517 if(np==PWDNOD)
1518 nv_onattr(np,NV_TAGGED);
1519 }
1520 else
1521 {
1522 char *sub=0, *prefix= shp->prefix;
1523 Namval_t *mp;
1524 Namarr_t *ap;
1525 int isref;
1526 shp->prefix = 0;
1527 if((flags&NV_STATIC) && !shp->mktype)
1528 {
1529 if(!nv_isnull(np))
1530 {
1531 shp->prefix = prefix;
1532 return(np);
1533 }
1534 }
1535 isref = nv_isref(np);
1536 #if SHOPT_FIXEDARRAY
1537 if(sh_isoption(SH_XTRACE) && (ap=nv_arrayptr(np)) && !ap->fixed)
1538 #else
1539 if(sh_isoption(SH_XTRACE) && nv_isarray(np))
1540 #endif /* SHOPT_FIXEDARRAY */
1541 sub = nv_getsub(np);
1542 c = msg==e_aliname? 0: (append | (flags&NV_EXPORT));
1543 if(isref)
1544 nv_offattr(np,NV_REF);
1545 if(!append && (flags&NV_UNJUST))
1546 {
1547 if(!np->nvfun)
1548 _nv_unset(np,NV_EXPORT);
1549 }
1550 if(flags&NV_MOVE)
1551 {
1552 if(ap=nv_arrayptr(np))
1553 {
1554 if(mp=nv_opensub(np))
1555 np = mp;
1556 else if(!array_assoc(ap) && (mp = nv_open(cp,shp->var_tree,NV_NOFAIL|NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOADD)) && nv_isvtree(np))
1557 {
1558 ap->nelem |= ARRAY_TREE;
1559 nv_putsub(np,(char*)0,ARRAY_ADD|nv_aindex(np));
1560 np = nv_opensub(np);
1561 ap->nelem &= ~ARRAY_TREE;
1562 ap->nelem -= 1;
1563 }
1564 }
1565 _nv_unset(np,NV_EXPORT);
1566 }
1567 nv_putval(np, cp, c);
1568 if(isref)
1569 {
1570 if(nv_search((char*)np,shp->var_base,HASH_BUCKET))
1571 shp->last_root = shp->var_base;
1572 nv_setref(np,(Dt_t*)0,NV_VARNAME);
1573 }
1574 savesub = sub;
1575 shp->prefix = prefix;
1576 }
1577 nv_onattr(np, flags&NV_ATTRIBUTES);
1578 }
1579 else if(c)
1580 {
1581 if(flags&NV_NOFAIL)
1582 return(0);
1583 if(c=='.')
1584 msg = e_noparent;
1585 else if(c=='[')
1586 msg = e_noarray;
1587 errormsg(SH_DICT,ERROR_exit(1),msg,name);
1588 }
1589 if(fun.nofree&1)
1590 stakseek(offset);
1591 return(np);
1592 }
1593
1594 #if SHOPT_MULTIBYTE
1595 static int ja_size(char*, int, int);
1596 static void ja_restore(void);
1597 static char *savep;
1598 static char savechars[8+1];
1599 #endif /* SHOPT_MULTIBYTE */
1600
1601 /*
1602 * put value <string> into name-value node <np>.
1603 * If <np> is an array, then the element given by the
1604 * current index is assigned to.
1605 * If <flags> contains NV_RDONLY, readonly attribute is ignored
1606 * If <flags> contains NV_INTEGER, string is a pointer to a number
1607 * If <flags> contains NV_NOFREE, previous value is freed, and <string>
1608 * becomes value of node and <flags> becomes attributes
1609 */
nv_putval(register Namval_t * np,const char * string,int flags)1610 void nv_putval(register Namval_t *np, const char *string, int flags)
1611 {
1612 Shell_t *shp = sh_getinterp();
1613 register const char *sp=string;
1614 register union Value *up;
1615 register char *cp;
1616 register int size = 0;
1617 register int dot;
1618 int was_local = nv_local;
1619 union Value u;
1620 #if SHOPT_FIXEDARRAY
1621 Namarr_t *ap;
1622 #endif /* SHOPT_FIXEDARRAY */
1623 if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
1624 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1625 /* The following could cause the shell to fork if assignment
1626 * would cause a side effect
1627 */
1628 shp->argaddr = 0;
1629 if(shp->subshell && !nv_local && !(flags&NV_RDONLY))
1630 np = sh_assignok(np,1);
1631 if(np->nvfun && np->nvfun->disc && !(flags&NV_NODISC) && !nv_isref(np))
1632 {
1633 /* This function contains disc */
1634 if(!nv_local)
1635 {
1636 nv_local=1;
1637 nv_putv(np,sp,flags,np->nvfun);
1638 if(sp && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
1639 sh_envput(shp->env,np);
1640 return;
1641 }
1642 /* called from disc, assign the actual value */
1643 }
1644 flags &= ~NV_NODISC;
1645 nv_local=0;
1646 if(flags&(NV_NOREF|NV_NOFREE))
1647 {
1648 if(np->nvalue.cp && np->nvalue.cp!=sp && !nv_isattr(np,NV_NOFREE))
1649 free((void*)np->nvalue.cp);
1650 np->nvalue.cp = (char*)sp;
1651 nv_setattr(np,(flags&~NV_RDONLY)|NV_NOFREE);
1652 return;
1653 }
1654 up= &np->nvalue;
1655 if(nv_isattr(np,NV_INT16P) == NV_INT16)
1656 {
1657 if(!np->nvalue.up || !nv_isarray(np))
1658 {
1659 up = &u;
1660 up->up = &np->nvalue;
1661 }
1662 }
1663 #if SHOPT_FIXEDARRAY
1664 else if(np->nvalue.up && nv_isarray(np) && (ap=nv_arrayptr(np)) && !ap->fixed)
1665 #else
1666 else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np))
1667 #endif /* SHOPT_FIXEDARRAY */
1668 up = np->nvalue.up;
1669 if(up && up->cp==Empty)
1670 up->cp = 0;
1671 if(nv_isattr(np,NV_EXPORT))
1672 nv_offattr(np,NV_IMPORT);
1673 if(nv_isattr (np, NV_INTEGER))
1674 {
1675 if(nv_isattr(np, NV_DOUBLE) == NV_DOUBLE)
1676 {
1677 if(nv_isattr(np, NV_LONG) && sizeof(double)<sizeof(Sfdouble_t))
1678 {
1679 Sfdouble_t ld, old=0;
1680 if(flags&NV_INTEGER)
1681 {
1682 if(flags&NV_LONG)
1683 ld = *((Sfdouble_t*)sp);
1684 else if(flags&NV_SHORT)
1685 ld = *((float*)sp);
1686 else
1687 ld = *((double*)sp);
1688 }
1689 else
1690 ld = sh_arith(shp,sp);
1691 if(!up->ldp)
1692 up->ldp = new_of(Sfdouble_t,0);
1693 else if(flags&NV_APPEND)
1694 old = *(up->ldp);
1695 *(up->ldp) = old?ld+old:ld;
1696 }
1697 else
1698 {
1699 double d,od=0;
1700 if(flags&NV_INTEGER)
1701 {
1702 if(flags&NV_LONG)
1703 d = (double)(*(Sfdouble_t*)sp);
1704 else if(flags&NV_SHORT)
1705 d = (double)(*(float*)sp);
1706 else
1707 d = *(double*)sp;
1708 }
1709 else
1710 d = sh_arith(shp,sp);
1711 if(!up->dp)
1712 up->dp = new_of(double,0);
1713 else if(flags&NV_APPEND)
1714 od = *(up->dp);
1715 *(up->dp) = od?d+od:d;
1716 }
1717 }
1718 else
1719 {
1720 if(nv_isattr(np, NV_LONG) && sizeof(int32_t)<sizeof(Sflong_t))
1721 {
1722 Sflong_t ll=0,oll=0;
1723 if(flags&NV_INTEGER)
1724 {
1725 if((flags&NV_DOUBLE) == NV_DOUBLE)
1726 {
1727 if(flags&NV_LONG)
1728 ll = *((Sfdouble_t*)sp);
1729 else if(flags&NV_SHORT)
1730 ll = *((float*)sp);
1731 else
1732 ll = *((double*)sp);
1733 }
1734 else if(nv_isattr(np,NV_UNSIGN))
1735 {
1736 if(flags&NV_LONG)
1737 ll = *((Sfulong_t*)sp);
1738 else if(flags&NV_SHORT)
1739 ll = *((uint16_t*)sp);
1740 else
1741 ll = *((uint32_t*)sp);
1742 }
1743 else
1744 {
1745 if(flags&NV_LONG)
1746 ll = *((Sflong_t*)sp);
1747 else if(flags&NV_SHORT)
1748 ll = *((uint16_t*)sp);
1749 else
1750 ll = *((uint32_t*)sp);
1751 }
1752 }
1753 else if(sp)
1754 ll = (Sflong_t)sh_arith(shp,sp);
1755 if(!up->llp)
1756 up->llp = new_of(Sflong_t,0);
1757 else if(flags&NV_APPEND)
1758 oll = *(up->llp);
1759 *(up->llp) = ll+oll;
1760 }
1761 else
1762 {
1763 int32_t l=0,ol=0;
1764 if(flags&NV_INTEGER)
1765 {
1766 if((flags&NV_DOUBLE) == NV_DOUBLE)
1767 {
1768 Sflong_t ll;
1769 if(flags&NV_LONG)
1770 ll = *((Sfdouble_t*)sp);
1771 else if(flags&NV_SHORT)
1772 ll = *((float*)sp);
1773 else
1774 ll = *((double*)sp);
1775 l = (int32_t)ll;
1776 }
1777 else if(nv_isattr(np,NV_UNSIGN))
1778 {
1779 if(flags&NV_LONG)
1780 l = *((Sfulong_t*)sp);
1781 else if(flags&NV_SHORT)
1782 l = *((uint16_t*)sp);
1783 else
1784 l = *(uint32_t*)sp;
1785 }
1786 else
1787 {
1788 if(flags&NV_LONG)
1789 l = *((Sflong_t*)sp);
1790 else if(flags&NV_SHORT)
1791 l = *((int16_t*)sp);
1792 else
1793 l = *(int32_t*)sp;
1794 }
1795 }
1796 else if(sp)
1797 {
1798 Sfdouble_t ld = sh_arith(shp,sp);
1799 if(ld<0)
1800 l = (int32_t)ld;
1801 else
1802 l = (uint32_t)ld;
1803 }
1804 if(nv_size(np) <= 1)
1805 nv_setsize(np,10);
1806 if(nv_isattr (np, NV_SHORT))
1807 {
1808 int16_t s=0;
1809 if(flags&NV_APPEND)
1810 s = *up->sp;
1811 *(up->sp) = s+(int16_t)l;
1812 nv_onattr(np,NV_NOFREE);
1813 }
1814 else
1815 {
1816 if(!up->lp)
1817 up->lp = new_of(int32_t,0);
1818 else if(flags&NV_APPEND)
1819 ol = *(up->lp);
1820 *(up->lp) = l+ol;
1821 }
1822 }
1823 }
1824 }
1825 else
1826 {
1827 const char *tofree=0;
1828 int offset,append;
1829 #if _lib_pathnative
1830 char buff[PATH_MAX];
1831 #endif /* _lib_pathnative */
1832 if(flags&NV_INTEGER)
1833 {
1834 if((flags&NV_DOUBLE)==NV_DOUBLE)
1835 {
1836 if(flags&NV_LONG)
1837 sfprintf(shp->strbuf,"%.*Lg",LDBL_DIG,*((Sfdouble_t*)sp));
1838 else
1839 sfprintf(shp->strbuf,"%.*g",DBL_DIG,*((double*)sp));
1840 }
1841 else if(flags&NV_UNSIGN)
1842 {
1843 if(flags&NV_LONG)
1844 sfprintf(shp->strbuf,"%I*lu",sizeof(Sfulong_t),*((Sfulong_t*)sp));
1845 else
1846 sfprintf(shp->strbuf,"%lu",(unsigned long)((flags&NV_SHORT)?*((uint16_t*)sp):*((uint32_t*)sp)));
1847 }
1848 else
1849 {
1850 if(flags&NV_LONG)
1851 sfprintf(shp->strbuf,"%I*ld",sizeof(Sflong_t),*((Sflong_t*)sp));
1852 else
1853 sfprintf(shp->strbuf,"%ld",(long)((flags&NV_SHORT)?*((int16_t*)sp):*((int32_t*)sp)));
1854 }
1855 sp = sfstruse(shp->strbuf);
1856 }
1857 if(nv_isattr(np, NV_HOST|NV_INTEGER)==NV_HOST && sp)
1858 {
1859 #ifdef _lib_pathnative
1860 /*
1861 * return the host file name given the UNIX name
1862 */
1863 pathnative(sp,buff,sizeof(buff));
1864 if(buff[1]==':' && buff[2]=='/')
1865 {
1866 buff[2] = '\\';
1867 if(*buff>='A' && *buff<='Z')
1868 *buff += 'a'-'A';
1869 }
1870 sp = buff;
1871 #else
1872 ;
1873 #endif /* _lib_pathnative */
1874 }
1875 else if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
1876 {
1877 for(;*sp == ' '|| *sp=='\t';sp++);
1878 if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
1879 for(;*sp=='0';sp++);
1880 size = nv_size(np);
1881 #if SHOPT_MULTIBYTE
1882 if(size)
1883 size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
1884 #endif /* SHOPT_MULTIBYTE */
1885 }
1886 if(!up->cp || *up->cp==0)
1887 flags &= ~NV_APPEND;
1888 if(!nv_isattr(np, NV_NOFREE))
1889 {
1890 /* delay free in case <sp> points into free region */
1891 tofree = up->cp;
1892 }
1893 if(nv_isattr(np,NV_BINARY) && !(flags&NV_RAW))
1894 tofree = 0;
1895 if(nv_isattr(np,NV_LJUST|NV_RJUST) && nv_isattr(np,NV_LJUST|NV_RJUST)!=(NV_LJUST|NV_RJUST))
1896 tofree = 0;
1897 if (sp)
1898 {
1899 append=0;
1900 if(sp==up->cp && !(flags&NV_APPEND))
1901 return;
1902 dot = strlen(sp);
1903 #if (_AST_VERSION>=20030127L)
1904 if(nv_isattr(np,NV_BINARY))
1905 {
1906 int oldsize = (flags&NV_APPEND)?nv_size(np):0;
1907 if(flags&NV_RAW)
1908 {
1909 if(tofree)
1910 {
1911 free((void*)tofree);
1912 nv_offattr(np,NV_NOFREE);
1913 }
1914 up->cp = sp;
1915 return;
1916 }
1917 size = 0;
1918 if(nv_isattr(np,NV_ZFILL))
1919 size = nv_size(np);
1920 if(size==0)
1921 size = oldsize + (3*dot/4);
1922 *(cp = (char*)malloc(size+1)) = 0;
1923 nv_offattr(np,NV_NOFREE);
1924 if(oldsize)
1925 memcpy((void*)cp,(void*)up->cp,oldsize);
1926 up->cp = cp;
1927 if(size <= oldsize)
1928 return;
1929 dot = base64decode(sp,dot, (void**)0, cp+oldsize, size-oldsize,(void**)0);
1930 dot += oldsize;
1931 if(!nv_isattr(np,NV_ZFILL) || nv_size(np)==0)
1932 nv_setsize(np,dot);
1933 else if(nv_isattr(np,NV_ZFILL) && (size>dot))
1934 memset((void*)&cp[dot],0,size-dot);
1935 return;
1936 }
1937 else
1938 #endif
1939 {
1940 if(size==0 && nv_isattr(np,NV_HOST)!=NV_HOST &&nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
1941 {
1942 nv_setsize(np,size=dot);
1943 tofree = up->cp;
1944 }
1945 else if(size > dot)
1946 dot = size;
1947 else if(nv_isattr(np,NV_LJUST|NV_RJUST)==NV_LJUST && dot>size)
1948 dot = size;
1949 if(flags&NV_APPEND)
1950 {
1951 if(dot==0)
1952 return;
1953 append = strlen(up->cp);
1954 if(!tofree || size)
1955 {
1956 offset = staktell();
1957 stakputs(up->cp);
1958 stakputs(sp);
1959 stakputc(0);
1960 sp = stakptr(offset);
1961 dot += append;
1962 append = 0;
1963 }
1964 else
1965 {
1966 flags &= ~NV_APPEND;
1967 }
1968 }
1969 }
1970 if(size==0 || tofree || dot || !(cp=(char*)up->cp))
1971 {
1972 if(dot==0 && !nv_isattr(np,NV_LJUST|NV_RJUST))
1973 {
1974 cp = Null;
1975 nv_onattr(np,NV_NOFREE);
1976 }
1977 else
1978 {
1979 if(tofree && tofree!=Empty && tofree!=Null)
1980 {
1981 cp = (char*)realloc((void*)tofree,((unsigned)dot+append+8));
1982 tofree = 0;
1983 }
1984 else
1985 cp = (char*)malloc(((unsigned)dot+8));
1986 cp[dot+append] = 0;
1987 nv_offattr(np,NV_NOFREE);
1988 }
1989 }
1990
1991 }
1992 else
1993 cp = 0;
1994 up->cp = cp;
1995 if(sp)
1996 {
1997 int c = cp[dot+append];
1998 memmove(cp+append,sp,dot);
1999 cp[dot+append] = c;
2000 if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
2001 rightjust(cp,size,'0');
2002 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_RJUST)
2003 rightjust(cp,size,' ');
2004 else if(nv_isattr(np, NV_LJUST|NV_RJUST)==NV_LJUST)
2005 {
2006 register char *dp;
2007 dp = strlen (cp) + cp;
2008 cp = cp+size;
2009 for (; dp < cp; *dp++ = ' ');
2010 }
2011 #if SHOPT_MULTIBYTE
2012 /* restore original string */
2013 if(savep)
2014 ja_restore();
2015 #endif /* SHOPT_MULTIBYTE */
2016 }
2017 if(flags&NV_APPEND)
2018 stakseek(offset);
2019 if(tofree && tofree!=Empty && tofree!=Null)
2020 free((void*)tofree);
2021 }
2022 if(!was_local && ((flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT)))
2023 sh_envput(shp->env,np);
2024 return;
2025 }
2026
2027 /*
2028 *
2029 * Right-justify <str> so that it contains no more than
2030 * <size> characters. If <str> contains fewer than <size>
2031 * characters, left-pad with <fill>. Trailing blanks
2032 * in <str> will be ignored.
2033 *
2034 * If the leftmost digit in <str> is not a digit, <fill>
2035 * will default to a blank.
2036 */
rightjust(char * str,int size,int fill)2037 static void rightjust(char *str, int size, int fill)
2038 {
2039 register int n;
2040 register char *cp,*sp;
2041 n = strlen(str);
2042
2043 /* ignore trailing blanks */
2044 for(cp=str+n;n && *--cp == ' ';n--);
2045 if (n == size)
2046 return;
2047 if(n > size)
2048 {
2049 *(str+n) = 0;
2050 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
2051 return;
2052 }
2053 else *(sp = str+size) = 0;
2054 if (n == 0)
2055 {
2056 while (sp > str)
2057 *--sp = ' ';
2058 return;
2059 }
2060 while(n--)
2061 {
2062 sp--;
2063 *sp = *cp--;
2064 }
2065 if(!isdigit(*str))
2066 fill = ' ';
2067 while(sp>str)
2068 *--sp = fill;
2069 return;
2070 }
2071
2072 #if SHOPT_MULTIBYTE
2073 /*
2074 * handle left and right justified fields for multi-byte chars
2075 * given physical size, return a logical size which reflects the
2076 * screen width of multi-byte characters
2077 * Multi-width characters replaced by spaces if they cross the boundary
2078 * <type> is non-zero for right justified fields
2079 */
2080
ja_size(char * str,int size,int type)2081 static int ja_size(char *str,int size,int type)
2082 {
2083 register char *cp = str;
2084 register int c, n=size;
2085 register int outsize;
2086 register char *oldcp=cp;
2087 int oldn;
2088 wchar_t w;
2089 while(*cp)
2090 {
2091 oldn = n;
2092 w = mbchar(cp);
2093 if((outsize = mbwidth(w)) <0)
2094 outsize = 0;
2095 size -= outsize;
2096 c = cp-oldcp;
2097 n += (c-outsize);
2098 oldcp = cp;
2099 if(size<=0 && type==0)
2100 break;
2101 }
2102 /* check for right justified fields that need truncating */
2103 if(size <0)
2104 {
2105 if(type==0)
2106 {
2107 /* left justified and character crosses field boundary */
2108 n = oldn;
2109 /* save boundary char and replace with spaces */
2110 size = c;
2111 savechars[size] = 0;
2112 while(size--)
2113 {
2114 savechars[size] = cp[size];
2115 cp[size] = ' ';
2116 }
2117 savep = cp;
2118 }
2119 size = -size;
2120 if(type)
2121 n -= (ja_size(str,size,0)-size);
2122 }
2123 return(n);
2124 }
2125
ja_restore(void)2126 static void ja_restore(void)
2127 {
2128 register char *cp = savechars;
2129 while(*cp)
2130 *savep++ = *cp++;
2131 savep = 0;
2132 }
2133 #endif /* SHOPT_MULTIBYTE */
2134
2135 #ifndef _ENV_H
staknam(register Namval_t * np,char * value)2136 static char *staknam(register Namval_t *np, char *value)
2137 {
2138 register char *p,*q;
2139 q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
2140 p=strcopy(q,nv_name(np));
2141 if(value)
2142 {
2143 *p++ = '=';
2144 strcpy(p,value);
2145 }
2146 return(q);
2147 }
2148 #endif
2149
2150 /*
2151 * put the name and attribute into value of attributes variable
2152 */
2153 #ifdef _ENV_H
attstore(register Namval_t * np,void * data)2154 static void attstore(register Namval_t *np, void *data)
2155 {
2156 register int flag, c = ' ';
2157 NOT_USED(data);
2158 if(!(nv_isattr(np,NV_EXPORT)))
2159 return;
2160 flag = nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
2161 stakputc('=');
2162 if((flag&NV_DOUBLE) == NV_DOUBLE)
2163 {
2164 /* export doubles as integers for ksh88 compatibility */
2165 stakputc(c+NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE)));
2166 }
2167 else
2168 {
2169 stakputc(c+flag);
2170 if(flag&NV_INTEGER)
2171 c += nv_size(np);
2172 }
2173 stakputc(c);
2174 stakputs(nv_name(np));
2175 }
2176 #else
attstore(register Namval_t * np,void * data)2177 static void attstore(register Namval_t *np, void *data)
2178 {
2179 register int flag = np->nvflag;
2180 register struct adata *ap = (struct adata*)data;
2181 ap->sh = sh_getinterp();
2182 ap->tp = 0;
2183 if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
2184 return;
2185 if((flag&(NV_UTOL|NV_LTOU|NV_INTEGER)) == (NV_UTOL|NV_LTOU))
2186 {
2187 data = (void*)nv_mapchar(np,0);
2188 if(strcmp(data,e_tolower) && strcmp(data,e_toupper))
2189 return;
2190 }
2191 flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
2192 *ap->attval++ = '=';
2193 if((flag&NV_DOUBLE) == NV_DOUBLE)
2194 {
2195 /* export doubles as integers for ksh88 compatibility */
2196 *ap->attval++ = ' '+ NV_INTEGER|(flag&~(NV_DOUBLE|NV_EXPNOTE));
2197 *ap->attval = ' ';
2198 }
2199 else
2200 {
2201 *ap->attval++ = ' '+flag;
2202 if(flag&NV_INTEGER)
2203 *ap->attval = ' ' + nv_size(np);
2204 else
2205 *ap->attval = ' ';
2206 }
2207 ap->attval = strcopy(++ap->attval,nv_name(np));
2208 }
2209 #endif
2210
2211 #ifndef _ENV_H
pushnam(Namval_t * np,void * data)2212 static void pushnam(Namval_t *np, void *data)
2213 {
2214 register char *value;
2215 register struct adata *ap = (struct adata*)data;
2216 ap->sh = sh_getinterp();
2217 ap->tp = 0;
2218 if(nv_isattr(np,NV_IMPORT) && np->nvenv)
2219 *ap->argnam++ = np->nvenv;
2220 else if(value=nv_getval(np))
2221 *ap->argnam++ = staknam(np,value);
2222 if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
2223 ap->attsize += (strlen(nv_name(np))+4);
2224 }
2225 #endif
2226
2227 /*
2228 * Generate the environment list for the child.
2229 */
2230
2231 #ifdef _ENV_H
sh_envgen(void)2232 char **sh_envgen(void)
2233 {
2234 Shell_t *shp = sh_getinterp();
2235 int offset,tell;
2236 register char **er;
2237 env_delete(shp->env,"_");
2238 er = env_get(shp->env);
2239 offset = staktell();
2240 stakputs(e_envmarker);
2241 tell = staktell();
2242 nv_scan(shp->var_tree, attstore,(void*)0,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
2243 if(tell ==staktell())
2244 stakseek(offset);
2245 else
2246 *--er = stakfreeze(1)+offset;
2247 return(er);
2248 }
2249 #else
sh_envgen(void)2250 char **sh_envgen(void)
2251 {
2252 register char **er;
2253 register int namec;
2254 register char *cp;
2255 struct adata data;
2256 Shell_t *shp = sh_getinterp();
2257 data.sh = shp;
2258 data.tp = 0;
2259 data.mapname = 0;
2260 /* L_ARGNOD gets generated automatically as full path name of command */
2261 nv_offattr(L_ARGNOD,NV_EXPORT);
2262 data.attsize = 6;
2263 namec = nv_scan(shp->var_tree,nullscan,(void*)0,NV_EXPORT,NV_EXPORT);
2264 namec += shp->nenv;
2265 er = (char**)stakalloc((namec+4)*sizeof(char*));
2266 data.argnam = (er+=2) + shp->nenv;
2267 if(shp->nenv)
2268 memcpy((void*)er,environ,shp->nenv*sizeof(char*));
2269 nv_scan(shp->var_tree, pushnam,&data,NV_EXPORT, NV_EXPORT);
2270 *data.argnam = (char*)stakalloc(data.attsize);
2271 cp = data.attval = strcopy(*data.argnam,e_envmarker);
2272 nv_scan(shp->var_tree, attstore,&data,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
2273 *data.attval = 0;
2274 if(cp!=data.attval)
2275 data.argnam++;
2276 *data.argnam = 0;
2277 return(er);
2278 }
2279 #endif
2280
2281 struct scan
2282 {
2283 void (*scanfn)(Namval_t*, void*);
2284 int scanmask;
2285 int scanflags;
2286 int scancount;
2287 void *scandata;
2288 };
2289
scanfilter(Dt_t * dict,void * arg,void * data)2290 static int scanfilter(Dt_t *dict, void *arg, void *data)
2291 {
2292 register Namval_t *np = (Namval_t*)arg;
2293 register int k=np->nvflag;
2294 register struct scan *sp = (struct scan*)data;
2295 register struct adata *tp = (struct adata*)sp->scandata;
2296 char *cp;
2297 NOT_USED(dict);
2298 #if SHOPT_TYPEDEF
2299 if(!is_abuiltin(np) && tp && tp->tp && nv_type(np)!=tp->tp)
2300 return(0);
2301 #endif /*SHOPT_TYPEDEF */
2302 if(sp->scanmask==NV_TABLE && nv_isvtree(np))
2303 k = NV_TABLE;
2304 if(sp->scanmask?(k&sp->scanmask)==sp->scanflags:(!sp->scanflags || (k&sp->scanflags)))
2305 {
2306 if(tp && tp->mapname)
2307 {
2308 if(sp->scanflags==NV_FUNCTION || sp->scanflags==(NV_NOFREE|NV_BINARY|NV_RAW))
2309 {
2310 int n = strlen(tp->mapname);
2311 if(memcmp(np->nvname,tp->mapname,n) || np->nvname[n]!='.' || strchr(&np->nvname[n+1],'.'))
2312 return(0);
2313 }
2314 else if((sp->scanflags==NV_UTOL||sp->scanflags==NV_LTOU) && (cp=(char*)nv_mapchar(np,0)) && strcmp(cp,tp->mapname))
2315 return(0);
2316 }
2317 if(!np->nvalue.cp && !np->nvfun && !nv_isattr(np,~NV_DEFAULT))
2318 return(0);
2319 if(sp->scanfn)
2320 {
2321 if(nv_isarray(np))
2322 nv_putsub(np,NIL(char*),0L);
2323 (*sp->scanfn)(np,sp->scandata);
2324 }
2325 sp->scancount++;
2326 }
2327 return(0);
2328 }
2329
2330 /*
2331 * Walk through the name-value pairs
2332 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
2333 * are visited
2334 * If <mask> is zero, and <flags> non-zero, then nodes with one or
2335 * more of <flags> is visited
2336 * If <mask> and <flags> are zero, then all nodes are visted
2337 */
nv_scan(Dt_t * root,void (* fn)(Namval_t *,void *),void * data,int mask,int flags)2338 int nv_scan(Dt_t *root, void (*fn)(Namval_t*,void*), void *data,int mask, int flags)
2339 {
2340 Namval_t *np;
2341 Dt_t *base=0;
2342 struct scan sdata;
2343 int (*hashfn)(Dt_t*, void*, void*);
2344 sdata.scanmask = mask;
2345 sdata.scanflags = flags&~NV_NOSCOPE;
2346 sdata.scanfn = fn;
2347 sdata.scancount = 0;
2348 sdata.scandata = data;
2349 hashfn = scanfilter;
2350 if(flags&NV_NOSCOPE)
2351 base = dtview((Dt_t*)root,0);
2352 for(np=(Namval_t*)dtfirst(root);np; np=(Namval_t*)dtnext(root,np))
2353 hashfn(root, np, &sdata);
2354 if(base)
2355 dtview((Dt_t*)root,base);
2356 return(sdata.scancount);
2357 }
2358
2359 /*
2360 * create a new environment scope
2361 */
sh_scope(Shell_t * shp,struct argnod * envlist,int fun)2362 void sh_scope(Shell_t *shp, struct argnod *envlist, int fun)
2363 {
2364 register Dt_t *newscope, *newroot=shp->var_base;
2365 struct Ufunction *rp;
2366 #if SHOPT_NAMESPACE
2367 if(shp->namespace)
2368 newroot = nv_dict(shp->namespace);
2369 #endif /* SHOPT_NAMESPACE */
2370 newscope = dtopen(&_Nvdisc,Dtoset);
2371 if(envlist)
2372 {
2373 dtview(newscope,(Dt_t*)shp->var_tree);
2374 shp->var_tree = newscope;
2375 nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN,0);
2376 if(!fun)
2377 return;
2378 shp->var_tree = dtview(newscope,0);
2379 }
2380 if((rp=shp->st.real_fun) && rp->sdict)
2381 {
2382 dtview(rp->sdict,newroot);
2383 newroot = rp->sdict;
2384
2385 }
2386 dtview(newscope,(Dt_t*)newroot);
2387 shp->var_tree = newscope;
2388 }
2389
2390 /*
2391 * Remove freeable local space associated with the nvalue field
2392 * of nnod. This includes any strings representing the value(s) of the
2393 * node, as well as its dope vector, if it is an array.
2394 */
2395
sh_envnolocal(register Namval_t * np,void * data)2396 void sh_envnolocal (register Namval_t *np, void *data)
2397 {
2398 struct adata *tp = (struct adata*)data;
2399 char *cp=0;
2400 if(np==VERSIONNOD && nv_isref(np))
2401 return;
2402 if(np==L_ARGNOD)
2403 return;
2404 if(np == tp->sh->namespace)
2405 return;
2406 if(nv_isref(np))
2407 nv_unref(np);
2408 if(nv_isattr(np,NV_EXPORT) && nv_isarray(np))
2409 {
2410 nv_putsub(np,NIL(char*),0);
2411 if(cp = nv_getval(np))
2412 cp = strdup(cp);
2413 }
2414 if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
2415 {
2416 if(nv_isref(np) && np!=VERSIONNOD)
2417 {
2418 nv_offattr(np,NV_NOFREE|NV_REF);
2419 free((void*)np->nvalue.nrp);
2420 np->nvalue.cp = 0;
2421 }
2422 if(!cp)
2423 return;
2424 }
2425 if(nv_isarray(np))
2426 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
2427 _nv_unset(np,NV_RDONLY);
2428 nv_setattr(np,0);
2429 if(cp)
2430 {
2431 nv_putval(np,cp,0);
2432 free((void*)cp);
2433 }
2434 }
2435
2436 /*
2437 * Currently this is a dummy, but someday will be needed
2438 * for reference counting
2439 */
nv_close(Namval_t * np)2440 void nv_close(Namval_t *np)
2441 {
2442 NOT_USED(np);
2443 }
2444
table_unset(Shell_t * shp,register Dt_t * root,int flags,Dt_t * oroot)2445 static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroot)
2446 {
2447 register Namval_t *np,*nq, *npnext;
2448 for(np=(Namval_t*)dtfirst(root);np;np=npnext)
2449 {
2450 if(nq=dtsearch(oroot,np))
2451 {
2452 if(nv_cover(nq))
2453 {
2454 int subshell = shp->subshell;
2455 shp->subshell = 0;
2456 if(nv_isattr(nq, NV_INTEGER))
2457 {
2458 Sfdouble_t d = nv_getnum(nq);
2459 nv_putval(nq,(char*)&d,NV_LDOUBLE);
2460 }
2461 else if(shp->test&4)
2462 nv_putval(nq, strdup(nv_getval(nq)), NV_RDONLY);
2463 else
2464 nv_putval(nq, nv_getval(nq), NV_RDONLY);
2465 shp->subshell = subshell;
2466 np->nvfun = 0;
2467 }
2468 if(nv_isattr(nq,NV_EXPORT))
2469 sh_envput(shp->env,nq);
2470 }
2471 shp->last_root = root;
2472 shp->last_table = 0;
2473 if(nv_isvtree(np))
2474 {
2475 int len = strlen(np->nvname);
2476 npnext = (Namval_t*)dtnext(root,np);
2477 while((nq=npnext) && memcmp(np->nvname,nq->nvname,len)==0 && nq->nvname[len]=='.')
2478
2479 {
2480 _nv_unset(nq,flags);
2481 npnext = (Namval_t*)dtnext(root,nq);
2482 nv_delete(nq,root,0);
2483 }
2484 }
2485 npnext = (Namval_t*)dtnext(root,np);
2486 _nv_unset(np,flags);
2487 nv_delete(np,root,0);
2488 }
2489 }
2490
2491 /*
2492 *
2493 * Set the value of <np> to 0, and nullify any attributes
2494 * that <np> may have had. Free any freeable space occupied
2495 * by the value of <np>. If <np> denotes an array member, it
2496 * will retain its attributes.
2497 * <flags> can contain NV_RDONLY to override the readonly attribute
2498 * being cleared.
2499 * <flags> can contain NV_EXPORT to override preserve nvenv
2500 */
_nv_unset(register Namval_t * np,int flags)2501 void _nv_unset(register Namval_t *np,int flags)
2502 {
2503 Shell_t *shp = sh_getinterp();
2504 register union Value *up;
2505 #if SHOPT_FIXEDARRAY
2506 Namarr_t *ap;
2507 #endif /* SHOPT_FIXEDARRAY */
2508 if(!(flags&NV_RDONLY) && nv_isattr (np,NV_RDONLY))
2509 errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
2510 if(is_afunction(np) && np->nvalue.ip)
2511 {
2512 register struct slnod *slp = (struct slnod*)(np->nvenv);
2513 if(shp->st.real_fun == np->nvalue.rp)
2514 {
2515 np->nvalue.rp->running |= 1;
2516 return;
2517 }
2518 if(slp && !nv_isattr(np,NV_NOFREE))
2519 {
2520 struct Ufunction *rq,*rp = np->nvalue.rp;
2521 /* free function definition */
2522 register char *name=nv_name(np),*cp= strrchr(name,'.');
2523 if(cp)
2524 {
2525 Namval_t *npv;
2526 *cp = 0;
2527 npv = nv_open(name,shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOADD);
2528 *cp++ = '.';
2529 if(npv && npv!=shp->namespace)
2530 nv_setdisc(npv,cp,NIL(Namval_t*),(Namfun_t*)npv);
2531 }
2532 if(rp->fname && shp->fpathdict && (rq = (struct Ufunction*)nv_search(rp->fname,shp->fpathdict,0)))
2533 {
2534 do
2535 {
2536 if(rq->np != np)
2537 continue;
2538 dtdelete(shp->fpathdict,rq);
2539 break;
2540 }
2541 while(rq = (struct Ufunction*)dtnext(shp->fpathdict,rq));
2542 }
2543 if(rp->sdict)
2544 {
2545 Namval_t *mp, *nq;
2546 for(mp=(Namval_t*)dtfirst(rp->sdict);mp;mp=nq)
2547 {
2548 nq = dtnext(rp->sdict,mp);
2549 _nv_unset(mp,NV_RDONLY);
2550 nv_delete(mp,rp->sdict,0);
2551 }
2552 dtclose(rp->sdict);
2553 }
2554 stakdelete(slp->slptr);
2555 free((void*)np->nvalue.ip);
2556 np->nvalue.ip = 0;
2557 }
2558 goto done;
2559 }
2560 if(shp->subshell)
2561 np = sh_assignok(np,0);
2562 nv_offattr(np,NV_NODISC);
2563 if(np->nvfun && !nv_isref(np))
2564 {
2565 /* This function contains disc */
2566 if(!nv_local)
2567 {
2568 nv_local=1;
2569 nv_putv(np,NIL(char*),flags,np->nvfun);
2570 nv_local=0;
2571 return;
2572 }
2573 /* called from disc, assign the actual value */
2574 nv_local=0;
2575 }
2576 if(nv_isattr(np,NV_INT16P) == NV_INT16)
2577 {
2578 np->nvalue.cp = nv_isarray(np)?Empty:0;
2579 goto done;
2580 }
2581 #if SHOPT_FIXEDARRAY
2582 else if(np->nvalue.up && nv_isarray(np) && (ap=nv_arrayptr(np)) && !ap->fixed)
2583 #else
2584 else if(np->nvalue.up && nv_isarray(np) && nv_arrayptr(np))
2585 #endif /* SHOPT_FIXEDARRAY */
2586 up = np->nvalue.up;
2587 else if(nv_isref(np) && !nv_isattr(np,NV_EXPORT|NV_MINIMAL) && np->nvalue.nrp)
2588 {
2589
2590 if(np->nvalue.nrp->root)
2591 dtdelete(Refdict,(void*)np->nvalue.nrp);
2592 if(np->nvalue.nrp->sub)
2593 free(np->nvalue.nrp->sub);
2594 free((void*)np->nvalue.nrp);
2595 np->nvalue.cp = 0;
2596 up = 0;
2597 }
2598 else
2599 up = &np->nvalue;
2600 if(up && up->cp)
2601 {
2602 if(up->cp!=Empty && up->cp!=Null && !nv_isattr(np, NV_NOFREE))
2603 free((void*)up->cp);
2604 up->cp = 0;
2605 }
2606 done:
2607 if(!nv_isarray(np) || !nv_arrayptr(np))
2608 {
2609 nv_setsize(np,0);
2610 if(!nv_isattr(np,NV_MINIMAL) || nv_isattr(np,NV_EXPORT))
2611 {
2612 if(nv_isattr(np,NV_EXPORT) && !strchr(np->nvname,'['))
2613 env_delete(shp->env,nv_name(np));
2614 if(!(flags&NV_EXPORT) || nv_isattr(np,NV_EXPORT))
2615 np->nvenv = 0;
2616 nv_setattr(np,0);
2617 }
2618 else
2619 {
2620 nv_setattr(np,NV_MINIMAL);
2621 nv_delete(np,(Dt_t*)0,0);
2622 }
2623 }
2624 }
2625
2626 /*
2627 * return the node pointer in the highest level scope
2628 */
sh_scoped(Shell_t * shp,register Namval_t * np)2629 Namval_t *sh_scoped(Shell_t *shp, register Namval_t *np)
2630 {
2631 if(!dtvnext(shp->var_tree))
2632 return(np);
2633 return(dtsearch(shp->var_tree,np));
2634 }
2635
2636 #if 1
2637 /*
2638 * return space separated list of names of variables in given tree
2639 */
tableval(Dt_t * root)2640 static char *tableval(Dt_t *root)
2641 {
2642 static Sfio_t *out;
2643 register Namval_t *np;
2644 register int first=1;
2645 register Dt_t *base = dtview(root,0);
2646 if(out)
2647 sfseek(out,(Sfoff_t)0,SEEK_SET);
2648 else
2649 out = sfnew((Sfio_t*)0,(char*)0,-1,-1,SF_WRITE|SF_STRING);
2650 for(np=(Namval_t*)dtfirst(root);np;np=(Namval_t*)dtnext(root,np))
2651 {
2652 if(!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE))
2653 {
2654 if(!first)
2655 sfputc(out,' ');
2656 else
2657 first = 0;
2658 sfputr(out,np->nvname,-1);
2659 }
2660 }
2661 sfputc(out,0);
2662 if(base)
2663 dtview(root,base);
2664 return((char*)out->_data);
2665 }
2666 #endif
2667
2668 #if SHOPT_OPTIMIZE
2669 struct optimize
2670 {
2671 Namfun_t hdr;
2672 Shell_t *sh;
2673 char **ptr;
2674 struct optimize *next;
2675 Namval_t *np;
2676 };
2677
2678 static struct optimize *opt_free;
2679
optimize_clear(Namval_t * np,Namfun_t * fp)2680 static void optimize_clear(Namval_t* np, Namfun_t *fp)
2681 {
2682 struct optimize *op = (struct optimize*)fp;
2683 nv_stack(np,fp);
2684 nv_stack(np,(Namfun_t*)0);
2685 for(;op && op->np==np; op=op->next)
2686 {
2687 if(op->ptr)
2688 {
2689 *op->ptr = 0;
2690 op->ptr = 0;
2691 }
2692 }
2693 }
2694
put_optimize(Namval_t * np,const char * val,int flags,Namfun_t * fp)2695 static void put_optimize(Namval_t* np,const char *val,int flags,Namfun_t *fp)
2696 {
2697 nv_putv(np,val,flags,fp);
2698 optimize_clear(np,fp);
2699 }
2700
clone_optimize(Namval_t * np,Namval_t * mp,int flags,Namfun_t * fp)2701 static Namfun_t *clone_optimize(Namval_t* np, Namval_t *mp, int flags, Namfun_t *fp)
2702 {
2703 return((Namfun_t*)0);
2704 }
2705
2706 static const Namdisc_t optimize_disc = {sizeof(struct optimize),put_optimize,0,0,0,0,clone_optimize};
2707
nv_optimize(Namval_t * np)2708 void nv_optimize(Namval_t *np)
2709 {
2710 Shell_t *shp = sh_getinterp();
2711 register Namfun_t *fp;
2712 register struct optimize *op, *xp;
2713 if(shp->argaddr)
2714 {
2715 if(np==SH_LINENO)
2716 {
2717 shp->argaddr = 0;
2718 return;
2719 }
2720 for(fp=np->nvfun; fp; fp = fp->next)
2721 {
2722 if(fp->disc && (fp->disc->getnum || fp->disc->getval))
2723 {
2724 shp->argaddr = 0;
2725 return;
2726 }
2727 if(fp->disc== &optimize_disc)
2728 break;
2729 }
2730 if((xp= (struct optimize*)fp) && xp->ptr==shp->argaddr)
2731 return;
2732 if(op = opt_free)
2733 opt_free = op->next;
2734 else
2735 op=(struct optimize*)calloc(1,sizeof(struct optimize));
2736 op->ptr = shp->argaddr;
2737 op->np = np;
2738 if(xp)
2739 {
2740 op->hdr.disc = 0;
2741 op->next = xp->next;
2742 xp->next = op;
2743 }
2744 else
2745 {
2746 op->hdr.disc = &optimize_disc;
2747 op->next = (struct optimize*)shp->optlist;
2748 shp->optlist = (void*)op;
2749 nv_stack(np,&op->hdr);
2750 }
2751 }
2752 }
2753
sh_optclear(Shell_t * shp,void * old)2754 void sh_optclear(Shell_t *shp, void *old)
2755 {
2756 register struct optimize *op,*opnext;
2757 for(op=(struct optimize*)shp->optlist; op; op = opnext)
2758 {
2759 opnext = op->next;
2760 if(op->ptr && op->hdr.disc)
2761 {
2762 nv_stack(op->np,&op->hdr);
2763 nv_stack(op->np,(Namfun_t*)0);
2764 }
2765 op->next = opt_free;
2766 opt_free = op;
2767 }
2768 shp->optlist = old;
2769 }
2770
2771 #else
2772 # define optimize_clear(np,fp)
2773 #endif /* SHOPT_OPTIMIZE */
2774
2775 /*
2776 * Return a pointer to a character string that denotes the value
2777 * of <np>. If <np> refers to an array, return a pointer to
2778 * the value associated with the current index.
2779 *
2780 * If the value of <np> is an integer, the string returned will
2781 * be overwritten by the next call to nv_getval.
2782 *
2783 * If <np> has no value, 0 is returned.
2784 */
2785
nv_getval(register Namval_t * np)2786 char *nv_getval(register Namval_t *np)
2787 {
2788 Shell_t *shp = sh_getinterp();
2789 register union Value *up= &np->nvalue;
2790 register int numeric;
2791 #if SHOPT_OPTIMIZE
2792 if(!nv_local && shp->argaddr)
2793 nv_optimize(np);
2794 #endif /* SHOPT_OPTIMIZE */
2795 if((!np->nvfun || !np->nvfun->disc) && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF))
2796 goto done;
2797 if(nv_isref(np))
2798 {
2799 char *sub;
2800 if(!np->nvalue.cp)
2801 return(0);
2802 shp->last_table = nv_reftable(np);
2803 sub=nv_refsub(np);
2804 np = nv_refnode(np);
2805 if(sub)
2806 {
2807 sfprintf(shp->strbuf,"%s[%s]",nv_name(np),sub);
2808 return(sfstruse(shp->strbuf));
2809 }
2810 return(nv_name(np));
2811 }
2812 if(np->nvfun && np->nvfun->disc)
2813 {
2814 if(!nv_local)
2815 {
2816 nv_local=1;
2817 return(nv_getv(np, np->nvfun));
2818 }
2819 nv_local=0;
2820 }
2821 numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
2822 if(numeric)
2823 {
2824 Sflong_t ll;
2825 if(!up->cp)
2826 return("0");
2827 if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
2828 {
2829 Sfdouble_t ld;
2830 double d;
2831 char *format;
2832 if(nv_isattr(np,NV_LONG))
2833 {
2834 ld = *up->ldp;
2835 if(nv_isattr (np,NV_EXPNOTE))
2836 format = "%.*Lg";
2837 else if(nv_isattr (np,NV_HEXFLOAT))
2838 format = "%.*La";
2839 else
2840 format = "%.*Lf";
2841 sfprintf(shp->strbuf,format,nv_size(np),ld);
2842 }
2843 else
2844 {
2845 d = *up->dp;
2846 if(nv_isattr (np,NV_EXPNOTE))
2847 format = "%.*g";
2848 else if(nv_isattr (np,NV_HEXFLOAT))
2849 format = "%.*a";
2850 else
2851 format = "%.*f";
2852 sfprintf(shp->strbuf,format,nv_size(np),d);
2853 }
2854 return(sfstruse(shp->strbuf));
2855 }
2856 else if(nv_isattr(np,NV_UNSIGN))
2857 {
2858 if(nv_isattr (np,NV_LONG))
2859 ll = *(Sfulong_t*)up->llp;
2860 else if(nv_isattr (np,NV_SHORT))
2861 {
2862 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2863 ll = *(uint16_t*)(up->sp);
2864 else
2865 ll = (uint16_t)up->s;
2866 }
2867 else
2868 ll = *(uint32_t*)(up->lp);
2869 }
2870 else if(nv_isattr (np,NV_LONG))
2871 ll = *up->llp;
2872 else if(nv_isattr (np,NV_SHORT))
2873 {
2874 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2875 ll = *up->sp;
2876 else
2877 ll = up->s;
2878 }
2879 else
2880 ll = *(up->lp);
2881 if((numeric=nv_size(np))==10)
2882 {
2883 if(nv_isattr(np,NV_UNSIGN))
2884 {
2885 sfprintf(shp->strbuf,"%I*u",sizeof(ll),ll);
2886 return(sfstruse(shp->strbuf));
2887 }
2888 numeric = 0;
2889 }
2890 return(fmtbase(ll,numeric, numeric&&numeric!=10));
2891 }
2892 done:
2893 #if (_AST_VERSION>=20030127L)
2894 /*
2895 * if NV_RAW flag is on, return pointer to binary data
2896 * otherwise, base64 encode the data and return this string
2897 */
2898 if(up->cp && nv_isattr(np,NV_BINARY) && !nv_isattr(np,NV_RAW))
2899 {
2900 char *cp;
2901 char *ep;
2902 int size= nv_size(np), insize=(4*size)/3+size/45+8;
2903 base64encode(up->cp, size, (void**)0, cp=getbuf(insize), insize, (void**)&ep);
2904 *ep = 0;
2905 return(cp);
2906 }
2907 #endif
2908 if(!nv_isattr(np,NV_LJUST|NV_RJUST) && (numeric=nv_size(np)) && up->cp && up->cp[numeric])
2909 {
2910 char *cp = getbuf(numeric+1);
2911 memcpy(cp,up->cp,numeric);
2912 cp[numeric]=0;
2913 return(cp);
2914 }
2915 return ((char*)up->cp);
2916 }
2917
nv_getnum(register Namval_t * np)2918 Sfdouble_t nv_getnum(register Namval_t *np)
2919 {
2920 Shell_t *shp = sh_getinterp();
2921 register union Value *up;
2922 register Sfdouble_t r=0;
2923 register char *str;
2924 #if SHOPT_OPTIMIZE
2925 if(!nv_local && shp->argaddr)
2926 nv_optimize(np);
2927 #endif /* SHOPT_OPTIMIZE */
2928 if(nv_istable(np))
2929 errormsg(SH_DICT,ERROR_exit(1),e_number,nv_name(np));
2930 if(np->nvfun && np->nvfun->disc)
2931 {
2932 if(!nv_local)
2933 {
2934 nv_local=1;
2935 return(nv_getn(np, np->nvfun));
2936 }
2937 nv_local=0;
2938 }
2939 if(nv_isref(np))
2940 {
2941 str = nv_refsub(np);
2942 np = nv_refnode(np);
2943 if(str)
2944 nv_putsub(np,str,0L);
2945 }
2946 if(nv_isattr (np, NV_INTEGER))
2947 {
2948 up= &np->nvalue;
2949 if(!up->lp || up->cp==Empty)
2950 r = 0;
2951 else if(nv_isattr(np, NV_DOUBLE)==NV_DOUBLE)
2952 {
2953 if(nv_isattr(np, NV_LONG))
2954 r = *up->ldp;
2955 else
2956 r = *up->dp;
2957 }
2958 else if(nv_isattr(np, NV_UNSIGN))
2959 {
2960 if(nv_isattr(np, NV_LONG))
2961 r = (Sflong_t)*((Sfulong_t*)up->llp);
2962 else if(nv_isattr(np, NV_SHORT))
2963 {
2964 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2965 r = (Sflong_t)(*(uint16_t*)up->sp);
2966 else
2967 r = (Sflong_t)((uint16_t)up->s);
2968 }
2969 else
2970 r = *((uint32_t*)up->lp);
2971 }
2972 else
2973 {
2974 if(nv_isattr(np, NV_LONG))
2975 r = *up->llp;
2976 else if(nv_isattr(np, NV_SHORT))
2977 {
2978 if(nv_isattr(np,NV_INT16P)==NV_INT16P)
2979 r = *up->sp;
2980 else
2981 r = up->s;
2982 }
2983 else
2984 r = *up->lp;
2985 }
2986 }
2987 else if((str=nv_getval(np)) && *str!=0)
2988 {
2989 if(nv_isattr(np,NV_LJUST|NV_RJUST) || (*str=='0' && !(str[1]=='x'||str[1]=='X')))
2990 {
2991 while(*str=='0')
2992 str++;
2993 }
2994 r = sh_arith(shp,str);
2995 }
2996 return(r);
2997 }
2998
2999 /*
3000 * Give <np> the attributes <newatts,> and change its current
3001 * value to conform to <newatts>. The <size> of left and right
3002 * justified fields may be given.
3003 */
nv_newattr(register Namval_t * np,unsigned newatts,int size)3004 void nv_newattr (register Namval_t *np, unsigned newatts, int size)
3005 {
3006 Shell_t *shp = sh_getinterp();
3007 register char *sp;
3008 register char *cp = 0;
3009 register unsigned int n;
3010 Namval_t *mp = 0;
3011 Namarr_t *ap = 0;
3012 int oldsize,oldatts,trans;
3013 Namfun_t *fp= (newatts&NV_NODISC)?np->nvfun:0;
3014 char *prefix = shp->prefix;
3015 newatts &= ~NV_NODISC;
3016
3017 /* check for restrictions */
3018 if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) || sp==nv_name(FPATHNOD)))
3019 errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
3020 /* handle attributes that do not change data separately */
3021 n = np->nvflag;
3022 trans = !(n&NV_INTEGER) && (n&(NV_LTOU|NV_UTOL));
3023 if(newatts&NV_EXPORT)
3024 nv_offattr(np,NV_IMPORT);
3025 if(((n^newatts)&NV_EXPORT))
3026 {
3027 /* record changes to the environment */
3028 if(n&NV_EXPORT)
3029 {
3030 nv_offattr(np,NV_EXPORT);
3031 env_delete(shp->env,nv_name(np));
3032 }
3033 else
3034 {
3035 nv_onattr(np,NV_EXPORT);
3036 sh_envput(shp->env,np);
3037 }
3038 if((n^newatts)==NV_EXPORT)
3039 return;
3040 }
3041 oldsize = nv_size(np);
3042 if((size==oldsize|| (n&NV_INTEGER)) && !trans && ((n^newatts)&~NV_NOCHANGE)==0)
3043 {
3044 if(size)
3045 nv_setsize(np,size);
3046 nv_offattr(np, ~NV_NOFREE);
3047 nv_onattr(np, newatts);
3048 return;
3049 }
3050 /* for an array, change all the elements */
3051 if((ap=nv_arrayptr(np)) && ap->nelem>0)
3052 nv_putsub(np,NIL(char*),ARRAY_SCAN);
3053 oldsize = nv_size(np);
3054 oldatts = np->nvflag;
3055 if(fp)
3056 np->nvfun = 0;
3057 if(ap) /* add element to prevent array deletion */
3058 {
3059 ap->nelem++;
3060 #if SHOPT_FIXEDARRAY
3061 if(ap->fixed)
3062 {
3063 nv_setsize(np,size);
3064 np->nvflag &= NV_ARRAY;
3065 np->nvflag |= newatts;
3066 goto skip;
3067 }
3068 #endif /* SHOPT_TYPEDEF */
3069 }
3070 do
3071 {
3072 nv_setsize(np,oldsize);
3073 np->nvflag = oldatts;
3074 if (sp = nv_getval(np))
3075 {
3076 if(nv_isattr(np,NV_ZFILL))
3077 while(*sp=='0') sp++;
3078 cp = (char*)malloc((n=strlen (sp)) + 8);
3079 strcpy(cp, sp);
3080 if(sp && (mp=nv_opensub(np)))
3081 {
3082 if(trans)
3083 {
3084 nv_disc(np, &ap->hdr,NV_POP);
3085 nv_clone(np,mp,0);
3086 nv_disc(np, &ap->hdr,NV_FIRST);
3087 nv_offattr(mp,NV_ARRAY);
3088 }
3089 nv_newattr(mp,newatts&~NV_ARRAY,size);
3090 }
3091 if(!mp)
3092 {
3093 if(ap)
3094 ap->nelem &= ~ARRAY_SCAN;
3095 if(!trans)
3096 _nv_unset(np,NV_RDONLY|NV_EXPORT);
3097 if(ap)
3098 ap->nelem |= ARRAY_SCAN;
3099 }
3100 if(size==0 && (newatts&NV_HOST)!=NV_HOST && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
3101 size = n;
3102 }
3103 else if(!trans)
3104 _nv_unset(np,NV_EXPORT);
3105 nv_setsize(np,size);
3106 np->nvflag &= (NV_ARRAY|NV_NOFREE);
3107 np->nvflag |= newatts;
3108 if (cp)
3109 {
3110 if(!mp)
3111 nv_putval (np, cp, NV_RDONLY);
3112 free(cp);
3113 }
3114 }
3115 while(ap && nv_nextsub(np));
3116 #if SHOPT_FIXEDARRAY
3117 skip:
3118 #endif /* SHOPT_TYPEDEF */
3119 if(fp)
3120 np->nvfun = fp;
3121 if(ap)
3122 ap->nelem--;
3123 shp->prefix = prefix;
3124 return;
3125 }
3126
oldgetenv(const char * string)3127 static char *oldgetenv(const char *string)
3128 {
3129 register char c0,c1;
3130 register const char *cp, *sp;
3131 register char **av = environ;
3132 if(!string || (c0= *string)==0)
3133 return(0);
3134 if((c1=*++string)==0)
3135 c1= '=';
3136 while(cp = *av++)
3137 {
3138 if(cp[0]!=c0 || cp[1]!=c1)
3139 continue;
3140 sp = string;
3141 while(*sp && *sp++ == *++cp);
3142 if(*sp==0 && *++cp=='=')
3143 return((char*)(cp+1));
3144 }
3145 return(0);
3146 }
3147
3148 /*
3149 * This version of getenv uses the hash storage to access environment values
3150 */
sh_getenv(const char * name)3151 char *sh_getenv(const char *name)
3152 {
3153 Shell_t *shp = sh_getinterp();
3154 register Namval_t *np;
3155 if(!shp->var_tree)
3156 {
3157 #if 0
3158 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] == '_')
3159 #endif
3160 return(oldgetenv(name));
3161 }
3162 else if((np = nv_search(name,shp->var_tree,0)) && nv_isattr(np,NV_EXPORT))
3163 return(nv_getval(np));
3164 return(0);
3165 }
3166
3167 #ifndef _NEXT_SOURCE
3168 /*
3169 * Some dynamic linkers will make this file see the libc getenv(),
3170 * so sh_getenv() is used for the astintercept() callback. Plain
3171 * getenv() is provided for static links.
3172 */
getenv(const char * name)3173 char *getenv(const char *name)
3174 {
3175 return sh_getenv(name);
3176 }
3177 #endif /* _NEXT_SOURCE */
3178
3179 #undef putenv
3180 /*
3181 * This version of putenv uses the hash storage to assign environment values
3182 */
putenv(const char * name)3183 int putenv(const char *name)
3184 {
3185 Shell_t *shp = sh_getinterp();
3186 register Namval_t *np;
3187 if(name)
3188 {
3189 np = nv_open(name,shp->var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
3190 if(!strchr(name,'='))
3191 _nv_unset(np,0);
3192 }
3193 return(0);
3194 }
3195
3196 /*
3197 * Override libast setenviron().
3198 */
sh_setenviron(const char * name)3199 char* sh_setenviron(const char *name)
3200 {
3201 Shell_t *shp = sh_getinterp();
3202 register Namval_t *np;
3203 if(name)
3204 {
3205 np = nv_open(name,shp->var_tree,NV_EXPORT|NV_IDENT|NV_NOARRAY|NV_ASSIGN);
3206 if(strchr(name,'='))
3207 return(nv_getval(np));
3208 _nv_unset(np,0);
3209 }
3210 return("");
3211 }
3212
3213 /*
3214 * Same linker dance as with getenv() above.
3215 */
setenviron(const char * name)3216 char* setenviron(const char *name)
3217 {
3218 return sh_setenviron(name);
3219 }
3220
3221 /*
3222 * normalize <cp> and return pointer to subscript if any
3223 * if <eq> is specified, return pointer to first = not in a subscript
3224 */
lastdot(char * cp,int eq)3225 static char *lastdot(char *cp, int eq)
3226 {
3227 register char *ep=0;
3228 register int c;
3229 if(eq)
3230 cp++;
3231 while(c= mbchar(cp))
3232 {
3233 if(c=='[')
3234 {
3235 if(*cp==']')
3236 cp++;
3237 else
3238 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
3239 }
3240 else if(c=='.')
3241 {
3242 if(*cp=='[')
3243 {
3244 cp = nv_endsubscript((Namval_t*)0,ep=cp,0);
3245 if((ep=sh_checkid(ep+1,cp)) < cp)
3246 cp=strcpy(ep,cp);
3247 }
3248 ep = 0;
3249 }
3250 else if(eq && c == '=')
3251 return(cp-1);
3252 }
3253 return(eq?0:ep);
3254 }
3255
nv_rename(register Namval_t * np,int flags)3256 int nv_rename(register Namval_t *np, int flags)
3257 {
3258 Shell_t *shp = sh_getinterp();
3259 register Namval_t *mp=0,*nr=0;
3260 register char *cp;
3261 int arraynp=0,arraynr,index= -1;
3262 Namval_t *last_table = shp->last_table;
3263 Dt_t *last_root = shp->last_root;
3264 Dt_t *hp = 0;
3265 char *nvenv=0,*prefix=shp->prefix;
3266 Namarr_t *ap;
3267 if(nv_isattr(np,NV_PARAM) && shp->st.prevst)
3268 {
3269 if(!(hp=(Dt_t*)shp->st.prevst->save_tree))
3270 hp = dtvnext(shp->var_tree);
3271 }
3272 if(!nv_isattr(np,NV_MINIMAL))
3273 nvenv = np->nvenv;
3274 if(nvenv || (cp = nv_name(np)) && nv_isarray(np) && cp[strlen(cp)-1] == ']')
3275 arraynp = 1;
3276 if(!(cp=nv_getval(np)))
3277 {
3278 if(flags&NV_MOVE)
3279 errormsg(SH_DICT,ERROR_exit(1),e_varname,"");
3280 return(0);
3281 }
3282 if(lastdot(cp,0) && nv_isattr(np,NV_MINIMAL))
3283 errormsg(SH_DICT,ERROR_exit(1),e_varname,nv_name(np));
3284 arraynr = cp[strlen(cp)-1] == ']';
3285 if(nv_isarray(np) && !(mp=nv_opensub(np)))
3286 index=nv_aindex(np);
3287 shp->prefix = 0;
3288 if(!hp)
3289 hp = shp->var_tree;
3290 if(!(nr = nv_open(cp, hp, flags|NV_ARRAY|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
3291 {
3292 #if SHOPT_NAMESPACE
3293 if(shp->namespace)
3294 hp = nv_dict(shp->namespace);
3295 else
3296 #endif /* SHOPT_NAMESPACE */
3297 hp = shp->var_base;
3298 }
3299 else if(shp->last_root)
3300 hp = shp->last_root;
3301 if(!nr)
3302 nr= nv_open(cp, hp, flags|NV_NOREF|((flags&NV_MOVE)?0:NV_NOFAIL));
3303 shp->prefix = prefix;
3304 if(!nr)
3305 {
3306 if(!nv_isvtree(np))
3307 _nv_unset(np,0);
3308 return(0);
3309 }
3310 if(!mp && index>=0 && nv_isvtree(nr))
3311 {
3312 sfprintf(shp->strbuf,"%s[%d]%c",nv_name(np),index,0);
3313 /* create a virtual node */
3314 if(mp = nv_open(sfstruse(shp->strbuf),shp->var_tree,NV_VARNAME|NV_ADD|NV_ARRAY))
3315 {
3316 if(ap = nv_arrayptr(np))
3317 ap->nelem++;
3318 mp->nvenv = nvenv = (void*)np;
3319 }
3320 }
3321 if(mp)
3322 {
3323 nvenv = (char*)np;
3324 np = mp;
3325 }
3326 if(nr==np)
3327 {
3328 if(index<0)
3329 return(0);
3330 if(cp = nv_getval(np))
3331 cp = strdup(cp);
3332 }
3333 _nv_unset(np,NV_EXPORT);
3334 if(nr==np)
3335 {
3336 nv_putsub(np,(char*)0, index);
3337 nv_putval(np,cp,0);
3338 free((void*)cp);
3339 return(1);
3340 }
3341 shp->prev_table = shp->last_table;
3342 shp->prev_root = shp->last_root;
3343 shp->last_table = last_table;
3344 shp->last_root = last_root;
3345 if(flags&NV_MOVE)
3346 {
3347 if(arraynp && !nv_isattr(np,NV_MINIMAL) && (mp=(Namval_t*)np->nvenv) && (ap=nv_arrayptr(mp)))
3348 ap->nelem++;
3349 }
3350 if((nv_arrayptr(nr) && !arraynr) || nv_isvtree(nr))
3351 {
3352 if(ap=nv_arrayptr(np))
3353 {
3354 if(!ap->table)
3355 ap->table = dtopen(&_Nvdisc,Dtoset);
3356 if(ap->table)
3357 mp = nv_search(nv_getsub(np),ap->table,NV_ADD);
3358 nv_arraychild(np,mp,0);
3359 nvenv = (void*)np;
3360 }
3361 else
3362 mp = np;
3363 nv_clone(nr,mp,(flags&NV_MOVE)|NV_COMVAR);
3364 mp->nvenv = nvenv;
3365 if(flags&NV_MOVE)
3366 {
3367 if(arraynr && !nv_isattr(nr,NV_MINIMAL) && (mp=(Namval_t*)nr->nvenv) && (ap=nv_arrayptr(mp)))
3368 {
3369 nv_putsub(mp,nr->nvname,0);
3370 _nv_unset(mp,0);
3371 }
3372 nv_delete(nr,(Dt_t*)0,NV_NOFREE);
3373 }
3374 }
3375 else
3376 {
3377 nv_putval(np,nv_getval(nr),0);
3378 if(flags&NV_MOVE)
3379 {
3380 if(!nv_isattr(nr,NV_MINIMAL) && (mp=(Namval_t*)(nr->nvenv)) && (ap=nv_arrayptr(mp)))
3381 ap->nelem--;
3382 _nv_unset(nr,0);
3383 }
3384 }
3385 return(1);
3386 }
3387
3388 /*
3389 * Create a reference node from <np> to $np in dictionary <hp>
3390 */
nv_setref(register Namval_t * np,Dt_t * hp,int flags)3391 void nv_setref(register Namval_t *np, Dt_t *hp, int flags)
3392 {
3393 Shell_t *shp = sh_getinterp();
3394 register Namval_t *nq=0, *nr=0;
3395 register char *ep,*cp;
3396 Dt_t *root = shp->last_root, *hpnext=0;
3397 Namarr_t *ap=0;
3398 Dt_t *openmatch;
3399 if(nv_isref(np))
3400 return;
3401 if(nv_isarray(np))
3402 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
3403 if(!(cp=nv_getval(np)))
3404 {
3405 _nv_unset(np,0);
3406 nv_onattr(np,NV_REF);
3407 return;
3408 }
3409 if((ep = lastdot(cp,0)) && nv_isattr(np,NV_MINIMAL))
3410 errormsg(SH_DICT,ERROR_exit(1),e_badref,nv_name(np));
3411 if(hp)
3412 hpnext = dtvnext(hp);
3413 if((nr=nv_open(cp, hp?hp:shp->var_tree, flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
3414 nq = nr;
3415 else if(hpnext && dtvnext(hpnext)==shp->var_base && (nr=nv_open(cp,hpnext,flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
3416 nq = nr;
3417 else if((openmatch=shp->openmatch) && hpnext==shp->var_base && (nr=nv_open(cp,hpnext,flags|NV_NOSCOPE|NV_NOADD|NV_NOFAIL)))
3418 nq = nr;
3419 if(nq)
3420 hp = shp->last_root;
3421 else
3422 hp = hp?(openmatch?openmatch:shp->var_base):shp->var_tree;
3423 if(nr==np)
3424 {
3425 if(shp->namespace && nv_dict(shp->namespace)==hp)
3426 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3427 /* bind to earlier scope, or add to global scope */
3428 if(!(hp=dtvnext(hp)) || (nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET))==np)
3429 errormsg(SH_DICT,ERROR_exit(1),e_selfref,nv_name(np));
3430 if(nv_isarray(nq))
3431 nv_putsub(nq,(char*)0,ARRAY_UNDEF);
3432 }
3433 #if SHOPT_FIXEDARRAY
3434 if(nq && ep && nv_isarray(nq) && !((ap=nv_arrayptr(nq)) && ap->fixed) && !nv_getsub(nq))
3435 #else
3436 if(nq && ep && nv_isarray(nq) && !nv_getsub(nq))
3437 #endif /* SHOPT_FIXEDARRAY */
3438 {
3439 if(!nv_arrayptr(nq))
3440 {
3441 nv_putsub(nq,"1",ARRAY_FILL);
3442 _nv_unset(nq,NV_RDONLY);
3443 }
3444 nv_endsubscript(nq,ep-1,NV_ARRAY);
3445 }
3446 if(!nr)
3447 {
3448 shp->last_root = 0;
3449 nr= nq = nv_open(cp, hp, flags);
3450 if(shp->last_root)
3451 hp = shp->last_root;
3452 }
3453 if(shp->last_root == shp->var_tree && root!=shp->var_tree)
3454 {
3455 _nv_unset(np,NV_RDONLY);
3456 nv_onattr(np,NV_REF);
3457 errormsg(SH_DICT,ERROR_exit(1),e_globalref,nv_name(np));
3458 }
3459 shp->instance = 1;
3460 if(nq && !ep && (ap=nv_arrayptr(nq)) && !(ap->nelem&(ARRAY_UNDEF|ARRAY_SCAN)))
3461 ep = nv_getsub(nq);
3462 #if SHOPT_FIXEDARRAY
3463 if(ep && !(ap && ap->fixed))
3464 #else
3465 if(ep)
3466 #endif /* SHOPT_FIXEDARRAY */
3467 {
3468 /* cause subscript evaluation and return result */
3469 if(nv_isarray(nq))
3470 ep = nv_getsub(nq);
3471 else
3472 {
3473 int n;
3474 ep[n=strlen(ep)-1] = 0;
3475 nv_putsub(nr, ep, ARRAY_FILL);
3476 ep[n] = ']';
3477 if(nq = nv_opensub(nr))
3478 ep = 0;
3479 else
3480 ep = nv_getsub(nq=nr);
3481 }
3482 }
3483 shp->instance = 0;
3484 shp->last_root = root;
3485 _nv_unset(np,0);
3486 nv_delete(np,(Dt_t*)0,0);
3487 np->nvalue.nrp = newof(0,struct Namref,1,sizeof(Dtlink_t));
3488 np->nvalue.nrp->np = nq;
3489 np->nvalue.nrp->root = hp;
3490 if(ep)
3491 {
3492 #if SHOPT_FIXEDARRAY
3493 if(ap && ap->fixed)
3494 np->nvalue.nrp->curi = ARRAY_FIXED|nv_arrfixed(nq,(Sfio_t*)0,1,&np->nvalue.nrp->dim);
3495 else
3496 #endif /* SHOPT_FIXEDARRAY */
3497 np->nvalue.nrp->sub = strdup(ep);
3498 }
3499 np->nvalue.nrp->table = shp->last_table;
3500 nv_onattr(np,NV_REF|NV_NOFREE);
3501 if(!Refdict)
3502 {
3503 NullNode.nvname = ".deleted";
3504 NullNode.nvflag = NV_RDONLY;
3505 Refdict = dtopen(&_Refdisc,Dtobag);
3506 }
3507 dtinsert(Refdict,np->nvalue.nrp);
3508 }
3509
3510 /*
3511 * get the scope corresponding to <index>
3512 * whence uses the same values as lseeek()
3513 */
sh_getscope(int index,int whence)3514 Shscope_t *sh_getscope(int index, int whence)
3515 {
3516 Shell_t *shp = sh_getinterp();
3517 register struct sh_scoped *sp, *topmost;
3518 if(whence==SEEK_CUR)
3519 sp = &shp->st;
3520 else
3521 {
3522 if ((struct sh_scoped*)shp->topscope != shp->st.self)
3523 topmost = (struct sh_scoped*)shp->topscope;
3524 else
3525 topmost = &(shp->st);
3526 sp = topmost;
3527 if(whence==SEEK_SET)
3528 {
3529 int n =0;
3530 while(sp = sp->prevst)
3531 n++;
3532 index = n - index;
3533 sp = topmost;
3534 }
3535 }
3536 if(index < 0)
3537 return((Shscope_t*)0);
3538 while(index-- && (sp = sp->prevst));
3539 return((Shscope_t*)sp);
3540 }
3541
3542 /*
3543 * make <scoped> the top scope and return previous scope
3544 */
sh_setscope(Shscope_t * scope)3545 Shscope_t *sh_setscope(Shscope_t *scope)
3546 {
3547 Shell_t *shp = sh_getinterp();
3548 Shscope_t *old = (Shscope_t*)shp->st.self;
3549 *shp->st.self = shp->st;
3550 shp->st = *((struct sh_scoped*)scope);
3551 shp->var_tree = scope->var_tree;
3552 SH_PATHNAMENOD->nvalue.cp = shp->st.filename;
3553 SH_FUNNAMENOD->nvalue.cp = shp->st.funname;
3554 return(old);
3555 }
3556
sh_unscope(Shell_t * shp)3557 void sh_unscope(Shell_t *shp)
3558 {
3559 register Dt_t *root = shp->var_tree;
3560 register Dt_t *dp = dtview(root,(Dt_t*)0);
3561 if(dp)
3562 {
3563 table_unset(shp,root,NV_RDONLY|NV_NOSCOPE,dp);
3564 if(shp->st.real_fun && dp==shp->st.real_fun->sdict)
3565 {
3566 dp = dtview(dp,(Dt_t*)0);
3567 shp->st.real_fun->sdict->view = dp;
3568 }
3569 shp->var_tree=dp;
3570 dtclose(root);
3571 }
3572 }
3573
3574 /*
3575 * The inverse of creating a reference node
3576 */
nv_unref(register Namval_t * np)3577 void nv_unref(register Namval_t *np)
3578 {
3579 Namval_t *nq;
3580 if(!nv_isref(np))
3581 return;
3582 nv_offattr(np,NV_NOFREE|NV_REF);
3583 if(!np->nvalue.nrp)
3584 return;
3585 nq = nv_refnode(np);
3586 if(Refdict)
3587 {
3588 if(np->nvalue.nrp->sub)
3589 free(np->nvalue.nrp->sub);
3590 dtdelete(Refdict,(void*)np->nvalue.nrp);
3591 }
3592 free((void*)np->nvalue.nrp);
3593 np->nvalue.cp = strdup(nv_name(nq));
3594 #if SHOPT_OPTIMIZE
3595 {
3596 Namfun_t *fp;
3597 for(fp=nq->nvfun; fp; fp = fp->next)
3598 {
3599 if(fp->disc== &optimize_disc)
3600 {
3601 optimize_clear(nq,fp);
3602 return;
3603 }
3604 }
3605 }
3606 #endif
3607 }
3608
3609 /*
3610 * These following are for binary compatibility with the old hash library
3611 * They will be removed someday
3612 */
3613
3614 #if defined(__IMPORT__) && defined(__EXPORT__)
3615 # define extern __EXPORT__
3616 #endif
3617
3618 #undef hashscope
3619
hashscope(Dt_t * root)3620 extern Dt_t *hashscope(Dt_t *root)
3621 {
3622 return(dtvnext(root));
3623 }
3624
3625 #undef hashfree
3626
hashfree(Dt_t * root)3627 extern Dt_t *hashfree(Dt_t *root)
3628 {
3629 Dt_t *dp = dtvnext(root);
3630 dtclose(root);
3631 return(dp);
3632 }
3633
3634 #undef hashname
3635
hashname(void * obj)3636 extern char *hashname(void *obj)
3637 {
3638 Namval_t *np = (Namval_t*)obj;
3639 return(np->nvname);
3640 }
3641
3642 #undef hashlook
3643
hashlook(Dt_t * root,const char * name,int mode,int size)3644 extern void *hashlook(Dt_t *root, const char *name, int mode,int size)
3645 {
3646 NOT_USED(size);
3647 return((void*)nv_search(name,root,mode));
3648 }
3649
nv_name(register Namval_t * np)3650 char *nv_name(register Namval_t *np)
3651 {
3652 Shell_t *shp = sh_getinterp();
3653 register Namval_t *table;
3654 register Namfun_t *fp;
3655 #if SHOPT_FIXEDARRAY
3656 Namarr_t *ap;
3657 #endif /* SHOPT_FIXEDARRAY */
3658 char *cp;
3659 if(is_abuiltin(np) || is_afunction(np))
3660 {
3661 #if SHOPT_NAMESPACE
3662 if(shp->namespace && is_afunction(np))
3663 {
3664 char *name = nv_name(shp->namespace);
3665 int n = strlen(name);
3666 if(memcmp(np->nvname,name,n)==0 && np->nvname[n]=='.')
3667 return(np->nvname+n+1);
3668 }
3669 #endif /* SHOPT_NAMESPACE */
3670 return(np->nvname);
3671 }
3672 #if SHOPT_FIXEDARRAY
3673 ap = nv_arrayptr(np);
3674 #endif /* SHOPT_FIXEDARRAY */
3675 if(!nv_isattr(np,NV_MINIMAL|NV_EXPORT) && np->nvenv)
3676 {
3677 Namval_t *nq= shp->last_table, *mp= (Namval_t*)np->nvenv;
3678 if(np==shp->last_table)
3679 shp->last_table = 0;
3680 if(nv_isarray(mp))
3681 sfprintf(shp->strbuf,"%s[%s]",nv_name(mp),np->nvname);
3682 else
3683 sfprintf(shp->strbuf,"%s.%s",nv_name(mp),np->nvname);
3684 shp->last_table = nq;
3685 return(sfstruse(shp->strbuf));
3686 }
3687 if(nv_istable(np))
3688 #if 1
3689 shp->last_table = nv_parent(np);
3690 #else
3691 shp->last_table = nv_create(np,0, NV_LAST,(Namfun_t*)0);
3692 #endif
3693 else if(!nv_isref(np))
3694 {
3695 for(fp= np->nvfun ; fp; fp=fp->next)
3696 if(fp->disc && fp->disc->namef)
3697 {
3698 if(np==shp->last_table)
3699 shp->last_table = 0;
3700 return((*fp->disc->namef)(np,fp));
3701 }
3702 }
3703 if(!(table=shp->last_table) || *np->nvname=='.' || table==shp->namespace || np==table)
3704 {
3705 #if SHOPT_FIXEDARRAY
3706 if(!ap || !ap->fixed || (ap->nelem&ARRAY_UNDEF))
3707 return(np->nvname);
3708 table = 0;
3709 #else
3710 return(np->nvname);
3711 #endif /* SHOPT_FIXEDARRAY */
3712 }
3713 if(table)
3714 {
3715 cp = nv_name(table);
3716 sfprintf(shp->strbuf,"%s.%s",cp,np->nvname);
3717 }
3718 else
3719 sfprintf(shp->strbuf,"%s",np->nvname);
3720 #if SHOPT_FIXEDARRAY
3721 if(ap && ap->fixed)
3722 nv_arrfixed(np,shp->strbuf,1,(char*)0);
3723 #endif /* SHOPT_FIXEDARRAY */
3724 return(sfstruse(shp->strbuf));
3725 }
3726
nv_lastdict(void)3727 Namval_t *nv_lastdict(void)
3728 {
3729 Shell_t *shp = sh_getinterp();
3730 return(shp->last_table);
3731 }
3732
3733 #undef nv_context
3734 /*
3735 * returns the data context for a builtin
3736 */
nv_context(Namval_t * np)3737 void *nv_context(Namval_t *np)
3738 {
3739 return((void*)np->nvfun);
3740 }
3741
3742 #define DISABLE /* proto workaround */
3743
DISABLE(register Namval_t * np)3744 int nv_isnull DISABLE (register Namval_t *np)
3745 {
3746 return(nv_isnull(np));
3747 }
3748
3749 #undef nv_setsize
nv_setsize(register Namval_t * np,int size)3750 int nv_setsize(register Namval_t *np, int size)
3751 {
3752 int oldsize = nv_size(np);
3753 if(size>=0)
3754 np->nvsize = size;
3755 return(oldsize);
3756 }
3757
nv_shell(Namval_t * np)3758 Shell_t *nv_shell(Namval_t *np)
3759 {
3760 Namfun_t *fp;
3761 for(fp=np->nvfun;fp;fp=fp->next)
3762 {
3763 if(!fp->disc)
3764 return((Shell_t*)fp->last);
3765 }
3766 return(0);
3767 }
3768
3769 #undef nv_unset
3770
nv_unset(register Namval_t * np)3771 void nv_unset(register Namval_t *np)
3772 {
3773 _nv_unset(np,0);
3774 return;
3775 }
3776