VirtualBox

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

Last change on this file since 41670 was 41670, checked in by vboxsync, 13 years ago

RTEnvClone: don't return an error if we found elements without a proper translation (xtracker 5667)

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