/*! \file scol_glib_keyfile.c
*	\brief all functions of this API
*   \author Stephane Bisaro
*/
/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/

#include "../include/scol_glib_keyfile.h"

#if ((defined _WIN32) || (defined __WIN32__))
cbmachine ww;
#endif
mmachine  mm;


/**
 * \brief GKF_VALUE_RAW : I : flag used to load a key file. The raw value associated with key under group.
 * The value can be escaped string
 */
int GKF_VALUE_RAW (mmachine m) { return MMpush (m, ITOM (1)); }
/**
 * \brief GKF_VALUE_STRING : I : flag used to load a key file. The string value associated with key under group.
 * Unlike GKF_VALUE_RAW, any escaped sequence are unescaped
 */
int GKF_VALUE_STRING (mmachine m) { return MMpush (m, ITOM (2)); }
/**
 * \brief GKF_VALUE_INTEGER : Not implemented yet
 */
int GKF_VALUE_INTEGER (mmachine m) { return MMpush (m, ITOM (3)); }
/**
 * \brief GKF_VALUE_INTEGER64 : Not implemented yet
 */
int GKF_VALUE_INTEGER64 (mmachine m) { return MMpush (m, ITOM (4)); }
/**
 * \brief GKF_VALUE_UINTEGER64 : Not implemented yet
 */
int GKF_VALUE_UINTEGER64 (mmachine m) { return MMpush (m, ITOM (5)); }
/**
 * \brief GKF_VALUE_DOUBLE : Not implemented yet
 */
int GKF_VALUE_DOUBLE (mmachine m) { return MMpush (m, ITOM (6)); }
/**
 * \brief GKF_VALUE_BOOLEAN : Not implemented yet
 */
int GKF_VALUE_BOOLEAN (mmachine m) { return MMpush (m, ITOM (7)); }


/**
 * \brief _gkeyFileReadP : read a key file
 * fun [P S] [[S [[S S] r1]] r1]
 *
 * \param P : any file (read reference only)
 * \param S : the list seperator, or nil (default ";")
 * \return [[S [[S S] r1]] r1] : the list of datas = group names and for each group name, a list of tuple [key value]
 */
