From adb98feb93f09d8de343c504a0c8c72815d62dab Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 23 Jan 2016 18:48:50 +0100
Subject: Created storable items for user comments.

---
 plugins/pychrysa/analysis/db/items/comment.c |   3 +-
 src/analysis/db/collection.c                 |  39 ++-
 src/analysis/db/items/bookmark.c             |   2 +-
 src/analysis/db/items/comment.c              | 460 ++++++++++++++++++++++++++-
 src/analysis/db/items/comment.h              |   6 +-
 src/analysis/db/items/switcher.c             |   2 +-
 src/analysis/disass/output.c                 |   2 +
 src/common/sqlite.h                          |   5 +-
 src/format/symbol.h                          |  20 +-
 src/glibext/gbufferline.c                    |  59 ++++
 src/glibext/gbufferline.h                    |   3 +
 src/glibext/gcodebuffer.c                    |  74 ++++-
 src/glibext/gcodebuffer.h                    |   7 +-
 13 files changed, 634 insertions(+), 48 deletions(-)

diff --git a/plugins/pychrysa/analysis/db/items/comment.c b/plugins/pychrysa/analysis/db/items/comment.c
index 951f6ce..ead5179 100644
--- a/plugins/pychrysa/analysis/db/items/comment.c
+++ b/plugins/pychrysa/analysis/db/items/comment.c
@@ -81,7 +81,8 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject
     addr = get_internal_vmpa(py_vmpa);
     if (py_vmpa == NULL) Py_RETURN_NONE;
 
-    comment = g_db_comment_new(addr, text, is_volatile);
+    return NULL;/* FIXME */
+    //comment = g_db_comment_new(addr, text, is_volatile);
 
     result = pygobject_new(G_OBJECT(comment));
     g_object_unref(comment);
diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index d5518dd..aa7591e 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -992,15 +992,21 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
             /**
              * On réalise une petite conversion selon le champ.
              *
-             * Le filtre SQLITE_NATIVE est destiné à conserver un champ sur 32 bits
-             * quand il s'agit du format utilisé, même si toutes les valeurs sont
-             * enregistrées en 64 bits.
+             * Le filtre SQLITE_NATIVE est destiné à conserver le type choisi par
+             * SQLite. Typiquement, une chaîne peut être à SQLITE_NULL ou SQLITE_TEXT
+             * selon la valeur conservée dans la base.
              *
-             * C'est par exemple le cas dans les bascules d'affichage.
-             *
-             * D'autres éléments, comme les localisations en mémoire, peuvent
+             * D'autres éléments, comme les localisations en mémoire, peuvent aussi
              * avoir un champ éventuellement nul, donc la définition à partir des
              * indications de la base de données reste importante.
+             *
+             * En ce qui concerne les valeurs numériques, SQLite ne fait pas de
+             * distinction : tout passe par la fonction sqlite3VdbeIntValue(),
+             * qui effectue des transtypages au besoin pour tout ce qui n'est
+             * pas numérique.
+             *
+             * Pour les types internes SQLITE_INTEGER et SQLITE_BOOLEAN,
+             * il est donc nécessaire d'ajuster en interne.
              */
 
             if (native_type == SQLITE_INTEGER)
@@ -1010,13 +1016,18 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db)
                 values[i].type = native_type;
 
             else
