Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
environ.cpp
Go to the documentation of this file.
1
29// expand _TEST_EXPORT macros
30#define _RWSTD_TEST_SRC
31
32#include <rw_environ.h>
33
34#include <assert.h> // for assert
35#include <stdlib.h> // for getenv, malloc, putenv
36#include <string.h> // for strchr, strlen, ...
37
38
39extern "C" {
40
41// char** environ;
42
43#ifndef _RWSTD_NO_PUTENV_CONST_CHAR
44
46
47#else // if defined (_RWSTD_NO_PUTENV_CONST_CHAR)
48
50
51#endif // _RWSTD_NO_PUTENV_CONST_CHAR
52
53
54#ifdef _RWSTD_NO_UNSETENV
55# ifndef _RWSTD_NO_UNSETENV_IN_LIBC
56
57_RWSTD_DLLIMPORT int unsetenv (const char*) _LIBC_THROWS ();
58
59# undef _RWSTD_NO_UNSETENV
60
61# endif // _RWSTD_NO_UNSETENV_IN_LIBC
62#endif // _RWSTD_NO_UNSETENV
63
64} // extern "C"
65
66
67// sets (or unsets) one or more sep-separated environment variables
69rw_putenv (const char* str, int sep /* = -1 */)
70{
71 int nset = 0;
72 int ret = 0;
73
74 if (!str) {
75 str = getenv ("RW_PUTENV");
76 if (str)
77 sep = *str++;
78 else
79 return 0;
80 }
81
82 // set separator to NUL if it's invalid
83 if (sep < 0 || int (_RWSTD_UCHAR_MAX) < sep)
84 sep = 0;
85
86 for (const char *pvar = str; pvar && *pvar; ++nset) {
87
88 // look for separator (or the terminating NUL by default)
89 const char *pend = strchr (pvar, sep);
90
91 if (0 == pend)
92 pend = pvar + strlen (pvar);
93
94 const size_t varlen = pend - pvar;
95
96 // reserve the one more character for Windows mode
97 char* const envvar = (char*)malloc (varlen + 2);
98 if (0 == envvar)
99 return -1;
100
101 memcpy (envvar, pvar, varlen);
102 envvar [varlen] = '\0';
103
104 // look for the first equals sign
105 char* const equals = strchr (envvar, '=');
106
107 char *var = 0;
108
109 // putenv mode: 0 - POSIX; 1 - undefined; 2 - Windows
110 static int mode = 1;
111
112 if (equals) {
113 // add the variable to the environment or modify it if
114 // it's already defined
115
116 // Note: calling Solaris 7 putenv() during program startup
117 // (i.e., from ctors of namespace-scope objects) prevents
118 // getenv() from finding that variable at program runtime
119
120 char namebuf [256];
121 const size_t namelen = equals - envvar;
122 assert (namelen < sizeof (namebuf));
123
124 memcpy (namebuf, envvar, namelen);
125 namebuf [namelen] = '\0';
126
127 switch (!equals [1] * mode) {
128 case 0:
129 ret = putenv (envvar);
130 break;
131 case 1:
132 ret = putenv (envvar);
133 if (getenv (namebuf)) {
134 mode = 0;
135 break;
136 }
137 mode = 2;
138 // fall through
139 case 2:
140 // on Windows it's impossible to set empty environment variable
141 // append any character after '='
142 equals [1] = '1';
143 equals [2] = '\0';
144 ret = putenv (envvar);
145 equals [1] = '\0';
146 break;
147 }
148
149 // determine wheteher putenv() made copy of the variable
150 // or if it simply used the pointer passed to it; if the
151 // former, deallocate the buffer dynamically allocated
152 // above
153 var = getenv (namebuf);
154
155 // empty the environment variable directly on Windows
156 if (!equals [1] && 2 == mode)
157 *var = '\0';
158
159 if (equals + 1 != var)
160 free (envvar);
161 }
162 else if ((var = getenv (envvar))) {
163 // try to remove variable from the environment
164
165#ifndef _RWSTD_NO_UNSETENV
166# if defined (_RWSTD_OS_FREEBSD) || defined (_RWSTD_OS_DARWIN)
167 // FreeBSD (and Darwin) declares void unsetenv(const char*)
168 // http://www.freebsd.org/cgi/man.cgi?query=unsetenv&sektion=3
169 unsetenv (envvar);
170 ret = 0;
171# else // !FreeBSD ...
172 ret = unsetenv (envvar);
173# endif // FreeBSD ...
174#else // ifdef _RWSTD_NO_UNSETENV
175 switch (mode) {
176 case 0:
177 ret = putenv (envvar);
178 break;
179 case 1:
180 ret = putenv (envvar);
181 if (!getenv (envvar)) {
182 mode = 0;
183 break;
184 }
185 mode = 2;
186 // fall through
187 case 2:
188 // on Windows append '=' character to remove
189 // the environment variable
190 envvar [varlen] = '=';
191 envvar [varlen + 1] = '\0';
192 ret = putenv (envvar);
193 envvar [varlen] = '\0';
194 break;
195 }
196#endif // _RWSTD_NO_UNSETENV
197
198 if (0 == ret) {
199 // see if the variable has been removed
200 var = getenv (envvar);
201 if (var) {
202 // if not, zero-out the first byte of its name
203 // FIXME: make this more robust, e.g., by calling
204 // unsetenv() when provided or by manipulating
205 // the environment directly
206 *(var - 1 - varlen) = '\0';
207
208#if 0 // disabled
209
210 char **penv = environ;
211 if (penv) {
212 while (*penv && *penv != (var - 1 - varlen))
213 ++penv;
214
215 while (*penv)
216 *penv = penv [1];
217 }
218
219#endif // 0/1
220
221 }
222 }
223
224 free (envvar);
225 }
226
227 pvar = pend + !!*pend;
228 }
229
230 if (1 == nset)
231 return ret;
232
233 return nset;
234}
#define var
Definition 17.names.cpp:573
#define pend
Definition 17.names.cpp:523
#define mode
Definition 17.names.cpp:497
#define assert(expr)
Definition _cassert.h:40
#define _RWSTD_DLLIMPORT
Definition _config.h:391
#define _LIBC_THROWS()
Definition _defs.h:1152
_TEST_EXPORT int rw_putenv(const char *str, int sep)
Definition environ.cpp:69
_RWSTD_DLLIMPORT int putenv(const char *) _LIBC_THROWS()
const char * str
Definition exec.cpp:170
#define _TEST_EXPORT
Definition rw_testdefs.h:55