VirtualBox

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

Last change on this file since 46208 was 46035, checked in by vboxsync, 12 years ago

Remove L4 support from main tree.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 22.9 KB
Line 
1/* $Id: env-generic.cpp 46035 2013-05-13 16:47:40Z vboxsync $ */
2/** @file
3 * IPRT - Environment, Generic.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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#else
105 return environ;
106#endif
107}
108
109
110/**
111 * Internal worker that creates an environment handle with a specified capacity.
112 *
113 * @returns IPRT status code.
114 * @param ppIntEnv Where to store the result.
115 * @param cAllocated The initial array size.
116 */
117static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated)
118{
119 /*
120 * Allocate environment handle.
121 */
122 PRTENVINTERNAL pIntEnv = (PRTENVINTERNAL)RTMemAlloc(sizeof(*pIntEnv));
123 if (pIntEnv)
124 {
125 /*
126 * Pre-allocate the variable array.
127 */
128 pIntEnv->u32Magic = RTENV_MAGIC;
129 pIntEnv->papszEnvOtherCP = NULL;
130 pIntEnv->cVars = 0;
131 pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE);
132 pIntEnv->papszEnv = (char **)RTMemAllocZ(sizeof(pIntEnv->papszEnv[0]) * pIntEnv->cAllocated);
133 if (pIntEnv->papszEnv)
134 {
135 *ppIntEnv = pIntEnv;
136 return VINF_SUCCESS;
137 }
138
139 RTMemFree(pIntEnv);
140 }
141
142 return VERR_NO_MEMORY;
143}
144
145
146RTDECL(int) RTEnvCreate(PRTENV pEnv)
147{
148 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
149 return rtEnvCreate(pEnv, RTENV_GROW_SIZE);
150}
151RT_EXPORT_SYMBOL(RTEnvCreate);
152
153
154RTDECL(int) RTEnvDestroy(RTENV Env)
155{
156 /*
157 * Ignore NIL_RTENV and validate input.
158 */
159 if ( Env == NIL_RTENV
160 || Env == RTENV_DEFAULT)
161 return VINF_SUCCESS;
162
163 PRTENVINTERNAL pIntEnv = Env;
164 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
165 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
166
167 /*
168 * Do the cleanup.
169 */
170 RTENV_LOCK(pIntEnv);
171 pIntEnv->u32Magic++;
172 size_t iVar = pIntEnv->cVars;
173 while (iVar-- > 0)
174 RTStrFree(pIntEnv->papszEnv[iVar]);
175 RTMemFree(pIntEnv->papszEnv);
176 pIntEnv->papszEnv = NULL;
177
178 if (pIntEnv->papszEnvOtherCP)
179 {
180 for (iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
181 {
182 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
183 pIntEnv->papszEnvOtherCP[iVar] = NULL;
184 }
185 RTMemFree(pIntEnv->papszEnvOtherCP);
186 pIntEnv->papszEnvOtherCP = NULL;
187 }
188
189 RTENV_UNLOCK(pIntEnv);
190 /*RTCritSectDelete(&pIntEnv->CritSect) */
191 RTMemFree(pIntEnv);
192
193 return VINF_SUCCESS;
194}
195RT_EXPORT_SYMBOL(RTEnvDestroy);
196
197
198RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
199{
200 /*
201 * Validate input and figure out how many variable to clone and where to get them.
202 */
203 size_t cVars;
204 const char * const *papszEnv;
205 PRTENVINTERNAL pIntEnvToClone;
206 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
207 if (EnvToClone == RTENV_DEFAULT)
208 {
209 pIntEnvToClone = NULL;
210 papszEnv = rtEnvDefault();
211 cVars = 0;
212 if (papszEnv)
213 while (papszEnv[cVars])
214 cVars++;
215 }
216 else
217 {
218 pIntEnvToClone = EnvToClone;
219 AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE);
220 AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
221 RTENV_LOCK(pIntEnvToClone);
222
223 papszEnv = pIntEnvToClone->papszEnv;
224 cVars = pIntEnvToClone->cVars;
225 }
226
227 /*
228 * Create the duplicate.
229 */
230 PRTENVINTERNAL pIntEnv;
231 int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */);
232 if (RT_SUCCESS(rc))
233 {
234 pIntEnv->cVars = cVars;
235 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
236 if (EnvToClone == RTENV_DEFAULT)
237 {
238 /* ASSUMES the default environment is in the current codepage. */
239 size_t iDst = 0;
240 for (size_t iSrc = 0; iSrc < cVars; iSrc++)
241 {
242 int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
243 if (RT_SUCCESS(rc2))
244 iDst++;
245 else if (rc2 == VERR_NO_TRANSLATION)
246 rc = VWRN_ENV_NOT_FULLY_TRANSLATED;
247 else
248 {
249 pIntEnv->cVars = iDst;
250 RTEnvDestroy(pIntEnv);
251 return rc2;
252 }
253 }
254 pIntEnv->cVars = iDst;
255 }
256 else
257 {
258 for (size_t iVar = 0; iVar < cVars; iVar++)
259 {
260 char *pszVar = RTStrDup(papszEnv[iVar]);
261 if (RT_UNLIKELY(!pszVar))
262 {
263 RTENV_UNLOCK(pIntEnvToClone);
264
265 pIntEnv->cVars = iVar;
266 RTEnvDestroy(pIntEnv);
267 return VERR_NO_STR_MEMORY;
268 }
269 pIntEnv->papszEnv[iVar] = pszVar;
270 }
271 }
272
273 /* done */
274 *pEnv = pIntEnv;
275 }
276
277 if (pIntEnvToClone)
278 RTENV_UNLOCK(pIntEnvToClone);
279 return rc;
280}
281RT_EXPORT_SYMBOL(RTEnvClone);
282
283
284RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
285{
286 int rc;
287 AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER);
288 const char *pszEq = strchr(pszVarEqualValue, '=');
289 if (!pszEq)
290 rc = RTEnvUnsetEx(Env, pszVarEqualValue);
291 else
292 {
293 /*
294 * Make a copy of the variable name so we can terminate it
295 * properly and then pass the request on to RTEnvSetEx.
296 */
297 const char *pszValue = pszEq + 1;
298
299 size_t cchVar = pszEq - pszVarEqualValue;
300 Assert(cchVar < 1024);
301 char *pszVar = (char *)alloca(cchVar + 1);
302 memcpy(pszVar, pszVarEqualValue, cchVar);
303 pszVar[cchVar] = '\0';
304
305 rc = RTEnvSetEx(Env, pszVar, pszValue);
306 }
307 return rc;
308}
309RT_EXPORT_SYMBOL(RTEnvPutEx);
310
311
312RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
313{
314 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
315 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
316 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
317
318 int rc;
319 if (Env == RTENV_DEFAULT)
320 {
321 /*
322 * Since RTEnvPut isn't UTF-8 clean and actually expects the strings
323 * to be in the current code page (codeset), we'll do the necessary
324 * conversions here.
325 */
326 char *pszVarOtherCP;
327 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
328 if (RT_SUCCESS(rc))
329 {
330 char *pszValueOtherCP;
331 rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue);
332 if (RT_SUCCESS(rc))
333 {
334 rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP);
335 RTStrFree(pszValueOtherCP);
336 }
337 RTStrFree(pszVarOtherCP);
338 }
339 }
340 else
341 {
342 PRTENVINTERNAL pIntEnv = Env;
343 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
344 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
345
346 /*
347 * Create the variable string.
348 */
349 const size_t cchVar = strlen(pszVar);
350 const size_t cchValue = strlen(pszValue);
351 char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2);
352 if (pszEntry)
353 {
354 memcpy(pszEntry, pszVar, cchVar);
355 pszEntry[cchVar] = '=';
356 memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1);
357
358 RTENV_LOCK(pIntEnv);
359
360 /*
361 * Find the location of the variable. (iVar = cVars if new)
362 */
363 rc = VINF_SUCCESS;
364 size_t iVar;
365 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
366 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
367 && pIntEnv->papszEnv[iVar][cchVar] == '=')
368 break;
369 if (iVar < pIntEnv->cVars)
370 {
371 /*
372 * Replace the current entry. Simple.
373 */
374 RTMemFree(pIntEnv->papszEnv[iVar]);
375 pIntEnv->papszEnv[iVar] = pszEntry;
376 }
377 else
378 {
379 /*
380 * Adding a new variable. Resize the array if required
381 * and then insert the new value at the end.
382 */
383 if (pIntEnv->cVars + 2 > pIntEnv->cAllocated)
384 {
385 void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE));
386 if (!pvNew)
387 rc = VERR_NO_MEMORY;
388 else
389 {
390 pIntEnv->papszEnv = (char **)pvNew;
391 pIntEnv->cAllocated += RTENV_GROW_SIZE;
392 for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++)
393 pIntEnv->papszEnv[iNewVar] = NULL;
394 }
395 }
396 if (RT_SUCCESS(rc))
397 {
398 pIntEnv->papszEnv[iVar] = pszEntry;
399 pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */
400 pIntEnv->cVars++;
401 Assert(pIntEnv->cVars == iVar + 1);
402 }
403 }
404
405 RTENV_UNLOCK(pIntEnv);
406
407 if (RT_FAILURE(rc))
408 RTMemFree(pszEntry);
409 }
410 else
411 rc = VERR_NO_MEMORY;
412 }
413 return rc;
414}
415RT_EXPORT_SYMBOL(RTEnvSetEx);
416
417
418RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
419{
420 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
421 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
422
423 int rc;
424 if (Env == RTENV_DEFAULT)
425 {
426 /*
427 * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings
428 * to be in the current code page (codeset), we'll do the necessary
429 * conversions here.
430 */
431 char *pszVarOtherCP;
432 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
433 if (RT_SUCCESS(rc))
434 {
435 rc = RTEnvUnset(pszVarOtherCP);
436 RTStrFree(pszVarOtherCP);
437 }
438 }
439 else
440 {
441 PRTENVINTERNAL pIntEnv = Env;
442 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
443 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
444
445 RTENV_LOCK(pIntEnv);
446
447 /*
448 * Remove all variable by the given name.
449 */
450 rc = VINF_ENV_VAR_NOT_FOUND;
451 const size_t cchVar = strlen(pszVar);
452 size_t iVar;
453 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
454 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
455 && pIntEnv->papszEnv[iVar][cchVar] == '=')
456 {
457 RTMemFree(pIntEnv->papszEnv[iVar]);
458 pIntEnv->cVars--;
459 if (pIntEnv->cVars > 0)
460 pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars];
461 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
462 rc = VINF_SUCCESS;
463 /* no break, there could be more. */
464 }
465
466 RTENV_UNLOCK(pIntEnv);
467 }
468 return rc;
469
470}
471RT_EXPORT_SYMBOL(RTEnvUnsetEx);
472
473
474RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual)
475{
476 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
477 AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER);
478 AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER);
479 AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER);
480
481 if (pcchActual)
482 *pcchActual = 0;
483 int rc;
484 if (Env == RTENV_DEFAULT)
485 {
486 /*
487 * Since RTEnvGet isn't UTF-8 clean and actually expects the strings
488 * to be in the current code page (codeset), we'll do the necessary
489 * conversions here.
490 */
491 char *pszVarOtherCP;
492 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
493 if (RT_SUCCESS(rc))
494 {
495 const char *pszValueOtherCP = RTEnvGet(pszVarOtherCP);
496 RTStrFree(pszVarOtherCP);
497 if (pszValueOtherCP)
498 {
499 char *pszValueUtf8;
500 rc = RTStrCurrentCPToUtf8(&pszValueUtf8, pszValueOtherCP);
501 if (RT_SUCCESS(rc))
502 {
503 rc = VINF_SUCCESS;
504 size_t cch = strlen(pszValueUtf8);
505 if (pcchActual)
506 *pcchActual = cch;
507 if (pszValue && cbValue)
508 {
509 if (cch < cbValue)
510 memcpy(pszValue, pszValueUtf8, cch + 1);
511 else
512 rc = VERR_BUFFER_OVERFLOW;
513 }
514 RTStrFree(pszValueUtf8);
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 variables.
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