summaryrefslogtreecommitdiffstats
path: root/src/util/environ.c
blob: 4b6c59e30881082315c797823685f3e6b44014b0 (plain)
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
 /*
  * From: TCP Wrapper.
  * 
  * 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.
  */
#include "sys_defs.h"

#ifdef MISSING_SETENV_PUTENV

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

extern char **environ;

static int addenv(char *);		/* 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 ssize_t namelength(const char *name)
{
    char   *equal;

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

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

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

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

#if 0

/* getenv - given name, locate value */

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

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

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

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

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

/* unsetenv - remove variable from environment */

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

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

#endif

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

int     setenv(const char *name, const char *value, int clobber)
{
    char   *destination;
    char  **envp;
    ssize_t l_name;			/* length of name part */
    unsigned 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(ssize_t new_len, char *old, ssize_t old_len)
{
    char   *new = malloc(new_len);

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

/* addenv - append environment entry */

static int addenv(char *nameval)
{
    char  **envp;
    ssize_t n_used;			/* number of environment entries */
    ssize_t l_used;			/* bytes used excl. terminator */
    ssize_t 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);
    }
}

#endif