int SCOL_gkeyFileReadP (mmachine m)
{
    int mfile, msep;
    gboolean b;
    GKeyFile *ini;
    GError *err = NULL;

    msep = MTOP (MMpull (m));
    mfile = MMpull (m);
    if (mfile == NIL)
    {
        MMpush (m, NIL);
        return 0;
    }

    ini = g_key_file_new ();
    if (msep != NIL)
        g_key_file_set_list_separator (ini, (MMstart (m, msep))[0]);
    b = g_key_file_load_from_file (ini, MMstartstr (m, MTOP (mfile)), G_KEY_FILE_NONE, &err);
    if (!b)
    {
        MMechostr (0, "SCOL_gkeyFileReadP load error : %d .:. %s\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
        return 0;
    }
    g_key_file_free (ini);
    return scol_g_key_file_read (ini, m);
}








/* ========================================================================= */


/** \private
 * internal function : get groups names
 */
int scol_g_key_file_get_groups (mmachine m, int flag)
{
    int mini;
    int i = 0;
    gsize len = 0;
    GKeyFile *ini;
    gchar **groups;

    mini = MMpull (m);
    if (mini == NIL)
    {
        MMechostr (0, "scol_g_key_file_get_groups error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    groups = g_key_file_get_groups (ini, &len);
    if (flag)
        MMpush (m, ITOM ((int) len));   /* I */
    else
    {
        for (i = 0; i < (int) len; i++)
            Mpushstrbloc (m, groups[i]);
        MMpush (m, NIL);
        for (i = 0; i < (int) len; i++)
        {
            MMpush (m, ITOM (2));
            MBdeftab (m);
        }                               /* [S r1] */
    }
    g_strfreev (groups);
    return 0;
}
/** \private
 * internal function : return a list of the entire content ( [[S [[S S] r1]] r1] )
 */
int scol_g_key_file_read (GKeyFile *ini, mmachine m)
{
    int i, j;
    gsize ngroups, nkeys;
    gchar **groups;

    groups = g_key_file_get_groups (ini, &ngroups);
    for (i = 0; i < (int) ngroups; i++)
    {
        gchar **keys;

        Mpushstrbloc (m, groups[i]);    /* S */

        keys = g_key_file_get_keys (ini, groups[i], &nkeys, NULL);
        for (j = 0; j < (int) nkeys; j++)
        {
            gchar *value;

            value = g_key_file_get_value (ini, groups[i], keys[j], NULL);
            Mpushstrbloc (m, keys[j]);
            Mpushstrbloc (m, value);
            MMpush (m, ITOM (2));
            MBdeftab (m);               /* [S S] */
            g_free (value);
        }
        g_strfreev (keys);
        MMpush (m, NIL);
        for (j = 0; j < (int) nkeys; j++)
        {
            MMpush (m, ITOM (2));
            MBdeftab (m);
        }                               /* [[S S] r1] */
        MMpush (m, ITOM (2));
        MBdeftab (m);                   /* [S [[S S] r1]] */
    }
    g_strfreev (groups);
    MMpush (m, NIL);
    for (i = 0; i < (int) ngroups; i++)
    {
        MMpush (m, ITOM (2));
        MBdeftab (m);
    }                                   /* [[S [[S S] r1]] r1] */
    return 0;
}

/** \private
 * internal function : load a file or data
 */
int scol_g_key_file_load (mmachine m, int typ)
{
    int mchannel, mfile, msep, mflag;
    int initab;
    gboolean b;
    GKeyFileFlags flag = G_KEY_FILE_NONE;
    GKeyFile *ini;
    GError *err = NULL;

    mflag = MTOI (MMpull (m));
    msep = MTOP (MMpull (m));
    mfile = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        MMechostr (0, "scol_g_key_file_load error : channel is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    if (mfile == NIL)
    {
        MMechostr (0, "scol_g_key_file_load error : file is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = g_key_file_new ();
    if (msep != NIL)
        g_key_file_set_list_separator (ini, (MMstart (m, msep))[0]);

    if (mflag == 1)
        flag = G_KEY_FILE_KEEP_COMMENTS;
    else if (mflag == 2)
        flag = G_KEY_FILE_KEEP_TRANSLATIONS;
    else if (mflag == 3)
        flag = G_KEY_FILE_KEEP_TRANSLATIONS|G_KEY_FILE_KEEP_COMMENTS;

    if (typ)
        b = g_key_file_load_from_data (ini, MMstartstr (m, MTOP (mfile)), MMsizestr (m, MTOP (mfile)), flag, &err);
    else
        b = g_key_file_load_from_file (ini, MMstartstr (m, MTOP (mfile)), flag, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "scol_g_key_file_load error : loading is failed -> %s\n", err->message);
        g_error_free (err);
        MMpush (m, NIL);
        return 0;
    }

    initab = MMmalloc (m, sizeof (ini) + 1, TYPETAB);
    if (initab == NIL)
    {
        MMechostr (0, "scol_g_key_file_load error : not enough memory\n");
        MMpull (m);
        MMpush (m, NIL);
        g_key_file_free (ini);
        return 0;
    }
    MMstore (m, initab, OBJGKEYFILE_HANDLE, (int) ini);
    MMpush (m, PTOM (initab));
    OBJcreate (m, ObjKeyFile, (int) ini, -1, -1);
    return 0;
}

/**
 * \brief _gkeyFileLoadP : Loads a key file from any valid file
 *
 * fun [Chn P S I] ObjKeyFile
 *
 * \param Chn : the channel
 * \param P : any read referenced file
 * \param S : the list separator or nil (default ";"). One character only (if more, they are ignored)
 * \param I : flag :
 *      0 -> No flags, default behaviour
 *      1 -> Use this flag if you plan to write the (possibly modified) contents of the key file back to a file;
 *      otherwise all comments will be lost when the key file is written back.
 *      2 -> Use this flag if you plan to write the (possibly modified) contents of the key file back to a file;
 *      otherwise only the translations for the current language will be written back.
 *      3 -> 1 and 2
 * \return ObjKeyFile : the new object, or nil if error
 *
 * Importante note : if you want get/set any localized key, be sure set the flag to 2 (or 3) !
 */
int SCOL_gkeyFileLoadP (mmachine m)
{
    return scol_g_key_file_load (m, 0);
}

/**
 * \brief _gkeyFileLoadS : Loads a key file from any valid data
 *
 * fun [Chn P S I] ObjKeyFile
 *
 * \param Chn : the channel
 * \param S : any valid content
 * \param S : the list separator or nil (default ";"). One character only (if more, they are ignored)
 * \param I : flag :
 *      0 -> No flags, default behaviour
 *      1 -> Use this flag if you plan to write the (possibly modified) contents of the key file back to a file;
 *      otherwise all comments will be lost when the key file is written back.
 *      2 -> Use this flag if you plan to write the (possibly modified) contents of the key file back to a file;
 *      otherwise only the translations for the current language will be written back.
 *      3 -> 1 and 2
 * \return ObjKeyFile : the new object, or nil if error
 */
int SCOL_gkeyFileLoadS (mmachine m)
{
    return scol_g_key_file_load (m, 1);
}


/**
 * \brief _gkeyFileSave : save a keyfile to a filename
 *
 * fun [ObjKeyFile W] I
 *
 * \param ObjKeyFile : a valid object
 * \param W : a Scol write referenced filename
 * \return I : 0 if success or nil if error (see log message)
 */
int SCOL_gkeyFileSave (mmachine m)
{
    int mini, mwfile;
    gboolean b;
    GKeyFile *ini;
    gchar *content, *wfile;
    gsize len = 0;
    GError *err = NULL;

    mwfile = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mwfile == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSave error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    wfile = MMstartstr (m, MTOP (mwfile));
    content = g_key_file_to_data (ini, &len, &err);
    if ((content == NULL) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileSave error : %d ->  %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
        return 0;
    }
    b = g_file_set_contents (wfile, content, len, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileSave error : %d ->  %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
        return 0;
    }
    g_free (content);
    MMpush (m, ITOM (0));
    return 0;
}

/**
 *\brief _gkeyFileDestroy : Destroys an object
 *
 * \param ObjKeyFile
 * \return I : O or nil if error
 */
int SCOL_gkeyFileDestroy (mmachine m)
{
    int mini;
    GKeyFile *ini;

    mini = MMpull (m);
    if (mini == NIL)
    {
        MMechostr (0, "SCOL_gkeyFileDestroy error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    g_key_file_free (ini);
    OBJdelTM (m, ObjKeyFile, mini);
    MMpush (m, 0);

    return 0;
}

/**
 * \brief _gkeyFileGetContent : Returns the content of key file
 *
 * fun [ObjKeyFile] [S I]
 *
 * \param ObjKeyFile : any valid object
 * \return [S I] : a tuple : the content and its length or nil if error
 */
int SCOL_gkeyFileGetContent (mmachine m)
{
    int mini;
    gchar *content;
    gsize len = 0;
    GKeyFile *ini;

    mini = MMpull (m);
    if (mini == NIL)
    {
        MMechostr (0, "SCOL_gkeyFileGetContent error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    content = g_key_file_to_data (ini, &len, NULL);
    Mpushstrbloc (m, content);
    MMpush (m, ITOM ((int) len));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    g_free (content);
    return 0;
}

/**
 * \brief _gkeyFileGetDatas : Return a list of the content
 *
 * fun [ObjKeyFile] [[S [[S S] r1]] r1]
 *
 * \param ObjKeyFile : an object already created
 * \return [[S [[S S] r1]] r1] : a list of group names and for each group name, a list of tuple [key value] or nil if error
 */
int SCOL_gkeyFileGetDatas (mmachine m)
{
    int mini;
    GKeyFile *ini;

    mini = MMpull (m);
    if (mini == NIL)
    {
        MMechostr (0, "SCOL_gkeyFileGetDatas error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    return scol_g_key_file_read (ini, m);
}

/**
 * \brief _gkeyFileGetGroups : Returns a list of all groups
 *
 * fun [ObjKeyFile] [S r1]
 *
 * \param ObjKeyFile : any object already created
 * \return [S r1] : this list or nil if error
 */
int SCOL_gkeyFileGetGroups (mmachine m)
{
    return scol_g_key_file_get_groups (m, 0);
}

/**
 * \brief _gkeyFileGetNbGroups : Returns the number of group
 *
 * fun [ObjKeyFile] I
 *
 * \param ObjKeyFile : any object already created
 * \return I : this number or nil if error
 */
int SCOL_gkeyFileGetNbGroups (mmachine m)
{
    return scol_g_key_file_get_groups (m, 1);
}

/**
 * \brief _gkeyFileDataExist : Looks whether the key file has the datas
 *
 * fun [ObjKeyFile S S] I
 *
 * \param ObjKeyFile : any object already created
 * \param S : a group name or nil
 * \param S : a key name or nil
 * \return I : the result (see below) or nil if error
 *
 * If the group name and the key name are not nil, this function searches the key into the group.
 * If found, 1 is returned, else 0
 * If the group name is nil, this function searches the key into all groups.
 * The returned value is the number of this key, 0 if not found.
 * If the key name is nil, this function searches the group into the keyfile.
 * If found, 1 is returned, else 0.
 * If the keyfile is nil or if the group and key names are nil, nil is returned.
 */
int SCOL_gkeyFileDataExist (mmachine m)
{
    int mini, mgroup, mkey;
    GKeyFile *ini;
    gboolean b;

    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if (mini == NIL)
    {
        MMechostr (0, "SCOL_gkeyFileDataExist error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    if ((mkey == NIL) && (mgroup == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileDataExist error : group and key are nil\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);

    if (mkey == NIL)    /* search a group only */
    {
        b = g_key_file_has_group (ini, MMstartstr (m, MTOP (mgroup)));
        MMpush (m, ITOM (b));
        return 0;
    }

    if (mgroup == NIL)  /* search a key in all groups */
    {
        gchar ** groups;
        gsize len = 0;
        int i, r = 0;

        groups = g_key_file_get_groups (ini, &len);
        for (i = 0; i < len; i++)
        {
            if (g_key_file_has_key (ini, groups[i], MMstartstr (m, MTOP (mkey)), NULL))
                r++;
        }
        MMpush (m, ITOM (r));
        g_strfreev (groups);
        return 0;
    }

    /* search a key in a group */
    b = g_key_file_has_key (ini, MMstartstr (m, MTOP (mgroup)), MMstartstr (m, MTOP (mkey)), NULL);
    MMpush (m, ITOM (b));
    return 0;
}

/**
 * \brief _keyFileGetValue : Returns the value for any key in any group
 *
 * fun [ObjKeyFile S S I] S
 *
 * \param ObjKeyFile : any valid object
 * \param S : any group name
 * \param S : any key name
 * \param I : flag : GKF_VALUE_RAW, GKF_VALUE_STRING, GKF_VALUE_INTEGER, GKF_VALUE_INTEGER64, GKF_VALUE_UINTEGER64, GKF_VALUE_DOUBLE, GKF_VALUE_BOOLEAN
 * GKF_VALUE_RAW and GKF_VALUE_STRING have a difference, others always return a string
 * \return S : the value or nil if error or not found
 */
int SCOL_keyFileGetValue (mmachine m)
{
    int mini, mgroup, mkey, mflag;
    GKeyFile *ini;
    gchar *value, *group, *key;
    GError *err = NULL;

    mflag = MTOI (MMpull (m));
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mkey == NIL) || (mgroup == NIL))
    {
        MMechostr (0, "SCOL_keyFileGetValue error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));

    switch (mflag)
    {
        case (2) :
            value = g_key_file_get_string (ini, group, key, &err);
            break;

        case (3) :
        {
            int v;

            v = g_key_file_get_integer (ini, group, key, &err);
            value = g_malloc (sizeof (gchar) * 64);
            snprintf (value, 64, "%d", v);
            break;
        }
#ifndef GLIB_224
        case (4) :
        {
            gint64 v;

            v = g_key_file_get_int64 (ini, group, key, &err);
            value = g_malloc (sizeof (gchar) * 64);
            snprintf (value, 64, "%" G_GINT64_MODIFIER "x", v);
            break;
        }

        case (5) :
        {
            guint64 v;

            v = g_key_file_get_uint64 (ini, group, key, &err);
            value = g_malloc (sizeof (gchar) * 64);
            snprintf (value, 64, "%" G_GUINT64_FORMAT "x", v);
            break;
        }
#endif
        case (6) :
        {
            double v;

            v = g_key_file_get_double (ini, group, key, &err);
            value = g_malloc (sizeof (gchar) * 64);
            snprintf (value, 64, "%f", v);
            break;
        }

        case (7) :
        {
            gboolean v;

            v = g_key_file_get_boolean (ini, group, key, &err);
            value = g_malloc (sizeof (gchar) * 64);
            snprintf (value, 64, "%d", v);
            break;
        }

        default :
            value = g_key_file_get_value (ini, group, key, &err);

    }
    if ((value == NULL) || (err != NULL))
    {
        MMechostr (0, "SCOL_keyFileGetValue error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    else
    {
        Mpushstrbloc (m, value);
        g_free (value);
    }
    return 0;
}

/**
 * \brief _keyFileGetLocaleValue : Returns the locale value for any key in any group
 *
 * fun [ObjKeyFile S S S] S
 *
 * \param ObjKeyFile : any valid object
 * \param S : any group name
 * \param S : any key name
 * \param S : any locale identifier or nil
 * \return S : the value or nil if error or not found
 *
 * If locale is nil or not found, the value of the default key (without localization) will be returned
 * When the ObjKeyFile has been created, if the flag is at 0 or 1, the current locale can be used only.
 * In this last case, to get a value of an other locale, the flag should have set to 2 or 3.
 */
int SCOL_keyFileGetLocaleValue (mmachine m)
{
    int mini, mgroup, mkey, mlang;
    GKeyFile *ini;
    gchar *value, *group, *key, *lang = NULL;
    GError *err = NULL;

    mlang = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mkey == NIL) || (mgroup == NIL))
    {
        MMechostr (0, "SCOL_keyFileGetLocaleValue error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));
    if (mlang != NIL)
        lang = MMstartstr (m, MTOP (mlang));

    value = g_key_file_get_locale_string (ini, group, key, lang, &err);
    if ((value == NULL) || (err != NULL))
    {
        MMechostr (0, "SCOL_keyFileGetLocaleValue error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }

    Mpushstrbloc (m, value);
    g_free (value);
    return 0;
}

/**
 * \brief _gkeyFileGetValueList : Returns the values associated with key under group
 *
 * fun [ObjKeyFile S S] [S r1]
 *
 * \param ObjKeyFile : any valid object
 * \param S : any group name
 * \param S : any key name
 * \return [S r1] : the value or nil if error or not found
 */
int SCOL_gkeyFileGetValueList (mmachine m)
{
    int mini, mgroup, mkey;
    int i;
    GKeyFile *ini;
    gchar *group, *key;
    gchar **list;
    gsize len = 0;
    GError *err = NULL;

    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mkey == NIL) || (mgroup == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileGetValueList error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));

    list = g_key_file_get_string_list (ini, group, key, &len, &err);
    if ((list == NULL) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileGetValueList error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }

    for (i = 0; i < (int) len; i++)
        Mpushstrbloc (m, list[i]);
    MMpush (m, NIL);
    for (i = 0; i < (int) len; i++)
    {
        MMpush (m, ITOM (2));
        MBdeftab (m);
    }
    g_strfreev (list);
    return 0;
}

/**
 * \brief _gkeyFileGetValueLocaleList : Returns the locales values associated with key under group
 *
 * fun [ObjKeyFile S S S] [S r1]
 *
 * \param ObjKeyFile : any valid object
 * \param S : any group name
 * \param S : any key name
 * \param S : any locale identifier or nil
 * \return [S r1] : the value or nil if error or not found
 *
 * If locale is nil or not found, the values of the default key (without localization) will be returned
 * When the ObjKeyFile has been created, if the flag is at 0 or 1, the current locale can be used only.
 * In this last case, to get the values of an other locale, the flag should have set to 2 or 3.
 */
int SCOL_gkeyFileGetValueLocaleList (mmachine m)
{
    int mini, mgroup, mkey, mlang;
    int i;
    GKeyFile *ini;
    gchar *group, *key, *lang = NULL;
    gchar **list;
    gsize len = 0;
    GError *err = NULL;

    mlang = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mkey == NIL) || (mgroup == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileGetValueLocaleList error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));
    if (mlang != NIL)
        lang = MMstartstr (m, MTOP (mlang));

    list = g_key_file_get_locale_string_list (ini, group, key, lang, &len, &err);
    if ((list == NULL) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileGetValueLocaleList error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }

    for (i = 0; i < (int) len; i++)
        Mpushstrbloc (m, list[i]);
    MMpush (m, NIL);
    for (i = 0; i < (int) len; i++)
    {
        MMpush (m, ITOM (2));
        MBdeftab (m);
    }
    g_strfreev (list);
    return 0;
}

/**
 * \brief _gkeyFileGetComment : Return a comment
 *
 * fun [ObjKeyFile S S] S
 *
 * \param ObjKeyFile : an object
 * \param S : a group name
 * \param S : a key name
 * \return S : the comment or nil if error or not found
 *
 * Retrieves a comment above key name from group name. If key is NULL then comment will be read from above group name.
 * If both key name and group name are NULL, then comment will be read from above the first group in the file.
 */
int SCOL_gkeyFileGetComment (mmachine m)
{
    int mini, mgroup, mkey;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL, *comment;
    GError *err = NULL;

    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if (mini == NIL)
    {
        MMechostr (0, "SCOL_gkeyFileGetComment error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));

    comment = g_key_file_get_comment (ini, group, key, &err);
    if (err != NULL)
    {
        MMechostr (0, "SCOL_gkeyFileGetComment error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    Mpushstrbloc (m, comment);
    g_free (comment);
    return 0;
}

/**
 * \brief _gkeyFileSetValue : Associates a new value with key under group.
 *
 * Fun [ObjKeyFile S S S I] ObjKeyFile
 * If key cannot be found then it is created. If group cannot be found then it is created.
 *
 * \param ObjKeyFile : a valid object
 * \param S : a group name
 * \param S : a key name
 * \param S : the new value
 * \param I : a flag = GKF_VALUE_RAW or GKF_VALUE_STRING (others flags aren't implemented yet)
 * \return ObjKeyFile : the same object or nil if error
 *
 * If key or group is nil, the command is ignored but a message is written to the log
 */
int SCOL_gkeyFileSetValue (mmachine m)
{
    int mini, mgroup, mkey, mvalue, mflag;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL, *value = NULL;

    mflag = MTOI (MMpull (m));
    mvalue = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mvalue == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSetValue error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));
    if (mvalue != NIL)
        value =  MMstartstr (m, MTOP (mvalue));

    switch (mflag)
    {
        case (2) :
            g_key_file_set_string (ini, group, key, SCOLUTF8 (value, -1));
            break;

        default :
            g_key_file_set_value (ini, group, key, value);
    }
    MMpush (m, mini);
    return 0;
}
/**
 * \brief _gkeyFileSetLocaleValue : Associates a new value with key under group.
 *
 * Fun [ObjKeyFile S S S I] ObjKeyFile
 * If key cannot be found then it is created. If group cannot be found then it is created.
 *
 * \param ObjKeyFile : a valid object
 * \param S : a group name
 * \param S : a key name
 * \param S : the new value
 * \param S : a locale identifier
 * \return ObjKeyFile : the same object or nil if error
 *
 * If key or group is nil, the command is ignored but a message is written to the log
 */
int SCOL_gkeyFileSetLocaleValue (mmachine m)
{
    int mini, mgroup, mkey, mvalue, mlocale;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL, *value = NULL, *locale = NULL;

    mlocale = MMpull (m);
    mvalue = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mvalue == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSetLocaleValue error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));
    if (mvalue != NIL)
        value =  SCOLUTF8 (MMstartstr (m, MTOP (mvalue)), -1);
    if (mlocale != NIL)
        locale =  MMstartstr (m, MTOP (mlocale));

    g_key_file_set_locale_string (ini, group, key, locale, value);
    g_free (value);
    MMpush (m, mini);
    return 0;
}

/**
 * \brief _gkeyFileSetValueList : Associates a list of string for key under group.
 *
 * fun [ObjKeyFile S S [S r1] ObjKeyFile
 * If key cannot be found then it is created. If group cannot be found then it is created.
 *
 * \param ObjKeyFile : an object
 * \param S : a group
 * \param S : a key
 * \param [S r1] : a list of values
 * \return ObjKeyFile : the same object or nil if error
 *
 * If key or group is nil, the command is ignored but a message is written to the log
 */
int SCOL_gkeyFileSetValueList (mmachine m)
{
    int mini, mgroup, mkey, mvalues, mtmp;
    int i = 0, size = 0;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL;
    gchar ** values = NULL;

    mtmp = MMget (m, 0);    /* blurps */
    mvalues = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mvalues == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSetValueList error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));

    mvalues = MTOP (mvalues);
    mtmp = MTOP (mtmp);

    while (mtmp != NIL)
    {
        size++;
        mtmp = MMfetch (m, mtmp, 1)>>1;
    }
    values = g_new0 (gchar *, size+1);
    while (mvalues != NIL)
    {
        values[i] = SCOLUTF8 (MMstartstr (m, MTOP (MMfetch (m, mvalues, 0))), -1);
        i++;
        mvalues = MMfetch (m, mvalues, 1)>>1;
    }

    g_key_file_set_string_list (ini, group, key, (const gchar** const) values, size);
    MMpush (m, mini);
    g_strfreev (values);
    return 0;
}

/**
 * \brief _gkeyFileSetLocaleValueList : Associates a list of string for key under group.
 *
 * fun [ObjKeyFile S S S [S r1] ObjKeyFile
 * If key cannot be found then it is created. If group cannot be found then it is created.
 *
 * \param ObjKeyFile : an object
 * \param S : a group
 * \param S : a key
 * \param S : a locale identifier
 * \param [S r1] : a list of values
 * \return ObjKeyFile : the same object or nil if error
 *
 * If key or group is nil, the command is ignored but a message is written to the log
 */
int SCOL_gkeyFileSetLocaleValueList (mmachine m)
{
    int mini, mgroup, mkey, mlocale, mvalues, mtmp;
    int i = 0, size = 0;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL, *locale = NULL;
    gchar ** values = NULL;

    mtmp = MMget (m, 0);    /* blurps */
    mvalues = MMpull (m);
    mlocale = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mvalues == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSetLocaleValueList error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));
    if (mlocale != NIL)
        locale = MMstartstr (m, MTOP (mlocale));

    mvalues = MTOP (mvalues);
    mtmp = MTOP (mtmp);

    while (mtmp != NIL)
    {
        size++;
        mtmp = MMfetch (m, mtmp, 1)>>1;
    }
    values = g_new0 (gchar *, size+1);
    while (mvalues != NIL)
    {
        values[i] = SCOLUTF8 (MMstartstr (m, MTOP (MMfetch (m, mvalues, 0))), -1);
        i++;
        mvalues = MMfetch (m, mvalues, 1)>>1;
    }

    g_key_file_set_locale_string_list (ini, group, key, locale, (const gchar** const) values, size);
    MMpush (m, mini);
    g_strfreev (values);
    return 0;
}

/**
 * \brief _gkeyFileSetComment : Comments a key, a group or the key file.
 *
 * fun [ObjKeyFile S S S] ObjKeyFile
 *
 * \param ObjKeyFile : an object already created
 * \param S : a group
 * \param S : a key name
 * \param S : a comment
 * \return ObjKeyFile : the same object or nil if error
 *
 * See _gkeyFileGetComment too
 */
int SCOL_gkeyFileSetComment (mmachine m)
{
    int mini, mgroup, mkey, mcomment;
    gboolean b;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL, *comment = NULL;
    GError *err = NULL;

    mcomment = MMpull (m);
    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mcomment == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileSetComment error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    if (mgroup != NIL)
        group = MMstartstr (m, MTOP (mgroup));
    if (mkey != NIL)
        key = MMstartstr (m, MTOP (mkey));
    comment = SCOLUTF8 (MMstartstr (m, MTOP (mcomment)), -1);

    b = g_key_file_set_comment (ini, group, key, comment, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileSetComment error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    MMpush (m, mini);
    g_free (comment);
    return 0;
}

/**
 * \brief _gkeyFileRemGroup : Removes the specified group from the object.
 *
 * fun [ObjKeyFile S] ObjKeyFile
 *
 * \param ObjKeyFile : an object already created
 * \param S : a group
 * \return ObjKeyFile : the same object or nil if error
 */
int SCOL_gkeyFileRemGroup (mmachine m)
{
    int mini, mgroup;
    gboolean b;
    GKeyFile *ini;
    gchar *group = NULL;
    GError *err = NULL;

    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mgroup == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileRemGroup error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    b = g_key_file_remove_group (ini, group, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileRemGroup error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    MMpush (m, mini);
    return 0;
}

/**
 * \brief _gkeyFileRemKey : Removes the specified key in group from the object.
 *
 * fun [ObjKeyFile S S] ObjKeyFile
 *
 * \param ObjKeyFile : an object already created
 * \param S : a group
 * \param S : a key
 * \return ObjKeyFile : the same object or nil if error
 */
int SCOL_gkeyFileRemKey (mmachine m)
{
    int mini, mgroup, mkey;
    gboolean b;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL;
    GError *err = NULL;

    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mgroup == NIL) || (mkey == NIL))
    {
        MMechostr (0, "SCOL_gkeyFileRemKey error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));
    b = g_key_file_remove_key (ini, group, key, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "SCOL_gkeyFileRemKey error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    MMpush (m, mini);
    return 0;
}

/**
 * \brief _gkeyFileRemComment : Removes a comment above key from group.
 *
 * fun [ObjKeyFile S S] ObjKeyFile
 * If key is NULL then comment will be removed above group.
 * If both key and group are NULL, then comment will be removed above the first group in the file.
 *
 * \param ObjKeyFile : an object already created
 * \param S : a group
 * \param S : a key
 * \return ObjKeyFile : the same object or nil if error
 */
int SCOL_gkeyFileRemComment (mmachine m)
{
    int mini, mgroup, mkey;
    gboolean b;
    GKeyFile *ini;
    gchar *group = NULL, *key = NULL;
    GError *err = NULL;

    mkey = MMpull (m);
    mgroup = MMpull (m);
    mini = MMpull (m);

    if ((mini == NIL) || (mgroup == NIL) || (mkey == NIL))
    {
        MMechostr (0, "_gkeyFileRemComment error : bad(s) argument(s) !\n");
        MMpush (m, NIL);
        return 0;
    }

    ini = (GKeyFile*) MMfetch (m, MTOP (mini), OBJGKEYFILE_HANDLE);
    group = MMstartstr (m, MTOP (mgroup));
    key = MMstartstr (m, MTOP (mkey));
    b = g_key_file_remove_comment (ini, group, key, &err);
    if ((!b) || (err != NULL))
    {
        MMechostr (0, "_gkeyFileRemComment error : %d -> %s !\n", err->code, err->message);
        g_error_free (err);
        MMpush (m, NIL);
    }
    MMpush (m, mini);
    return 0;
}









/* API définitions : */

char* gkey_name[GKEYFILE_PKG_NB]=
{
    "ObjKeyFile",

    "_gkeyFileReadP",

    "_gkeyFileLoadS",
    "_gkeyFileLoadP",
    "_gkeyFileSave",
    "_gkeyFileDestroy",

    "_gkeyFileGetContent",
    "_gkeyFileGetDatas",
    "_gkeyFileGetGroups",
    "_gkeyFileGetNbGroups",
    "_gkeyFileDataExist",
    "_gkeyFileGetValue",
    "_gkeyFileGetLocaleValue",
    "_gkeyFileGetValueList",
    "_gkeyFileGetValueLocaleList",
    "_gkeyFileGetComment",

    "_gkeyFileSetValue",
    "_gkeyFileSetLocaleValue",
    "_gkeyFileSetValueList",
    "_gkeyFileSetLocaleValueList",
    "_gkeyFileSetComment",

    "_gkeyFileRemGroup",
    "_gkeyFileRemKey",
    "_gkeyFileRemComment",

    "GKF_VALUE_RAW",
    "GKF_VALUE_STRING",
    "GKF_VALUE_INTEGER",
    "GKF_VALUE_INTEGER64",
    "GKF_VALUE_UINTEGER64",
    "GKF_VALUE_DOUBLE",
    "GKF_VALUE_BOOLEAN"

};

int (*gkey_fun[GKEYFILE_PKG_NB])(mmachine m)=
{
    NULL,

    SCOL_gkeyFileReadP,

    SCOL_gkeyFileLoadS,
    SCOL_gkeyFileLoadP,
    SCOL_gkeyFileSave,
    SCOL_gkeyFileDestroy,

    SCOL_gkeyFileGetContent,
    SCOL_gkeyFileGetDatas,
    SCOL_gkeyFileGetGroups,
    SCOL_gkeyFileGetNbGroups,
    SCOL_gkeyFileDataExist,
    SCOL_keyFileGetValue,
    SCOL_keyFileGetLocaleValue,
    SCOL_gkeyFileGetValueList,
    SCOL_gkeyFileGetValueLocaleList,
    SCOL_gkeyFileGetComment,

    SCOL_gkeyFileSetValue,
    SCOL_gkeyFileSetLocaleValue,
    SCOL_gkeyFileSetValueList,
    SCOL_gkeyFileSetLocaleValueList,
    SCOL_gkeyFileSetComment,

    SCOL_gkeyFileRemGroup,
    SCOL_gkeyFileRemKey,
    SCOL_gkeyFileRemComment,

    GKF_VALUE_RAW,
    GKF_VALUE_STRING,
    GKF_VALUE_INTEGER,
    GKF_VALUE_INTEGER64,
    GKF_VALUE_UINTEGER64,
    GKF_VALUE_DOUBLE,
    GKF_VALUE_BOOLEAN
};

int gkey_narg[GKEYFILE_PKG_NB]=
{
    TYPTYPE,

    2,       /* SCOL_gkeyFileReadP */

    4,       /* SCOL_gkeyFileLoadS */
    4,       /* SCOL_gkeyFileLoadP */
    2,       /* SCOL_gkeyFileSave */
    1,       /* SCOL_gkeyFileDestroy */

    1,       /* SCOL_gkeyFileGetContent */
    1,       /* SCOL_gkeyFileGetDatas */
    1,       /* SCOL_gkeyFileGetGroups */
    1,       /* SCOL_gkeyFileGetNbGroups */
    3,       /* SCOL_gkeyFileDataExist */
    4,       /* SCOL_keyFileGetValue */
    4,       /* SCOL_keyFileGetLocaleValue */
    3,       /* SCOL_gkeyFileGetValueList */
    4,       /* SCOL_gkeyFileGetValueLocaleList */
    3,       /* SCOL_gkeyFileGetComment */

    5,       /* SCOL_gkeyFileSetValue */
    5,       /* SCOL_gkeyFileSetLocaleValue */
    4,       /* SCOL_gkeyFileSetValueList */
    5,       /* SCOL_gkeyFileSetLocaleValueList */
    4,       /* SCOL_gkeyFileSetComment */

    2,       /* SCOL_gkeyFileRemGroup */
    3,       /* SCOL_gkeyFileRemKey */
    3,       /* SCOL_gkeyFileRemComment */

    0,
    0,
    0,
    0,
    0,
    0,
    0
};

char* gkey_type[GKEYFILE_PKG_NB]=
{
    NULL,

    "fun [P S] [[S [[S S] r1]] r1]",        /* SCOL_gkeyFileReadP */

    "fun [Chn S S I] ObjKeyFile",           /* SCOL_gkeyFileLoadS */
    "fun [Chn P S I] ObjKeyFile",           /* SCOL_gkeyFileLoadP */
    "fun [ObjKeyFile W] I",                 /* SCOL_gkeyFileSave */
    "fun [ObjKeyFile] I",                   /* SCOL_gkeyFileDestroy */

    "fun [ObjKeyFile] [S I]",               /* SCOL_gkeyFileGetContent */
    "fun [ObjKeyFile] [[S [[S S] r1]] r1]", /* SCOL_gkeyFileGetDatas */
    "fun [ObjKeyFile] [S r1]",              /* SCOL_gkeyFileGetGroups */
    "fun [ObjKeyFile] I",                   /* SCOL_gkeyFileGetNbGroups */
    "fun [ObjKeyFile S S] I",               /* SCOL_gkeyFileDataExist */
    "fun [ObjKeyFile S S I] S",             /* SCOL_keyFileGetValue */
    "fun [ObjKeyFile S S S] S",             /* SCOL_keyFileGetLocaleValue */
    "fun [ObjKeyFile S S] [S r1]",          /* SCOL_gkeyFileGetValueList */
    "fun [ObjKeyFile S S S] [S r1]",        /* SCOL_gkeyFileGetValueLocaleList */
    "fun [ObjKeyFile S S] S",               /* SCOL_gkeyFileGetComment */

    "fun [ObjKeyFile S S S I] ObjKeyFile",  /* SCOL_gkeyFileSetValue */
    "fun [ObjKeyFile S S S S] ObjKeyFile",  /* SCOL_gkeyFileSetLocaleValue */
    "fun [ObjKeyFile S S [S r1]] ObjKeyFile",   /* SCOL_gkeyFileSetValueList */
    "fun [ObjKeyFile S S S [S r1]] ObjKeyFile", /* SCOL_gkeyFileSetLocaleValueList */
    "fun [ObjKeyFile S S S] ObjKeyFile",    /* SCOL_gkeyFileSetComment */

    "fun [ObjKeyFile S] ObjKeyFile",        /* SCOL_gkeyFileRemGroup */
    "fun [ObjKeyFile S S] ObjKeyFile",      /* SCOL_gkeyFileRemKey */
    "fun [ObjKeyFile S S] ObjKeyFile",      /* SCOL_gkeyFileRemComment */

    "fun [] I",
    "fun [] I",
    "fun [] I",
    "fun [] I",
    "fun [] I",
    "fun [] I",
    "fun [] I"
};


/** \private
 */
int ObjKeyFileTypeDestroy (mmachine m, int handsys, int mobj)
{
    GKeyFile *o;
    MMechostr (MSKDEBUG, "ObjKeyFileTypeDestroy: entering\n");

    o = (GKeyFile*) MMfetch (m, MTOP (mobj), OBJGKEYFILE_HANDLE);
    if (o == (int) NULL)
    {
        MMechostr (MSKDEBUG, "ObjKeyFileTypeDestroy : object %p already destroyed\n", (void *) o);
        return 0;
    }
    g_key_file_free (o);

    MMstore (m, MTOP (mobj), OBJGKEYFILE_HANDLE, (int) NULL);
    MMechostr (MSKDEBUG, "ObjKeyFileTypeDestroy : object %p has been destroyed\n", (void *) o);

    return 0;
}

/** \private
 */
int SCOLinitGlibKeyClass (mmachine m)
{
    int k;

    MMechostr (0, "SCOLinitGlibKeyClass : entering\n");

    ObjKeyFile = OBJregister (GKEYFILE_RFL_NB, 1, ObjKeyFileTypeDestroy, "ObjKeyFileType");

    k = PKhardpak (m, "GkeyEngine", GKEYFILE_PKG_NB, gkey_name, gkey_fun, gkey_narg, gkey_type);
    return k;
}


/**
 * \private
 * \brief Free the key file library
 * Plateforms supported : MS Windows and GNU / Linux
 */
int GkeyRelease ()
{
    MMechostr (0, "\nG KEY FILE library released !\n");
    return 0;
}


#if ((defined _WIN32) || (defined __WIN32__))
# define SCOL_GBASE_PLUGIN_EXPORT __declspec (dllexport)
#elif ((defined linux) || (defined __linux))
# define SCOL_GBASE_PLUGIN_EXPORT
#else
# error no platform supported
#endif

SCOL_GBASE_PLUGIN_EXPORT int SCOLloadGBASE(mmachine m, cbmachine w)
{
    ww = w;
    mm = m;

    SCOLinitplugin(w);
    return SCOLinitGlibKeyClass (m);
}

SCOL_GBASE_PLUGIN_EXPORT int SCOLfreeGBASE()
{
    GkeyRelease ();
    return 0;
}

