Branch: refs/heads/master Author: Dimitar Zhekov dimitar.zhekov@gmail.com Committer: Dimitar Zhekov dimitar.zhekov@gmail.com Date: Thu, 17 Jan 2013 17:42:57 UTC Commit: f194ba8c143198dfb499a7169809ba2198b7350f https://github.com/geany/geany-plugins/commit/f194ba8c143198dfb499a7169809ba...
Log Message: ----------- scope - added memory.c, memory.h
Modified Paths: -------------- scope/src/memory.c scope/src/memory.h
Modified: scope/src/memory.c 414 files changed, 414 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,414 @@ +/* + * memory.c + * + * Copyright 2013 Dimitar Toshkov Zhekov dimitar.zhekov@gmail.com + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see http://www.gnu.org/licenses/. + */ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <gdk/gdkkeysyms.h> + +#include "common.h" + +enum +{ + MEMORY_ADDR, + MEMORY_BYTES, + MEMORY_ASCII +}; + +static GtkListStore *store; +static GtkTreeModel *model; +static GtkTreeSelection *selection; + +static void on_memory_bytes_edited(G_GNUC_UNUSED GtkCellRendererText *renderer, gchar *path_str, + gchar *new_text, G_GNUC_UNUSED gpointer gdata) +{ + if (*new_text && (debug_state() & DS_SENDABLE)) + { + GtkTreeIter iter; + const char *addr, *bytes; + guint i; + + gtk_tree_model_get_iter_from_string(model, &iter, path_str); + gtk_tree_model_get(model, &iter, MEMORY_ADDR, &addr, MEMORY_BYTES, &bytes, -1); + + for (i = 0; bytes[i]; i++) + if (!(isxdigit(bytes[i]) ? isxdigit(new_text[i]) : new_text[i] == ' ')) + break; + + if (bytes[i] || new_text[i]) + dc_error("memory: invalid format"); + else + { + utils_strchrepl(new_text, ' ', '\0'); + debug_send_format(T, "07-data-write-memory-bytes 0x%s%s", addr, new_text); + } + } + else + plugin_blink(); +} + +static gboolean on_memory_entry_key_press(G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event, + GtkEditable *editable) +{ + const char *text = gtk_entry_get_text(GTK_ENTRY(editable)); + gint pos = gtk_editable_get_position(editable); + + if (event->keyval <= 0x7F && ((isxdigit(event->keyval) && isxdigit(text[pos])) || + (event->keyval == ' ' && text[pos] == ' ')) && event->state <= GDK_SHIFT_MASK) + { + char c = event->keyval; + + gtk_editable_set_editable(editable, TRUE); + gtk_editable_delete_text(editable, pos, pos + 1); + gtk_editable_insert_text(editable, &c, 1, &pos); + gtk_editable_set_position(editable, pos); + gtk_editable_set_editable(editable, FALSE); + return TRUE; + } + + return event->keyval == GDK_Insert || event->keyval == GDK_KP_Insert || + event->keyval == GDK_space || event->keyval == GDK_KP_Space; +} + +static const char *memory_font; + +static void on_memory_bytes_editing_started(G_GNUC_UNUSED GtkCellRenderer *cell, + GtkCellEditable *cell_editable, G_GNUC_UNUSED const gchar *path, + G_GNUC_UNUSED gpointer gdata) +{ + iff (GTK_IS_ENTRY(cell_editable), "memory_bytes: not an entry") + { + GtkEditable *editable = GTK_EDITABLE(cell_editable); + + ui_widget_modify_font_from_string(GTK_WIDGET(editable), memory_font); + gtk_entry_set_overwrite_mode(GTK_ENTRY(editable), TRUE); + gtk_editable_set_editable(editable, FALSE); + gtk_editable_set_position(editable, 0); + g_signal_connect(editable, "key-press-event", G_CALLBACK(on_memory_entry_key_press), + editable); + } +} + +static const TreeCell memory_cells[] = +{ + { "memory_bytes", G_CALLBACK(on_memory_bytes_edited) }, + { NULL, NULL } +}; + +static guint pointer_size; +static char *addr_format; +#define MAX_BYTES_PER_LINE 128 +#define MAX_POINTER_SIZE 8 + +static gint back_bytes_per_line; +static gint bytes_per_line; +static gint bytes_per_group = 1; + +static void memory_configure(void) +{ + gint groups_per_line; + + back_bytes_per_line = pref_memory_bytes_per_line; + bytes_per_line = pref_memory_bytes_per_line; + if ((unsigned) (bytes_per_line - 8) > MAX_BYTES_PER_LINE - 8) + bytes_per_line = 16; + + groups_per_line = bytes_per_line / bytes_per_group; + bytes_per_line = groups_per_line * bytes_per_group; +} + +static guint64 memory_start; +static guint memory_count = 0; +#define MAX_BYTES (128 * MAX_BYTES_PER_LINE) /* +1 incomplete line */ + +static void write_block(guint64 start, const char *contents, guint count) +{ + if (!memory_count) + memory_start = start; + + while (memory_count < MAX_BYTES) + { + GtkTreeIter iter; + char *addr = g_strdup_printf(addr_format, start); + GString *bytes = g_string_sized_new(bytes_per_line * 3); + GString *ascii = g_string_new(" "); + gint n = 0; + + gtk_list_store_append(store, &iter); + + while (n < bytes_per_line) + { + char locale; + gchar *utf8; + + g_string_append_len(bytes, contents, 2); + contents += 2; + memory_count++; + locale = strtol(bytes->str + bytes->len - 2, NULL, 16); + utf8 = locale >= 0x20 ? g_locale_to_utf8(&locale, 1, NULL, NULL, NULL) : NULL; + + if (utf8) + { + g_string_append(ascii, utf8); + g_free(utf8); + } + else + g_string_append_c(ascii, '.'); /* 0xfffd? */ + + if (++n % bytes_per_group == 0) + g_string_append_c(bytes, ' '); + + if (!--count) + break; + } + + while (n < bytes_per_line) + { + g_string_append(bytes, " "); + + if (++n % bytes_per_group == 0) + g_string_append_c(bytes, ' '); + } + + gtk_list_store_set(store, &iter, MEMORY_ADDR, addr, MEMORY_BYTES, bytes->str, + MEMORY_ASCII, ascii->str, -1); + + g_free(addr); + g_string_free(bytes, TRUE); + g_string_free(ascii, TRUE); + + if (!count) + break; + + start += bytes_per_line; + } + + if (count) + dc_error("memory: too much data"); +} + +static void memory_node_read(const ParseNode *node, G_GNUC_UNUSED gpointer gdata) +{ + iff (node->type == PT_ARRAY, "memory: contains value") + { + GArray *nodes = (GArray *) node->value; + const char *begin = parse_find_value(nodes, "begin"); + const char *contents = parse_find_value(nodes, "contents"); + + iff (begin && contents, "memory: no begin or contents") + { + guint64 start; + guint64 count = strlen(contents) / 2; + + sscanf(begin, "%" G_GINT64_MODIFIER "i", &start); + + iff (count, "memory: contents too short") + write_block(start, contents, count); + } + } +} + +void on_memory_read_bytes(GArray *nodes) +{ + if (pointer_size <= MAX_POINTER_SIZE) + { + GtkTreeIter iter; + char *addr = NULL; + + if (gtk_tree_selection_get_selected(selection, NULL, &iter)) + { + gtk_tree_model_get(model, &iter, MEMORY_ADDR, &addr, -1); + addr = strdup(addr); + } + + memory_clear(); + + if (pref_memory_bytes_per_line != back_bytes_per_line) + { + memory_configure(); + gtk_tree_view_column_queue_resize(get_column("memory_bytes_column")); + gtk_tree_view_column_queue_resize(get_column("memory_ascii_column")); + } + + array_foreach(parse_lead_array(nodes), (GFunc) memory_node_read, + GINT_TO_POINTER(TRUE)); + + if (addr) + { + if (model_find(model, &iter, MEMORY_ADDR, addr)) + utils_tree_set_cursor(selection, &iter, -1); + g_free(addr); + } + } +} + +void memory_clear(void) +{ + gtk_list_store_clear(store); + memory_count = 0; +} + +gboolean memory_update(void) +{ + if (memory_count) + { + debug_send_format(T, "04-data-read-memory-bytes 0x%" G_GINT64_MODIFIER "x %u", + memory_start, memory_count); + } + return TRUE; +} + +static void on_memory_refresh(G_GNUC_UNUSED const MenuItem *menu_item) +{ + debug_send_format(T, "-data-read-memory-bytes 0x%" G_GINT64_MODIFIER "x %u", + memory_start, memory_count); +} + +static void on_memory_read(G_GNUC_UNUSED const MenuItem *menu_item) +{ + GString *command = g_string_new("-data-read-memory-bytes "); + gchar *expr = utils_get_default_selection(); + + if (expr) + { + g_string_append(command, expr); + g_free(expr); + } + else if (memory_count) + { + g_string_append_printf(command, "0x%" G_GINT64_MODIFIER "x %u", memory_start, + memory_count); + } + + view_command_line(command->str, _("Read Memory"), " ", TRUE); + g_string_free(command, TRUE); +} + +static void on_memory_copy(G_GNUC_UNUSED const MenuItem *menu_item) +{ + GtkTreeModel *model; + GtkTreeIter iter; + const char *addr, *bytes; + const gchar *ascii; + gchar *string; + + gtk_tree_selection_get_selected(selection, &model, &iter); + gtk_tree_model_get(model, &iter, MEMORY_ADDR, &addr, MEMORY_BYTES, &bytes, + MEMORY_ASCII, &ascii, -1); + string = g_strdup_printf("%s%s%s", addr, bytes, ascii); + gtk_clipboard_set_text(gtk_widget_get_clipboard(menu_item->widget, + GDK_SELECTION_CLIPBOARD), string, -1); + g_free(string); +} + +static void on_memory_clear(G_GNUC_UNUSED const MenuItem *menu_item) +{ + memory_clear(); +} + +static void on_memory_group_display(const MenuItem *menu_item) +{ + guint i; + + for (i = 0; (1 << i) < bytes_per_group; i++); + menu_item_set_active(menu_item + i + 1, TRUE); +} + +static void on_memory_group_update(const MenuItem *menu_item) +{ + bytes_per_group = 1 << GPOINTER_TO_INT(menu_item->gdata); + back_bytes_per_line = 0; + + if (memory_count) + on_memory_refresh(menu_item); +} + +#define DS_FRESHABLE (DS_SENDABLE | DS_EXTRA_2) +#define DS_COPYABLE (DS_BASICS | DS_EXTRA_1) +#define DS_CLEARABLE (DS_ACTIVE | DS_EXTRA_2) + +#define GROUP_ITEM(count, POWER) \ + { ("memory_group_"count), on_memory_group_update, DS_SENDABLE, NULL, \ + GINT_TO_POINTER(POWER) } + +static MenuItem memory_menu_items[] = +{ + { "memory_refresh", on_memory_refresh, DS_FRESHABLE, NULL, NULL }, + { "memory_read", on_memory_read, DS_SENDABLE, NULL, NULL }, + { "memory_copy", on_memory_copy, DS_COPYABLE, NULL, NULL }, + { "memory_clear", on_memory_clear, DS_CLEARABLE, NULL, NULL }, + { "memory_group", on_memory_group_display, DS_SENDABLE, NULL, NULL }, + GROUP_ITEM("1", 0), + GROUP_ITEM("2", 1), + GROUP_ITEM("4", 2), + GROUP_ITEM("8", 3), + { NULL, NULL, 0, NULL, NULL } +}; + +static guint memory_menu_extra_state(void) +{ + return (gtk_tree_selection_get_selected(selection, NULL, NULL) << DS_INDEX_1) | + (memory_count != 0) << DS_INDEX_1; +} + +static MenuInfo memory_menu_info = { memory_menu_items, memory_menu_extra_state, 0 }; + +static gboolean on_memory_key_press(G_GNUC_UNUSED GtkWidget *widget, GdkEventKey *event, + gpointer gdata) +{ + if (event->keyval == GDK_Insert || event->keyval == GDK_KP_Insert) + { + menu_item_execute(&memory_menu_info, (const MenuItem *) gdata, FALSE); + return TRUE; + } + + return FALSE; +} + +void memory_init(void) +{ + GtkWidget *tree = GTK_WIDGET(view_connect("memory_view", &model, &selection, + memory_cells, "memory_window", NULL)); + + store = GTK_LIST_STORE(model); + memory_font = *pref_memory_font ? pref_memory_font : pref_vte_font; + ui_widget_modify_font_from_string(tree, memory_font); + g_signal_connect(get_object("memory_bytes"), "editing-started", + G_CALLBACK(on_memory_bytes_editing_started), NULL); + g_signal_connect(tree, "key-press-event", G_CALLBACK(on_memory_key_press), + (gpointer) menu_item_find(memory_menu_items, "memory_read")); + + pointer_size = sizeof(void *) > sizeof &memory_init ? sizeof(void *) : + sizeof &memory_init; + addr_format = g_strdup_printf("%%0%u" G_GINT64_MODIFIER "x ", pointer_size * 2); + memory_configure(); + + if (pointer_size > MAX_POINTER_SIZE) + { + msgwin_status_add(_("Scope: pointer size > 8, Data disabled.")); + gtk_widget_hide(tree); + } + else + menu_connect("memory_menu", &memory_menu_info, tree); +} + +void memory_finalize(void) +{ + g_free(addr_format); +}
Modified: scope/src/memory.h 32 files changed, 32 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,32 @@ +/* + * utils.h + * + * Copyright 2013 Dimitar Toshkov Zhekov dimitar.zhekov@gmail.com + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see http://www.gnu.org/licenses/. + */ + +#ifndef MEMORY_H + +void on_memory_read_bytes(GArray *nodes); +void on_memory_modified(GArray *nodes); + +void memory_clear(void); +gboolean memory_update(void); + +void memory_init(void); +void memory_finalize(void); + +#define MEMORY_H 1 +#endif
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
plugins-commits@lists.geany.org