/*
Copyright (C) 2001-2010, Parrot Foundation.
$Id: env.pmc 48329 2010-08-05 13:06:41Z coke $

=head1 NAME

src/pmc/env.pmc - System Environment

=head1 DESCRIPTION

C<Env> is a singleton class which provides access to the system environment.

=head2 Methods

=over 4

=cut

*/

/* array of environment variables,
   speced in POSIX.1, but not in ISO-C
   MS C compilers know about environ, as it is declared in stdlib.h.
   OS X doesn't allow access to "environ" from within shared libraries.
*/
#ifndef WIN32
#  ifdef __APPLE_CC__
#    include <crt_externs.h>
#    define environ (*_NSGetEnviron())
#  else /* !__APPLE_CC__ */
extern char **environ;
#  endif /* __APPLE_CC__ */
#endif /* !WIN32 */

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */


static PMC *Env_PMC;
pmclass Env singleton provides hash {

/*

=item C<void *get_pointer()>

=item C<void set_pointer(void *ptr)>

These two functions are part of the singleton creation interface. For more
information see F<src/pmc.c>.

=cut

*/
    void class_init() {
        Env_PMC = NULL;
    }

    VTABLE void *get_pointer() {
        return Env_PMC;
    }

    VTABLE void set_pointer(void *ptr) {
        Env_PMC = (PMC *)ptr;
    }

/*

=item C<PMC *get_iter()>

Returns a new iterator for the environment.
This method is questionable, as environ is not in ISO-C.

=cut

*/

    VTABLE PMC *get_iter() {
        return Parrot_pmc_new_init(INTERP, enum_class_ArrayIterator, SELF);
    }

/*

=item C<INTVAL elements()>

Returns the number of elements in the environment.
This method is questionable, as environ is not in ISO-C.

=cut

*/

    VTABLE INTVAL elements() {
        INTVAL rv = 0;

        while (environ[rv] != NULL)
            ++rv;

        return rv;
    }

/*

=item C<INTVAL get_bool()>

Returns whether the environment has any elements.

=cut

*/
    VTABLE INTVAL get_bool() {
        return SELF.elements() ? 1 : 0;
    }

/*

=item C<INTVAL get_integer()>

Returns the size of the hash.

=cut

*/

    VTABLE INTVAL get_integer() {
        return SELF.elements();
    }

/*

=item C<FLOATVAL get_number()>

Returns the size of the hash.

=cut

*/
    VTABLE FLOATVAL get_number() {
        return SELF.elements();
    }

/*

=item C<STRING *get_string_keyed(PMC *key)>

Returns the Parrot string value for the environment variable C<*key>.

=cut

*/

    VTABLE STRING *get_string_keyed_str(STRING *key) {
        if (!STRING_IS_EMPTY(key)) {
            const char * const val = Parrot_getenv(INTERP, key);

            if (val) {
                STRING * const retval = Parrot_str_new(INTERP, val, 0);
                return retval;
            }
        }

        return CONST_STRING(interp, "");
    }

    VTABLE STRING *get_string_keyed(PMC *key) {
        return SELF.get_string_keyed_str(VTABLE_get_string(INTERP, key));
    }

/*

=item C<STRING *get_string_keyed_int(PMC *key)>

Returns the Parrot string value for the environment variable at position C<pos>.

Used during iteration.

=cut

*/

    VTABLE STRING *get_string_keyed_int(INTVAL pos) {
        if (pos < 0 || pos >= SELF.elements()) {
            return CONST_STRING(interp, "");
        }
        else {
            const char * const envp = environ[pos];
            const char * const p    = strchr(envp, '=');
            return Parrot_str_new(INTERP, envp, (UINTVAL)(p - envp));
        }
    }

/*

=item C<STRING *get_pmc_keyed(PMC *key)>

Returns a String PMC for the environment variable C<*key>.

=cut

*/

    VTABLE PMC *get_pmc_keyed(PMC *key) {
        STRING * const keyname = VTABLE_get_string(INTERP, key);

        STRING *retval  = NULL;
        PMC    *return_pmc;

        if (!STRING_IS_EMPTY(keyname)) {
            const char * const val = Parrot_getenv(INTERP, keyname);

            if (val) {
                retval = Parrot_str_new(INTERP, val, 0);
            }
        }

        if (!retval)
            retval = CONST_STRING(interp, "");

        return_pmc = Parrot_pmc_new(INTERP, enum_class_String);

        VTABLE_set_string_native(INTERP, return_pmc, retval);
        return return_pmc;
    }

/*

=item C<void set_string_keyed(PMC *key, STRING *value)>

Sets the environment variable C<*key> to C<*value>.

=cut

*/

    VTABLE void set_string_keyed(PMC *key, STRING *value) {
        STRING * const keyname = VTABLE_get_string(INTERP, key);

        if (keyname && value)
            Parrot_setenv(INTERP, keyname, value);
    }

/*

=item C<void set_pmc_keyed(PMC *key, PMC *value)>

Sets the environment variable C<*key> to C<*value>.

=cut

*/

    VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
        STRING * const keyname   = VTABLE_get_string(INTERP, key);
        STRING * const str_value = VTABLE_get_string(INTERP, value);

        if (keyname && str_value)
            Parrot_setenv(INTERP, keyname, str_value);
    }

/*

=item C<INTVAL exists_keyed(PMC *key)>

Returns whether the environment variable for C<*key> exists.

=cut

*/

    VTABLE INTVAL exists_keyed(PMC *pmckey) {
        STRING * const keyname = VTABLE_get_string(INTERP, pmckey);

        if (!STRING_IS_EMPTY(keyname)) {
            const char * const val = Parrot_getenv(INTERP, keyname);

            if (val != NULL) {
                return 1;
            }
        }

        return 0;
    }

/*

=item C<void delete_keyed(PMC *key)>

Deletes the the environment variable for C<*key>.

=cut

*/

    VTABLE void delete_keyed(PMC *key) {
        STRING * const keyname = VTABLE_get_string(INTERP, key);

        if (!STRING_IS_EMPTY(keyname)) {
            const char * const val = Parrot_getenv(INTERP, keyname);

            if (val != NULL) {
                Parrot_unsetenv(INTERP, keyname);
            }
        }
    }
}

/*

=back

=head1 SEE ALS0

PDD -
L<http://docs.parrot.org/parrot/latest/html/docs/pdds/pdd17_pmc.pod.html#Hash_types>

Environment in Perl 6 - L<http://dev.perl.org/perl6/rfc/318.html>

Module for Perl 5 - L<http://search.cpan.org/~stas/Env-C-0.06/>

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
