/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.28 from the
 * contents of GConfValue.xs. Do not edit this file, edit GConfValue.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "xs/GConfValue.xs"
/*
 * Copyright (c) 2003 by Emmanuele Bassi (see the file AUTHORS)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 * Boston, MA  02111-1307  USA.
 */

#include "gconfperl.h"

/*
 * GConfValue is a dynamic type container used by GConf, in many ways similar
 * to GValue.  It should be accessed only via methods, so GConf doesn't export
 * it as a registered type.  Hence, I decided to translate it into a Perl data
 * structure completely transparent to the programmer; GConfValues are used
 * only internally: what a programmer will always see or use will be an hashref
 * containing the "type" field, which is used to store the symbolic type of the
 * key which GConfValue is bound to, and the payload, that is the value bound
 * to the key.  Fundamental types will have the "value" field filled with the
 * corresponding perl scalar; lists of fundamental types will have the "value"
 * field filled with an arrayref of scalars; pairs of fundamental types will
 * have two fields, "car" (for the first value of the pair) and "cdr" (for the
 * second value of the pair), each one containing an hashref corresponding to a
 * GConfValue of their fundamental types. This may seems a little obfuscated,
 * but, since we're not providing any accessor methods to gather the data
 * inside GConfValue, I've decided to keep the semantics as much as similar to
 * the corresponding C one. (ebassi)
 * 
 */

/* gconfperl_sv_from_value returns the correct SV for the fundamental types
 * stored inside a GConfValue.  gconfperl_value_from_sv is used the other way
 * around, to fill an already initialized GConfValue from a SV.
 */
static SV *
gconfperl_sv_from_value (GConfValue * v)
{
	SV * sv;
	
	switch (v->type) {
		case GCONF_VALUE_BOOL:
			sv = newSViv (gconf_value_get_bool (v));
                        break;
		case GCONF_VALUE_FLOAT:
			sv = newSVnv (gconf_value_get_float (v));
                        break;
		case GCONF_VALUE_INT:
			sv = newSViv (gconf_value_get_int (v));
                        break;
		case GCONF_VALUE_STRING:
			sv = newSVGChar (gconf_value_get_string (v));
                        break;
		case GCONF_VALUE_SCHEMA:
                        sv = newSVGConfSchema (gconf_value_get_schema (v));
                        break;
		case GCONF_VALUE_INVALID:
		default:
			sv = NULL;
                        break;
	}
	
	return sv;
}

static void
gconfperl_value_from_sv (SV * sv, GConfValue * v)
{
	switch (v->type) {
		case GCONF_VALUE_BOOL:
			gconf_value_set_bool (v, SvIV (sv));
                        break;
		case GCONF_VALUE_FLOAT:
			gconf_value_set_float (v, SvNV (sv));
                        break;
		case GCONF_VALUE_INT:
			gconf_value_set_int (v, SvIV (sv));
                        break;
		case GCONF_VALUE_STRING:
			gconf_value_set_string (v, SvGChar (sv));
                        break;
                case GCONF_VALUE_SCHEMA:
                        gconf_value_set_schema (v, SvGConfSchema (sv));
                        break;
		case GCONF_VALUE_INVALID:
		default:
			break;
	}
}

/*
 * Create a SV from a GConfValue.
 * The hash has this form:
 * 
 * fundamentals = { 'int' | 'bool' | 'float' | 'string' | 'schema' }
 * 
 * iff <type> := <fundamentals>
 * 	{ type => <type>, value => { <scalar> | <arrayref> } }
 * 
 * iff <type> := 'pair'
 * 	{
 * 		type => 'pair',
 * 		car  => { type => <fundamentals>, value => <scalar> },
 * 		cdr  => { type => <fundamentals>, value => <scalar> }
 * 	}
 * 
 * a schema is a fundamental type because we have a type for it, like
 * we do have types for integer, boolean, floating and string values.
 */ 