-                assert(values[i].type == native_type || values[i].type == SQLITE_INTEGER);
-
+                assert(values[i].type == native_type
+                       || values[i].type == SQLITE_INTEGER
+                       || values[i].type == SQLITE_BOOLEAN);
 
             switch (values[i].type)
             {
+                case SQLITE_BOOLEAN:
+                    values[i].boolean = (bool)sqlite3_column_int(stmt, i);
+                    break;
+
                 case SQLITE_INTEGER:
-                    values[i].integer = (int)sqlite3_column_int64(stmt, i);
+                    values[i].integer = sqlite3_column_int(stmt, i);
                     break;
 
                 case SQLITE_INT64:
@@ -1142,6 +1153,11 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte
     {
         switch (values[i].type)
         {
+            case SQLITE_BOOLEAN:
+                ret = sqlite3_bind_int(stmt, index, values[i].boolean);
+                index++;
+                break;
+
             case SQLITE_INTEGER:
                 ret = sqlite3_bind_int(stmt, index, values[i].integer);
                 index++;
@@ -1301,6 +1317,11 @@ static bool g_db_collection_store_updated_item(const GDbCollection *collec, cons
 
         switch (values[i].type)
         {
+            case SQLITE_BOOLEAN:
+                ret = sqlite3_bind_int(stmt, index, values[i].boolean);
+                index++;
+                break;
+
             case SQLITE_INTEGER:
                 ret = sqlite3_bind_int(stmt, index, values[i].integer);
                 index++;
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index 6914bc3..4c93faf 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -393,7 +393,7 @@ static void g_db_bookmark_build_label(GDbBookmark *bookmark)
 *                                                                             *
 *  Paramètres  : bookmark = signet à manipuler.                               *
 *                binary   = binaire chargé en mémoire à modifier.             *
-*                prev     = état précédent de la présence du drapeau.         *
+*                prev     = état précédent de la présence du drapeau. [OUT]   *
 *                set      = précision quant au nouvel état du drapeau.        *
 *                                                                             *
 *  Description : Exécute un signet sur un tampon de binaire chargé.           *
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 9212cae..b4a1dc0 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -24,12 +24,18 @@
 #include "comment.h"
 
 
+#include <assert.h>
+#include <malloc.h>
 #include <stdio.h>
 #include <sys/socket.h>
 
 
+#include <i18n.h>
+
+
 #include "../collection-int.h"
 #include "../item-int.h"
+#include "../../../common/io.h"
 
 
 
@@ -42,8 +48,21 @@ struct _GDbComment
     GDbItem parent;                         /* A laisser en premier        */
 
     vmpa2t addr;                            /* Adresse du commentaire      */
+    BufferLineFlags flags;                  /* Identification de l'accroche*/
+
     rle_string text;                        /* Contenu du commentaire      */
 
+    bool inlined;                           /* Intégration dans une ligne ?*/
+
+    union
+    {
+        bool repeatable;                    /* Répétition aux lignes liées */
+        bool before;                        /* Zone dédiée au dessus ?     */
+    };
+
+    GDbComment **oldies;                    /* Commentaires d'origine ?    */
+    size_t old_count;                       /* Nombre de places à restaurer*/
+
 };
 
 /* Commentaire à placer dans du texte quelconque (classe) */
@@ -75,6 +94,18 @@ static bool g_db_comment_recv_from_fd(GDbComment *, int, int);
 /* Exporte la définition d'un commentaire dans un flux réseau. */
 static bool g_db_comment_send_to_fd(const GDbComment *, int, int);
 
+/* Construit la description humaine d'un commentaire. */
+static void g_db_comment_build_label(GDbComment *);
+
+/* Exécute l'impression de commentaire dans du code de binaire. */
+static bool g_db_comment_run(GDbComment *, GLoadedBinary *, bool);
+
+/* Réalise l'impression de commentaire dans du code de binaire. */
+static bool g_db_comment_apply(GDbComment *, GLoadedBinary *);
+
+/* Annule l'impression d'un commentaire dans du code de binaire. */
+static bool g_db_comment_cancel(GDbComment *, GLoadedBinary *);
+
 /* Constitue les champs destinés à une insertion / modification. */
 static bool g_db_comment_prepare_db_statement(const GDbComment *, bound_value **, size_t *);
 
@@ -162,6 +193,10 @@ static void g_db_comment_class_init(GDbCommentClass *klass)
     item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd;
     item->send = (send_db_item_fc)g_db_comment_send_to_fd;
 
+    item->build_label = (build_item_label_fc)g_db_comment_build_label;
+    item->apply = (run_item_fc)g_db_comment_apply;
+    item->cancel = (run_item_fc)g_db_comment_cancel;
+
     item->prepare_stmt = (prepare_db_statement)g_db_comment_prepare_db_statement;
     item->load = (load_db_item_fc)g_db_comment_load;
 
@@ -200,6 +235,14 @@ static void g_db_comment_init(GDbComment *comment)
 
 static void g_db_comment_dispose(GDbComment *comment)
 {
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < comment->old_count; i++)
+        g_object_unref(G_OBJECT(comment->oldies[i]));
+
+    if (comment->oldies != NULL)
+        free(comment->oldies);
+
     G_OBJECT_CLASS(g_db_comment_parent_class)->dispose(G_OBJECT(comment));
 
 }
@@ -228,9 +271,10 @@ static void g_db_comment_finalize(GDbComment *comment)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : addr        = adresse inamovible localisant une position.    *
-*                text        = commentaire construit ou NULL.                 *
-*                is_volatile = état du besoin en sauvegarde.                  *
+*  Paramètres  : addr       = adresse inamovible localisant une position.     *
+*                flags      = indentifiants supplémentaires de ligne visée.   *
+*                text       = commentaire construit ou NULL.                  *
+*                repeatable = repétition aux instructions liées ?             *
 *                                                                             *
 *  Description : Crée une définition de commentaire dans une zone de texte.   *
 *                                                                             *
@@ -240,7 +284,7 @@ static void g_db_comment_finalize(GDbComment *comment)
 *                                                                             *
 ******************************************************************************/
 
-GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volatile)
+GDbComment *g_db_comment_new_inlined(const vmpa2t *addr, BufferLineFlags flags, const char *text, bool repeatable)
 {
     GDbComment *result;                    /* Instance à retourner        */
 
@@ -248,9 +292,49 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat
 
     copy_vmpa(&result->addr, addr);
 
+    result->flags = flags;
+
     g_db_comment_set_text(result, text);
 
-    g_db_item_set_volatile(G_DB_ITEM(result), is_volatile);
+    result->inlined = true;
+
+    result->repeatable = repeatable;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : addr   = adresse inamovible localisant une position.         *
+*                flags  = indentifiants supplémentaires de ligne visée.       *
+*                text   = commentaire construit ou NULL.                      *
+*                before = précision quant à la position de la zone à définir. *
+*                                                                             *
+*  Description : Crée une définition de commentaire dans une zone de texte.   *
+*                                                                             *
+*  Retour      : Commentaire mis en place ou NULL en cas d'erreur.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GDbComment *g_db_comment_new_area(const vmpa2t *addr, BufferLineFlags flags, const char *text, bool before)
+{
+    GDbComment *result;                    /* Instance à retourner        */
+
+    result = g_object_new(G_TYPE_DB_COMMENT, NULL);
+
+    copy_vmpa(&result->addr, addr);
+
+    result->flags = flags;
+
+    g_db_comment_set_text(result, text);
+
+    result->inlined = false;
+
+    result->before = before;
 
     return result;
 
@@ -305,6 +389,8 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b, bool with)
 static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
 {
     bool status;                            /* Bilan d'opération initiale  */
+    uint32_t val32;                         /* Valeur sur 32 bits          */
+    uint8_t val8;                           /* Valeur sur 8 bits           */
 
     status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->recv(G_DB_ITEM(comment), fd, flags);
     if (!status) return false;
@@ -312,9 +398,24 @@ static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags)
     if (!recv_vmpa(&comment->addr, fd, flags))
         return false;
 
+    status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags);
+    if (!status) return false;
+
+    comment->flags = be32toh(val32);
+
     if (!recv_rle_string(&comment->text, fd, flags))
         return false;
 
+    status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
+    if (!status) return false;
+
+    comment->inlined = val8;
+
+    status = safe_recv(fd, &val8, sizeof(uint8_t), MSG_WAITALL | flags);
+    if (!status) return false;
+
+    comment->repeatable = val8;
+
     return true;
 
 }
@@ -344,9 +445,18 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
     if (!send_vmpa(&comment->addr, fd, MSG_MORE | flags))
         return false;
 
-    if (!send_rle_string(&comment->text, fd, flags))
+    status = safe_send(fd, (uint32_t []) { htobe32(comment->flags) }, sizeof(uint32_t), MSG_MORE | flags);
+    if (!status) return false;
+
+    if (!send_rle_string(&comment->text, fd, MSG_MORE | flags))
         return false;
 
+    status = safe_send(fd, (uint8_t []) { (uint8_t)comment->inlined }, sizeof(uint8_t), MSG_MORE | flags);
+    if (!status) return false;
+
+    status = safe_send(fd, (uint8_t []) { (uint8_t)comment->repeatable }, sizeof(uint8_t), flags);
+    if (!status) return false;
+
     return true;
 
 }
