/* Chrysalide - Outil d'analyse de fichiers binaires
 * manager.c - prise en compte d'une syntaxe du langage d'assemblage
 *
 * Copyright (C) 2016-2017 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */


#include "manager.h"


#include <malloc.h>
#include <string.h>


#include "../helpers.h"



/* Paramèter d'une fonction de renvoi */
typedef struct _instr_func
{
    char *type;                             /* Type de fonction définie    */
    char *name;                             /* Désignation humaine         */

} instr_func;

/* Liste des fonctions de renvoi pour une instruction */
struct _instr_hooks
{
    instr_func *funcs;                      /* Liste de fonctions présentes*/
    size_t func_count;                      /* Taille de cette liste       */

};



/******************************************************************************
*                                                                             *
*  Paramètres  : -                                                            *
*                                                                             *
*  Description : Crée une liste de fonctions à lier à une instruction.        *
*                                                                             *
*  Retour      : Nouvelle structure prête à emploi.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

instr_hooks *create_instr_hooks(void)
{
    instr_hooks *result;                    /* Définition vierge à renvoyer*/

    result = (instr_hooks *)calloc(1, sizeof(instr_hooks));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : hooks = gestionnaire d'un ensemble de fonctions associées.   *
*                                                                             *
*  Description : Supprime de la mémoire une liste de fonctions liées.         *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void delete_instr_hooks(instr_hooks *hooks)
{
    size_t i;                               /* Boucle de parcours          */

    for (i = 0; i < hooks->func_count; i++)
    {
        free(hooks->funcs[i].type);
        free(hooks->funcs[i].name);
    }

    if (hooks->funcs != NULL)
        free(hooks->funcs);

    free(hooks);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : hooks = gestionnaire d'un ensemble de fonctions associées.   *
*                type  = type de fonction à enregistrer pour une instruction. *
*                name  = désignation de la fonction à associer.               *
*                                                                             *
*  Description : Enregistre l'utilité d'une fonction pour une instruction.    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void register_hook_function(instr_hooks *hooks, char *type, char *name)
{
    instr_func *func;                       /* Nouvelle prise en compte    */

    hooks->funcs = (instr_func *)realloc(hooks->funcs, ++hooks->func_count * sizeof(instr_func));

    func = &hooks->funcs[hooks->func_count - 1];

    func->type = make_string_upper(type);
    func->name = strdup(name);

}


/******************************************************************************
*                                                                             *
*  Paramètres  : hooks = gestionnaire d'un ensemble de fonctions associées.   *
*                top   = indique si l'écriture se réalise au plus haut niveau.*
*                fd    = descripteur d'un flux ouvert en écriture.            *
*                                                                             *
*  Description : Déclare des opérations complémentaires pour une instruction. *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd)
{
    bool result;                            /* Bilan à retourner           */
    size_t i;                               /* Boucle de parcours #1       */
    const instr_func *func;                 /* Nouvelle prise en compte    */

    static const char *hook_types[] = {
        "FETCH",
        "LINK",
        "POST"
    };

    const instr_func *find_hook_by_name(const instr_hooks *list, const char *type)
    {
        const instr_func *hook;             /* Trouvaille à retourner      */
        size_t k;                           /* Boucle de parcours #2       */

        hook = NULL;

        for (k = 0; k < list->func_count && hook == NULL; k++)
            if (strcmp(list->funcs[k].type, type) == 0)
                hook = &list->funcs[k];

        return hook;

    }

    result = true;

    if (hooks->func_count > 0)
    {
        if (!top)
            dprintf(fd, "\t");

        dprintf(fd, "\tstatic const instr_hook_fc hooks[IPH_COUNT] = {\n\n");

        for (i = 0; i < (sizeof(hook_types) / sizeof(hook_types[0])); i++)
        {
            func = find_hook_by_name(hooks, hook_types[i]);

            if (!top)
                dprintf(fd, "\t");

            dprintf(fd, "\t\t[IPH_%s] = (instr_hook_fc)%s,\n", hook_types[i], func != NULL ? func->name : "NULL");

        }

        dprintf(fd, "\n");

        if (!top)
            dprintf(fd, "\t");

        dprintf(fd, "\t};\n");

        dprintf(fd, "\n");

    }

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : hooks = gestionnaire d'un ensemble de fonctions associées.   *
*                top   = indique si l'écriture se réalise au plus haut niveau.*
*                fd    = descripteur d'un flux ouvert en écriture.            *
*                                                                             *
*  Description : Associe dans le code des fonctions à une instruction.        *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool write_hook_functions(const instr_hooks *hooks, bool top, int fd)
{
    bool result;                            /* Bilan à retourner           */

    result = true;

    if (hooks->func_count > 0)
    {
        if (!top)
            dprintf(fd, "\t");

        dprintf(fd, "\tg_arch_instruction_set_hooks(%s, hooks);\n",
                top ? "result" : "instr");

        dprintf(fd, "\n");

    }

    return result;

}