From 7b99c255f7b5a6cd82196d8ae396b5cf991f9784 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 28 Sep 2016 23:43:18 +0200
Subject: Updated and improved the symbols panel.

---
 ChangeLog                |   5 +
 src/gui/panels/symbols.c | 236 +++++++++++++++++++++++++++++++++++++----------
 2 files changed, 190 insertions(+), 51 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 848a371..00d6f56 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+16-09-28  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/gui/panels/symbols.c:
+	Update and improve the symbols panel.
+
 16-09-27  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gui/menus/binary.c:
diff --git a/src/gui/panels/symbols.c b/src/gui/panels/symbols.c
index d1bca91..0cbb9eb 100644
--- a/src/gui/panels/symbols.c
+++ b/src/gui/panels/symbols.c
@@ -37,6 +37,7 @@
 
 
 #include "panel-int.h"
+#include "../../common/extstr.h"
 #include "../../format/format.h"
 #include "../../gtkext/easygtk.h"
 #include "../../gtkext/support.h"
@@ -79,6 +80,7 @@ typedef enum _SymbolsColumn
 
     SBC_PICTURE,                            /* Image de représentation     */
     SBC_NAME,                               /* Désignation humaine         */
+    SBC_ORIGINAL,                           /* Version brute d'origine     */
     SBC_ADDRESS,                            /* Adresse mémoire du symbole  */
     SBC_SECTION,                            /* Section d'appartenance      */
 
@@ -124,11 +126,11 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *);
 
 
 /* S'assure qu'un noeud donné existe bien. */
-#if 0
-static GtkTreeIter ensure_symbol_node_exist(GtkTreeStore *, GtkTreeIter *, const char *);
-#endif
+
+static GtkTreeIter ensure_symbol_node_exist(GSymbolsPanel *, GtkTreeIter *, const char *, const regmatch_t *, size_t);
+
 /* Détermine le point d'insertion parent d'une routine. */
-static bool find_parent_for_symbol(GtkTreeStore *, const GBinSymbol *, GtkTreeIter *);
+static bool find_parent_for_symbol(GSymbolsPanel *, const GBinSymbol *, GtkTreeIter *, const regmatch_t *, size_t *);
 
 /* Réagit à un changement d'affichage principal de contenu. */
 static void reload_symbols_for_new_tree_view(GSymbolsPanel *);
@@ -151,7 +153,10 @@ static void on_symbols_filter_changed(GtkSearchEntry *, GSymbolsPanel *);
 static void do_filtering_on_symbols(GSymbolsPanel *);
 
 /* Détermine si un nom de symbole doit être filtré ou non. */
-static bool is_symbol_filtered(GSymbolsPanel *, const GBinSymbol *);
+static bool is_symbol_filtered(GSymbolsPanel *, const GBinSymbol *, regmatch_t *);
+
+/* Met en évidence le texte recherché en cas de correspondance. */
+static char *build_highlighted_name(const char *, const regmatch_t *, size_t);
 
 
 
@@ -338,7 +343,7 @@ static void g_symbols_panel_init(GSymbolsPanel *panel)
     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwnd), GTK_SHADOW_IN);
 
     panel->store = gtk_tree_store_new(SBC_COUNT, G_TYPE_OBJECT, CAIRO_GOBJECT_TYPE_SURFACE, G_TYPE_STRING,
-                                      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+                                      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
 
     treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(panel->store));
     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
@@ -353,17 +358,18 @@ static void g_symbols_panel_init(GSymbolsPanel *panel)
 
     /* Cellules d'affichage */
 
+    column = gtk_tree_view_column_new();
+
     renderer = gtk_cell_renderer_pixbuf_new();
-    column = gtk_tree_view_column_new_with_attributes("", renderer,
-                                                      "surface", SBC_PICTURE,
-                                                      NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+    gtk_tree_view_column_pack_start(column, renderer, FALSE);
+    gtk_tree_view_column_add_attribute(column, renderer, "surface", SBC_PICTURE);
 
     renderer = gtk_cell_renderer_text_new();
-    column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
-                                                      "text", SBC_NAME,
-                                                      NULL);
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_add_attribute(column, renderer, "markup", SBC_NAME);
     gtk_tree_view_column_set_sort_column_id(column, SBC_NAME);
+
+    gtk_tree_view_column_set_title(column, _("Name"));
     gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
     renderer = gtk_cell_renderer_text_new();
