*** empty log message ***
authorSøren Sandmann Pedersen <ssp@src.gnome.org>
Mon, 15 Nov 2004 23:15:59 +0000 (23:15 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Mon, 15 Nov 2004 23:15:59 +0000 (23:15 +0000)
profile.c
profile.h
sfile.c [new file with mode: 0644]
sfile.h [new file with mode: 0644]
sysprof.c

index 7d4299c..eb33db6 100644 (file)
--- a/profile.c
+++ b/profile.c
@@ -117,7 +117,8 @@ serialize_call_tree (Node *node, SaveContext *context)
        return;
     
     g_string_append_printf (context->str,
-                           "        <node id=\"%d\" object=\"%d\" siblings=\"%d\" children=\"%d\" parent=\"%d\" next=\"%d\" total=\"%d\" self=\"%d\">\n",
+                           "        <node id=\"%d\" object=\"%d\" siblings=\"%d\" children=\"%d\" "
+                           "parent=\"%d\" next=\"%d\" total=\"%d\" self=\"%d\" toplevel=\"%d\">\n",
                            get_id (context, node),
                            get_id (context, node->object),
                            get_id (context, node->siblings),
@@ -125,7 +126,8 @@ serialize_call_tree (Node *node, SaveContext *context)
                            get_id (context, node->parent),
                            get_id (context, node->next),
                            node->total,
-                           node->self);
+                           node->self,
+                           node->toplevel);
 
     serialize_call_tree (node->siblings, context);
     serialize_call_tree (node->children, context);
@@ -133,8 +135,7 @@ serialize_call_tree (Node *node, SaveContext *context)
 
 gboolean
 profile_save (Profile           *profile,
-             const char         *file_name,
-             GError            **err)
+             const char         *file_name)
 {
     SaveContext context;
 
@@ -156,14 +157,13 @@ profile_save (Profile              *profile,
     g_hash_table_destroy (context.id_by_pointer);
     g_hash_table_destroy (context.pointer_by_id);
 
+    /* FIXME - write it to disk, not screen */
+    
     g_print (context.str->str);
     
     g_string_free (context.str, TRUE);
-    
-    /* Actually the way to fix this is probably to save StackStashes instead
-     * of profiles
-     */
-    return FALSE;
+
+    return TRUE;
 }
 
 typedef struct LoadContext LoadContext;
@@ -175,27 +175,62 @@ struct LoadContext
 };
 
 static int
-get_number (const char *s, GError **err)
+get_number (const char *input_name,
+           const char *target_name,
+           const char *value)
 {
-    char *end;
-    
-    int r = strtol (s, &end, 10);
-    if (*end != '\0')
+    if (strcmp (input_name, target_name) == 0)
     {
-       /* FIXME: set error to something appropriate */
+       char *end;
+       int r = strtol (value, &end, 10);
+       if (*end == '\0')
+           return r;
     }
 
-    return r;
+    return -1;
 }
 
 static Node *
