VirtualBox

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

Last change on this file since 44824 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 23.1 KB
Line 
1/* $Id: env-generic.cpp 44528 2013-02-04 14:27:54Z 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#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 size_t iDst = 0;
243 for (size_t iSrc = 0; iSrc < cVars; iSrc++)
244 {
245 int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
246 if (RT_SUCCESS(rc2))
247 iDst++;
248 else if (rc2 == VERR_NO_TRANSLATION)
249 rc = VWRN_ENV_NOT_FULLY_TRANSLATED;
250 else
251 {
252 pIntEnv->cVars = iDst;
253 RTEnvDestroy(pIntEnv);
254 return rc2;
255 }
256 }
257 pIntEnv->cVars = iDst;
258 }
259 else
260 {
261 for (size_t iVar = 0; iVar < cVars; iVar++)
262 {
263 char *pszVar = RTStrDup(papszEnv[iVar]);
264 if (RT_UNLIKELY(!pszVar))
265 {
266 RTENV_UNLOCK(pIntEnvToClone);
267
268 pIntEnv->cVars = iVar;
269 RTEnvDestroy(pIntEnv);
270 return VERR_NO_STR_MEMORY;
271 }
272 pIntEnv->papszEnv[iVar] = pszVar;
273 }
274 }
275
276 /* done */
277 *pEnv = pIntEnv;
278 }
279
280 if (pIntEnvToClone)
281 RTENV_UNLOCK(pIntEnvToClone);
282 return rc;
283}
284RT_EXPORT_SYMBOL(RTEnvClone);
285
286
287RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
288{
289 int rc;
290 AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER);
291 const char *pszEq = strchr(pszVarEqualValue, '=');
292 if (!pszEq)
293 rc = RTEnvUnsetEx(Env, pszVarEqualValue);
294 else
295 {
296 /*
297 * Make a copy of the variable name so we can terminate it
298 * properly and then pass the request on to RTEnvSetEx.
299 */
300 const char *pszValue = pszEq + 1;
301
302 size_t cchVar = pszEq - pszVarEqualValue;
303 Assert(cchVar < 1024);
304 char *pszVar = (char *)alloca(cchVar + 1);
305 memcpy(pszVar, pszVarEqualValue, cchVar);
306 pszVar[cchVar] = '\0';
307
308 rc = RTEnvSetEx(Env, pszVar, pszValue);
309 }
310 return rc;
311}
312RT_EXPORT_SYMBOL(RTEnvPutEx);
313
314
315RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
316{
317 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
318 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
319 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
320
321 int rc;
322 if (Env == RTENV_DEFAULT)
323 {
324 /*
325 * Since RTEnvPut isn't UTF-8 clean and actually expects the strings
326 * to be in the current code page (codeset), we'll do the necessary
327 * conversions here.
328 */
329 char *pszVarOtherCP;
330 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
331 if (RT_SUCCESS(rc))
332 {
333 char *pszValueOtherCP;
334 rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue);
335 if (RT_SUCCESS(rc))
336 {
337 rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP);
338 RTStrFree(pszValueOtherCP);
339 }
340 RTStrFree(pszVarOtherCP);
341 }
342 }
343 else
344 {
345 PRTENVINTERNAL pIntEnv = Env;
346 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
347 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
348
349 /*
350 * Create the variable string.
351 */
352 const size_t cchVar = strlen(pszVar);
353 const size_t cchValue = strlen(pszValue);
354 char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2);
355 if (pszEntry)
356 {
357 memcpy(pszEntry, pszVar, cchVar);
358 pszEntry[cchVar] = '=';
359 memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1);
360
361 RTENV_LOCK(pIntEnv);
362
363 /*
364 * Find the location of the variable. (iVar = cVars if new)
365 */
366 rc = VINF_SUCCESS;
367 size_t iVar;
368 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
369 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
370 && pIntEnv->papszEnv[iVar][cchVar] == '=')
371 break;
372 if (iVar < pIntEnv->cVars)
373 {
374 /*
375 * Replace the current entry. Simple.
376 */
377 RTMemFree(pIntEnv->papszEnv[iVar]);
378 pIntEnv->papszEnv[iVar] = pszEntry;
379 }
380 else
381 {
382 /*
383 * Adding a new variable. Resize the array if required
384 * and then insert the new value at the end.
385 */
386 if (pIntEnv->cVars + 2 > pIntEnv->cAllocated)
387 {
388 void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE));
389 if (!pvNew)
390 rc = VERR_NO_MEMORY;
391 else
392 {
393 pIntEnv->papszEnv = (char **)pvNew;
394 pIntEnv->cAllocated += RTENV_GROW_SIZE;
395 for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++)
396 pIntEnv->papszEnv[iNewVar] = NULL;
397 }
398 }
399 if (RT_SUCCESS(rc))
400 {
401 pIntEnv->papszEnv[iVar] = pszEntry;
402 pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */
403 pIntEnv->cVars++;
404 Assert(pIntEnv->cVars == iVar + 1);
405 }
406 }
407
408 RTENV_UNLOCK(pIntEnv);
409
410 if (RT_FAILURE(rc))
411 RTMemFree(pszEntry);
412 }
413 else
414 rc = VERR_NO_MEMORY;
415 }
416 return rc;
417}
418RT_EXPORT_SYMBOL(RTEnvSetEx);
419
420
421RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
422{
423 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
424 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
425
426 int rc;
427 if (Env == RTENV_DEFAULT)
428 {
429 /*
430 * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings
431 * to be in the current code page (codeset), we'll do the necessary
432 * conversions here.
433 */
434 char *pszVarOtherCP;
435 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
436 if (RT_SUCCESS(rc))
437 {
438 rc = RTEnvUnset(pszVarOtherCP);
439 RTStrFree(pszVarOtherCP);
440 }
441 }
442 else
443 {
444 PRTENVINTERNAL pIntEnv = Env;
445 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
446 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
447
448 RTENV_LOCK(pIntEnv);
449
450 /*
451 * Remove all variable by the given name.
452 */
453 rc = VINF_ENV_VAR_NOT_FOUND;
454 const size_t cchVar = strlen(pszVar);
455 size_t iVar;
456 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
457 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
458 && pIntEnv->papszEnv[iVar][cchVar] == '=')
459 {
460 RTMemFree(pIntEnv->papszEnv[iVar]);
461 pIntEnv->cVars--;
462 if (pIntEnv->cVars > 0)
463 pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars];
464 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
465 rc = VINF_SUCCESS;
466 /* no break, there could be more. */
467 }
468
469 RTENV_UNLOCK(pIntEnv);
470 }
471 return rc;
472
473}
474RT_EXPORT_SYMBOL(RTEnvUnsetEx);
475
476
477RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual)
478{
479 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
480 AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER);
481 AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER);
482 AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER);
483
484 if (pcchActual)
485 *pcchActual = 0;
486 int rc;
487 if (Env == RTENV_DEFAULT)
488 {
489 /*
490 * Since RTEnvGet isn't UTF-8 clean and actually expects the strings
491 * to be in the current code page (codeset), we'll do the necessary
492 * conversions here.
493 */
494 char *pszVarOtherCP;
495 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
496 if (RT_SUCCESS(rc))
497 {
498 const char *pszValueOtherCP = RTEnvGet(pszVarOtherCP);
499 RTStrFree(pszVarOtherCP);
500 if (pszValueOtherCP)
501 {
502 char *pszValueUtf8;
503 rc = RTStrCurrentCPToUtf8(&pszValueUtf8, pszValueOtherCP);
504 if (RT_SUCCESS(rc))
505 {
506 rc = VINF_SUCCESS;
507 size_t cch = strlen(pszValueUtf8);
508 if (pcchActual)
509 *pcchActual = cch;
510 if (pszValue && cbValue)
511 {
512 if (cch < cbValue)
513 memcpy(pszValue, pszValueUtf8, cch + 1);
514 else
515 rc = VERR_BUFFER_OVERFLOW;
516 }
517 RTStrFree(pszValueUtf8);
518 }
519 }
520 else
521 rc = VERR_ENV_VAR_NOT_FOUND;
522 }
523 }
524 else
525 {
526 PRTENVINTERNAL pIntEnv = Env;
527 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
528 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
529
530 RTENV_LOCK(pIntEnv);
531
532 /*
533 * Locate the first variable and return it to the caller.
534 */
535 rc = VERR_ENV_VAR_NOT_FOUND;
536 const size_t cchVar = strlen(pszVar);
537 size_t iVar;
538 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
539 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
540 && pIntEnv->papszEnv[iVar][cchVar] == '=')
541 {
542 rc = VINF_SUCCESS;
543 const char *pszValueOrg = pIntEnv->papszEnv[iVar] + cchVar + 1;
544 size_t cch = strlen(pszValueOrg);
545 if (pcchActual)
546 *pcchActual = cch;
547 if (pszValue && cbValue)
548 {
549 if (cch < cbValue)
550 memcpy(pszValue, pszValueOrg, cch + 1);
551 else
552 rc = VERR_BUFFER_OVERFLOW;
553 }
554 break;
555 }
556
557 RTENV_UNLOCK(pIntEnv);
558 }
559 return rc;
560
561}
562RT_EXPORT_SYMBOL(RTEnvGetEx);
563
564
565RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
566{
567 AssertPtrReturn(pszVar, false);
568
569 bool fExist = false;
570 if (Env == RTENV_DEFAULT)
571 {
572 /*
573 * Since RTEnvExist isn't UTF-8 clean and actually expects the strings
574 * to be in the current code page (codeset), we'll do the necessary
575 * conversions here.
576 */
577 char *pszVarOtherCP;
578 int rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
579 if (RT_SUCCESS(rc))
580 {
581 fExist = RTEnvExist(pszVarOtherCP);
582 RTStrFree(pszVarOtherCP);
583 }
584 }
585 else
586 {
587 PRTENVINTERNAL pIntEnv = Env;
588 AssertPtrReturn(pIntEnv, false);
589 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, false);
590
591 RTENV_LOCK(pIntEnv);
592
593 /*
594 * Simple search.
595 */
596 const size_t cchVar = strlen(pszVar);
597 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
598 if ( !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar)
599 && pIntEnv->papszEnv[iVar][cchVar] == '=')
600 {
601 fExist = true;
602 break;
603 }
604
605 RTENV_UNLOCK(pIntEnv);
606 }
607 return fExist;
608}
609RT_EXPORT_SYMBOL(RTEnvExistEx);
610
611
612RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env)
613{
614 const char * const *papszRet;
615 if (Env == RTENV_DEFAULT)
616 {
617 papszRet = rtEnvDefault();
618 if (!papszRet)
619 {
620 static const char * const s_papszDummy[2] = { NULL, NULL };
621 papszRet = &s_papszDummy[0];
622 }
623 }
624 else
625 {
626 PRTENVINTERNAL pIntEnv = Env;
627 AssertPtrReturn(pIntEnv, NULL);
628 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, NULL);
629
630 RTENV_LOCK(pIntEnv);
631
632 /*
633 * Free any old envp.
634 */
635 if (pIntEnv->papszEnvOtherCP)
636 {
637 for (size_t iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
638 {
639 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
640 pIntEnv->papszEnvOtherCP[iVar] = NULL;
641 }
642 RTMemFree(pIntEnv->papszEnvOtherCP);
643 pIntEnv->papszEnvOtherCP = NULL;
644 }
645
646 /*
647 * Construct a new envp with the strings in the process code set.
648 */
649 char **papsz;
650 papszRet = pIntEnv->papszEnvOtherCP = papsz = (char **)RTMemAlloc(sizeof(char *) * (pIntEnv->cVars + 1));
651 if (papsz)
652 {
653 papsz[pIntEnv->cVars] = NULL;
654 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
655 {
656 int rc = RTStrUtf8ToCurrentCP(&papsz[iVar], pIntEnv->papszEnv[iVar]);
657 if (RT_FAILURE(rc))
658 {
659 /* RTEnvDestroy / we cleans up later. */
660 papsz[iVar] = NULL;
661 AssertRC(rc);
662 papszRet = NULL;
663 break;
664 }
665 }
666 }
667
668 RTENV_UNLOCK(pIntEnv);
669 }
670 return papszRet;
671}
672RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
673
674
675/**
676 * RTSort callback for comparing two environment variables.
677 *
678 * @returns -1, 0, 1. See PFNRTSORTCMP.
679 * @param pvElement1 Variable 1.
680 * @param pvElement2 Variable 2.
681 * @param pvUser Ignored.
682 */
683DECLCALLBACK(int) rtEnvSortCompare(const void *pvElement1, const void *pvElement2, void *pvUser)
684{
685 NOREF(pvUser);
686 int iDiff = strcmp((const char *)pvElement1, (const char *)pvElement2);
687 if (iDiff < 0)
688 iDiff = -1;
689 else if (iDiff > 0)
690 iDiff = 1;
691 return iDiff;
692}
693
694
695RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock)
696{
697 RTENV hClone = NIL_RTENV;
698 PRTENVINTERNAL pIntEnv;
699 int rc;
700
701 /*
702 * Validate / simplify input.
703 */
704 if (hEnv == RTENV_DEFAULT)
705 {
706 rc = RTEnvClone(&hClone, RTENV_DEFAULT);
707 if (RT_FAILURE(rc))
708 return rc;
709 pIntEnv = hClone;
710 }
711 else
712 {
713 pIntEnv = hEnv;
714 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
715 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
716 rc = VINF_SUCCESS;
717 }
718
719 RTENV_LOCK(pIntEnv);
720
721 /*
722 * Sort it first.
723 */
724 RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv);
725
726 /*
727 * Calculate the size.
728 */
729 size_t cwc;
730 size_t cwcTotal = 2;
731 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
732 {
733 rc = RTStrCalcUtf16LenEx(pIntEnv->papszEnv[iVar], RTSTR_MAX, &cwc);
734 AssertRCBreak(rc);
735 cwcTotal += cwc + 1;
736 }
737
738 PRTUTF16 pwszzBlock = NULL;
739 if (RT_SUCCESS(rc))
740 {
741 /*
742 * Perform the conversion.
743 */
744 PRTUTF16 pwszz = pwszzBlock = (PRTUTF16)RTMemAlloc(cwcTotal * sizeof(RTUTF16));
745 if (pwszz)
746 {
747 size_t cwcLeft = cwcTotal;
748 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
749 {
750 rc = RTStrToUtf16Ex(pIntEnv->papszEnv[iVar], RTSTR_MAX,
751 &pwszz, cwcTotal - (pwszz - pwszzBlock), &cwc);
752 AssertRCBreak(rc);
753 pwszz += cwc + 1;
754 cwcLeft -= cwc + 1;
755 AssertBreakStmt(cwcLeft >= 2, rc = VERR_INTERNAL_ERROR_3);
756 }
757 AssertStmt(cwcLeft == 2 || RT_FAILURE(rc), rc = VERR_INTERNAL_ERROR_2);
758 if (RT_SUCCESS(rc))
759 {
760 pwszz[0] = '\0';
761 pwszz[1] = '\0';
762 }
763 else
764 {
765 RTMemFree(pwszzBlock);
766 pwszzBlock = NULL;
767 }
768 }
769 else
770 rc = VERR_NO_MEMORY;
771 }
772
773 RTENV_UNLOCK(pIntEnv);
774
775 if (hClone != NIL_RTENV)
776 RTEnvDestroy(hClone);
777 if (RT_SUCCESS(rc))
778 *ppwszzBlock = pwszzBlock;
779 return rc;
780}
781RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
782
783
784RTDECL(void) RTEnvFreeUtf16Block(PRTUTF16 pwszzBlock)
785{
786 RTMemFree(pwszzBlock);
787}
788RT_EXPORT_SYMBOL(RTEnvFreeUtf16Block);
789
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