/***
*stdenvp.c - standard _setenvp routine
*
*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       This module is called by the C start-up routine to set up "_environ".
*       Its sets up an array of pointers to strings in the environment.
*       The global symbol "_environ" is set to point to this array.
*
*******************************************************************************/

#include <cruntime.h>
#include <string.h>
#include <stdlib.h>
#include <internal.h>
#include <rterr.h>
#include <oscalls.h>
#include <tchar.h>
#include <dbgint.h>

#ifndef CRTDLL

#ifdef _MBCS
/*
 * Flag to ensure multibyte ctype table is only initialized once
 */
extern int __mbctype_initialized;

#endif  /* _MBCS */

/*
 * Flag checked by getenv() and _putenv() to determine if the environment has
 * been initialized.
 */
extern int __env_initialized;

#endif  /* CRTDLL */

/***
*_setenvp - set up "envp" for C programs
*
*Purpose:
*       Reads the environment and build the envp array for C programs.
*
*Entry:
*       The environment strings occur at _aenvptr.
*       The list of environment strings is terminated by an extra null
*       byte.  Thus two null bytes in a row indicate the end of the
*       last environment string and the end of the environment, resp.
*
*Exit:
*       "environ" points to a null-terminated list of pointers to ASCIZ
*       strings, each of which is of the form "VAR=VALUE".  The strings
*       are copied from the environment area. This array of pointers will
*       be malloc'ed.  The block pointed to by _aenvptr is deallocated.
*
*Uses:
*       Allocates space on the heap for the environment pointers.
*
*Exceptions:
*       If space cannot be allocated, program is terminated.
*
*******************************************************************************/

#ifdef WPRFLAG
void __cdecl _wsetenvp (
#else  /* WPRFLAG */
void __cdecl _setenvp (
#endif  /* WPRFLAG */
        void
        )
{
        _TSCHAR *p;
        _TSCHAR **env;              /* _environ ptr traversal pointer */
        int numstrings;             /* number of environment strings */
        int cchars;

#if !defined (CRTDLL) && defined (_MBCS)
        /* If necessary, initialize the multibyte ctype table. */
        if ( __mbctype_initialized == 0 )
            __initmbctable();
#endif  /* !defined (CRTDLL) && defined (_MBCS) */

        numstrings = 0;

#ifdef WPRFLAG
        p = _wenvptr;
#else  /* WPRFLAG */
        p = _aenvptr;
#endif  /* WPRFLAG */

        /*
         * NOTE: starting with single null indicates no environ.
         * Count the number of strings. Skip drive letter settings
         * ("=C:=C:\foo" type) by skipping all environment variables
         * that begin with '=' character.
         */

        while (*p != _T('\0')) {
            /* don't count "=..." type */
            if (*p != _T('='))
                ++numstrings;
            p += _tcslen(p) + 1;
        }

        /* need pointer for each string, plus one null ptr at end */
        if ( (_tenviron = env = (_TSCHAR **)
            _malloc_crt((numstrings+1) * sizeof(_TSCHAR *))) == NULL )
            _amsg_exit(_RT_SPACEENV);

        /* copy strings to malloc'd memory and save pointers in _environ */
#ifdef WPRFLAG
        for ( p = _wenvptr ; *p != L'\0' ; p += cchars ) {
#else  /* WPRFLAG */
        for ( p = _aenvptr ; *p != '\0' ; p += cchars ) {
#endif  /* WPRFLAG */
            cchars = _tcslen(p) + 1;
            /* don't copy "=..." type */
            if (*p != _T('=')) {
                if ( (*env = (_TSCHAR *)_malloc_crt(cchars * sizeof(_TSCHAR)))
                     == NULL )
                    _amsg_exit(_RT_SPACEENV);
                _tcscpy(*env, p);
                env++;
            }
        }

#ifdef WPRFLAG
        _free_crt(_wenvptr);
        _wenvptr = NULL;
#else  /* WPRFLAG */
        _free_crt(_aenvptr);
        _aenvptr = NULL;
#endif  /* WPRFLAG */

        /* and a final NULL pointer */
        *env = NULL;

#ifndef CRTDLL
        /*
         * Set flag for getenv() and _putenv() to know the environment
         * has been set up.
         */
        __env_initialized = 1;
#endif  /* CRTDLL */

}
