[gnome-builder/wip/chergert/debugger: 20/46] mi2: more client infrastructure
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/debugger: 20/46] mi2: more client infrastructure
- Date: Sun, 26 Mar 2017 00:07:30 +0000 (UTC)
commit ebcb08dc5fa3fb38bf315694fe6eb4a316548fcc
Author: Christian Hergert <chergert redhat com>
Date: Fri Mar 24 00:04:12 2017 -0700
mi2: more client infrastructure
contrib/mi2/Makefile.am | 12 +++
contrib/mi2/mi2-client.c | 172 ++++++++++++++++++++++++++++++++++++---
contrib/mi2/mi2-client.h | 94 ++++++++++++++--------
contrib/mi2/mi2-enums.c.in | 39 +++++++++
contrib/mi2/mi2-enums.h.in | 24 ++++++
contrib/mi2/mi2-error.h | 1 +
contrib/mi2/mi2-event-message.c | 13 +---
contrib/mi2/mi2-message.c | 34 ++++++++
contrib/mi2/mi2-message.h | 2 +
contrib/mi2/mi2-util.c | 81 ++++++++++---------
contrib/mi2/test-client.c | 45 +++++++++--
11 files changed, 418 insertions(+), 99 deletions(-)
---
diff --git a/contrib/mi2/Makefile.am b/contrib/mi2/Makefile.am
index ea739c5..ab7d112 100644
--- a/contrib/mi2/Makefile.am
+++ b/contrib/mi2/Makefile.am
@@ -1,5 +1,6 @@
CLEANFILES =
DISTCLEANFILES =
+BUILT_SOURCES =
EXTRA_DIST = \
test-stream-1.txt \
@@ -38,6 +39,8 @@ libmi2_glib_la_public_sources = \
libmi2_glib_la_SOURCES = \
$(libmi2_glib_la_public_sources) \
mi2-glib.h \
+ mi2-enums.c \
+ mi2-enums.h \
$(NULL)
libmi2_glib_la_CFLAGS = \
@@ -50,6 +53,15 @@ libmi2_glib_la_CFLAGS = \
libmi2_glib_la_LIBADD = $(MI2_LIBS)
libmi2_glib_la_LDFLAGS = $(OPTIMIZE_LDFLAGS)
+glib_enum_headers = \
+ mi2-error.h \
+ $(NULL)
+
+glib_enum_h = mi2-enums.h
+glib_enum_c = mi2-enums.c
+
+include $(top_srcdir)/build/autotools/Makefile.am.enums
+
if HAVE_INTROSPECTION
-include $(INTROSPECTION_MAKEFILE)
diff --git a/contrib/mi2/mi2-client.c b/contrib/mi2/mi2-client.c
index 8807109..5783920 100644
--- a/contrib/mi2/mi2-client.c
+++ b/contrib/mi2/mi2-client.c
@@ -21,6 +21,7 @@
#include "mi2-client.h"
#include "mi2-command-message.h"
#include "mi2-console-message.h"
+#include "mi2-enums.h"
#include "mi2-error.h"
#include "mi2-event-message.h"
#include "mi2-input-stream.h"
@@ -49,6 +50,7 @@ enum {
BREAKPOINT_REMOVED,
EVENT,
LOG,
+ STOPPED,
N_SIGNALS
};
@@ -94,6 +96,29 @@ mi2_client_set_io_stream (Mi2Client *self,
}
static void
+mi2_client_real_event (Mi2Client *self,
+ Mi2EventMessage *message)
+{
+ const gchar *name;
+
+ g_assert (MI2_IS_CLIENT (self));
+ g_assert (MI2_IS_EVENT_MESSAGE (message));
+
+ name = mi2_event_message_get_name (message);
+
+ if (g_strcmp0 (name, "stopped") == 0)
+ {
+ const gchar *reasonstr;
+ Mi2StopReason reason;
+
+ reasonstr = mi2_message_get_param_string (MI2_MESSAGE (message), "reason");
+ reason = mi2_stop_reason_parse (reasonstr);
+
+ g_signal_emit (self, signals [STOPPED], 0, reason, message);
+ }
+}
+
+static void
mi2_client_finalize (GObject *object)
{
Mi2Client *self = (Mi2Client *)object;
@@ -155,6 +180,8 @@ mi2_client_class_init (Mi2ClientClass *klass)
object_class->get_property = mi2_client_get_property;
object_class->set_property = mi2_client_set_property;
+ klass->event = mi2_client_real_event;
+
properties [PROP_IO_STREAM] =
g_param_spec_object ("io-stream",
"IO Stream",
@@ -195,6 +222,14 @@ mi2_client_class_init (Mi2ClientClass *klass)
G_STRUCT_OFFSET (Mi2ClientClass, log),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ signals [STOPPED] =
+ g_signal_new ("stopped",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (Mi2ClientClass, stopped),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, MI2_TYPE_STOP_REASON, MI2_TYPE_MESSAGE);
}
static void
@@ -482,7 +517,6 @@ mi2_client_insert_breakpoint_async (Mi2Client *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- g_autoptr(Mi2CommandMessage) command = NULL;
g_autoptr(GTask) task = NULL;
g_autoptr(GString) str = NULL;
const gchar *address;
@@ -521,10 +555,6 @@ mi2_client_insert_breakpoint_async (Mi2Client *self,
if (address)
g_string_append_printf (str, " %s", address);
- command = g_object_new (MI2_TYPE_COMMAND_MESSAGE,
- "command", str,
- NULL);
-
mi2_client_exec_async (self,
str->str,
cancellable,
@@ -588,7 +618,6 @@ mi2_client_remove_breakpoint_async (Mi2Client *self,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
- g_autoptr(Mi2CommandMessage) command = NULL;
g_autofree gchar *str = NULL;
g_return_if_fail (MI2_IS_CLIENT (self));
@@ -600,10 +629,6 @@ mi2_client_remove_breakpoint_async (Mi2Client *self,
str = g_strdup_printf ("-break-delete %d", breakpoint_id);
- command = g_object_new (MI2_TYPE_COMMAND_MESSAGE,
- "command", str,
- NULL);
-
mi2_client_exec_async (self,
str,
cancellable,
@@ -622,6 +647,89 @@ mi2_client_remove_breakpoint_finish (Mi2Client *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
+static void
+mi2_client_exec_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Mi2Client *self = (Mi2Client *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = user_data;
+
+ g_assert (MI2_IS_CLIENT (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!mi2_client_exec_finish (self, result, NULL, &error))
+ g_task_return_error (task, g_steal_pointer (&error));
+ else
+ g_task_return_boolean (task, TRUE);
+}
+
+void
+mi2_client_run_async (Mi2Client *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail (MI2_IS_CLIENT (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, mi2_client_run_async);
+
+ mi2_client_exec_async (self,
+ "-exec-run --start",
+ cancellable,
+ mi2_client_exec_cb,
+ g_steal_pointer (&task));
+}
+
+gboolean
+mi2_client_run_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (MI2_IS_CLIENT (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+void
+mi2_client_continue_async (Mi2Client *self,
+ gboolean reverse,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail (MI2_IS_CLIENT (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, mi2_client_continue_async);
+
+ mi2_client_exec_async (self,
+ reverse ? "-exec-continue --reverse" : "-exec-continue",
+ cancellable,
+ mi2_client_exec_cb,
+ g_steal_pointer (&task));
+}
+
+gboolean
+mi2_client_continue_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (MI2_IS_CLIENT (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
#if 0
void
mi2_client_async (Mi2Client *self,
@@ -629,6 +737,12 @@ mi2_client_async (Mi2Client *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail (MI2_IS_CLIENT (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
}
gboolean
@@ -642,3 +756,41 @@ mi2_client_finish (Mi2Client *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
#endif
+
+GType
+mi2_stop_reason_get_type (void)
+{
+ static GType type_id;
+
+ if (g_once_init_enter (&type_id))
+ {
+ GType _type_id;
+ static const GEnumValue values[] = {
+ { MI2_STOP_UNKNOWN, "MI2_STOP_UNKNOWN", "unknown" },
+ { MI2_STOP_EXITED_NORMALLY, "MI2_STOP_EXITED_NORMALLY", "exited-normally" },
+ { MI2_STOP_BREAKPOINT_HIT, "MI2_STOP_BREAKPOINT_HIT", "breakpoint-hit" },
+ { 0 }
+ };
+
+ _type_id = g_enum_register_static ("Mi2StopReason", values);
+ g_once_init_leave (&type_id, _type_id);
+ }
+
+ return type_id;
+}
+
+Mi2StopReason
+mi2_stop_reason_parse (const gchar *reason)
+{
+ GEnumClass *klass;
+ GEnumValue *value = NULL;
+
+ if (reason)
+ {
+ klass = g_type_class_ref (MI2_TYPE_STOP_REASON);
+ value = g_enum_get_value_by_nick (klass, reason);
+ g_type_class_unref (klass);
+ }
+
+ return value ? value->value : 0;
+}
diff --git a/contrib/mi2/mi2-client.h b/contrib/mi2/mi2-client.h
index 56de564..818b960 100644
--- a/contrib/mi2/mi2-client.h
+++ b/contrib/mi2/mi2-client.h
@@ -28,10 +28,18 @@ G_BEGIN_DECLS
#include "mi2-event-message.h"
#include "mi2-reply-message.h"
-#define MI2_TYPE_CLIENT (mi2_client_get_type())
+#define MI2_TYPE_CLIENT (mi2_client_get_type())
+#define MI2_TYPE_STOP_REASON (mi2_stop_reason_get_type())
G_DECLARE_DERIVABLE_TYPE (Mi2Client, mi2_client, MI2, CLIENT, GObject)
+typedef enum
+{
+ MI2_STOP_UNKNOWN,
+ MI2_STOP_EXITED_NORMALLY,
+ MI2_STOP_BREAKPOINT_HIT,
+} Mi2StopReason;
+
struct _Mi2ClientClass
{
GObjectClass parent_instance;
@@ -40,10 +48,13 @@ struct _Mi2ClientClass
const gchar *log);
void (*event) (Mi2Client *self,
Mi2EventMessage *message);
- void (*breakpoint_inserted) (Mi2Client *client,
- Mi2Breakpoint *breakpoint);
- void (*breakpoint_removed) (Mi2Client *client,
- gint breakpoint_id);
+ void (*breakpoint_inserted) (Mi2Client *client,
+ Mi2Breakpoint *breakpoint);
+ void (*breakpoint_removed) (Mi2Client *client,
+ gint breakpoint_id);
+ void (*stopped) (Mi2Client *self,
+ Mi2StopReason reason,
+ Mi2Message *message);
gpointer _reserved1;
gpointer _reserved2;
@@ -63,34 +74,51 @@ struct _Mi2ClientClass
gpointer _reserved16;
};
-Mi2Client *mi2_client_new (GIOStream *stream);
-void mi2_client_exec_async (Mi2Client *self,
- const gchar *command,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean mi2_client_exec_finish (Mi2Client *self,
- GAsyncResult *result,
- Mi2ReplyMessage **reply,
- GError **error);
-void mi2_client_start_listening (Mi2Client *self);
-void mi2_client_stop_listening (Mi2Client *self);
-void mi2_client_insert_breakpoint_async (Mi2Client *self,
- Mi2Breakpoint *breakpoint,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gint mi2_client_insert_breakpoint_finish (Mi2Client *self,
- GAsyncResult *result,
- GError **error);
-void mi2_client_remove_breakpoint_async (Mi2Client *self,
- gint breakpoint_id,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean mi2_client_remove_breakpoint_finish (Mi2Client *self,
- GAsyncResult *result,
- GError **error);
+GType mi2_stop_reason_get_type (void);
+Mi2StopReason mi2_stop_reason_parse (const gchar *reason);
+Mi2Client *mi2_client_new (GIOStream *stream);
+void mi2_client_exec_async (Mi2Client *self,
+ const gchar *command,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_exec_finish (Mi2Client *self,
+ GAsyncResult *result,
+ Mi2ReplyMessage **reply,
+ GError **error);
+void mi2_client_start_listening (Mi2Client *self);
+void mi2_client_stop_listening (Mi2Client *self);
+void mi2_client_continue_async (Mi2Client *self,
+ gboolean reverse,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_continue_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
+void mi2_client_run_async (Mi2Client *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_run_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
+void mi2_client_insert_breakpoint_async (Mi2Client *self,
+ Mi2Breakpoint *breakpoint,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gint mi2_client_insert_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
+void mi2_client_remove_breakpoint_async (Mi2Client *self,
+ gint breakpoint_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mi2_client_remove_breakpoint_finish (Mi2Client *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/contrib/mi2/mi2-enums.c.in b/contrib/mi2/mi2-enums.c.in
new file mode 100644
index 0000000..72d5d5c
--- /dev/null
+++ b/contrib/mi2/mi2-enums.c.in
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+
+#include "config.h"
+
+#include "mi2-enums.h"
+#include "mi2-error.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+@enum_name@_get_type (void)
+{
+ static GType etype = 0;
+ if (G_UNLIKELY(etype == 0)) {
+ static const G@Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ }
+ return etype;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+
+/*** END file-tail ***/
diff --git a/contrib/mi2/mi2-enums.h.in b/contrib/mi2/mi2-enums.h.in
new file mode 100644
index 0000000..5b7a196
--- /dev/null
+++ b/contrib/mi2/mi2-enums.h.in
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef __MI2_ENUMS_H__
+#define __MI2_ENUMS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void);
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __MI2_ENUMS_H__ */
+/*** END file-tail ***/
diff --git a/contrib/mi2/mi2-error.h b/contrib/mi2/mi2-error.h
index 8975fd2..0bd46dc 100644
--- a/contrib/mi2/mi2-error.h
+++ b/contrib/mi2/mi2-error.h
@@ -29,6 +29,7 @@ typedef enum
{
MI2_ERROR_UNKNOWN_ERROR,
MI2_ERROR_EXEC_PENDING,
+ MI2_ERROR_INVALID_DATA,
} Mi2Error;
GQuark mi2_error_quark (void);
diff --git a/contrib/mi2/mi2-event-message.c b/contrib/mi2/mi2-event-message.c
index e909a4a..079117e 100644
--- a/contrib/mi2/mi2-event-message.c
+++ b/contrib/mi2/mi2-event-message.c
@@ -125,18 +125,7 @@ mi2_event_message_new_from_string (const gchar *line)
if (line && *line)
{
ret->name = mi2_util_parse_word (&line[1], &line);
-
- while (line != NULL && *line != '\0')
- {
- g_autofree gchar *key = NULL;
- g_autofree gchar *value = NULL;
-
- if (!(key = mi2_util_parse_word (line, &line)) ||
- !(value = mi2_util_parse_string (line, &line)))
- break;
-
- mi2_message_set_param_string (MI2_MESSAGE (ret), key, value);
- }
+ mi2_message_parse_params (MI2_MESSAGE (ret), line);
}
return MI2_MESSAGE (ret);
diff --git a/contrib/mi2/mi2-message.c b/contrib/mi2/mi2-message.c
index 4c9c3b2..9fd873d 100644
--- a/contrib/mi2/mi2-message.c
+++ b/contrib/mi2/mi2-message.c
@@ -22,9 +22,11 @@
#include "mi2-command-message.h"
#include "mi2-console-message.h"
+#include "mi2-error.h"
#include "mi2-event-message.h"
#include "mi2-info-message.h"
#include "mi2-reply-message.h"
+#include "mi2-util.h"
typedef struct
{
@@ -78,11 +80,14 @@ mi2_message_parse (const gchar *line,
gsize len,
GError **error)
{
+ const gchar *begin = line;
Mi2Message *ret = NULL;
g_return_val_if_fail (line != NULL, NULL);
g_return_val_if_fail (len > 0, NULL);
+ g_print (">>> %s\n", line);
+
switch (line[0])
{
case '~':
@@ -110,9 +115,38 @@ mi2_message_parse (const gchar *line,
break;
}
+ if (ret == NULL)
+ g_set_error (error,
+ MI2_ERROR,
+ MI2_ERROR_INVALID_DATA,
+ "Failed to parse: %s", begin);
+
return ret;
}
+void
+mi2_message_parse_params (Mi2Message *self,
+ const gchar *line)
+{
+ g_autoptr(GVariant) params = NULL;
+
+ g_return_if_fail (MI2_IS_MESSAGE (self));
+ g_return_if_fail (line != NULL);
+
+ params = mi2_util_parse_record (line, NULL);
+
+ if (params)
+ {
+ GVariantIter iter;
+ const gchar *key;
+ GVariant *value;
+
+ g_variant_iter_init (&iter, params);
+ while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
+ mi2_message_set_param (self, key, value);
+ }
+}
+
/**
* mi2_message_serialize:
* @self: An #Mi2Message
diff --git a/contrib/mi2/mi2-message.h b/contrib/mi2/mi2-message.h
index dece0b7..58ffca0 100644
--- a/contrib/mi2/mi2-message.h
+++ b/contrib/mi2/mi2-message.h
@@ -48,6 +48,8 @@ Mi2Message *mi2_message_parse (const gchar *line,
GError **error);
GBytes *mi2_message_serialize (Mi2Message *self);
const gchar **mi2_message_get_params (Mi2Message *self);
+void mi2_message_parse_params (Mi2Message *self,
+ const gchar *line);
GVariant *mi2_message_get_param (Mi2Message *self,
const gchar *param);
void mi2_message_set_param (Mi2Message *self,
diff --git a/contrib/mi2/mi2-util.c b/contrib/mi2/mi2-util.c
index f5cefc6..299720e 100644
--- a/contrib/mi2/mi2-util.c
+++ b/contrib/mi2/mi2-util.c
@@ -25,9 +25,7 @@ mi2_util_parse_string (const gchar *line,
g_autoptr(GString) str = NULL;
g_return_val_if_fail (line != NULL, NULL);
-
- if (*line != '"')
- goto failure;
+ g_return_val_if_fail (line[0] == '"', NULL);
str = g_string_new (NULL);
@@ -76,6 +74,8 @@ mi2_util_parse_string (const gchar *line,
return g_string_free (g_steal_pointer (&str), FALSE);
failure:
+ g_warning ("Failed to parse string");
+
if (endptr)
*endptr = NULL;
@@ -108,20 +108,20 @@ mi2_util_parse_word (const gchar *line,
}
GVariant *
-mi2_util_parse_record (const gchar *line,
+mi2_util_parse_record (const gchar *line,
const gchar **endptr)
{
GVariantDict dict;
g_return_val_if_fail (line != NULL, NULL);
- g_return_val_if_fail (*line == '{', NULL);
g_variant_dict_init (&dict, NULL);
- /* move past { */
- line++;
+ /* move past { if we aren't starting from inside {} */
+ if (*line == '{')
+ line++;
- while (*line != '}')
+ while (*line && *line != '}')
{
g_autofree gchar *key = NULL;
@@ -168,9 +168,8 @@ mi2_util_parse_record (const gchar *line,
line++;
}
- g_assert (*line == '}');
-
- line++;
+ if (*line == '}')
+ line++;
if (endptr)
*endptr = line;
@@ -178,6 +177,7 @@ mi2_util_parse_record (const gchar *line,
return g_variant_ref_sink (g_variant_dict_end (&dict));
failure:
+ g_warning ("Failed to parse record");
g_variant_dict_clear (&dict);
if (endptr)
*endptr = NULL;
@@ -197,43 +197,49 @@ mi2_util_parse_list (const gchar *line,
line++;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
- g_variant_builder_open (&builder, G_VARIANT_TYPE ("v"));
- while (*line != ']')
+ if (*line != ']')
{
- if (*line == '"')
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("v"));
+
+ while (*line != ']')
{
- g_autofree gchar *value = NULL;
+ if (*line == '"')
+ {
+ g_autofree gchar *value = NULL;
- if (!(value = mi2_util_parse_string (line, &line)))
- goto failure;
+ if (!(value = mi2_util_parse_string (line, &line)))
+ goto failure;
- g_variant_builder_add (&builder, "s", value);
- }
- else if (*line == '{')
- {
- g_autoptr(GVariant) v = NULL;
+ g_variant_builder_add (&builder, "s", value);
+ }
+ else if (*line == '{')
+ {
+ g_autoptr(GVariant) v = NULL;
- if (!(v = mi2_util_parse_record (line, &line)))
- goto failure;
+ if (!(v = mi2_util_parse_record (line, &line)))
+ goto failure;
- g_variant_builder_add_value (&builder, v);
- }
- else if (*line == '[')
- {
- g_autoptr(GVariant) ar = NULL;
+ g_variant_builder_add_value (&builder, v);
+ }
+ else if (*line == '[')
+ {
+ g_autoptr(GVariant) ar = NULL;
- if (!(ar = mi2_util_parse_list (line, &line)))
+ if (!(ar = mi2_util_parse_list (line, &line)))
+ goto failure;
+
+ g_variant_builder_add_value (&builder, ar);
+ }
+ else
goto failure;
- g_variant_builder_add_value (&builder, ar);
- }
- else
- goto failure;
+ if (*line == ',')
+ line++;
+ }
- if (*line == ',')
- line++;
+ g_variant_builder_close (&builder);
}
g_assert (*line == ']');
@@ -243,11 +249,10 @@ mi2_util_parse_list (const gchar *line,
if (endptr)
*endptr = line;
- g_variant_builder_close (&builder);
-
return g_variant_ref_sink (g_variant_builder_end (&builder));
failure:
+ g_warning ("Failed to parse list");
g_variant_builder_clear (&builder);
if (endptr)
*endptr = NULL;
diff --git a/contrib/mi2/test-client.c b/contrib/mi2/test-client.c
index b5408de..8411c2f 100644
--- a/contrib/mi2/test-client.c
+++ b/contrib/mi2/test-client.c
@@ -20,6 +20,7 @@
#include "mi2-error.h"
static GMainLoop *main_loop;
+static gint g_breakpoint_id;
static GIOStream *
create_io_stream_to_gdb (void)
@@ -128,17 +129,48 @@ stack_info_frame_cb (GObject *object,
}
static void
+on_stopped (Mi2Client *client,
+ Mi2StopReason reason,
+ Mi2Message *message,
+ gpointer user_data)
+{
+ g_assert (MI2_IS_CLIENT (client));
+ g_assert (MI2_IS_MESSAGE (message));
+
+
+ if (reason == MI2_STOP_BREAKPOINT_HIT)
+ mi2_client_continue_async (client, FALSE, NULL, NULL, NULL);
+ else
+ mi2_client_remove_breakpoint_async (client,
+ g_breakpoint_id,
+ NULL,
+ remove_breakpoint_cb,
+ NULL);
+}
+
+static void
+run_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Mi2Client *client = (Mi2Client *)object;
+ g_autoptr(GError) error = NULL;
+ gboolean r;
+
+ r = mi2_client_run_finish (client, result, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (r, ==, TRUE);
+}
+
+static void
on_breakpoint_inserted (Mi2Client *client,
Mi2Breakpoint *breakpoint,
gpointer user_data)
{
- g_print ("breakpoint added: %d\n", mi2_breakpoint_get_id (breakpoint));
+ g_breakpoint_id = mi2_breakpoint_get_id (breakpoint);
+ g_print ("breakpoint added: %d\n", g_breakpoint_id);
- mi2_client_remove_breakpoint_async (client,
- mi2_breakpoint_get_id (breakpoint),
- NULL,
- remove_breakpoint_cb,
- NULL);
+ mi2_client_run_async (client, NULL, run_cb, NULL);
}
static void
@@ -165,6 +197,7 @@ main (gint argc,
g_signal_connect (client, "log", G_CALLBACK (log_handler), NULL);
g_signal_connect (client, "event::thread-group-added", G_CALLBACK (thread_group_added), NULL);
g_signal_connect (client, "event", G_CALLBACK (event), NULL);
+ g_signal_connect (client, "stopped", G_CALLBACK (on_stopped), NULL);
g_signal_connect (client, "breakpoint-inserted", G_CALLBACK (on_breakpoint_inserted), NULL);
g_signal_connect (client, "breakpoint-removed", G_CALLBACK (on_breakpoint_removed), NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]