2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: name.c /main/4 1996/11/07 16:19:40 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
29 * AT&T BELL LABORATORIES *
30 * AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
31 * ACCORDANCE WITH APPLICABLE AGREEMENTS *
33 * Copyright (c) 1995 AT&T Corp. *
34 * Unpublished & Not for Publication *
35 * All Rights Reserved *
37 * The copyright notice above does not evidence any *
38 * actual or intended publication of such source code *
40 * This software was created by the *
41 * Advanced Software Technology Department *
42 * AT&T Bell Laboratories *
44 * For further information contact *
45 * {research,attmail}!dgk *
47 ***************************************************************/
49 /* : : generated by proto : : */
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__ "C"
59 #define __PROTO__(x) x
61 #define __PARAM__(n,o) n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
74 #define __PROTO__(x) ()
75 #define __OTORP__(x) x
76 #define __PARAM__(n,o) o
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__ ...
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a) va_start(p,a)
92 #define __VA_START__(p,a) va_start(p)
97 #include "variables.h"
99 #include "lexstates.h"
101 #include "FEATURE/locale"
102 #include "national.h"
105 extern __MANGLE__ void ev_$delete_var(__VARARG__);
106 extern __MANGLE__ void ev_$set_var(__VARARG__);
109 static void attstore __PROTO__((Namval_t*));
110 static void pushnam __PROTO__((Namval_t*));
111 static char *staknam __PROTO__((Namval_t*, char*));
112 static void utol __PROTO__((const char*,char*));
113 static void ltou __PROTO__((const char*,char*));
114 static void rightjust __PROTO__((char*, int, int));
116 static char **argnam;
121 static void(*nullscan) __PROTO__((Namval_t*));
123 /* ======== name value pair routines ======== */
126 #include "builtins.h"
129 * necessary to force linking to system putenv. Otherwise putenv is defined
130 * to be "setenv" which is resolved in libast.a
134 extern char *getenv();
137 * Remove an element from the environ array. Code mostly taken from
138 * DtEnvRemove, but this code does pointer comparisons rather than
139 * strcmp calls, and does not free anything.
141 extern char **environ;
142 int remove_env_entry __PARAM__((char *pEntry), (pEntry)) __OTORP__(char *pEntry;)
144 char **pEnviron, **pEnviron2 = (char **)environ;
148 int count = 0; /* count is the number of items in the */
150 int index; /* index will range from 0 to count - 1 */
153 if (!(len = strlen(pEntry)))
156 pEnviron = pEnviron2;
167 pEnviron = pEnviron2;
170 for (index = 0; index < count; index++)
174 for (temp = index; temp != count - 1; temp++)
176 pEnviron2[temp] = pEnviron2[temp + 1];
178 pEnviron2[count - 1] = NULL;
188 * Utility to mirror changes in our environment hash table into the
189 * environment seen by library routines in internally-linked libc
192 void mirror_env __PARAM__((Namval_t *np), (np)) __OTORP__(Namval_t *np;)
194 char *buf, *val = nv_getval(np), *name = nv_name(np);
198 * CDExc22516: Under some circumstances, dtksh's environ
199 * is NULL on Fujitsu. This in itself may be a problem
200 * that should be researched, but for now, we simply
201 * protect against using putenv/getenv if environ is
202 * NULL. rswiston@x.org 11/07/96
204 if((name != (char *)NULL) && (environ != (char **)NULL))
207 * This is funky, but I'm not confident that I fully understand the
208 * use/reuse patterns of the NamVal_t structs. This code ensures
209 * that we only free up environment variables that we are replacing.
211 if((np->nvdtenv != (char *)NULL) &&
212 (getenv(name) == (np->nvdtenv + strlen(name) + 1)))
215 if(val != (char *)NULL)
216 buf = (char *)malloc(strlen(name) + strlen(val) + 2);
218 buf = (char *)malloc(strlen(name) + 2);
221 if(val != (char *)NULL)
226 free((__V_*)np->nvdtenv);
233 * Perform parameter assignment for a linked list of parameters
234 * <flags> contains attributes for the parameters
236 void nv_setlist __PARAM__((register struct argnod *arg,register int flags), (arg, flags)) __OTORP__(register struct argnod *arg;register int flags;){
238 register Namval_t *np;
239 int traceon = (sh_isoption(SH_XTRACE)!=0);
240 if(sh_isoption(SH_ALLEXPORT))
244 flags &= ~(NV_IDENT|NV_EXPORT);
247 for(;arg; arg=arg->argnxt.ap)
250 if(arg->argflag&ARG_MAC)
251 cp = sh_mactrim(arg->argval,-1);
257 int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
258 struct fornod *fp=(struct fornod*)arg->argchn.ap;
259 register union anynode *tp=fp->fortre;
260 char *prefix = sh.prefix;
262 error_info.line = fp->fortyp-sh.st.firstline;
263 if(sh.fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
265 np = nv_open(cp,sh.var_tree,flag);
267 /* check for array assignment */
268 if(tp->tre.tretyp!=TLST && !tp->com.comset)
271 char **argv = sh_argbuild(&argc,&tp->com);
272 nv_setvec(np,argc,argv);
275 sh_trace(NIL(char**),0);
276 sfputr(sfstderr,nv_name(np),'=');
277 sfwrite(sfstderr,"( ",2);
279 sfputr(sfstderr,sh_fmtq(cp),' ');
280 sfwrite(sfstderr,")\n",2);
284 if(tp->tre.tretyp==TLST || tp->com.comset->argval[0]!='[')
287 nv_setarray(np,nv_associative);
296 sh_exec(tp,sh_isstate(SH_ERREXIT));
302 np = nv_open(cp,sh.var_tree,flags);
304 np->nvsize |= NV_PARAM;
306 np->nvsize &= ~NV_PARAM;
309 register char *sp=cp;
310 sh_trace(NIL(char**),0);
311 sfputr(sfstderr,nv_name(np),-1);
312 if(nv_isattr(np,NV_ARRAY) && (cp=strchr(sp,'[')))
314 /* no quoting needed up to the = */
315 sp = nv_endsubscript(np,cp,0);
316 sfwrite(sfstderr,cp,sp -cp);
322 sfprintf(sfstderr,"=%s\n",sh_fmtq(cp+1));
328 * construct a new name from a prefix and base name on the stack
330 static char *newname __PARAM__((register const char *prefix, register const char *name), (prefix, name)) __OTORP__(register const char *prefix; register const char *name;){
331 register int offset = staktell();
338 return(stakptr(offset));
342 * Put <arg> into associative memory.
343 * If <flags> & NV_ARRAY then subscript is not allowed
344 * If <flags> & NV_NOSCOPE then use the current scope only
345 * If <flags> & NV_ASSIGN then assignment is allowed
346 * If <flags> & NV_IDENT then name must be an identifier
347 * If <flags> & NV_VARNAME then name must be a valid variable name
348 * If <flags> & NV_NOADD then node will not be added if not found
349 * SH_INIT is only set while initializing the environment
351 Namval_t *nv_open __PARAM__((const char *name,Hashtab_t *root,int flags), (name, root, flags)) __OTORP__(const char *name;Hashtab_t *root;int flags;){
352 register char *cp = (char*)name;
353 register Namval_t *np=0;
354 register int sep = *cp;
355 register char *lastdot = 0;
356 register long mode = ((flags&NV_NOADD)?0:NV_ADD);
357 if(root==sh.alias_tree)
359 while((sep= *(unsigned char*)cp) && (sep!='=') && (sep!='/') &&
360 (!(sep=sh_lexstates[ST_NORM][sep]) || sep==S_EPAT))
367 if(!(flags&(NV_IDENT|NV_VARNAME|NV_ASSIGN)))
370 mode |= HASH_SCOPE|HASH_NOSCOPE;
371 np = nv_search(name,root,mode);
372 if(np && !(flags&NV_REF))
374 while(nv_isattr(np,NV_REF))
379 if(sh.prefix && (flags&NV_ASSIGN))
380 name = cp = newname(sh.prefix,name);
381 /* first skip over alpha-numeric */
388 if(root==sh.var_tree)
389 flags &= ~(NV_NOSCOPE|NV_EXPORT);
390 if(!lastdot && cp!=name && (flags&NV_VARNAME))
392 /* see whether first component is ref */
394 np = nv_search(name,sh.var_tree,0);
396 if(np && nv_isattr(np,NV_REF))
398 /* substitute ref name */
399 while(nv_isattr(np,NV_REF))
403 name=lastdot=newname(name,cp+1);
404 cp = lastdot + sep +1;
412 if(sep= *(unsigned char*)cp, !isaletter(sep))
414 while(sep= *(unsigned char*)(++cp),isaname(sep));
416 /* if name doesn't have to be an varname or ident skip to '=' */
418 if(sep && sep!='=' && sep!='[' && sep!='+')
420 if(sep && sep!='=' && sep!='[')
421 #endif /* SHOPT_APPEND */
425 else if(flags&NV_VARNAME)
426 error(ERROR_exit(1),(root==sh.var_tree?e_varname:e_funname),name);
427 while((sep= *++cp) && sep!='=');
430 np = nv_search(name,root,0);
431 while(!np && lastdot && lastdot>name)
434 np = nv_search(name,sh.var_tree,0);
440 if(np->nvfun && (np->nvfun)->disc->create)
443 np = nv_create(nq=np,lastdot+1,(Namfun_t*)np);
446 error(ERROR_exit(1),e_varname,name);
448 else if((sp=strchr(lastdot+1,'.')) && sp<cp)
449 error(ERROR_exit(1),e_noparent,name);
454 while(--lastdot>name && *lastdot!='.');
455 if(lastdot==name || (!np && root!=sh.var_tree))
456 error(ERROR_exit(1),e_noparent,name);
463 if((flags&NV_NOSCOPE) && hashscope(root) && root==sh.var_tree
464 && (np=nv_search(name,sh.var_base,0)))
466 Namfun_t *disc = nv_cover(np);
467 if(np=nv_search((char*)np,root,mode|HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET))
473 mode |= HASH_SCOPE|HASH_NOSCOPE;
474 np = nv_search(name,root,mode);
478 if((flags&NV_REF) || (!np && (flags&NV_NOADD)))
480 while(nv_isattr(np,NV_REF))
482 /* check for subscript*/
483 if(sep=='[' && !(flags&NV_ARRAY))
485 sep = (flags&NV_ASSIGN?NV_ADD:0);
486 cp = nv_endsubscript(np,cp,NV_ADD);
489 else if(nv_isattr(np,NV_ARRAY))
490 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
494 #endif /* SHOPT_APPEND */
495 if(sep && ((sep!='=')||!(flags&NV_ASSIGN)))
497 if(sh_isstate(SH_INIT))
501 if(root==sh.alias_tree)
503 if(nv_isattr(np,NV_TAGGED|NV_NOALIAS))
504 nv_offattr(np,(NV_NOALIAS|NV_TAGGED|NV_EXPORT));
509 if(sh_isstate(SH_INIT))
511 nv_putval(np, cp, NV_RDONLY);
513 nv_onattr(np,NV_TAGGED);
517 nv_putval(np, cp, 0);
520 nv_offattr(np,NV_IMPORT);
521 #endif /* SHOPT_BSH */
523 nv_onattr(np, flags&NV_ATTRIBUTES);
526 * Set environment variable defined in the underlying
527 * DOMAIN_OS cache. This is done because dsee will only
528 * process the path if it has changed since the last
531 if(nv_isattr(np,NV_EXPORT) && !nv_isattr(np,NV_IMPORT)
532 && (flags&NV_ASSIGN) && !(flags&(NV_NOSCOPE|NV_ARRAY)))
535 namlen =strlen(nv_name(np));
537 ev_$set_var(nv_name(np),&namlen,cp,&vallen);
541 * Set environment variable defined in the underlying
542 * libc environ. This is done because routines within
543 * a shared libc will only look in the libc environ,
544 * not in our hash trees to find environment variables.
546 if(nv_isattr(np,NV_EXPORT))
552 if(!sh_isstate(SH_INIT))
553 error(ERROR_exit(1),(root==sh.alias_tree?e_aliname:e_ident),name);
557 #ifdef SHOPT_MULTIBYTE
559 static char savechars[ESS_MAXCHAR+1];
560 static int ja_size __PROTO__((char*, int, int));
561 static void ja_restore __PROTO__((void));
562 #endif /* SHOPT_MULTIBYTE */
565 * put value <string> into name-value node <np>.
566 * If <np> is an array, then the element given by the
567 * current index is assigned to.
568 * If <flags> contains NV_RDONLY, readonly attribute is ignored
569 * If <flags> contains NV_INTEGER, string is a pointer to a number
570 * If <flags> contains NV_NOFREE, previous value is freed, and <string>
571 * becomes value of node and <flags> becomes attributes
573 void nv_putval __PARAM__((register Namval_t *np, const char *string, int flags), (np, string, flags)) __OTORP__(register Namval_t *np; const char *string; int flags;){
574 register const char *sp=string;
575 register union Value *up;
577 register int size = 0;
579 if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
580 error(ERROR_exit(1),e_readonly, nv_name(np));
581 /* The following could cause the shell to fork if assignment
582 * would cause a side effect
585 np = sh_assignok(np,1);
586 if(nv_isattr(np, NV_ARRAY))
587 array_check(np,ARRAY_ASSIGN);
590 /* This function contains disc */
594 nv_putv(np,sp,flags,np->nvfun);
597 /* called from disc, assign the actual value */
600 if(flags&(NV_REF|NV_NOFREE))
603 np->nvalue.cp = (char*)sp;
604 nv_setattr(np,flags|NV_NOFREE);
607 if(nv_isattr(np, NV_ARRAY))
608 up = array_find(np,ARRAY_ASSIGN);
612 nv_offattr(np,NV_IMPORT);
614 #endif /* SHOPT_BSH */
615 if(nv_isattr (np, NV_INTEGER))
617 if(nv_isattr (np, NV_CPOINTER))
619 else if(nv_isattr(np, NV_DOUBLE))
627 up->dp = new_of(double,0);
636 l = (long)sh_arith(sp);
640 nv_setsize(np,sh.lastbase);
641 if(nv_isattr (np, NV_SHORT))
646 up->lp = new_of(long,0);
648 if(l && *sp++ == '0')
649 nv_onattr(np,NV_UNSIGN);
655 const char *tofree=0;
657 sp = sh_etos(*((double*)sp),12);
659 if(nv_isattr(np, NV_HOST)==NV_HOST && sp)
662 * return the host file name given the UNIX name
663 * non-unix hosts that use file name mapping
668 unix_fio_$get_name(sp,pathname,&pathlen);
669 pathname[pathlen] = 0;
673 if((nv_isattr(np, NV_RJUST|NV_ZFILL|NV_LJUST)) && sp)
675 for(;*sp == ' '|| *sp=='\t';sp++);
676 if((nv_isattr(np,NV_ZFILL)) && (nv_isattr(np,NV_LJUST)))
679 #ifdef SHOPT_MULTIBYTE
681 size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL));
682 #endif /* SHOPT_MULTIBYTE */
684 if(!nv_isattr(np, NV_NOFREE|NV_NOALLOC))
686 /* delay free in case <sp> points into free region */
689 if(nv_isattr(np, NV_NOALLOC))
693 nv_offattr(np,NV_NOFREE);
697 if(size==0 && nv_isattr(np,NV_LJUST|NV_RJUST|NV_ZFILL))
698 nv_setsize(np,size=dot);
701 cp = (char*)malloc(((unsigned)dot+1));
709 if(nv_isattr(np, NV_LTOU))
711 else if(nv_isattr (np, NV_UTOL))
715 if(nv_isattr(np, NV_RJUST) && nv_isattr(np, NV_ZFILL))
716 rightjust(cp,size,'0');
717 else if(nv_isattr(np, NV_RJUST))
718 rightjust(cp,size,' ');
719 else if(nv_isattr(np, NV_LJUST))
722 dp = strlen (cp) + cp;
723 *(cp = (cp + size)) = 0;
724 for (; dp < cp; *dp++ = ' ');
726 #ifdef SHOPT_MULTIBYTE
727 /* restore original string */
730 #endif /* SHOPT_MULTIBYTE */
736 if((flags&NV_RDONLY) && nv_isattr(np,NV_EXPORT))
738 short namlen, vallen;
739 char *vp = nv_getval(np);
740 namlen =strlen(nv_name(np));
742 ev_$set_var(nv_name(np),&namlen,vp,&vallen);
746 * Set environment variable defined in the underlying
747 * libc environ. This is done because routines within
748 * a shared libc will only look in the libc environ,
749 * not in our hash trees to find environment variables.
751 if((flags&NV_RDONLY) && nv_isattr(np,NV_EXPORT))
758 * Right-justify <str> so that it contains no more than
759 * <size> characters. If <str> contains fewer than <size>
760 * characters, left-pad with <fill>. Trailing blanks
761 * in <str> will be ignored.
763 * If the leftmost digit in <str> is not a digit, <fill>
764 * will default to a blank.
766 static void rightjust __PARAM__((char *str, int size, int fill), (str, size, fill)) __OTORP__(char *str; int size; int fill;){
768 register char *cp,*sp;
771 /* ignore trailing blanks */
772 for(cp=str+n;n && *--cp == ' ';n--);
778 for (sp = str, cp = str+n-size; sp <= str+size; *sp++ = *cp++);
781 else *(sp = str+size) = 0;
800 #ifdef SHOPT_MULTIBYTE
802 * handle left and right justified fields for multi-byte chars
803 * given physical size, return a logical size which reflects the
804 * screen width of multi-byte characters
805 * Multi-width characters replaced by spaces if they cross the boundary
806 * <type> is non-zero for right justified fields
809 static int ja_size __PARAM__((char *str,int size,int type), (str, size, type)) __OTORP__(char *str;int size;int type;){
810 register char *cp = str;
811 register int c, n=size;
817 if((c=mbtowc(&w,cp,MB_CUR_MAX))>0)
819 register int outsize = wcwidth(w);
820 /* allow room for excess input bytes */
829 if(size<=0 && type==0)
833 /* check for right justified fields that need truncating */
838 /* left justified and character crosses field boundary */
840 /* save boundary char and replace with spaces */
845 savechars[size] = cp[size];
852 n -= (ja_size(str,size,0)-size);
857 static void ja_restore __PARAM__((void), ()){
858 register char *cp = savechars;
863 #endif /* SHOPT_MULTIBYTE */
865 static char *staknam __PARAM__((register Namval_t *np, char *value), (np, value)) __OTORP__(register Namval_t *np; char *value;){
867 q = stakalloc(strlen(nv_name(np))+(value?strlen(value):0)+2);
868 p=strcopy(q,nv_name(np));
878 * put the name and attribute into value of attributes variable
880 static void attstore __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
881 register int flag = np->nvflag;
882 if(!(flag&NV_EXPORT) || (flag&NV_FUNCT))
884 flag &= (NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER);
886 *attval++ = ' '+flag;
888 *attval = ' ' + nv_size(np);
891 attval = strcopy(++attval,nv_name(np));
894 static void pushnam __PARAM__((Namval_t *np), (np)) __OTORP__(Namval_t *np;){
895 register char *value;
896 if(nv_isattr(np,NV_IMPORT))
899 *argnam++ = np->nvenv;
901 else if(value=nv_getval(np))
902 *argnam++ = staknam(np,value);
903 if(nv_isattr(np,NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER))
904 attsize += (strlen(nv_name(np))+4);
908 * Generate the environment list for the child.
911 char **sh_envgen __PARAM__((void), ()){
915 /* L_ARGNOD gets generated automatically as full path name of command */
916 nv_offattr(L_ARGNOD,NV_EXPORT);
918 namec = nv_scan(sh.var_tree,nullscan,NV_EXPORT,NV_EXPORT);
919 er = (char**)stakalloc((namec+3)*sizeof(char*));
921 nv_scan(sh.var_tree, pushnam, NV_EXPORT, NV_EXPORT);
922 *argnam = (char*)stakalloc(attsize);
923 cp = attval = strcopy(*argnam,e_envmarker);
924 nv_scan(sh.var_tree, attstore,0,(NV_RDONLY|NV_UTOL|NV_LTOU|NV_RJUST|NV_LJUST|NV_ZFILL|NV_INTEGER));
932 static void (*scanfn) __PROTO__((Namval_t*));
934 static int scanflags;
935 static int scancount = 0;
937 static int scanfilter __PARAM__((const char *name, char *arg, __V_ *notused), (name, arg, notused)) __OTORP__(const char *name; char *arg; __V_ *notused;){
938 register Namval_t *np = (Namval_t*)arg;
939 register int k=np->nvflag;
942 if(scanmask?(k&scanmask)==scanflags:(!scanflags || (k&scanflags)))
944 if(!np->nvalue.cp && !nv_isattr(np,~NV_DEFAULT))
948 if(nv_isattr(np,NV_ARRAY))
949 nv_putsub(np,NIL(char*),0L);
958 * Walk through the name-value pairs
959 * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags
961 * If <mask> is zero, and <flags> non-zero, then nodes with one or
962 * more of <flags> is visited
963 * If <mask> and <flags> are zero, then all nodes are visted
965 int nv_scan __PARAM__((Hashtab_t *root, void (*fn)(Namval_t*), int mask, int flags), (root, fn, mask, flags)) __OTORP__(Hashtab_t *root; void (*fn)(); int mask; int flags;){
966 int (*hashfn) __PROTO__((const char*, char*, __V_*));
972 hashwalk(root, 0, hashfn,NIL(char*));
977 * create a new environment scope
979 void nv_scope __PARAM__((struct argnod *envlist), (envlist)) __OTORP__(struct argnod *envlist;){
980 register Hashtab_t *newscope;
981 newscope = hashalloc(sh.var_tree,HASH_set,HASH_SCOPE|HASH_ALLOCATE,0);
982 sh.var_tree = newscope;
983 nv_setlist(envlist,NV_EXPORT|NV_NOSCOPE|NV_IDENT|NV_ASSIGN);
987 * Remove freeable local space associated with the nvalue field
988 * of nnod. This includes any strings representing the value(s) of the
989 * node, as well as its dope vector, if it is an array.
992 void sh_envnolocal __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
993 if(nv_isattr(np,NV_EXPORT|NV_NOFREE))
995 if(nv_isattr(np,NV_REF))
997 nv_offattr(np,NV_NOFREE|NV_REF);
1002 if(nv_isattr(np, NV_ARRAY))
1003 nv_putsub(np,NIL(char*),ARRAY_SCAN);
1011 * Currently this is a dummy, but someday will be needed
1012 * for reference counting
1014 void nv_close __PARAM__((Namval_t *np), (np)) __OTORP__(Namval_t *np;){
1020 * Set the value of <np> to 0, and nullify any attributes
1021 * that <np> may have had. Free any freeable space occupied
1022 * by the value of <np>. If <np> denotes an array member, it
1023 * will retain its attributes.
1025 void nv_unset __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1026 register union Value *up = &np->nvalue;
1027 register Namarr_t *ap;
1028 if(!forced && nv_isattr (np,NV_RDONLY))
1029 error(ERROR_exit(1),e_readonly, nv_name(np));
1030 if(sh.subshell && !nv_isnull(np))
1031 np = sh_assignok(np,0);
1032 if(ap = nv_arrayptr(np))
1033 array_check(np,ARRAY_DELETE);
1036 /* This function contains disc */
1040 nv_putv(np,NIL(char*),forced?NV_RDONLY:0,np->nvfun);
1043 /* called from disc, assign the actual value */
1051 if(!(up=array_find(np,ARRAY_DELETE)))
1054 if((!nv_isattr (np, NV_NOFREE)) && up->cp)
1055 free((__V_*)up->cp);
1058 while(ap?nv_nextsub(np):0);
1059 if(!nv_isattr(np,NV_ARRAY))
1065 /* dtksh-specific code to sync hash table & environ */
1066 if(np->nvdtenv != (char *)NULL)
1068 remove_env_entry(np->nvdtenv);
1069 free((__V_*)np->nvdtenv);
1070 np->nvdtenv = (char *)NULL;
1075 * return the node pointer in the highest level scope
1077 Namval_t *nv_scoped __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1078 if(hashscope(sh.var_tree))
1079 return(nv_search((char*)np,sh.var_tree,HASH_BUCKET));
1085 * Return a pointer to a character string that denotes the value
1086 * of <np>. If <np> refers to an array, return a pointer to
1087 * the value associated with the current index.
1089 * If the value of <np> is an integer, the string returned will
1090 * be overwritten by the next call to nv_getval.
1092 * If <np> has no value, 0 is returned.
1095 char *nv_getval __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1096 register union Value *up= &np->nvalue;
1097 register int numeric;
1098 register Namarr_t *ap;
1099 if(!np->nvfun && !nv_isattr(np,NV_ARRAY|NV_INTEGER|NV_FUNCT|NV_REF))
1101 if(ap = nv_arrayptr(np))
1102 array_check(np,ARRAY_LOOKUP);
1108 return(nv_getv(np, np->nvfun));
1112 numeric = ((nv_isattr (np, NV_INTEGER)) != 0);
1115 if(!(up = array_find(np,ARRAY_LOOKUP)))
1116 return (NIL(char*));
1121 if(!up->cp || nv_isattr (np,NV_CPOINTER))
1122 return((char*)up->cp);
1123 else if(nv_isattr (np,NV_DOUBLE))
1126 if(nv_isattr (np,NV_EXPNOTE))
1127 return(sh_etos(d,nv_size(np)));
1129 return(sh_ftos(d,nv_size(np)));
1131 else if(nv_isattr (np,NV_SHORT))
1135 if((numeric=nv_size(np))==10 && !nv_isattr(np,NV_UNSIGN))
1137 return(fmtbase(l,numeric, numeric&&numeric!=10));
1139 if(nv_isattr(np,NV_REF))
1140 return(nv_name(up->np));
1143 /* This is not nearly complete */
1144 if(!up->cp && (np=nv_class(np)))
1145 return(nv_getval(np));
1146 #endif /* SHOPT_OO */
1147 return ((char*)up->cp);
1150 double nv_getnum __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1151 register union Value *up;
1152 register double r=0;
1159 return(nv_getn(np, np->nvfun));
1163 if(nv_isattr (np, NV_INTEGER))
1165 if(nv_isattr(np, NV_ARRAY))
1166 up = array_find(np,ARRAY_ASSIGN);
1171 else if(nv_isattr(np, NV_DOUBLE))
1176 else if((str=nv_getval(np)) && *str!=0)
1181 * Give <np> the attributes <newatts,> and change its current
1182 * value to conform to <newatts>. The <size> of left and right
1183 * justified fields may be given.
1185 void nv_newattr __PARAM__((register Namval_t *np, unsigned newatts, int size), (np, newatts, size)) __OTORP__(register Namval_t *np; unsigned newatts; int size;){
1187 register char *cp = 0;
1188 register unsigned int n;
1190 int oldsize,oldatts;
1192 /* check for restrictions */
1193 if(sh_isoption(SH_RESTRICTED) && ((sp=nv_name(np))==nv_name(PATHNOD) || sp==nv_name(SHELLNOD) || sp==nv_name(ENVNOD) ))
1194 error(ERROR_exit(1),e_restricted,nv_name(np));
1195 /* handle attributes that do not change data separately */
1198 if(newatts&NV_EXPORT)
1199 nv_offattr(np,NV_IMPORT);
1200 #endif /* SHOPT_BSH */
1202 if(((n^newatts)&NV_EXPORT))
1203 /* record changes to the environment */
1205 short namlen = strlen(nv_name(np));
1207 ev_$delete_var(nv_name(np),&namlen);
1210 char *vp = nv_getval(np);
1211 short vallen = strlen(vp);
1212 ev_$set_var(nv_name(np),&namlen,vp,&vallen);
1217 * Set environment variable defined in the underlying
1218 * libc environ. This is done because routines within
1219 * a shared libc will only look in the libc environ,
1220 * not in our hash trees to find environment variables.
1222 if(newatts&NV_EXPORT)
1225 if((size==0||(n&NV_INTEGER)) && ((n^newatts)&~NV_NOCHANGE)==0)
1228 nv_setsize(np,size);
1229 nv_offattr(np, ~NV_NOFREE);
1230 nv_onattr(np, newatts);
1233 /* for an array, change all the elements */
1234 if((ap=nv_arrayptr(np)) && ap->nelem>0)
1235 nv_putsub(np,NIL(char*),ARRAY_SCAN);
1236 oldsize = nv_size(np);
1237 oldatts = np->nvflag;
1240 nv_setsize(np,oldsize);
1241 np->nvflag = oldatts;
1242 if (sp = nv_getval(np))
1244 cp = (char*)malloc((n=strlen (sp)) + 1);
1246 if(ap) /* add element to prevent array deletion */
1248 ap->nelem &= ~ARRAY_SCAN;
1255 ap->nelem |= ARRAY_SCAN;
1257 if(size==0 && (newatts&(NV_LJUST|NV_RJUST|NV_ZFILL)))
1262 nv_setsize(np,size);
1263 np->nvflag &= NV_ARRAY;
1264 np->nvflag |= newatts;
1267 nv_putval (np, cp, NV_RDONLY);
1271 while(ap && nv_nextsub(np));
1275 #ifndef _NEXT_SOURCE
1276 static char *oldgetenv __PARAM__((const char *string), (string)) __OTORP__(const
1278 register char c0,c1;
1279 register const char *cp, *sp;
1280 register char **av = environ;
1281 if(!string || (c0= *string)==0)
1283 if((c1= *++string)==0)
1287 if(cp[0]!=c0 || cp[1]!=c1)
1290 while(*sp && *sp++ == *++cp);
1291 if(*sp==0 && *++cp=='=')
1292 return((char*)(cp+1));
1298 * This version of getenv the hash storage to access environment values
1300 * This had to be renamed to ksh_getenv to allow the dtksh code access to
1301 * the libc getenv. While some platforms support calling _getenv to work
1302 * around the problems, others don't.
1304 char *ksh_getenv __PARAM__((const char *name), (name)) __OTORP__(const char *name;){
1305 register Namval_t *np;
1307 return(oldgetenv(name));
1308 if((np = nv_search(name,sh.var_tree,0)) && nv_isattr(np,NV_EXPORT))
1309 return(nv_getval(np));
1312 #endif /* _NEXT_SOURCE */
1316 * This version of putenv uses the hash storage to assign environment values
1318 * The original ksh93 code had this routine called "putenv". This hid
1319 * the libc version of putenv, which caused problems for dtksh on systems
1320 * with shared libraries, as it caused the existance of two separate and
1321 * non-overlapping environments. To the best of my knowledge there are
1322 * no calls to this routine. - harry phinney 8/15/1994.
1324 int ksh_putenv __PARAM__((const char *name), (name)) __OTORP__(const char *name;){
1325 register Namval_t *np;
1328 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_ARRAY|NV_ASSIGN);
1329 if(!strchr(name,'='))
1337 * Override libast setenv()
1339 char* setenviron __PARAM__((const char *name), (name)) __OTORP__(const char *name;){
1340 register Namval_t *np;
1343 np = nv_open(name,sh.var_tree,NV_EXPORT|NV_IDENT|NV_ARRAY|NV_ASSIGN);
1344 if(strchr(name,'='))
1345 return(nv_getval(np));
1352 * copy <str1> to <str2> changing lower case to upper case
1353 * <str2> must be big enough to hold <str1>
1354 * <str1> and <str2> may point to the same place.
1357 static void ltou __PARAM__((register char const *str1,register char *str2), (str1, str2)) __OTORP__(register char const *str1;register char *str2;){
1359 for(; c= *((unsigned char*)str1); str1++,str2++)
1370 * copy <str1> to <str2> changing upper case to lower case
1371 * <str2> must be big enough to hold <str1>
1372 * <str1> and <str2> may point to the same place.
1375 static void utol __PARAM__((register char const *str1,register char *str2), (str1, str2)) __OTORP__(register char const *str1;register char *str2;){
1377 for(; c= *((unsigned char*)str1); str1++,str2++)
1388 * Push or pop getval and putval functions to node <np>
1389 * <fp> is null to pop, otherwise, <fp> is pushed onto stack
1390 * The top of the stack is returned
1392 Namfun_t *nv_stack __PARAM__((register Namval_t *np, register Namfun_t* fp), (np, fp)) __OTORP__(register Namval_t *np; register Namfun_t* fp;){
1393 register Namfun_t *lp;
1396 if((lp=np->nvfun)==fp)
1398 /* see if <fp> is on the list already and move to top */
1399 if(lp) while(lp->next)
1403 lp->next = fp->next;
1409 fp->next = np->nvfun;
1412 else if(fp = np->nvfun)
1413 np->nvfun = fp->next;
1418 * add or replace built-in version of command commresponding to <path>
1419 * The <bltin> argument is a pointer to the built-in
1420 * Special builtins cannot be replaced and return -1
1422 int sh_addbuiltin __PARAM__((const char *path, int (*bltin)(int, char*[],__V_*),__V_ *extra), (path, bltin, extra)) __OTORP__(const char *path; int (*bltin)();__V_ *extra;){
1423 register const char *cp, *name = path_basename(path);
1424 register Namval_t *np, *nq=0;
1425 if(name==path && (cp=strchr(name,'.')) && cp!=name)
1427 int offset = staktell();
1428 stakwrite(name,cp-name);
1430 nq=nv_open(stakptr(offset),0,NV_VARNAME|NV_NOARRAY);
1431 offset = staktell();
1432 stakputs(nv_name(nq));
1435 path = name = stakptr(offset);
1437 np = nv_search(name,sh.bltin_tree,NV_ADD);
1438 if(!np || nv_isattr(np,BLT_SPC))
1440 if(np->nvenv && !nv_isattr(np,NV_NOFREE))
1441 free((__V_*)np->nvenv);
1447 np->nvalue.bfp = bltin;
1448 nv_onattr(np,NV_BLTIN);
1450 np->nvenv = strdup(path);
1451 np->nvfun = (Namfun_t*)extra;
1455 cp=nv_setdisc(nq,cp+1,np,(Namfun_t*)nq);
1458 error(ERROR_exit(1),e_baddisc,name);
1463 static int maxbufsize;
1464 static char *curbuf;
1467 * Return a pointer to a string denoting the value of <val>
1468 * with <places> places after the decimal point. The string
1469 * will be stored within static variable <numbuf>.
1471 char *sh_ftos __PARAM__((double val,register int places), (val, places)) __OTORP__(double val;register int places;){
1472 register char *cp, *sp;
1475 cp = sffcvt(val,places,&decpt,&sign);
1478 places +=3; /* room for sign, decimal point and null byte */
1480 curbuf = (char*)malloc(maxbufsize=places);
1481 else if(places > maxbufsize)
1482 curbuf = (char*)realloc(curbuf,maxbufsize=places);
1488 *sp++ = GETDECIMAL(0);
1491 while(*sp++ = *cp++);
1496 * convert <val> to a string with <places> significant figures
1497 * The result is placed in a local buffer and a pointer returned
1499 char *sh_etos __PARAM__((double val,register int places), (val, places)) __OTORP__(double val;register int places;){
1500 register int bufsize = places+8;
1502 curbuf = (char*)malloc(maxbufsize=bufsize);
1503 else if(bufsize > maxbufsize)
1504 curbuf = (char*)realloc(curbuf,maxbufsize=bufsize);
1505 sfsprintf(curbuf,bufsize,"%.*g",places,val);
1510 * call the next getval function in the chain
1512 char *nv_getv __PARAM__((Namval_t *np, register Namfun_t *nfp), (np, nfp)) __OTORP__(Namval_t *np; register Namfun_t *nfp;){
1513 register Namfun_t *fp;
1515 if((fp = nfp) != NIL(Namfun_t*) && !local)
1516 fp = nfp = nfp->next;
1518 while(fp && !fp->disc->getnum && !fp->disc->getval)
1522 if(nfp && nfp->disc->getval)
1523 cp = (*nfp->disc->getval)(np,nfp);
1524 else if(nfp && nfp->disc->getnum)
1525 cp = sh_etos((*nfp->disc->getnum)(np,nfp),12);
1535 * call the next getnum function in the chain
1537 double nv_getn __PARAM__((Namval_t *np, register Namfun_t *nfp), (np, nfp)) __OTORP__(Namval_t *np; register Namfun_t *nfp;){
1538 register Namfun_t *fp;
1539 register double d=0;
1540 if((fp = nfp) != NIL(Namfun_t*) && !local)
1541 fp = nfp = nfp->next;
1543 while(fp && !fp->disc->getnum && !fp->disc->getval)
1547 if(nfp && nfp->disc->getnum)
1548 d = (*nfp->disc->getnum)(np,nfp);
1549 else if(nfp && nfp->disc->getval)
1551 char *str = (*nfp->disc->getval)(np,nfp);
1564 * call the next assign function in the chain
1566 void nv_putv __PARAM__((Namval_t *np, const char *value, int flags, register Namfun_t *nfp), (np, value, flags, nfp)) __OTORP__(Namval_t *np; const char *value; int flags; register Namfun_t *nfp;){
1567 register Namfun_t *fp;
1568 if((fp=nfp) != NIL(Namfun_t*) && !local)
1569 fp = nfp = nfp->next;
1571 while(fp && !fp->disc->putval)
1575 if(nfp && nfp->disc->putval)
1576 (*nfp->disc->putval)(np,value, flags, nfp);
1581 nv_putval(np, value, flags);
1590 #define BLOCKED ((Namval_t*)&local)
1599 * free discipline if no more discipline functions
1601 static void chktfree __PARAM__((register Namval_t *np, register struct vardisc *vp), (np, vp)) __OTORP__(register Namval_t *np; register struct vardisc *vp;){
1603 for(n=0; n< sizeof(vp->disc)/sizeof(*vp->disc); n++)
1608 if(n>=sizeof(vp->disc)/sizeof(*vp->disc))
1610 /* no disc left so pop */
1612 if(fp=nv_stack(np, NIL(Namfun_t*)))
1618 * This function performs an assignment disc on the given node <np>
1620 static void assign __PARAM__((Namval_t *np,const char* val,int flags,Namfun_t *handle), (np, val, flags, handle)) __OTORP__(Namval_t *np;const char* val;int flags;Namfun_t *handle;){
1621 register struct vardisc *vp = (struct vardisc*)handle;
1622 register Namval_t *nq, **disc;
1625 if(!(nq=vp->disc[ASSIGN]))
1627 nv_putv(np,val,flags,handle);
1630 nv_putval(SH_VALNOD, val, (flags&NV_INTEGER)?NV_NOFREE|NV_INTEGER|NV_DOUBLE|NV_EXPNOTE:NV_NOFREE);
1632 disc = (val? &(vp->disc[ASSIGN]):&(vp->disc[UNASSIGN]));
1633 if((nq= *disc) && nq!=BLOCKED)
1646 if(nv_isnull(SH_VALNOD))
1648 else if(flags&NV_INTEGER)
1650 d = nv_getnum(SH_VALNOD);
1654 cp = nv_getval(SH_VALNOD);
1656 nv_putv(np,cp,flags|NV_RDONLY,handle);
1657 nv_unset(SH_VALNOD);
1659 else if(!nq || nq==BLOCKED)
1661 if(vp->disc[ASSIGN])
1662 nv_unset(vp->disc[ASSIGN]);
1663 if(vp->disc[LOOKUP])
1664 nv_unset(vp->disc[LOOKUP]);
1665 if(vp->disc[UNASSIGN])
1666 nv_unset(vp->disc[UNASSIGN]);
1667 if(handle=nv_stack(np, NIL(Namfun_t*)))
1668 free((__V_*)handle);
1674 * This function executes a lookup disc and then performs
1675 * the lookup on the given node <np>
1677 static char* lookup __PARAM__((Namval_t *np, Namfun_t *handle), (np, handle)) __OTORP__(Namval_t *np; Namfun_t *handle;){
1678 register struct vardisc *vp = (struct vardisc*)handle;
1679 register Namval_t *nq;
1680 register char *cp=0;
1681 if((nq=vp->disc[LOOKUP]) && nq!=BLOCKED)
1683 nv_unset(SH_VALNOD);
1684 vp->disc[LOOKUP]=BLOCKED;
1686 if(vp->disc[LOOKUP]==BLOCKED)
1687 vp->disc[LOOKUP]=nq;
1688 else if(!vp->disc[LOOKUP])
1690 cp = nv_getval(SH_VALNOD);
1693 cp = nv_getv(np,handle);
1698 * node creation discipline
1700 Namval_t *nv_create __PARAM__((register Namval_t* np,const char *name,register Namfun_t *fp), (np, name, fp)) __OTORP__(register Namval_t* np;const char *name;register Namfun_t *fp;){
1701 if(np == (Namval_t*)fp)
1705 while(fp && !fp->disc->create)
1707 if(fp && fp->disc->create)
1708 return((*fp->disc->create)(np,name,fp));
1709 return(NIL(Namval_t*));
1712 static const Namdisc_t shdisc =
1714 sizeof(struct vardisc),
1721 * Set disc on given <event> to <action>
1722 * If action==np, the current disc is returned
1723 * A null return value indicates that no <event> is known for <np>
1724 * If <event> is NULL, then return the event name after <action>
1725 * If <event> is NULL, and <action> is NULL, return the first event
1727 char *nv_setdisc __PARAM__((register Namval_t* np,register const char *event,Namval_t *action,register Namfun_t *fp), (np, event, action, fp)) __OTORP__(register Namval_t* np;register const char *event;Namval_t *action;register Namfun_t *fp;){
1728 register struct vardisc *vp = (struct vardisc*)np->nvfun;
1730 if(np == (Namval_t*)fp)
1732 static const char *discnames[] = { "get", "set", "unset", 0 };
1733 register const char *name;
1734 register int getname=0;
1735 /* top level call, check for get/set */
1739 return((char*)discnames[0]);
1741 event = (char*)action;
1743 for(type=0; name=discnames[type]; type++)
1745 if(strcmp(event,name)==0)
1751 if(name && !(name = discnames[++type]))
1756 if((fp=(Namfun_t*)vp) && fp->disc->setdisc)
1757 return((*fp->disc->setdisc)(np,event,action,fp));
1760 return((char*)name);
1764 if(np != (Namval_t*)fp)
1766 /* not the top level */
1767 while(fp = fp->next)
1769 if(fp->disc->setdisc)
1770 return((*fp->disc->setdisc)(np,event,action,fp));
1774 /* Handle GET/SET/UNSET disc */
1775 if(vp && vp->fun.disc->putval!=assign)
1780 return((char*)action);
1781 if(!(vp = newof(NIL(struct vardisc*),struct vardisc,1,0)))
1783 vp->fun.disc = &shdisc;
1784 nv_stack(np, (Namfun_t*)vp);
1787 action = vp->disc[type];
1789 vp->disc[type] = action;
1792 action = vp->disc[type];
1797 return(action?(char*)action:"");
1801 * Create a reference node from <np>
1803 void nv_setref __PARAM__((register Namval_t *np), (np)) __OTORP__(register Namval_t *np;){
1804 register Namval_t *nq, *nr;
1806 register int flags = NV_ARRAY|NV_VARNAME|NV_REF;
1807 Hashtab_t *hp=sh.var_tree;
1808 if(nv_isattr(np,NV_REF))
1810 if(nv_isattr(np,NV_ARRAY))
1811 error(ERROR_exit(1),e_badref,nv_name(np));
1812 if(!(cp=nv_getval(np)))
1813 error(ERROR_exit(1),e_noref,nv_name(np));
1814 if(np->nvsize&NV_PARAM)
1816 if(!(hp=(Hashtab_t*)sh.st.par_tree))
1818 if(!(hp=hashscope(sh.var_tree)))
1822 nr= nq = nv_open(cp, hp, NV_ARRAY|NV_VARNAME|NV_REF);
1823 while(nv_isattr(nr,NV_REF))
1827 if(!(hp=hashscope(hp)))
1828 error(ERROR_exit(1),e_selfref,nv_name(np));
1829 /* bind to earlier scope, or add to global scope */
1830 nq=nv_search((char*)np,hp,NV_ADD|HASH_BUCKET);
1834 nv_onattr(np,NV_REF|NV_NOFREE);
1838 * return the scope corresponding to <index>
1839 * if <index>==0, global scope returned
1840 * otherwise <index>th previous scope on function call stack returned
1841 * If <index> greater than or equal to number of scopes, NULL returned
1843 Hashtab_t *nv_getscope(int index)
1846 struct sh_scoped *sp;
1847 if(index==0) /* return global scope */
1848 return((hp=hashscope(sh.var_tree))?hp:sh.var_tree);
1850 while(sp && index-->0)
1853 return((Hashtab_t*)sp->par_tree);
1856 return(NIL(Hashtab_t*));