@@ -354,6 +464,250 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : comment = définition de commentaire à manipuler.             *
+*                                                                             *
+*  Description : Construit la description humaine d'un commentaire.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_db_comment_build_label(GDbComment *comment)
+{
+    VMPA_BUFFER(loc);                       /* Indication de position      */
+
+    if (has_virt_addr(&comment->addr))
+        vmpa2_virt_to_string(&comment->addr, MDS_UNDEFINED, loc, NULL);
+    else
+        vmpa2_phys_to_string(&comment->addr, MDS_UNDEFINED, loc, NULL);
+
+    if (is_rle_string_empty(&comment->text))
+        asprintf(&G_DB_ITEM(comment)->label, _("Delete comment at %s"), loc);
+
+    else
+    {
+        if (comment->inlined)
+            asprintf(&G_DB_ITEM(comment)->label, _("Enter inlined comment at %s"), loc);
+        else
+            asprintf(&G_DB_ITEM(comment)->label, _("Enter comment area at %s"), loc);
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : comment = définition de commentaire à manipuler.             *
+*                binary  = binaire chargé en mémoire à modifier.              *
+*                apply   = indique s'il faut appliquer la définition ou non.  *
+*                                                                             *
+*  Description : Exécute l'impression de commentaire dans du code de binaire. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool apply)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    GCodeBuffer *buffer;                    /* Tampon de lignes à traiter  */
+    GBufferLine *line;                      /* Ligne de tampon à marquer   */
+    GArchProcessor *proc;                   /* Propriétaire d'instructions */
+    GArchInstruction *instr;                /* Instruction à traiter       */
+    GArchInstruction **sources;             /* Instructions diverses liées */
+    size_t scount;                          /* Nbre de sources affichées   */
+    size_t i;                               /* Boucle de parcours          */
+    const mrange_t *range;                  /* Emplacement d'instruction   */
+    GBufferLine *linked;                    /* Ligne liée à traiter        */
+    GDbComment *old;                        /* Ancien élément à restaurer  */
+
+    result = true;
+
+    /* Recherche de la ligne visée */
+
+    buffer = g_loaded_binary_get_disassembled_buffer(binary);
+
+    line = g_code_buffer_find_line_by_addr(buffer, &comment->addr, comment->flags, NULL);
+    if (line == NULL)
+    {
+        result = false;
+        goto exit_gui;
+    }
+
+    /* Détermination de l'imprimeur précédent */
+
+    if (apply)
+    {
+        assert(comment->old_count == 0);
+
+        comment->old_count = 1;
+        comment->oldies = (GDbComment **)calloc(comment->old_count, sizeof(GDbComment *));
+
+    }
+
+    /* Applications globales finales */
+
+#define g_code_buffer_update_inlined_comment_dummy(b, l, c, d, o)   \
+    g_code_buffer_update_inlined_comment(b, l, c, o)
+
+    /**
+     * Note : on part du principe qu'un commentaire intégré ne peut remplacer qu'un
+     * commentaire intégré. Et pareil pour les commentaires en blocs.
+     */
+
+#define RUN_COMMENT_ON(ln, idx, func)                                                               \
+    if (apply)                                                                                      \
+    {                                                                                               \
+        comment->oldies[idx] = (GDbComment *)g_code_buffer_get_comment_creator(buffer, ln);         \
+        assert(comment->oldies[idx] == NULL || G_IS_DB_COMMENT(comment->oldies[idx]));              \
+        assert(comment->oldies[idx] == NULL || comment->oldies[idx]->inlined == comment->inlined);  \
+                                                                                                    \
+        if (is_rle_string_empty(&comment->text))                                                    \
+            result = g_code_buffer_delete_lines_comment(buffer, ln);                                \
+        else                                                                                        \
+            result = func(buffer, ln, get_rle_string(&comment->text),                               \
+                          comment->before, G_OBJECT(comment));                                      \
+    }                                                                                               \
+    else                                                                                            \
+    {                                                                                               \
+        old = comment->oldies[idx];                                                                 \
+                                                                                                    \
+        if (old == NULL)                                                                            \
+        {                                                                                           \
+            if (!is_rle_string_empty(&comment->text))                                               \
+                result = g_code_buffer_delete_lines_comment(buffer, ln);                            \
+            else                                                                                    \
+                result = true;                                                                      \
+        }                                                                                           \
+        else                                                                                        \
+        {                                                                                           \
+            if (is_rle_string_empty(&old->text))                                                    \
+                result = g_code_buffer_delete_lines_comment(buffer, ln);                            \
+            else                                                                                    \
+                result = func(buffer, ln, get_rle_string(&old->text),                               \
+                              old->before, G_OBJECT(old));                                          \
+        }                                                                                           \
+                                                                                                    \
+    }
+
+    if (comment->inlined)
+    {
+        /* Traitement d'un commentaire inscrusté */
+
+        RUN_COMMENT_ON(line, 0, g_code_buffer_update_inlined_comment_dummy);
+
+        /* Traitement des répétitions ? */
+
+        if (comment->repeatable/* && result*/)
+        {
+            proc = g_loaded_binary_get_processor(binary);
+
+            range = g_buffer_line_get_range(line);
+
+            instr = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range));
+            assert(instr != NULL);
+
+            scount = g_arch_instruction_get_sources(instr, &sources, NULL);
+
+            if (apply)
+            {
+                comment->old_count += scount;
+                comment->oldies = (GDbComment **)realloc(comment->oldies,
+                                                         comment->old_count * sizeof(GDbComment *));
+            }
+
+            for (i = 0; i < scount && result; i++)
+            {
+                range = g_arch_instruction_get_range(sources[i]);
+
+                /**
+                 * On recherche ici une ligne potentiellement BLF_HAS_CODE ou BLF_IS_LABEL.
+                 * Comme on ne peut pas traiter les deux cas, on prend la première qui vient
+                 * avec BLF_NONE.
+                 */
+                linked = g_code_buffer_find_line_by_addr(buffer, get_mrange_addr(range), BLF_NONE, NULL);
+                assert(linked != NULL);
+
+                RUN_COMMENT_ON(linked, 1 + i, g_code_buffer_update_inlined_comment_dummy);
+
+            }
+
+            g_object_unref(G_OBJECT(proc));
+
+        }
+
+    }
+
+    else
+    {
+        RUN_COMMENT_ON(line, 0, g_code_buffer_update_comment_area);
+    }
+
+    g_object_unref(G_OBJECT(line));
+
+ exit_gui:
+
+    /* TODO g_object_unref(G_OBJECT(buffer));*/
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : comment = définition de commentaire à manipuler.             *
+*                binary  = binaire chargé en mémoire à modifier.              *
+*                                                                             *
+*  Description : Réalise l'impression de commentaire dans du code de binaire. *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_db_comment_apply(GDbComment *comment, GLoadedBinary *binary)
+{
+    bool result;                            /* Bilan à faire remonter      */
+
+    result = g_db_comment_run(comment, binary, true);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : comment = définition de commentaire à manipuler.             *
+*                binary  = binaire chargé en mémoire à modifier.              *
+*                                                                             *
+*  Description : Annule l'impression d'un commentaire dans du code de binaire.*
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_db_comment_cancel(GDbComment *comment, GLoadedBinary *binary)
+{
+    bool result;                            /* Bilan à faire remonter      */
+
+    result = g_db_comment_run(comment, binary, false);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : comment = base d'éléments sur laquelle s'appuyer.            *
 *                values   = couples de champs et de valeurs à lier. [OUT]     *
 *                count    = nombre de ces couples. [OUT]                      *
@@ -369,6 +723,7 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags
 static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_value **values, size_t *count)
 {
     bool status;                            /* Bilan d'opération initiale  */
+    bound_value *value;                     /* Valeur à éditer / définir   */
 
     status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->prepare_stmt(G_DB_ITEM(comment), values, count);
     if (!status) return false;
@@ -376,9 +731,36 @@ static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_v
     status = prepare_vmpa_db_statement(&comment->addr, values, count);
     if (!status) return false;
 
+    *count += 1;
+    *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+    value = &(*values)[*count - 1];
+
+    value->name = "flags";
+    value->type = SQLITE_INTEGER;
+    value->integer = comment->flags;
+    value->delete = NULL;
+
     status &= prepare_db_statement_for_rle_string(&comment->text, "text", values, count);
     if (!status) return false;
 
+    *count += 2;
+    *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+    value = &(*values)[*count - 2];
+
+    value->name = "inlined";
+    value->type = SQLITE_BOOLEAN;
+    value->boolean = comment->inlined;
+    value->delete = NULL;
+
+    value = &(*values)[*count - 1];
+
+    value->name = "repeatable";
+    value->type = SQLITE_BOOLEAN;
+    value->boolean = comment->repeatable;
+    value->delete = NULL;
+
     return true;
 
 }
@@ -401,13 +783,44 @@ static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_v
 static bool g_db_comment_load(GDbComment *comment, const bound_value *values, size_t count)
 {
     bool result;                            /* Bilan à faire remonter      */
+    const bound_value *value;               /* Valeur à éditer / définir   */
 
     result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->load(G_DB_ITEM(comment), values, count);
 
     result &= load_vmpa(&comment->addr, values, count);
 
+    if (result)
+    {
+        value = find_bound_value(values, count, "flags");
+        result = (value != NULL && value->type == SQLITE_INTEGER);
+
+        if (result)
+            comment->flags = value->integer;
+
+    }
+
     result &= load_rle_string(&comment->text, "text", values, count);
 
+    if (result)
+    {
+        value = find_bound_value(values, count, "inlined");
+        result = (value != NULL && value->type == SQLITE_BOOLEAN);
+
+        if (result)
+            comment->inlined = value->boolean;
+
+    }
+
+    if (result)
+    {
+        value = find_bound_value(values, count, "repeatable");
+        result = (value != NULL && value->type == SQLITE_BOOLEAN);
+
+        if (result)
+            comment->repeatable = value->boolean;
+
+    }
+
     return result;
 
 }
@@ -526,7 +939,7 @@ static void g_comment_collection_class_init(GCommentCollectionClass *klass)
 
 static void g_comment_collection_init(GCommentCollection *collec)
 {
-    G_DB_COLLECTION(collec)->featuring = 0;
+    G_DB_COLLECTION(collec)->featuring = DBF_COMMENTS;
     G_DB_COLLECTION(collec)->type = G_TYPE_DB_COMMENT;
     G_DB_COLLECTION(collec)->name = "Comments";
 
@@ -613,10 +1026,13 @@ static bool g_comment_collection_create_db_table(const GCommentCollection *colle
     int ret;                                /* Bilan de la création        */
     char *msg;                              /* Message d'erreur            */
 
-    sql = "CREATE TABLE Comments ("         \
-             SQLITE_DB_ITEM_CREATE ", "     \
-             SQLITE_VMPA_CREATE ", "        \
-             SQLITE_RLESTR_CREATE("text")   \
+    sql = "CREATE TABLE Comments ("             \
+             SQLITE_DB_ITEM_CREATE ", "         \
+             SQLITE_VMPA_CREATE ", "            \
+             "flags INTEGER, "                  \
+             SQLITE_RLESTR_CREATE("text") ", "  \
+             "inlined INTEGER, "                \
+             "repeatable INTEGER"               \
           ");";
 
     ret = sqlite3_exec(db, sql, NULL, NULL, &msg);
@@ -648,6 +1064,7 @@ static bool g_comment_collection_create_db_table(const GCommentCollection *colle
 static bool g_comment_collection_setup_load(GCommentCollection *collec, bound_value **values, size_t *count)
 {
     bool status;                            /* Bilan d'une préparation     */
+    bound_value *value;                     /* Valeur à éditer / définir   */
 
     status = G_DB_COLLECTION_CLASS(g_comment_collection_parent_class)->setup_load(G_DB_COLLECTION(collec), \
                                                                                   values, count);
@@ -656,9 +1073,30 @@ static bool g_comment_collection_setup_load(GCommentCollection *collec, bound_va
     if (!setup_load_for_vmpa(NULL, values, count))
         return false;
 
+    *count += 1;
+    *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+    value = &(*values)[*count - 1];
+
+    value->name = "flags";
+    value->type = SQLITE_INTEGER;
+
     if (!setup_load_of_rle_string(NULL, "text", values, count))
         return false;
 
+    *count += 2;
+    *values = (bound_value *)realloc(*values, *count * sizeof(bound_value));
+
+    value = &(*values)[*count - 2];
+
+    value->name = "inlined";
+    value->type = SQLITE_BOOLEAN;
+
+    value = &(*values)[*count - 1];
+
+    value->name = "repeatable";
+    value->type = SQLITE_BOOLEAN;
+
     return true;
 
 }
diff --git a/src/analysis/db/items/comment.h b/src/analysis/db/items/comment.h
index 316f4c5..dc9addc 100644
--- a/src/analysis/db/items/comment.h
+++ b/src/analysis/db/items/comment.h
@@ -32,6 +32,7 @@
 
 
 #include "../../../arch/vmpa.h"
+#include "../../../glibext/gbufferline.h"
 
 
 
@@ -57,7 +58,10 @@ typedef struct _GDbCommentClass GDbCommentClass;
 GType g_db_comment_get_type(void);
 
 /* Crée une définition de commentaire dans une zone de texte. */
-GDbComment *g_db_comment_new(const vmpa2t *, const char *, bool);
+GDbComment *g_db_comment_new_inlined(const vmpa2t *, BufferLineFlags, const char *, bool);
+
+/* Crée une définition de commentaire dans une zone de texte. */
+GDbComment *g_db_comment_new_area(const vmpa2t *, BufferLineFlags, const char *, bool);
 
 /* Fournit l'adresse associée à un commentaire. */
 const vmpa2t *g_db_comment_get_address(GDbComment *);
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 7b72cf2..6497e41 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -481,7 +481,7 @@ static void g_db_switcher_build_label(GDbSwitcher *switcher)
 *                                                                             *
 *  Paramètres  : switcher = bascule d'affichage à manipuler.                  *
 *                binary   = binaire chargé en mémoire à modifier.             *
-*                old      = état précédent à conserver.                       *
+*                old      = état précédent à conserver. [OUT]                 *
 *                new      = nouvel état à appliquer.                          *
 *                                                                             *
 *  Description : Exécute une bascule d'affichage d'opérande sur un binaire.   *
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index 75444a5..07165c0 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -269,6 +269,8 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form
                 if (comment != NULL)
                 {
 
+                    /* FIXME : appliquer ! */
+
                     text = g_db_comment_get_text(comment);
 
 
diff --git a/src/common/sqlite.h b/src/common/sqlite.h
index 2036589..064972b 100644
--- a/src/common/sqlite.h
+++ b/src/common/sqlite.h
@@ -25,6 +25,7 @@
 #define _COMMON_SQLITE_H
 
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -33,7 +34,8 @@
 /* Type pour les insertions brutes */
 #define SQLITE_RAW      0                   /* En dur dans une requête     */
 #define SQLITE_INT64    10                  /* Entier sur 64 bits          */
-#define SQLITE_NATIVE   11                  /* Déterminé par la base       */
+#define SQLITE_BOOLEAN  11                  /* Booléen sur 1 bit           */
+#define SQLITE_NATIVE   12                  /* Déterminé par la base       */
 
 
 /* Description des champs et de leur valeur associée */
@@ -44,6 +46,7 @@ typedef struct _bound_value
 
     union
     {
+        bool boolean;                       /* Etat sur 1 bit              */
         int32_t integer;                    /* Nombre sur 32 bits          */
         int64_t integer64;                  /* Nombre sur 64 bits          */
         char *string;                       /* Chaîne de caractères #1     */
diff --git a/src/format/symbol.h b/src/format/symbol.h
index 94003bb..6f2078c 100644
--- a/src/format/symbol.h
+++ b/src/format/symbol.h
@@ -29,6 +29,7 @@
 
 
 #include "../analysis/routine.h"
+#include "../analysis/db/item.h"
 #include "../analysis/db/items/comment.h"
 #include "../arch/instruction.h"
 
@@ -129,15 +130,16 @@ GDbComment *g_binary_symbol_get_comment(const GBinSymbol *);
     }                                                                   \
     while (0)
 
-#define ADD_RAW_AS_SYM(_fmt, _sym, _pos, _ins, _cmt, _txt)      \
-    do                                                          \
-    {                                                           \
-        _cmt = g_db_comment_new(_pos, _txt, true);              \
-        _sym = g_binary_symbol_new(STP_DATA);                   \
-        g_binary_symbol_attach_instruction(_sym, _ins);         \
-        g_binary_symbol_set_comment(_sym, _cmt);                \
-        g_binary_format_add_symbol(G_BIN_FORMAT(_fmt), _sym);   \
-    }                                                           \
+#define ADD_RAW_AS_SYM(_fmt, _sym, _pos, _ins, _cmt, _txt)                  \
+    do                                                                      \
+    {                                                                       \
+        _cmt = g_db_comment_new_inlined(_pos, BLF_HAS_CODE, _txt, false);   \
+        g_db_item_set_volatile(G_DB_ITEM(_cmt), true);                      \
+        _sym = g_binary_symbol_new(STP_DATA);                               \
+        g_binary_symbol_attach_instruction(_sym, _ins);                     \
+        g_binary_symbol_set_comment(_sym, _cmt);                            \
+        g_binary_format_add_symbol(G_BIN_FORMAT(_fmt), _sym);               \
+    }                                                                       \
     while (0)
 
 #define ADD_STR_AS_SYM(_fmt, _sym, _ins)                        \
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 2f29ee4..b8838ae 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -78,6 +78,9 @@ static GBufferSegment *get_segment_at(const buffer_line_column *, gint *, GdkScr
 static GBufferSegment *find_near_segment(const buffer_line_column *, GBufferSegment *, GdkScrollDirection);
 
 /* Fournit le segment créé par un objet particulier. */
+static GObject *find_first_segment_creator(const buffer_line_column *);
+
+/* Fournit le segment créé par un objet particulier. */
 static GBufferSegment *find_segment_from_creator(const buffer_line_column *, GObject *);
 
 /* Imprime le contenu d'une colonne de ligne de texte. */
@@ -410,6 +413,33 @@ static GBufferSegment *find_near_segment(const buffer_line_column *column, GBuff
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : column = colonne de ligne de texte à consulter.              *
+*                                                                             *
+*  Description : Fournit le segment créé par un objet particulier.            *
+*                                                                             *
+*  Retour      : Créateur trouvé à déréférencer par la suite ou NULL si échec.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GObject *find_first_segment_creator(const buffer_line_column *column)
+{
+    GObject *result;                        /* Trouvaille à retourner      */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = NULL;
+
+    for (i = 0; i < column->count && result == NULL; i++)
+        result = g_buffer_segment_get_creator(column->segments[i]);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : column  = colonne de ligne de texte à consulter.             *
 *                creator = créateur à l'origine du segment recherché.         *
 *                                                                             *
@@ -1165,6 +1195,35 @@ GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBuffer
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : line   = ligne à venir consulter.                            *
+*                column = indice de la colonne visée par les recherches.      *
+*                                                                             *
+*  Description : Recherche le premier créateur enregistré dans des segments.  *
+*                                                                             *
+*  Retour      : Créateur trouvé à déréférencer par la suite ou NULL si échec.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, BufferLineColumn column)
+{
+    GObject *result;                        /* Trouvaille à retourner      */
+
+    assert(column < BLC_COUNT);
+
+    result = find_first_segment_creator(&line->columns[column]);
+
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : line    = ligne à venir consulter.                           *
 *                creator = créateur à l'origine du segment recherché.         *
 *                                                                             *
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index 19652ab..89313be 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -120,6 +120,9 @@ GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const gint [BL
 /* Fournit le segment voisin d'un autre segment identifié. */
 GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const gint [BLC_COUNT], const bool *, GdkScrollDirection, gint *);
 
+/* Recherche le premier créateur enregistré dans des segments. */
+GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn);
+
 /* Fournit le segment créé par un objet particulier. */
 GBufferSegment *g_buffer_line_find_segment_from_creator(const GBufferLine *, GObject *);
 
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index f96212c..be7fa37 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -158,10 +158,10 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *, GBufferLine **, size_t,
 
 
 /* Affiche un commentaire sur une ligne de tampon donnée. */
-static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *, GBufferLine *, const char *);
+static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *, GBufferLine *, const char *, GObject *);
 
 /* Affiche un commentaire sur une ligne de tampon dédiée. */
-static bool _g_code_buffer_write_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool);
+static bool _g_code_buffer_write_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool, GObject *);
 
 /* Retrouve la première ligne d'une zone de commentaire. */
 static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *, size_t);
@@ -453,6 +453,7 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar)
 *  Paramètres  : buffer  = tampon de lignes à consulter.                      *
 *                line    = ligne à l'intérieur d'un commentaire.              *
 *                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
 *  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
 *                                                                             *
@@ -462,7 +463,7 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar)
 *                                                                             *
 ******************************************************************************/
 
-static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment)
+static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
 {
     bool result;                            /* Bilan à retourner           */
     const mrange_t *range;                  /* Emplace de ligne à utiliser */
@@ -472,6 +473,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
     char *saveptr;                          /* Sauvegarde pour la sécurité */
     char *token;                            /* Fragment à insérer          */
     size_t len;                             /* Taille dudit fragment       */
+    GBufferSegment *segment;                /* Segment à marquer au fer    */
     GBufferLine *new;                       /* Nouvelle ligne créée        */
     size_t i;                               /* Boucle de parcours          */
 
@@ -493,12 +495,17 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
         len = strlen(token);
 
         if (!result)
-            g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
+        {
+            segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
+            g_buffer_segment_set_creator(segment, creator);
+        }
 
         else
         {
             new = g_code_buffer_prepare_new_line(buffer, range);
-            g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
+
+            segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
+            g_buffer_segment_set_creator(segment, creator);
 
             extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
 
@@ -534,6 +541,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
 *  Paramètres  : buffer  = tampon de lignes à consulter.                      *
 *                line    = ligne à l'intérieur d'un commentaire.              *
 *                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
 *  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
 *                                                                             *
@@ -543,7 +551,7 @@ static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLin
 *                                                                             *
 ******************************************************************************/
 
-bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment)
+bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
 {
     bool result;                            /* Bilan à retourner           */
 
@@ -553,7 +561,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
         result = true;
 
     if (result)
-        result = _g_code_buffer_write_inlined_comment(buffer, line, comment);
+        result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator);
 
     /* TODO : emit() */
 
@@ -568,6 +576,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
 *                line    = ligne à l'intérieur d'un commentaire.              *
 *                comment = nouveau commentaire à inscrire à la ligne donnée.  *
 *                before  = précise la position du commentaire.                *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
 *  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
 *                                                                             *
@@ -577,7 +586,7 @@ bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line
 *                                                                             *
 ******************************************************************************/
 
-static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before)
+static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
 {
     bool result;                            /* Bilan à retourner           */
     const mrange_t *range;                  /* Emplace de ligne à utiliser */
@@ -588,6 +597,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
     char *token;                            /* Fragment à insérer          */
     size_t len;                             /* Taille dudit fragment       */
     GBufferLine *new;                       /* Nouvelle ligne créée        */
+    GBufferSegment *segment;                /* Segment à marquer au fer    */
     size_t i;                               /* Boucle de parcours          */
 
     assert(!g_buffer_line_has_comment(line));
@@ -609,7 +619,9 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
 
         new = g_code_buffer_prepare_new_line(buffer, range);
         g_buffer_line_start_merge_at(new, BLC_DISPLAY);
-        g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
+
+        segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
+        g_buffer_segment_set_creator(segment, creator);
 
         extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
 
@@ -644,6 +656,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
 *                line    = ligne à l'intérieur d'un commentaire.              *
 *                comment = nouveau commentaire à inscrire à la ligne donnée.  *
 *                before  = précise la position du commentaire.                *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
 *  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
 *                                                                             *
@@ -653,7 +666,7 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
 *                                                                             *
 ******************************************************************************/
 
-bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before)
+bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
 {
     bool result;                            /* Bilan à retourner           */
 
@@ -663,7 +676,7 @@ bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, c
         result = true;
 
     if (result)
-        result = _g_code_buffer_write_comment_area(buffer, line, comment, before);
+        result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator);
 
     /* TODO : emit() */
 
