diff options
Diffstat (limited to 'private/crt32/misc/putenv.c')
-rw-r--r-- | private/crt32/misc/putenv.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/private/crt32/misc/putenv.c b/private/crt32/misc/putenv.c new file mode 100644 index 000000000..0e74fcbb5 --- /dev/null +++ b/private/crt32/misc/putenv.c @@ -0,0 +1,453 @@ +/*** +*putenv.c - put an environment variable into the environment +* +* Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _putenv() - adds a new variable to environment; does not +* change global environment, only the process' environment. +* +*Revision History: +* 08-08-84 RN initial version +* 02-23-88 SKS check for environment containing only the NULL string +* 05-31-88 PHG Merged DLL and normal versions +* 07-14-88 JCR Much simplified since (1) __setenvp always uses heap, and +* (2) envp array and env strings are in seperate heap blocks +* 07-03-89 PHG Now "option=" string removes string from environment +* 08-17-89 GJF Removed _NEAR_, _LOAD_DS and fixed indents. +* 09-14-89 KRS Don't give error if 'option' not defined in "option=". +* 11-20-89 GJF Added const to arg type. Also, fixed copyright. +* 03-15-90 GJF Made the calling type _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 04-05-90 GJF Made findenv() _CALLTYPE4. +* 04-26-90 JCR Bug fix if environ is NULL (stubbed out _setenvp) +* 07-25-90 SBM Removed redundant include (stdio.h) +* 10-04-90 GJF New-style function declarators. +* 01-21-91 GJF ANSI naming. +* 02-06-91 SRW Added _WIN32_ conditional for SetEnvironmentVariable +* 02-18-91 SRW Changed _WIN32_ conditional for SetEnvironmentVariable +* to be in addition to old logic instead of replacement +* 04-23-92 GJF Made findenv insensitive to the case of name for Win32. +* Also added support for 'current drive' environment +* strings in Win32. +* 04-29-92 GJF Repackaged so that _putenv_lk could be easily added for +* for Win32. +* 05-05-92 DJM POSIX not supported. +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <errno.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> +#include <internal.h> +#include <os2dll.h> +#include <memory.h> +#include <oscalls.h> + +static int _CALLTYPE4 findenv(const char *name, int len); + + +#ifdef _CRUISER_ + +/*** +*int _putenv(option) - add/replace/remove variable in environment +* +*Purpose: +* option should be of the form "option=value". If a string with the +* given option part already exists, it is replaced with the given +* string; otherwise the given string is added to the environment. +* If the string is of the form "option=", then the string is +* removed from the environment, if it exists. If the string has +* no equals sign, error is returned. +* +*Entry: +* char *option - option string to set in the environment list. +* should be of the form "option=value". +* +*Exit: +* returns 0 if OK, -1 if fails. +* +*Exceptions: +* +*Warning: +* This code will not work if variables are removed from the +* environment by deleting them from environ[]. Use _putenv("option=") +* to remove a variable. +* +*******************************************************************************/ + +int _CALLTYPE1 _putenv ( + REG3 const char *option + ) +{ + REG1 char **env; + REG4 const char *equal; + REG2 int ix; + int remove; /* 1 means remove string from environment */ + + if (!option) + return(-1); + + _mlock( _ENV_LOCK ); + + /* find the equal sign to delimit the name being searched for. + * If no equal sign, then return error + */ + + for (equal = option; *equal != '='; equal++) + if (*equal == '\0') + goto unlock_error; + + /* see if removing or adding */ + remove = (equal[1] == '\0'); + + /* see if _environ array exists */ + if (_environ == NULL) { + if (remove) + goto unlock_good; + else { + /* get an array and init it to NULL */ + if ( (_environ = malloc(sizeof(void *))) == NULL) + goto unlock_error; + *_environ = NULL; + } + } + + /* init env pointer */ + + env = _environ; + + /* See if the string is already in the environment */ + + ix = findenv(option, equal - option); + + if ((ix >= 0) && (*env != NULL)) { + /* String is already in the environment -- overwrite/remove it. + */ + if (remove) { + /* removing -- move all the later strings up */ + for ( ; env[ix] != NULL; ++ix) { + env[ix] = env[ix+1]; + } + + /* shrink the environment memory block + (ix now has number of strings, including NULL) -- + this realloc probably can't fail, since we're + shrinking a mem block, but we're careful anyway. */ + if (env = (char **) realloc(env, ix * sizeof(char *))) + _environ = env; + } + else { + /* replace the option */ + env[ix] = (char *) option; + } + } + else { + /* String is NOT in the environment */ + + if (!remove) { /* can't remove something that's not there */ + + /* Grow vector table by one */ + if (ix < 0) + ix = -ix; /* ix = length of environ table */ + + if (!(env = (char **)realloc(env, sizeof(char *) * (ix + 2)))) + goto unlock_error; + + env[ix] = (char *)option; + env[ix + 1] = NULL; + _environ = env; + } + } + +unlock_good: + _munlock( _ENV_LOCK ); + return(0); + +unlock_error: + _munlock( _ENV_LOCK ); + return -1; +} + + +/*** +*int findenv(name, len) - [STATIC] +* +*Purpose: +* Scan for the given string within the environment +* +*Entry: +* +*Exit: +* Returns the offset in "environ[]" of the given variable +* Returns the negative of the length of environ[] if not found. +* Returns 0 if the environment is empty. +* +* [NOTE: That a 0 return can mean that the environment is empty +* or that the string was found as the first entry in the array.] +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 findenv ( + const char *name, + int len + ) +{ + REG4 char **env = _environ; + REG2 const char *nm; + REG1 char *envname; + REG3 int l; + + + while (envname = *env) { + nm = name; + l = len; + while (l && *envname++ == *nm++) + l--; + + if (l == 0 && ( *envname == '=' || !*envname ) ) + return(env - _environ); + env++; + } + + return(-(env - _environ)); + +} + +#else /* _CRUISER_ */ + +#ifdef _WIN32_ + +/*** +*int _putenv(option) - add/replace/remove variable in environment +* +*Purpose: +* option should be of the form "option=value". If a string with the +* given option part already exists, it is replaced with the given +* string; otherwise the given string is added to the environment. +* If the string is of the form "option=", then the string is +* removed from the environment, if it exists. If the string has +* no equals sign, error is returned. +* +*Entry: +* char *option - option string to set in the environment list. +* should be of the form "option=value". +* +*Exit: +* returns 0 if OK, -1 if fails. +* +*Exceptions: +* +*Warning: +* This code will not work if variables are removed from the +* environment by deleting them from environ[]. Use _putenv("option=") +* to remove a variable. +* +*******************************************************************************/ + +#ifdef MTHREAD + +int _CALLTYPE1 _putenv ( + const char *option + ) +{ + int retval; + + _mlock(_ENV_LOCK); + + retval = _putenv_lk(option); + + _munlock(_ENV_LOCK); + + return retval; +} + +int _CALLTYPE1 _putenv_lk ( + const char *option + ) + +#else /* ndef MTHREAD */ + +int _CALLTYPE1 _putenv ( + const char *option + ) + +#endif /* MTHREAD */ + +{ + char **env; + const char *equal; + char *name, *value; + int ix; + int remove; /* 1 means remove string from environment */ + + /* check that the option string is valid and find the equal sign + */ + if ( (option == NULL) || ((equal = strchr(option, '=')) == NULL) ) + return(-1); + + /* check for the special case of '=' being the very first character + * of option. though the use of '=' in an environment variable name + * is documented as being illegal, the 'current directory' strings + * all look like this: + * + * =<Drive Letter>:=<Drive Letter><fully qualified path> + * + * handle this by setting the equal pointer to point to the second + * '=' if it exists. Otherwise, handle as before. + */ + if ( option == equal ) + if ( (equal = strchr(option + 1, '=')) == NULL ) + equal = option; + + /* if the character following '=' is null, we are removing the + * the environment variable. Otherwise, we are adding or updating + * an environment variable. + */ + remove = (*(equal + 1) == '\0'); + + /* see if _environ array exists */ + if (_environ == NULL) { + if ( remove ) + return 0; + else { + /* get an array and init it to NULL */ + if ( (_environ = malloc(sizeof(void *))) == NULL) + return -1; + *_environ = NULL; + } + } + + /* init env pointer */ + + env = _environ; + + /* See if the string is already in the environment */ + + ix = findenv(option, equal - option); + + if ((ix >= 0) && (*env != NULL)) { + /* String is already in the environment -- overwrite/remove it. + */ + if (remove) { + /* removing -- move all the later strings up */ + for ( ; env[ix] != NULL; ++ix) { + env[ix] = env[ix+1]; + } + + /* shrink the environment memory block + (ix now has number of strings, including NULL) -- + this realloc probably can't fail, since we're + shrinking a mem block, but we're careful anyway. */ + if (env = (char **) realloc(env, ix * sizeof(char *))) + _environ = env; + } + else { + /* replace the option */ + env[ix] = (char *) option; + } + } + else { + /* + * String is NOT in the environment + */ + if ( !remove ) { + + /* + * Append the string to the environ table. Note that + * table must be grown to do this. + */ + if (ix < 0) + ix = -ix; /* ix = length of environ table */ + + if ( (env = (char **)realloc(env, sizeof(char *) * + (ix + 2))) == NULL ) + return -1; + + env[ix] = (char *)option; + env[ix + 1] = NULL; + _environ = env; + } + else + /* + * We are asked to remove an environment var that + * isn't there...just return success + */ + return 0; + } + + /* + * Update the real environment. Don't give an error if this fails + * since the failure will not affect the user unless he/she is making + * direct API calls. + */ + if ( (name = malloc(strlen(option) + 2)) != NULL ) { + strcpy(name, option); + value = name + (equal - option); + *value++ = '\0'; + SetEnvironmentVariable(name, remove ? NULL : value); + free(name); + } + + return 0; +} + + +/*** +*int findenv(name, len) - [STATIC] +* +*Purpose: +* Scan for the given string within the environment +* +*Entry: +* +*Exit: +* Returns the offset in "environ[]" of the given variable +* Returns the negative of the length of environ[] if not found. +* Returns 0 if the environment is empty. +* +* [NOTE: That a 0 return can mean that the environment is empty +* or that the string was found as the first entry in the array.] +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 findenv ( + const char *name, + int len + ) +{ + char **env; + + for ( env = _environ ; *env != NULL ; env++ ) { + /* + * See if first len characters match, up to case + */ + if ( _strnicmp(name, *env, len) == 0 ) + /* + * the next character of the environment string must + * be an '=' or a '\0' + */ + if ( (*env)[len] == '=' || (*env)[len] == '\0' ) + return(env - _environ); +// +// We cannot break here since findenv must report the total number of strings. +// else +// break; + } + + return(-(env - _environ)); +} + + +#endif /* _WIN32_ */ +#endif /* _CRUISER_ */ + +#endif /* _POSIX_ */ |