-create_node (const char **attribute_names, const char **attribute_values, int *id, GError **error)
+create_node (const char **names,
+            const char **values,
+            int *id)
 {
     int i;
+
+    int object         = -1;
+    int siblings       = -1;
+    int children        = -1;
+    int parent         = -1;
+    int next           = -1;
+    int total          = -1;
+    int self           = -1;
+
+    Node *node = node_new ();
     
-    i = 0;
-    while (attribute_names[i])
+    for (i = 0; names[i] != NULL; ++i)
     {
+       *id            = get_number (names[i], "id", values[i]);
+       node->object   = GINT_TO_POINTER (get_number (names[i], "object", values[i]));
+       node->siblings = GINT_TO_POITNER (get_number (names[i], "siblings", values[i]));
+       node->children = GINT_TO_POINTER (get_number (names[i], "children", values[i]));
+       node->parent   = GINT_TO_POINTER (get_number (names[i], "parent", values[i]));
+       node->next     = GINT_TO_POINTER (get_number (names[i], "next", values[i]));
+       node->total    = get_number (names[i], "total", values[i]);
+       node->self     = get_number (names[i], "self", values[i]);
+    }
+                              
+    if (id == -1 || object == -1 || siblings == -1 ||
+       children == -1 || parent == -1 || next == -1 ||
+       total == -1 || self == -1)
+    {
+       return NULL;
+    }
+
+    node->object = GINT_TO_POINTER (object);
+    node->siblings = GINT_TO_POINTER (siblings);
+    
+    
+    i = 0;
        const char *name = attribute_names[i];
        const char *value = attribute_values[i];
 
@@ -241,7 +276,6 @@ parse_start_element (GMarkupParseContext *context,
 {
     int id;
     LoadContext *lc = user_data;
-
     
     if (strcmp (element_name, "object") == 0)
     {
index 64165e6..e6a6cbc 100644 (file)
--- a/profile.h
+++ b/profile.h
@@ -68,8 +68,7 @@ ProfileCaller *          profile_list_callers       (Profile           *profile,
                                               ProfileObject     *callee);
 void              profile_caller_free        (ProfileCaller     *caller);
 void               profile_descendant_free    (ProfileDescendant *descendant);
+
 gboolean          profile_save               (Profile           *profile,
-                                              const char        *file_name,
-                                              GError           **err);
-Profile *         profile_load               (const char        *filename,
-                                              GError           **err);
+                                              const char        *file_name);
+Profile *         profile_load               (const char        *filename);
diff --git a/sfile.c b/sfile.c
new file mode 100644 (file)
index 0000000..9960875
--- /dev/null
+++ b/sfile.c
@@ -0,0 +1,787 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- */
+
+/*  Lac - Library for asynchronous communication
+ *  Copyright (C) 2004  Søren Sandmann (sandmann@daimi.au.dk)
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the 
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "sfile.h"
+
+typedef struct ReadItem ReadItem;
+
+typedef enum
+{
+    BEGIN_RECORD,
+    BEGIN_LIST,
+    END,
+    READ_POINTER,
+    READ_INTEGER,
+    READ_STRING
+} ReadAction;
+
+typedef enum
+{
+    RECORD,
+    LIST,
+    POINTER,
+    INTEGER,
+    STRING
+} SFormatType;
+
+struct SFormat
+{
+    SFormatType type;
+
+    char *name;
+    
+    union
+    {
+       struct
+       {
+           GQueue *fields;
+       } record;
+       
+       struct
+       {
+           SFormat *content;
+       } list;
+    } u;
+};
+
+struct ReadItem
+{
+    ReadAction action;
+
+    union
+    {
+        struct
+        {
+            int         id;
+            gpointer    pointer;        /* Points to the user created object */
+        } end;
+        
+        struct
+        {
+            int         id;
+        } read_pointer;
+
+        struct
+        {
+            int         n_items;
+        } read_list;
+        
+        struct
+        {
+            int         value;
+        } read_integer;
+        
+        struct
+        {
+            char *      value;
+        } read_string;
+    } u;
+};
+
+struct SFile
+{
+    int n_items;
+    ReadItem *items;
+    ReadItem *current_item;
+    GHashTable *locations_by_id;
+    GHashTable *objects_by_id;
+};
+
+/* defining types */
+
+static SFormat *
+create_sformat (const char *name,
+                SFormatType type)
+{
+    SFormat *sformat = g_new0 (SFormat, 1);
+
+    sformat->name = g_strdup (name);
+    sformat->type = type;
+
+    return sformat;
+}
+
+SFormat *
+sformat_new_record  (const char *     name,
+                     SFormat      *content1,
+                     ...)
+{
+    va_list args;
+    SFormat *sformat = create_sformat (name, RECORD);
+    SFormat *field;
+    GQueue *fields = g_queue_new ();
+    
+    va_start (args, content1);
+    field = va_arg (args, SFormat *);
+    while (field)
+    {
+       g_queue_push_tail (fields, field);
+       field = va_arg (args, SFormat *);
+    }
+    va_end (args);
+    
+    sformat->u.record.fields = fields;
+    
+    return sformat;
+}
+
+SFormat *
+sformat_new_list (const char *name,
+                  SFormat *content)
+{
+    SFormat *sformat = create_sformat (name, LIST);
+    sformat->u.list.content = content;
+    return sformat;
+}
+
+SFormat *
+sformat_new_pointer (const char *name)
+{
+    SFormat *sformat = create_sformat (name, POINTER);
+    return sformat;
+}
+
+SFormat *
+sformat_new_integer (const char *name)
+{
+    SFormat *sformat = create_sformat (name, INTEGER);
+    return sformat;
+}
+
+SFormat *
+sformat_new_string (const char *name)
+{
+    SFormat *sformat = create_sformat (name, STRING);
+    return sformat;
+}
+
+/* reading */
+typedef struct BuildContext BuildContext;
+typedef struct ParseNode ParseNode;
+
+struct BuildContext
+{
+    ParseNode *root;
+    ParseNode *current_node;
+    GHashTable *nodes_by_id;
+};
+
+struct ParseNode
+{
+    ParseNode *parent;
+    char *name;
+    gpointer id;
+    GPtrArray *children;
+    GString *text;
+
+    SFormat *format;
+};
+
+void
+sfile_begin_get_record (SFile       *file)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_if_fail (file->current_item - file->items < file->n_items);
+    g_return_if_fail (item->action == BEGIN_RECORD);
+}
+
+int
+sfile_begin_get_list   (SFile       *file)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_val_if_fail (file->current_item - file->items < file->n_items, -1);
+    g_return_val_if_fail (item->action == BEGIN_LIST, -1);
+
+    return item->u.read_list.n_items;
+}
+
+void
+sfile_get_pointer      (SFile       *file,
+                        gpointer    *pointer)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_if_fail (file->current_item - file->items < file->n_items);
+    g_return_if_fail (item->action == READ_POINTER);
+
+    g_hash_table_insert (file->locations_by_id, GINT_TO_POINTER (item->u.read_pointer.id), pointer);
+}
+
+void
+sfile_get_integer      (SFile       *file,
+                        int         *integer)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_if_fail (file->current_item - file->items < file->n_items);
+    g_return_if_fail (item->action == READ_INTEGER);
+
+    *integer = item->u.read_integer.value;
+}
+
+void
+sfile_get_string       (SFile       *file,
+                        char       **string)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_if_fail (file->current_item - file->items < file->n_items);
+    g_return_if_fail (item->action == READ_STRING);
+
+    *string = g_strdup (item->u.read_string.value);
+}
+
+static void
+fixup_pointers (gpointer key, gpointer value, gpointer data)
+{
+    SFile *file = data;
+    int id = GPOINTER_TO_INT (key);
+    gpointer *location = value;
+
+    *location = g_hash_table_lookup (file->objects_by_id, GINT_TO_POINTER (id));
+}
+
+void
+sfile_end_get          (SFile       *file,
+                        gpointer     object)
+{
+    ReadItem *item = file->current_item++;
+
+    g_return_if_fail (file->current_item - file->items < file->n_items);
+    g_return_if_fail (item->action == END);
+
+    g_hash_table_insert (file->objects_by_id, GINT_TO_POINTER (item->u.end.id), object);
+
+    if (file->current_item - file->items == file->n_items)
+    {
+        /* Nothing else to read. Fix up pointers */
+        g_hash_table_foreach (file->locations_by_id, fixup_pointers, file);
+    }
+}
+
+static gboolean
+get_number (const char *text, int *number)
+{
+    char *end;
+    int result;
+    char *stripped;
+    
+    stripped = g_strstrip (g_strdup (text));
+    result = strtol (stripped, &end, 10);
+    g_free (stripped);
+    
+    if (*end != '\0')
+       return FALSE;
+    
+    if (number)
+       *number = result;
+    
+    return TRUE;
+}
+
+static ParseNode *
+parse_node_new (ParseNode *parent,
+                const char *name)
+{
+    ParseNode *node = g_new0 (ParseNode, 1);
+
+    node->parent = parent;
+    node->name = g_strdup (name);
+    node->id = NULL;
+    node->children = g_ptr_array_new ();
+    node->text = g_string_new ("");
+
+    if (parent)
+        g_ptr_array_add (parent->children, node);
+    
+    return node;
+}
+
+static void
+handle_begin_element (GMarkupParseContext *parse_context,
+                     const gchar *element_name,
+                     const gchar **attribute_names,
+                     const gchar **attribute_values,
+                     gpointer user_data,
+                     GError **err)
+{
+    BuildContext *build = user_data;
+    const char *id_string;
+    ParseNode *node;
+    int id;
+    int i;
+
+    /* Check for id */
+    id_string = NULL;
+    for (i = 0; attribute_names[i] != NULL; ++i)
+    {
+       if (strcmp (attribute_names[i], "id") == 0)
+       {
+           if (id_string)
+           {
+               /* FIXME: error: id defined twice */
+               return;
+           }
+           else
+           {
+               id_string = attribute_values[i];
+                
+                if (!get_number (id_string, &id) || id < 1)
+                {
+                    /* FIXME: bad attribute value for attribute 'id' */
+                    return;
+                }
+           }
+       }
+       else
+       {
+           /* FIXME: unknown attribute */
+           return;
+       }
+    }
+
+    if (build->current_node->text->len > 0)
+    {
+        /* FIXME: mixing children and text */
+        return;
+    }
+    
+    node = parse_node_new (build->current_node, element_name);
+
+    if (id_string)
+    {
+        node->id = GINT_TO_POINTER (id);
+        g_hash_table_insert (build->nodes_by_id, node->id, node);
+    }
+
+    build->current_node = node;
+
+    if (!build->root)
+        build->root = node;
+}
+    
+static void
+handle_end_element (GMarkupParseContext *context,
+                   const gchar *element_name,
+                   gpointer user_data,
+                   GError **err)
+{
+    BuildContext *build = user_data;
+
+    build->current_node = build->current_node->parent;
+}
+
+static void
+handle_text (GMarkupParseContext *context,
+            const gchar *text,
+             gsize text_len,
+            gpointer user_data,
+            GError **err)
+{
+    BuildContext *build = user_data;
+
+    if (build->current_node->children->len > 0)
+    {
+        /* FIXME: set error: mixing children and text */
+        return;
+    }
+    
+    g_string_append (build->current_node->text, text);
+}
+
+static ParseNode *
+build_tree (const char *text,
+           GHashTable *nodes_by_id,
+           GError **err)
+{
+    BuildContext build;
+    GMarkupParseContext *parse_context;
+    
+    GMarkupParser parser = {
+       handle_begin_element,
+       handle_end_element,
+       handle_text,
+       NULL, /* passthrough */
+       NULL, /* error */
+    };
+
+    build.root = NULL;
+    build.current_node = NULL;
+    build.nodes_by_id = nodes_by_id;
+    
+    parse_context = g_markup_parse_context_new (&parser, 0, &build, NULL);
+
+    if (!g_markup_parse_context_parse (parse_context, text, -1, err))
+    {
+       /* FIXME: free stuff */
+       return NULL;
+    }
+
+    if (!build.root)
+    {
+        /* FIXME: empty document not allowed */
+        /* FIXME: free stuff */
+        return NULL;
+    }
+    
+    return build.root;
+}
+
+static gboolean check_structure (ParseNode *node, SFormat *format, GHashTable *nodes_by_id, GError **err);
+
+static gboolean
+check_list_node (ParseNode *list_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    SFormat *content = format->u.list.content;
+    int i;
+    
+    for (i = 0; i < list_node->children->len; ++i)
+    {
+        ParseNode *child = list_node->children->pdata[i];
+        
+        if (!check_structure (child, content, nodes_by_id, err))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+check_pointer_node (ParseNode *pointer_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    int ref_id;
+
+    if (!get_number (pointer_node->text->str, &ref_id))
+    {
+        /* Expected number */
+        return FALSE;
+    }
+
+    if (g_hash_table_lookup (nodes_by_id, GINT_TO_POINTER (ref_id)))
+    {
+        /* Dangling pointer */
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+check_integer_node (ParseNode *integer_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    if (!get_number (integer_node->text->str, NULL))
+    {
+        /* Expected number */
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+check_string_node (ParseNode *parse_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    char *text = g_strdup (parse_node->text->str);
+
+    g_strstrip (text);
+
+    if (strlen (text) < 2)
+    {
+        /* FIXME: syntax error */
+        return FALSE;
+    }
+    
+    if (text[0] != '\"' || text[strlen (text) - 1] != '\"')
+    {
+        /* FIMXE: string not quoted */
+        return FALSE;
+    }
+
+    g_free (text);
+
+    return TRUE;
+}
+
+static gboolean
+check_record_node (ParseNode *parse_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    GList *list;
+    int i;
+    
+    if (parse_node->children->len != g_queue_get_length (format->u.record.fields))
+    {
+        /* FIXME: Set error: incorrect number of fields */
+        return FALSE;
+    }
+
+    list = format->u.record.fields->head;
+    for (i = 0; i < parse_node->children->len; ++i)
+    {
+        SFormat *field = list->data;
+        ParseNode *child = parse_node->children->pdata[i];
+
+        if (!check_structure (child, field, nodes_by_id, err))
+            return FALSE;
+
+        list = list->next;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+check_structure (ParseNode *parse_node, SFormat *format, GHashTable *nodes_by_id, GError **err)
+{
+    if (strcmp (parse_node->name, format->name) != 0)
+    {
+        /* FIXME: format->name expected */
+        return FALSE;
+    }
+
+    parse_node->format = format;
+    
+    switch (format->type)
+    {
+    case LIST:
+        return check_list_node (parse_node, format, nodes_by_id, err);
+       break;
+       
+    case POINTER:
+        return check_pointer_node (parse_node, format, nodes_by_id, err);
+        break;
+        
+    case INTEGER:
+        return check_integer_node (parse_node, format, nodes_by_id, err);
+        break;
+        
+    case STRING:
+        return check_string_node (parse_node, format, nodes_by_id, err);
+       break;
+       
+    case RECORD:
+        return check_record_node (parse_node, format, nodes_by_id, err);
+        break;
+
+    default:
+        g_assert_not_reached ();
+        return TRUE; /* quiet gcc */
+    }
+}
+
+static void
+create_read_list (ParseNode *tree, GArray *read_list)
+{
+    ReadItem item;
+    int i;
+
+    switch (tree->format->type)
+    {
+    case RECORD:
+        item.action = BEGIN_RECORD;
+        g_array_append_val (read_list, item);
+
+        for (i = 0; i < tree->children->len; ++i)
+            create_read_list (tree, read_list);
+
+        item.action = END;
+        g_array_append_val (read_list, item);
+        break;
+        
+    case LIST:
+        item.action = BEGIN_LIST;
+        g_array_append_val (read_list, item);
+        
+        for (i = 0; i < tree->children->len; ++i)
+            create_read_list (tree, read_list);
+
+        item.action = END;
+        g_array_append_val (read_list, item);
+        break;
+
+    case POINTER:
+        item.action = READ_POINTER;
+        get_number (tree->text->str, &item.u.read_pointer.id);
+        break;
+
+    case INTEGER:
+        item.action = READ_INTEGER;
+        get_number (tree->text->str, &item.u.read_integer.value);
+        break;
+
+    case STRING:
+        item.action = READ_STRING;
+        /* Copy string without quotation marks */
+        item.u.read_string.value =
+            g_strndup (tree->text->str + 1, strlen (tree->text->str) - 2);
+        break;
+    }
+}
+
+static void
+parse_node_free (ParseNode *node)
+{
+    int i;
+
+    for (i = 0; i < node->children->len; ++i)
+        parse_node_free (node);
+    
+    g_free (node->name);
+    g_ptr_array_free (node->children, TRUE);
+    g_string_free (node->text, TRUE);
+    
+}
+
+SFile *
+sfile_load (const char  *filename,
+           SFormat       *format,
+           GError     **err)
+{
+    gchar *contents;
+    gsize length;
+    ParseNode *tree;
+    GHashTable *nodes_by_id;
+    GArray *read_list;
+    SFile *sfile = g_new0 (SFile, 1);
+    
+    if (!g_file_get_contents (filename, &contents, &length, err))
+       return NULL;
+    
+    nodes_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+    tree = build_tree (contents, nodes_by_id, err);
+    if (!tree)
+    {
+       /* FIXME: free stuff */
+       return NULL;
+    }
+
+    if (!check_structure (tree, format, nodes_by_id, err))
+    {
+       /* FIXME: free stuff */
+       return NULL;
+    }
+
+    read_list = g_array_new (TRUE, TRUE, sizeof (ReadItem));
+    
+    create_read_list (tree, read_list);
+
+    sfile->n_items = read_list->len;
+    sfile->items = (ReadItem *)g_array_free (read_list, FALSE);
+    sfile->current_item = sfile->items;
+    sfile->objects_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
+    sfile->locations_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+    parse_node_free (tree);
+    
+    return sfile;
+}
+
+/* A transisition can start or end in the 'external state'.
+ * This state just represents something outside the machine.
+ * There is one transition *from* the external state, and
+ * one transition *to* the external state.
+ */
+
+#define EXTERNAL_STATE  (-1)
+
+struct Transition
+{
+    int from, to;
+    
+    enum { BEGIN, END, TEXT } type;
+    char *element;
+};
+
+struct StateMachine
+{
+    int n_transitions;
+    Transition *transitions;
+};
+
+static void
+get_machine_info (StateMachine *machine,
+                  Transition **enter,
+                  Transition **exit,
+                  int *n_states)
+{
+    
+}
+
+static void
+make_list_machine (State *external, State *content, )
+{
+    int n_transitions = content->n_transitions;
+    int n_states, new_state;
+    Transition *enter_trans;
+    Transition *exit_trans;
+
+    get_machine_info (content, &n_states, &enter_trans, &exit_trans);
+
+    new_state = n_states;
+    
+    content->transitions = g_renew (Transition, content->transitions, n_transitions + 2);
+
+    content->transitions[n_transitions].from = EXTERNAL_STATE;
+    content->transitions[n_transitions].to = n_states;
+    content->transitions[n_transitions].type = BEGIN;
+    content->transitions[n_transitions].element = g_strdup ("froot");
+
+    content->transitions[n_transitions + 1].to = EXTERNAL_STATE;
+    content->transitions[n_transitions + 1].from = n_states;
+    content->transitions[n_transitions + 1].type = END;
+    content->transitions[n_transitions + 1].element = g_strdup ("froot");
+    
+    enter_trans->from = new_state;
+    exit_trans->to = new_state;
+}
+
+static void
+chain_machines (GList *machines, int *enter_state, int *exit_state)
+{
+}
+
+static void
+make_record_machine (GQueue *fields)
+{
+    Transition *enter_trans;
+    int from = EXTERNAL_STATE;
+    GQueue *state_chain = g_queue_new ();
+
+    g_queue_push_tail (state_chain, EXTERNAL_STATEA);
+
+    for (list = fields->head; list; list = list->next)
+    {
+        StateMachine *machine = list->data;
+        Transition *enter_trans;
+        Transition *exit_trans;
+
+        get_machine_info (machine, NULL, &enter_trans, &exit_trans);
+        enter_trans->from = from;
+
+        if (list->next)
+            get_machine_info (list->next->data, NULL, NULL, next_enterenter_trans->to = to;
+    }
+}
diff --git a/sfile.h b/sfile.h
new file mode 100644 (file)
index 0000000..9f2fd58
--- /dev/null
+++ b/sfile.h
@@ -0,0 +1,58 @@
+typedef struct SFormat SFormat;
+typedef struct SFile SFile;
+
+/* - Describing Types - */
+
+SFormat *  sdesc_new_record       (const char  *name,
+                                  SFormat     *content,
+                                  ...);
+SFormat *  sdesc_new_list         (const char  *name,
+                                SFormat       *content);
+SFormat *  sdesc_new_pointer      (const char  *name);
+SFormat *  sdesc_new_integer      (const char  *name);
+SFormat *  sdesc_new_string       (const char  *name);
+
+/* - Reading - */
+SFile *  sfile_load             (const char  *filename,
+                                SFormat       *format,
+                                GError     **err);
+void     sfile_begin_get_record (SFile       *file);
+int      sfile_begin_get_list   (SFile       *file);
+void     sfile_get_pointer      (SFile       *file,
+                                gpointer    *pointer);
+void     sfile_get_integer      (SFile       *file,
+                                int         *integer);
+void     sfile_get_string       (SFile       *file,
+                                char       **string);
+void     sfile_end_get          (SFile       *file,
+                                gpointer     object);
+
+#if 0
+/* incremental loading (worth considering at least) */
+SFileLoader *sfile_loader_new      (SFormat        *format);
+void         sfile_loader_add_text (SFileLoader  *loader,
+                                   const char   *text,
+                                   int           len);
+SFile *      sfile_loader_finish   (SFileLoader  *loader,
+                                   GError      **err);
+void         sfile_loader_free     (SFileLoader  *loader);
+#endif
+
+/* - Writing - */
+SFile *  sfile_new              (SFormat       *format);
+void     sfile_begin_add_record (SFile       *file,
+                                gpointer     id);
+void     sfile_begin_add_list   (SFile       *file,
+                                gpointer     id);
+void     sfile_end_add          (SFile       *file);
+void     sfile_add_string       (SFile       *file,
+                                const char  *string);
+void     sfile_add_integer      (SFile       *file,
+                                int          integer);
+void     sfile_add_pointer      (SFile       *file,
+                                gpointer     pointer);
+gboolean sfile_save             (SFile       *sfile,
+                                const char  *filename,
+                                GError     **err);
+
+
index 06be3e4..2a8c98e 100644 (file)
--- a/sysprof.c
+++ b/sysprof.c
@@ -395,12 +395,6 @@ sorry (GtkWidget *parent_window,
 }
 
 static void
-on_open_clicked (gpointer widget, gpointer data)
-{
-    sorry (NULL, "Open is not implemented yet. (Fortunately, neither is saving),");
-}
-
-static void
 on_reset_clicked (gpointer widget, gpointer data)
 {
     Application *app = data;
@@ -420,7 +414,8 @@ on_save_as_clicked (gpointer widget, gpointer data)
 
     ensure_profile (app);
     
-    profile_save (app->profile, NULL, NULL);
+    if (!profile_save (app->profile, NULL))
+       sorry (NULL, "Couldn't save\n");
     
 #if 0
     sorry (NULL, "Saving profiles is not yet implemented.");
@@ -432,6 +427,12 @@ on_save_as_clicked (gpointer widget, gpointer data)
 }
 
 static void
+on_open_clicked (gpointer widget, gpointer data)
+{
+    sorry (NULL, "Open is not implemented yet. (Fortunately, neither is saving),");
+}
+
+static void
 on_delete (GtkWidget *window)
 {
     gtk_main_quit ();
@@ -869,13 +870,11 @@ main (int argc, char **argv)
     if (app->input_fd < 0)
     {
        disaster ("Can't open /proc/sysprof-trace. You need to insert\n"
-                 "the sysprof kernel module. As root type\n"
-                 "\n"
-                 "       insmod sysprof-module.o\n"
-                 "\n"
-                 "or if you are using a 2.6 kernel:\n"
+                 "the sysprof kernel module. Type \n"
                  "\n"
                  "       insmod sysprof-module.ko\n"
+                 "\n"
+                 "as root.\n"
                  "\n");
     }