Logo Search packages:      
Sourcecode: jmp version File versions  Download package

string_inspector.c

#include <string.h>
#include <stdlib.h>
#include <string_inspector.h>
#include <gtk/gtk.h>
#include <gtkutils.h>
#include <jmp.h>
#include <obj.h>
#include <heap_dump.h>
#include <ui.h>
#include <instance_owners.h>
#include <string_dumper.h>

/** 
 * TODO: fix so that SI_COUNT is the number of times each string occurs. 
 */

enum {
    SI_TEXT,
    SI_COUNT, /* number of strings */
    SI_BYTES, /* number of bytes used. */
    SI_OBJ,
    SIN_COLUMNS
};

static GtkTreeIter* find_parent (GtkTreeStore* clist, gchar* txt, 
                         gint size, GtkTreeIter* parent) {
    gboolean fi;
    gint count;
    gint used;
    gchar* converted_text = NULL;    
    fi = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (clist), parent);
    if (!fi)
      return NULL;
    
    // TODO: binary search instead of linear?
    do {
      gtk_tree_model_get (GTK_TREE_MODEL (clist), parent, 
                      SI_TEXT, &converted_text,
                      SI_COUNT, &count,
                      SI_BYTES, &used, 
                      -1);
      if (g_utf8_get_char (txt) == g_utf8_get_char (converted_text)) {
          gtk_tree_store_set (clist, parent, 
                        SI_COUNT, count + 1,
                        SI_BYTES, used + size,
                        -1);
          return parent;
      }
    } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (clist), parent));
    return NULL;
}

static void add_string (obj* o, GtkTreeStore* clist) {
    down_link* dl;
    get_instance_info (o);
    dl = get_last_down_link ();
    while (dl != NULL) {
      glong items_written;
      glong items_read;
      GError* err = NULL;
      char*   converted_text;
      GtkTreeIter iter;
      GtkTreeIter parent;

      switch (dl->type) {
      case JVMPI_GC_PRIM_ARRAY_DUMP:
          converted_text = 
            g_utf16_to_utf8 ((gunichar2*)dl->value.txt, dl->pos, &items_read, 
                         &items_written, &err);
          if (err != NULL) {
            fprintf (stderr, "Unable to convert text: %s\n", err->message);
            break;
          }
          /* yes its a kind of insertion sort, may be stupid but probably 
           * there are no more than 200 top level entries..... 
           */
          if (find_parent (clist, converted_text, dl->pos * 2, &parent) == NULL) {
            /* get first unicode char */
            gchar dest[8];
            gtk_tree_store_append (clist, &parent, NULL);
            g_utf8_strncpy (dest, converted_text, 1);
            
            /* Store a parent node with the given name. */
            gtk_tree_store_set (clist, &parent, 
                            SI_TEXT, dest,
                            SI_COUNT, 1,
                            SI_BYTES, dl->pos * 2,
                            SI_OBJ, NULL,
                            -1);
          }
          gtk_tree_store_append (clist, &iter, &parent);
          gtk_tree_store_set (clist, &iter, 
                        SI_TEXT, converted_text,
                        SI_COUNT, 1, 
                        SI_BYTES, dl->pos * 2,
                        SI_OBJ, obj_get_object_id (o),
                        -1);
          free (converted_text);
          break;
      default:
          fprintf (stderr, "Odd type when dumping strings: %d\n", dl->type);
      }
      dl = dl->next;    
    }
    free_last_down_link ();
}

static gint sort_by_text (GtkTreeModel* model,
                    GtkTreeIter* a,
                    GtkTreeIter* b,
                    gpointer user_data) {
    gchar* cn1;
    gchar* cn2;
    gtk_tree_model_get (model, a, SI_TEXT, &cn1, -1);
    gtk_tree_model_get (model, b, SI_TEXT, &cn2, -1); 
    return g_strcasecmp (cn1, cn2);
}

static gint sort_by_count (GtkTreeModel* model,
                     GtkTreeIter* a,
                     GtkTreeIter* b,
                     gpointer user_data) {
    gint c1;
    gint c2;
    gtk_tree_model_get (model, a, SI_COUNT, &c1, -1);
    gtk_tree_model_get (model, b, SI_COUNT, &c2, -1); 
    return c1 - c2;    
}

static gint sort_by_bytes (GtkTreeModel* model,
                     GtkTreeIter* a,
                     GtkTreeIter* b,
                     gpointer user_data) {
    gint c1;
    gint c2;
    gtk_tree_model_get (model, a, SI_BYTES, &c1, -1);
    gtk_tree_model_get (model, b, SI_BYTES, &c2, -1); 
    return c1 - c2;    
}

static void set_sorter (GtkWidget* widget, gpointer data, 
                  int column, compr_func sorter) {
    GtkTreeStore* clist = (GtkTreeStore*)data;
    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (clist), 
                                column, GTK_SORT_ASCENDING);
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (clist), 0, 
                             sorter, NULL, NULL);
    gtk_tree_sortable_sort_column_changed (GTK_TREE_SORTABLE (clist));  
}

static void set_sorter_text (GtkWidget* widget, gpointer data) {
    set_sorter (widget, data, 0, sort_by_text);
}

static void set_sorter_count (GtkWidget* widget, gpointer data) {
    set_sorter (widget, data, 1, sort_by_count);
}

static void set_sorter_bytes (GtkWidget* widget, gpointer data) {
    set_sorter (widget, data, 2, sort_by_bytes);
}

static void close_strings_window (GtkWidget *widget, gpointer data) {
    gtk_object_destroy ((GtkObject*)data);
}

