/* OpenIDA - Outil d'analyse de fichiers binaires
 * gbufferline.c - représentation de fragments de texte en ligne
 *
 * Copyright (C) 2010-2012 Cyrille Bagard
 *
 *  This file is part of OpenIDA.
 *
 *  OpenIDA 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.
 *
 *  OpenIDA 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 .
 */
#include "gbufferline.h"
#include 
#include     /* Récupération du langage par défaut ; FIXME ? */
#include "../common/extstr.h"
#include  /* FIXME : à virer */
/* ---------------------------- REGROUPEMENT PAR COLONNE ---------------------------- */
/* Informations sur le contenu d'une colonne */
typedef struct _buffer_line_column
{
    GBufferSegment **segments;
    size_t count;
    int max_width;                          /* Largeur max. de l'espace    */
} buffer_line_column;
/* Réinitialise une colonne de ligne. */
static void reset_column(buffer_line_column *);
/* Fournit la quantité de pixels requise pour l'impression. */
static gint get_column_width(buffer_line_column *);
/* Ajoute un fragment de texte à une colonne de ligne. */
static void add_segment_to_column(buffer_line_column *, GBufferSegment *);
/* Donne le segment d'une colonne présent à une abscisse donnée. */
static GBufferSegment *get_segment_at(const buffer_line_column *, gint);
/* Met en surbrillance des segments similaires. */
GSList *highlight_all_same_segments(const buffer_line_column *, GSList *, const GBufferSegment *);
/* Imprime le contenu d'une colonne de ligne de texte. */
static void draw_segments_of_column(buffer_line_column *, cairo_t *, GFontCache *, gint, gint);
/* ---------------------------- GESTION DE LINE COMPLETE ---------------------------- */
/* Représentation de fragments de texte en ligne (instance) */
struct _GBufferLine
{
    GObject parent;                         /* A laisser en premier        */
    vmpa_t addr;                            /* Adresse geographique        */
    BufferLineColumn main_column;           /* Colonne principale          */
    buffer_line_column columns[BLC_COUNT];  /* Répartition du texte        */
    BufferLineColumn merge_start;           /* Début de la zone globale    */
    BufferLineColumn last_used;             /* Dernière colonne utilisée   */
};
/* Représentation de fragments de texte en ligne (classe) */
struct _GBufferLineClass
{
    GObjectClass parent;                    /* A laisser en premier        */
    PangoAttrList *attribs[RTT_COUNT];      /* Décorateurs pour tampons    */
};
/* Procède à l'initialisation d'une classe de représentation. */
static void g_buffer_line_class_init(GBufferLineClass *);
/* Procède à l'initialisation d'une représentation de fragments. */
static void g_buffer_line_init(GBufferLine *);
/* ---------------------------------------------------------------------------------- */
/*                              REGROUPEMENT PAR COLONNE                              */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
*                                                                             *
*  Paramètres  : column  = colonne de ligne à mettre à jour.                  *
*                                                                             *
*  Description : Réinitialise une colonne de ligne.                           *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void reset_column(buffer_line_column *column)
{
    column->max_width = -1;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : column  = colonne de ligne à consulter.                      *
*                                                                             *
*  Description : Fournit la quantité de pixels requise pour l'impression.     *
*                                                                             *
*  Retour      : Largeur requise par la colonne, en pixel.                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static gint get_column_width(buffer_line_column *column)
{
    size_t i;                               /* Boucle de parcours          */
    if (column->max_width == -1)
    {
        column->max_width = 0;
        for (i = 0; i < column->count; i++)
            column->max_width += g_buffer_segment_get_width(column->segments[i]);
    }
    return column->max_width;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : column  = colonne de ligne à venir compléter.                *
*                segment = fragment de texte à ajouter à la colonne.          *
*                                                                             *
*  Description : Ajoute un fragment de texte à une colonne de ligne.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void add_segment_to_column(buffer_line_column *column, GBufferSegment *segment)
{
    /* FIXME : à remplacer */
    column->segments = (GBufferSegment **)realloc(column->segments, ++column->count * sizeof(GBufferSegment *));
    column->segments[column->count - 1] = segment;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : column = colonne de ligne de texte à consulter.              *
*                x      = position de recherche à ajuster.                    *
*                                                                             *
*  Description : Donne le segment d'une colonne présent à une abscisse donnée.*
*                                                                             *
*  Retour      : Segment trouvé ou NULL si hors borne.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static GBufferSegment *get_segment_at(const buffer_line_column *column, gint x)
{
    GBufferSegment *result;                 /* Trouvaille à retourner      */
    size_t i;                               /* Boucle de parcours          */
    gint width;                             /* Largeur à retirer           */
    result = NULL;
    for (i = 0; i < column->count && result == NULL; i++)
    {
        width = g_buffer_segment_get_width(column->segments[i]);
        if (width <= x)
            x -= width;
        else
            result = column->segments[i];
    }
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : column = colonne de ligne de texte à consulter.              *
*                list   = liste de segments identiques à constituer.          *
*                ref    = segment de référence à comparer avec les autres.    *
*                                                                             *
*  Description : Met en surbrillance des segments similaires.                 *
*                                                                             *
*  Retour      : Liste de segments identiques complétée.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GSList *highlight_all_same_segments(const buffer_line_column *column, GSList *list, const GBufferSegment *ref)
{
    size_t i;                               /* Boucle de parcours          */
    for (i = 0; i < column->count; i++)
        if (g_buffer_segment_compare(column->segments[i], ref))
        {
            g_buffer_segment_set_style(column->segments[i], SRS_HIGHLIGHT_SAME);
            g_object_ref(G_OBJECT(column->segments[i]));
            list = g_slist_prepend(list, column->segments[i]);
        }
    return list;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : column = colonne de ligne de texte à manipuler.              *
*                cairo  = contexte graphique à utiliser pour les pinceaux.    *
*                fcache = gestionnaire des polices pour l'impression.         *
*                x_init = abscisse du point d'impression de départ.           *
*                y      = ordonnée du point d'impression.                     *
*                                                                             *
*  Description : Imprime le contenu d'une colonne de ligne de texte.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void draw_segments_of_column(buffer_line_column *column, cairo_t *cairo, GFontCache *fcache, gint x_init, gint y)
{
    gint x;
    size_t i;
    x = x_init;
    for (i = 0; i < column->count; i++)
        g_buffer_segment_draw(column->segments[i], cairo, fcache, &x, y);
}
/* ---------------------------------------------------------------------------------- */
/*                              GESTION DE LINE COMPLETE                              */
/* ---------------------------------------------------------------------------------- */
/* Détermine le type de la représentation de fragments de texte en ligne. */
G_DEFINE_TYPE(GBufferLine, g_buffer_line, G_TYPE_OBJECT);
/******************************************************************************
*                                                                             *
*  Paramètres  : class = classe de composant GTK à initialiser.               *
*                                                                             *
*  Description : Procède à l'initialisation d'une classe de représentation.   *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_buffer_line_class_init(GBufferLineClass *class)
{
    PangoAttribute *attrib;                 /* Propriété de rendu          */
    /* RTT_RAW */
    class->attribs[RTT_RAW] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_RAW], attrib);
    /* RTT_COMMENT */
    class->attribs[RTT_COMMENT] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(14335, 45311, 23551);
    pango_attr_list_insert(class->attribs[RTT_COMMENT], attrib);
    /* RTT_INDICATION */
    class->attribs[RTT_INDICATION] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(33410, 33410, 33410);
    pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib);
    attrib = pango_attr_style_new(PANGO_STYLE_ITALIC);
    pango_attr_list_insert(class->attribs[RTT_INDICATION], attrib);
    /* RTT_RAW_CODE */
    class->attribs[RTT_RAW_CODE] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(48895, 48895, 48895);
    pango_attr_list_insert(class->attribs[RTT_RAW_CODE], attrib);
    /* RTT_INSTRUCTION */
    class->attribs[RTT_INSTRUCTION] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_INSTRUCTION], attrib);
    /* RTT_IMMEDIATE */
    class->attribs[RTT_IMMEDIATE] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(41215, 8447, 61695);
    pango_attr_list_insert(class->attribs[RTT_IMMEDIATE], attrib);
    /* RTT_REGISTER */
    class->attribs[RTT_REGISTER] = pango_attr_list_new();
    //attrib = pango_attr_foreground_new(23551, 23551, 51455);
    attrib = pango_attr_foreground_new(16895, 16895, 53759);
    pango_attr_list_insert(class->attribs[RTT_REGISTER], attrib);
    /* RTT_PUNCT */
    class->attribs[RTT_PUNCT] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_PUNCT], attrib);
    attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
    pango_attr_list_insert(class->attribs[RTT_PUNCT], attrib);
    /* RTT_HOOK */
    class->attribs[RTT_HOOK] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_HOOK], attrib);
    attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
    pango_attr_list_insert(class->attribs[RTT_HOOK], attrib);
    /* RTT_SIGNS */
    class->attribs[RTT_SIGNS] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_SIGNS], attrib);
    attrib = pango_attr_weight_new(PANGO_WEIGHT_SEMIBOLD);
    pango_attr_list_insert(class->attribs[RTT_SIGNS], attrib);
    /* RTT_LTGT */
    class->attribs[RTT_LTGT] = pango_attr_list_new();
    /* RTT_SECTION */
    class->attribs[RTT_SECTION] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(51200, 2560, 2560);
    pango_attr_list_insert(class->attribs[RTT_SECTION], attrib);
    /*
    attrib = pango_attr_foreground_new(56832, 26880, 43008);
    pango_attr_list_insert(class->attribs[RTT_SECTION], attrib);
    attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
    pango_attr_list_insert(class->attribs[RTT_SECTION], attrib);
    */
    /* RTT_SEGMENT */
    class->attribs[RTT_SEGMENT] = pango_attr_list_new();
    /* RTT_STRING */
    class->attribs[RTT_STRING] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(52224, 32256, 0);
    pango_attr_list_insert(class->attribs[RTT_STRING], attrib);
    /* RTT_VAR_NAME */
    class->attribs[RTT_VAR_NAME] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_VAR_NAME], attrib);
    /* RTT_KEY_WORD */
    class->attribs[RTT_KEY_WORD] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(0, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_KEY_WORD], attrib);
    /* RTT_ERROR */
    class->attribs[RTT_ERROR] = pango_attr_list_new();
    attrib = pango_attr_foreground_new(65535, 0, 0);
    pango_attr_list_insert(class->attribs[RTT_ERROR], attrib);
    attrib = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
    pango_attr_list_insert(class->attribs[RTT_ERROR], attrib);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line = composant GTK à initialiser.                          *