SV *
newSVGConfValue (GConfValue * v)
{
	HV * h;
	SV * sv;
	HV * stash;
	
	if (! v)
		return newSVsv(&PL_sv_undef);

	h = newHV ();
	sv = newRV_noinc ((SV *) h);	/* safe */
	
	switch (v->type) {
		case GCONF_VALUE_STRING:
		case GCONF_VALUE_INT:
		case GCONF_VALUE_FLOAT:
		case GCONF_VALUE_BOOL:
                case GCONF_VALUE_SCHEMA:
			/* these are fundamental types, so store type and value
			 * directly inside the hashref; for the type, use the
			 * 'stringyfied' version.
			 */
			hv_store (h, "type", 4, gperl_convert_back_enum (GCONF_TYPE_VALUE_TYPE, v->type), 0);
			hv_store (h, "value", 5, gconfperl_sv_from_value (v), 0);
			break;
		case GCONF_VALUE_PAIR:
			/* a pair consists of two fundamental types, stored as
			 * car and cdr (damned LISP lovers).  We do not supply
			 * accessor methods for GConfValue, so we try to
			 * reflect the storage as much as we can; thus, we
			 * create two keys, 'car' and 'cdr', instead of the
			 * usual 'value' one.  The programmer must be warned,
			 * so we leave type as 'pair' (also because car and cdr
			 * may be of two different types, so we need a marker
			 * for this situation).
			 */
			{
			SV * car, * cdr;
			hv_store (h, "type", 4,
				gperl_convert_back_enum (GCONF_TYPE_VALUE_TYPE, v->type), 0);
			
			car = newSVGConfValue (gconf_value_get_car (v));
			cdr = newSVGConfValue (gconf_value_get_cdr (v));
			hv_store (h, "car", 3, newSVsv (car), 0);
			hv_store (h, "cdr", 3, newSVsv (cdr), 0);
			}
			break;
		case GCONF_VALUE_LIST:
			/* lists are handled like arrayrefs; the type is the
			 * list type, in order to mask the special 'list' type
			 * from the programmer.
			 */
			{
			AV * a;
			SV * r;
			GSList * l, * tmp;
			GConfValueType t = gconf_value_get_list_type (v);
			
			a = newAV ();
			r = newRV_noinc ((SV *) a);	/* safe */
			l = gconf_value_get_list (v);
			for (tmp = l; tmp != NULL; tmp = tmp->next)
				av_push (a, gconfperl_sv_from_value ((GConfValue *) tmp->data));
			
			hv_store (h, "type", 4, gperl_convert_back_enum (GCONF_TYPE_VALUE_TYPE, t), 0);
			hv_store (h, "value", 5, newSVsv (r), 0);
			}
			break;
		case GCONF_VALUE_INVALID:
			/* this is used only for error handling */
		default:
			croak ("newSVGConfValue: invalid type found");
                        break;
	}

	stash = gv_stashpv ("Gnome2::GConf::Value", TRUE);
	sv_bless (sv, stash);
	
	return sv;
}