static void write_file (GtkWidget *widget, gpointer data) {
    char status[128];
    gboolean pb, cb; 
    FILE* f;
    GtkTreeIter parent;
    GtkTreeIter child;
    GtkTreeStore* clist = (GtkTreeStore*)data;
    f = get_string_dump_file (); 
    if (f == NULL) {
      set_status (_("string dumped failed to open file"));
      return;
    }

    pb = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (clist), &parent);
    if (pb) {
      do {
          cb = gtk_tree_model_iter_children (GTK_TREE_MODEL (clist), &child, &parent);
          if (cb) {
            do {
                gchar* text;
                gint count;
                gint used;
                gtk_tree_model_get (GTK_TREE_MODEL (clist), &child, 
                              SI_TEXT, &text, 
                              SI_COUNT, &count,
                              SI_BYTES, &used,
                              -1);
                write_string (f, text, count, used);
            } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (clist), &child));
          }
      } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (clist), &parent));
    }
    
    fflush (f);
    fclose (f);    
    snprintf (status, 128, _("strings dumped to %s"), get_current_dump_file ());
    set_status (status);
}

static GtkWidget *build_menu (GtkWidget* object_list, jobjectID o) {
    GtkWidget *omenu = gtk_menu_new ();
    GtkWidget* menuitem = gtk_menu_item_new_with_label (_("show owner"));
    gtk_menu_append (GTK_MENU (omenu), menuitem);
    gtk_signal_connect_object (GTK_OBJECT (menuitem), "activate",
                         GTK_SIGNAL_FUNC (show_owner),
                         o); 
    gtk_widget_show_all (omenu);
    return omenu;
}

static gint instance_button_handler (GtkWidget *widget,
                             GdkEventButton *event,
                             gpointer model) {
    GtkTreeIter iter;
    GtkTreeSelection *select; 
    jobjectID current_object;
    GtkTreeModel* m = (GtkTreeModel*)model;
    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
    if (gtk_tree_selection_get_selected (select, &m, &iter)) 
      gtk_tree_model_get (model, &iter, SI_OBJ, 
                      &current_object, -1);
    if (event->button == 3 && current_object != NULL) {
      GtkWidget* imenu = build_menu (widget, current_object);
      gtk_menu_popup (GTK_MENU (imenu), NULL, NULL, NULL, NULL,
                        event->button, event->time);  
      return TRUE;
    }
    return FALSE;
}


void inspect_strings () {
    GtkTreeStore* clist;
    GtkWidget* scrolled_window;
    GtkWidget* tree;
    GtkWidget* strings_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    GtkWidget* vbox;
    GtkWidget* hbox;
    GtkWidget* btn;
    gtk_container_set_border_width (GTK_CONTAINER (strings_window), 10);
    gtk_window_set_title (GTK_WINDOW (strings_window), 
                    _("Current strings (char[]) in memory"));
    clist = gtk_tree_store_new (SIN_COLUMNS, G_TYPE_STRING, 
                        G_TYPE_INT, G_TYPE_INT, G_TYPE_POINTER);
    for_each_string ((string_callback)add_string, clist);
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    vbox = gtk_vbox_new (FALSE, 5);
    gtk_container_add (GTK_CONTAINER (strings_window), vbox);    
    gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (clist));
    add_column (tree, _("Text"), SI_TEXT, (gpointer)clist, 
            set_sorter_text, 300, 0);
    add_column (tree, _("Count"), SI_COUNT, (gpointer)clist, 
            set_sorter_count, 50, 1);
    add_column (tree, _("Bytes"), SI_BYTES, (gpointer)clist, 
            set_sorter_bytes, 50, 1);
    gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (tree), TRUE);
    gtk_container_add (GTK_CONTAINER (scrolled_window), tree);    
    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (clist), 0, 
                                GTK_SORT_ASCENDING);
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (clist), 0, 
                             sort_by_text, NULL, NULL);
    gtk_tree_sortable_sort_column_changed (GTK_TREE_SORTABLE (clist));
    gtk_signal_connect (GTK_OBJECT(tree), "button_press_event",
                  GTK_SIGNAL_FUNC (instance_button_handler), 
                  clist);
    hbox = gtk_hbox_new (FALSE, 5);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
    btn = gtk_button_new_with_label (_("Close"));
    gtk_signal_connect (GTK_OBJECT (btn), "clicked",
                  GTK_SIGNAL_FUNC (close_strings_window),
                  strings_window);  
    gtk_box_pack_end (GTK_BOX (hbox), btn, FALSE, FALSE, 0);
    btn = gtk_button_new_with_label (_("Write file"));
    gtk_signal_connect (GTK_OBJECT (btn), "clicked",
                  GTK_SIGNAL_FUNC (write_file),
                  clist);     
    gtk_box_pack_end (GTK_BOX (hbox), btn, FALSE, FALSE, 0);
    

    gtk_widget_set_usize (strings_window, 450, 200);
    gtk_widget_show_all (strings_window);           
}

/* Emacs Local Variables: */
/* Emacs mode:C */
/* Emacs c-indentation-style:"gnu" */
/* Emacs c-hanging-braces-alist:((brace-list-open)(brace-entry-open)(defun-open after)(substatement-open after)(block-close . c-snug-do-while)(extern-lang-open after)) */
/* Emacs c-cleanup-list:(brace-else-brace brace-elseif-brace space-before-funcall) */
/* Emacs c-basic-offset:4 */
/* Emacs End: */

Generated by  Doxygen 1.6.0   Back to index