[net.sources] Environment mucking routines

david@ukma.UUCP (David Herron, NPR Lover) (09/24/85)

This is for them people in net.lang.c who want to change
environment variables from a C program.

Of course you cannot change your parents' environment with
these routines.  That would be *DIFFICULT*!

	Enjoy!


#! /bin/sh
: This is a shell archive, meaning:
: 1. Remove everything above the '#! /bin/sh' line.
: 2. Save the resulting text in a file.
: 3. Execute the file with /bin/sh '(not csh)' to create the files:
:	'README'
:	'libenv.3l'
:	'Makefile'
:	'getenv.c'
: This archive created: 'Tue Sep 24 16:52:53 1985'
: By:	'David Herron, NPR Lover ()'
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1334 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//'  >'README' <<'SHAR_EOF'
XThis was an exercise I did one afternoon and never touched since.
XBut with the recent discussion in net.lang.c about setting environment
Xvariables I thought I'd clean it up and post it.  (It hasn't been
Xtested in its' new form, hope I didn't break it! :-).
X
XThe routines work on 4.2BSD but should be portable to most systems.
X(I believe system V uses the same format for environment variables).
X
XOn 4.2, the environment variables are stored in a global double dimensioned
Xcharacter array pointed to by "environ".  The format of each entry
Xis "name=value".  All versions of exec() eventually end up calling
Xthe same system call and give the environment as that pointed to
Xby "environ".
X
XFor programs which "know" what environ "looks like", these routines
Xalmost exactly mimic that behavior.  The only way in which it doesn't
Xis the existance of "rstenv()" which makes us revert to our parent's
Xenvironment.  There is a possibility that (if you're adding these
Xroutines to an existing program) that the program could get very
Xconfused if a variable it added itself suddenly "went away".
X
XThe only other time a program could break would be if envp were
Xdeclared as an argument to main and saved/used elsewhere
Xindependantly of environ.
X
X	David Herron
X	University of Kentucky, Computer Science
X	cbosgd!ukma!david
X	ukma!david@anl-mcs.arpa
SHAR_EOF
if test 1334 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1334 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'libenv.3l'" '(1946 characters)'
if test -f 'libenv.3l'
then
	echo shar: will not over-write existing file "'libenv.3l'"
else
sed 's/^X//'  >'libenv.3l' <<'SHAR_EOF'
X.TH LIBENV 3 "University of Kentucky" "4.2BSD"
X.SH NAME
Xlibenv \- routines to muck around with environment variables
X.SH SYNOPSIS
Xchar *getenv(\fIname\fP);
X.br
Xchar *\fIname\fP;
X.br
X.sp 1
Xint setenv(\fIname\fP, \fIvalue\fP);
X.br
Xchar *\fIname\fP, *\fIvalue\fP;
X.br 
X.sp 1
Xvoid rstenv();
X.br
X.sp 1
Xchar *firstenv();
X.br
X.sp 1
Xchar *nextenv();
X.br
X.sp 2
X.SH DESCRIPTION
XThese routines allow one to look at and modify the 
Xcurrent environment variables.
X.PP
X.IP getenv(name) 1.7i
Xlooks in the current environment for the named variable and returns its\' value.
XReturns NULL if it wasn\'t found.
X.IP "setenv(name, value)" 1.7i
Xsets the value for variable \fIname\fP to \fIvalue\fP.
XReturn value is (0==0) when successful and (0==1) when not.
X.IP rstenv() 1.7i
XResets the environment to the original environment 
Xthis process was called with.
X.IP firstenv() 1.7i
X.IP nextenv() 1.7i
Xprovide a method for scanning sequentially through the current environment.
X\fIFirstenv()\fP sets us to be looking at the first variable
X(and also returns a pointer to it);
X\fINextenv()\fP steps to the next one.
X.SH AUTHOR
XDavid Herron
X.br
XUniversity of Kentucky, Computer Science.
X.br
Xcbosgd!ukma!david (soon, david@ukma.{CSNet,BITNET})
X.SH BUGS
XThis version runs with 4.2BSD on a Vax, giving it some built in assumptions.
XFirst is that the environment is pointed to by an
X\fIextern char **environ\fP.
XThe second is that we have a fairly unlimited amount of memory
Xto muck around with.
X.PP
XAt the first call to any of the routines, the first thing done
Xis to save a pointer to the parent\'s environment.
XThen it uses malloc() to allocate an array and copy copy the old
Xenvironment to the new array.
XThere must be enough malloc()-able memory around to do this.
XAll \fIrstenv()\fP has to do (for instance) is free all the
Xstorage then make \fIenviron\fP point to the old environment.
XIf we run out of memory while copying the environment, things
Xwill fail mysteriously.
SHAR_EOF
if test 1946 -ne "`wc -c < 'libenv.3l'`"
then
	echo shar: error transmitting "'libenv.3l'" '(should have been 1946 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(309 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//'  >'Makefile' <<'SHAR_EOF'
