VirtualBox

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

Last change on this file since 4071 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 9.0 KB
Line 
1/* $Id: env-generic.cpp 4071 2007-08-07 17:07:59Z 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 if (apszEnv == NULL)
133 apszEnv = environ;
134
135 /* count the number of varialbes to clone */
136 size_t cEnv = 0;
137 for (; apszEnv[cEnv]; ++cEnv) {}
138
139 struct RTENVINTERNAL *pIntEnv;
140
141 int rc = rtEnvCreate(&pIntEnv, cEnv);
142 if (RT_FAILURE(rc))
143 return rc;
144
145 for (size_t i = 0; i < cEnv; ++i)
146 {
147 char *pszVar = RTStrDup(environ[i]);
148 if (pszVar == NULL)
149 {
150 rc = VERR_NO_MEMORY;
151 break;
152 }
153
154 pIntEnv->apszEnv[i] = pszVar;
155 ++pIntEnv->cCount;
156 }
157
158 if (RT_SUCCESS(rc))
159 {
160 /* add terminating NULL */
161 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
162 *pEnv = pIntEnv;
163 return VINF_SUCCESS;
164 }
165
166 RTEnvDestroy(pIntEnv);
167 return rc;
168}
169
170static int rtEnvRemoveVars(struct RTENVINTERNAL *pIntEnv, size_t iFrom, size_t cVars)
171{
172 AssertReturn (iFrom < pIntEnv->cCount, VERR_GENERAL_FAILURE);
173 AssertReturn (cVars <= pIntEnv->cCount, VERR_GENERAL_FAILURE);
174 AssertReturn (cVars > 0, VERR_GENERAL_FAILURE);
175
176 /* free variables */
177 size_t iTo = iFrom + cVars - 1;
178 for (size_t i = iFrom; i <= iTo; ++i)
179 RTStrFree(pIntEnv->apszEnv[i]);
180
181 /* remove the hole */
182 size_t cToMove = pIntEnv->cCount - iTo - 1;
183 if (cToMove)
184 memcpy(&pIntEnv->apszEnv[iFrom], &pIntEnv->apszEnv[iTo + 1],
185 sizeof(pIntEnv->apszEnv[0]) * cToMove);
186
187 pIntEnv->cCount -= cVars;
188
189 /// @todo resize pIntEnv->apszEnv to a multiply of RTENV_GROW_SIZE to keep
190 /// it compact
191
192 /* add terminating NULL */
193 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
194 return VINF_SUCCESS;
195}
196
197static int rtEnvInsertVars(struct RTENVINTERNAL *pIntEnv, size_t iAt, size_t cVars)
198{
199 AssertReturn (iAt <= pIntEnv->cCount, VERR_GENERAL_FAILURE);
200
201 int rc;
202
203 size_t cCapacity = (pIntEnv->cCount + cVars + RTENV_GROW_SIZE - 1)
204 / RTENV_GROW_SIZE * RTENV_GROW_SIZE;
205 bool needAlloc = cCapacity != pIntEnv->cCapacity;
206
207 /* allocate a new variable array if needed */
208 char **apszEnv = needAlloc ? (char **)RTMemAlloc(sizeof(apszEnv[0]) * cCapacity)
209 : pIntEnv->apszEnv;
210 if (apszEnv)
211 {
212 /* copy old variables */
213 if (needAlloc && iAt)
214 memcpy (apszEnv, pIntEnv->apszEnv, sizeof(apszEnv[0]) * iAt);
215 if (iAt < pIntEnv->cCount)
216 memcpy (&apszEnv[iAt + cVars], &pIntEnv->apszEnv[iAt],
217 sizeof(apszEnv[0]) * pIntEnv->cCount - iAt);
218 /* initialize new variables with NULL */
219 memset(&apszEnv[iAt], 0, sizeof(apszEnv[0]) * cVars);
220 /* replace the array */
221 if (needAlloc)
222 {
223 RTMemFree(pIntEnv->apszEnv);
224 pIntEnv->apszEnv = apszEnv;
225 pIntEnv->cCapacity = cCapacity;
226 }
227 pIntEnv->cCount += cVars;
228 /* add terminating NULL */
229 pIntEnv->apszEnv[pIntEnv->cCount] = NULL;
230 return VINF_SUCCESS;
231 }
232 else
233 rc = VERR_NO_MEMORY;
234
235 return rc;
236}
237
238static int rtEnvSetEx(struct RTENVINTERNAL *pIntEnv,
239 const char *pszVar, size_t cchVar,
240 const char *pszValue)
241{
242 AssertReturn (pszVar != NULL, VERR_GENERAL_FAILURE);
243
244 size_t i = 0;
245 for (; i < pIntEnv->cCount; ++i)
246 {
247 if ((cchVar == 0 && !*pszVar) ||
248 strncmp(pIntEnv->apszEnv[i], pszVar, cchVar) == 0)
249 {
250 if (pszValue == NULL)
251 return rtEnvRemoveVars(pIntEnv, i, 1);
252
253 break;
254 }
255 }
256
257 /* allocate a new variable */
258 size_t cchNew = cchVar + 1 + strlen(pszValue) + 1;
259 char *pszNew = (char *)RTMemAlloc(cchNew);
260 if (pszNew == NULL)
261 return VERR_NO_MEMORY;
262 memcpy(pszNew, pszVar, cchVar);
263 pszNew[cchVar] = '=';
264 strcpy(pszNew + cchVar + 1, pszValue);
265
266 if (i < pIntEnv->cCount)
267 {
268 /* replace the old variable */
269 RTStrFree(pIntEnv->apszEnv[i]);
270 pIntEnv->apszEnv[i] = pszNew;
271 return VINF_SUCCESS;
272 }
273
274 /* nothing to do to remove a non-existent variable */
275 if (pszValue == NULL)
276 return VINF_SUCCESS;
277
278 /* insert the new variable */
279 int rc = rtEnvInsertVars(pIntEnv, i, 1);
280 if (RT_SUCCESS(rc))
281 {
282 pIntEnv->apszEnv[i] = pszNew;
283 return VINF_SUCCESS;
284 }
285
286 RTStrFree(pszNew);
287 return rc;
288}
289
290/**
291 * Puts a 'variable=value' string into the environment.
292 *
293 * The supplied string must be in the current process' codepage.
294 * This function makes a copy of the supplied string.
295 *
296 * @returns IPRT status code. Typical error is VERR_NO_MEMORY.
297 *
298 * @param Env Handle of the environment block.
299 * @param pszVarEqualValue The variable '=' value string. If the value and '=' is
300 * omitted, the variable is removed from the environment.
301 */
302RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
303{
304 struct RTENVINTERNAL *pIntEnv = Env;
305
306 if (pIntEnv == NULL)
307 return VERR_INVALID_HANDLE;
308
309 if (pszVarEqualValue == NULL)
310 return VERR_INVALID_POINTER;
311
312 const char *pszEq = strchr(pszVarEqualValue, '=');
313 return rtEnvSetEx(pIntEnv, pszVarEqualValue,
314 pszEq ? pszEq - pszVarEqualValue
315 : strlen (pszVarEqualValue),
316 pszEq ? pszEq + 1 : NULL);
317}
318
319/**
320 * Returns a raw pointer to the array of environment variables of the given
321 * environment block where every variable is a string in format
322 * 'variable=value'.
323 *
324 * All returned strings are in the current process' codepage.
325 *
326 * @returns Pointer to the raw array of environment variables.
327 * @returns NULL if Env is NULL or invalid.
328 *
329 * @param Env Handle of the environment block.
330 */
331RTDECL(char const *const *) RTEnvGetArray(RTENV Env)
332{
333 struct RTENVINTERNAL *pIntEnv = Env;
334
335 if (pIntEnv == NULL)
336 return NULL;
337
338 return pIntEnv->apszEnv;
339}
Note: See TracBrowser for help on using the repository browser.

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