VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 22.8 KB
Line 
1/* $Id: env-generic.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * IPRT - Environment, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/env.h>
32#include "internal/iprt.h"
33
34#include <iprt/assert.h>
35#include <iprt/alloc.h>
36#include <iprt/alloca.h>
37#include <iprt/string.h>
38#include <iprt/sort.h>
39#include <iprt/err.h>
40#include "internal/magics.h"
41
42#include <stdlib.h>
43#if !defined(RT_OS_WINDOWS)
44# include <unistd.h>
45#endif
46#ifdef RT_OS_DARWIN
47# include <crt_externs.h>
48#endif
49#if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
50RT_C_DECLS_BEGIN
51extern char **environ;
52RT_C_DECLS_END
53#endif
54
55
56/*******************************************************************************
57* Defined Constants And Macros *
58*******************************************************************************/
59/** Macro that unlocks the specified environment block. */
60#define RTENV_LOCK(pEnvInt) do { } while (0)
61/** Macro that unlocks the specified environment block. */
62#define RTENV_UNLOCK(pEnvInt) do { } while (0)
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * The internal representation of a (non-default) environment.
70 */
71typedef struct RTENVINTERNAL
72{
73 /** Magic value . */
74 uint32_t u32Magic;
75 /** Number of variables in the array.
76 * This does not include the terminating NULL entry. */
77 size_t cVars;
78 /** Capacity (allocated size) of the array.
79 * This includes space for the terminating NULL element (for compatibility
80 * with the C library), so that c <= cCapacity - 1. */
81 size_t cAllocated;
82 /** Array of environment variables. */
83 char **papszEnv;
84 /** Array of environment variables in the process CP.
85 * This get (re-)constructed when RTEnvGetExecEnvP method is called. */
86 char **papszEnvOtherCP;
87} RTENVINTERNAL, *PRTENVINTERNAL;
88
89/** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */
90#define RTENV_GROW_SIZE 16
91
92
93/**
94 * Internal worker that resolves the pointer to the default
95 * process environment. (environ)
96 *
97 * @returns Pointer to the default environment.
98 * This may be NULL.
99 */
100static const char * const *rtEnvDefault(void)
101{
102#ifdef RT_OS_DARWIN
103 return *(_NSGetEnviron());
104#elif defined(RT_OS_L4)
105 /* So far, our L4 libraries do not include environment support. */
106 return NULL;
107#else
108 return environ;
109#endif
110}
111
112
113/**
114 * Internal worker that creates an environment handle with a specified capacity.
115 *
116 * @returns IPRT status code.
117 * @param ppIntEnv Where to store the result.
118 * @param cAllocated The initial array size.
119 */
120static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated)
121{
122 /*
123 * Allocate environment handle.
124 */
125 PRTENVINTERNAL pIntEnv = (PRTENVINTERNAL)RTMemAlloc(sizeof(*pIntEnv));
126 if (pIntEnv)
127 {
128 /*
129 * Pre-allocate the variable array.
130 */
131 pIntEnv->u32Magic = RTENV_MAGIC;
132 pIntEnv->papszEnvOtherCP = NULL;
133 pIntEnv->cVars = 0;
134 pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE);
135 pIntEnv->papszEnv = (char **)RTMemAllocZ(sizeof(pIntEnv->papszEnv[0]) * pIntEnv->cAllocated);
136 if (pIntEnv->papszEnv)
137 {
138 *ppIntEnv = pIntEnv;
139 return VINF_SUCCESS;
140 }
141
142 RTMemFree(pIntEnv);
143 }
144
145 return VERR_NO_MEMORY;
146}
147
148
149RTDECL(int) RTEnvCreate(PRTENV pEnv)
150{
151 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
152 return rtEnvCreate(pEnv, RTENV_GROW_SIZE);
153}
154RT_EXPORT_SYMBOL(RTEnvCreate);
155
156
157RTDECL(int) RTEnvDestroy(RTENV Env)
158{
159 /*
160 * Ignore NIL_RTENV and validate input.
161 */
162 if ( Env == NIL_RTENV
163 || Env == RTENV_DEFAULT)
164 return VINF_SUCCESS;
165
166 PRTENVINTERNAL pIntEnv = Env;
167 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
168 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
169
170 /*
171 * Do the cleanup.
172 */
173 RTENV_LOCK(pIntEnv);
174 pIntEnv->u32Magic++;
175 size_t iVar = pIntEnv->cVars;
176 while (iVar-- > 0)
177 RTStrFree(pIntEnv->papszEnv[iVar]);
178 RTMemFree(pIntEnv->papszEnv);
179 pIntEnv->papszEnv = NULL;
180
181 if (pIntEnv->papszEnvOtherCP)
182 {
183 for (iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
184 {
185 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
186 pIntEnv->papszEnvOtherCP[iVar] = NULL;
187 }
188 RTMemFree(pIntEnv->papszEnvOtherCP);
189 pIntEnv->papszEnvOtherCP = NULL;
190 }
191
192 RTENV_UNLOCK(pIntEnv);
193 /*RTCritSectDelete(&pIntEnv->CritSect) */
194 RTMemFree(pIntEnv);
195
196 return VINF_SUCCESS;
197}
198RT_EXPORT_SYMBOL(RTEnvDestroy);
199
200
201RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
202{
203 /*
204 * Validate input and figure out how many variable to clone and where to get them.
205 */
206 size_t cVars;
207 const char * const *papszEnv;
208 PRTENVINTERNAL pIntEnvToClone;
209 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
210 if (EnvToClone == RTENV_DEFAULT)
211 {
212 pIntEnvToClone = NULL;
213 papszEnv = rtEnvDefault();
214 cVars = 0;
215 if (papszEnv)
216 while (papszEnv[cVars])
217 cVars++;
218 }
219 else
220 {
221 pIntEnvToClone = EnvToClone;
222 AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE);
223 AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
224 RTENV_LOCK(pIntEnvToClone);
225
226 papszEnv = pIntEnvToClone->papszEnv;
227 cVars = pIntEnvToClone->cVars;
228 }
229
230 /*
231 * Create the duplicate.
232 */
233 PRTENVINTERNAL pIntEnv;
234 int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */);
235 if (RT_SUCCESS(rc))
236 {
237 pIntEnv->cVars = cVars;
238 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
239 if (EnvToClone == RTENV_DEFAULT)
240 {
241 /* ASSUMES the default environment is in the current codepage. */
242 for (size_t iVar = 0; iVar < cVars; iVar++)
243 {
244 int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iVar], papszEnv[iVar]);
245 if (RT_FAILURE(rc2))
246 {
247 pIntEnv->cVars = iVar;
248 RTEnvDestroy(pIntEnv);
249 return rc2;
250 }
251 }
252 }
253 else
254 {
255 for (size_t iVar = 0; iVar < cVars; iVar++)
256 {
257 char *pszVar = RTStrDup(papszEnv[iVar]);
258 if (RT_UNLIKELY(!pszVar))
259 {
260 RTENV_UNLOCK(pIntEnvToClone);
261
262 pIntEnv->cVars = iVar;
263 RTEnvDestroy(pIntEnv);
264 return VERR_NO_STR_MEMORY;
265 }
266 pIntEnv->papszEnv[iVar] = pszVar;
267 }
268 }
269
270 /* done */
271 *pEnv = pIntEnv;
272 }
273
274 if (pIntEnvToClone)
275 RTENV_UNLOCK(pIntEnvToClone);
276 return rc;
277}
278RT_EXPORT_SYMBOL(RTEnvClone);
279
280
281RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
282{
283 int rc;
284 AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER);
285 const char *pszEq = strchr(pszVarEqualValue, '=');
286 if (!pszEq)
287 rc = RTEnvUnsetEx(Env, pszVarEqualValue);
288 else
289 {
290 /*
291 * Make a copy of the variable name so we can terminate it
292 * properly and then pass the request on to RTEnvSetEx.
293 */
294 const char *pszValue = pszEq + 1;
295
296 size_t cchVar = pszEq - pszVarEqualValue;
297 Assert(cchVar < 1024);
298 char *pszVar = (char *)alloca(cchVar + 1);
299 memcpy(pszVar, pszVarEqualValue, cchVar);
300 pszVar[cchVar] = '\0';
301
302 rc = RTEnvSetEx(Env, pszVar, pszValue);
303 }
304 return rc;
305}
306RT_EXPORT_SYMBOL(RTEnvPutEx);
307
308
309RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
310{
311 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
312 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
313 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
314
315 int rc;
316 if (Env == RTENV_DEFAULT)
317 {
318 /*
319 * Since RTEnvPut isn't UTF-8 clean and actually expects the strings
320 * to be in the current code page (codeset), we'll do the necessary
321 * conversions here.
322 */
323 char *pszVarOtherCP;
324 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
325 if (RT_SUCCESS(rc))
326 {
327 char *pszValueOtherCP;
328 rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue);
329 if (RT_SUCCESS(rc))
330 {
331 rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP);
332 RTStrFree(pszValueOtherCP);
333 }
334 RTStrFree(pszVarOtherCP);
335 }
336 }
337 else
338 {
339 PRTENVINTERNAL pIntEnv = Env;
340 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
341 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
342
343 /*
344 * Create the variable string.
345 */
346 const size_t cchVar = strlen(pszVar);
347 const size_t cchValue = strlen(pszValue);
348 char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2);
349 if (pszEntry)
350 {
351 memcpy(pszEntry, pszVar, cchVar);
352 pszEntry[cchVar] = '=';
353 memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1);
354
355 RTENV_LOCK(pIntEnv);
356
357 /*
358 * Find the location of the variable. (iVar = cVars if new)
359 */
360 rc = VINF_SUCCESS;
361 size_t iVar;
362 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
363 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
364 && pIntEnv->papszEnv[iVar][cchVar] == '=')
365 break;
366 if (iVar < pIntEnv->cVars)
367 {
368 /*
369 * Replace the current entry. Simple.
370 */
371 RTMemFree(pIntEnv->papszEnv[iVar]);
372 pIntEnv->papszEnv[iVar] = pszEntry;
373 }
374 else
375 {
376 /*
377 * Adding a new variable. Resize the array if required
378 * and then insert the new value at the end.
379 */
380 if (pIntEnv->cVars + 2 > pIntEnv->cAllocated)
381 {
382 void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE));
383 if (!pvNew)
384 rc = VERR_NO_MEMORY;
385 else
386 {
387 pIntEnv->papszEnv = (char **)pvNew;
388 pIntEnv->cAllocated += RTENV_GROW_SIZE;
389 for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++)
390 pIntEnv->papszEnv[iNewVar] = NULL;
391 }
392 }
393 if (RT_SUCCESS(rc))
394 {
395 pIntEnv->papszEnv[iVar] = pszEntry;
396 pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */
397 pIntEnv->cVars++;
398 Assert(pIntEnv->cVars == iVar + 1);
399 }
400 }
401
402 RTENV_UNLOCK(pIntEnv);
403
404 if (RT_FAILURE(rc))
405 RTMemFree(pszEntry);
406 }
407 else
408 rc = VERR_NO_MEMORY;
409 }
410 return rc;
411}
412RT_EXPORT_SYMBOL(RTEnvSetEx);
413
414
415RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
416{
417 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
418 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
419
420 int rc;
421 if (Env == RTENV_DEFAULT)
422 {
423 /*
424 * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings
425 * to be in the current code page (codeset), we'll do the necessary
426 * conversions here.
427 */
428 char *pszVarOtherCP;
429 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
430 if (RT_SUCCESS(rc))
431 {
432 rc = RTEnvUnset(pszVarOtherCP);
433 RTStrFree(pszVarOtherCP);
434 }
435 }
436 else
437 {
438 PRTENVINTERNAL pIntEnv = Env;
439 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
440 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
441
442 RTENV_LOCK(pIntEnv);
443
444 /*
445 * Remove all variable by the given name.
446 */
447 rc = VINF_ENV_VAR_NOT_FOUND;
448 const size_t cchVar = strlen(pszVar);
449 size_t iVar;
450 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
451 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
452 && pIntEnv->papszEnv[iVar][cchVar] == '=')
453 {
454 RTMemFree(pIntEnv->papszEnv[iVar]);
455 pIntEnv->cVars--;
456 if (pIntEnv->cVars > 0)
457 pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars];
458 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
459 rc = VINF_SUCCESS;
460 /* no break, there could be more. */
461 }
462
463 RTENV_UNLOCK(pIntEnv);
464 }
465 return rc;
466
467}
468RT_EXPORT_SYMBOL(RTEnvUnsetEx);
469
470
471RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual)
472{
473 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
474 AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER);
475 AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER);
476 AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER);
477
478 if (pcchActual)
479 *pcchActual = 0;
480 int rc;
481 if (Env == RTENV_DEFAULT)
482 {
483 /*
484 * Since RTEnvGet isn't UTF-8 clean and actually expects the strings
485 * to be in the current code page (codeset), we'll do the necessary
486 * conversions here.
487 */
488 char *pszVarOtherCP;
489 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
490 if (RT_SUCCESS(rc))
491 {
492 const char *pszValueOtherCP = RTEnvGet(pszVarOtherCP);
493 RTStrFree(pszVarOtherCP);
494 if (pszValueOtherCP)
495 {
496 char *pszValueUtf8;
497 rc = RTStrCurrentCPToUtf8(&pszValueUtf8, pszValueOtherCP);
498 if (RT_SUCCESS(rc))
499 {
500 rc = VINF_SUCCESS;
501 size_t cch = strlen(pszValueUtf8);
502 if (pcchActual)
503 *pcchActual = cch;
504 if (pszValue && cbValue)
505 {
506 if (cch < cbValue)
507 memcpy(pszValue, pszValueUtf8, cch + 1);
508 else
509 rc = VERR_BUFFER_OVERFLOW;
510 }
511 }
512 }
513 else
514 rc = VERR_ENV_VAR_NOT_FOUND;
515 }
516 }
517 else
518 {
519 PRTENVINTERNAL pIntEnv = Env;
520 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
521 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
522
523 RTENV_LOCK(pIntEnv);
524
525 /*
526 * Locate the first variable and return it to the caller.
527 */
528 rc = VERR_ENV_VAR_NOT_FOUND;
529 const size_t cchVar = strlen(pszVar);
530 size_t iVar;
531 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
532 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
533 && pIntEnv->papszEnv[iVar][cchVar] == '=')
534 {
535 rc = VINF_SUCCESS;
536 const char *pszValueOrg = pIntEnv->papszEnv[iVar] + cchVar + 1;
537 size_t cch = strlen(pszValueOrg);
538 if (pcchActual)
539 *pcchActual = cch;
540 if (pszValue && cbValue)
541 {
542 if (cch < cbValue)
543 memcpy(pszValue, pszValueOrg, cch + 1);
544 else
545 rc = VERR_BUFFER_OVERFLOW;
546 }
547 break;
548 }
549
550 RTENV_UNLOCK(pIntEnv);
551 }
552 return rc;
553
554}
555RT_EXPORT_SYMBOL(RTEnvGetEx);
556
557
558RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
559{
560 AssertPtrReturn(pszVar, false);
561
562 bool fExist = false;
563 if (Env == RTENV_DEFAULT)
564 {
565 /*
566 * Since RTEnvExist isn't UTF-8 clean and actually expects the strings
567 * to be in the current code page (codeset), we'll do the necessary
568 * conversions here.
569 */
570 char *pszVarOtherCP;
571 int rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
572 if (RT_SUCCESS(rc))
573 {
574 fExist = RTEnvExist(pszVarOtherCP);
575 RTStrFree(pszVarOtherCP);
576 }
577 }
578 else
579 {
580 PRTENVINTERNAL pIntEnv = Env;
581 AssertPtrReturn(pIntEnv, false);
582 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, false);
583
584 RTENV_LOCK(pIntEnv);
585
586 /*
587 * Simple search.
588 */
589 const size_t cchVar = strlen(pszVar);
590 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
591 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
592 && pIntEnv->papszEnv[iVar][cchVar] == '=')
593 {
594 fExist = true;
595 break;
596 }
597
598 RTENV_UNLOCK(pIntEnv);
599 }
600 return fExist;
601}
602RT_EXPORT_SYMBOL(RTEnvExistEx);
603
604
605RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env)
606{
607 const char * const *papszRet;
608 if (Env == RTENV_DEFAULT)
609 {
610 papszRet = rtEnvDefault();
611 if (!papszRet)
612 {
613 static const char * const s_papszDummy[2] = { NULL, NULL };
614 papszRet = &s_papszDummy[0];
615 }
616 }
617 else
618 {
619 PRTENVINTERNAL pIntEnv = Env;
620 AssertPtrReturn(pIntEnv, NULL);
621 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, NULL);
622
623 RTENV_LOCK(pIntEnv);
624
625 /*
626 * Free any old envp.
627 */
628 if (pIntEnv->papszEnvOtherCP)
629 {
630 for (size_t iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
631 {
632 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
633 pIntEnv->papszEnvOtherCP[iVar] = NULL;
634 }
635 RTMemFree(pIntEnv->papszEnvOtherCP);
636 pIntEnv->papszEnvOtherCP = NULL;
637 }
638
639 /*
640 * Construct a new envp with the strings in the process code set.
641 */
642 char **papsz;
643 papszRet = pIntEnv->papszEnvOtherCP = papsz = (char **)RTMemAlloc(sizeof(char *) * (pIntEnv->cVars + 1));
644 if (papsz)
645 {
646 papsz[pIntEnv->cVars] = NULL;
647 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
648 {
649 int rc = RTStrUtf8ToCurrentCP(&papsz[iVar], pIntEnv->papszEnv[iVar]);
650 if (RT_FAILURE(rc))
651 {
652 /* RTEnvDestroy / we cleans up later. */
653 papsz[iVar] = NULL;
654 AssertRC(rc);
655 papszRet = NULL;
656 break;
657 }
658 }
659 }
660
661 RTENV_UNLOCK(pIntEnv);
662 }
663 return papszRet;
664}
665RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
666
667
668/**
669 * RTSort callback for comparing two environment varibles.
670 *
671 * @returns -1, 0, 1. See PFNRTSORTCMP.
672 * @param pvElement1 Variable 1.
673 * @param pvElement2 Variable 2.
674 * @param pvUser Ignored.
675 */
676DECLCALLBACK(int) rtEnvSortCompare(const void *pvElement1, const void *pvElement2, void *pvUser)
677{
678 NOREF(pvUser);
679 int iDiff = strcmp((const char *)pvElement1, (const char *)pvElement2);
680 if (iDiff < 0)
681 iDiff = -1;
682 else if (iDiff > 0)
683 iDiff = 1;
684 return iDiff;
685}
686
687
688RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock)
689{
690 RTENV hClone = NIL_RTENV;
691 PRTENVINTERNAL pIntEnv;
692 int rc;
693
694 /*
695 * Validate / simplify input.
696 */
697 if (hEnv == RTENV_DEFAULT)
698 {
699 rc = RTEnvClone(&hClone, RTENV_DEFAULT);
700 if (RT_FAILURE(rc))
701 return rc;
702 pIntEnv = hClone;
703 }
704 else
705 {
706 pIntEnv = hEnv;
707 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
708 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
709 rc = VINF_SUCCESS;
710 }
711
712 RTENV_LOCK(pIntEnv);
713
714 /*
715 * Sort it first.
716 */
717 RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv);
718
719 /*
720 * Calculate the size.
721 */
722 size_t cwc;
723 size_t cwcTotal = 2;
724 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
725 {
726 rc = RTStrCalcUtf16LenEx(pIntEnv->papszEnv[iVar], RTSTR_MAX, &cwc);
727 AssertRCBreak(rc);
728 cwcTotal += cwc + 1;
729 }
730
731 PRTUTF16 pwszzBlock = NULL;
732 if (RT_SUCCESS(rc))
733 {
734 /*
735 * Perform the conversion.
736 */
737 PRTUTF16 pwszz = pwszzBlock = (PRTUTF16)RTMemAlloc(cwcTotal * sizeof(RTUTF16));
738 if (pwszz)
739 {
740 size_t cwcLeft = cwcTotal;
741 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
742 {
743 rc = RTStrToUtf16Ex(pIntEnv->papszEnv[iVar], RTSTR_MAX,
744 &pwszz, cwcTotal - (pwszz - pwszzBlock), &cwc);
745 AssertRCBreak(rc);
746 pwszz += cwc + 1;
747 cwcLeft -= cwc + 1;
748 AssertBreakStmt(cwcLeft >= 2, rc = VERR_INTERNAL_ERROR_3);
749 }
750 AssertStmt(cwcLeft == 2 || RT_FAILURE(rc), rc = VERR_INTERNAL_ERROR_2);
751 if (RT_SUCCESS(rc))
752 {
753 pwszz[0] = '\0';
754 pwszz[1] = '\0';
755 }
756 else
757 {
758 RTMemFree(pwszzBlock);
759 pwszzBlock = NULL;
760 }
761 }
762 else
763 rc = VERR_NO_MEMORY;
764 }
765
766 RTENV_UNLOCK(pIntEnv);
767
768 if (hClone != NIL_RTENV)
769 RTEnvDestroy(hClone);
770 if (RT_SUCCESS(rc))
771 *ppwszzBlock = pwszzBlock;
772 return rc;
773}
774RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
775
776
777RTDECL(void) RTEnvFreeUtf16Block(PRTUTF16 pwszzBlock)
778{
779 RTMemFree(pwszzBlock);
780}
781RT_EXPORT_SYMBOL(RTEnvFreeUtf16Block);
782
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