/*** *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 * and removed #include . * 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 #include #include #include #include #include #include #include #include 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: * * =:= * * 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_ */