environ.c 4.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
/*
 * Many systems have putenv() but no setenv(). Other systems have setenv()
 * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
 * re-implementation that hopefully ends all problems.
 *
 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
 */

#ifndef lint
static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
#endif

/* System libraries. */

extern char **environ;
extern char *strchr();
extern char *strcpy();
extern char *strncpy();
extern char *malloc();
extern char *realloc();
extern int strncmp();
extern void free();

#ifdef no_memcpy
#define memcpy(d,s,l) bcopy(s,d,l)
#else
extern char *memcpy();
#endif

/* Local stuff. */

static int addenv();			/* append entry to environment */

static int allocated = 0;		/* environ is, or is not, allocated */

#define DO_CLOBBER	1

/* namelength - determine length of name in "name=whatever" */

static int namelength(name)
char   *name;
{
    char   *equal;

    equal = strchr(name, '=');
    return ((equal == 0) ? strlen(name) : (equal - name));
}

/* findenv - given name, locate name=value */

static char **findenv(name, len)
char   *name;
int     len;
{
    char  **envp;

    for (envp = environ; envp && *envp; envp++)
	if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
	    return (envp);
    return (0);
}

/* getenv - given name, locate value */

char   *getenv(name)
char   *name;
{
    int     len = namelength(name);
    char  **envp = findenv(name, len);

    return (envp ? *envp + len + 1 : 0);
}

/* putenv - update or append environment (name,value) pair */

int     putenv(nameval)
char   *nameval;
{
    char   *equal = strchr(nameval, '=');
    char   *value = (equal ? equal : "");

    return (setenv(nameval, value, DO_CLOBBER));
}

/* unsetenv - remove variable from environment */

void    unsetenv(name)
char   *name;
{
    char  **envp;

    if ((envp = findenv(name, namelength(name))) != 0)
	while (envp[0] = envp[1])
	    envp++;
}

/* setenv - update or append environment (name,value) pair */

int     setenv(name, value, clobber)
char   *name;
char   *value;
int     clobber;
{
    char   *destination;
    char  **envp;
    int     l_name;			/* length of name part */
    int     l_nameval;			/* length of name=value */

    /* Permit name= and =value. */

    l_name = namelength(name);
    envp = findenv(name, l_name);
    if (envp != 0 && clobber == 0)
	return (0);
    if (*value == '=')
	value++;
    l_nameval = l_name + strlen(value) + 1;

    /*
     * Use available memory if the old value is long enough. Never free an
     * old name=value entry because it may not be allocated.
     */

    destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
	*envp : malloc(l_nameval + 1);
    if (destination == 0)
	return (-1);
    strncpy(destination, name, l_name);
    destination[l_name] = '=';
    strcpy(destination + l_name + 1, value);
    return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
}

/* cmalloc - malloc and copy block of memory */

static char *cmalloc(new_len, old, old_len)
char   *old;
int     old_len;
{
    char   *new = malloc(new_len);

    if (new != 0)
	memcpy(new, old, old_len);
    return (new);
}

/* addenv - append environment entry */

static int addenv(nameval)
char   *nameval;
{
    char  **envp;
    int     n_used;			/* number of environment entries */
    int     l_used;			/* bytes used excl. terminator */
    int     l_need;			/* bytes needed incl. terminator */

    for (envp = environ; envp && *envp; envp++)
	 /* void */ ;
    n_used = envp - environ;
    l_used = n_used * sizeof(*envp);
    l_need = l_used + 2 * sizeof(*envp);

    envp = allocated ?
	(char **) realloc((char *) environ, l_need) :
	(char **) cmalloc(l_need, (char *) environ, l_used);
    if (envp == 0) {
	return (-1);
    } else {
	allocated = 1;
	environ = envp;
	environ[n_used++] = nameval;		/* add new entry */
	environ[n_used] = 0;			/* terminate list */
	return (0);
    }
}

#ifdef TEST

 /*
  * Stand-alone program for test purposes.
  */

/* printenv - display environment */

static void printenv()
{
    char  **envp;

    for (envp = environ; envp && *envp; envp++)
	printf("%s\n", *envp);
}

int     main(argc, argv)
int     argc;
char  **argv;
{
    char   *cp;
    int     changed = 0;

    if (argc < 2) {
	printf("usage: %s name[=value]...\n", argv[0]);
	return (1);
    }
    while (--argc && *++argv) {
	if (argv[0][0] == '-') {		/* unsetenv() test */
	    unsetenv(argv[0] + 1);
	    changed = 1;
	} else if (strchr(argv[0], '=') == 0) {	/* getenv() test */
	    cp = getenv(argv[0]);
	    printf("%s: %s\n", argv[0], cp ? cp : "not found");
	} else {				/* putenv() test */
	    if (putenv(argv[0])) {
		perror("putenv");
		return (1);
	    }
	    changed = 1;
	}
    }
    if (changed)
	printenv();
    return (0);
}

#endif /* TEST */