/* Create a GConfValue from a SV. */
GConfValue *
SvGConfValue (SV * data)
{
	HV * h;
	SV ** s;
	GConfValue * v;
	GConfValueType t;
	int n;
		
	if ((!data) || (!SvOK(data)) || (!SvRV(data)) || (SvTYPE(SvRV(data)) != SVt_PVHV))
		croak ("SvGConfValue: value must be an hashref");

	h = (HV *) SvRV (data);
	
	/* retrieve the type */
	if (! ((s = hv_fetch (h, "type", 4, 0)) && SvOK (*s)))
		croak ("SvGConfValue: 'type' key is needed");
	
	/* if it is an integer, just assign it... */
	if (looks_like_number (*s))
		t = SvIV (*s);
	
	/* otherwise, try to convert it from the enum */
	if (!gperl_try_convert_enum (GCONF_TYPE_VALUE_TYPE, *s, &n))
		croak ("SvGConfValue: 'type' should be either a GConfValueType or an integer");
	t = (GConfValueType) n;
	
	/* set GConfValue using the right setter method */
	switch (t) {
		case GCONF_VALUE_STRING:
		case GCONF_VALUE_INT:
		case GCONF_VALUE_FLOAT:
		case GCONF_VALUE_BOOL:
                case GCONF_VALUE_SCHEMA:
			if (! ((s = hv_fetch (h, "value", 5, 0)) && SvOK (*s)))
				croak ("SvGConfValue: fundamental types require a value key");
			
			/* the argument is not a reference, so convert it */
			if (!SvROK (*s)) {
				v = gconf_value_new (t);
				gconfperl_value_from_sv (*s, v);
			}
			else if (SvROK (*s) || SvTYPE (SvRV (*s)) == SVt_PVAV) {
				/* the argument is an array, so fill the list */
				AV * av = (AV*) SvRV (*s);
				GSList * list = NULL;
				int i;
				
				v = gconf_value_new (GCONF_VALUE_LIST);
				gconf_value_set_list_type (v, t);
				
				for (i = av_len (av) ; i >= 0 ; i--) {
					GConfValue * v = gconf_value_new (t);
					gconfperl_value_from_sv (*av_fetch (av, i, FALSE), v);
					list = g_slist_prepend (list, v);
				}
				gconf_value_set_list_nocopy (v, list);
			}
			else
				croak ("SvGConfValue: value must be either a "
				       "scalar or an array reference");
			break;
		case GCONF_VALUE_PAIR:
			{
			GConfValue * car, * cdr;
			
			v = gconf_value_new (GCONF_VALUE_PAIR);
			
			/* build up the first value of the pair */	
			if (! ((s = hv_fetch (h, "car", 3, 0)) && SvOK (*s)))
				croak ("SvGConfValue: 'pair' type requires a 'car' key");
			
			car = SvGConfValue (*s);
			gconf_value_set_car_nocopy (v, car);
			
			/* and then the second value */
			if (! ((s = hv_fetch (h, "cdr", 3, 0)) && SvOK (*s)))
				croak ("SvGConfValue: 'pair' type requires a 'cdr' key");
			
			cdr = SvGConfValue (*s);
			gconf_value_set_cdr_nocopy (v, cdr);
			}
			break;	
		case GCONF_VALUE_LIST:
			/* handled above, this should never be passed */
		case GCONF_VALUE_INVALID:
			/* used for error situations */
		default:
			croak ("SvGConfValue: invalid type found.");
	}
	
	return v;
}

#line 307 "xs/GConfValue.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 451 "xs/GConfValue.c"

XS_EUPXS(XS_Gnome2__GConf__Value_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Gnome2__GConf__Value_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "value");
    {
	SV *	value = ST(0)
;
#line 383 "xs/GConfValue.xs"
        gconf_value_free (SvGConfValue (value));        
#line 464 "xs/GConfValue.c"
    }
    XSRETURN_EMPTY;
}

#if GCONF_CHECK_VERSION (2, 13, 1)
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_Gnome2__GConf__Value_compare); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Gnome2__GConf__Value_compare)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "value_a, value_b");
    {
	GConfValue *	value_a = SvGConfValue (ST(0))
;
	GConfValue *	value_b = SvGConfValue (ST(1))
;
	gint	RETVAL;
	dXSTARG;
#line 392 "xs/GConfValue.xs"
    	RETVAL = gconf_value_compare (value_a, value_b);
#line 488 "xs/GConfValue.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#endif /* GCONF_CHECK_VERSION (2, 13, 1) */

XS_EUPXS(XS_Gnome2__GConf__Value_to_string); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Gnome2__GConf__Value_to_string)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "value");
    {
	GConfValue *	value = SvGConfValue (ST(0))
;
	gchar_own *	RETVAL;
#line 402 "xs/GConfValue.xs"
    	RETVAL = gconf_value_to_string (value);
#line 508 "xs/GConfValue.c"
	{
	    SV * RETVALSV;
	    RETVALSV = sv_newmortal();
	    /* used when we can directly own the returned string. */
	    /* we have to copy in the case when perl's malloc != gtk's malloc,
	     * so best copy all the time. */
	    sv_setpv ((SV*)RETVALSV, RETVAL);
	    SvUTF8_on (RETVALSV);
	    g_free (RETVAL);
	    ST(0) = RETVALSV;
	}
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Gnome2__GConf__Value); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Gnome2__GConf__Value)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("Gnome2::GConf::Value::DESTROY", XS_Gnome2__GConf__Value_DESTROY);
#if XSubPPtmpAAAA
        newXS_deffile("Gnome2::GConf::Value::compare", XS_Gnome2__GConf__Value_compare);
#endif
        newXS_deffile("Gnome2::GConf::Value::to_string", XS_Gnome2__GConf__Value_to_string);

    /* Initialisation Section */

#if XSubPPtmpAAAA
#endif
#line 562 "xs/GConfValue.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

