VirtualBox

Changeset 4475

Show
Ignore:
Timestamp:
09/01/07 03:21:19 (1 year ago)
Author:
vboxsync
Message:

Some adjustments to RTEnv and RTProcCreate. Should work on darwin now.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/iprt/env.h

    r4071 r4475  
    3030#ifdef IN_RING3 
    3131 
    32  
    33 /** 
    34  * Checks if an environment variable exists. 
    35  *  
    36  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    37  *  
    38  * @param   pszVar      The environment variable name. 
     32/** Special handle that indicates the default process environment. */ 
     33#define RTENV_DEFAULT   ((RTENV)~(uintptr_t)0) 
     34 
     35/** 
     36 * Creates an empty environment block. 
     37 *  
     38 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     39 *  
     40 * @param   pEnv        Where to store the handle of the new environment block. 
     41 */ 
     42RTDECL(int) RTEnvCreate(PRTENV pEnv); 
     43 
     44/** 
     45 * Creates an environment block and fill it with variables from the given 
     46 * environment array. 
     47 * 
     48 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     49 * 
     50 * @param   pEnv        Where to store the handle of the new environment block. 
     51 * @param   EnvToClone  The environment to clone. 
     52 */ 
     53RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone); 
     54 
     55/** 
     56 * Destroys an environment block. 
     57 * 
     58 * @returns IPRT status code. 
     59 * 
     60 * @param   Env     Environment block handle. 
     61 *                  Both RTENV_DEFAULT and NIL_RTENV are silently ignored. 
     62 */ 
     63RTDECL(int) RTEnvDestroy(RTENV Env); 
     64 
     65/** 
     66 * Get the execve/spawnve/main envp. 
     67 *  
     68 * All returned strings are in the current process' codepage. 
     69 * This array is only valid until the next RTEnv call. 
     70 *  
     71 * @returns Pointer to the raw array of environment variables. 
     72 * @returns NULL if Env is NULL or invalid. 
     73 *  
     74 * @param   Env     Environment block handle. 
     75 */ 
     76RTDECL(char const * const *) RTEnvGetExecEnvP(RTENV Env); 
     77 
     78 
     79/** 
     80 * Checks if an environment variable exists in the default environment block. 
     81 *  
     82 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     83 *  
     84 * @param   pszVar      The environment variable name. 
     85 * @remark  WARNING! The current implementation does not perform the appropriate  
     86 *          codeset conversion. We'll figure this out when it becomes necessary. 
    3987 */ 
    4088RTDECL(bool) RTEnvExist(const char *pszVar); 
    4189 
    4290/** 
    43  * Gets an environment variable (getenv). 
     91 * Checks if an environment variable exists in a specific environment block. 
     92 *  
     93 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     94 *  
     95 * @param   Env         The environment handle. 
     96 * @param   pszVar      The environment variable name. 
     97 */ 
     98RTDECL(bool) RTEnvExistEx(RTENV Env, const char *pszVar); 
     99 
     100/** 
     101 * Gets an environment variable from the default environment block. (getenv). 
    44102 *  
    45103 * The caller is responsible for ensuring that nobody changes the environment  
     
    49107 *  
    50108 * @param   pszVar      The environment variable name. 
     109 *  
     110 * @remark  WARNING! The current implementation does not perform the appropriate  
     111 *          codeset conversion. We'll figure this out when it becomes necessary. 
    51112 */ 
    52113RTDECL(const char *) RTEnvGet(const char *pszVar); 
     114 
     115/** 
     116 * Gets an environment variable in a specific environment block. 
     117 *  
     118 * @returns IPRT status code. 
     119 *  
     120 * @param   Env         The environment handle. 
     121 * @param   pszVar      The environment variable name. 
     122 * @param   pszValue    Where to put the buffer. 
     123 * @param   cbValue     The size of the value buffer. 
     124 * @param   pcchActual  Returns the actual value string length. Optional. 
     125 */ 
     126RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual); 
    53127 
    54128/** 
     
    59133 * @param   pszVarEqualValue    The variable '=' value string. If the value and '=' is  
    60134 *                              omitted, the variable is removed from the environment. 
     135 *  
     136 * @remark Don't assume the value is copied. 
     137 * @remark  WARNING! The current implementation does not perform the appropriate  
     138 *          codeset conversion. We'll figure this out when it becomes necessary. 
    61139 */ 
    62140RTDECL(int) RTEnvPut(const char *pszVarEqualValue); 
    63141 
    64142/** 
    65  * Sets an environment variable (setenv(,,1)). 
    66  *  
    67  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    68  *  
    69  * @param   pszVar      The environment variable name. 
    70  * @param   pszValue    The environment variable value. 
    71  */ 
    72 RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); 
    73  
    74 /** @todo Add the missing environment APIs: safe, printf like, and various modifications. */ 
    75  
    76 /** 
    77  * Creates an empty environment block. 
    78  *  
    79  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    80  *  
    81  * @param   pEnv        Where to store the handle of the environment block. 
    82  */ 
    83 RTDECL(int) RTEnvCreate(PRTENV pEnv); 
    84  
    85 /** 
    86  * Destroys an environment block. 
    87  * 
    88  * @returns IPRT status code. 
    89  * 
    90  * @param   Env     Handle of the environment block. 
    91  */ 
    92 RTDECL(int) RTEnvDestroy(RTENV Env); 
    93  
    94 /** 
    95  * Creates an environment block and fill it with variables from the given 
    96  * environment array. 
    97  * 
    98  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    99  * 
    100  * @param   pEnv        Where to store the handle of the environment block. 
    101  * @param   apszEnv     Pointer to the NULL-terminated array of environment 
    102  *                      variables. If NULL, the current process' environment 
    103  *                      will be cloned. 
    104  */ 
    105 RTDECL(int) RTEnvClone(PRTENV pEnv, char const *const *apszEnv); 
    106  
    107 /** @todo later */ 
    108 /* 
    109 RTDECL(int) RTEnvCloneEx(PRTENV pEnv, const RTENV Env); 
    110  
    111 RTDECL(int) RTEnvExistEx(RTENV Env, const char *pszVar); 
    112 RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); 
    113 RTDECL(int) RTEnvGetEx(RTENV Env, const char *pszVar, const char **ppszValue); 
    114 RTDECL(int) RTEnvCountEx(RTENV Env, size_t *cbCount); 
    115 */ 
    116  
    117 /** 
    118  * Puts a 'variable=value' string into the environment. 
    119  * 
    120  * The supplied string must be in the current process' codepage. 
    121  * This function makes a copy of the supplied string. 
     143 * Puts a copy of the passed in 'variable=value' string into the environment block. 
    122144 *  
    123145 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     
    130152 
    131153/** 
    132  * Returns a raw pointer to the array of environment variables of the given 
    133  * environment block where every variable is a string in format 
    134  * 'variable=value'. 
    135  * 
    136  * All returned strings are in the current process' codepage. 
    137  *  
    138  * @returns Pointer to the raw array of environment variables. 
    139  * @returns NULL if Env is NULL or invalid. 
    140  *  
    141  * @param   Env                 Handle of the environment block. 
    142  */ 
    143 RTDECL(char const *const *) RTEnvGetArray(RTENV Env); 
     154 * Sets an environment variable (setenv(,,1)). 
     155 *  
     156 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     157 *  
     158 * @param   pszVar      The environment variable name. 
     159 * @param   pszValue    The environment variable value. 
     160 *  
     161 * @remark  WARNING! The current implementation does not perform the appropriate  
     162 *          codeset conversion. We'll figure this out when it becomes necessary. 
     163 */ 
     164RTDECL(int) RTEnvSet(const char *pszVar, const char *pszValue); 
     165 
     166/** 
     167 * Sets an environment variable (setenv(,,1)). 
     168 *  
     169 * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
     170 *  
     171 * @param   Env         The environment handle. 
     172 * @param   pszVar      The environment variable name. 
     173 * @param   pszValue    The environment variable value. 
     174 */ 
     175RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue); 
     176 
     177/** 
     178 * Removes an environment variable from the default environment block. 
     179 *  
     180 * @returns IPRT status code. 
     181 * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. 
     182 *  
     183 * @param   pszVar      The environment variable name. 
     184 *  
     185 * @remark  WARNING! The current implementation does not perform the appropriate  
     186 *          codeset conversion. We'll figure this out when it becomes necessary. 
     187 */ 
     188RTDECL(int) RTEnvUnset(const char *pszVar); 
     189 
     190/** 
     191 * Removes an environment variable from the specified environment block. 
     192 *  
     193 * @returns IPRT status code. 
     194 * @returns VINF_ENV_VAR_NOT_FOUND if the variable was not found. 
     195 *  
     196 * @param   Env         The environment handle. 
     197 * @param   pszVar      The environment variable name. 
     198 */ 
     199RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar); 
    144200 
    145201#endif /* IN_RING3 */ 
  • trunk/include/iprt/err.h

    r4071 r4475  
    819819/** @} */ 
    820820 
     821/** @name Environment Status Code  
     822 * @{ 
     823 */ 
     824/** The specified environment variable was not found. (RTEnvGetEx) */ 
     825#define VERR_ENV_VAR_NOT_FOUND                  (-750) 
     826/** The specified environment variable was not found. (RTEnvUnsetEx) */ 
     827#define VINF_ENV_VAR_NOT_FOUND                  (750) 
     828/** @} */ 
     829 
    821830/* SED-END */ 
    822831 
  • trunk/include/iprt/process.h

    r4071 r4475  
    117117 * @param   pszExec     Executable image to use to create the child process. 
    118118 * @param   papszArgs   Pointer to an array of arguments to the child. The array terminated by an entry containing NULL. 
    119  * @param   papszEnv    Pointer to array of environment variables for the child process. An NULL entry 
    120  *                      terminates the array. The variables are on the form '\<var\>=\<value\>'. 
    121  *                      If NULL the environment of the process will be used. 
     119 * @param   Env         Handle to the environment block for the child. 
    122120 * @param   fFlags      Flags. This is currently reserved and must be 0. 
    123121 * @param   pProcess    Where to store the process identifier on successful return. 
    124122 *                      The content is not changed on failure. NULL is allowed. 
    125123 */ 
    126 RTR3DECL(int)   RTProcCreate(const char *pszExec, const char * const *papszArgs, const char * const *papszEnv, unsigned fFlags, PRTPROCESS pProcess); 
     124RTR3DECL(int)   RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess); 
    127125 
    128126/** 
  • trunk/src/VBox/Main/MachineImpl.cpp

    r4306 r4475  
    28092809    RTPROCESS pid = NIL_RTPROCESS; 
    28102810 
    2811     RTENV env = NIL_RTENV
     2811    RTENV env = RTENV_DEFAULT
    28122812 
    28132813    if (aEnvironment) 
     
    28182818        { 
    28192819            /* clone the current environment */ 
    2820             int vrc = RTEnvClone(&env, NULL); 
    2821             AssertRCBreak (vrc, vrc = vrc); 
    2822  
    2823             vrc = RTStrUtf8ToCurrentCP (&newEnvStr, Utf8Str (aEnvironment)); 
    2824             AssertRCBreak (vrc, vrc = vrc); 
     2820            int vrc2 = RTEnvClone (&env, RTENV_DEFAULT); 
     2821            AssertRCBreak (vrc2, vrc = vrc2); 
     2822 
     2823            newEnvStr = RTStrDup(Utf8Str (aEnvironment)); 
     2824            AssertPtrBreak (newEnvStr, vrc = vrc2); 
    28252825 
    28262826            /* put new variables to the environment 
     
    28342834                    *p = '\0'; 
    28352835                    if (*var) 
    2836                         if (VBOX_FAILURE (vrc = RTEnvPutEx(env, var))) 
     2836                    { 
     2837                        char *val = strchr (var, '='); 
     2838                        if (val) 
     2839                        { 
     2840                            *val++ = '\0'; 
     2841                            vrc2 = RTEnvSetEx (env, var, val); 
     2842                        } 
     2843                        else 
     2844                            vrc2 = RTEnvUnsetEx (env, var); 
     2845                        if (VBOX_FAILURE (vrc2)) 
    28372846                            break; 
     2847                    } 
    28382848                    var = p + 1; 
    28392849                } 
    28402850            } 
    2841             if (VBOX_SUCCESS (vrc) && *var) 
    2842                 vrc = RTEnvPutEx(env, var); 
    2843  
    2844             AssertRCBreak (vrc, vrc = vrc); 
     2851            if (VBOX_SUCCESS (vrc2) && *var) 
     2852                vrc2 = RTEnvPutEx (env, var); 
     2853 
     2854            AssertRCBreak (vrc2, vrc = vrc2); 
    28452855        } 
    28462856        while (0); 
     
    28682878        const char * args[] = {path, "-comment", name, "-startvm", idStr, 0 }; 
    28692879#endif 
    2870         vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid); 
     2880        vrc = RTProcCreate (path, args, env, 0, &pid); 
    28712881    } 
    28722882    else 
     
    28852895        const char * args[] = {path, "-comment", name, "-startvm", idStr, 0 }; 
    28862896#endif 
    2887         vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid); 
     2897        vrc = RTProcCreate (path, args, env, 0, &pid); 
    28882898    } 
    28892899    else 
     
    29022912        const char * args[] = {path, "-comment", name, "-startvm", idStr, "-capture", 0 }; 
    29032913#endif 
    2904         vrc = RTProcCreate (path, args, RTEnvGetArray (env), 0, &pid); 
     2914        vrc = RTProcCreate (path, args, env, 0, &pid); 
    29052915    } 
    29062916    else 
    29072917    { 
    2908         if (env != NIL_RTENV) 
    2909             RTEnvDestroy (env); 
     2918        RTEnvDestroy (env); 
    29102919        return setError (E_INVALIDARG, 
    29112920            tr ("Invalid session type: '%ls'"), aType); 
    29122921    } 
    29132922 
    2914     if (env != NIL_RTENV) 
    2915         RTEnvDestroy (env); 
     2923    RTEnvDestroy (env); 
    29162924 
    29172925    if (VBOX_FAILURE (vrc)) 
  • trunk/src/VBox/Main/VirtualBoxImpl.cpp

    r4260 r4475  
    4444#include <iprt/thread.h> 
    4545#include <iprt/process.h> 
     46#include <iprt/env.h> 
    4647#include <iprt/cpputils.h> 
    4748 
     
    23382339        { 
    23392340            const char *args[] = { exePath, "/Helper", client.name(), 0 }; 
    2340             vrc = RTProcCreate (exePath, args, NULL, 0, &pid); 
     2341            vrc = RTProcCreate (exePath, args, RTENV_DEFAULT, 0, &pid); 
    23412342            if (VBOX_FAILURE (vrc)) 
    23422343            { 
  • trunk/src/VBox/Main/linux/server_module.cpp

    r4071 r4475  
    4949#include <iprt/path.h> 
    5050#include <iprt/process.h> 
     51#include <iprt/env.h> 
    5152#include <iprt/thread.h> 
    5253 
     
    179180                const char *args[] = { VBoxSVCPath, "--automate", 0 }; 
    180181                RTPROCESS pid = NIL_RTPROCESS; 
    181                 vrc = RTProcCreate (VBoxSVCPath, args, NULL, 0, &pid); 
     182                vrc = RTProcCreate (VBoxSVCPath, args, RTENV_DEFAULT, 0, &pid); 
    182183                if (VBOX_FAILURE (vrc)) 
    183184                { 
  • trunk/src/VBox/Runtime/VBox/RTAssertDoBreakpoint-vbox.cpp

    r4071 r4475  
    8787        }; 
    8888        RTPROCESS Process; 
    89         int rc = RTProcCreate(apszArgs[0], &apszArgs[0], NULL, 0, &Process); 
     89        int rc = RTProcCreate(apszArgs[0], &apszArgs[0], RTENV_DEFAULT, 0, &Process); 
    9090        if (RT_FAILURE(rc)) 
    9191            return false; 
  • trunk/src/VBox/Runtime/generic/env-generic.cpp

    r4474 r4475  
    2323#include <iprt/assert.h> 
    2424#include <iprt/alloc.h> 
     25#include <iprt/alloca.h> 
    2526#include <iprt/string.h> 
    2627#include <iprt/err.h> 
    27  
    28 #if defined(RT_OS_WINDOWS) 
    29 # include <stdlib.h> 
    30 #else 
     28#include "internal/magics.h" 
     29 
     30#include <stdlib.h> 
     31#if !defined(RT_OS_WINDOWS) 
    3132# include <unistd.h> 
    3233#endif 
    33  
    34 #include <string.h> 
    35  
    3634#if defined(RT_OS_SOLARIS) 
    37 /* It's an implementation detail in Solaris, see  
    38  * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/gen/getenv.c line 50. 
     35__BEGIN_DECLS 
     36extern char **environ; 
     37__END_DECLS 
     38#endif 
     39 
     40/******************************************************************************* 
     41*   Defined Constants And Macros                                               * 
     42*******************************************************************************/ 
     43/** Macro that unlocks the specified environment block. */ 
     44#define RTENV_LOCK(pEnvInt)     do { } while (0) 
     45/** Macro that unlocks the specified environment block. */ 
     46#define RTENV_UNLOCK(pEnvInt)   do { } while (0) 
     47 
     48 
     49/******************************************************************************* 
     50*   Structures and Typedefs                                                    * 
     51*******************************************************************************/ 
     52/** 
     53 * The internal representation of a (non-default) environment. 
    3954 */ 
    40 extern char **environ; 
    41 #endif 
    42  
    43 struct RTENVINTERNAL 
    44 
    45     /* Array of environment variables. */ 
    46     char **apszEnv; 
    47     /* Count of variables in the array. */ 
    48     size_t cCount; 
    49     /* Capacity (real size) of the array. This includes space for the 
    50      * terminating NULL element (for compatibility with the C library), so 
    51      * that cCount <= cCapacity - 1. */ 
    52     size_t cCapacity; 
    53 }; 
    54  
    55 #define RTENV_GROW_SIZE 16 
    56  
    57 static int rtEnvCreate(struct RTENVINTERNAL **ppIntEnv, size_t cCapacity) 
    58 
    59     int rc; 
    60  
     55typedef struct RTENVINTERNAL 
     56
     57    /** Magic value . */ 
     58    uint32_t    u32Magic; 
     59    /** Number of variables in the array.  
     60     * This does not include the terminating NULL entry. */ 
     61    size_t      cVars; 
     62    /** Capacity (allocated size) of the array.  
     63     * This includes space for the terminating NULL element (for compatibility  
     64     * with the C library), so that c <= cCapacity - 1. */ 
     65    size_t      cAllocated; 
     66    /** Array of environment variables. */ 
     67    char      **papszEnv; 
     68    /** Array of environment variables in the process CP.  
     69     * This get (re-)constructed when RTEnvGetExecEnvP method is called. */ 
     70    char      **papszEnvOtherCP; 
     71} RTENVINTERNAL, *PRTENVINTERNAL; 
     72 
     73/** The allocation granularity of the RTENVINTERNAL::papszEnv memory. */ 
     74#define RTENV_GROW_SIZE     16 
     75 
     76 
     77/** 
     78 * Internal worker that resolves the pointer to the default  
     79 * process environment. (environ) 
     80 *  
     81 * @returns Pointer to the default environment. 
     82 *          This may be NULL. 
     83 */ 
     84static const char * const *rtEnvDefault(void) 
     85
     86#ifdef RT_OS_DARWIN 
     87    return *(_NSGetEnviron()); 
     88#elif defined(RT_OS_L4)   
     89    /* So far, our L4 libraries do not include environment support. */ 
     90    return NULL; 
     91#else 
     92    return environ; 
     93#endif  
     94
     95 
     96 
     97/** 
     98 * Internal worker that creates an environment handle with a specified capacity. 
     99 *  
     100 * @returns IPRT status code. 
     101 * @param   ppIntEnv    Where to store the result. 
     102 * @param   cAllocated  The initial array size. 
     103 */ 
     104static int rtEnvCreate(PRTENVINTERNAL *ppIntEnv, size_t cAllocated) 
     105
    61106    /* 
    62107     * Allocate environment handle. 
    63108     */ 
    64     struct RTENVINTERNAL *pIntEnv = (struct RTENVINTERNAL *)RTMemAlloc(sizeof(struct RTENVINTERNAL)); 
     109    PRTENVINTERNAL pIntEnv = (PRTENVINTERNAL)RTMemAlloc(sizeof(*pIntEnv)); 
    65110    if (pIntEnv) 
    66111    { 
    67         cCapacity = (cCapacity + RTENV_GROW_SIZE - 1) 
    68                     / RTENV_GROW_SIZE * RTENV_GROW_SIZE; 
    69112        /* 
    70113         * Pre-allocate the variable array. 
    71114         */ 
    72         pIntEnv->cCount = 0
    73         pIntEnv->cCapacity = cCapacity
    74         pIntEnv->apszEnv = (char **)RTMemAlloc(sizeof(pIntEnv->apszEnv[0]) * pIntEnv->cCapacity)
    75         if (pIntEnv->apszEnv) 
    76         { 
    77             /* add terminating NULL */ 
    78             pIntEnv->apszEnv[0] = NULL; 
     115        pIntEnv->u32Magic = RTENV_MAGIC
     116        pIntEnv->papszEnvOtherCP = NULL
     117        pIntEnv->cVars = 0
     118        pIntEnv->cAllocated = RT_ALIGN_Z(RT_MAX(cAllocated, RTENV_GROW_SIZE), RTENV_GROW_SIZE); 
     119        pIntEnv->papszEnv = (char **)RTMemAllocZ(sizeof(pIntEnv->papszEnv[0]) * pIntEnv->cAllocated); 
     120        if (pIntEnv->papszEnv) 
     121        { 
    79122            *ppIntEnv = pIntEnv; 
    80123            return VINF_SUCCESS; 
    81124        } 
    82125 
    83         rc = VERR_NO_MEMORY; 
    84126        RTMemFree(pIntEnv); 
    85127    }     
     128 
     129    return VERR_NO_MEMORY; 
     130} 
     131 
     132 
     133RTDECL(int) RTEnvCreate(PRTENV pEnv) 
     134{ 
     135    AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 
     136    return rtEnvCreate(pEnv, RTENV_GROW_SIZE); 
     137} 
     138 
     139 
     140RTDECL(int) RTEnvDestroy(RTENV Env) 
     141{ 
     142    /*  
     143     * Ignore NIL_RTENV and validate input. 
     144     */ 
     145    if (    Env == NIL_RTENV 
     146        ||  Env == RTENV_DEFAULT) 
     147        return VINF_SUCCESS; 
     148 
     149    PRTENVINTERNAL pIntEnv = Env; 
     150    AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 
     151    AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 
     152 
     153    /*  
     154     * Do the cleanup. 
     155     */ 
     156    RTENV_LOCK(pIntEnv); 
     157    pIntEnv->u32Magic++; 
     158    size_t iVar = pIntEnv->cVars; 
     159    while (iVar-- > 0) 
     160        RTStrFree(pIntEnv->papszEnv[iVar]); 
     161    RTMemFree(pIntEnv->papszEnv); 
     162    pIntEnv->papszEnv = NULL; 
     163 
     164    if (pIntEnv->papszEnvOtherCP) 
     165    { 
     166        for (iVar = 0; pIntEnv->papszEnvOtherCP[iVar]; iVar++) 
     167        { 
     168            RTStrFree(pIntEnv->papszEnvOtherCP[iVar]); 
     169            pIntEnv->papszEnvOtherCP[iVar] = NULL; 
     170        } 
     171        RTMemFree(pIntEnv->papszEnvOtherCP); 
     172        pIntEnv->papszEnvOtherCP = NULL; 
     173    } 
     174 
     175    RTENV_UNLOCK(pIntEnv); 
     176    /*RTCritSectDelete(&pIntEnv->CritSect) */ 
     177    RTMemFree(pIntEnv); 
     178     
     179    return VINF_SUCCESS; 
     180} 
     181 
     182 
     183RTDECL(int) RTEnvClone(PRTENV pEnv, RTENV EnvToClone) 
     184{ 
     185    /* 
     186     * Validate input and figure out how many variable to clone and where to get them. 
     187     */ 
     188    size_t cVars; 
     189    const char * const *papszEnv; 
     190    PRTENVINTERNAL pIntEnvToClone; 
     191    AssertPtrReturn(pEnv, VERR_INVALID_POINTER); 
     192    if (EnvToClone == RTENV_DEFAULT) 
     193    { 
     194        pIntEnvToClone = NULL; 
     195        papszEnv = rtEnvDefault(); 
     196        cVars = 0; 
     197        if (papszEnv) 
     198            while (papszEnv[cVars]) 
     199                cVars++; 
     200    } 
    86201    else 
    87         rc = VERR_NO_MEMORY; 
    88  
     202    { 
     203        pIntEnvToClone = EnvToClone; 
     204        AssertPtrReturn(pIntEnvToClone, VERR_INVALID_HANDLE); 
     205        AssertReturn(pIntEnvToClone->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 
     206        RTENV_LOCK(pIntEnvToClone); 
     207 
     208        papszEnv = pIntEnvToClone->papszEnv; 
     209        cVars = pIntEnvToClone->cVars; 
     210    } 
     211 
     212    /* 
     213     * Create the duplicate. 
     214     */ 
     215    PRTENVINTERNAL pIntEnv; 
     216    int rc = rtEnvCreate(&pIntEnv, cVars + 1 /* NULL */); 
     217    if (RT_SUCCESS(rc)) 
     218    { 
     219        pIntEnv->cVars = cVars; 
     220        pIntEnv->papszEnv[pIntEnv->cVars] = NULL; 
     221        if (EnvToClone == RTENV_DEFAULT) 
     222        { 
     223            /* ASSUMES the default environment is in the current codepage. */ 
     224            for (size_t iVar = 0; iVar < cVars; iVar++) 
     225            { 
     226                int rc = RTStrCurrentCPToUtf8(&pIntEnv->papszEnv[iVar], papszEnv[iVar]); 
     227                if (RT_FAILURE(rc)) 
     228                { 
     229                    pIntEnv->cVars = iVar; 
     230                    RTEnvDestroy(pIntEnv); 
     231                    return rc; 
     232                } 
     233            } 
     234        } 
     235        else 
     236        { 
     237            for (size_t iVar = 0; iVar < cVars; iVar++) 
     238            { 
     239                char *pszVar = RTStrDup(papszEnv[iVar]); 
     240                if (RT_UNLIKELY(!pszVar)) 
     241                { 
     242                    RTENV_UNLOCK(pIntEnvToClone); 
     243 
     244                    pIntEnv->cVars = iVar; 
     245                    RTEnvDestroy(pIntEnv); 
     246                    return rc; 
     247                } 
     248                pIntEnv->papszEnv[iVar] = pszVar; 
     249            } 
     250        } 
     251 
     252        /* done */ 
     253        *pEnv = pIntEnv; 
     254    } 
     255 
     256    if (pIntEnvToClone) 
     257        RTENV_UNLOCK(pIntEnvToClone); 
    89258    return rc; 
    90259} 
    91260 
    92 /** 
    93  * Creates an empty environment block. 
    94  *  
    95  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    96  *  
    97  * @param   pEnv        Where to store the handle of the environment block. 
    98  */ 
    99 RTDECL(int) RTEnvCreate(PRTENV pEnv) 
    100 
    101     if (pEnv == NULL) 
    102         return VERR_INVALID_POINTER; 
    103  
    104     return rtEnvCreate(pEnv, RTENV_GROW_SIZE); 
    105 
    106  
    107 /** 
    108  * Destroys an environment block. 
    109  * 
    110  * @returns IPRT status code. 
    111  * 
    112  * @param   Env     Handle of the environment block. 
    113  */ 
    114 RTDECL(int) RTEnvDestroy(RTENV Env) 
    115 
    116     struct RTENVINTERNAL *pIntEnv = Env; 
    117  
    118     if (pIntEnv == NULL) 
    119         return VERR_INVALID_HANDLE; 
    120  
    121     for (size_t i = 0; i < pIntEnv->cCount; ++i) 
    122     { 
    123         RTStrFree(pIntEnv->apszEnv[i]); 
    124     } 
    125  
    126     RTMemFree(pIntEnv->apszEnv); 
    127     RTMemFree(pIntEnv); 
    128     return VINF_SUCCESS; 
    129 
    130  
    131 /** 
    132  * Creates an environment block and fill it with variables from the given 
    133  * environment array. 
    134  * 
    135  * @returns IPRT status code. Typical error is VERR_NO_MEMORY. 
    136  * 
    137  * @param   pEnv        Where to store the handle of the environment block. 
    138  * @param   apszEnv     Pointer to the NULL-terminated array of environment 
    139  *                      variables. If NULL, the current process' environment 
    140  *                      will be cloned. 
    141  */ 
    142 RTDECL(int) RTEnvClone(PRTENV pEnv, char const *const *apszEnv) 
    143 
    144 #ifndef RT_OS_L4  /* So far, our L4 libraries do not include environment support. */ 
    145     if (apszEnv == NULL) 
    146         apszEnv = environ; 
    147  
    148     /* count the number of varialbes to clone */ 
    149     size_t cEnv = 0; 
    150     for (; apszEnv[cEnv]; ++cEnv) {} 
    151 #else 
    152     size_t cEnv = 0; 
    153 #endif 
    154  
    155     struct RTENVINTERNAL *pIntEnv; 
    156  
    157     int rc = rtEnvCreate(&pIntEnv, cEnv + 1 /* NULL */); 
    158     if (RT_FAILURE(rc)) 
    159         return rc; 
    160  
    161 #ifndef RT_OS_L4 
    162     for (size_t i = 0; i < cEnv; ++i) 
    163     { 
    164         char *pszVar = RTStrDup(environ[i]); 
    165         if (pszVar == NULL) 
    166         { 
     261 
     262RTDECL(int) RTEnvPutEx(RTENV Env, const char *pszVarEqualValue) 
     263
     264    int rc; 
     265    AssertPtrReturn(pszVarEqualValue, VERR_INVALID_POINTER); 
     266    const char *pszEq = strchr(pszVarEqualValue, '='); 
     267    if (!pszEq) 
     268        rc = RTEnvUnsetEx(Env, pszVarEqualValue); 
     269    else 
     270    { 
     271        /*  
     272         * Make a copy of the variable name so we can terminate it 
     273         * properly and then pass the request on to RTEnvSetEx. 
     274         */ 
     275        const char *pszValue = pszEq + 1; 
     276 
     277        size_t cchVar = pszEq - pszVarEqualValue; 
     278        Assert(cchVar < 1024); 
     279        char *pszVar = (char *)alloca(cchVar + 1); 
     280        memcpy(pszVar, pszVarEqualValue, cchVar); 
     281        pszVar[cchVar] = '\0'; 
     282 
     283        rc = RTEnvSetEx(Env, pszVar, pszValue); 
     284    } 
     285    return rc; 
     286
     287 
     288 
     289RTDECL(int) RTEnvSetEx(RTENV Env, const char *pszVar, const char *pszValue) 
     290
     291    AssertPtrReturn(pszVar, VERR_INVALID_POINTER); 
     292    AssertPtrReturn(*pszVar, VERR_INVALID_PARAMETER); 
     293    AssertPtrReturn(pszValue, VERR_INVALID_POINTER); 
     294 
     295    int rc; 
     296    if (Env == RTENV_DEFAULT) 
     297    { 
     298        /*  
     299         * Since RTEnvPut isn't UTF-8 clean and actually expects the strings 
     300         * to be in the current code page (codeset), we'll do the necessary  
     301         * conversions here. 
     302         */ 
     303        char *pszVarOtherCP; 
     304        rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); 
     305        if (RT_SUCCESS(rc)) 
     306        { 
     307            char *pszValueOtherCP; 
     308            rc = RTStrUtf8ToCurrentCP(&pszValueOtherCP, pszValue); 
     309            if (RT_SUCCESS(rc)) 
     310            { 
     311                rc = RTEnvSet(pszVarOtherCP, pszValueOtherCP); 
     312                RTStrFree(pszValueOtherCP); 
     313            } 
     314            RTStrFree(pszVarOtherCP); 
     315        } 
     316    } 
     317    else 
     318    { 
     319        PRTENVINTERNAL pIntEnv = Env; 
     320        AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 
     321        AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 
     322 
     323        /* 
     324         * Create the variable string. 
     325         */ 
     326        const size_t cchVar = strlen(pszVar); 
     327        const size_t cchValue = strlen(pszValue); 
     328        char *pszEntry = (char *)RTMemAlloc(cchVar + cchValue + 2); 
     329        if (pszEntry) 
     330        { 
     331            memcpy(pszEntry, pszVar, cchVar); 
     332            pszEntry[cchVar] = '='; 
     333            memcpy(&pszEntry[cchVar + 1], pszValue, cchValue + 1); 
     334 
     335            RTENV_LOCK(pIntEnv); 
     336 
     337            /* 
     338             * Find the location of the variable. (iVar = cVars if new) 
     339             */ 
     340            rc = VINF_SUCCESS; 
     341            size_t iVar; 
     342            for (iVar = 0; iVar < pIntEnv->cVars; iVar++) 
     343                if (    !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar) 
     344                    &&  pIntEnv->papszEnv[iVar][cchVar] == '=') 
     345                    break; 
     346            if (iVar < pIntEnv->cVars) 
     347            { 
     348                /*  
     349                 * Replace the current entry. Simple. 
     350                 */ 
     351                RTMemFree(pIntEnv->papszEnv[iVar]); 
     352                pIntEnv->papszEnv[iVar] = pszEntry; 
     353            } 
     354            else 
     355            { 
     356                /* 
     357                 * Adding a new variable. Resize the array if required  
     358                 * and then insert the new value at the end. 
     359                 */ 
     360                if (pIntEnv->cVars + 2 > pIntEnv->cAllocated) 
     361                { 
     362                    void *pvNew = RTMemRealloc(pIntEnv->papszEnv, sizeof(char *) * (pIntEnv->cAllocated + RTENV_GROW_SIZE)); 
     363                    if (!pvNew) 
     364                        rc = VERR_NO_MEMORY; 
     365                    else 
     366                    { 
     367                        pIntEnv->papszEnv = (char **)pvNew; 
     368                        pIntEnv->cAllocated += RTENV_GROW_SIZE; 
     369                        for (size_t iNewVar = pIntEnv->cVars; iNewVar < pIntEnv->cAllocated; iNewVar++) 
     370                            pIntEnv->papszEnv[iNewVar] = NULL; 
     371                    } 
     372                } 
     373                if (RT_SUCCESS(rc)) 
     374                { 
     375                    pIntEnv->papszEnv[iVar] = pszEntry; 
     376                    pIntEnv->papszEnv[iVar + 1] = NULL; /* this isn't really necessary, but doesn't hurt. */ 
     377                    pIntEnv->cVars++; 
     378                    Assert(pIntEnv->cVars == iVar + 1); 
     379                } 
     380            } 
     381     
     382            RTENV_UNLOCK(pIntEnv); 
     383 
     384            if (RT_FAILURE(rc)) 
     385                RTMemFree(pszEntry); 
     386        } 
     387        else 
    167388            rc = VERR_NO_MEMORY; 
    168             break; 
    169         } 
    170  
    171         pIntEnv->apszEnv[i] = pszVar; 
    172         ++pIntEnv->cCount; 
    173     } 
    174 #endif 
    175  
    176     if (RT_SUCCESS(rc)) 
    177     { 
    178         /* add terminating NULL */ 
    179         pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 
    180         *pEnv = pIntEnv; 
    181         return VINF_SUCCESS; 
    182     } 
    183  
    184     RTEnvDestroy(pIntEnv); 
     389    } 
    185390    return rc; 
    186391} 
    187392 
    188 static int rtEnvRemoveVars(struct RTENVINTERNAL *pIntEnv, size_t iFrom, size_t cVars) 
    189 
    190     AssertReturn (iFrom < pIntEnv->cCount, VERR_GENERAL_FAILURE); 
    191     AssertReturn (cVars <= pIntEnv->cCount, VERR_GENERAL_FAILURE); 
    192     AssertReturn (cVars > 0, VERR_GENERAL_FAILURE); 
    193  
    194     /* free variables */ 
    195     size_t iTo = iFrom + cVars - 1; 
    196     for (size_t i = iFrom; i <= iTo; ++i) 
    197         RTStrFree(pIntEnv->apszEnv[i]); 
    198  
    199     /* remove the hole */ 
    200     size_t cToMove = pIntEnv->cCount - iTo - 1; 
    201     if (cToMove) 
    202         memcpy(&pIntEnv->apszEnv[iFrom], &pIntEnv->apszEnv[iTo + 1], 
    203                sizeof(pIntEnv->apszEnv[0]) * cToMove); 
    204  
    205     pIntEnv->cCount -= cVars; 
    206  
    207     /// @todo resize pIntEnv->apszEnv to a multiply of RTENV_GROW_SIZE to keep 
    208     /// it compact 
    209  
    210     /* add terminating NULL */ 
    211     pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 
    212     return VINF_SUCCESS; 
    213 
    214  
    215 static int rtEnvInsertVars(struct RTENVINTERNAL *pIntEnv, size_t iAt, size_t cVars) 
    216 
    217     AssertReturn (iAt <= pIntEnv->cCount, VERR_GENERAL_FAILURE); 
     393 
     394RTDECL(int) RTEnvUnsetEx(RTENV Env, const char *pszVar) 
     395
     396    AssertPtrReturn(pszVar, VERR_INVALID_POINTER); 
     397    AssertPtrReturn(*pszVar, VERR_INVALID_PARAMETER); 
    218398 
    219399    int rc; 
    220  
    221     size_t cCapacity = (pIntEnv->cCount + cVars + 1 /* NULL */ + RTENV_GROW_SIZE - 1) 
    222                        / RTENV_GROW_SIZE * RTENV_GROW_SIZE; 
    223     bool needAlloc = cCapacity != pIntEnv->cCapacity; 
    224  
    225     /* allocate a new variable array if needed */ 
    226     char **apszEnv = needAlloc ? (char **)RTMemAlloc(sizeof(apszEnv[0]) * cCapacity) 
    227                                : pIntEnv->apszEnv; 
    228     if (apszEnv) 
    229     { 
    230         /* copy old variables */ 
    231         if (needAlloc && iAt) 
    232             memcpy (apszEnv, pIntEnv->apszEnv, sizeof(apszEnv[0]) * iAt); 
    233         if (iAt < pIntEnv->cCount) 
    234             memcpy (&apszEnv[iAt + cVars], &pIntEnv->apszEnv[iAt], 
    235                     sizeof(apszEnv[0]) * pIntEnv->cCount - iAt); 
    236         /* initialize new variables with NULL */ 
    237         memset(&apszEnv[iAt], 0, sizeof(apszEnv[0]) * cVars); 
    238         /* replace the array */ 
    239         if (needAlloc) 
    240         { 
    241             RTMemFree(pIntEnv->apszEnv); 
    242             pIntEnv->apszEnv = apszEnv; 
    243             pIntEnv->cCapacity = cCapacity; 
    244         } 
    245         pIntEnv->cCount += cVars; 
    246         /* add terminating NULL */ 
    247         pIntEnv->apszEnv[pIntEnv->cCount] = NULL; 
    248         return VINF_SUCCESS; 
     400    if (Env == RTENV_DEFAULT) 
     401    { 
     402        /*  
     403         * Since RTEnvUnset isn't UTF-8 clean and actually expects the strings 
     404         * to be in the current code page (codeset), we'll do the necessary  
     405         * conversions here. 
     406         */ 
     407        char *pszVarOtherCP; 
     408        rc = RTStrUtf8ToCurrentCP(&pszVarOtherCP, pszVar); 
     409        if (RT_SUCCESS(rc)) 
     410        { 
     411            rc = RTEnvUnset(pszVarOtherCP); 
     412            RTStrFree(pszVarOtherCP); 
     413        } 
    249414    } 
    250415    else 
    251         rc = VERR_NO_MEMORY; 
    252  
     416    { 
     417        PRTENVINTERNAL pIntEnv = Env; 
     418        AssertPtrReturn(pIntEnv, VERR_INVALID_HANDLE); 
     419        AssertReturn(pIntEnv->u32Magic == RTENV_MAGIC, VERR_INVALID_HANDLE); 
     420 
     421        RTENV_LOCK(pIntEnv); 
     422 
     423        /* 
     424         * Remove all variable by the given name. 
     425         */ 
     426        rc = VINF_ENV_VAR_NOT_FOUND; 
     427        const size_t cchVar = strlen(pszVar); 
     428        size_t iVar; 
     429        for (iVar = 0; iVar < pIntEnv->cVars; iVar++) 
     430            if (    !strncmp(pIntEnv->papszEnv[iVar], pszVar, cchVar) 
     431                &&  pIntEnv->papszEnv[iVar][cchVar] == '=') 
     432            { 
     433                RTMemFree(pIntEnv->papszEnv[iVar]); 
     434                pIntEnv->cVars--; 
     435                if (pIntEnv->cVars > 0) 
     436                    pIntEnv->papszEnv[iVar] = pIntEnv->papszEnv[pIntEnv->cVars]; 
     437                pIntEnv->papszEnv[pIntEnv->cVars] = NULL; 
     438                rc = VINF_SUCCESS; 
     439                /* no break, there could be more. */ 
     440            } 
     441 
     442        RTENV_UNLOCK(pIntEnv); 
     443    } 
    253444