VirtualBox

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

Last change on this file since 28587 was 27350, checked in by vboxsync, 15 years ago

build fix

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