@@ -873,6 +886,43 @@ static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, si
 *  Paramètres  : buffer = tampon de lignes à consulter.                       *
 *                line   = ligne à l'intérieur d'un commentaire.               *
 *                                                                             *
+*  Description : Retrouve le créateur d'un commentaire existant.              *
+*                                                                             *
+*  Retour      : Instance trouvée à déréférencer ensuite ou NULL si aucune.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line)
+{
+    GObject *result;                        /* Instance à retourner        */
+    BufferLineColumn merge_col;             /* Colonne de fusion           */
+
+    if (g_buffer_line_has_comment(line))
+    {
+        merge_col = g_buffer_line_get_merge_start(line);
+
+        if (merge_col == BLC_DISPLAY)
+            result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY);
+        else
+            result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS);
+
+    }
+
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                line   = ligne à l'intérieur d'un commentaire.               *
+*                                                                             *
 *  Description : Récupère le contenu d'un commentaire existant.               *
 *                                                                             *
 *  Retour      : Commentaire retrouver à libérer ou NULL en cas d'échec.      *
@@ -1536,7 +1586,7 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vm
         result = buffer->lines[index];
 
         if (flags != BLF_NONE)
-            while ((g_buffer_line_get_flags(result) & flags) == 0)
+            while ((g_buffer_line_get_flags(result) & flags) != flags)
             {
                 if ((index + 1) == buffer->used) break;
 
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index d04ed76..8bcbc4a 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -111,10 +111,13 @@ GDelayedWork *g_buffer_code_scan(GCodeBuffer *, const vmpa2t *, const vmpa2t *,
 
 
 /* Affiche un commentaire sur une ligne de tampon donnée. */
-bool g_code_buffer_update_inlined_comment(GCodeBuffer *, GBufferLine *, const char *);
+bool g_code_buffer_update_inlined_comment(GCodeBuffer *, GBufferLine *, const char *, GObject *);
 
 /* Affiche un commentaire sur une ligne de tampon dédiée. */
-bool g_code_buffer_update_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool);
+bool g_code_buffer_update_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool, GObject *);
+
+/* Retrouve le créateur d'un commentaire existant. */
+GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *, const GBufferLine *);
 
 /* Récupère le contenu d'un commentaire existant. */
 char *g_code_buffer_get_lines_comment(const GCodeBuffer *, const GBufferLine *);
-- 
cgit v0.11.2-87-g4458