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