Postfix3.3.1
environ.c
[詳解]
1  /*
2  * From: TCP Wrapper.
3  *
4  * Many systems have putenv() but no setenv(). Other systems have setenv() but
5  * no putenv() (MIPS). Still other systems have neither (NeXT). This is a
6  * re-implementation that hopefully ends all problems.
7  *
8  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
9  */
10 #include "sys_defs.h"
11 
12 #ifdef MISSING_SETENV_PUTENV
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 
18 extern char **environ;
19 
20 static int addenv(char *); /* append entry to environment */
21 static int allocated = 0; /* environ is, or is not, allocated */
22 
23 #define DO_CLOBBER 1
24 
25 /* namelength - determine length of name in "name=whatever" */
26 
27 static ssize_t namelength(const char *name)
28 {
29  char *equal;
30 
31  equal = strchr(name, '=');
32  return ((equal == 0) ? strlen(name) : (equal - name));
33 }
34 
35 /* findenv - given name, locate name=value */
36 
37 static char **findenv(const char *name, ssize_t len)
38 {
39  char **envp;
40 
41  for (envp = environ; envp && *envp; envp++)
42  if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
43  return (envp);
44  return (0);
45 }
46 
47 #if 0
48 
49 /* getenv - given name, locate value */
50 
51 char *getenv(const char *name)
52 {
53  ssize_t len = namelength(name);
54  char **envp = findenv(name, len);
55 
56  return (envp ? *envp + len + 1 : 0);
57 }
58 
59 /* putenv - update or append environment (name,value) pair */
60 
61 int putenv(const char *nameval)
62 {
63  char *equal = strchr(nameval, '=');
64  char *value = (equal ? equal : "");
65 
66  return (setenv(nameval, value, DO_CLOBBER));
67 }
68 
69 /* unsetenv - remove variable from environment */
70 
71 void unsetenv(const char *name)
72 {
73  char **envp;
74 
75  while ((envp = findenv(name, namelength(name))) != 0)
76  while (envp[0] = envp[1])
77  envp++;
78 }
79 
80 #endif
81 
82 /* setenv - update or append environment (name,value) pair */
83 
84 int setenv(const char *name, const char *value, int clobber)
85 {
86  char *destination;
87  char **envp;
88  ssize_t l_name; /* length of name part */
89  unsigned int l_nameval; /* length of name=value */
90 
91  /* Permit name= and =value. */
92 
93  l_name = namelength(name);
94  envp = findenv(name, l_name);
95  if (envp != 0 && clobber == 0)
96  return (0);
97  if (*value == '=')
98  value++;
99  l_nameval = l_name + strlen(value) + 1;
100 
101  /*
102  * Use available memory if the old value is long enough. Never free an
103  * old name=value entry because it may not be allocated.
104  */
105 
106  destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
107  *envp : malloc(l_nameval + 1);
108  if (destination == 0)
109  return (-1);
110  strncpy(destination, name, l_name);
111  destination[l_name] = '=';
112  strcpy(destination + l_name + 1, value);
113  return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
114 }
115 
116 /* cmalloc - malloc and copy block of memory */
117 
118 static char *cmalloc(ssize_t new_len, char *old, ssize_t old_len)
119 {
120  char *new = malloc(new_len);
121 
122  if (new != 0)
123  memcpy(new, old, old_len);
124  return (new);
125 }
126 
127 /* addenv - append environment entry */
128 
129 static int addenv(char *nameval)
130 {
131  char **envp;
132  ssize_t n_used; /* number of environment entries */
133  ssize_t l_used; /* bytes used excl. terminator */
134  ssize_t l_need; /* bytes needed incl. terminator */
135 
136  for (envp = environ; envp && *envp; envp++)
137  /* void */ ;
138  n_used = envp - environ;
139  l_used = n_used * sizeof(*envp);
140  l_need = l_used + 2 * sizeof(*envp);
141 
142  envp = allocated ?
143  (char **) realloc((char *) environ, l_need) :
144  (char **) cmalloc(l_need, (char *) environ, l_used);
145  if (envp == 0) {
146  return (-1);
147  } else {
148  allocated = 1;
149  environ = envp;
150  environ[n_used++] = nameval; /* add new entry */
151  environ[n_used] = 0; /* terminate list */
152  return (0);
153  }
154 }
155 
156 #endif