mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-09 14:40:54 +00:00
Experiment with a file-format-description format.
Wed Mar 2 23:39:50 2005 Soeren Sandmann <sandmann@redhat.com> * profile.[ch], sfile.[ch]: Experiment with a file-format-description format. * sysprof.c: Add commented out code using /proc/ based timeout.
This commit is contained in:
committed by
Søren Sandmann Pedersen
parent
5dec3764c1
commit
de4b3c076d
@ -1,3 +1,11 @@
|
|||||||
|
Wed Mar 2 23:39:50 2005 Soeren Sandmann <sandmann@redhat.com>
|
||||||
|
|
||||||
|
* profile.[ch], sfile.[ch]: Experiment with a
|
||||||
|
file-format-description format.
|
||||||
|
|
||||||
|
* sysprof.c: Add commented out code using /proc/ based
|
||||||
|
timeout.
|
||||||
|
|
||||||
Fri Jan 21 11:23:54 2005 Søren Sandmann <sandmann@redhat.com>
|
Fri Jan 21 11:23:54 2005 Søren Sandmann <sandmann@redhat.com>
|
||||||
|
|
||||||
* README: Some updates - add note about SMP kernels.
|
* README: Some updates - add note about SMP kernels.
|
||||||
|
|||||||
3
Makefile
3
Makefile
@ -7,7 +7,8 @@ else
|
|||||||
|
|
||||||
CFLAGS := $(shell pkg-config --cflags gtk+-2.0 libglade-2.0) -Wall -g
|
CFLAGS := $(shell pkg-config --cflags gtk+-2.0 libglade-2.0) -Wall -g
|
||||||
LIBS := $(shell pkg-config --libs gtk+-2.0 libglade-2.0) -lbfd -liberty
|
LIBS := $(shell pkg-config --libs gtk+-2.0 libglade-2.0) -lbfd -liberty
|
||||||
C_FILES := sysprof.c binfile.c stackstash.c watch.c process.c profile.c treeviewutils.c sfile.c
|
C_FILES := sysprof.c binfile.c stackstash.c watch.c process.c \
|
||||||
|
profile.c treeviewutils.c sfile.c
|
||||||
OBJS := $(addsuffix .o, $(basename $(C_FILES)))
|
OBJS := $(addsuffix .o, $(basename $(C_FILES)))
|
||||||
BINARY := sysprof
|
BINARY := sysprof
|
||||||
MODULE := sysprof-module
|
MODULE := sysprof-module
|
||||||
|
|||||||
@ -200,7 +200,7 @@ process_ensure_map (Process *process, int pid, gulong addr)
|
|||||||
{
|
{
|
||||||
/* Round down to closest page */
|
/* Round down to closest page */
|
||||||
addr = (addr - addr % PAGE_SIZE);
|
addr = (addr - addr % PAGE_SIZE);
|
||||||
|
|
||||||
if (process_has_page (process, addr))
|
if (process_has_page (process, addr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ process_ensure_map (Process *process, int pid, gulong addr)
|
|||||||
process->maps = read_maps (pid);
|
process->maps = read_maps (pid);
|
||||||
|
|
||||||
if (!process_has_page (process, addr))
|
if (!process_has_page (process, addr))
|
||||||
g_list_prepend (process->bad_pages, (gpointer)addr);
|
process->bad_pages = g_list_prepend (process->bad_pages, (gpointer)addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|||||||
397
profile.c
397
profile.c
@ -6,7 +6,7 @@
|
|||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "stackstash.h"
|
#include "stackstash.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
|
#include "sfile.h"
|
||||||
|
|
||||||
typedef struct Node Node;
|
typedef struct Node Node;
|
||||||
|
|
||||||
@ -52,14 +52,118 @@ struct Profile
|
|||||||
GHashTable * nodes_by_object;
|
GHashTable * nodes_by_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SaveContext SaveContext;
|
static SFormat *
|
||||||
struct SaveContext
|
create_format (void)
|
||||||
{
|
{
|
||||||
GString *str;
|
#if 0
|
||||||
GHashTable *id_by_pointer;
|
SType object_type = 0;
|
||||||
GHashTable *pointer_by_id;
|
SType node_type = 0;
|
||||||
int last_id;
|
|
||||||
};
|
return sformat_new (
|
||||||
|
sformat_new_record (
|
||||||
|
"profile",
|
||||||
|
sformat_new_integer ("size", NULL),
|
||||||
|
sformat_new_list (
|
||||||
|
"objects", NULL,
|
||||||
|
sformat_new_record (
|
||||||
|
"object", &object_type,
|
||||||
|
sformat_new_string ("name", NULL),
|
||||||
|
sformat_new_integer ("total", NULL),
|
||||||
|
sformat_new_integer ("self", NULL),
|
||||||
|
NULL)),
|
||||||
|
sformat_new_list (
|
||||||
|
"nodes", NULL,
|
||||||
|
sformat_new_record (
|
||||||
|
"node", &node_type,
|
||||||
|
sformat_new_pointer ("object", &object_type),
|
||||||
|
sformat_new_pointer ("siblings", &node_type),
|
||||||
|
sformat_new_pointer ("children", &node_type),
|
||||||
|
sformat_new_pointer ("parent", &node_type),
|
||||||
|
sformat_new_pointer ("next", &node_type),
|
||||||
|
NULL)),
|
||||||
|
NULL));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_object (gpointer key, gpointer value, gpointer data)
|
||||||
|
{
|
||||||
|
SFileOutput *output = data;
|
||||||
|
ProfileObject *object = key;
|
||||||
|
|
||||||
|
sfile_begin_add_record (output, "object");
|
||||||
|
|
||||||
|
sfile_add_string (output, "name", object->name);
|
||||||
|
sfile_add_integer (output, "total", object->total);
|
||||||
|
sfile_add_integer (output, "self", object->self);
|
||||||
|
|
||||||
|
sfile_end_add (output, "object", object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
serialize_call_tree (Node *node, SFileOutput *output)
|
||||||
|
{
|
||||||
|
sfile_begin_add_record (output, "node");
|
||||||
|
sfile_add_pointer (output, "object", node->object);
|
||||||
|
sfile_add_pointer (output, "siblings", node->siblings);
|
||||||
|
sfile_add_pointer (output, "children", node->children);
|
||||||
|
sfile_add_pointer (output, "parent", node->parent);
|
||||||
|
sfile_add_pointer (output, "next", node->next);
|
||||||
|
sfile_end_add (output, "node", node);
|
||||||
|
|
||||||
|
serialize_call_tree (node->siblings, output);
|
||||||
|
serialize_call_tree (node->children, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
profile_save (Profile *profile,
|
||||||
|
const char *file_name,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
SFormat *format = create_format ();
|
||||||
|
#if 0
|
||||||
|
SFileOutput *output = sfile_output_new (format);
|
||||||
|
sfile_begin_add_record (output, "profile");
|
||||||
|
|
||||||
|
sfile_add_integer (output, "size", profile->size);
|
||||||
|
|
||||||
|
sfile_begin_add_list (output, "objects");
|
||||||
|
g_hash_table_foreach (profile->nodes_by_object, add_object, output);
|
||||||
|
sfile_end_add (output, "objects", NULL);
|
||||||
|
|
||||||
|
sfile_begin_add_list (output, "nodes");
|
||||||
|
serialize_call_tree (profile->call_tree, output);
|
||||||
|
sfile_end_add (output, "nodes", NULL);
|
||||||
|
|
||||||
|
sfile_end_add (output, "profile", NULL);
|
||||||
|
|
||||||
|
result = sfile_output_save (output, file_name, err);
|
||||||
|
|
||||||
|
sformat_free (format);
|
||||||
|
sfile_output_free (output);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile *
|
||||||
|
profile_load (const char *filename, GError **err)
|
||||||
|
{
|
||||||
|
SFormat *format = create_format ();
|
||||||
|
SFileInput *input;
|
||||||
|
|
||||||
|
input = sfile_load (filename, format, err);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
sformat_free (format);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static ProfileObject *
|
static ProfileObject *
|
||||||
profile_object_new (void)
|
profile_object_new (void)
|
||||||
@ -71,283 +175,6 @@ profile_object_new (void)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
insert (SaveContext *context, int id, gpointer pointer)
|
|
||||||
{
|
|
||||||
g_hash_table_insert (context->id_by_pointer, pointer, GINT_TO_POINTER (id));
|
|
||||||
g_hash_table_insert (context->pointer_by_id, GINT_TO_POINTER (id), pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_id (SaveContext *context, gpointer pointer)
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
|
|
||||||
if (!pointer)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
id = GPOINTER_TO_INT (g_hash_table_lookup (context->id_by_pointer, pointer));
|
|
||||||
|
|
||||||
if (!id)
|
|
||||||
{
|
|
||||||
id = ++context->last_id;
|
|
||||||
insert (context, id, pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
serialize_object (gpointer key, gpointer value, gpointer data)
|
|
||||||
{
|
|
||||||
SaveContext *context = data;
|
|
||||||
ProfileObject *object = key;
|
|
||||||
|
|
||||||
g_string_append_printf (context->str, " <object id=\"%d\" name=\"%s\" total=\"%d\" self=\"%d\"/>\n",
|
|
||||||
get_id (context, object),
|
|
||||||
object->name,
|
|
||||||
object->total,
|
|
||||||
object->self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
serialize_call_tree (Node *node, SaveContext *context)
|
|
||||||
{
|
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
|
|
||||||
g_string_append_printf (context->str,
|
|
||||||
" <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),
|
|
||||||
get_id (context, node->children),
|
|
||||||
get_id (context, node->parent),
|
|
||||||
get_id (context, node->next),
|
|
||||||
node->total,
|
|
||||||
node->self,
|
|
||||||
node->toplevel);
|
|
||||||
|
|
||||||
serialize_call_tree (node->siblings, context);
|
|
||||||
serialize_call_tree (node->children, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
profile_save (Profile *profile,
|
|
||||||
const char *file_name)
|
|
||||||
{
|
|
||||||
SaveContext context;
|
|
||||||
|
|
||||||
context.str = g_string_new ("");
|
|
||||||
context.id_by_pointer = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
||||||
context.pointer_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
||||||
context.last_id = 0;
|
|
||||||
|
|
||||||
g_string_append_printf (context.str, "<profile>\n <objects>\n");
|
|
||||||
|
|
||||||
g_hash_table_foreach (profile->nodes_by_object, serialize_object, &context);
|
|
||||||
|
|
||||||
g_string_append_printf (context.str, " </objects>\n <nodes>\n");
|
|
||||||
|
|
||||||
serialize_call_tree (profile->call_tree, &context);
|
|
||||||
|
|
||||||
g_string_append_printf (context.str, " </nodes>\n</profile>\n");
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct LoadContext LoadContext;
|
|
||||||
struct LoadContext
|
|
||||||
{
|
|
||||||
GHashTable *objects_by_id;
|
|
||||||
GHashTable *nodes_by_id;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_number (const char *input_name,
|
|
||||||
const char *target_name,
|
|
||||||
const char *value)
|
|
||||||
{
|
|
||||||
if (strcmp (input_name, target_name) == 0)
|
|
||||||
{
|
|
||||||
char *end;
|
|
||||||
int r = strtol (value, &end, 10);
|
|
||||||
if (*end == '\0')
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static Node *
|
|
||||||
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 ();
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
if (strcmp (name, "id") == 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (strcmp (name, "sibling") == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ProfileObject *
|
|
||||||
create_object (const char **attribute_names, const char **attribute_values, int *id, GError **err)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (attribute_names[i])
|
|
||||||
{
|
|
||||||
const char *name = attribute_names[i];
|
|
||||||
const char *value = attribute_values[i];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
parse_start_element (GMarkupParseContext *context,
|
|
||||||
const char *element_name,
|
|
||||||
const char **attribute_names,
|
|
||||||
const char **attribute_values,
|
|
||||||
gpointer user_data,
|
|
||||||
GError **err)
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
LoadContext *lc = user_data;
|
|
||||||
|
|
||||||
if (strcmp (element_name, "object") == 0)
|
|
||||||
{
|
|
||||||
ProfileObject *object = create_object (attribute_names, attribute_values, &id, err);
|
|
||||||
|
|
||||||
if (object)
|
|
||||||
g_hash_table_insert (lc->objects_by_id, GINT_TO_POINTER (id), object);
|
|
||||||
}
|
|
||||||
else if (strcmp (element_name, "node") == 0)
|
|
||||||
{
|
|
||||||
Node *node = create_node (attribute_names, attribute_values, &id, err);
|
|
||||||
|
|
||||||
if (node)
|
|
||||||
g_hash_table_insert (lc->nodes_by_id, GINT_TO_POINTER (id), node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* ignore anything but object and node */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
parse_end_element (GMarkupParseContext *context,
|
|
||||||
const char *element_name,
|
|
||||||
gpointer user_data,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
parse_error (GMarkupParseContext *context,
|
|
||||||
GError **error,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Profile *
|
|
||||||
profile_load (const char *filename,
|
|
||||||
GError **err)
|
|
||||||
{
|
|
||||||
char *input = NULL;
|
|
||||||
Profile *result = NULL;
|
|
||||||
|
|
||||||
GMarkupParser parser = {
|
|
||||||
parse_start_element, parse_end_element, NULL, NULL, NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
LoadContext load_context;
|
|
||||||
GMarkupParseContext *parse_context;
|
|
||||||
|
|
||||||
if (!g_file_get_contents (filename, &input, NULL, err))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
parse_context = g_markup_parse_context_new (&parser, 0, NULL, NULL);
|
|
||||||
|
|
||||||
if (!g_markup_parse_context_parse (parse_context, input, -1, err))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!g_markup_parse_context_end_parse (parse_context, err))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_markup_parse_context_free (parse_context);
|
|
||||||
|
|
||||||
out:
|
|
||||||
g_free (input);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
profile_object_free (ProfileObject *obj)
|
profile_object_free (ProfileObject *obj)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -70,5 +70,7 @@ void profile_caller_free (ProfileCaller *caller);
|
|||||||
void profile_descendant_free (ProfileDescendant *descendant);
|
void profile_descendant_free (ProfileDescendant *descendant);
|
||||||
|
|
||||||
gboolean profile_save (Profile *profile,
|
gboolean profile_save (Profile *profile,
|
||||||
const char *file_name);
|
const char *file_name,
|
||||||
Profile * profile_load (const char *filename);
|
GError **err);
|
||||||
|
Profile * profile_load (const char *filename,
|
||||||
|
GError **err);
|
||||||
|
|||||||
385
sfile.c
385
sfile.c
@ -152,6 +152,12 @@ sformat_new (gpointer f)
|
|||||||
return sformat;
|
return sformat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sformat_destroy (SFormat *format)
|
||||||
|
{
|
||||||
|
/* FIXME */
|
||||||
|
}
|
||||||
|
|
||||||
static GQueue *
|
static GQueue *
|
||||||
fragment_queue (va_list args)
|
fragment_queue (va_list args)
|
||||||
{
|
{
|
||||||
@ -437,9 +443,9 @@ state_transition_text (const State *state, TransitionType *type, GError **err)
|
|||||||
|
|
||||||
/* reading */
|
/* reading */
|
||||||
typedef struct BuildContext BuildContext;
|
typedef struct BuildContext BuildContext;
|
||||||
typedef struct ReadItem ReadItem;
|
typedef struct Instruction Instruction;
|
||||||
|
|
||||||
struct ReadItem
|
struct Instruction
|
||||||
{
|
{
|
||||||
TransitionType type;
|
TransitionType type;
|
||||||
|
|
||||||
@ -448,21 +454,23 @@ struct ReadItem
|
|||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int n_items;
|
int n_instructions;
|
||||||
int id;
|
int id;
|
||||||
ReadItem *end_item;
|
Instruction *end_instruction;
|
||||||
} begin;
|
} begin;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
Instruction *begin_instruction;
|
||||||
gpointer object;
|
gpointer object;
|
||||||
} end;
|
} end;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int target_id;
|
int target_id;
|
||||||
ReadItem *target_item;
|
Instruction *target_instruction;
|
||||||
gpointer *location;
|
gpointer *location;
|
||||||
|
gpointer object;
|
||||||
} pointer;
|
} pointer;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -481,7 +489,7 @@ struct BuildContext
|
|||||||
{
|
{
|
||||||
const State *state;
|
const State *state;
|
||||||
|
|
||||||
GArray *items;
|
GArray *instructions;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -506,32 +514,32 @@ get_number (const char *text, int *number)
|
|||||||
|
|
||||||
struct SFileInput
|
struct SFileInput
|
||||||
{
|
{
|
||||||
int n_items;
|
int n_instructions;
|
||||||
ReadItem *items;
|
Instruction *instructions;
|
||||||
ReadItem *current_item;
|
Instruction *current_instruction;
|
||||||
GHashTable *items_by_location;
|
GHashTable *instructions_by_location;
|
||||||
GHashTable *objects_by_id;
|
GHashTable *objects_by_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
sfile_begin_get_record (SFileInput *file, const char *name)
|
sfile_begin_get_record (SFileInput *file, const char *name)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
|
|
||||||
g_return_if_fail (item->type == BEGIN_RECORD &&
|
g_return_if_fail (instruction->type == BEGIN_RECORD &&
|
||||||
strcmp (item->name, name) == 0);
|
strcmp (instruction->name, name) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sfile_begin_get_list (SFileInput *file,
|
sfile_begin_get_list (SFileInput *file,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
|
|
||||||
g_return_val_if_fail (item->type == BEGIN_LIST &&
|
g_return_val_if_fail (instruction->type == BEGIN_LIST &&
|
||||||
strcmp (item->name, name) == 0, 0);
|
strcmp (instruction->name, name) == 0, 0);
|
||||||
|
|
||||||
return item->u.begin.n_items;
|
return instruction->u.begin.n_instructions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -539,20 +547,20 @@ sfile_get_pointer (SFileInput *file,
|
|||||||
const char *name,
|
const char *name,
|
||||||
gpointer *location)
|
gpointer *location)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
g_return_if_fail (item->type == POINTER &&
|
g_return_if_fail (instruction->type == POINTER &&
|
||||||
strcmp (item->name, name) == 0);
|
strcmp (instruction->name, name) == 0);
|
||||||
|
|
||||||
item->u.pointer.location = location;
|
instruction->u.pointer.location = location;
|
||||||
|
|
||||||
*location = (gpointer) 0xFedeAbe;
|
*location = (gpointer) 0xFedeAbe;
|
||||||
|
|
||||||
if (location)
|
if (location)
|
||||||
{
|
{
|
||||||
if (g_hash_table_lookup (file->items_by_location, location))
|
if (g_hash_table_lookup (file->instructions_by_location, location))
|
||||||
g_warning ("Reading into the same location twice\n");
|
g_warning ("Reading into the same location twice\n");
|
||||||
|
|
||||||
g_hash_table_insert (file->items_by_location, location, item);
|
g_hash_table_insert (file->instructions_by_location, location, instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,12 +569,12 @@ sfile_get_integer (SFileInput *file,
|
|||||||
const char *name,
|
const char *name,
|
||||||
int *integer)
|
int *integer)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
g_return_if_fail (item->type == INTEGER &&
|
g_return_if_fail (instruction->type == INTEGER &&
|
||||||
strcmp (item->name, name) == 0);
|
strcmp (instruction->name, name) == 0);
|
||||||
|
|
||||||
if (integer)
|
if (integer)
|
||||||
*integer = item->u.integer.value;
|
*integer = instruction->u.integer.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -574,12 +582,12 @@ sfile_get_string (SFileInput *file,
|
|||||||
const char *name,
|
const char *name,
|
||||||
char **string)
|
char **string)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
g_return_if_fail (item->type == STRING &&
|
g_return_if_fail (instruction->type == STRING &&
|
||||||
strcmp (item->name, name) == 0);
|
strcmp (instruction->name, name) == 0);
|
||||||
|
|
||||||
if (string)
|
if (string)
|
||||||
*string = g_strdup (item->u.string.value);
|
*string = g_strdup (instruction->u.string.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -587,16 +595,16 @@ hook_up_pointers (SFileInput *file)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < file->n_items; ++i)
|
for (i = 0; i < file->n_instructions; ++i)
|
||||||
{
|
{
|
||||||
ReadItem *item = &(file->items[i]);
|
Instruction *instruction = &(file->instructions[i]);
|
||||||
|
|
||||||
if (item->type == POINTER)
|
if (instruction->type == POINTER)
|
||||||
{
|
{
|
||||||
gpointer target_object =
|
gpointer target_object =
|
||||||
item->u.pointer.target_item->u.begin.end_item->u.end.object;
|
instruction->u.pointer.target_instruction->u.begin.end_instruction->u.end.object;
|
||||||
|
|
||||||
*(item->u.pointer.location) = target_object;
|
*(instruction->u.pointer.location) = target_object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -606,15 +614,15 @@ sfile_end_get (SFileInput *file,
|
|||||||
const char *name,
|
const char *name,
|
||||||
gpointer object)
|
gpointer object)
|
||||||
{
|
{
|
||||||
ReadItem *item = file->current_item++;
|
Instruction *instruction = file->current_instruction++;
|
||||||
|
|
||||||
g_return_if_fail ((item->type == END_LIST ||
|
g_return_if_fail ((instruction->type == END_LIST ||
|
||||||
item->type == END_RECORD) &&
|
instruction->type == END_RECORD) &&
|
||||||
strcmp (item->name, name) == 0);
|
strcmp (instruction->name, name) == 0);
|
||||||
|
|
||||||
item->u.end.object = object;
|
instruction->u.end.object = object;
|
||||||
|
|
||||||
if (file->current_item == file->items + file->n_items)
|
if (file->current_instruction == file->instructions + file->n_instructions)
|
||||||
hook_up_pointers (file);
|
hook_up_pointers (file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,17 +670,17 @@ handle_begin_element (GMarkupParseContext *parse_context,
|
|||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
BuildContext *build = user_data;
|
BuildContext *build = user_data;
|
||||||
ReadItem item;
|
Instruction instruction;
|
||||||
|
|
||||||
item.u.begin.id = get_id (attribute_names, attribute_values, err);
|
instruction.u.begin.id = get_id (attribute_names, attribute_values, err);
|
||||||
|
|
||||||
if (item.u.begin.id == -1)
|
if (instruction.u.begin.id == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
build->state = state_transition_begin (build->state, element_name, &item.type, err);
|
build->state = state_transition_begin (build->state, element_name, &instruction.type, err);
|
||||||
item.name = g_strdup (element_name);
|
instruction.name = g_strdup (element_name);
|
||||||
|
|
||||||
g_array_append_val (build->items, item);
|
g_array_append_val (build->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -682,13 +690,13 @@ handle_end_element (GMarkupParseContext *context,
|
|||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
BuildContext *build = user_data;
|
BuildContext *build = user_data;
|
||||||
ReadItem item;
|
Instruction instruction;
|
||||||
|
|
||||||
build->state = state_transition_end (build->state, element_name, &item.type, err);
|
build->state = state_transition_end (build->state, element_name, &instruction.type, err);
|
||||||
|
|
||||||
item.name = g_strdup (element_name);
|
instruction.name = g_strdup (element_name);
|
||||||
|
|
||||||
g_array_append_val (build->items, item);
|
g_array_append_val (build->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -716,16 +724,16 @@ handle_text (GMarkupParseContext *context,
|
|||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
BuildContext *build = user_data;
|
BuildContext *build = user_data;
|
||||||
ReadItem item;
|
Instruction instruction;
|
||||||
|
|
||||||
build->state = state_transition_text (build->state, &item.type, err);
|
build->state = state_transition_text (build->state, &instruction.type, err);
|
||||||
|
|
||||||
item.name = NULL;
|
instruction.name = NULL;
|
||||||
|
|
||||||
switch (item.type)
|
switch (instruction.type)
|
||||||
{
|
{
|
||||||
case POINTER:
|
case POINTER:
|
||||||
if (!get_number (text, &item.u.pointer.target_id))
|
if (!get_number (text, &instruction.u.pointer.target_id))
|
||||||
{
|
{
|
||||||
set_invalid_content_error (err, "Contents '%s' of pointer element is not a number", text);
|
set_invalid_content_error (err, "Contents '%s' of pointer element is not a number", text);
|
||||||
return;
|
return;
|
||||||
@ -733,7 +741,7 @@ handle_text (GMarkupParseContext *context,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
if (!get_number (text, &item.u.integer.value))
|
if (!get_number (text, &instruction.u.integer.value))
|
||||||
{
|
{
|
||||||
set_invalid_content_error (err, "Contents '%s' of integer element not a number", text);
|
set_invalid_content_error (err, "Contents '%s' of integer element not a number", text);
|
||||||
return;
|
return;
|
||||||
@ -741,7 +749,7 @@ handle_text (GMarkupParseContext *context,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case STRING:
|
case STRING:
|
||||||
if (!decode_text (text, &item.u.string.value))
|
if (!decode_text (text, &instruction.u.string.value))
|
||||||
{
|
{
|
||||||
set_invalid_content_error (err, "Contents '%s' of text element is illformed", text);
|
set_invalid_content_error (err, "Contents '%s' of text element is illformed", text);
|
||||||
return;
|
return;
|
||||||
@ -753,117 +761,119 @@ handle_text (GMarkupParseContext *context,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_array_append_val (build->items, item);
|
g_array_append_val (build->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_items (ReadItem *items, int n_items)
|
free_instructions (Instruction *instructions, int n_instructions)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < n_items; ++i)
|
for (i = 0; i < n_instructions; ++i)
|
||||||
{
|
{
|
||||||
ReadItem *item = &(items[i]);
|
Instruction *instruction = &(instructions[i]);
|
||||||
|
|
||||||
if (item->name)
|
if (instruction->name)
|
||||||
g_free (item->name);
|
g_free (instruction->name);
|
||||||
|
|
||||||
if (item->type == STRING)
|
if (instruction->type == STRING)
|
||||||
g_free (item->u.string.value);
|
g_free (instruction->u.string.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (items);
|
g_free (instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This functions counts the number of items in each list, and
|
/* This functions counts the number of instructions in each list, and
|
||||||
* matches up pointers with the lists/records they point to.
|
* matches up pointers with the lists/records they point to.
|
||||||
* FIMXE: think of a better name
|
* FIMXE: think of a better name
|
||||||
*/
|
*/
|
||||||
static ReadItem *
|
static Instruction *
|
||||||
post_process_items_recurse (ReadItem *first, GHashTable *items_by_id, GError **err)
|
post_process_instructions_recurse (Instruction *first, GHashTable *instructions_by_id, GError **err)
|
||||||
{
|
{
|
||||||
ReadItem *item;
|
Instruction *instruction;
|
||||||
int n_items;
|
int n_instructions;
|
||||||
|
|
||||||
g_assert (first->type >= FIRST_BEGIN_TRANSITION &&
|
g_assert (first->type >= FIRST_BEGIN_TRANSITION &&
|
||||||
first->type <= LAST_BEGIN_TRANSITION);
|
first->type <= LAST_BEGIN_TRANSITION);
|
||||||
|
|
||||||
item = first + 1;
|
instruction = first + 1;
|
||||||
|
|
||||||
n_items = 0;
|
n_instructions = 0;
|
||||||
while (item->type < FIRST_END_TRANSITION ||
|
while (instruction->type < FIRST_END_TRANSITION ||
|
||||||
item->type > LAST_END_TRANSITION)
|
instruction->type > LAST_END_TRANSITION)
|
||||||
{
|
{
|
||||||
if (item->type >= FIRST_BEGIN_TRANSITION &&
|
if (instruction->type >= FIRST_BEGIN_TRANSITION &&
|
||||||
item->type <= LAST_BEGIN_TRANSITION)
|
instruction->type <= LAST_BEGIN_TRANSITION)
|
||||||
{
|
{
|
||||||
item = post_process_items_recurse (item, items_by_id, err);
|
instruction = post_process_instructions_recurse (instruction, instructions_by_id, err);
|
||||||
if (!item)
|
if (!instruction)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (item->type == POINTER)
|
if (instruction->type == POINTER)
|
||||||
{
|
{
|
||||||
int target_id = item->u.pointer.target_id;
|
int target_id = instruction->u.pointer.target_id;
|
||||||
ReadItem *target = g_hash_table_lookup (items_by_id, GINT_TO_POINTER (target_id));
|
Instruction *target = g_hash_table_lookup (instructions_by_id, GINT_TO_POINTER (target_id));
|
||||||
|
|
||||||
if (!target)
|
if (!target)
|
||||||
{
|
{
|
||||||
set_invalid_content_error (err, "Id %d doesn't reference any record or list\n",
|
set_invalid_content_error (err, "Id %d doesn't reference any record or list\n",
|
||||||
item->u.pointer.target_id);
|
instruction->u.pointer.target_id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->u.pointer.target_item = target;
|
instruction->u.pointer.target_instruction = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
item++;
|
instruction++;
|
||||||
}
|
}
|
||||||
|
|
||||||
n_items++;
|
n_instructions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
first->u.begin.n_items = n_items;
|
first->u.begin.n_instructions = n_instructions;
|
||||||
first->u.begin.end_item = item;
|
first->u.begin.end_instruction = instruction;
|
||||||
|
|
||||||
return item + 1;
|
instruction->u.end.begin_instruction = first;
|
||||||
|
|
||||||
|
return instruction + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
post_process_items (ReadItem *items, int n_items, GError **err)
|
post_process_read_instructions (Instruction *instructions, int n_instructions, GError **err)
|
||||||
{
|
{
|
||||||
gboolean retval = TRUE;
|
gboolean retval = TRUE;
|
||||||
GHashTable *items_by_id;
|
GHashTable *instructions_by_id;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Build id->item map */
|
/* Build id->instruction map */
|
||||||
items_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
|
instructions_by_id = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
for (i = 0; i < n_items; ++i)
|
for (i = 0; i < n_instructions; ++i)
|
||||||
{
|
{
|
||||||
ReadItem *item = &(items[i]);
|
Instruction *instruction = &(instructions[i]);
|
||||||
|
|
||||||
if (item->type >= FIRST_BEGIN_TRANSITION &&
|
if (instruction->type >= FIRST_BEGIN_TRANSITION &&
|
||||||
item->type <= LAST_BEGIN_TRANSITION)
|
instruction->type <= LAST_BEGIN_TRANSITION)
|
||||||
{
|
{
|
||||||
int id = item->u.begin.id;
|
int id = instruction->u.begin.id;
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
g_hash_table_insert (items_by_id, GINT_TO_POINTER (id), item);
|
g_hash_table_insert (instructions_by_id, GINT_TO_POINTER (id), instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count list items, check pointers */
|
/* count list instructions, check pointers */
|
||||||
if (!post_process_items_recurse (items, items_by_id, err))
|
if (!post_process_instructions_recurse (instructions, instructions_by_id, err))
|
||||||
retval = FALSE;
|
retval = FALSE;
|
||||||
|
|
||||||
g_hash_table_destroy (items_by_id);
|
g_hash_table_destroy (instructions_by_id);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReadItem *
|
static Instruction *
|
||||||
build_items (const char *contents, SFormat *format, int *n_items, GError **err)
|
build_instructions (const char *contents, SFormat *format, int *n_instructions, GError **err)
|
||||||
{
|
{
|
||||||
BuildContext build;
|
BuildContext build;
|
||||||
GMarkupParseContext *parse_context;
|
GMarkupParseContext *parse_context;
|
||||||
@ -877,31 +887,31 @@ build_items (const char *contents, SFormat *format, int *n_items, GError **err)
|
|||||||
};
|
};
|
||||||
|
|
||||||
build.state = sformat_get_start_state (format);
|
build.state = sformat_get_start_state (format);
|
||||||
build.items = g_array_new (TRUE, TRUE, sizeof (ReadItem));
|
build.instructions = g_array_new (TRUE, TRUE, sizeof (Instruction));
|
||||||
|
|
||||||
parse_context = g_markup_parse_context_new (&parser, 0, &build, NULL);
|
parse_context = g_markup_parse_context_new (&parser, 0, &build, NULL);
|
||||||
if (!sformat_is_end_state (format, build.state))
|
if (!sformat_is_end_state (format, build.state))
|
||||||
{
|
{
|
||||||
set_invalid_content_error (err, "Unexpected end of file\n");
|
set_invalid_content_error (err, "Unexpected end of file\n");
|
||||||
|
|
||||||
free_items ((ReadItem *)build.items->data, build.items->len);
|
free_instructions ((Instruction *)build.instructions->data, build.instructions->len);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_markup_parse_context_parse (parse_context, contents, -1, err))
|
if (!g_markup_parse_context_parse (parse_context, contents, -1, err))
|
||||||
{
|
{
|
||||||
free_items ((ReadItem *)build.items->data, build.items->len);
|
free_instructions ((Instruction *)build.instructions->data, build.instructions->len);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!post_process_items ((ReadItem *)build.items->data, build.items->len, err))
|
if (!post_process_read_instructions ((Instruction *)build.instructions->data, build.instructions->len, err))
|
||||||
{
|
{
|
||||||
free_items ((ReadItem *)build.items->data, build.items->len);
|
free_instructions ((Instruction *)build.instructions->data, build.instructions->len);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*n_items = build.items->len;
|
*n_instructions = build.instructions->len;
|
||||||
return (ReadItem *)g_array_free (build.items, FALSE);
|
return (Instruction *)g_array_free (build.instructions, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
SFileInput *
|
SFileInput *
|
||||||
@ -918,9 +928,9 @@ sfile_load (const char *filename,
|
|||||||
|
|
||||||
input = g_new (SFileInput, 1);
|
input = g_new (SFileInput, 1);
|
||||||
|
|
||||||
input->items = build_items (contents, format, &input->n_items, err);
|
input->instructions = build_instructions (contents, format, &input->n_instructions, err);
|
||||||
|
|
||||||
if (!input->items)
|
if (!input->instructions)
|
||||||
{
|
{
|
||||||
g_free (input);
|
g_free (input);
|
||||||
g_free (contents);
|
g_free (contents);
|
||||||
@ -933,48 +943,10 @@ sfile_load (const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Writing */
|
/* Writing */
|
||||||
typedef struct WriteItem WriteItem;
|
|
||||||
|
|
||||||
struct WriteItem
|
|
||||||
{
|
|
||||||
TransitionType type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
int id;
|
|
||||||
} begin;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
} end;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
gpointer object;
|
|
||||||
} pointer;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
int value;
|
|
||||||
} integer;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
char *value;
|
|
||||||
} string;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SFileOutput
|
struct SFileOutput
|
||||||
{
|
{
|
||||||
SFormat *format;
|
SFormat *format;
|
||||||
GArray *items;
|
GArray *instructions;
|
||||||
const State *state;
|
const State *state;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -985,7 +957,7 @@ sfile_output_mew (SFormat *format)
|
|||||||
SFileOutput *output = g_new (SFileOutput, 1);
|
SFileOutput *output = g_new (SFileOutput, 1);
|
||||||
|
|
||||||
output->format = format;
|
output->format = format;
|
||||||
output->items = g_array_new (TRUE, TRUE, sizeof (WriteItem));
|
output->instructions = g_array_new (TRUE, TRUE, sizeof (Instruction));
|
||||||
output->state = sformat_get_start_state (format);
|
output->state = sformat_get_start_state (format);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -995,84 +967,104 @@ void
|
|||||||
sfile_begin_add_record (SFileOutput *file,
|
sfile_begin_add_record (SFileOutput *file,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
WriteItem item;
|
Instruction instruction;
|
||||||
|
|
||||||
file->state = state_transition_begin (
|
file->state = state_transition_begin (
|
||||||
file->state, name, &item.type, NULL);
|
file->state, name, &instruction.type, NULL);
|
||||||
|
|
||||||
g_return_if_fail (file->state && item.type == BEGIN_RECORD);
|
g_return_if_fail (file->state && instruction.type == BEGIN_RECORD);
|
||||||
|
|
||||||
item.u.begin.name = g_strdup (name);
|
instruction.name = g_strdup (name);
|
||||||
|
|
||||||
g_array_append_val (file->items, item);
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sfile_begin_add_list (SFileOutput *file,
|
sfile_begin_add_list (SFileOutput *file,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
WriteItem item;
|
Instruction instruction;
|
||||||
TransitionType type;
|
TransitionType type;
|
||||||
|
|
||||||
file->state = state_transition_begin (
|
file->state = state_transition_begin (
|
||||||
file->state, name, &item.type, NULL);
|
file->state, name, &instruction.type, NULL);
|
||||||
|
|
||||||
g_return_if_fail (file->state && type == BEGIN_LIST);
|
g_return_if_fail (file->state && type == BEGIN_LIST);
|
||||||
|
|
||||||
item.u.begin.name = g_strdup (name);
|
instruction.name = g_strdup (name);
|
||||||
|
|
||||||
g_array_append_val (file->items, item);
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sfile_end_add (SFileOutput *file,
|
sfile_end_add (SFileOutput *file,
|
||||||
const char *name,
|
const char *name,
|
||||||
gpointer object)
|
gpointer object)
|
||||||
{
|
{
|
||||||
WriteItem item;
|
Instruction instruction;
|
||||||
|
|
||||||
file->state = state_transition_end (
|
file->state = state_transition_end (
|
||||||
file->state, name, &item.type, NULL);
|
file->state, name, &instruction.type, NULL);
|
||||||
|
|
||||||
g_return_if_fail (file->state &&
|
g_return_if_fail (file->state &&
|
||||||
(item.type == END_RECORD || item.type == END_LIST));
|
(instruction.type == END_RECORD || instruction.type == END_LIST));
|
||||||
|
|
||||||
item.u.end.name = g_strdup (name);
|
instruction.name = g_strdup (name);
|
||||||
|
instruction.u.end.object = object;
|
||||||
|
|
||||||
g_array_append_val (file->items, item);
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TransitionType
|
static void
|
||||||
sfile_add_value (SFileOutput *file,
|
sfile_check_value (SFileOutput *file,
|
||||||
const char *name,
|
const char *name,
|
||||||
TransitionType begin,
|
TransitionType begin,
|
||||||
TransitionType value,
|
TransitionType value,
|
||||||
TransitionType end)
|
TransitionType end)
|
||||||
{
|
{
|
||||||
TransitionType tmp_type;
|
|
||||||
TransitionType type;
|
TransitionType type;
|
||||||
|
|
||||||
file->state = state_transition_begin (file->state, name, &tmp_type, NULL);
|
file->state = state_transition_begin (file->state, name, &type, NULL);
|
||||||
file->state = state_transition_text (file->state, &type, NULL);
|
g_return_if_fail (file->state && type == begin);
|
||||||
file->state = state_transition_end (file->state, name, &tmp_type, NULL);
|
|
||||||
|
|
||||||
return type;
|
file->state = state_transition_text (file->state, &type, NULL);
|
||||||
|
g_return_if_fail (file->state && type == value);
|
||||||
|
|
||||||
|
file->state = state_transition_end (file->state, name, &type, NULL);
|
||||||
|
g_return_if_fail (file->state && type == end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sfile_add_string (SFileOutput *file,
|
sfile_add_string (SFileOutput *file,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *string)
|
const char *string)
|
||||||
{
|
{
|
||||||
sfile_add_value (file, name, BEGIN_STRING, STRING, END_STRING);
|
Instruction instruction;
|
||||||
|
|
||||||
|
g_return_if_fail (g_utf8_validate (string, -1, NULL));
|
||||||
|
|
||||||
|
sfile_check_value (file, name, BEGIN_STRING, STRING, END_STRING);
|
||||||
|
|
||||||
|
instruction.type = STRING;
|
||||||
|
instruction.u.string.value = g_strdup (string);
|
||||||
|
|
||||||
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sfile_add_integer (SFileOutput *file,
|
sfile_add_integer (SFileOutput *file,
|
||||||
const char *name,
|
const char *name,
|
||||||
int integer)
|
int integer)
|
||||||
{
|
{
|
||||||
sfile_add_value (file, name, BEGIN_INTEGER, INTEGER, END_INTEGER);
|
Instruction instruction;
|
||||||
|
|
||||||
|
sfile_check_value (file, name, BEGIN_INTEGER, INTEGER, END_INTEGER);
|
||||||
|
|
||||||
|
instruction.type = INTEGER;
|
||||||
|
instruction.name = g_strdup (name);
|
||||||
|
instruction.u.integer.value = integer;
|
||||||
|
|
||||||
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1080,13 +1072,22 @@ sfile_add_pointer (SFileOutput *file,
|
|||||||
const char *name,
|
const char *name,
|
||||||
gpointer pointer)
|
gpointer pointer)
|
||||||
{
|
{
|
||||||
sfile_add_value (file, name, BEGIN_POINTER, POINTER, END_POINTER);
|
Instruction instruction;
|
||||||
|
|
||||||
|
sfile_check_value (file, name, BEGIN_POINTER, POINTER, END_POINTER);
|
||||||
|
|
||||||
|
instruction.type = POINTER;
|
||||||
|
instruction.name = g_strdup (name);
|
||||||
|
instruction.u.pointer.object = pointer;
|
||||||
|
|
||||||
|
g_array_append_val (file->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
sfile_save (SFileOutput *sfile,
|
sfile_output_save (SFileOutput *sfile,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
|
|
||||||
return FALSE; /* FIXME */
|
return FALSE; /* FIXME */
|
||||||
}
|
}
|
||||||
|
|||||||
7
sfile.h
7
sfile.h
@ -12,6 +12,7 @@ gpointer sformat_new_list (const char *name,
|
|||||||
gpointer sformat_new_pointer (const char *name);
|
gpointer sformat_new_pointer (const char *name);
|
||||||
gpointer sformat_new_integer (const char *name);
|
gpointer sformat_new_integer (const char *name);
|
||||||
gpointer sformat_new_string (const char *name);
|
gpointer sformat_new_string (const char *name);
|
||||||
|
void sformat_free (SFormat *format);
|
||||||
|
|
||||||
/* - Reading - */
|
/* - Reading - */
|
||||||
SFileInput * sfile_load (const char *filename,
|
SFileInput * sfile_load (const char *filename,
|
||||||
@ -51,7 +52,7 @@ void sfile_loader_free (SFileLoader *loader);
|
|||||||
* a way to get the name back then, though.
|
* a way to get the name back then, though.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SFileOutput * sfile_output_mew (SFormat *format);
|
SFileOutput * sfile_output_new (SFormat *format);
|
||||||
void sfile_begin_add_record (SFileOutput *file,
|
void sfile_begin_add_record (SFileOutput *file,
|
||||||
const char *name);
|
const char *name);
|
||||||
void sfile_begin_add_list (SFileOutput *file,
|
void sfile_begin_add_list (SFileOutput *file,
|
||||||
@ -68,8 +69,8 @@ void sfile_add_integer (SFileOutput *file,
|
|||||||
void sfile_add_pointer (SFileOutput *file,
|
void sfile_add_pointer (SFileOutput *file,
|
||||||
const char *name,
|
const char *name,
|
||||||
gpointer pointer);
|
gpointer pointer);
|
||||||
gboolean sfile_save (SFileOutput *sfile,
|
gboolean sfile_output_save (SFileOutput *sfile,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
GError **err);
|
GError **err);
|
||||||
|
|
||||||
|
void sfile_output_free (SFileOutput *sfile);
|
||||||
|
|||||||
68
sysprof.c
68
sysprof.c
@ -13,7 +13,7 @@
|
|||||||
#include "stackstash.h"
|
#include "stackstash.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "treeviewutils.h"
|
#include "treeviewutils.h"
|
||||||
|
#include "tracing.h"
|
||||||
|
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
#define _(a) a
|
#define _(a) a
|
||||||
@ -170,6 +170,62 @@ get_name (pid_t pid)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
on_timeout (gpointer data)
|
||||||
|
{
|
||||||
|
Application *app = data;
|
||||||
|
GList *pids, *list;
|
||||||
|
int mypid = getpid();
|
||||||
|
|
||||||
|
pids = list_processes ();
|
||||||
|
|
||||||
|
for (list = pids; list != NULL; list = list->next)
|
||||||
|
{
|
||||||
|
int pid = GPOINTER_TO_INT (list->data);
|
||||||
|
|
||||||
|
if (pid == mypid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (get_process_state (pid) == PROCESS_RUNNING)
|
||||||
|
{
|
||||||
|
Process *process;
|
||||||
|
SysprofStackTrace trace;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!generate_stack_trace (pid, &trace))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
process = process_get_from_pid (pid);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
process_ensure_map (process, trace.pid,
|
||||||
|
(gulong)trace.addresses[i]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_print ("n addr: %d\n", trace.n_addresses);
|
||||||
|
for (i = 0; i < trace.n_addresses; ++i)
|
||||||
|
process_ensure_map (process, trace.pid,
|
||||||
|
(gulong)trace.addresses[i]);
|
||||||
|
g_assert (!app->generating_profile);
|
||||||
|
|
||||||
|
stack_stash_add_trace (
|
||||||
|
app->stash, process,
|
||||||
|
(gulong *)trace.addresses, trace.n_addresses, 1);
|
||||||
|
|
||||||
|
app->n_samples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_sensitivity (app);
|
||||||
|
g_list_free (pids);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_read (gpointer data)
|
on_read (gpointer data)
|
||||||
{
|
{
|
||||||
@ -413,8 +469,9 @@ on_save_as_clicked (gpointer widget, gpointer data)
|
|||||||
Application *app = data;
|
Application *app = data;
|
||||||
|
|
||||||
ensure_profile (app);
|
ensure_profile (app);
|
||||||
|
|
||||||
if (!profile_save (app->profile, NULL))
|
/* FIXME */
|
||||||
|
if (!profile_save (app->profile, "name.profile", NULL))
|
||||||
sorry (NULL, "Couldn't save\n");
|
sorry (NULL, "Couldn't save\n");
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -880,6 +937,11 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
fd_add_watch (app->input_fd, app);
|
fd_add_watch (app->input_fd, app);
|
||||||
fd_set_read_callback (app->input_fd, on_read);
|
fd_set_read_callback (app->input_fd, on_read);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
nice (-19);
|
||||||
|
g_timeout_add (10, on_timeout, app);
|
||||||
|
#endif
|
||||||
|
|
||||||
build_gui (app);
|
build_gui (app);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user