Blame src/cmd/ksh93/sh/env.c

Packit Service a8c26c
/***********************************************************************
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*               This software is part of the ast package               *
Packit Service a8c26c
*          Copyright (c) 1982-2011 AT&T Intellectual Property          *
Packit Service a8c26c
*                      and is licensed under the                       *
Packit Service a8c26c
*                 Eclipse Public License, Version 1.0                  *
Packit Service a8c26c
*                    by AT&T Intellectual Property                     *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                A copy of the License is available at                 *
Packit Service a8c26c
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit Service a8c26c
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*              Information and Software Systems Research               *
Packit Service a8c26c
*                            AT&T Research                             *
Packit Service a8c26c
*                           Florham Park NJ                            *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
*                  David Korn <dgk@research.att.com>                   *
Packit Service a8c26c
*                                                                      *
Packit Service a8c26c
***********************************************************************/
Packit Service a8c26c
#pragma prototyped
Packit Service a8c26c
Packit Service a8c26c
#include	<ast.h>
Packit Service a8c26c
#include	<cdt.h>
Packit Service a8c26c
Packit Service a8c26c
#define	env_change()		(++ast.env_serial)
Packit Service a8c26c
Packit Service a8c26c
typedef struct _venv_ Evar_t;
Packit Service a8c26c
struct _venv_
Packit Service a8c26c
{
Packit Service a8c26c
	union
Packit Service a8c26c
	{
Packit Service a8c26c
		Evar_t		*next;
Packit Service a8c26c
		char		*ptr;
Packit Service a8c26c
	}	un;
Packit Service a8c26c
	Dtlink_t	link;
Packit Service a8c26c
	int		index;
Packit Service a8c26c
};
Packit Service a8c26c
Packit Service a8c26c
typedef  struct _env_
Packit Service a8c26c
{
Packit Service a8c26c
	Dt_t	*dt;
Packit Service a8c26c
	Evar_t	*freelist;
Packit Service a8c26c
	char	**env;
Packit Service a8c26c
	int	count;
Packit Service a8c26c
	int	extra;
Packit Service a8c26c
	int	max;
Packit Service a8c26c
	int	flags;
Packit Service a8c26c
} Env_t;
Packit Service a8c26c
Packit Service a8c26c
#define _BLD_env	1
Packit Service a8c26c
#include	<env.h>
Packit Service a8c26c
Packit Service a8c26c
#define ENV_VALID	2		/* set if env is valid */
Packit Service a8c26c
#define ENV_PMALLOC	1		/* set if Evar_t->un.ptr  *s malloced */
Packit Service a8c26c
#define ENV_VMALLOC	2		/* set of Evar_t was malloced */
Packit Service a8c26c
#define ENV_BITS	3
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * Compares the name portion of name=... only.
Packit Service a8c26c
 */
