diff options
Diffstat (limited to 'src/glibext/gcodebuffer.c')
-rw-r--r-- | src/glibext/gcodebuffer.c | 1778 |
1 files changed, 0 insertions, 1778 deletions
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c deleted file mode 100644 index e9f1762..0000000 --- a/src/glibext/gcodebuffer.c +++ /dev/null @@ -1,1778 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * gcodebuffer.c - affichage d'un fragment de code d'assemblage - * - * Copyright (C) 2010-2014 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "gcodebuffer.h" - - -#include <assert.h> -#include <malloc.h> -#include <stdlib.h> -#include <string.h> - - -#include "chrysamarshal.h" -#include "delayed-int.h" -#include "../common/extstr.h" - - - -/* -------------------------- PARCOURS DU CODE D'UN TAMPON -------------------------- */ - - -#define G_TYPE_BUFFER_SCAN g_buffer_scan_get_type() -#define G_BUFFER_SCAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_buffer_scan_get_type(), GDelayedExport)) -#define G_IS_BUFFER_SCAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_buffer_scan_get_type())) -#define G_BUFFER_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_SCAN, GDelayedExportClass)) -#define G_IS_BUFFER_SCAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_SCAN)) -#define G_BUFFER_SCAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_SCAN, GDelayedExportClass)) - - -/* Ensembles binaires à désassembler (instance) */ -typedef struct _GBufferScan -{ - GDelayedWork parent; /* A laisser en premier */ - - GCodeBuffer *buffer; /* Tampon à manipuler */ - - vmpa2t start; /* Début du parcours */ - bool has_start; /* Validité des données #1 */ - vmpa2t end; /* Fin du parcours */ - bool has_end; /* Validité des données #2 */ - - char *message; /* Message de progression */ - - process_line_fc process; /* Fonction de traitement réel */ - void *user_data; /* Données à faire suivre */ - -} GBufferScan; - -/* Ensembles binaires à désassembler (classe) */ -typedef struct _GBufferScanClass -{ - GDelayedWorkClass parent; /* A laisser en premier */ - -} GBufferScanClass; - - -/* Indique le type défini pour les tâches d'exportation différée. */ -static GType g_buffer_scan_get_type(void); - -/* Initialise la classe des tâches d'exportation différée. */ -static void g_buffer_scan_class_init(GBufferScanClass *); - -/* Initialise une tâche d'exportation différée. */ -static void g_buffer_scan_init(GBufferScan *); - -/* Supprime toutes les références externes. */ -static void g_buffer_scan_dispose(GBufferScan *); - -/* Procède à la libération totale de la mémoire. */ -static void g_buffer_scan_finalize(GBufferScan *); - -/* Crée une tâche d'exportation différée. */ -static GBufferScan *g_buffer_scan_new(GCodeBuffer *, const vmpa2t *, const vmpa2t *, const char *, process_line_fc, void *); - -/* Assure l'exportation en différé. */ -static void g_buffer_scan_process(GBufferScan *, GtkStatusStack *); - - - -/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ - - -/* Suivi distant des évolutions */ -typedef struct _view_callback -{ - buffer_size_changed_cb size_changed; /* Evolution de taille */ - GObject *data; /* Données à associer */ - -} view_callback; - - -/* Tampon pour code désassemblé (instance) */ -struct _GCodeBuffer -{ - GObject parent; /* A laisser en premier */ - - BufferLineColumn main_column; /* Colonne principale */ - - GBufferLine **lines; /* Liste des lignes intégrées */ - size_t count; /* Quantité en cache */ - size_t used; /* Quantité utilisée */ - - GWidthTracker *tracker; /* Suivi des largeurs */ - - size_t indent; /* Indentation des lignes */ - - view_callback *vcallbacks; /* Vues à mettre à jour */ - size_t vcount; /* Quantité de ces vues */ - -}; - -/* Tampon pour code désassemblé (classe) */ -struct _GCodeBufferClass -{ - GObjectClass parent; /* A laisser en premier */ - - /* Signaux */ - - void (* line_changed) (GCodeBuffer *, GBufferLine *, line_segment *); - -}; - - -/* Taille des allocations de masse */ -#define LINE_ALLOC_BULK 20 - - -/* Procède à l'initialisation d'une classe de tampon de code. */ -static void g_code_buffer_class_init(GCodeBufferClass *); - -/* Procède à l'initialisation d'un tampon pour code désassemblé. */ -static void g_code_buffer_init(GCodeBuffer *); - -/* Réagit à un changement de contenu d'une ligne donnée. */ -static void on_line_content_change(GBufferLine *, line_segment *, GCodeBuffer *); - -/* Réagit à un changement de propriété rattachée à une ligne. */ -static void on_line_flag_flip(GBufferLine *, BufferLineFlags, BufferLineFlags, GCodeBuffer *); - -/* Ajoute de nouvelles lignes à une position donnée. */ -static void g_code_buffer_insert_lines_at(GCodeBuffer *, GBufferLine **, size_t, size_t); - - - -/* ------------------------- CONFORTS POUR LES COMMENTAIRES ------------------------- */ - - -/* Affiche un commentaire sur une ligne de tampon donnée. */ -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, 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); - -/* Retrouve la dernière ligne d'une zone de commentaire. */ -static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *, size_t); - -/* Supprime un commentaire existant. */ -static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *); - - - -/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */ - - -/* Fait suivre une variation de la quantité de lignes du tampon. */ -static void g_code_buffer_notify_size_changed(const GCodeBuffer *, bool, size_t, size_t); - - - -/* ---------------------------------------------------------------------------------- */ -/* PARCOURS DU CODE D'UN TAMPON */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini pour les tâches d'exportation différée. */ -G_DEFINE_TYPE(GBufferScan, g_buffer_scan, G_TYPE_DELAYED_WORK); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des tâches d'exportation différée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_scan_class_init(GBufferScanClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GDelayedWorkClass *work; /* Version en classe parente */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_scan_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_scan_finalize; - - work = G_DELAYED_WORK_CLASS(klass); - - work->run = (run_task_fc)g_buffer_scan_process; - -} - - -/****************************************************************************** -* * -* Paramètres : scan = instance à initialiser. * -* * -* Description : Initialise une tâche d'exportation différée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_scan_init(GBufferScan *scan) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : scan = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_scan_dispose(GBufferScan *scan) -{ - g_object_unref(G_OBJECT(scan->buffer)); - - G_OBJECT_CLASS(g_buffer_scan_parent_class)->dispose(G_OBJECT(scan)); - -} - - -/****************************************************************************** -* * -* Paramètres : scan = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_scan_finalize(GBufferScan *scan) -{ - free(scan->message); - - G_OBJECT_CLASS(g_buffer_scan_parent_class)->finalize(G_OBJECT(scan)); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon à manipuler. * -* start = première adresse visée ou NULL. * -* end = dernière adresse visée ou NULL. * -* message = message à afficher lors de la progression. * -* process = fonction assurant le traitement effectif. * -* data = données utilisateur à faire suivre. * -* * -* Description : Crée une tâche d'exportation différée. * -* * -* Retour : Tâche créée. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GBufferScan *g_buffer_scan_new(GCodeBuffer *buffer, const vmpa2t *start, const vmpa2t *end, const char *message, process_line_fc process, void *data) -{ - GBufferScan *result; /* Tâche à retourner */ - - result = g_object_new(G_TYPE_BUFFER_SCAN, NULL); - - result->buffer = buffer; - g_object_ref(G_OBJECT(buffer)); - - result->has_start = (start != NULL); - - if (result->has_start) - copy_vmpa(&result->start, start); - - result->has_end = (end != NULL); - - if (result->has_end) - copy_vmpa(&result->end, end); - - result->message = strdup(message); - - result->process = process; - result->user_data = data; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : scan = parcours à mener. * -* status = barre de statut à tenir informée. * -* * -* Description : Assure l'exportation en différé. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_buffer_scan_process(GBufferScan *scan, GtkStatusStack *status) -{ - size_t first; /* Première ligne visée */ - size_t last; /* Dernière ligne visée + 1 */ - GBufferLine **lines; /* Liste des lignes à traiter */ - //bstatus_id_t id; /* Identifiant de statut */ - size_t i; /* Boucle de parcours */ - - /* TODO : lock scan->buffer->lines */ - - if (scan->has_start) - first = g_code_buffer_get_index_from_address(scan->buffer, &scan->start, true); - else - first = 0; - - if (scan->has_end) - last = g_code_buffer_get_index_from_address(scan->buffer, &scan->end, false); - else - last = scan->buffer->used - 1; - - lines = scan->buffer->lines; - - //id = gtk_extended_status_bar_push(statusbar, scan->message, true); - - if (scan->buffer->used > 0) - for (i = first; i <= last; i++) - { - if (!scan->process(scan->buffer, lines[i], scan->user_data)) - break; - - /* - gtk_extended_status_bar_update_activity(statusbar, id, - (i - first) * 1.0 / (last - first)); - */ - - } - - /* TODO : unlock scan->buffer->lines */ - - //gtk_extended_status_bar_remove(statusbar, id); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TAMPON POUR CODE DESASSEMBLE */ -/* ---------------------------------------------------------------------------------- */ - - -/* Détermine le type du composant de tampon pour code désassemblé. */ -G_DEFINE_TYPE(GCodeBuffer, g_code_buffer, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : class = classe de composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une classe de tampon de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_code_buffer_class_init(GCodeBufferClass *class) -{ - g_signal_new("line-changed", - G_TYPE_CODE_BUFFER, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GCodeBufferClass, line_changed), - NULL, NULL, - g_cclosure_user_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'un tampon pour code désassemblé.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_code_buffer_init(GCodeBuffer *buffer) -{ - buffer->tracker = g_width_tracker_new(buffer); - -} - - -/****************************************************************************** -* * -* Paramètres : main = colonne à référencer comme étant la principale. * -* * -* Description : Crée un nouveau composant de tampon pour code désassemblé. * -* * -* Retour : Composant GTK créé. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GCodeBuffer *g_code_buffer_new(BufferLineColumn main) -{ - GCodeBuffer *result; /* Composant à retourner */ - - result = g_object_new(G_TYPE_CODE_BUFFER, NULL); - - result->main_column = main; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à consulter. * -* * -* Description : Compte le nombre de lignes rassemblées dans un tampon. * -* * -* Retour : Nombre de lignes constituant le tampon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_code_buffer_count_lines(const GCodeBuffer *buffer) -{ - return buffer->used; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à consulter. * -* * -* Description : Fournit un lien vers la structure de suivi de largeurs. * -* * -* Retour : Gestionnaire de largeurs de lignes. * -* * -* Remarques : - * -* * -******************************************************************************/ - -const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *buffer) -{ - return buffer->tracker; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à consulter. * -* range = emplacement où va se situer la ligne. * -* * -* Description : Initie une nouvelle ligne devant être insérée dans le tampon.* -* * -* Retour : Nouvelle ligne vierge à écrire. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferLine *g_code_buffer_prepare_new_line(GCodeBuffer *buffer, const mrange_t *range) -{ - GBufferLine *result; /* Instance à retourner */ - size_t i; /* Boucle de parcours */ - - result = g_buffer_line_new(range, buffer->main_column); - - for (i = 0; i < buffer->indent; i++) - g_buffer_line_append_text(result, BLC_ASSEMBLY_HEAD, " ", 4, RTT_RAW, NULL); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne dont la définition vient d'évoluer. * -* segment = éventuel segment qui vient d'évoluer ou NULL. * -* buffer = tampon de lignes cohérentes à manipuler. * -* * -* Description : Réagit à un changement de contenu d'une ligne donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void on_line_content_change(GBufferLine *line, line_segment *segment, GCodeBuffer *buffer) -{ - g_signal_emit_by_name(buffer, "line-changed", line, segment); - -} - - -/****************************************************************************** -* * -* Paramètres : line = ligne dont la définition vient d'évoluer. * -* old = ancien groupe de propriétés associées. * -* old = nouveau groupe de propriétés associées. * -* buffer = tampon de lignes cohérentes à manipuler. * -* * -* Description : Réagit à un changement de propriété rattachée à une ligne. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void on_line_flag_flip(GBufferLine *line, BufferLineFlags old, BufferLineFlags new, GCodeBuffer *buffer) -{ - g_signal_emit_by_name(buffer, "line-changed", line, NULL); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à mettre à jour. * -* lines = liste de lignes à insérer. * -* count = taille de cette liste. * -* index = point d'insertion de la première ligne. * -* * -* Description : Ajoute de nouvelles lignes à une position donnée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lines, size_t count, size_t index) -{ - size_t i; /* Boucle de parcours */ - - /* Elaboration d'un espace suffisant */ - - if ((buffer->used + count) > buffer->count) - { - if (count > LINE_ALLOC_BULK) - buffer->count += count; - else - buffer->count += LINE_ALLOC_BULK; - - buffer->lines = (GBufferLine **)realloc(buffer->lines, - buffer->count * sizeof(GBufferLine *)); - - } - - /* Insertion des lignes */ - - if (index < buffer->used) - { - memmove(&buffer->lines[index + count], &buffer->lines[index], - (buffer->used - index) * sizeof(GBufferLine *)); - } - - buffer->used += count; - - for (i = 0; i < count; i++) - { - assert((index + i) < buffer->used); - - buffer->lines[index + i] = lines[i]; - - g_signal_connect(lines[i], "content-changed", G_CALLBACK(on_line_content_change), buffer); - g_signal_connect(lines[i], "flip-flag", G_CALLBACK(on_line_flag_flip), buffer); - - } - - /* Recueil initial des largeurs */ - - g_width_tracker_update_added(buffer->tracker, index, count); - - g_code_buffer_notify_size_changed(buffer, true, index, count); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à mettre à jour. * -* line = lign à insérer à la fin du tampon. * -* * -* Description : Ajoute une nouvelle ligne en fin de tampon. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_append_new_line(GCodeBuffer *buffer, GBufferLine *line) -{ - g_code_buffer_insert_lines_at(buffer, (GBufferLine *[]) { line }, 1, buffer->used); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à mettre à jour. * -* lines = liste de lignes à insérer. * -* count = taille de cette liste. * -* point = point d'insertion du bloc de ligne. * -* before = emplacement de l'insertion par rapport au point. * -* * -* Description : Ajoute de nouvelles lignes par rapport à une ligne donnée. * -* * -* Retour : Bilan : insertion réussie ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_insert_lines(GCodeBuffer *buffer, GBufferLine **lines, size_t count, const GBufferLine *point, bool before) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice d'insertion final */ - - result = false; - - index = g_code_buffer_find_index_by_line(buffer, point); - - if (index == buffer->used) - goto gcbil_exit; - - if (!before) - index++; - - g_code_buffer_insert_lines_at(buffer, lines, count, index); - - - - - result = true; - - gcbil_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GLib à mettre à jour. * -* start = première ligne devant être supprimée. * -* end = dernière ligne devant être supprimée. * -* * -* Description : Supprime une ou plusieurs lignes du tampon indiqué. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_delete_lines(GCodeBuffer *buffer, size_t start, size_t end) -{ - size_t i; /* Boucle de parcours */ - GBufferLine *line; /* Ligne en cours de traitement*/ - - assert(start < buffer->used); - assert(end < buffer->used); - - for (i = start; i <= end; i++) - { - line = buffer->lines[i]; - - g_signal_handlers_disconnect_by_func(line, G_CALLBACK(on_line_content_change), buffer); - g_signal_handlers_disconnect_by_func(line, G_CALLBACK(on_line_flag_flip), buffer); - - g_object_unref(G_OBJECT(line)); - - } - - if ((end + 1) < buffer->used) - memmove(&buffer->lines[start], &buffer->lines[end + 1], - (buffer->used - end - 1) * sizeof(GBufferLine *)); - - buffer->used -= (end - start + 1); - - g_width_tracker_update_deleted(buffer->tracker, start, end); - - g_code_buffer_notify_size_changed(buffer, false, start, end - start + 1); - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à mettre à jour. * -* addr = adresse où retrouver la ligne recherchée. * -* flags = propriétés à vérifier en tout ou partie. * -* idx = indice de la ligne trouvée ou NULL. [OUT] * -* * -* Description : Retrouve une ligne au sein d'un tampon avec une adresse. * -* * -* Retour : Line retrouvée ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vmpa2t *addr, BufferLineFlags flags, size_t *idx) -{ - GBufferLine *result; /* Instance à retourner */ - size_t index; /* Indice de la ligne visée */ - - index = g_code_buffer_get_index_from_address(buffer, addr, true); - - if (index == buffer->used) - result = NULL; - - else - { - if (idx != NULL) - *idx = index; - - result = buffer->lines[index]; - - if (flags != BLF_NONE) - while ((g_buffer_line_get_flags(result) & flags) != flags) - { - if ((index + 1) == buffer->used) break; - - /* FIXME : vérifier que l'adresse est toujours celle recherchée ! */ - - if (idx != NULL) - (*idx)++; - - result = buffer->lines[++index]; - - } - - g_object_ref(G_OBJECT(result)); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de la ligne recherchée. * -* * -* Description : Retrouve une ligne au sein d'un tampon avec un indice. * -* * -* Retour : Line retrouvée ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t index) -{ - GBufferLine *result; /* Ligne trouvée à retourner */ - - /* TODO : ref */ - - if (index < buffer->used) - result = buffer->lines[index]; - else - result = NULL; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à mettre à jour. * -* addr = adresse où va se situer la ligne. * -* first = indique si on l'arrête à la première ou la dernière.* -* * -* Description : Convertit une adresse en indice de ligne. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first) -{ - size_t result; /* Indice à retourner */ - GBufferLine **found; /* Renvoi vers une trouvaille */ - const mrange_t *range; /* Couverture d'une ligne */ - - /** - * Si aucune adresse (ie. aucune limite ?) n'est précisée, on se base sur - * la direction pour trouver le bon indice. - */ - - if (addr == NULL) - result = (first ? 0 : buffer->used - 1); - - /** - * Sinon on parcourt méthodiquement toutes les lignes ! - */ - - else - { - /* Recherche dichotomique grossière */ - - int cmp_addr_and_line(const vmpa2t *addr, const GBufferLine **line) - { - int status; /* Bilan d'une comparaison */ - const mrange_t *lrange; /* Couverture d'une ligne */ - - lrange = g_buffer_line_get_range(*line); - - status = cmp_mrange_with_vmpa(lrange, addr); - - return status; - - } - - found = bsearch(addr, buffer->lines, buffer->used, sizeof(GBufferLine *), - (__compar_fn_t)cmp_addr_and_line); - - /* Dernier raffinage pour approcher la cible réelle */ - - if (found == NULL) - result = buffer->used; - - else - { - result = found - buffer->lines; - - if (first) - for (; result > 0; result--) - { - range = g_buffer_line_get_range(buffer->lines[result - 1]); - if (!mrange_contains_addr(range, addr)) break; - } - - else - for (; (result + 1) < buffer->used; result++) - { - range = g_buffer_line_get_range(buffer->lines[result + 1]); - if (!mrange_contains_addr(range, addr)) break; - } - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* line = ligne dont l'indice est à retrouver. * -* * -* Description : Retrouve l'indice associé à une ligne au sein d'un tampon. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -size_t g_code_buffer_find_index_by_line(const GCodeBuffer *buffer, const GBufferLine *line) -{ - size_t result; /* Indice trouvé à retourner */ - const mrange_t *range; /* Emplacement de la ligne */ - const mrange_t *next; /* Emplacement suivant */ - - range = g_buffer_line_get_range(line); - - result = g_code_buffer_get_index_from_address(buffer, get_mrange_addr(range), true); - - /** - * Comme plusieurs lignes consécutives peuvent avoir la même adresse, - * on parcourt les lignes suivantes pour retrouver la ligne recherchée. - */ - - if (result < buffer->used) - { - while (buffer->lines[result] != line) - { - if (++result == buffer->used) - break; - - next = g_buffer_line_get_range(buffer->lines[result]); - - if (cmp_vmpa(get_mrange_addr(range), get_mrange_addr(next)) != 0) - { - result = buffer->used; - break; - } - - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à mettre à jour. * -* * -* Description : Augmente l'indentation des prochaines lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_inc_indentation(GCodeBuffer *buffer) -{ - buffer->indent++; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à mettre à jour. * -* * -* Description : Diminue l'indentation des prochaines lignes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_dec_indentation(GCodeBuffer *buffer) -{ - /* BUG_ON(buffer->indent == 0) */ - - buffer->indent--; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de données à utiliser. * -* start = première adresse visée ou 0. * -* end = dernière adresse visée ou VMPA_MAX. * -* message = message à afficher lors de la progression. * -* process = fonction assurant le traitement effectif. * -* data = données utilisateur à faire suivre. * -* * -* Description : Lance un parcours des différentes lignes du tampon de code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -GDelayedWork *g_buffer_code_scan(GCodeBuffer *buffer, const vmpa2t *start, const vmpa2t *end, const char *message, process_line_fc process, void *data) -{ - GBufferScan *result; /* Procédure à créer / renvoyer*/ - GWorkQueue *queue; /* Gestionnaire de différés */ - - result = g_buffer_scan_new(buffer, start, end, message, process, data); - g_object_ref(G_OBJECT(result)); - - queue = get_work_queue(); - g_work_queue_schedule_work(queue, G_DELAYED_WORK(result), DEFAULT_WORK_GROUP); - - return G_DELAYED_WORK(result); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* CONFORTS POUR LES COMMENTAIRES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* 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. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -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 */ - char *wcopy; /* Copie de travail */ - GBufferLine **extra; /* Lignes supplémentaires */ - size_t extra_count; /* Quantité de ces lignes */ - char *saveptr; /* Sauvegarde pour la sécurité */ - char *token; /* Fragment à insérer */ - size_t len; /* Taille dudit fragment */ - GBufferLine *new; /* Nouvelle ligne créée */ - size_t i; /* Boucle de parcours */ - - assert(!g_buffer_line_has_comment(line)); - - result = false; - - range = g_buffer_line_get_range(line); - - wcopy = strdup(comment); - - extra = NULL; - extra_count = 0; - - for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); - token != NULL; - token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) - { - len = strlen(token); - - if (!result) - g_buffer_line_append_text(line, BLC_COMMENTS, token, len, RTT_COMMENT, creator); - - else - { - new = g_code_buffer_prepare_new_line(buffer, range); - - g_buffer_line_append_text(new, BLC_COMMENTS, token, len, RTT_COMMENT, creator); - - extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - - extra[extra_count - 1] = new; - - } - - result = true; - - } - - free(wcopy); - - if (extra_count > 0) - { - result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false); - - if (!result) - for (i = 0; i < extra_count; i++) - g_object_unref(G_OBJECT(extra[i])); - - free(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* 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. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) -{ - bool result; /* Bilan à retourner */ - - if (g_buffer_line_has_comment(line)) - result = _g_code_buffer_delete_lines_comment(buffer, line); - else - result = true; - - if (result) - result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator); - - /* TODO : emit() */ - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* 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. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -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 */ - char *wcopy; /* Copie de travail */ - GBufferLine **extra; /* Lignes supplémentaires */ - size_t extra_count; /* Quantité de ces lignes */ - char *saveptr; /* Sauvegarde pour la sécurité */ - char *token; /* Fragment à insérer */ - size_t len; /* Taille dudit fragment */ - GBufferLine *new; /* Nouvelle ligne créée */ - size_t i; /* Boucle de parcours */ - - assert(!g_buffer_line_has_comment(line)); - - result = false; - - range = g_buffer_line_get_range(line); - - wcopy = strdup(comment); - - extra = NULL; - extra_count = 0; - - for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); - token != NULL; - token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) - { - len = strlen(token); - - new = g_code_buffer_prepare_new_line(buffer, range); - g_buffer_line_start_merge_at(new, BLC_DISPLAY); - - g_buffer_line_append_text(new, BLC_DISPLAY, token, len, RTT_COMMENT, creator); - - extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - - extra[extra_count - 1] = new; - - result = true; - - } - - free(wcopy); - - if (extra_count > 0) - { - result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, before); - - if (!result) - for (i = 0; i < extra_count; i++) - g_object_unref(G_OBJECT(extra[i])); - - free(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* 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. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) -{ - bool result; /* Bilan à retourner */ - - if (g_buffer_line_has_comment(line)) - result = _g_code_buffer_delete_lines_comment(buffer, line); - else - result = true; - - if (result) - result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator); - - /* TODO : emit() */ - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve la première ligne d'une zone de commentaire. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - GBufferLine *prev; /* Ligne précédente */ - - assert(index < buffer->used); - - bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv) - { - bool first; /* Statut à renvoyer */ - BufferLineColumn merge_col; /* Colonne de fusion #1 */ - BufferLineColumn prev_merge_col; /* Colonne de fusion #2 */ - - merge_col = g_buffer_line_get_merge_start(ln); - - /** - * La ligne consultée contient toujours un commentaire. - * - * Deux cas de figures sont possibles ici : - * - * - soit du texte est présent dans la colonne "commentaires". - * Si du texte est présent avant, alors il s'agit forcément de - * la première (et unique ?) ligne de commentaire. - * - * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. - * Si la ligne qui précède fait de même, il s'agit alors d'une étiquette - * ou de l'amont du commentaire. - * - */ - - if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) - { - first = g_buffer_line_has_text(ln, BLC_DISPLAY, BLC_COMMENTS); - - if (!first) - { - /* La ligne d'avant doit avoir un commentaire ! */ - first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT); - } - - } - - else - { - /** - * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, - * la seule fusion possible ici est la suivante. - */ - assert(merge_col == BLC_DISPLAY); - - /** - * La première ligne d'un tampon est toujours un prologue. - */ - assert(pv != NULL); - - prev_merge_col = g_buffer_line_get_merge_start(pv); - - first = (prev_merge_col != BLC_DISPLAY); - - if (!first) - first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL); - - } - - return first; - - } - - for (result = index; result > 0; result--) - { - prev = (result > 0 ? buffer->lines[result - 1] : NULL); - - if (is_first_line_of_comment(buffer->lines[result], prev)) - break; - - } - - if (result == 0) - { - if (!is_first_line_of_comment(buffer->lines[0], NULL)) - result = buffer->used; - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve la dernière ligne d'une zone de commentaire. * -* * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - GBufferLine *next; /* Ligne suivante */ - - assert(index < buffer->used); - - bool is_last_line_of_comment(const GBufferLine *ln, const GBufferLine *nx) - { - bool last; /* Statut à renvoyer */ - BufferLineColumn merge_col; /* Colonne de fusion #1 */ - BufferLineColumn next_merge_col; /* Colonne de fusion #2 */ - - merge_col = g_buffer_line_get_merge_start(ln); - - /** - * La ligne consultée contient toujours un commentaire. - * - * Deux cas de figures sont possibles ici : - * - * - soit du texte est présent dans la colonne "commentaires". - * Si la ligne suivante est similaire et si du texte est présent avant, - * alors il s'agit forcément de d'un nouveau commentaire. S'il n'y a - * aucun texte, il s'agit de la suite du commentaire. - * - * - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY. - * Si la ligne qui suit fait de même, il s'agit alors d'une étiquette - * ou de l'aval du commentaire. - * - */ - - if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) - { - last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT); - - if (!last) - last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS); - - } - - else - { - /** - * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable, - * la seule fusion possible ici est la suivante. - */ - assert(merge_col == BLC_DISPLAY); - - if (nx == NULL) - last = true; - - else - { - next_merge_col = g_buffer_line_get_merge_start(nx); - - last = (next_merge_col != BLC_DISPLAY); - - if (!last) - last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL); - - } - - } - - return last; - - } - - for (result = index; result < buffer->used; result++) - { - next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL); - - if (is_last_line_of_comment(buffer->lines[result], next)) - break; - - } - - return result; - -} - - -/****************************************************************************** -* * -* 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. * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line) -{ - char *result; /* Contenu à retourner */ - size_t index; /* Indice de la ligne fournie */ - size_t start; /* Ligne de départ */ - size_t end; /* Ligne d'arrivée */ - BufferLineColumn merge_col; /* Colonne de fusion */ - size_t i; /* Boucle de parcours */ - char *extra; /* Commentaire supplémentaire */ - - /* Pas de prologue ici ! */ - assert(g_buffer_line_has_comment(line)); - - result = NULL; - - index = g_code_buffer_find_index_by_line(buffer, line); - - if (index == buffer->used) - goto gcbglc_exit; - - start = g_code_buffer_find_first_line_comment(buffer, index); - - if (start == buffer->used) - goto gcbglc_exit; - - end = g_code_buffer_find_last_line_comment(buffer, index); - - if (end == buffer->used) - goto gcbglc_exit; - - merge_col = g_buffer_line_get_merge_start(line); - - for (i = start; i <= end; i++) - { - if (merge_col == BLC_DISPLAY) - extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false); - - else - extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false); - - assert(extra != NULL); - - if (result == NULL) - result = extra; - - else - { - result = stradd(result, extra); - free(extra); - } - - } - - gcbglc_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Supprime un commentaire existant. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) -{ - bool result; /* Bilan à retourner */ - size_t index; /* Indice de la ligne fournie */ - size_t start; /* Ligne de départ */ - size_t end; /* Ligne d'arrivée */ - BufferLineColumn merge_col; /* Colonne de fusion */ - - /* Pas de prologue ici ! */ - assert(g_buffer_line_has_comment(line)); - - result = false; - - index = g_code_buffer_find_index_by_line(buffer, line); - - if (index == buffer->used) - goto gcbdlc_exit; - - start = g_code_buffer_find_first_line_comment(buffer, index); - - if (start == buffer->used) - goto gcbdlc_exit; - - end = g_code_buffer_find_last_line_comment(buffer, index); - - if (end == buffer->used) - goto gcbdlc_exit; - - result = true; - - merge_col = g_buffer_line_get_merge_start(line); - - if (merge_col == BLC_DISPLAY) - g_code_buffer_delete_lines(buffer, start, end); - - else - { - g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT); - - if (end > start) - g_code_buffer_delete_lines(buffer, start + 1, end); - - } - - gcbdlc_exit: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* line = ligne à l'intérieur d'un commentaire. * -* * -* Description : Supprime un commentaire existant. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line) -{ - bool result; /* Bilan à retourner */ - - result = _g_code_buffer_delete_lines_comment(buffer, line); - - /* TODO : emit() */ - - return result; - -} - - -/* ---------------------------------------------------------------------------------- */ -/* SIGNAUX IMMEDIATS POUR UNE VUE */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* cb = fonction à appeler au moment opportun. * -* data = object GLib à associer à l'appel. * -* * -* Description : Enregistre l'adresse d'une fonction de mise à jour de vue. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_register_view_callback(GCodeBuffer *buffer, buffer_size_changed_cb cb, GObject *data) -{ - view_callback *new; /* Informations sur l'appel */ - - buffer->vcount++; - - buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks, buffer->vcount * sizeof(view_callback)); - - new = &buffer->vcallbacks[buffer->vcount - 1]; - - new->size_changed = cb; - new->data = data; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à modifier. * -* data = object GLib à associer à l'appel. * -* * -* Description : Supprime un élément des vues à contacter pour mises à jour. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_code_buffer_unregister_view_callback(GCodeBuffer *buffer, GObject *data) -{ - size_t i; /* Boucle de parcours */ - - for (i = 0; i < buffer->vcount; i++) - if (buffer->vcallbacks[i].data == data) - { - if ((i + 1) < buffer->vcount) - memmove(&buffer->vcallbacks[i], &buffer->vcallbacks[i + 1], - (buffer->vcount - i - 1) * sizeof(view_callback)); - - buffer->vcount--; - - buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks, - buffer->vcount * sizeof(view_callback)); - - } - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à diffuser. * -* added = indication sur la variation de la taille du tampon. * -* index = indice de la première ligne à traiter. * -* count = nombre de lignes à traiter. * -* * -* Description : Fait suivre une variation de la quantité de lignes du tampon.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_code_buffer_notify_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count) -{ - size_t i; /* Boucle de parcours */ - view_callback *cb; /* Informations sur l'appel */ - - for (i = 0; i < buffer->vcount; i++) - { - cb = &buffer->vcallbacks[i]; - - cb->size_changed(buffer, added, index, count, cb->data); - - } - -} |