stephen@dcl-cs.UUCP (Stephen J. Muir) (10/23/85)
----------------------------------- Cut Here ---------------------------------- #!/bin/sh echo 'Start of pack.out, part 01 of 01:' echo 'x - setenv.3' sed 's/^X//' > setenv.3 << '/' X.TH SETENV 3 "22 October 1985" X.SH NAME Xsetenv, delenv \- add/change/delete environment variables X.SH SYNOPSIS X.nf X.B setenv (name, value) X.B char *name, *value; X X.B delenv (name) X.B char *name; X.fi X.SH DESCRIPTION X.I Setenv Xallows a program to set environment variables. X.I Delenv Xallows a program to delete them. XThese routines follow on logically from X.IR getenv (3). X.SH EXAMPLES X.nf Xsetenv ("EDITOR", "/usr/ucb/ex"); Xdelenv ("EDITOR"); X.fi X.SH NOTES XThe third argument to routine X.B main Xstill points to the original environment after execution of these routines. XThe flag X.I \-lsjm Xneeds to be given to X.IR cc (1) Xor X.IR ld (1). X.SH "RETURN VALUES" X.I Setenv Xand X.I delenv Xboth return 0 on success and -1 if enough memory couldn't be allocated. X.I Delenv Xcan also return 1 meaning that the X.B name Xwasn't found in the current environment. XThe first call to X.I setenv Xor X.I delenv Xinitialises both routines. XAfter that, X.I delenv Xcannot return -1. X.SH "SEE ALSO" Xgetenv (3), execve (2) X.SH AUTHOR XStephen J. Muir, Lancaster University. / echo 'x - setenv.c' sed 's/^X//' > setenv.c << '/' X/* Written by Stephen J. Muir, Computing Dept., Lancaster University */ X X# include <strings.h> X X/* This is the number of extra array elements to allocate each time it becomes X * necessary. X */ X# define INC 10 X Xextern char **environ, *malloc (); Xextern int free (); X Xstatic char **original, **current, **limit; X X/* This routine should be called only once (when either "setenv" or "delenv" is X * called for the first time). It would only be called again if it fails due X * to lack of memory. It makes a copy of the original environment because the X * original environment array and its elements were not obtained from "malloc" X * and the "free" routine cannot, therefore, be called with any of its X * elements. X * X * return values: X * 0: success X * -1: out of memory - nothing has changed X */ Xstatic /* this is a private routine */ Xinitialise () X { register char **old, **new_ptr, *tmp, **new_env; X X /* count number of existing strings */ X for (old = environ; *old; ++old) X ; X X /* make space for extra strings */ X if ((new_ptr = X new_env = X (char **)malloc (sizeof (char **) * ((old - environ) + INC + 1)) X ) X == 0 X ) X return (-1); X X /* "limit" points to the last element of the array -- it is used to X * decide when to recreate it X */ X limit = new_env + (old - environ) + INC; X X /* copy across old strings */ X for (old = environ; *old; ++old) X { if ((tmp = malloc (strlen (*old) + 1)) == 0) X { /* out of memory -- undo everything */ X while (new_ptr != new_env) X free (*--new_ptr); X free ((char *)new_ptr); X return (-1); X } X strcpy (tmp, *old); X *new_ptr++ = tmp; X } X /* "current" points to the null pointer at the end of the array */ X *(current = new_ptr) = 0; X X /* this is really just a flag to say it's initialised */ X original = environ; X /* overwrite old environment with new */ X environ = new_env; X return (0); X } X X/* This is a special routine to compare a string "name" of the form "NAME" with X * a string "name_value" of the form "NAME=VALUE". It returns zero if the X * comparison is successful X */ Xstatic /* this is a private routine */ Xdiffer (name, name_value) X char *name, *name_value; X { while (*name && *name_value) X if (*name++ != *name_value++) X return (1); X return (*name_value != '='); X } X X/* This routine deletes an environment variable, e.g. delenv ("SHELL"); X * X * return values: X * 0: success X * 1: environment variable not found X * -1: out of memory - nothing has changed X */ Xdelenv (name) X char *name; X { register char **ptr; X X /* initialise if necessary */ X if (original == 0 && initialise ()) X return (-1); X X /* attempt to find it */ X for (ptr = environ; *ptr && differ (name, *ptr); ++ptr) X ; X if (*ptr == 0) X return (1); /* not found */ X X /* delete it */ X free (*ptr); X *ptr = *--current; X *current = 0; X return (0); X } X X/* This routine sets a new environment variable, replacing an existing one X * where appropriate, e.g. setenv ("SHELL", "/bin/csh"); X * X * return values: X * 0: success X * -1: out of memory - nothing has changed X */ Xsetenv (name, value) X char *name, *value; X { register char **old, **new_ptr, *cp, *tmp, **new_env; X X /* initialise if necessary */ X if (original == 0 && initialise ()) X return (-1); X X /* allocate space for the new string */ X if ((cp = tmp = malloc (strlen (name) + strlen (value) + 2)) == 0) X return (-1); X X /* find an existing one if we can - we do this now as we will lose X * the original "name" pointer in the while loop following X */ X for (old = environ; *old && differ (name, *old); ++old) X ; X X /* make the new entry */ X while (*name) X *cp++ = *name++; X *cp++ = '='; X while (*value) X *cp++ = *value++; X *cp = '\0'; X X /* case 1: overwrite previous value */ X if (*old) X { free (*old); X *old = tmp; X } X X /* case 2: no previous value and no space left - allocate more */ X else if (current == limit) X { if ((new_ptr = X new_env = X (char **)malloc (sizeof (char **) * X ((old - environ) + INC + 1) X ) X ) == 0 X ) X { free (tmp); X return (-1); X } X limit = new_env + (old - environ) + INC; X for (old = environ; *old; ) X *new_ptr++ = *old++; X *new_ptr++ = tmp; X *(current = new_ptr) = 0; X free ((char *)environ); X environ = new_env; X } X X /* case 3: no previous value and there is enough space */ X else X { *current++ = tmp; X *current = 0; X } X return (0); X } / echo 'Part 01 of pack.out complete.' exit -- UUCP: ...!seismo!mcvax!ukc!dcl-cs!stephen DARPA: stephen%lancs.comp@ucl-cs | Post: University of Lancaster, JANET: stephen@uk.ac.lancs.comp | Department of Computing, Phone: +44 524 65201 Ext. 4599 | Bailrigg, Lancaster, UK. Project:Alvey ECLIPSE Distribution | LA1 4YR