@@ -550,12 +556,16 @@ static void on_symbols_selection_change(GtkTreeSelection *selection, GSymbolsPan
     {
         gtk_tree_model_get(model, &iter, SBC_SYMBOL, &symbol, -1);
 
-        range = g_binary_symbol_get_range(symbol);
+        if (symbol != NULL)
+        {
+            range = g_binary_symbol_get_range(symbol);
+
+            vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(panel));
+            gtk_view_panel_request_move(vpanel, get_mrange_addr(range));
 
-        vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(panel));
-        gtk_view_panel_request_move(vpanel, get_mrange_addr(range));
+            g_object_unref(G_OBJECT(symbol));
 
-        g_object_unref(G_OBJECT(symbol));
+        }
 
     }
 
@@ -632,7 +642,10 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
     GArchProcessor *proc;                   /* Architecture utilisée       */
     MemoryDataSize size;                    /* Taille des localisations    */
     size_t i;                               /* Boucle de parcours          */
+    regmatch_t match;                       /* Récupération des trouvailles*/
     cairo_surface_t *icon;                  /* Image associée au symbole   */
+    const char *original;                   /* Etiquette brute d'origine   */
+    char *name;                             /* Etiquette mise en relief    */
     const vmpa2t *addr;                     /* Localisation d'un symbole   */
     char virt[VMPA_MAX_LEN];                /* Version humainement lisible */
     GtkTreeIter iter;                       /* Point d'insertion           */
@@ -647,7 +660,7 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
 
     for (i = 0; i < sym_count; i++)
     {
-        if (is_symbol_filtered(panel, symbols[i]))
+        if (is_symbol_filtered(panel, symbols[i], &match))
             continue;
 
         switch (g_binary_symbol_get_target_type(symbols[i]))
@@ -664,6 +677,9 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
                 break;
         }
 
+        original = g_binary_symbol_get_label(symbols[i]);
+        name = build_highlighted_name(original, &match, 0);
+
         addr = get_mrange_addr(g_binary_symbol_get_range(symbols[i]));
         vmpa2_virt_to_string(addr, size, virt, NULL);
 
@@ -671,10 +687,13 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
         gtk_tree_store_set(panel->store, &iter,
                            SBC_SYMBOL, symbols[i],
                            SBC_PICTURE, icon,
-                           SBC_NAME, g_binary_symbol_get_label(symbols[i]),
+                           SBC_NAME, name,
+                           SBC_ORIGINAL, original,
                            SBC_ADDRESS, virt,
                            -1);
 
+        free(name);
+
     }
 
 }
@@ -688,9 +707,11 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : store  = gestion des différents éléments insérés.            *
+*  Paramètres  : panel  = panneau en cours de mise à jour.                    *
 *                parent = point d'insertion parent à retrouver. [OUT]         *
-*                name   = nom du noeud ciblé.                                 *
+*                raw    = nom du noeud ciblé.                                 *
+*                match  = portion de texte à mettre en évidence.              *
+*                start  = position du texte brute dans l'étiquette complète.  *
 *                                                                             *
 *  Description : S'assure qu'un noeud donné existe bien.                      *
 *                                                                             *
@@ -699,21 +720,24 @@ static void reload_symbols_for_new_list_view(GSymbolsPanel *panel)
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
-#if 0
-static GtkTreeIter ensure_symbol_node_exist(GtkTreeStore *store, GtkTreeIter *parent, const char *name)
+
+static GtkTreeIter ensure_symbol_node_exist(GSymbolsPanel *panel, GtkTreeIter *parent, const char *raw, const regmatch_t *match, size_t start)
 {
+    GtkTreeStore *store;                    /* Gestionnaire de données     */
     bool found;                             /* Bilan des recherches        */
     GtkTreeIter iter;                       /* Boucle de parcours          */
     gchar *string;                          /* Chaîne sélectionnée         */
-    cairo_surface_t *icon;                  /* Image associée au symbole   */
+    char *name;                             /* Etiquette mise en relief    */
+
+    store = panel->store;
 
     found = false;
 
     if (gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent))
         do
         {
-            gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, SBC_NAME, &string, -1);
-            found = (strcmp(string, name) == 0);
+            gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, SBC_ORIGINAL, &string, -1);
+            found = (strcmp(string, raw) == 0);
             g_free(string);
 
             if (found) break;
@@ -723,23 +747,31 @@ static GtkTreeIter ensure_symbol_node_exist(GtkTreeStore *store, GtkTreeIter *pa
 
     if (!found) 
     {
+        name = build_highlighted_name(raw, match, start);
+
         gtk_tree_store_append(store, &iter, parent);
         gtk_tree_store_set(store, &iter,
                            SBC_PICTURE, G_SYMBOLS_PANEL_GET_CLASS(panel)->package_img,
                            SBC_NAME, name,
+                           SBC_ORIGINAL, raw,
                            -1);
+
+        free(name);
+
     }
 
     return iter;
 
 }
-#endif
+
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : store  = gestion des différents éléments insérés.            *
+*  Paramètres  : panel  = panneau en cours de mise à jour.                    *
 *                symbol = routine ou objet à intégrer.                        *
