/*
 * Copyright (C) 2001-2007 Chris Ross, Stephan Engstrom, Alex Holden et al
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * o Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * o Neither the name of the ferite software nor the names of its contributors may
 *   be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

uses "sys.lib";


module-header {

#ifdef WIN32
#include <windows.h>
#endif

}

/**
 * @namespace Sys
 * @modifies Sys
 */
namespace modifies Sys
{
    /**
     * @namespace env
     * @brief Provides access to the enviroment the script runs in 
     */
    namespace env
    {
        /**
         * @function toArray
         * @declaration function toArray()
         * @brief Get a hash of key,value pairs from the environment
         * @return An array of the environment
         */
        native function toArray()
        {
            FeriteVariable *var = NULL, *val = NULL;
            char *currentValue = NULL;
            char *name, *value;
            int i = 0;
#ifdef USING_DARWIN
            char **environ = *_NSGetEnviron();
#endif
            var = ferite_create_uarray_variable( script, "Environment::toArray-element", 50, FE_STATIC );
            while( (currentValue = environ[i++]) != NULL )
            {
                if( strcmp( currentValue, "" ) != 0 && ferite_find_string( currentValue, "=" ) > -1 ) {
                    
                    name = memset( fmalloc( strlen(currentValue)+1 ), '\0', strlen(currentValue)+1 );
                    value = memset( fmalloc( strlen(currentValue)+1 ), '\0', strlen(currentValue)+1 );
                    
                    strncpy( name, currentValue, ferite_find_string( currentValue, "=" ) );
                    strcpy( value, currentValue + ferite_find_string( currentValue, "=" ) + 1 );
                    val = fe_new_str( name, value, 0, FE_CHARSET_DEFAULT );
                    ferite_uarray_add( script, VAUA(var), val, name, FE_ARRAY_ADD_AT_END );
                    
                    ffree( name );
                    ffree( value );
                }
            }
            FE_RETURN_VAR( var );
        }

        /**
         * @function read
         * @declaration function read( string key )
         * @brief Read an environmental string
         * @param string key The key to read from the environment, eg. HOME, USER
         * @return The value of the environment variable key
         */
        native function read( string key )
        {
            char *ev_value = NULL;
            FeriteVariable *returnValue = NULL;

            if( (ev_value = getenv(key->data)) != NULL )
              returnValue = fe_new_str_static( "Environment::read-return", ev_value, 0, FE_CHARSET_DEFAULT );
            else
              returnValue = fe_new_str_static( "Environment::read-return", "", 0, FE_CHARSET_DEFAULT );
            FE_RETURN_VAR( returnValue );
        }

        /**
         * @function write
         * @declaration function write( string key, string value )
         * @brief Write an environment variable
         * @param string key The key to write
         * @param string value The value to write to the key
         */
        native function write( string key, string value )
        {
           /* Solaris is a PITA - it doesn't seem to have a setenv this is the work around */
#ifdef USING_SOLARIS
            char *buf = memset( malloc( key->length + value->length + 10 ), '\0', key->length + value->length + 10 );
            sprintf( buf, "%s=%s", key->data, value->data );
	    putenv(buf);
#else
#ifdef WIN32
		SetEnvironmentVariable( key->data, value->data );
#else
            setenv( key->data, value->data, 1 );
#endif
#endif
        }

        /**
         * @function del
         * @declaration function del( string key )
         * @brief Delete a value from the environment
         * @param string key The value to delete
         */
        native function del( string key )
        {
#ifdef USING_SOLARIS
#if _LIBC
/* This lock protects against simultaneous modifications of `environ'.  */
# include <bits/libc-lock.h>
__libc_lock_define_initialized (static, envlock)
# define LOCK  __libc_lock_lock (envlock)
# define UNLOCK        __libc_lock_unlock (envlock)
#else
# define LOCK
# define UNLOCK
#endif

/* In the GNU C library we must keep the namespace clean.  */
#ifdef _LIBC
# define unsetenv __unsetenv
#endif

            size_t len;
            char **ep;
            char *name = key->data;
            
            if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
            {
                return;
            }
            
            len = strlen (name);
            
            LOCK;
            
            ep = environ;
            while (*ep != NULL) {
                if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
                {
                    /* Found it.  Remove this pointer by moving later ones back.  */
                    char **dp = ep;
                    
                    /* Continue the loop in case NAME appears again.  */
                    do {
                        dp[0] = dp[1];
                    } while (*dp++);
                }
                else
                    ++ep;
            }
            UNLOCK;
            
#ifdef _LIBC
# undef unsetenv
weak_alias (__unsetenv, unsetenv)
#endif
#else
#ifdef WIN32
	    SetEnvironmentVariable(key->data, NULL);
#else
            unsetenv( key->data );
#endif
#endif
        }
    }
}
/**
 * @end
 */
