VirtualBox

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

Last change on this file since 51898 was 50644, checked in by vboxsync, 11 years ago

env-generic.cpp: Workaround for lazy _wenviron initialization in the CRT.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 26.6 KB
Line 
1/* $Id: env-generic.cpp 50644 2014-02-27 20:26:21Z 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/** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */
60#define RTENV_GROW_SIZE 16
61
62/** Macro that unlocks the specified environment block. */
63#define RTENV_LOCK(pEnvInt) do { } while (0)
64/** Macro that unlocks the specified environment block. */
65#define RTENV_UNLOCK(pEnvInt) do { } while (0)
66
67/** @def RTENV_HAVE_WENVIRON
68 * Indicates that we have a _wenviron variable with UTF-16 strings that we
69 * better use instead of the current-cp strings in environ. */
70#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
71# define RTENV_HAVE_WENVIRON 1
72#endif
73
74/** @def RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
75 * Indicates the RTEnv*Utf8 APIs are implemented. */
76#if defined(RT_OS_WINDOWS) || defined(DOXYGEN_RUNNING)
77# define RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API 1
78#endif
79
80
81/*******************************************************************************
82* Structures and Typedefs *
83*******************************************************************************/
84/**
85 * The internal representation of a (non-default) environment.
86 */
87typedef struct RTENVINTERNAL
88{
89 /** Magic value . */
90 uint32_t u32Magic;
91 /** Number of variables in the array.
92 * This does not include the terminating NULL entry. */
93 size_t cVars;
94 /** Capacity (allocated size) of the array.
95 * This includes space for the terminating NULL element (for compatibility
96 * with the C library), so that c <= cCapacity - 1. */
97 size_t cAllocated;
98 /** Array of environment variables. */
99 char **papszEnv;
100 /** Array of environment variables in the process CP.
101 * This get (re-)constructed when RTEnvGetExecEnvP method is called. */
102 char **papszEnvOtherCP;
103
104 /** The compare function we're using. */
105 DECLCALLBACKMEMBER(int, pfnCompare)(const char *psz1, const char *psz2, size_t cchMax);
106} RTENVINTERNAL, *PRTENVINTERNAL;
107
108
109/**
110 * Internal worker that resolves the pointer to the default
111 * process environment. (environ)
112 *
113 * @returns Pointer to the default environment.
114 * This may be NULL.
115 */
116static const char * const *rtEnvDefault(void)
117{
118#ifdef RT_OS_DARWIN
119 return *(_NSGetEnviron());
120#else
121 return environ;
122#endif
123}
124
125
126/**
127 * Internal worker that creates an environment handle with a specified capacity.
128 *
129 * @returns IPRT status code.
130 * @param ppIntEnv Where to store the result.
131 * @param cAllocated The initial array size.
132 * @param fCaseSensitive Whether the environment block is case sensitive or
133 * not.
134 */
135static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated, bool fCaseSensitive)
136{
137 /*
138 * Allocate environment handle.
139 */
140 PRTENVINTERNAL pIntEnv = (PRTENVINTERNAL)RTMemAlloc(sizeof(*pIntEnv));
141 if (pIntEnv)
142 {
143 /*
144 * Pre-allocate the variable array.
145 */
146 pIntEnv->u32Magic = RTENV_MAGIC;
147 pIntEnv->pfnCompare = fCaseSensitive ? RTStrNCmp : RTStrNICmp;
148 pIntEnv->papszEnvOtherCP = NULL;
149 pIntEnv->cVars = 0;
150 pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE);
151 pIntEnv->papszEnv = (char **)RTMemAllocZ(sizeof(pIntEnv->papszEnv[0]) * pIntEnv->cAllocated);
152 if (pIntEnv->papszEnv)
153 {
154 *ppIntEnv = pIntEnv;
155 return VINF_SUCCESS;
156 }
157
158 RTMemFree(pIntEnv);
159 }
160
161 return VERR_NO_MEMORY;
162}
163
164
165RTDECL(int) RTEnvCreate(PRTENV pEnv)
166{
167 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
168 return rtEnvCreate(pEnv, RTENV_GROW_SIZE, false /*fCaseSensitive*/);
169}
170RT_EXPORT_SYMBOL(RTEnvCreate);
171
172
173RTDECL(int) RTEnvDestroy(RTENV Env)
174{
175 /*
176 * Ignore NIL_RTENV and validate input.
177 */
178 if ( Env == NIL_RTENV
179 || Env == RTENV_DEFAULT)
180 return VINF_SUCCESS;
181
182 PRTENVINTERNAL pIntEnv = Env;
183 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
184 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
185
186 /*
187 * Do the cleanup.
188 */
189 RTENV_LOCK(pIntEnv);
190 pIntEnv->u32Magic++;
191 size_t iVar = pIntEnv->cVars;
192 while (iVar-- > 0)
193 RTStrFree(pIntEnv->papszEnv[iVar]);
194 RTMemFree(pIntEnv->papszEnv);
195 pIntEnv->papszEnv = NULL;
196
197 if (pIntEnv->papszEnvOtherCP)
198 {
199 for (iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
200 {
201 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
202 pIntEnv->papszEnvOtherCP[iVar] = NULL;
203 }
204 RTMemFree(pIntEnv->papszEnvOtherCP);
205 pIntEnv->papszEnvOtherCP = NULL;
206 }
207
208 RTENV_UNLOCK(pIntEnv);
209 /*RTCritSectDelete(&pIntEnv->CritSect) */
210 RTMemFree(pIntEnv);
211
212 return VINF_SUCCESS;
213}
214RT_EXPORT_SYMBOL(RTEnvDestroy);
215
216
217RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone)
218{
219 /*
220 * Validate input and figure out how many variable to clone and where to get them.
221 */
222 bool fCaseSensitive = true;
223 size_t cVars;
224 const char * const *papszEnv;
225#ifdef RTENV_HAVE_WENVIRON
226 PCRTUTF16 const * papwszEnv;
227#endif
228 PRTENVINTERNAL pIntEnvToClone;
229 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
230 if (EnvToClone == RTENV_DEFAULT)
231 {
232 cVars = 0;
233 pIntEnvToClone = NULL;
234#ifdef RTENV_HAVE_WENVIRON
235 papszEnv = NULL;
236 papwszEnv = (PCRTUTF16 * const)_wenviron;
237 if (!papwszEnv)
238 {
239 _wgetenv(L"Path"); /* Force the CRT to initalize it. */
240 papwszEnv = (PCRTUTF16 * const)_wenviron;
241 }
242 if (papwszEnv)
243 while (papwszEnv[cVars])
244 cVars++;
245#else
246 papszEnv = rtEnvDefault();
247 if (papszEnv)
248 while (papszEnv[cVars])
249 cVars++;
250#endif
251
252#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
253 /* DOS systems was case insensitive. A prime example is the 'Path'
254 variable on windows which turns into the 'PATH' variable. */
255 fCaseSensitive = false;
256#endif
257 }
258 else
259 {
260 pIntEnvToClone = EnvToClone;
261 AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE);
262 AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
263 RTENV_LOCK(pIntEnvToClone);
264
265 papszEnv = pIntEnvToClone->papszEnv;
266 cVars = pIntEnvToClone->cVars;
267 }
268
269 /*
270 * Create the duplicate.
271 */
272 PRTENVINTERNAL pIntEnv;
273 int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */, fCaseSensitive);
274 if (RT_SUCCESS(rc))
275 {
276 pIntEnv->cVars = cVars;
277 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
278 if (EnvToClone == RTENV_DEFAULT)
279 {
280 /* ASSUMES the default environment is in the current codepage. */
281 size_t iDst = 0;
282 for (size_t iSrc = 0; iSrc < cVars; iSrc++)
283 {
284#ifdef RTENV_HAVE_WENVIRON
285 int rc2 = RTUtf16ToUtf8(papwszEnv[iSrc], &pIntEnv->papszEnv[iDst]);
286#else
287 int rc2 = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iDst], papszEnv[iSrc]);
288#endif
289 if (RT_SUCCESS(rc2))
290 iDst++;
291 else if (rc2 == VERR_NO_TRANSLATION)
292 rc = VWRN_ENV_NOT_FULLY_TRANSLATED;
293 else
294 {
295 pIntEnv->cVars = iDst;
296 RTEnvDestroy(pIntEnv);
297 return rc2;
298 }
299 }
300 pIntEnv->cVars = iDst;
301 }
302 else
303 {
304 for (size_t iVar = 0; iVar < cVars; iVar++)
305 {
306 char *pszVar = RTStrDup(papszEnv[iVar]);
307 if (RT_UNLIKELY(!pszVar))
308 {
309 RTENV_UNLOCK(pIntEnvToClone);
310
311 pIntEnv->cVars = iVar;
312 RTEnvDestroy(pIntEnv);
313 return VERR_NO_STR_MEMORY;
314 }
315 pIntEnv->papszEnv[iVar] = pszVar;
316 }
317 }
318
319 /* done */
320 *pEnv = pIntEnv;
321 }
322
323 if (pIntEnvToClone)
324 RTENV_UNLOCK(pIntEnvToClone);
325 return rc;
326}
327RT_EXPORT_SYMBOL(RTEnvClone);
328
329
330RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue)
331{
332 int rc;
333 AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER);
334 const char *pszEq = strchr(pszVarEqualValue, '=');
335 if (!pszEq)
336 rc = RTEnvUnsetEx(Env, pszVarEqualValue);
337 else
338 {
339 /*
340 * Make a copy of the variable name so we can terminate it
341 * properly and then pass the request on to RTEnvSetEx.
342 */
343 const char *pszValue = pszEq + 1;
344
345 size_t cchVar = pszEq - pszVarEqualValue;
346 Assert(cchVar < 1024);
347 char *pszVar = (char *)alloca(cchVar + 1);
348 memcpy(pszVar, pszVarEqualValue, cchVar);
349 pszVar[cchVar] = '\0';
350
351 rc = RTEnvSetEx(Env, pszVar, pszValue);
352 }
353 return rc;
354}
355RT_EXPORT_SYMBOL(RTEnvPutEx);
356
357
358RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue)
359{
360 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
361 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
362 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
363
364 int rc;
365 if (Env == RTENV_DEFAULT)
366 {
367#ifdef RT_OS_WINDOWS
368 rc = RTEnvSetUtf8(pszVar, pszValue);
369#else
370 /*
371 * Since RTEnvPut isn't UTF-8 clean and actually expects the strings
372 * to be in the current code page (codeset), we'll do the necessary
373 * conversions here.
374 */
375 char *pszVarOtherCP;
376 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
377 if (RT_SUCCESS(rc))
378 {
379 char *pszValueOtherCP;
380 rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue);
381 if (RT_SUCCESS(rc))
382 {
383 rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP);
384 RTStrFree(pszValueOtherCP);
385 }
386 RTStrFree(pszVarOtherCP);
387 }
388#endif
389 }
390 else
391 {
392 PRTENVINTERNAL pIntEnv = Env;
393 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
394 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
395
396 /*
397 * Create the variable string.
398 */
399 const size_t cchVar = strlen(pszVar);
400 const size_t cchValue = strlen(pszValue);
401 char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2);
402 if (pszEntry)
403 {
404 memcpy(pszEntry, pszVar, cchVar);
405 pszEntry[cchVar] = '=';
406 memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1);
407
408 RTENV_LOCK(pIntEnv);
409
410 /*
411 * Find the location of the variable. (iVar = cVars if new)
412 */
413 rc = VINF_SUCCESS;
414 size_t iVar;
415 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
416 if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
417 && pIntEnv->papszEnv[iVar][cchVar] == '=')
418 break;
419 if (iVar < pIntEnv->cVars)
420 {
421 /*
422 * Replace the current entry. Simple.
423 */
424 RTMemFree(pIntEnv->papszEnv[iVar]);
425 pIntEnv->papszEnv[iVar] = pszEntry;
426 }
427 else
428 {
429 /*
430 * Adding a new variable. Resize the array if required
431 * and then insert the new value at the end.
432 */
433 if (pIntEnv->cVars + 2 > pIntEnv->cAllocated)
434 {
435 void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE));
436 if (!pvNew)
437 rc = VERR_NO_MEMORY;
438 else
439 {
440 pIntEnv->papszEnv = (char **)pvNew;
441 pIntEnv->cAllocated += RTENV_GROW_SIZE;
442 for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++)
443 pIntEnv->papszEnv[iNewVar] = NULL;
444 }
445 }
446 if (RT_SUCCESS(rc))
447 {
448 pIntEnv->papszEnv[iVar] = pszEntry;
449 pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */
450 pIntEnv->cVars++;
451 Assert(pIntEnv->cVars == iVar + 1);
452 }
453 }
454
455 RTENV_UNLOCK(pIntEnv);
456
457 if (RT_FAILURE(rc))
458 RTMemFree(pszEntry);
459 }
460 else
461 rc = VERR_NO_MEMORY;
462 }
463 return rc;
464}
465RT_EXPORT_SYMBOL(RTEnvSetEx);
466
467
468RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar)
469{
470 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
471 AssertReturn(*pszVar, VERR_INVALID_PARAMETER);
472
473 int rc;
474 if (Env == RTENV_DEFAULT)
475 {
476#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
477 rc = RTEnvUnsetUtf8(pszVar);
478#else
479 /*
480 * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings
481 * to be in the current code page (codeset), we'll do the necessary
482 * conversions here.
483 */
484 char *pszVarOtherCP;
485 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
486 if (RT_SUCCESS(rc))
487 {
488 rc = RTEnvUnset(pszVarOtherCP);
489 RTStrFree(pszVarOtherCP);
490 }
491#endif
492 }
493 else
494 {
495 PRTENVINTERNAL pIntEnv = Env;
496 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
497 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
498
499 RTENV_LOCK(pIntEnv);
500
501 /*
502 * Remove all variable by the given name.
503 */
504 rc = VINF_ENV_VAR_NOT_FOUND;
505 const size_t cchVar = strlen(pszVar);
506 size_t iVar;
507 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
508 if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
509 && pIntEnv->papszEnv[iVar][cchVar] == '=')
510 {
511 RTMemFree(pIntEnv->papszEnv[iVar]);
512 pIntEnv->cVars--;
513 if (pIntEnv->cVars > 0)
514 pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars];
515 pIntEnv->papszEnv[pIntEnv->cVars] = NULL;
516 rc = VINF_SUCCESS;
517 /* no break, there could be more. */
518 }
519
520 RTENV_UNLOCK(pIntEnv);
521 }
522 return rc;
523
524}
525RT_EXPORT_SYMBOL(RTEnvUnsetEx);
526
527
528RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual)
529{
530 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
531 AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER);
532 AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER);
533 AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER);
534
535 if (pcchActual)
536 *pcchActual = 0;
537 int rc;
538 if (Env == RTENV_DEFAULT)
539 {
540#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
541 rc = RTEnvGetUtf8(pszVar, pszValue, cbValue, pcchActual);
542#else
543 /*
544 * Since RTEnvGet isn't UTF-8 clean and actually expects the strings
545 * to be in the current code page (codeset), we'll do the necessary
546 * conversions here.
547 */
548 char *pszVarOtherCP;
549 rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
550 if (RT_SUCCESS(rc))
551 {
552 const char *pszValueOtherCP = RTEnvGet(pszVarOtherCP);
553 RTStrFree(pszVarOtherCP);
554 if (pszValueOtherCP)
555 {
556 char *pszValueUtf8;
557 rc = RTStrCurrentCPToUtf8(&pszValueUtf8, pszValueOtherCP);
558 if (RT_SUCCESS(rc))
559 {
560 rc = VINF_SUCCESS;
561 size_t cch = strlen(pszValueUtf8);
562 if (pcchActual)
563 *pcchActual = cch;
564 if (pszValue && cbValue)
565 {
566 if (cch < cbValue)
567 memcpy(pszValue, pszValueUtf8, cch + 1);
568 else
569 rc = VERR_BUFFER_OVERFLOW;
570 }
571 RTStrFree(pszValueUtf8);
572 }
573 }
574 else
575 rc = VERR_ENV_VAR_NOT_FOUND;
576 }
577#endif
578 }
579 else
580 {
581 PRTENVINTERNAL pIntEnv = Env;
582 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
583 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
584
585 RTENV_LOCK(pIntEnv);
586
587 /*
588 * Locate the first variable and return it to the caller.
589 */
590 rc = VERR_ENV_VAR_NOT_FOUND;
591 const size_t cchVar = strlen(pszVar);
592 size_t iVar;
593 for (iVar = 0; iVar < pIntEnv->cVars; iVar++)
594 if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
595 && pIntEnv->papszEnv[iVar][cchVar] == '=')
596 {
597 rc = VINF_SUCCESS;
598 const char *pszValueOrg = pIntEnv->papszEnv[iVar] + cchVar + 1;
599 size_t cch = strlen(pszValueOrg);
600 if (pcchActual)
601 *pcchActual = cch;
602 if (pszValue && cbValue)
603 {
604 if (cch < cbValue)
605 memcpy(pszValue, pszValueOrg, cch + 1);
606 else
607 rc = VERR_BUFFER_OVERFLOW;
608 }
609 break;
610 }
611
612 RTENV_UNLOCK(pIntEnv);
613 }
614 return rc;
615}
616RT_EXPORT_SYMBOL(RTEnvGetEx);
617
618
619RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar)
620{
621 AssertPtrReturn(pszVar, false);
622
623 bool fExists = false;
624 if (Env == RTENV_DEFAULT)
625 {
626#ifdef RTENV_IMPLEMENTS_UTF8_DEFAULT_ENV_API
627 fExists = RTEnvExistsUtf8(pszVar);
628#else
629 /*
630 * Since RTEnvExist isn't UTF-8 clean and actually expects the strings
631 * to be in the current code page (codeset), we'll do the necessary
632 * conversions here.
633 */
634 char *pszVarOtherCP;
635 int rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar);
636 if (RT_SUCCESS(rc))
637 {
638 fExists = RTEnvExist(pszVarOtherCP);
639 RTStrFree(pszVarOtherCP);
640 }
641#endif
642 }
643 else
644 {
645 PRTENVINTERNAL pIntEnv = Env;
646 AssertPtrReturn(pIntEnv, false);
647 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, false);
648
649 RTENV_LOCK(pIntEnv);
650
651 /*
652 * Simple search.
653 */
654 const size_t cchVar = strlen(pszVar);
655 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
656 if ( !pIntEnv->pfnCompare(pIntEnv->papszEnv[iVar], pszVar, cchVar)
657 && pIntEnv->papszEnv[iVar][cchVar] == '=')
658 {
659 fExists = true;
660 break;
661 }
662
663 RTENV_UNLOCK(pIntEnv);
664 }
665 return fExists;
666}
667RT_EXPORT_SYMBOL(RTEnvExistEx);
668
669
670RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env)
671{
672 const char * const *papszRet;
673 if (Env == RTENV_DEFAULT)
674 {
675 /** @todo fix this API it's fundamentally wrong! */
676 papszRet = rtEnvDefault();
677 if (!papszRet)
678 {
679 static const char * const s_papszDummy[2] = { NULL, NULL };
680 papszRet = &s_papszDummy[0];
681 }
682 }
683 else
684 {
685 PRTENVINTERNAL pIntEnv = Env;
686 AssertPtrReturn(pIntEnv, NULL);
687 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, NULL);
688
689 RTENV_LOCK(pIntEnv);
690
691 /*
692 * Free any old envp.
693 */
694 if (pIntEnv->papszEnvOtherCP)
695 {
696 for (size_t iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++)
697 {
698 RTStrFree(pIntEnv->papszEnvOtherCP[iVar]);
699 pIntEnv->papszEnvOtherCP[iVar] = NULL;
700 }
701 RTMemFree(pIntEnv->papszEnvOtherCP);
702 pIntEnv->papszEnvOtherCP = NULL;
703 }
704
705 /*
706 * Construct a new envp with the strings in the process code set.
707 */
708 char **papsz;
709 papszRet = pIntEnv->papszEnvOtherCP = papsz = (char **)RTMemAlloc(sizeof(char *) * (pIntEnv->cVars + 1));
710 if (papsz)
711 {
712 papsz[pIntEnv->cVars] = NULL;
713 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
714 {
715 int rc = RTStrUtf8ToCurrentCP(&papsz[iVar], pIntEnv->papszEnv[iVar]);
716 if (RT_FAILURE(rc))
717 {
718 /* RTEnvDestroy / we cleans up later. */
719 papsz[iVar] = NULL;
720 AssertRC(rc);
721 papszRet = NULL;
722 break;
723 }
724 }
725 }
726
727 RTENV_UNLOCK(pIntEnv);
728 }
729 return papszRet;
730}
731RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
732
733
734/**
735 * RTSort callback for comparing two environment variables.
736 *
737 * @returns -1, 0, 1. See PFNRTSORTCMP.
738 * @param pvElement1 Variable 1.
739 * @param pvElement2 Variable 2.
740 * @param pvUser Ignored.
741 */
742DECLCALLBACK(int) rtEnvSortCompare(const void *pvElement1, const void *pvElement2, void *pvUser)
743{
744 NOREF(pvUser);
745 int iDiff = strcmp((const char *)pvElement1, (const char *)pvElement2);
746 if (iDiff < 0)
747 iDiff = -1;
748 else if (iDiff > 0)
749 iDiff = 1;
750 return iDiff;
751}
752
753
754RTDECL(int) RTEnvQueryUtf16Block(RTENV hEnv, PRTUTF16 *ppwszzBlock)
755{
756 RTENV hClone = NIL_RTENV;
757 PRTENVINTERNAL pIntEnv;
758 int rc;
759
760 /*
761 * Validate / simplify input.
762 */
763 if (hEnv == RTENV_DEFAULT)
764 {
765 rc = RTEnvClone(&hClone, RTENV_DEFAULT);
766 if (RT_FAILURE(rc))
767 return rc;
768 pIntEnv = hClone;
769 }
770 else
771 {
772 pIntEnv = hEnv;
773 AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE);
774 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE);
775 rc = VINF_SUCCESS;
776 }
777
778 RTENV_LOCK(pIntEnv);
779
780 /*
781 * Sort it first.
782 */
783 RTSortApvShell((void **)pIntEnv->papszEnv, pIntEnv->cVars, rtEnvSortCompare, pIntEnv);
784
785 /*
786 * Calculate the size.
787 */
788 size_t cwc;
789 size_t cwcTotal = 2;
790 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
791 {
792 rc = RTStrCalcUtf16LenEx(pIntEnv->papszEnv[iVar], RTSTR_MAX, &cwc);
793 AssertRCBreak(rc);
794 cwcTotal += cwc + 1;
795 }
796
797 PRTUTF16 pwszzBlock = NULL;
798 if (RT_SUCCESS(rc))
799 {
800 /*
801 * Perform the conversion.
802 */
803 PRTUTF16 pwszz = pwszzBlock = (PRTUTF16)RTMemAlloc(cwcTotal * sizeof(RTUTF16));
804 if (pwszz)
805 {
806 size_t cwcLeft = cwcTotal;
807 for (size_t iVar = 0; iVar < pIntEnv->cVars; iVar++)
808 {
809 rc = RTStrToUtf16Ex(pIntEnv->papszEnv[iVar], RTSTR_MAX,
810 &pwszz, cwcTotal - (pwszz - pwszzBlock), &cwc);
811 AssertRCBreak(rc);
812 pwszz += cwc + 1;
813 cwcLeft -= cwc + 1;
814 AssertBreakStmt(cwcLeft >= 2, rc = VERR_INTERNAL_ERROR_3);
815 }
816 AssertStmt(cwcLeft == 2 || RT_FAILURE(rc), rc = VERR_INTERNAL_ERROR_2);
817 if (RT_SUCCESS(rc))
818 {
819 pwszz[0] = '\0';
820 pwszz[1] = '\0';
821 }
822 else
823 {
824 RTMemFree(pwszzBlock);
825 pwszzBlock = NULL;
826 }
827 }
828 else
829 rc = VERR_NO_MEMORY;
830 }
831
832 RTENV_UNLOCK(pIntEnv);
833
834 if (hClone != NIL_RTENV)
835 RTEnvDestroy(hClone);
836 if (RT_SUCCESS(rc))
837 *ppwszzBlock = pwszzBlock;
838 return rc;
839}
840RT_EXPORT_SYMBOL(RTEnvGetExecEnvP);
841
842
843RTDECL(void) RTEnvFreeUtf16Block(PRTUTF16 pwszzBlock)
844{
845 RTMemFree(pwszzBlock);
846}
847RT_EXPORT_SYMBOL(RTEnvFreeUtf16Block);
848
849
850RTDECL(uint32_t) RTEnvCountEx(RTENV hEnv)
851{
852 PRTENVINTERNAL pIntEnv = hEnv;
853 AssertPtrReturn(pIntEnv, UINT32_MAX);
854 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, UINT32_MAX);
855
856 RTENV_LOCK(pIntEnv);
857 uint32_t cVars = (uint32_t)pIntEnv->cVars;
858 RTENV_UNLOCK(pIntEnv);
859
860 return cVars;
861}
862RT_EXPORT_SYMBOL(RTEnvCountEx);
863
864
865RTDECL(uint32_t) RTEnvGetByIndexEx(RTENV hEnv, uint32_t iVar, char *pszVar, size_t cbVar, char *pszValue, size_t cbValue)
866{
867 PRTENVINTERNAL pIntEnv = hEnv;
868 AssertPtrReturn(pIntEnv, UINT32_MAX);
869 AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, UINT32_MAX);
870 if (cbVar)
871 AssertPtrReturn(pszVar, VERR_INVALID_POINTER);
872 if (cbValue)
873 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
874
875 RTENV_LOCK(pIntEnv);
876
877 int rc;
878 if (iVar < pIntEnv->cVars)
879 {
880 const char *pszSrcVar = pIntEnv->papszEnv[iVar];
881 const char *pszSrcValue = strchr(pszSrcVar, '=');
882 bool fHasEqual = pszSrcValue != NULL;
883 if (pszSrcValue)
884 pszSrcValue++;
885 else
886 pszSrcValue = strchr(pszSrcVar, '\0');
887 rc = VINF_SUCCESS;
888 if (cbVar)
889 rc = RTStrCopyEx(pszVar, cbVar, pszSrcVar, pszSrcValue - pszSrcVar - fHasEqual);
890 if (cbValue)
891 {
892 int rc2 = RTStrCopy(pszValue, cbValue, pszSrcValue);
893 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
894 rc = rc2;
895 }
896 }
897 else
898 rc = VERR_ENV_VAR_NOT_FOUND;
899
900 RTENV_UNLOCK(pIntEnv);
901
902 return rc;
903}
904RT_EXPORT_SYMBOL(RTEnvGetByIndexEx);
905
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