From dd33acbff36c0a3ae4618ac5021e74448cad5ce5 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 21 Jan 2016 21:51:27 +0100 Subject: Defined some raw primitives to write or delete comments. --- ChangeLog | 15 + src/analysis/disass/disassembler.c | 20 +- src/analysis/disass/output.c | 6 +- src/arch/instruction.c | 2 +- src/arch/raw.c | 2 +- src/glibext/gbinportion.c | 24 +- src/glibext/gbufferline.c | 106 ++++- src/glibext/gbufferline.h | 29 +- src/glibext/gcodebuffer.c | 806 +++++++++++++++++++++++++++++++++++-- src/glibext/gcodebuffer.h | 43 +- 10 files changed, 1003 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2901b77..204c090 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 16-01-21 Cyrille Bagard + * src/analysis/disass/disassembler.c: + * src/analysis/disass/output.c: + * src/arch/instruction.c: + * src/arch/raw.c: + * src/glibext/gbinportion.c: + Update calls registering new lines. + + * src/glibext/gbufferline.c: + * src/glibext/gbufferline.h: + * src/glibext/gcodebuffer.c: + * src/glibext/gcodebuffer.h: + Define some raw primitives to write or delete comments. + +16-01-21 Cyrille Bagard + * src/glibext/gcodebuffer.c: * src/glibext/gcodebuffer.h: Remove useless functions dealing with buffers and optimize some old code. diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c index 272529c..0fcc7f3 100644 --- a/src/analysis/disass/disassembler.c +++ b/src/analysis/disass/disassembler.c @@ -636,6 +636,9 @@ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, con { g_buffer_line_start_merge_at(line, BLC_PHYSICAL); g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER); + + g_code_buffer_append_new_line(buffer, line); + } managed = (line != NULL); @@ -649,13 +652,19 @@ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, con if (!managed) g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER); + g_code_buffer_append_new_line(buffer, line); + line = g_lang_output_continue_comments(output, buffer, SL(_("Chrysalide is free software - © 2008-2015 Cyrille Bagard"))); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); + line = g_lang_output_continue_comments(output, buffer, NULL, 0); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); + /* Fichier */ len = strlen(_("File: ")) + strlen(filename) + 1; @@ -666,6 +675,8 @@ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, con line = g_lang_output_continue_comments(output, buffer, content, len - 1); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); + free(content); /* Checksum SHA256 */ @@ -678,17 +689,24 @@ static void build_disass_prologue(GCodeBuffer *buffer, const char *filename, con line = g_lang_output_continue_comments(output, buffer, content, len - 1); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); + free(content); /* Ligne de séparation */ line = g_lang_output_continue_comments(output, buffer, NULL, 0); g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); /* Conclusion */ line = g_lang_output_end_comments(output, buffer); - if (line != NULL) g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + if (line != NULL) + { + g_buffer_line_start_merge_at(line, BLC_PHYSICAL); + g_code_buffer_append_new_line(buffer, line); + } g_object_unref(G_OBJECT(output)); diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c index 67a3ce8..75444a5 100644 --- a/src/analysis/disass/output.c +++ b/src/analysis/disass/output.c @@ -210,13 +210,15 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form { init_mrange(&range, get_mrange_addr(g_binary_symbol_get_range(symbols[sym_index])), 0); - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); + g_buffer_line_add_flag(line, BLF_IS_LABEL); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, label, strlen(label), RTT_LABEL); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, ":", 1, RTT_PUNCT); + g_code_buffer_append_new_line(buffer, line); } @@ -288,6 +290,8 @@ void print_disassembled_instructions(GCodeBuffer *buffer, const GExeFormat *form } + g_code_buffer_append_new_line(buffer, line); + //gtk_extended_status_bar_update_activity(statusbar, id, (iaddr - start) * 1.0 / (end - start)); diff --git a/src/arch/instruction.c b/src/arch/instruction.c index 184d98c..021bdd4 100644 --- a/src/arch/instruction.c +++ b/src/arch/instruction.c @@ -895,7 +895,7 @@ static GBufferLine *_g_arch_instruction_print(const GArchInstruction *instr, GCo size_t klen; /* Taille de ce mot clef */ size_t i; /* Boucle de parcours */ - result = g_code_buffer_append_new_line(buffer, &instr->range); + result = g_code_buffer_prepare_new_line(buffer, &instr->range); g_buffer_line_add_flag(result, BLF_HAS_CODE); diff --git a/src/arch/raw.c b/src/arch/raw.c index 57860c0..d04f141 100644 --- a/src/arch/raw.c +++ b/src/arch/raw.c @@ -366,7 +366,7 @@ static GBufferLine *g_raw_instruction_print(const GRawInstruction *instr, GCodeB else { - result = g_code_buffer_append_new_line(buffer, &base->range); + result = g_code_buffer_prepare_new_line(buffer, &base->range); g_buffer_line_add_flag(result, BLF_HAS_CODE); diff --git a/src/glibext/gbinportion.c b/src/glibext/gbinportion.c index abdec60..0744a79 100644 --- a/src/glibext/gbinportion.c +++ b/src/glibext/gbinportion.c @@ -536,31 +536,37 @@ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, Mem init_mrange(&range, get_mrange_addr(&portion->range), 0); - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_add_flag(line, BLF_WIDTH_MANAGER); + g_code_buffer_append_new_line(buffer, line); + /* Séparation */ - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ======================================================", 56, RTT_COMMENT); + g_code_buffer_append_new_line(buffer, line); + /* Retour à la ligne */ - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT); + g_code_buffer_append_new_line(buffer, line); + /* Description */ - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); @@ -577,16 +583,22 @@ void g_binary_portion_print(const GBinPortion *portion, GCodeBuffer *buffer, Mem g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, rights, strlen(rights), RTT_COMMENT); + g_code_buffer_append_new_line(buffer, line); + /* Retour à la ligne */ - line = g_code_buffer_append_new_line(buffer, &range); + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); g_buffer_line_start_merge_at(line, BLC_ASSEMBLY_HEAD); g_buffer_line_insert_text(line, BLC_ASSEMBLY_HEAD, "; ", 2, RTT_COMMENT); - line = g_code_buffer_append_new_line(buffer, &range); + g_code_buffer_append_new_line(buffer, line); + + line = g_code_buffer_prepare_new_line(buffer, &range); g_buffer_line_fill_mrange(line, msize, msize); + g_code_buffer_append_new_line(buffer, line); + } diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c index d09758f..2f29ee4 100644 --- a/src/glibext/gbufferline.c +++ b/src/glibext/gbufferline.c @@ -170,6 +170,19 @@ static void on_line_segment_changed(GBufferSegment *, GBufferLine *); static void reset_column(buffer_line_column *column) { + size_t i; /* Boucle de parcours */ + + for (i = 0; i < column->count; i++) + g_object_unref(G_OBJECT(column->segments[i])); + + if (column->segments != NULL) + { + free(column->segments); + column->segments = NULL; + } + + column->count = 0; + column->max_width = 0; } @@ -1264,6 +1277,37 @@ GBufferSegment *g_buffer_line_insert_text(GBufferLine *line, BufferLineColumn co * Paramètres : line = ligne à venir consulter. * * first = première colonne à parcourir. * * end = colonne de fin de parcours. * +* * +* Description : Indique si du texte est présent dans une ligne de tampon. * +* * +* Retour : true pour indiquer la présence de texte, false pour du vide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_buffer_line_has_text(const GBufferLine *line, BufferLineColumn first, BufferLineColumn end) +{ + bool result; /* Bilan à retourner */ + BufferLineColumn i; /* Boucle de parcours */ + + result = false; + + assert(first < end); + + for (i = first; i < end && !result; i++) + result = (line->columns[i].count > 0); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * +* first = première colonne à parcourir. * +* end = colonne de fin de parcours. * * markup = indique si le texte doit être décoré ou non. * * * * Description : Donne le texte représenté par une ligne de tampon. * @@ -1311,6 +1355,31 @@ char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, Bu } +/****************************************************************************** +* * +* Paramètres : line = ligne à venir modifier. * +* first = première colonne à parcourir. * +* end = colonne de fin de parcours. * +* * +* Description : Supprime du texte représenté par une ligne de tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, BufferLineColumn end) +{ + BufferLineColumn i; /* Boucle de parcours #1 */ + + assert(first < end); + + for (i = first; i < end; i++) + reset_column(&line->columns[i]); + +} + /****************************************************************************** * * @@ -1353,7 +1422,8 @@ void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager) g_object_ref(G_OBJECT(manager)); line->manager = manager; - g_object_unref(G_OBJECT(old)); + if (old != NULL) + g_object_unref(G_OBJECT(old)); } @@ -1388,6 +1458,32 @@ void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager) /****************************************************************************** * * * Paramètres : line = ligne à venir consulter. * +* * +* Description : Renvoie la ligne comptabilisant les largeurs pour un groupe. * +* * +* Retour : Ligne considérée comme la gestionnaire d'un ensemble. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBufferLine *g_buffer_line_get_width_manager(GBufferLine *line) +{ + GBufferLine *result; /* Gestionnaire à retourner */ + + if (line->flags & BLF_WIDTH_MANAGER) + result = line; + else + result = line->manager; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne à venir consulter. * * max_widths = tableau résumant les largeurs maximales. [OUT]* * merged_width = largeur maximale en cas de fusion. |OUT] * * * @@ -1404,10 +1500,7 @@ void g_buffer_line_apply_max_widths(GBufferLine *line, gint *max_widths, gint *m GBufferLine *manager; /* Gestionnaire de groupe */ BufferLineColumn i; /* Boucle de parcours */ - if (line->flags & BLF_WIDTH_MANAGER) - manager = line; - else - manager = line->manager; + manager = g_buffer_line_get_width_manager(line); for (i = 0; i < BLC_COUNT; i++) max_widths[i] = MAX(manager->max_widths[i], max_widths[i]); @@ -1434,6 +1527,7 @@ void g_buffer_line_apply_max_widths(GBufferLine *line, gint *max_widths, gint *m gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) { gint result; /* Largeur à retourner */ + //GBufferLine *manager; /* Gestionnaire de groupe */ assert(index < BLC_COUNT); @@ -1447,6 +1541,8 @@ gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn i else { + //manager = g_buffer_line_get_width_manager(line); + if (line->flags & BLF_WIDTH_MANAGER) result = line->max_widths[index]; else diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h index 643e899..19652ab 100644 --- a/src/glibext/gbufferline.h +++ b/src/glibext/gbufferline.h @@ -89,11 +89,12 @@ typedef enum _BufferLineFlags { BLF_NONE = 0 << 0, /* Aucune */ BLF_HAS_CODE = 1 << 0, /* La ligne contient du code */ - BLF_ENTRYPOINT = 1 << 1, /* Représentation d'une entrée */ - BLF_BOOKMARK = 1 << 2, /* Signet associé */ - BLF_WIDTH_MANAGER = 1 << 3, /* Début de groupe des largeurs*/ + BLF_IS_LABEL = 1 << 1, /* Etiquette pour symbole */ + BLF_ENTRYPOINT = 1 << 2, /* Représentation d'une entrée */ + BLF_BOOKMARK = 1 << 3, /* Signet associé */ + BLF_WIDTH_MANAGER = 1 << 4, /* Début de groupe des largeurs*/ - BLF_ALL = ((1 << 4) - 1) + BLF_ALL = ((1 << 5) - 1) } BufferLineFlags; @@ -125,12 +126,21 @@ GBufferSegment *g_buffer_line_find_segment_from_creator(const GBufferLine *, GOb /* Ajoute du texte à formater dans une ligne donnée. */ GBufferSegment *g_buffer_line_insert_text(GBufferLine *, BufferLineColumn, const char *, size_t, RenderingTagType); +/* Indique si du texte est présent dans une ligne de tampon. */ +bool g_buffer_line_has_text(const GBufferLine *, BufferLineColumn, BufferLineColumn); + /* Donne le texte représenté par une ligne de tampon. */ char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineColumn, bool); +/* Supprime du texte représenté par une ligne de tampon. */ +void g_buffer_line_delete_text(GBufferLine *, BufferLineColumn, BufferLineColumn); + /* Retient les largeurs d'une ligne si maximales. */ void g_buffer_line_update_max_widths(GBufferLine *, GBufferLine *); +/* Renvoie la ligne comptabilisant les largeurs pour un groupe. */ +GBufferLine *g_buffer_line_get_width_manager(GBufferLine *); + /* Filtre des largeurs de lignes et ne garde que les maximales. */ void g_buffer_line_apply_max_widths(GBufferLine *, gint *, gint *); @@ -159,5 +169,16 @@ void g_buffer_line_draw(GBufferLine *, cairo_t *, const gint [BLC_COUNT], gint, void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *); +/* Petite aide pour la détection de commentaire */ +#define g_buffer_line_has_comment(ln) \ + ({ \ + bool __result; \ + __result = g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT); \ + __result |= (g_buffer_line_get_merge_start(ln) == BLC_DISPLAY \ + && !(g_buffer_line_get_flags(ln) & BLF_IS_LABEL)); \ + __result; \ + }) + + #endif /* _GLIBEXT_GBUFFERLINE_H */ diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c index 1d4e6cd..f3634f0 100644 --- a/src/glibext/gcodebuffer.c +++ b/src/glibext/gcodebuffer.c @@ -32,6 +32,7 @@ #include "chrysamarshal.h" #include "delayed-int.h" +#include "../common/extstr.h" @@ -148,11 +149,28 @@ static void on_line_content_change(GBufferLine *, GBufferSegment *, GCodeBuffer /* Réagit à un changement de propriété rattachée à une ligne. */ static void on_line_flag_flip(GBufferLine *, BufferLineFlags, BufferLineFlags, GCodeBuffer *); -/* Ajoute une nouvelle ligne à une position donnée. */ -static GBufferLine *g_code_buffer_create_new_line(GCodeBuffer *, size_t, const mrange_t *); +/* Ajoute de nouvelles lignes à une position donnée. */ +static void g_code_buffer_insert_lines_at(GCodeBuffer *, GBufferLine **, size_t, size_t); -/* Retrouve l'indice associé à une ligne au sein d'un tampon. */ -static size_t g_code_buffer_find_index_by_line(const GCodeBuffer *, const GBufferLine *); + + +/* ------------------------- 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 *); + +/* Affiche un commentaire sur une ligne de tampon dédiée. */ +static bool _g_code_buffer_write_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool); + +/* 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 *); @@ -426,6 +444,591 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkExtStatusBar *statusbar) /* ---------------------------------------------------------------------------------- */ +/* 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. * +* * +* 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) +{ + 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_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT); + + else + { + new = g_code_buffer_prepare_new_line(buffer, range); + g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT); + + 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. * +* * +* 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) +{ + 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); + + /* 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. * +* * +* 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) +{ + 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_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT); + + 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. * +* * +* 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) +{ + 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); + + /* 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 : 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) +{ + _g_code_buffer_delete_lines_comment(buffer, line); + + /* TODO : emit() */ + +} + + + +/* ---------------------------------------------------------------------------------- */ /* TAMPON POUR CODE DESASSEMBLE */ /* ---------------------------------------------------------------------------------- */ @@ -642,6 +1245,34 @@ static void g_code_buffer_update_line_max_widths(const GCodeBuffer *buffer, size /****************************************************************************** * * +* 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_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 4, RTT_RAW); + + 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. * @@ -686,41 +1317,64 @@ static void on_line_flag_flip(GBufferLine *line, BufferLineFlags old, BufferLine /****************************************************************************** * * * Paramètres : buffer = composant GLib à mettre à jour. * -* range = emplacement où va se situer la ligne. * +* lines = liste de lignes à insérer. * +* count = taille de cette liste. * +* index = point d'insertion de la première ligne. * * * -* Description : Ajoute une nouvelle ligne à une position donnée. * +* Description : Ajoute de nouvelles lignes à une position donnée. * * * -* Retour : Nouvelle ligne vierge à écrire. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GBufferLine *g_code_buffer_create_new_line(GCodeBuffer *buffer, size_t index, const mrange_t *range) +static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lines, size_t count, size_t index) { - GBufferLine *result; /* Instance à retourner */ size_t i; /* Boucle de parcours */ - if (buffer->used == buffer->count) + /* Elaboration d'un espace suffisant */ + + if ((buffer->used + count) > buffer->count) { - buffer->count += LINE_ALLOC_BULK; + if (count > LINE_ALLOC_BULK) + buffer->count += count; + else + buffer->count += LINE_ALLOC_BULK; + buffer->lines = (GBufferLine **)realloc(buffer->lines, buffer->count * sizeof(GBufferLine *)); + } - buffer->used++; - assert(index < buffer->used); + /* Insertion des lignes */ - result = g_buffer_line_new(range, buffer->main_column); - buffer->lines[index] = result; + if (index < buffer->used) + { + memmove(&buffer->lines[index + count], &buffer->lines[index], + (buffer->used - index) * sizeof(GBufferLine *)); + } - for (i = 0; i < buffer->indent; i++) - g_buffer_line_insert_text(result, BLC_ASSEMBLY_HEAD, " ", 4, RTT_RAW); + buffer->used += count; - g_signal_connect(result, "content-changed", G_CALLBACK(on_line_content_change), buffer); - g_signal_connect(result, "flip-flag", G_CALLBACK(on_line_flag_flip), buffer); + for (i = 0; i < count; i++) + { + assert((index + i) < buffer->used); - return result; + 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 */ + + /** + * Comme des optimisations reposant sur des cas particuliers peuvent être + * réalisées ici, c'est à l'appelant de prendre cette charge de calculs à + * son compte ! + */ } @@ -728,21 +1382,78 @@ static GBufferLine *g_code_buffer_create_new_line(GCodeBuffer *buffer, size_t in /****************************************************************************** * * * Paramètres : buffer = composant GLib à mettre à jour. * -* range = emplacement où va se situer la ligne. * +* line = lign à insérer à la fin du tampon. * * * -* Description : Ajoute une nouvelle ligne à un tampon pour code désassemblé. * +* Description : Ajoute une nouvelle ligne en fin de tampon. * * * -* Retour : Nouvelle ligne vierge à écrire. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer, const mrange_t *range) +void g_code_buffer_append_new_line(GCodeBuffer *buffer, GBufferLine *line) { - GBufferLine *result; /* Instance à retourner */ + GBufferLine *manager; /* Ligne de gestion de largeurs*/ - result = g_code_buffer_create_new_line(buffer, buffer->used, range); + g_code_buffer_insert_lines_at(buffer, (GBufferLine *[]) { line }, 1, buffer->used); + + /* Recueil initial des largeurs */ + + if (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER) + manager = line; + + else + { + assert(buffer->used > 1); + manager = g_buffer_line_get_width_manager(buffer->lines[buffer->used - 2]); + } + + g_buffer_line_update_max_widths(line, manager); + +} + + +/****************************************************************************** +* * +* 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); + + + g_code_buffer_update_line_max_widths(buffer, index, index + count); + + + result = true; + + gcbil_exit: return result; @@ -751,6 +1462,45 @@ GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *buffer, const mrange_t * /****************************************************************************** * * +* 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)); + + } + + memmove(&buffer->lines[start], &buffer->lines[end + 1], + (buffer->used - end - 1) * sizeof(GBufferLine *)); + +} + + +/****************************************************************************** +* * * 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. * @@ -844,7 +1594,7 @@ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t * * ******************************************************************************/ -static size_t g_code_buffer_find_index_by_line(const GCodeBuffer *buffer, const GBufferLine *line) +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 */ @@ -1289,7 +2039,7 @@ static void g_buffer_view_compute_required_widths(GBufferView *view, const bool if (view->buffer->used > 0) { - g_code_buffer_update_line_max_widths(view->buffer, first, last); + //g_code_buffer_update_line_max_widths(view->buffer, first, last); for (i = first; i <= last; i++) g_buffer_line_apply_max_widths(lines[i], view->max_widths, &view->merged_width); diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h index 86e94d2..0f2d601 100644 --- a/src/glibext/gcodebuffer.h +++ b/src/glibext/gcodebuffer.h @@ -57,22 +57,38 @@ GType g_code_buffer_get_type(void); /* Crée un nouveau composant de tampon pour code désassemblé. */ GCodeBuffer *g_code_buffer_new(BufferLineColumn); +/* Initie une nouvelle ligne devant être insérée dans le tampon. */ +GBufferLine *g_code_buffer_prepare_new_line(GCodeBuffer *, const mrange_t *); + +/* Ajoute une nouvelle ligne en fin de tampon. */ +void g_code_buffer_append_new_line(GCodeBuffer *, GBufferLine *); + +/* Ajoute de nouvelles lignes par rapport à une ligne donnée. */ +bool g_code_buffer_insert_lines(GCodeBuffer *, GBufferLine **, size_t, const GBufferLine *, bool); + +/* Supprime une ou plusieurs lignes du tampon indiqué. */ +void g_code_buffer_delete_lines(GCodeBuffer *, size_t, size_t); + + + /* FIXME */ #define g_code_buffer_append_new_line_fixme(b) \ g_code_buffer_append_new_line(b, (mrange_t []){ { 0, 0 }, 0 }) -/* Ajoute une nouvelle ligne à un tampon pour code désassemblé. */ -GBufferLine *g_code_buffer_append_new_line(GCodeBuffer *, const mrange_t *); - /* FIXME */ #define g_code_buffer_insert_at(buf, a, b) NULL + + /* Retrouve une ligne au sein d'un tampon avec une adresse. */ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t *, BufferLineFlags, size_t *); /* Retrouve une ligne au sein d'un tampon avec un indice. */ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *, size_t); +/* Retrouve l'indice associé à une ligne au sein d'un tampon. */ +size_t g_code_buffer_find_index_by_line(const GCodeBuffer *, const GBufferLine *); + /* Augmente l'indentation des prochaines lignes. */ void g_code_buffer_inc_indentation(GCodeBuffer *); @@ -87,6 +103,27 @@ GDelayedWork *g_buffer_code_scan(GCodeBuffer *, const vmpa2t *, const vmpa2t *, +/* ------------------------- CONFORTS POUR LES COMMENTAIRES ------------------------- */ + + +/* Séparateur commun à tous les plateformes */ +#define COMMENT_LINE_SEP "\n" + + +/* Affiche un commentaire sur une ligne de tampon donnée. */ +bool g_code_buffer_update_inlined_comment(GCodeBuffer *, GBufferLine *, const char *); + +/* Affiche un commentaire sur une ligne de tampon dédiée. */ +bool g_code_buffer_update_comment_area(GCodeBuffer *, GBufferLine *, const char *, bool); + +/* Récupère le contenu d'un commentaire existant. */ +char *g_code_buffer_get_lines_comment(const GCodeBuffer *, const GBufferLine *); + +/* Supprime un commentaire existant. */ +bool g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *); + + + /* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */ -- cgit v0.11.2-87-g4458