VirtualBox

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

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

RTEnv: Use the unicode CRT APIs on windows to avoid lost-in-translation issues.

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