VirtualBox

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

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

Solaris

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