-*                parent = point d'insertion parent à constituer.              *
+*                parent = point d'insertion parent à constituer. [OUT]        *
+*                match = portion de texte à mettre en évidence.               *
+*                last   = position du dernier élément du nom de symbole. [OUT]*
 *                                                                             *
 *  Description : Détermine le point d'insertion parent d'une routine.         *
 *                                                                             *
@@ -749,33 +781,41 @@ static GtkTreeIter ensure_symbol_node_exist(GtkTreeStore *store, GtkTreeIter *pa
 *                                                                             *
 ******************************************************************************/
 
-static bool find_parent_for_symbol(GtkTreeStore *store, const GBinSymbol *symbol, GtkTreeIter *parent)
+static bool find_parent_for_symbol(GSymbolsPanel *panel, const GBinSymbol *symbol, GtkTreeIter *parent, const regmatch_t *match, size_t *last)
 {
-#if 0
-    GDataType *namespace;                   /* Espace d'appartenance       */
-    char *string;                           /* Conversion en chaîne        */
-    char *iter;                             /* Boucle de parcours          */
+    const char *label;                      /* Etiquette immuable          */
+    char *string;                           /* Etiquette modifiable        */
+    const char *sep;                        /* Délimitateur à utiliser     */
+    char *start;                            /* Début de boucle de parcours */
     char *token;                            /* Partie de texte isolée      */ 
     char *saveptr;                          /* Ctx. interne de découpage   */
+    char *next;                             /* Prochaine partie à traiter  */
+
+    *last = 0;
 
-    namespace = g_binary_routine_get_namespace(routine);
-    if (namespace == NULL) return false;
+    label = g_binary_symbol_get_label(symbol);
+    if (label == NULL) return false;
 
-    string = g_data_type_to_string(namespace);
+    string = strdup(label);
 
-    for (iter = string; ; iter = NULL)
+    sep = "."/*"::"*/;  /* FIXME */
+
+    for (start = string, token = strtok_r(start, sep, &saveptr); ; start = NULL, token = next)
     {
-        token = strtok_r(iter, "::", &saveptr);
-        if (token == NULL) break;
+        next = strtok_r(NULL, sep, &saveptr);
+        if (next == NULL)
+        {
+            *last = (token - string);
+            break;
+        }
 
-        *parent = ensure_symbol_node_exist(store, (iter == string ? NULL : parent), token);
+        *parent = ensure_symbol_node_exist(panel, (start == string ? NULL : parent), token, match, token - string);
 
     }
 
-    return true;
-#endif
+    free(string);
 
-    return false;
+    return true;
 
 }
 
@@ -800,8 +840,12 @@ static void reload_symbols_for_new_tree_view(GSymbolsPanel *panel)
     GArchProcessor *proc;                   /* Architecture utilisée       */
     MemoryDataSize size;                    /* Taille des localisations    */
     size_t i;                               /* Boucle de parcours          */
+    regmatch_t match;                       /* Récupération des trouvailles*/
     GtkTreeIter parent;                     /* Point d'insertion parent    */
+    size_t last;                            /* Position du dernier élément */
     cairo_surface_t *icon;                  /* Image associée au symbole   */
+    const char *original;                   /* Etiquette brute d'origine   */
+    char *name;                             /* Etiquette mise en relief    */
     const vmpa2t *addr;                     /* Localisation d'un symbole   */
     char virt[VMPA_MAX_LEN];                /* Version humainement lisible */
     GtkTreeIter iter;                       /* Point d'insertion           */
@@ -816,10 +860,10 @@ static void reload_symbols_for_new_tree_view(GSymbolsPanel *panel)
 
     for (i = 0; i < sym_count; i++)
     {
-        if (is_symbol_filtered(panel, symbols[i]))
+        if (is_symbol_filtered(panel, symbols[i], &match))
             continue;
 
-        if (find_parent_for_symbol(panel->store, symbols[i], &parent))
+        if (find_parent_for_symbol(panel, symbols[i], &parent, &match, &last))
         {
             gtk_tree_store_set(panel->store, &parent,
                                SBC_PICTURE, G_SYMBOLS_PANEL_GET_CLASS(panel)->class_img,
@@ -846,16 +890,22 @@ static void reload_symbols_for_new_tree_view(GSymbolsPanel *panel)
                 break;
         }
 
+        original = g_binary_symbol_get_label(symbols[i]);
+        name = build_highlighted_name(original + last, &match, last);
+
         addr = get_mrange_addr(g_binary_symbol_get_range(symbols[i]));
         vmpa2_virt_to_string(addr, size, virt, NULL);
 
         gtk_tree_store_set(panel->store, &iter,
                            SBC_SYMBOL, symbols[i],
                            SBC_PICTURE, icon,
-                           SBC_NAME, g_binary_symbol_get_label(symbols[i]),
+                           SBC_NAME, name,
+                           SBC_ORIGINAL, original + last,
                            SBC_ADDRESS, virt,
                            -1);
 
+        free(name);
+
     }
 
 }
@@ -969,7 +1019,7 @@ static void on_symbols_filter_changed(GtkSearchEntry *entry, GSymbolsPanel *pane
     if (strlen(text) > 0)
     {
         panel->filter = (regex_t *)calloc(1, sizeof(regex_t));
-        ret = regcomp(panel->filter, text, REG_EXTENDED);
+        ret = regcomp(panel->filter, text, REG_EXTENDED | REG_ICASE);
 
         if (ret != 0)
         {
@@ -1020,6 +1070,7 @@ static void do_filtering_on_symbols(GSymbolsPanel *panel)
 *                                                                             *
 *  Paramètres  : panel  = panneau assurant l'affichage des symboles.          *
 *                symbol = symbole à traiter.                                  *
+*                match  = récupération des trouvailles. [OUT]                 *
 *                                                                             *
 *  Description : Détermine si un nom de symbole doit être filtré ou non.      *
 *                                                                             *
@@ -1029,10 +1080,9 @@ static void do_filtering_on_symbols(GSymbolsPanel *panel)
 *                                                                             *
 ******************************************************************************/
 
-static bool is_symbol_filtered(GSymbolsPanel *panel, const GBinSymbol *symbol)
+static bool is_symbol_filtered(GSymbolsPanel *panel, const GBinSymbol *symbol, regmatch_t *match)
 {
     SymbolType type;                        /* Type associé au symbole     */
-    regmatch_t match;                       /* Récupération des trouvailles*/
     int ret;                                /* Bilan du filtrage           */
 
     type = g_binary_symbol_get_target_type(symbol);
@@ -1040,13 +1090,97 @@ static bool is_symbol_filtered(GSymbolsPanel *panel, const GBinSymbol *symbol)
     if (type != STP_ROUTINE && type != STP_ENTRY_POINT && type != STP_OBJECT)
         return true;
 
+    memset(match, 0, sizeof(regmatch_t));
+
     if (panel->filter == NULL)
         return false;
 
-    ret = regexec(panel->filter, g_binary_symbol_get_label(symbol), 1, &match, 0);
+    ret = regexec(panel->filter, g_binary_symbol_get_label(symbol), 1, match, 0);
     if (ret == REG_NOMATCH)
         return true;
 
     return false;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : raw   = bribe de texte à traiter.                            *
+*                match = portion de texte à mettre en évidence.               *
+*                start = position du texte brute dans l'étiquette complète.   *
+*                                                                             *
+*  Description : Met en évidence le texte recherché en cas de correspondance. *
+*                                                                             *
+*  Retour      : Texte final destiné à être inséré, à libérer après usage.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *build_highlighted_name(const char *raw, const regmatch_t *match, size_t start)
+{
+    char *result;                           /* Construction à retourner    */
+    size_t len;                             /* Taille du texte d'entrée    */
+    regmatch_t selection;                   /* Sélection relative au texte */
+    char *valid;                            /* Retouche partielle          */
+
+    len = strlen(raw);
+
+    /* Si aucune sélection ou texte hors champ... */
+
+    if ((match->rm_eo - match->rm_so) == 0 || (start + len) <= match->rm_so || match->rm_eo < start)
+    {
+        result = strdup(raw);
+        result = strrpl(result, "<", "&lt;");
+    }
+
+    /* Sinon, il y a forcément correspondance quelque part ! */
+
+    else
+    {
+        /* Adaptations */
+
+        if (match->rm_so < start)
+            selection.rm_so = 0;
+        else
+            selection.rm_so = match->rm_so - start;
+
+        selection.rm_eo = match->rm_eo - start;
+
+        if (selection.rm_eo > len)
+            selection.rm_eo = len;
+
+        /* Impressions */
+
+        if (selection.rm_so > 0)
+        {
+            result = strndup(raw, selection.rm_so);
+            result = strrpl(result, "<", "&lt;");
+        }
+        else
+            result = NULL;
+
+        result = stradd(result, "<b>");
+
+        valid = strndup(&raw[selection.rm_so], selection.rm_eo - selection.rm_so);
+        valid = strrpl(valid, "<", "&lt;");
+
+        result = stradd(result, valid);
+
+        free(valid);
+
+        result = stradd(result, "</b>");
+
+        valid = strdup(&raw[selection.rm_eo]);
+        valid = strrpl(valid, "<", "&lt;");
+
+        result = stradd(result, valid);
+
+        free(valid);
+
+    }
+
+    return result;
+
+}
-- 
cgit v0.11.2-87-g4458