VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/env-generic.cpp@ 4101

Last change on this file since 4101 was 4101, checked in by vboxsync, 18 years ago

Attempt to fix the burning L4 testbox by making Dmitry's environment variable code in the runtime into dummy code on L4

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 9.1 KB
Line 
1/* $Id: env-generic.cpp 4101 2007-08-09 17:26:04Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Environment, Generic.
4 */
5
6/*
7 * Copyright (C) 2007 innotek GmbH
8 *
9 * innotek GmbH confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include <iprt/env.h>
18#include <iprt/assert.h>
19#include <iprt/alloc.h>
20#include <iprt/string.h>
21#include <iprt/err.h>
22
23#if defined(RT_OS_WINDOWS)
24# include <stdlib.h>
25#else
26# include <unistd.h>
27#endif
28
29#include <string.h>
30
31struct RTENVINTERNAL
32{
33 /* Array of environment variables. */
34 char **apszEnv;
35 /* Count of variables in the array. */
36 size_t cCount;
37 /* Capacity (real size) of the array. This includes space for the
38 * terminating NULL element (for compatibility with the C library), so
39 * that cCount <= cCapacity - 1. */
40 size_t cCapacity;
41};
42
43#define RTENV_GROW_SIZE 16
44
45static int rtEnvCreate(struct RTENVINTERNAL **ppIntEnv, size_t cCapacity)
46{
47 int rc;
48
49 /*
50 * Allocate environment handle.
51 */
52 struct RTENVINTERNAL *pIntEnv = (struct RTENVINTERNAL *)RTMemAlloc(sizeof(struct RTENVINTERNAL));
53 if (pIntEnv)
54 {
55 cCapacity = (cCapacity + RTENV_GROW_SIZE - 1)
56 / RTENV_GROW_SIZE * RTENV_GROW_SIZE;
57 /*
58 * Pre-allocate the variable array.
59 */
60 pIntEnv->cCount = 0;
61 pIntEnv->cCapacity = cCapacity;
62 pIntEnv->apszEnv = (char **)RTMemAlloc(sizeof(pIntEnv->apszEnv[0]) * pIntEnv->cCapacity);
63 if (pIntEnv->apszEnv)
64 {
65 /* add terminating NULL */
66 pIntEnv->apszEnv[0] = NULL;
67 *ppIntEnv = pIntEnv;
68 return VINF_SUCCESS;
69 }
70
71 rc = VERR_NO_MEMORY;
72 RTMemFree(pIntEnv);
73 }
74 else
75 rc = VERR_NO_MEMORY;
76
77 return rc;
78}
79
80/**
81 * Creates an empty environment block.
82 *
83 * @returns IPRT status code. Typical error is VERR_NO_MEMORY.
84 *
85 * @param pEnv Where to store the handle of the environment block.
86 */
87RTDECL(int) RTEnvCreate(PRTENV pEnv)
88{
89 if (pEnv == NULL)
90 return VERR_INVALID_POINTER;
91
92 return rtEnvCreate(pEnv, RTENV_GROW_SIZE);
93}
94
95/**
96 * Destroys an environment block.
97 *
98 * @returns IPRT status code.
99 *
100 * @param Env Handle of the environment block.
101 */
102RTDECL(int) RTEnvDestroy(RTENV Env)
103{
104 struct RTENVINTERNAL *pIntEnv = Env;
105
106 if (pIntEnv == NULL)
107 return VERR_INVALID_HANDLE;
108
109 for (size_t i = 0; i < pIntEnv->cCount; ++i)
110 {
111 RTStrFree(pIntEnv->apszEnv[i]);
112 }
113
114 RTMemFree(pIntEnv->apszEnv);
115 RTMemFree(pIntEnv);
116 return VINF_SUCCESS;
117}
118
119/**
120 * Creates an environment block and fill it with variables from the given
121 * environment array.
122 *
123 * @returns IPRT status code. Typical error is VERR_NO_MEMORY.
124 *
125 * @param pEnv Where to store the handle of the environment block.
126 * @param apszEnv Pointer to the NULL-terminated array of environment
127 * variables. If NULL, the current process' environment
128 * will be cloned.
129 */
130RTDECL(int) RTEnvClone(PRTENV pEnv, char const *const *apszEnv)
131{
132#ifndef RT_OS_L4 /* So far, our L4 libraries do not include environment support. */
133 if (apszEnv == NULL)
134 apszEnv = environ;
135
136 /* count the number of varialbes to clone */
137 size_t cEnv = 0;
138 for (; apszEnv[cEnv]; ++cEnv) {}
139#else
140 size_t cEnv = 0;
141#endif
142
143 struct RTENVINTERNAL *pIntEnv;
144
145 int rc = rtEnvCreate(&pIntEnv, cEnv);
146 if (RT_FAILURE(rc))
147 return rc;
148
149#ifndef RT_OS_L4
150 for (size_t i = 0; i < cEnv; ++i)
151 {
152 char *pszVar = RTStrDup(environ[i]);
153 if (pszVar == NULL)
154 {
155 rc = VERR_NO_MEMORY;
156 break;
157 }
158
159 pIntEnv->apszEnv[i] = pszVar;
160 ++pIntEnv->cCount;
161 }
162#endif
163
164 if (RT_SUCCESS(rc))
165 {
166 /* add terminating NULL */
167 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
168 *pEnv = pIntEnv;
169 return VINF_SUCCESS;
170 }
171
172 RTEnvDestroy(pIntEnv);
173 return rc;
174}
175
176static int rtEnvRemoveVars(struct RTENVINTERNAL *pIntEnv, size_t iFrom, size_t cVars)
177{
178 AssertReturn (iFrom < pIntEnv->cCount, VERR_GENERAL_FAILURE);
179 AssertReturn (cVars <= pIntEnv->cCount, VERR_GENERAL_FAILURE);
180 AssertReturn (cVars > 0, VERR_GENERAL_FAILURE);
181
182 /* free variables */
183 size_t iTo = iFrom + cVars - 1;
184 for (size_t i = iFrom; i <= iTo; ++i)
185 RTStrFree(pIntEnv->apszEnv[i]);
186
187 /* remove the hole */
188 size_t cToMove = pIntEnv->cCount - iTo - 1;
189 if (cToMove)
190 memcpy(&pIntEnv->apszEnv[iFrom], &pIntEnv->apszEnv[iTo + 1],
191 sizeof(pIntEnv->apszEnv[0]) * cToMove);
192
193 pIntEnv->cCount -= cVars;
194
195 /// @todo resize pIntEnv->apszEnv to a multiply of RTENV_GROW_SIZE to keep
196 /// it compact
197
198 /* add terminating NULL */
199 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
200 return VINF_SUCCESS;
201}
202
203static int rtEnvInsertVars(struct RTENVINTERNAL *pIntEnv, size_t iAt, size_t cVars)
204{
205 AssertReturn (iAt <= pIntEnv->cCount, VERR_GENERAL_FAILURE);
206
207 int rc;
208
209 size_t cCapacity = (pIntEnv->cCount + cVars + RTENV_GROW_SIZE - 1)
210 / RTENV_GROW_SIZE * RTENV_GROW_SIZE;
211 bool needAlloc = cCapacity != pIntEnv->cCapacity;
212
213 /* allocate a new variable array if needed */
214 char **apszEnv = needAlloc ? (char **)RTMemAlloc(sizeof(apszEnv[0]) * cCapacity)
215 : pIntEnv->apszEnv;
216 if (apszEnv)
217 {
218 /* copy old variables */
219 if (needAlloc && iAt)
220 memcpy (apszEnv, pIntEnv->apszEnv, sizeof(apszEnv[0]) * iAt);
221 if (iAt < pIntEnv->cCount)
222 memcpy (&apszEnv[iAt + cVars], &pIntEnv->apszEnv[iAt],
223 sizeof(apszEnv[0]) * pIntEnv->cCount - iAt);
224 /* initialize new variables with NULL */
225 memset(&apszEnv[iAt], 0, sizeof(apszEnv[0]) * cVars);
226 /* replace the array */
227 if (needAlloc)
228 {
229 RTMemFree(pIntEnv->apszEnv);
230 pIntEnv->apszEnv = apszEnv;
231 pIntEnv->cCapacity = cCapacity;
232 }
233 pIntEnv->cCount += cVars;
234 /* add terminating NULL */
235 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
236 return VINF_SUCCESS;
237 }
238 else
239 rc = VERR_NO_MEMORY;
240
241 return rc;
242}
243
244static int rtEnvSetEx(struct RTENVINTERNAL *pIntEnv,
245 const char *pszVar, size_t cchVar,
246 const char *pszValue)
247{
248 AssertReturn (pszVar != NULL, VERR_GENERAL_FAILURE);
249
250 size_t i = 0;
251 for (; i < pIntEnv->cCount; ++i)
252 {
253 if ((cchVar == 0 && !*pszVar) ||
254 strncmp(pIntEnv->apszEnv[i], pszVar, cchVar) == 0)
255 {
256 if (pszValue == NULL)
257 return rtEnvRemoveVars(pIntEnv, i, 1);
258
259 break;
260 }
261 }
262
263 /* allocate a new variable */
264 size_t cchNew = cchVar + 1 + strlen(pszValue) + 1;
265 char *pszNew = (char *)RTMemAlloc(cchNew);
266 if (pszNew == NULL)
267 return VERR_NO_MEMORY;
268 memcpy(pszNew, pszVar, cchVar);
269 pszNew[cchVar] = '=';
270 strcpy(pszNew + cchVar + 1, pszValue);
271
272 if (i < pIntEnv->cCount)
273 {
274 /* replace the old variable */
275 RTStrFree(pIntEnv->apszEnv[i]);
276 pIntEnv->apszEnv[i] = pszNew;
277 return VINF_SUCCESS;
278 }
279
280 /* nothing to do to remove a non-existent variable */
281 if (pszValue == NULL)
282 return VINF_SUCCESS;
283
284 /* insert the new variable */
285 int rc = rtEnvInsertVars(pIntEnv, i, 1);
286 if (RT_SUCCESS(rc))
287 {
288 pIntEnv->apszEnv[i] = pszNew;
289 return VINF_SUCCESS;
290 }
291
292 RTStrFree(pszNew);
293 return rc;
294}
295
296/**
297 * Puts a 'variable=value' string into the environment.
298 *
299 * The supplied string must be in the current process' codepage.
300 * This function makes a copy of the supplied string.
301 *
302 * @returns IPRT status code. Typical error is VERR_NO_MEMORY.
303 *
304 * @param Env Handle of the environment block.
305 * @param pszVarEqualValue The variable '=' value string. If the value and '=' is
306 * omitted, the variable is removed from the environment.
307 */
308RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
309{
310 struct RTENVINTERNAL *pIntEnv = Env;
311
312 if (pIntEnv == NULL)
313 return VERR_INVALID_HANDLE;
314
315 if (pszVarEqualValue == NULL)
316 return VERR_INVALID_POINTER;
317
318 const char *pszEq = strchr(pszVarEqualValue, '=');
319 return rtEnvSetEx(pIntEnv, pszVarEqualValue,
320 pszEq ? pszEq - pszVarEqualValue
321 : strlen (pszVarEqualValue),
322 pszEq ? pszEq + 1 : NULL);
323}
324
325/**
326 * Returns a raw pointer to the array of environment variables of the given
327 * environment block where every variable is a string in format
328 * 'variable=value'.
329 *
330 * All returned strings are in the current process' codepage.
331 *
332 * @returns Pointer to the raw array of environment variables.
333 * @returns NULL if Env is NULL or invalid.
334 *
335 * @param Env Handle of the environment block.
336 */
337RTDECL(char const *const *) RTEnvGetArray(RTENV Env)
338{
339 struct RTENVINTERNAL *pIntEnv = Env;
340
341 if (pIntEnv == NULL)
342 return NULL;
343
344 return pIntEnv->apszEnv;
345}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette