1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
18da2e3ebchin*                                                                      *
19da2e3ebchin***********************************************************************/
20da2e3ebchin#pragma prototyped
21da2e3ebchin/*
22da2e3ebchin * AT&T Labs
23da2e3ebchin *
24da2e3ebchin */
25da2e3ebchin
26da2e3ebchin#define putenv	___putenv
27da2e3ebchin
28da2e3ebchin#include	"defs.h"
29da2e3ebchin#include	"variables.h"
30da2e3ebchin#include	"path.h"
31da2e3ebchin#include	"lexstates.h"
32da2e3ebchin#include	"timeout.h"
33da2e3ebchin#include	"FEATURE/externs"
34da2e3ebchin#include	"streval.h"
35da2e3ebchin
367c2fbfbApril Chin#define NVCACHE		8	/* must be a power of 2 */
377c2fbfbApril Chin#define Empty	((char*)(e_sptbnl+3))
38da2e3ebchinstatic char	*savesub = 0;
39da2e3ebchin
40da2e3ebchin#if !_lib_pathnative && _lib_uwin_path
41da2e3ebchin
42da2e3ebchin#define _lib_pathnative		1
43da2e3ebchin
44da2e3ebchinextern int	uwin_path(const char*, char*, int);
45da2e3ebchin
46da2e3ebchinsize_t
47da2e3ebchinpathnative(const char* path, char* buf, size_t siz)
48da2e3ebchin{
49da2e3ebchin	return uwin_path(path, buf, siz);
50da2e3ebchin}
51da2e3ebchin
52da2e3ebchin#endif /* _lib_pathnative */
53da2e3ebchin
54da2e3ebchinstatic void	attstore(Namval_t*,void*);
55da2e3ebchin#ifndef _ENV_H
563e14f97Roger A. Faulkner    static void	pushnam(Namval_t*,void*);
573e14f97Roger A. Faulkner    static char	*staknam(Namval_t*, char*);
58da2e3ebchin#endif
597c2fbfbApril Chinstatic void	ltou(char*);
607c2fbfbApril Chinstatic void	utol(char*);
61da2e3ebchinstatic void	rightjust(char*, int, int);
627c2fbfbApril Chinstatic char	*lastdot(char*, int);
63da2e3ebchin
64da2e3ebchinstruct adata
65da2e3ebchin{
667c2fbfbApril Chin	Shell_t		*sh;
677c2fbfbApril Chin	Namval_t	*tp;
687c2fbfbApril Chin	char		**argnam;
697c2fbfbApril Chin	int		attsize;
707c2fbfbApril Chin	char		*attval;
71da2e3ebchin};
72da2e3ebchin
737c2fbfbApril Chin#if SHOPT_TYPEDEF
747c2fbfbApril Chin    struct sh_type
757c2fbfbApril Chin    {
767c2fbfbApril Chin	void		*previous;
777c2fbfbApril Chin	Namval_t	**nodes;
787c2fbfbApril Chin	Namval_t	*rp;
797c2fbfbApril Chin	short		numnodes;
807c2fbfbApril Chin	short		maxnodes;
817c2fbfbApril Chin    };
827c2fbfbApril Chin#endif /*SHOPT_TYPEDEF */
837c2fbfbApril Chin
847c2fbfbApril Chin#if NVCACHE
857c2fbfbApril Chin    struct Namcache
867c2fbfbApril Chin    {
877c2fbfbApril Chin	struct Cache_entry
887c2fbfbApril Chin	{
897c2fbfbApril Chin		Dt_t		*root;
9034f9b3eRoland Mainz		Dt_t		*last_root;
917c2fbfbApril Chin		char		*name;
927c2fbfbApril Chin		Namval_t	*np;
937c2fbfbApril Chin		Namval_t	*last_table;
947c2fbfbApril Chin		int		flags;
957c2fbfbApril Chin		short		size;
967c2fbfbApril Chin		short		len;
977c2fbfbApril Chin	} entries[NVCACHE];
987c2fbfbApril Chin	short		index;
997c2fbfbApril Chin	short		ok;
1007c2fbfbApril Chin    };
1017c2fbfbApril Chin    static struct Namcache nvcache;
1027c2fbfbApril Chin#endif
1037c2fbfbApril Chin
104da2e3ebchinchar		nv_local = 0;
105da2e3ebchin#ifndef _ENV_H
106da2e3ebchinstatic void(*nullscan)(Namval_t*,void*);
107da2e3ebchin#endif
108da2e3ebchin
109da2e3ebchin#if ( SFIO_VERSION  <= 20010201L )
110da2e3ebchin#   define _data        data
111da2e3ebchin#endif
112da2e3ebchin
113da2e3ebchin#if !SHOPT_MULTIBYTE
114da2e3ebchin#   define mbchar(p)       (*(unsigned char*)p++)
115da2e3ebchin#endif /* SHOPT_MULTIBYTE */
116da2e3ebchin
117da2e3ebchin/* ========	name value pair routines	======== */
118da2e3ebchin
119da2e3ebchin#include	"shnodes.h"
120da2e3ebchin#include	"builtins.h"
121da2e3ebchin
122da2e3ebchinstatic char *getbuf(size_t len)
123da2e3ebchin{
124da2e3ebchin	static char *buf;
125da2e3ebchin	static size_t buflen;
126da2e3ebchin	if(buflen < len)
127da2e3ebchin	{
128da2e3ebchin		if(buflen==0)
129da2e3ebchin			buf = (char*)malloc(len);
130da2e3ebchin		else
131da2e3ebchin			buf = (char*)realloc(buf,len);
132da2e3ebchin		buflen = len;
133da2e3ebchin	}
134da2e3ebchin	return(buf);
135da2e3ebchin}
136da2e3ebchin
137da2e3ebchin#ifdef _ENV_H
138da2e3ebchinvoid sh_envput(Env_t* ep,Namval_t *np)
139da2e3ebchin{
140da2e3ebchin	int offset = staktell();
141da2e3ebchin	Namarr_t *ap = nv_arrayptr(np);
142da2e3ebchin	char *val;
143da2e3ebchin	if(ap)
144da2e3ebchin	{
145da2e3ebchin		if(ap->nelem&ARRAY_UNDEF)
146da2e3ebchin			nv_putsub(np,"0",0L);
147da2e3ebchin		else if(!(val=nv_getsub(np)) || strcmp(val,"0"))
148da2e3ebchin			return;
149da2e3ebchin	}
150da2e3ebchin	if(!(val = nv_getval(np)))
151da2e3ebchin		return;
152da2e3ebchin	stakputs(nv_name(np));
153da2e3ebchin	stakputc('=');
154da2e3ebchin	stakputs(val);
155da2e3ebchin	stakseek(offset);
156da2e3ebchin	env_add(ep,stakptr(offset),ENV_STRDUP);
157da2e3ebchin}
158da2e3ebchin#endif
159da2e3ebchin
160da2e3ebchin/*
161da2e3ebchin * output variable name in format for re-input
162da2e3ebchin */
163da2e3ebchinvoid nv_outname(Sfio_t *out, char *name, int len)
164da2e3ebchin{
165da2e3ebchin	const char *cp=name, *sp;
166da2e3ebchin	int c, offset = staktell();
167da2e3ebchin	while(sp= strchr(cp,'['))
168da2e3ebchin	{
169da2e3ebchin		if(len>0 && cp+len <= sp)
170da2e3ebchin			break;
171da2e3ebchin		sfwrite(out,cp,++sp-cp);
172da2e3ebchin		stakseek(offset);
1737c2fbfbApril Chin		while(c= *sp++)
174da2e3ebchin		{
175da2e3ebchin			if(c==']')
176da2e3ebchin				break;
177da2e3ebchin			else if(c=='\\')
178da2e3ebchin			{
179da2e3ebchin				if(*sp=='[' || *sp==']' || *sp=='\\')
180da2e3ebchin					c = *sp++;
181da2e3ebchin			}
182da2e3ebchin			stakputc(c);
183da2e3ebchin		}
184da2e3ebchin		stakputc(0);
185da2e3ebchin		sfputr(out,sh_fmtq(stakptr(offset)),-1);
186da2e3ebchin		if(len>0)
187da2e3ebchin		{
188da2e3ebchin			sfputc(out,']');
189da2e3ebchin			return;
190da2e3ebchin		}
1917c2fbfbApril Chin		cp = sp-1;
192da2e3ebchin	}
193da2e3ebchin	if(*cp)
194da2e3ebchin	{
195da2e3ebchin		if(len>0)
196da2e3ebchin			sfwrite(out,cp,len);
197da2e3ebchin		else
198da2e3ebchin			sfputr(out,cp,-1);
199da2e3ebchin	}
200da2e3ebchin	stakseek(offset);
201da2e3ebchin}
202da2e3ebchin
2037c2fbfbApril Chin#if SHOPT_TYPEDEF
2047c2fbfbApril ChinNamval_t *nv_addnode(Namval_t* np, int remove)
2057c2fbfbApril Chin{
2067c2fbfbApril Chin	register struct sh_type	*sp = (struct sh_type*)sh.mktype;
2077c2fbfbApril Chin	register int		i;
2087c2fbfbApril Chin	register char		*name=0;
2097c2fbfbApril Chin	if(sp->numnodes==0 && !nv_isnull(np) && sh.last_table)
2107c2fbfbApril Chin	{
2117c2fbfbApril Chin		/* could be an redefine */
2127c2fbfbApril Chin		Dt_t *root = nv_dict(sh.last_table);
2137c2fbfbApril Chin		sp->rp = np;
2147c2fbfbApril Chin		nv_delete(np,root,NV_NOFREE);
2157c2fbfbApril Chin		np = nv_search(sp->rp->nvname,root,NV_ADD);
2167c2fbfbApril Chin	}
2177c2fbfbApril Chin	if(sp->numnodes && memcmp(np->nvname,NV_CLASS,sizeof(NV_CLASS)-1))
2187c2fbfbApril Chin	{
2197c2fbfbApril Chin		name = (sp->nodes[0])->nvname;
2207c2fbfbApril Chin		i = strlen(name);
2217c2fbfbApril Chin		if(memcmp(np->nvname,name,i))
2227c2fbfbApril Chin			return(np);
2237c2fbfbApril Chin	}
2247c2fbfbApril Chin	if(sp->rp && sp->numnodes)
2257c2fbfbApril Chin	{
2267c2fbfbApril Chin		/* check for a redefine */
2277c2fbfbApril Chin		if(name && np->nvname[i]=='.' && np->nvname[i+1]=='_' && np->nvname[i+2]==0)
2287c2fbfbApril Chin			sp->rp = 0;
2297c2fbfbApril Chin		else
2307c2fbfbApril Chin		{
2317c2fbfbApril Chin			Dt_t *root = nv_dict(sh.last_table);
2327c2fbfbApril Chin			nv_delete(sp->nodes[0],root,NV_NOFREE);
2337c2fbfbApril Chin			dtinsert(root,sp->rp);
2347c2fbfbApril Chin			errormsg(SH_DICT,ERROR_exit(1),e_redef,sp->nodes[0]->nvname);
2357c2fbfbApril Chin		}
2367c2fbfbApril Chin	}
2377c2fbfbApril Chin	for(i=0; i < sp->numnodes; i++)
2387c2fbfbApril Chin	{
2397c2fbfbApril Chin		if(np == sp->nodes[i])
2407c2fbfbApril Chin		{
2417c2fbfbApril Chin			if(remove)
2427c2fbfbApril Chin			{
2437c2fbfbApril Chin				while(++i < sp->numnodes)
2447c2fbfbApril Chin					sp->nodes[i-1] = sp->nodes[i];
2457c2fbfbApril Chin				sp->numnodes--;
2467c2fbfbApril Chin			}
2477c2fbfbApril Chin			return(np);
2487c2fbfbApril Chin		}
2497c2fbfbApril Chin	}
2507c2fbfbApril Chin	if(remove)
2517c2fbfbApril Chin		return(np);
2527c2fbfbApril Chin	if(sp->numnodes==sp->maxnodes)
2537c2fbfbApril Chin	{
2547c2fbfbApril Chin		sp->maxnodes += 20;
2557c2fbfbApril Chin		sp->nodes = (Namval_t**)realloc(sp->nodes,sizeof(Namval_t*)*sp->maxnodes);
2567c2fbfbApril Chin	}
2577c2fbfbApril Chin	sp->nodes[sp->numnodes++] = np;
2587c2fbfbApril Chin	return(np);
2597c2fbfbApril Chin}
2607c2fbfbApril Chin#endif /* SHOPT_TYPEDEF */
2617c2fbfbApril Chin
2627c2fbfbApril Chin/*
2637c2fbfbApril Chin * given a list of assignments, determine <name> is on the list
2647c2fbfbApril Chin   returns a pointer to the argnod on the list or NULL
2657c2fbfbApril Chin */
2667c2fbfbApril Chinstruct argnod *nv_onlist(struct argnod *arg, const char *name)
2677c2fbfbApril Chin{
2687c2fbfbApril Chin	char *cp;
2697c2fbfbApril Chin	int len = strlen(name);
2707c2fbfbApril Chin	for(;arg; arg=arg->argnxt.ap)
2717c2fbfbApril Chin	{
2727c2fbfbApril Chin		if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
2737c2fbfbApril Chin			cp = ((struct fornod*)arg->argchn.ap)->fornam;
2747c2fbfbApril Chin		else
2757c2fbfbApril Chin			cp = arg->argval;
2767c2fbfbApril Chin		if(memcmp(cp,name,len)==0 && (cp[len]==0 || cp[len]=='='))
2777c2fbfbApril Chin			return(arg);
2787c2fbfbApril Chin	}
2797c2fbfbApril Chin	return(0);
2807c2fbfbApril Chin}
2817c2fbfbApril Chin
282da2e3ebchin/*
283da2e3ebchin * Perform parameter assignment for a linked list of parameters
284da2e3ebchin * <flags> contains attributes for the parameters
285da2e3ebchin */
28634f9b3eRoland Mainzvoid nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
287da2e3ebchin{
2887c2fbfbApril Chin	Shell_t		*shp = &sh;
289da2e3ebchin	register char	*cp;
2907c2fbfbApril Chin	register Namval_t *np, *mp;
2917c2fbfbApril Chin	char		*trap=shp->st.trap[SH_DEBUGTRAP];
2927c2fbfbApril Chin	char		*prefix = shp->prefix;
293da2e3ebchin	int		traceon = (sh_isoption(SH_XTRACE)!=0);
294da2e3ebchin	int		array = (flags&(NV_ARRAY|NV_IARRAY));
2957c2fbfbApril Chin	Namarr_t	*ap;
2967c2fbfbApril Chin	Namval_t	node;
2977c2fbfbApril Chin	struct Namref	nr;
2987c2fbfbApril Chin#if SHOPT_TYPEDEF
2997c2fbfbApril Chin	int		maketype = flags&NV_TYPE;
3007c2fbfbApril Chin	struct sh_type	shtp;
3017c2fbfbApril Chin	if(maketype)
3027c2fbfbApril Chin	{
3037c2fbfbApril Chin		shtp.previous = shp->mktype;
3047c2fbfbApril Chin		shp->mktype=(void*)&shtp;
3057c2fbfbApril Chin		shtp.numnodes=0;
3067c2fbfbApril Chin		shtp.maxnodes = 20;
3077c2fbfbApril Chin		shtp.rp = 0;
3087c2fbfbApril Chin		shtp.nodes =(Namval_t**)malloc(shtp.maxnodes*sizeof(Namval_t*));
3097c2fbfbApril Chin	}
3107c2fbfbApril Chin#endif /* SHOPT_TYPEDEF*/
3117c2fbfbApril Chin	flags &= ~(NV_TYPE|NV_ARRAY|NV_IARRAY);
312da2e3ebchin	if(sh_isoption(SH_ALLEXPORT))
313da2e3ebchin		flags |= NV_EXPORT;
3147c2fbfbApril Chin	if(shp->prefix)
315da2e3ebchin	{
316da2e3ebchin		flags &= ~(NV_IDENT|NV_EXPORT);
317da2e3ebchin		flags |= NV_VARNAME;
318da2e3ebchin	}
319da2e3ebchin	for(;arg; arg=arg->argnxt.ap)
320da2e3ebchin	{
3217c2fbfbApril Chin		shp->used_pos = 0;
322da2e3ebchin		if(arg->argflag&ARG_MAC)
3237c2fbfbApril Chin		{
3247c2fbfbApril Chin			shp->prefix = 0;
3257c2fbfbApril Chin			cp = sh_mactrim(shp,arg->argval,(flags&NV_NOREF)?-3:-1);
3267c2fbfbApril Chin			shp->prefix = prefix;
3277c2fbfbApril Chin		}
328da2e3ebchin		else
329da2e3ebchin		{
330da2e3ebchin			stakseek(0);
3317c2fbfbApril Chin			if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
332da2e3ebchin			{
333da2e3ebchin				int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
3347c2fbfbApril Chin				int sub=0;
335da2e3ebchin				struct fornod *fp=(struct fornod*)arg->argchn.ap;
336da2e3ebchin				register Shnode_t *tp=fp->fortre;
3377c2fbfbApril Chin				flag |= (flags&(NV_NOSCOPE|NV_STATIC));
338da2e3ebchin				if(arg->argflag&ARG_QUOTED)
3397c2fbfbApril Chin					cp = sh_mactrim(shp,fp->fornam,-1);
340da2e3ebchin				else
341da2e3ebchin					cp = fp->fornam;
3427c2fbfbApril Chin				error_info.line = fp->fortyp-shp->st.firstline;
34334f9b3eRoland Mainz				if(!array && tp->tre.tretyp!=TLST && tp->com.comset && !tp->com.comarg && tp->com.comset->argval[0]==0 && tp->com.comset->argval[1]=='[')
34434f9b3eRoland Mainz					array |= (tp->com.comset->argflag&ARG_MESSAGE)?NV_IARRAY:NV_ARRAY;
3457c2fbfbApril Chin				if(shp->fn_depth && (Namval_t*)tp->com.comnamp==SYSTYPESET)
346da2e3ebchin			                flag |= NV_NOSCOPE;
347da2e3ebchin				if(prefix && tp->com.comset && *cp=='[')
348da2e3ebchin				{
3497c2fbfbApril Chin					shp->prefix = 0;
3507c2fbfbApril Chin					np = nv_open(prefix,shp->var_tree,flag);
3517c2fbfbApril Chin					shp->prefix = prefix;
352da2e3ebchin					if(np)
353da2e3ebchin					{
3547c2fbfbApril Chin						if(nv_isvtree(np) && !nv_isarray(np))
355da2e3ebchin						{
356da2e3ebchin							stakputc('.');
357da2e3ebchin							stakputs(cp);
358da2e3ebchin							cp = stakfreeze(1);
359da2e3ebchin						}
360da2e3ebchin						nv_close(np);
361da2e3ebchin					}
362da2e3ebchin				}
3637c2fbfbApril Chin				np = nv_open(cp,shp->var_tree,flag|NV_ASSIGN);
36434f9b3eRoland Mainz				if(typ && !array  && (nv_isnull(np) || nv_isarray(np)))
36534f9b3eRoland Mainz					nv_settype(np,typ,0);
3667c2fbfbApril Chin				if((flags&NV_STATIC) && !nv_isnull(np))
3677c2fbfbApril Chin#if SHOPT_TYPEDEF
3687c2fbfbApril Chin					goto check_type;
3697c2fbfbApril Chin#else
3707c2fbfbApril Chin					continue;
371