VirtualBox

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

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

Runtime: Added basic RTEnv...(RTENV,..) API.

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