VirtualBox

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

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

Runtime: Fixed linux builds.

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