/* Chrysalide - Outil d'analyse de fichiers binaires
 * xdg.c - compléments mineurs au support Freedesktop
 *
 * Copyright (C) 2014-2018 Cyrille Bagard
 *
 *  This file is part of Chrysalide.
 *
 *  Chrysalide is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Chrysalide 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "xdg.h"


#include <assert.h>
#include <glib.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>


#include "pathname.h"



/**
 * Cf. https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
 */

/* $HOME/.cache */
#define CACHE_HOME_SUFFIX ".cache" G_DIR_SEPARATOR_S

/* $HOME/.config */
#define CONFIG_HOME_SUFFIX ".config" G_DIR_SEPARATOR_S

/* $HOME/.local/share */
#define DATA_HOME_SUFFIX ".local" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S

/* $HOME/.local/state */
#define STATE_HOME_SUFFIX ".local" G_DIR_SEPARATOR_S "state" G_DIR_SEPARATOR_S



/******************************************************************************
*                                                                             *
*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
*                create = assure la mise en place du répertoire final.        *
*                                                                             *
*  Description : Détermine le chemin d'un répertoire de données XDG.          *
*                                                                             *
*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
*                                                                             *
*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
*                                                                             *
******************************************************************************/

char *get_xdg_cache_dir(const char *suffix, bool create)
{
    char *result;                           /* Chemin d'accès à renvoyer   */
    const char *env;                        /* Valeur de l'environnement   */
    int ret;                                /* Bilan d'une assurance       */

    assert(suffix[0] != G_DIR_SEPARATOR);

    result = NULL;

    env = getenv("XDG_CACHE_HOME");

    if (env != NULL && env[0] != '\0')
    {
        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, suffix);

    }

    else
    {
        env = getenv("HOME");
        if (env == NULL || env[0] == '\0') goto no_env;

        result = calloc(strlen(env) + 1 + strlen(CACHE_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, CACHE_HOME_SUFFIX);
        strcat(result, suffix);

    }

    if (create)
    {
        ret = ensure_path_exists(result);

        if (ret != 0)
        {
            free(result);
            result = NULL;
        }

    }

 no_env:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
*                create = assure la mise en place du répertoire final.        *
*                                                                             *
*  Description : Détermine le chemin d'un répertoire de données XDG.          *
*                                                                             *
*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
*                                                                             *
*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
*                                                                             *
******************************************************************************/

char *get_xdg_config_dir(const char *suffix, bool create)
{
    char *result;                           /* Chemin d'accès à renvoyer   */
    const char *env;                        /* Valeur de l'environnement   */
    int ret;                                /* Bilan d'une assurance       */

    assert(suffix[0] != G_DIR_SEPARATOR);

    result = NULL;

    env = getenv("XDG_CONFIG_HOME");

    if (env != NULL && env[0] != '\0')
    {
        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, suffix);

    }

    else
    {
        env = getenv("HOME");
        if (env == NULL || env[0] == '\0') goto no_env;

        result = calloc(strlen(env) + 1 + strlen(CONFIG_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, CONFIG_HOME_SUFFIX);
        strcat(result, suffix);

    }

    if (create)
    {
        ret = ensure_path_exists(result);

        if (ret != 0)
        {
            free(result);
            result = NULL;
        }

    }

 no_env:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
*                create = assure la mise en place du répertoire final.        *
*                                                                             *
*  Description : Détermine le chemin d'un répertoire de données XDG.          *
*                                                                             *
*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
*                                                                             *
*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
*                                                                             *
******************************************************************************/

char *get_xdg_data_dir(const char *suffix, bool create)
{
    char *result;                           /* Chemin d'accès à renvoyer   */
    const char *env;                        /* Valeur de l'environnement   */
    int ret;                                /* Bilan d'une assurance       */

    assert(suffix[0] != G_DIR_SEPARATOR);

    result = NULL;

    env = getenv("XDG_DATA_HOME");

    if (env != NULL && env[0] != '\0')
    {
        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, suffix);

    }

    else
    {
        env = getenv("HOME");
        if (env == NULL || env[0] == '\0') goto no_env;

        result = calloc(strlen(env) + 1 + strlen(DATA_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, DATA_HOME_SUFFIX);
        strcat(result, suffix);

    }

    if (create)
    {
        ret = ensure_path_exists(result);

        if (ret != 0)
        {
            free(result);
            result = NULL;
        }

    }

 no_env:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
*                create = assure la mise en place du répertoire final.        *
*                                                                             *
*  Description : Détermine le chemin d'un répertoire de données XDG.          *
*                                                                             *
*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
*                                                                             *
*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
*                                                                             *
******************************************************************************/

char *get_xdg_state_dir(const char *suffix, bool create)
{
    char *result;                           /* Chemin d'accès à renvoyer   */
    const char *env;                        /* Valeur de l'environnement   */
    int ret;                                /* Bilan d'une assurance       */

    assert(suffix[0] != G_DIR_SEPARATOR);

    result = NULL;

    env = getenv("XDG_STATE_HOME");

    if (env != NULL && env[0] != '\0')
    {
        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, suffix);

    }

    else
    {
        env = getenv("HOME");
        if (env == NULL || env[0] == '\0') goto no_env;

        result = calloc(strlen(env) + 1 + strlen(STATE_HOME_SUFFIX) + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, STATE_HOME_SUFFIX);
        strcat(result, suffix);

    }

    if (create)
    {
        ret = ensure_path_exists(result);

        if (ret != 0)
        {
            free(result);
            result = NULL;
        }

    }

 no_env:

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : suffix = élément visé dans le répertoire de configuration.   *
*                                                                             *
*  Description : Détermine le chemin d'un répertoire éphémère XDG.            *
*                                                                             *
*  Retour      : Chemin d'accès aux configurations personnelles ou NULL.      *
*                                                                             *
*  Remarques   : cf. http://standards.freedesktop.org/basedir-spec/.          *
*                                                                             *
******************************************************************************/

char *get_xdg_runtime_dir(const char *suffix)
{
    char *result;                           /* Chemin d'accès à renvoyer   */
    const char *env;                        /* Valeur de l'environnement   */

    assert(suffix[0] != G_DIR_SEPARATOR);

    result = NULL;

    env = getenv("XDG_RUNTIME_DIR");

    if (env != NULL && env[0] != '\0')
    {
        result = calloc(strlen(env) + 1 + strlen(suffix) + 1, sizeof(char));

        strcpy(result, env);

        if (env[strlen(env) - 1] != G_DIR_SEPARATOR)
            strcat(result, G_DIR_SEPARATOR_S);

        strcat(result, suffix);

    }

    return result;

}