X# Makefile for libenv.a
X#
X#
X
XCFLAGS = -DBSD_4_2=BSD_4_2 -O
XSRCS = getenv.c
XOBJS = getenv.o
X
Xlibenv.a: $(OJBS)
X	rm -f libenv.a
X	ar c libenv.a $(OBJS)
X	ranlib libenv.a
X
Xgetenv.o: getenv.c
X	cc $(CFLAGS) -c getenv.c
X
Xclean:
X	rm -f $(OBJS) a.out core
X
Xshar:
X	shar -a README libenv.3l Makefile $(SRCS) >libenv.shar
SHAR_EOF
if test 309 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 309 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getenv.c'" '(4702 characters)'
if test -f 'getenv.c'
then
	echo shar: will not over-write existing file "'getenv.c'"
else
sed 's/^X//'  >'getenv.c' <<'SHAR_EOF'
X#ifndef lint
Xstatic char rcsid[] = "$Header: getenv.c,v 1.6 85/09/24 16:37:23 david Exp $";
X#endif lint
X/*
X * Routines to muck up environment variables.
X * 
X * $Log:	getenv.c,v $
X * Revision 1.6  85/09/24  16:37:23  david
X * Changed setenv() to 1) use that "untested" loop from getenv()
X * to find the variable, and 2) be a little more intelligent about
X * setting the new value into the environment.
X * 
X * Revision 1.5  85/09/24  16:18:37  david
X * Removed traces of Berkeley code for release to net.
X * (Rewrote getenv(), which hasn't been tested yet,
X * but "oughta work").
X * 
X * Revision 1.4  85/09/24  15:44:29  david
X * Fix setenv() to return an int.
X * Fix rstenv() to set nenv to 0 (for consistency).
X * 
X * Revision 1.3  85/05/14  18:33:47  david
X * Put #ifndef BSD_4_2 ... #endif around getenv().  Because it already
X * exists in the 4.2 library.
X * 
X * Revision 1.2  85/05/14  18:27:58  david
X * Added routines:
X * 
X * setenv(name, value) -- sets an environment variable for name to value.
X * rstenv() -- Resets environment to that of parent.
X * firstenv() -- Initializes sequential scan of environment variables.
X * nextenv() -- Gives next variable.
X * 
X * Also, an internal routine init() which saves the parent environment
X * and copies it to malloc()'d memory.
X * 
X * Revision 1.1  85/01/04  22:57:28  root
X * Initial revision
X * 
X *
X */
X
X#define NULL ((char *)0)
X
Xstatic int initd = 0;		/* set to non-zero after we've set
X				 * up environ for children.
X				 */
Xstatic char **p_environ;	/* Holds pointer to original environment.
X				 * We'll be modifying environ to point
X				 * to the new environment.
X				 */
Xstatic int nenv;		/* Number of entries in environ.
X				 * Use this to calculate the size of
X				 * environ.
X				 */
X
X
Xextern	char **environ;
Xchar	*nvmatch();
Xextern char *malloc(), *realloc();
Xextern int free();
Xextern char *strcpy();
X
X
X
X/*
X * init() -- Set up initialized and p_environ.
X */
Xstatic void init()
X{
X	int i;
X
X	p_environ = environ;
X	for (nenv = 0; p_environ[nenv] != (char *)NULL; nenv++)
X			;
X
X	/* Allocate an array of pointers to each environment string */
X	environ = (char **)malloc((unsigned)(nenv * sizeof(char **)));
X
X	/* Copy each string to the new environment */
X	for (i=0; i<nenv; i++) {
X		environ[i] = malloc((unsigned)(strlen(p_environ[i]) + 1));
X		(void) strcpy(environ[i], p_environ[i]);
X	}
X
X	/* trailer value */
X	environ[nenv] = (char *)NULL;
X	nenv++;
X	initd = 1;
X}
X
X
X
X#ifndef BSD_4_2
X/*
X *	getenv(name)
X *	returns ptr to value associated with name, if any, else NULL
X *	A version of this routine is already present in
X *	most standard libraries.  It's here mostly for reference.
X */
Xchar *getenv(name)
Xchar *name;
X{
X	register char *v, *s1, *s2;
X	register int i;
X
X	for (i = 0; environ[i] != NULL; i++) {
X		for (s1=environ[i], s2=name; *s1 == *s2; s1++, s2++) {
X			if (*s2 == '\0' || *s2 == '=')
X				/* Reached the end of "name" */
X				if (*s1 == '=')
X					return(++s1);
X				else
X					break;
X			if (*s1 == '=' || *s1 == '\0')
X				break;
X		}
X	}
X	return(NULL);
X}
X#endif /* BSD_4_2 */
X
X/*
X * setenv(name, value) -- Set new value for name.
X *	Returns: non-zero (TRUE) when out of memory, zero for success.
X *
X * WARNING!
X *	"goto"'s live within this procedure!
X */
Xint setenv(name, value)
Xchar *name, *value;
X{
X	int i;
X	register char *s1, *s2;
X
X	if (initd == 0)
X		init();
X	for (i = 0; environ[i] != NULL; i++) {
X		for (s1=environ[i], s2=name; *s1 == *s2; s1++, s2++) {
X			if (*s2 == '\0' || *s2 == '=')
X				/* Reached the end of "name" */
X				if (*s1 == '=')
X					goto found;
X				else
X					break;
X			if (*s1 == '=' || *s1 == '\0')
X				break;
X		}
X	}
X	/* It wasn't in the environment already.  add it there. */
X	nenv++;
X	environ = (char **)realloc((char *)environ,
X			(unsigned)(nenv * sizeof(char **)));
X	if (environ == (char **)NULL)
X		return(0 == 0);
X	environ[nenv] = (char *)NULL;
X	goto out;
Xfound:
X	(void) free(environ[i]);
X	environ[i] = malloc(strlen(name) + 1 + strlen(value) + 1);
Xout:
X	(void) strcpy(environ[i], name);
X	(void) strcat(environ[i], "=");
X	(void) strcat(environ[i], value);
X	return(0 == 1);
X}
X
X/*
X * rstenv() -- reset environment back to parents environment.
X */
Xvoid rstenv()
X{
X	register int i;
X
X	initd = 0;
X	for (i=0; i<nenv; i++)
X		(void) free(environ[i]);
X	(void) free((char *)environ);
X	environ = p_environ;
X	nenv = 0;
X}
X
X/*
X * firstenv() -- For sequentially scanning environment.  Sets pointer
X * to first environment variable.
X */
Xstatic int curenv;
X
Xchar *firstenv()
X{
X	if (initd == 0)
X		init();
X	curenv = 0;
X	return(environ[curenv]);
X}
X
X/*
X * nextenv() -- look at next environment variable.
X */
Xchar *nextenv()
X{
X	if (initd == 0) {
X		init();
X		curenv = 0;
X		return(environ[0]);
X	}
X	else {
X		return(environ[++curenv]);
X	}
X}
SHAR_EOF
if test 4702 -ne "`wc -c < 'getenv.c'`"
then
	echo shar: error transmitting "'getenv.c'" '(should have been 4702 characters)'
fi
fi # end of overwriting check
:	End of shell archive
exit 0
-- 
--- David Herron
--- ARPA-> ukma!david@ANL-MCS.ARPA
--- UUCP-> {ucbvax,unmvax,boulder,oddjob}!anlams!ukma!david
---        {ihnp4,decvax,ucbvax}!cbosgd!ukma!david

Hackin's in me blood.  My mother was known as Miss Hacker before she married!