*                                                                             *
*  Description : Procède à l'initialisation d'une représentation de fragments.*
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_buffer_line_init(GBufferLine *line)
{
    BufferLineColumn i;                     /* Boucle de parcours          */
    for (i = BLC_ADDRESS; i < BLC_COUNT; i++)
        reset_column(&line->columns[i]);
    line->merge_start = BLC_COUNT;
    line->last_used = BLC_COUNT;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : addr = adresse où va se situer la ligne.                     *
*                main = colonne à référencer comme étant la principale.       *
*                                                                             *
*  Description : Crée une nouvelle représentation de fragments de texte.      *
*                                                                             *
*  Retour      : Composant GTK créé.                                          *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GBufferLine *g_buffer_line_new(vmpa_t addr, BufferLineColumn main)
{
    GBufferLine *result;                    /* Composant à retourner       */
    result = g_object_new(G_TYPE_BUFFER_LINE, NULL);
    result->addr = addr;
    result->main_column = main;
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line = ligne à venir consulter.                              *
*                                                                             *
*  Description : Indique l'adresse à laquelle se situe la ligne.              *
*                                                                             *
*  Retour      : Adresse mémoire ou physique.                                 *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
vmpa_t g_buffer_line_get_address(const GBufferLine *line)
{
    return line->addr;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line    = ligne à venir compléter.                           *
*                index   = index de la colonne visée par la procédure.        *
*                segment = fragment de texte à ajouter à la colonne.          *
*                                                                             *
*  Description : Ajoute un fragment de texte à une colonne de ligne.          *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_buffer_line_add_segment(GBufferLine *line, BufferLineColumn index, GBufferSegment *segment)
{
    add_segment_to_column(&line->columns[index], segment);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line       = ligne à venir consulter.                        *
*                max_widths = largeurs de colonne à respecter.                *
*                x          = position à la colonne visée par la procédure.   *
*                                                                             *
*  Description : Donne le segment présent à une abscisse donnée.              *
*                                                                             *
*  Retour      : Segment trouvé ou NULL si hors borne.                        *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint max_widths[BLC_COUNT], gint x)
{
    GBufferSegment *result;                 /* Trouvaille à retourner      */
    BufferLineColumn i;                     /* Boucle de parcours          */
    result = NULL;
    for (i = BLC_ADDRESS; i < BLC_COUNT; i++)
        if (x < max_widths[i]) break;
        else x -= (max_widths[i] + COL_MARGIN);
    if (i < BLC_COUNT)
        result = get_segment_at(&line->columns[i], x);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line = ligne à venir consulter.                              *
*                list = liste de segments identiques à constituer.            *
*                ref  = segment de référence à comparer avec tous les autres. *
*                                                                             *
*  Description : Met en surbrillance des segments similaires.                 *
*                                                                             *
*  Retour      : Liste de segments identiques complétée.                      *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GSList *g_buffer_line_highlight_all_same_segments(const GBufferLine *line, GSList *list, const GBufferSegment *ref)
{
    BufferLineColumn i;                     /* Boucle de parcours          */
    for (i = BLC_ADDRESS; i < BLC_COUNT; i++)
        list = highlight_all_same_segments(&line->columns[i], list, ref);
    return list;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line   = ligne à venir compléter.                            *
*                column = colonne de la ligne visée par l'insertion.          *
*                text   = texte à insérer dans l'existant.                    *
*                length = taille du texte à traiter.                          *
*                type   = type de décorateur à utiliser.                      *
*                                                                             *
*  Description : Ajoute du texte à formater dans une ligne donnée.            *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type)
{
    GBufferLineClass *class;                /* Stockage de briques de base */ 
    GBufferSegment *segment;                /* Portion de texte à ajouter  */
    if (column == BLC_MAIN)
        column = line->main_column;
    if (column == BLC_LAST_USED)
        column = line->last_used;
    else
        line->last_used = column;
    if (length == 0)
        return;
    class = G_BUFFER_LINE_GET_CLASS(line);
    segment = g_buffer_segment_new(class->attribs[type], text, length);
    g_buffer_line_add_segment(line, column, segment);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line = ligne à venir consulter.                              *
*                                                                             *
*  Description : Donne le texte représenté par une ligne de tampon.           *
*                                                                             *
*  Retour      : Texte à libérer de la mémoire après usage.                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
char *g_buffer_line_get_text(const GBufferLine *line)
{
    char *result;                           /* Construction à retourner    */
    BufferLineColumn i;                     /* Boucle de parcours #1       */
    size_t j;                               /* Boucle de parcours #2       */
    result = NULL;
    for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++)
        for (j = 0; j < line->columns[i].count; j++)
            if (result == NULL)
            {
                result = strdup(g_buffer_segment_get_text(line->columns[i].segments[j]));
                result = stradd(result, " ");
            }
            else
                result = stradd(result, g_buffer_segment_get_text(line->columns[i].segments[j]));
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line  = ligne à venir compléter.                             *
*                index = index de la colonne visée par la procédure.          *
*                                                                             *
*  Description : Fournit la largeur requise pour une colonne de ligne donnée. *
*                                                                             *
*  Retour      : Largeur en pixel requise.                                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
gint g_buffer_line_get_column_width(GBufferLine *line, BufferLineColumn index)
{
    gint result;                            /* Largeur à retourner         */
    if (index >= line->merge_start) result = 0;
    else result = get_column_width(&line->columns[index]);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line  = ligne à venir compléter.                             *
*                merge = précise la première colonne marquant la fusion. [OUT]*
*                addr  = indique si les positions doivent être affichées.     *
*                code  = indique si le code binaire doit être affiché.        *
*                                                                             *
*  Description : Fournit la dernière largeur d'une ligne avec fusion.         *
*                                                                             *
*  Retour      : Largeur en pixel requise.                                    *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
gint g_buffer_line_get_merge_width(GBufferLine *line, BufferLineColumn *merge, bool addr, bool code)
{
    gint result;                            /* Largeur à retourner         */
    result = 0;
    *merge = line->merge_start;
    if (line->merge_start < BLC_COUNT)
        result = get_column_width(&line->columns[line->merge_start]);
    return result;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line  = ligne à venir compléter.                             *
*                start = début de la première (et unique) zone globale.       *
*                                                                             *
*  Description : Définit la colonne à partir de laquelle la fusion opère.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start)
{
    if (start == BLC_LAST_USED)
        line->merge_start = line->last_used;
    else
        line->merge_start = start;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line       = ligne de texte à manipuler.                     *
*                cairo      = contexte graphique à utiliser pour les pinceaux.*
*                fcache     = gestionnaire des polices pour l'impression.     *
*                max_widths = largeurs de colonne à respecter.                *
*                x_init     = abscisse du point d'impression de départ.       *
*                y          = ordonnée du point d'impression.                 *
*                addr       = indique si les positions doivent être affichées.*
*                code       = indique si le code binaire doit être affiché.   *
*                                                                             *
*  Description : Imprime la ligne de texte représentée.                       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, GFontCache *fcache, const gint max_widths[BLC_COUNT], gint x_init, gint y, bool addr, bool code)
{
    gint x;                                 /* Point de départ d'impression*/
    BufferLineColumn i;                     /* Boucle de parcours          */
    x = x_init;
    for (i = BLC_ADDRESS; i < BLC_COUNT; i++)
    {
        if (i == BLC_ADDRESS && !addr) continue;
        if (i == BLC_BINARY && !code) continue;
        draw_segments_of_column(&line->columns[i], cairo, fcache, x, y);
        if (i < line->merge_start)
            x += max_widths[i] + COL_MARGIN;
    }
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line    = ligne de texte à manipuler.                        *
*                fd      = flux ouvert en écriture.                           *
*                type    = type d'exportation attendue.                       *
*                addr    = indique si les positions doivent être affichées.   *
*                code    = indique si le code binaire doit être affiché.      *
*                content = indique si le gros du contenu doit être affiché.   *
*                                                                             *
*  Description : Exporte la ligne de texte représentée.                       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_buffer_line_export(GBufferLine *line, int fd, BufferExportType type, bool addr, bool code, bool content)
{
    BufferLineColumn i;                     /* Boucle de parcours          */
    for (i = BLC_ADDRESS; i < BLC_COUNT; i++)
    {
        if (i == BLC_ADDRESS && !addr) continue;
        if (i == BLC_BINARY && !code) continue;
        if (!(i == BLC_ADDRESS || i == BLC_BINARY) && !content) continue;
        dprintf(fd, "TODO\n");
    }
}