Packit Service a8c26c
static int compare(Dt_t *dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc)
Packit Service a8c26c
{
Packit Service a8c26c
	register int c,d;
Packit Service a8c26c
	const unsigned char *s1=(unsigned const char*)key1;
Packit Service a8c26c
	const unsigned char *s2=(unsigned const char*)key2; 
Packit Service a8c26c
	while((c= *s1++) && c!='=' && c==*s2) 
Packit Service a8c26c
		s2++;
Packit Service a8c26c
	if(c=='=')
Packit Service a8c26c
		c = 0;
Packit Service a8c26c
	if((d=*s2)=='=')
Packit Service a8c26c
		d = 0;
Packit Service a8c26c
	return(c-d);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
static Dtdisc_t env_disc =
Packit Service a8c26c
{
Packit Service a8c26c
	0, -1,
Packit Service a8c26c
	sizeof(char*),
Packit Service a8c26c
	0,
Packit Service a8c26c
	0,
Packit Service a8c26c
	compare
Packit Service a8c26c
};
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 *  return a pointer to the environment in sorted order
Packit Service a8c26c
 *  NULL is returned if there if there is nospace
Packit Service a8c26c
 */
Packit Service a8c26c
char **env_get(Env_t* ep)
Packit Service a8c26c
{
Packit Service a8c26c
	register Evar_t *vp;
Packit Service a8c26c
	register int n=ep->extra;
Packit Service a8c26c
	if(ep->flags&ENV_VALID)
Packit Service a8c26c
		return(ep->env+n);
Packit Service a8c26c
	if(ep->count > ep->max)
Packit Service a8c26c
	{
Packit Service a8c26c
		if(ep->flags&ENV_MALLOCED)
Packit Service a8c26c
			free((void*)ep->env);
Packit Service a8c26c
		if(!(ep->env = (char**)malloc(sizeof(char*)*(ep->count+1))))
Packit Service a8c26c
			return(0);
Packit Service a8c26c
		ep->flags |= ENV_MALLOCED;
Packit Service a8c26c
		ep->max = ep->count;
Packit Service a8c26c
	}
Packit Service a8c26c
	for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=(Evar_t*)dtnext(ep->dt,vp))
Packit Service a8c26c
	{
Packit Service a8c26c
		vp->index = (n<<ENV_BITS) | (vp->index&((1<
Packit Service a8c26c
		ep->env[n++] = vp->un.ptr;
Packit Service a8c26c
	}
Packit Service a8c26c
	ep->env[n] = 0;
Packit Service a8c26c
	ep->flags |= ENV_VALID;
Packit Service a8c26c
	environ = ep->env+ep->extra;
Packit Service a8c26c
	return(ep->env+ep->extra);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 *  add name=value pair given by <str> to <ep>
Packit Service a8c26c
 *  if malloced is set, the variable will be freed when reassigned
Packit Service a8c26c
 *  The environment list may become invalidated
Packit Service a8c26c
 *  Returns 1 for success, 0 for failure
Packit Service a8c26c
 */
Packit Service a8c26c
int env_add(Env_t *ep, const char *str, int flags)
Packit Service a8c26c
{
Packit Service a8c26c
	Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str);
Packit Service a8c26c
	if(vp && strcmp(str,vp->un.ptr)==0)
Packit Service a8c26c
		return(1);
Packit Service a8c26c
	if(flags&ENV_STRDUP)
Packit Service a8c26c
		str = strdup(str);
Packit Service a8c26c
	if(vp)
Packit Service a8c26c
	{
Packit Service a8c26c
		if(vp->index&ENV_PMALLOC)
Packit Service a8c26c
			free((void*)vp->un.ptr);
Packit Service a8c26c
		vp->un.ptr = (char*)str;
Packit Service a8c26c
		if(ep->env && (ep->flags&ENV_VALID))
Packit Service a8c26c
			ep->env[vp->index>>ENV_BITS] = vp->un.ptr;
Packit Service a8c26c
	}
Packit Service a8c26c
	else
Packit Service a8c26c
	{
Packit Service a8c26c
		ep->flags &= ~ENV_VALID;
Packit Service a8c26c
		if(vp = ep->freelist)
Packit Service a8c26c
			ep->freelist = vp->un.next;
Packit Service a8c26c
		else if(vp = newof((Evar_t*)0,Evar_t,2,0))
Packit Service a8c26c
		{
Packit Service a8c26c
			vp->index = ENV_VMALLOC;
Packit Service a8c26c
			ep->freelist = (vp+1);
Packit Service a8c26c
			ep->freelist->un.next = 0;
Packit Service a8c26c
		}
Packit Service a8c26c
		else
Packit Service a8c26c
			return(0);
Packit Service a8c26c
		vp->un.ptr = (void*)str;
Packit Service a8c26c
		if(!(vp=dtinsert(ep->dt,vp)))
Packit Service a8c26c
			return(0);
Packit Service a8c26c
		ep->count++;
Packit Service a8c26c
	}
Packit Service a8c26c
	if(flags)
Packit Service a8c26c
		vp->index |= ENV_PMALLOC;
Packit Service a8c26c
	else
Packit Service a8c26c
		vp->index &= ~ENV_PMALLOC;
Packit Service a8c26c
	env_change();
Packit Service a8c26c
	return(1);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 *  delete name  from <ep>
Packit Service a8c26c
 *  The environment list may become invalidated
Packit Service a8c26c
 *  Returns 1 for success, 0 for if name is not present 
Packit Service a8c26c
 */
Packit Service a8c26c
int env_delete(Env_t *ep, const char *str)
Packit Service a8c26c
{
Packit Service a8c26c
	Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str);
Packit Service a8c26c
	if(!vp)
Packit Service a8c26c
		return(0);
Packit Service a8c26c
	ep->flags &= ~ENV_VALID;
Packit Service a8c26c
	if(vp->index&ENV_PMALLOC)
Packit Service a8c26c
		free((void*)vp->un.ptr);
Packit Service a8c26c
	dtdelete(ep->dt,vp);
Packit Service a8c26c
	vp->un.next = ep->freelist;
Packit Service a8c26c
	ep->freelist = vp;
Packit Service a8c26c
	env_change();
Packit Service a8c26c
	return(1);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * open up a structure to support environment variables
Packit Service a8c26c
 * initialize with environment give by <envp>
Packit Service a8c26c
 * If <extra> > 0, <extra> slots will be left at beginning of
Packit Service a8c26c
 *    environment list when env_get() is involed.
Packit Service a8c26c
 * If <extra>==ENV_USABLE, then the original environ can be
Packit Service a8c26c
 *   used and returned.  Otherwise, a new one will be returned
Packit Service a8c26c
 */
Packit Service a8c26c
Env_t *env_open(char **envp, int extra)
Packit Service a8c26c
{
Packit Service a8c26c
	char **env;
Packit Service a8c26c
	Env_t *ep;
Packit Service a8c26c
	Evar_t *vp;
Packit Service a8c26c
	int n=2;
Packit Service a8c26c
	if(!(ep = newof((Env_t*)0,Env_t,1,0)))
Packit Service a8c26c
		return(0);
Packit Service a8c26c
	if(!(ep->dt = dtopen(&env_disc,Dtoset)))
Packit Service a8c26c
		return(0);
Packit Service a8c26c
	if(env=envp)
Packit Service a8c26c
	{
Packit Service a8c26c
		while(*env++);
Packit Service a8c26c
		n = (env+2)-envp;
Packit Service a8c26c
	}
Packit Service a8c26c
	if(extra==ENV_STABLE)
Packit Service a8c26c
	{
Packit Service a8c26c
		ep->env = envp;
Packit Service a8c26c
		ep->max = n-1;
Packit Service a8c26c
	}
Packit Service a8c26c
	else
Packit Service a8c26c
		ep->count = ep->extra = extra;
Packit Service a8c26c
	ep->freelist = vp = newof((Evar_t*)0,Evar_t,n,0);
Packit Service a8c26c
	vp->index = ENV_VMALLOC;
Packit Service a8c26c
	while(--n>0)
Packit Service a8c26c
	{
Packit Service a8c26c
		vp->un.next = (vp+1);
Packit Service a8c26c
		vp++;
Packit Service a8c26c
	}
Packit Service a8c26c
	vp->un.next = 0;
Packit Service a8c26c
	if(env)
Packit Service a8c26c
	{
Packit Service a8c26c
		for(env=envp; *env; env++)
Packit Service a8c26c
			env_add(ep,*env,0);
Packit Service a8c26c
	}
Packit Service a8c26c
	return(ep);
Packit Service a8c26c
}
Packit Service a8c26c
Packit Service a8c26c
/*
Packit Service a8c26c
 * close <ep> and free up all space used by it
Packit Service a8c26c
 */
Packit Service a8c26c
void env_close(Env_t *ep)
Packit Service a8c26c
{
Packit Service a8c26c
	Evar_t *vp, *vpnext,*top;
Packit Service a8c26c
	if(ep->env && (ep->flags&ENV_MALLOCED))
Packit Service a8c26c
		free((void*)ep->env);
Packit Service a8c26c
	for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=vpnext)
Packit Service a8c26c
	{
Packit Service a8c26c
		vpnext = (Evar_t*)dtnext(ep->dt,vp);
Packit Service a8c26c
		env_delete(ep,vp->un.ptr);
Packit Service a8c26c
	}
Packit Service a8c26c
	for(top=0,vp = ep->freelist; vp; vp = vpnext)
Packit Service a8c26c
	{
Packit Service a8c26c
		vpnext = vp->un.next;
Packit Service a8c26c
		if(vp->index&ENV_VMALLOC)
Packit Service a8c26c
		{
Packit Service a8c26c
			vp->un.next = top;
Packit Service a8c26c
			top = vp;
Packit Service a8c26c
		}
Packit Service a8c26c
	}
Packit Service a8c26c
	for(vp=top; vp; vp = vpnext)
Packit Service a8c26c
	{
Packit Service a8c26c
		vpnext = vp->un.next;
Packit Service a8c26c
		free((void*)vp);
Packit Service a8c26c
	}
Packit Service a8c26c
	dtclose(ep->dt);
Packit Service a8c26c
}