nemiver r954 - in trunk: . src/dbgengine tests



Author: dodji
Date: Sun Nov 30 13:27:49 2008
New Revision: 954
URL: http://svn.gnome.org/viewvc/nemiver?rev=954&view=rev

Log:
Refactor the parser and create GDBMParser as to fix #560662.

	* src/dbgengine/nmv-gdbmi-parser.cc,h (parse_attribute):
	  make sure attributes like foo = ["bar", "baz"] can now be parsed.
	  This is the most generic form of attribute (or GDB/MI Result) that
	  we can have.
	  Added a bunch of function to serialize MI datatypes.
	  (parse_gdbmi_list): allow the presence of space after ',' in MI LISTs.
	  (gdbmi_tuple_to_string): New entry point.
	  (gdbmi_result_to_string): Likewise.
	  (gdbmi_list_to_string): Likewise.
	  (gdbmi_value_to_string): Likewise.
	  (operator<<): Use the new serialisation entry points.
	* tests/test-gdbmi.cc (test_attr0):  Added a new test.
	  (test_gdbmi_result): New test.

Start GDBMIParser as a refactoring of the old parser

First version of the GDBMIParser type.

Debugged GDBMIParser and make GDBEngine switch to it.

Modified:
   trunk/ChangeLog
   trunk/src/dbgengine/nmv-gdb-engine.cc
   trunk/src/dbgengine/nmv-gdbmi-parser.cc
   trunk/src/dbgengine/nmv-gdbmi-parser.h
   trunk/tests/test-gdbmi.cc

Modified: trunk/src/dbgengine/nmv-gdb-engine.cc
==============================================================================
--- trunk/src/dbgengine/nmv-gdb-engine.cc	(original)
+++ trunk/src/dbgengine/nmv-gdb-engine.cc	Sun Nov 30 13:27:49 2008
@@ -102,6 +102,7 @@
     IDebugger::State state;
     ILangTraitSafePtr lang_trait;
     UString debugger_full_path;
+    GDBMIParser gdbmi_parser;
     sigc::signal<void> gdb_died_signal;
     sigc::signal<void, const UString& > master_pty_signal;
     sigc::signal<void, const UString& > gdb_stdout_signal;
@@ -313,8 +314,9 @@
         Output output (a_buf);
 
         UString::size_type from (0), to (0), end (a_buf.size ());
+        gdbmi_parser.push_input (a_buf);
         for (; from < end;) {
-            if (!parse_output_record (a_buf, from, to, output)) {
+            if (!gdbmi_parser.parse_output_record (from, to, output)) {
                 LOG_ERROR ("output record parsing failed: "
                         << a_buf.substr (from, end - from)
                         << "\npart of buf: " << a_buf
@@ -363,6 +365,7 @@
                 }
             }
         }
+        gdbmi_parser.pop_input ();
     }
 
     Priv (DynamicModule *a_dynmod) :
@@ -373,7 +376,8 @@
         is_attached (false),
         line_busy (false),
         error_buffer_status (DEFAULT),
-        state (IDebugger::NOT_STARTED)
+        state (IDebugger::NOT_STARTED),
+        gdbmi_parser (GDBMIParser::BROKEN_MODE)
     {
         gdb_stdout_signal.connect (sigc::mem_fun
                 (*this, &Priv::on_gdb_stdout_signal));
@@ -960,7 +964,9 @@
             }
         }
         LOG_DD ("going to parse overloads: >>>" << input << "<<<");
-        return parse_overloads_choice_prompt (input, cur, cur, a_prompts);
+        GDBMIParser gdbmi_parser (input, GDBMIParser::BROKEN_MODE);
+        gdbmi_parser.push_input (input);
+        return gdbmi_parser.parse_overloads_choice_prompt (cur, cur, a_prompts);
     }
 
     bool has_breakpoints_set (CommandAndOutput &a_in)

Modified: trunk/src/dbgengine/nmv-gdbmi-parser.cc
==============================================================================
--- trunk/src/dbgengine/nmv-gdbmi-parser.cc	(original)
+++ trunk/src/dbgengine/nmv-gdbmi-parser.cc	Sun Nov 30 13:27:49 2008
@@ -39,6 +39,14 @@
              << " cur index was: " << (int)(a_from)); \
 } while (0)
 
+#define LOG_PARSING_ERROR2(a_from) \
+do { \
+Glib::ustring str_01 (m_priv->input, (a_from), m_priv->end - (a_from));\
+LOG_ERROR ("parsing failed for buf: >>>" \
+             << m_priv->input << "<<<" \
+             << " cur index was: " << (int)(a_from)); \
+} while (0)
+
 #define LOG_PARSING_ERROR_MSG(a_buf, a_from, msg) \
 do { \
 Glib::ustring str_01 (a_buf, (a_from), a_buf.size () - (a_from));\
@@ -48,12 +56,27 @@
              << ", reason: " << msg); \
 } while (0)
 
+#define LOG_PARSING_ERROR_MSG2(a_from, msg) \
+do { \
+Glib::ustring str_01 (m_priv->input, (a_from), m_priv->end - (a_from));\
+LOG_ERROR ("parsing failed for buf: >>>" \
+             << m_priv->input << "<<<" \
+             << " cur index was: " << (int)(a_from) \
+             << ", reason: " << msg); \
+} while (0)
+
 #define CHECK_END(a_input, a_current, a_end) \
 if ((a_current) >= (a_end)) {\
 LOG_ERROR ("hit end index " << (int) a_end); \
 return false;\
 }
 
+#define CHECK_END2(a_current) \
+if ((a_current) >= (m_priv->end)) {\
+LOG_ERROR ("hit end index " << (int) m_priv->end); \
+return false;\
+}
+
 #define CHECK_END_BREAK(a_input, a_current, a_end) \
 if ((a_current) >= (a_end)) {\
 LOG_ERROR ("hit end index " << (int) a_end); \
@@ -66,12 +89,28 @@
 } \
 a_to = a_from;
 
+#define SKIP_WS2(a_from) \
+while (!m_priv->index_passed_end (a_from)  && isspace (RAW_CHAR_AT (a_from))) { \
+    CHECK_END2 (a_from);++a_from; \
+}
+
 #define SKIP_BLANK(a_input, a_from, a_to) \
 while (a_from < a_input.bytes () && isblank (a_input.c_str ()[a_from])) { \
     CHECK_END (a_input, a_from, end);++a_from; \
 } \
 a_to = a_from;
 
+#define SKIP_BLANK2(a_from) \
+while (!m_priv->index_passed_end (a_from) && isblank (RAW_CHAR_AT (a_from))) { \
+    CHECK_END2 (a_from); ++a_from; \
+}
+
+#define RAW_CHAR_AT(cur) m_priv->raw_char_at (cur)
+
+#define UCHAR_AT(cur) m_priv->m_priv->input (cur)
+
+#define RAW_INPUT m_priv->input.raw ()
+
 using namespace std;
 using namespace nemiver::common;
 
@@ -121,15 +160,14 @@
     GDBMIResultSafePtr result;
     if (!parse_gdbmi_result (a_input, cur, a_to, result)
         || !result
-        || !result->value ()
-        || result->value ()->content_type () != GDBMIValue::STRING_TYPE) {
+        || result->variable ().empty ()
+        || !result->value ()) {
         LOG_PARSING_ERROR (a_input, cur);
         return false;
     }
 
     a_name = result->variable ();
-    a_value = result->value ()->get_string_content ();
-    return true;
+    return gdbmi_value_to_string (result->value (), a_value);
 }
 
 /// \brief parses an attribute list
@@ -498,6 +536,7 @@
         for (;;) {
             if (a_input.c_str ()[cur] == ',') {
                 ++cur;
+                SKIP_BLANK (a_input, cur, cur);
                 CHECK_END (a_input, cur, end);
                 result.reset ();
                 if (parse_gdbmi_result (a_input, cur, cur, result)) {
@@ -515,6 +554,7 @@
         for (;;) {
             if (a_input.c_str ()[cur] == ',') {
                 ++cur;
+                SKIP_BLANK (a_input, cur, cur);
                 CHECK_END (a_input, cur, end);
                 value.reset ();
                 if (parse_gdbmi_value (a_input, cur, cur, value)) {
@@ -585,6 +625,135 @@
     return true;
 }
 
+bool
+gdbmi_tuple_to_string (GDBMITupleSafePtr a_result,
+                        UString &a_string)
+{
+
+    if (!a_result)
+        return false;
+
+    list<GDBMIResultSafePtr>::const_iterator it = a_result->content ().begin ();
+    UString str;
+    bool is_ok = true;
+    a_string = "{";
+
+    if (it == a_result->content ().end ())
+        goto end;
+
+    is_ok = gdbmi_result_to_string (*it, str);
+    if (!is_ok)
+        goto end;
+    a_string += str;
+    ++it;
+
+    for (; is_ok && it != a_result->content ().end (); ++it) {
+        is_ok = gdbmi_result_to_string (*it, str);
+        if (is_ok)
+            a_string += "," + str;
+    }
+
+end:
+    a_string += "}";
+    return is_ok;
+}
+
+bool
+gdbmi_result_to_string (GDBMIResultSafePtr a_result,
+                        UString &a_string)
+{
+    if (!a_result)
+        return false;
+
+    UString variable, value;
+    variable = a_result->variable ();
+
+    if (!gdbmi_value_to_string (a_result->value (), value))
+        return false;
+
+    a_string = variable + "=" + value;
+    return true;
+}
+
+bool
+gdbmi_list_to_string (GDBMIListSafePtr a_list,
+                      UString &a_string)
+{
+    if (!a_list)
+        return false;
+
+    bool is_ok = true;
+    UString str;
+    a_string = "[";
+    switch (a_list->content_type ()) {
+        case GDBMIList::RESULT_TYPE: {
+            list<GDBMIResultSafePtr> results;
+            a_list->get_result_content (results);
+            list<GDBMIResultSafePtr>::const_iterator result_it = results.begin ();
+            if (result_it == results.end ())
+                break;
+            if (!gdbmi_result_to_string (*result_it, str))
+                break;
+            a_string += str;
+            ++result_it;
+            for (; is_ok && result_it != results.end (); ++result_it) {
+                is_ok = gdbmi_result_to_string (*result_it, str);
+                if (is_ok)
+                    a_string += "," + str;
+            }
+        }
+            break;
+        case GDBMIList::VALUE_TYPE: {
+            list<GDBMIValueSafePtr> values;
+            a_list->get_value_content (values);
+            list<GDBMIValueSafePtr>::const_iterator value_it = values.begin ();
+            if (value_it == values.end ())
+                break;
+            if (!gdbmi_value_to_string (*value_it, str))
+                break;
+            a_string += str;
+            ++value_it;
+            for (; is_ok && value_it != values.end (); ++value_it) {
+                is_ok = gdbmi_value_to_string (*value_it, str);
+                if (is_ok)
+                    a_string += "," + str;
+            }
+        }
+            break;
+        case GDBMIList::UNDEFINED_TYPE:
+            a_string += "<undefined-gdbmi-list-type>";
+            break;
+    }
+    a_string += "]";
+    return is_ok;
+}
+
+bool
+gdbmi_value_to_string (GDBMIValueSafePtr a_value,
+                       UString &a_string)
+{
+    if (!a_value)
+        return false;
+
+    bool result = true;
+    switch (a_value->content_type ()) {
+        case GDBMIValue::EMPTY_TYPE:
+            a_string = "";
+            break;
+        case GDBMIValue::STRING_TYPE:
+            a_string = a_value->get_string_content ();
+            result = true;
+            break;
+        case GDBMIValue::LIST_TYPE:
+            result = gdbmi_list_to_string (a_value->get_list_content (), a_string);
+            break;
+        case GDBMIValue::TUPLE_TYPE:
+            result = gdbmi_tuple_to_string (a_value->get_tuple_content (), a_string);
+            break;
+    }
+    return result;
+}
+
 /// \brief parse a GDB/MI value.
 /// GDB/MI value type is defined as:
 /// VALUE ==> CONST | TUPLE | LIST
@@ -651,13 +820,12 @@
 operator<< (ostream &a_out, const GDBMIResultSafePtr &a_result)
 {
     if (!a_result) {
-        a_out << "<result nilpointer/>";
-        return a_out;
+        a_out << "";
+    } else {
+        UString str;
+        gdbmi_result_to_string (a_result, str);
+        a_out << str;
     }
-    a_out << "<result variable='";
-    a_out << Glib::locale_from_utf8 (a_result->variable ()) << "'>";
-    a_out << a_result->value ();
-    a_out << "</result>";
     return a_out;
 }
 
@@ -667,13 +835,11 @@
     if (!a_tuple) {
         a_out << "<tuple nilpointer/>";
         return a_out;
+    } else {
+        UString str;
+        gdbmi_tuple_to_string (a_tuple, str);
+        a_out << str;
     }
-    list<GDBMIResultSafePtr>::const_iterator iter;
-    a_out << "<tuple>" ;
-    for (iter=a_tuple->content ().begin (); iter!=a_tuple->content ().end(); ++iter) {
-        a_out  << *iter;
-    }
-    a_out  << "</tuple>";
     return a_out;
 }
 
@@ -682,32 +848,10 @@
 {
     if (!a_list) {
         a_out << "<list nilpointer/>";
-        return a_out;
-    }
-    if (a_list->content_type () == GDBMIList::RESULT_TYPE) {
-        a_out << "<list type='result'>";
-        list<GDBMIResultSafePtr>::const_iterator iter;
-        list<GDBMIResultSafePtr> result_list;
-        a_list->get_result_content (result_list);
-        for (iter = result_list.begin ();
-             iter != result_list.end ();
-             ++iter) {
-            a_out << *iter;
-        }
-        a_out << "</list>";
-    } else if (a_list->content_type () == GDBMIList::VALUE_TYPE) {
-        a_out << "<list type='value'>";
-        list<GDBMIValueSafePtr>::const_iterator iter;
-        list<GDBMIValueSafePtr> value_list;
-        a_list->get_value_content (value_list);
-        for (iter = value_list.begin ();
-             iter != value_list.end ();
-             ++iter) {
-            a_out << *iter;
-        }
-        a_out << "</list>";
     } else {
-        THROW_IF_FAIL ("assert not reached");
+        UString str;
+        gdbmi_list_to_string (a_list, str);
+        a_out << str;
     }
     return a_out;
 }
@@ -717,27 +861,10 @@
 {
     if (!a_val) {
         a_out << "<value nilpointer/>";
-        return a_out;
-    }
-
-    switch (a_val->content_type ()) {
-        case GDBMIValue::EMPTY_TYPE:
-            a_out << "<value type='empty'/>";
-            break;
-        case GDBMIValue::TUPLE_TYPE :
-            a_out << "<value type='tuple'>"
-                  << a_val->get_tuple_content ()
-                  << "</value>";
-            break;
-        case GDBMIValue::LIST_TYPE :
-            a_out << "<value type='list'>\n"
-                  << a_val->get_list_content ()<< "</value>";
-            break;
-        case GDBMIValue::STRING_TYPE:
-            a_out << "<value type='string'>"
-                  << Glib::locale_from_utf8 (a_val->get_string_content ())
-                  << "</value>";
-            break;
+    } else {
+        UString str;
+        gdbmi_value_to_string (a_val, str);
+        a_out << str;
     }
     return a_out;
 }
@@ -3365,6 +3492,2930 @@
     return true;
 }
 
+//******************************
+//<Parser methods>
+//******************************
+struct GDBMIParser::Priv {
+    UString input;
+    UString::size_type end;
+    Mode mode;
+    list<UString> input_stack;
+
+    Priv (Mode a_mode = GDBMIParser::STRICT_MODE):
+        end (0),
+        mode (a_mode)
+    {
+    }
+
+    Priv (const UString &a_input, Mode a_mode) :
+        end (0),
+        mode (a_mode)
+
+    {
+        push_input (a_input);
+    }
+
+    UString::value_type raw_char_at (UString::size_type at) const
+    {
+        return input.raw ()[at];
+    }
+
+    bool index_passed_end (UString::size_type a_index)
+    {
+        return a_index >= end;
+    }
+
+    void set_input (const UString &a_input)
+    {
+        input = a_input;
+        end = a_input.bytes ();
+    }
+
+    void clear_input ()
+    {
+        input.clear ();
+        end = 0;
+    }
+
+    void push_input (const UString &a_input)
+    {
+        input_stack.push_front (a_input);
+        set_input (a_input);
+    }
+
+    void pop_input ()
+    {
+        clear_input ();
+        input_stack.pop_front ();
+        if (!input_stack.empty ()) {
+            set_input (input_stack.front ());
+        }
+    }
+};//end class GDBMIParser;
+
+
+GDBMIParser::GDBMIParser (Mode a_mode)
+{
+    m_priv.reset (new Priv (a_mode));
+}
+
+GDBMIParser::GDBMIParser (const UString &a_input, Mode a_mode)
+{
+    m_priv.reset (new Priv (a_input, a_mode));
+}
+
+GDBMIParser::~GDBMIParser ()
+{
+}
+
+void
+GDBMIParser::push_input (const UString &a_input)
+{
+    m_priv->push_input (a_input);
+}
+
+void
+GDBMIParser::pop_input ()
+{
+    m_priv->pop_input ();
+}
+
+const UString&
+GDBMIParser::get_input () const
+{
+    return m_priv->input;
+}
+
+void
+GDBMIParser::set_mode (Mode a_mode)
+{
+    m_priv->mode = a_mode;
+}
+
+GDBMIParser::Mode
+GDBMIParser::get_mode () const
+{
+    return m_priv->mode;
+}
+
+bool
+GDBMIParser::parse_string (UString::size_type a_from,
+                           UString::size_type &a_to,
+                           UString &a_string)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur=a_from;
+    CHECK_END2 (cur);
+
+    UString::value_type ch = RAW_CHAR_AT (cur);
+    if (!is_string_start (ch)) {
+        LOG_PARSING_ERROR_MSG2 (cur,
+                                "string doesn't start with a string char");
+        return false;
+    }
+    UString::size_type str_start (cur), str_end (0);
+    ++cur;
+    CHECK_END2 (cur);
+
+    for (;;) {
+        ch = RAW_CHAR_AT (cur);
+        if (isalnum (ch)
+            || ch == '_'
+            || ch == '-'
+            || ch == '>'
+            || ch == '<') {
+            ++cur;
+            CHECK_END2 (cur);
+            continue;
+        }
+        str_end = cur - 1;
+        break;
+    }
+    Glib::ustring str (m_priv->input.raw ().c_str () + str_start,
+                       str_end - str_start + 1);
+    a_string = str;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_octal_escape (UString::size_type a_from,
+                                 UString::size_type &a_to,
+                                 unsigned char &a_byte_value)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur+3))
+        return false;
+
+    if (RAW_CHAR_AT (cur) != '\\'
+        || !isdigit (RAW_CHAR_AT (cur+1))
+        || !isdigit (RAW_CHAR_AT (cur+2))
+        || !isdigit (RAW_CHAR_AT (cur+3))) {
+        return false;
+    }
+
+    a_byte_value = (RAW_CHAR_AT (cur+1) - '0') * 64 +
+                   (RAW_CHAR_AT (cur+2) - '0') * 8 +
+                   (RAW_CHAR_AT (cur+3) - '0');
+
+    a_to = cur + 4;
+    return true;
+}
+
+bool
+GDBMIParser::parse_octal_escape_sequence (UString::size_type a_from,
+                                          UString::size_type &a_to,
+                                          UString &a_result)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur+3))
+        return false;
+
+    CHECK_END2 (cur);
+    CHECK_END2 (cur+1);
+
+    unsigned char b=0;
+    string raw;
+    while (RAW_CHAR_AT (cur) == '\\') {
+        if (parse_octal_escape (cur, cur, b)) {
+            raw += b;
+        } else {
+            break;
+        }
+    }
+    if (raw.empty ()) return false;
+    try {
+        a_result = Glib::locale_to_utf8 (raw);
+    } catch (...) {
+        a_result.assign (raw.size (), '?');
+    }
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_c_string_body (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  UString &a_string)
+{
+    UString::size_type cur=a_from;
+    CHECK_END2 (cur);
+
+    UString::value_type ch = RAW_CHAR_AT (cur), prev_ch;
+    if (ch == '"') {
+        a_string = "";
+        a_to = cur;
+        return true;
+    }
+
+    if (!isascii (ch) && ch != '\\') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    UString result;
+    if (ch != '\\') {
+        result += ch;
+        ++cur;
+    } else {
+        UString seq;
+        if (!m_priv->index_passed_end (cur+3)
+            && isdigit (RAW_CHAR_AT (cur +1))
+            && isdigit (RAW_CHAR_AT (cur +2))
+            && isdigit (RAW_CHAR_AT (cur +3))
+            && parse_octal_escape_sequence (cur, cur, seq)) {
+            result += seq;
+        } else {
+            result += ch;
+            ++cur;
+        }
+    }
+    CHECK_END2 (cur);
+
+    for (;;) {
+        prev_ch = ch;
+        ch = RAW_CHAR_AT (cur);
+        if (isascii (ch)) {
+            if (ch == '"' && prev_ch != '\\') {
+                break;
+            }
+            if (ch == '\\') {
+                UString seq;
+                if (!m_priv->index_passed_end (cur+3)
+                    && isdigit (RAW_CHAR_AT (cur +1))
+                    && isdigit (RAW_CHAR_AT (cur +2))
+                    && isdigit (RAW_CHAR_AT (cur +3))
+                    && parse_octal_escape_sequence (cur, cur, seq)) {
+                    ch = seq[seq.size ()-1];
+                    result += seq;
+                } else {
+                    result += ch;
+                    ++cur;
+                }
+            } else {
+                result += ch;
+                ++cur;
+            }
+            CHECK_END2 (cur);
+            continue;
+        }
+        break;
+    }
+
+    if (ch != '"') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    a_string = result;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_c_string (UString::size_type a_from,
+                             UString::size_type &a_to,
+                             UString &a_c_string)
+{
+    UString::size_type cur=a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_CHAR_AT (cur) != '"') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+    CHECK_END2 (cur);
+
+    UString str;
+    if (!parse_c_string_body (cur, cur, str)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) != '"') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    ++cur;
+    a_c_string = str;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_embedded_c_string_body (UString::size_type a_from,
+                                           UString::size_type &a_to,
+                                           UString &a_string)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+    CHECK_END2 (cur);
+    CHECK_END2 (cur+1);
+
+    if (RAW_CHAR_AT (cur) != '\\' || RAW_CHAR_AT (cur+1) != '"') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += 2;
+    CHECK_END2 (cur);
+    UString escaped_str;
+    escaped_str += '"';
+
+    //first walk the string, and unescape everything we find escaped
+    UString::value_type ch=0, prev_ch=0;
+    bool escaping = false, found_end=false;
+    for (; !m_priv->index_passed_end (cur); ++cur) {
+        ch = RAW_CHAR_AT (cur);
+        if (ch == '\\') {
+            if (escaping) {
+                prev_ch = ch;
+                escaped_str += ch;
+                escaping = false;
+            } else {
+                escaping = true;
+            }
+        } else if (ch == '"') {
+            if (escaping) {
+                if (prev_ch != '\\') {
+                    //found the end of string
+                    found_end = true;
+                }
+                prev_ch = ch;
+                escaped_str += ch;
+                escaping = false;
+                if (found_end) {
+                    break;
+                }
+            } else {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+        } else {
+            escaped_str += ch;
+            prev_ch = ch;
+            escaping = false;
+        }
+    }
+    if (!found_end) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    //TODO:debug this.
+    a_string = escaped_str;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_embedded_c_string (UString::size_type a_from,
+                                      UString::size_type &a_to,
+                                      UString &a_string)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_CHAR_AT (cur) != '\\' || RAW_CHAR_AT (cur+1) != '"') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (!parse_embedded_c_string_body (cur, cur, a_string)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    a_to = ++cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_gdbmi_result (UString::size_type a_from,
+                                 UString::size_type &a_to,
+                                 GDBMIResultSafePtr &a_value)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    UString variable;
+    if (!parse_string (cur, cur, variable)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    CHECK_END2 (cur);
+    SKIP_BLANK2 (cur);
+    if (RAW_CHAR_AT (cur) != '=') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    LOG_D ("got gdbmi variable: " << variable, GDBMI_PARSING_DOMAIN);
+    ++cur;
+    CHECK_END2 (cur);
+
+    GDBMIValueSafePtr value;
+    if (!parse_gdbmi_value (cur, cur, value)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (value);
+
+    GDBMIResultSafePtr result (new GDBMIResult (variable, value));
+    THROW_IF_FAIL (result);
+    a_to = cur;
+    a_value = result;
+    return true;
+}
+
+bool
+GDBMIParser::parse_gdbmi_value (UString::size_type a_from,
+                                UString::size_type &a_to,
+                                GDBMIValueSafePtr &a_value)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    GDBMIValueSafePtr value;
+    if (RAW_CHAR_AT (cur) == '"') {
+        UString const_string;
+        if (parse_c_string (cur, cur, const_string)) {
+            value = GDBMIValueSafePtr (new GDBMIValue (const_string));
+            LOG_D ("got str gdbmi value: '"
+                    << const_string
+                    << "'",
+                   GDBMI_PARSING_DOMAIN);
+        }
+    } else if (RAW_CHAR_AT (cur) == '{') {
+        GDBMITupleSafePtr tuple;
+        if (parse_gdbmi_tuple (cur, cur, tuple)) {
+            if (!tuple) {
+                value = GDBMIValueSafePtr (new GDBMIValue ());
+            } else {
+                value = GDBMIValueSafePtr (new GDBMIValue (tuple));
+            }
+        }
+    } else if (RAW_CHAR_AT (cur) == '[') {
+        GDBMIListSafePtr list;
+        if (parse_gdbmi_list (cur, cur, list)) {
+            THROW_IF_FAIL (list);
+            value = GDBMIValueSafePtr (new GDBMIValue (list));
+        }
+    } else {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (!value) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    a_value = value;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_gdbmi_tuple (UString::size_type a_from,
+                                UString::size_type &a_to,
+                                GDBMITupleSafePtr &a_tuple)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_CHAR_AT (cur) != '{') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+    CHECK_END2 (cur);
+
+    if (RAW_CHAR_AT (cur) == '}') {
+        ++cur;
+        a_to = cur;
+        return true;
+    }
+
+    GDBMITupleSafePtr tuple;
+    GDBMIResultSafePtr result;
+
+    for (;;) {
+        if (parse_gdbmi_result (cur, cur, result)) {
+            THROW_IF_FAIL (result);
+            SKIP_BLANK2 (cur);
+            CHECK_END2 (cur);
+            if (!tuple) {
+                tuple = GDBMITupleSafePtr (new GDBMITuple);
+                THROW_IF_FAIL (tuple);
+            }
+            tuple->append (result);
+            if (RAW_CHAR_AT (cur) == ',') {
+                ++cur;
+                CHECK_END2 (cur);
+                SKIP_BLANK2 (cur);
+                continue;
+            }
+            if (RAW_CHAR_AT (cur) == '}') {
+                ++cur;
+            }
+        } else {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        LOG_D ("getting out at char '"
+               << (char)RAW_CHAR_AT (cur)
+               << "', at offset '"
+               << (int)cur
+               << "' for text >>>"
+               << m_priv->input.raw ()
+               << "<<<",
+               GDBMI_PARSING_DOMAIN);
+        break;
+    }
+
+    SKIP_BLANK2 (cur);
+    a_to = cur;
+    a_tuple = tuple;
+    return true;
+}
+
+bool
+GDBMIParser::parse_gdbmi_list (UString::size_type a_from,
+                               UString::size_type &a_to,
+                               GDBMIListSafePtr &a_list)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    GDBMIListSafePtr return_list;
+    if (RAW_CHAR_AT (cur) != '[') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    CHECK_END2 (cur + 1);
+    if (RAW_CHAR_AT (cur + 1) == ']') {
+        a_list = GDBMIListSafePtr (new GDBMIList);
+        cur += 2;
+        a_to = cur;
+        return true;
+    }
+
+    ++cur;
+    CHECK_END2 (cur);
+    SKIP_BLANK2 (cur);
+
+    GDBMIValueSafePtr value;
+    GDBMIResultSafePtr result;
+    if ((isalpha (RAW_CHAR_AT (cur)) || RAW_CHAR_AT (cur) == '_')
+         && parse_gdbmi_result (cur, cur, result)) {
+        CHECK_END2 (cur);
+        THROW_IF_FAIL (result);
+        return_list = GDBMIListSafePtr (new GDBMIList (result));
+        for (;;) {
+            if (RAW_CHAR_AT (cur) == ',') {
+                ++cur;
+                SKIP_BLANK2 (cur);
+                CHECK_END2 (cur);
+                result.reset ();
+                if (parse_gdbmi_result (cur, cur, result)) {
+                    THROW_IF_FAIL (result);
+                    return_list->append (result);
+                    continue;
+                }
+            }
+            break;
+        }
+    } else if (parse_gdbmi_value (cur, cur, value)) {
+        CHECK_END2 (cur);
+        THROW_IF_FAIL (value);
+        return_list = GDBMIListSafePtr (new GDBMIList (value));
+        for (;;) {
+            if (RAW_CHAR_AT (cur) == ',') {
+                ++cur;
+                SKIP_BLANK2 (cur);
+                CHECK_END2 (cur);
+                value.reset ();
+                if (parse_gdbmi_value (cur, cur, value)) {
+                    THROW_IF_FAIL (value);
+                    return_list->append (value);
+                    continue;
+                }
+            }
+            break;
+        }
+    } else {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) != ']') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+
+    a_to = cur;
+    a_list = return_list;
+    return true;
+}
+
+bool
+GDBMIParser::parse_stream_record (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  Output::StreamRecord &a_record)
+{
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    UString console, target, log;
+    if (RAW_CHAR_AT (cur) == '~') {
+        //console stream output
+        ++cur;
+        if (m_priv->index_passed_end (cur)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        if (!parse_c_string (cur, cur, console)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        SKIP_WS2 (cur);
+        if (!m_priv->index_passed_end (cur + 1)
+            && RAW_CHAR_AT (cur) == '>'
+            && isspace (RAW_CHAR_AT (cur+1))) {
+            cur += 2;
+        }
+        SKIP_BLANK2 (cur);
+    } else if (RAW_CHAR_AT (cur) == '@') {
+        //target stream output
+        ++cur;
+        if (m_priv->index_passed_end (cur)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        if (!parse_c_string (cur, cur, target)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+    } else if (RAW_CHAR_AT (cur) == '&') {
+        //log stream output
+        ++cur;
+        if (m_priv->index_passed_end (cur)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        if (!parse_c_string (cur, cur, log)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+    } else {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    for (; !m_priv->index_passed_end (cur) && isspace (RAW_CHAR_AT (cur)); ++cur) {}
+
+    bool found (false);
+    if (!console.empty ()) {
+        found = true;
+        remove_stream_record_trailing_chars (console);
+        a_record.debugger_console (console);
+    }
+    if (!target.empty ()) {
+        found = true;
+        remove_stream_record_trailing_chars (target);
+        a_record.target_output (target);
+    }
+    if (!log.empty ()) {
+        found = true;
+        remove_stream_record_trailing_chars (log);
+        a_record.debugger_log (log);
+    }
+
+    if (!found) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_stopped_async_output (UString::size_type a_from,
+                                         UString::size_type &a_to,
+                                         bool &a_got_frame,
+                                         IDebugger::Frame &a_frame,
+                                         map<UString, UString> &a_attrs)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur)) {return false;}
+
+    if (m_priv->input.raw ().compare (cur, strlen (PREFIX_STOPPED_ASYNC_OUTPUT),
+                                      PREFIX_STOPPED_ASYNC_OUTPUT)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += 9;
+    if (m_priv->index_passed_end (cur)) {return false;}
+
+    map<UString, UString> attrs;
+    UString name, value;
+    bool got_frame (false);
+    IDebugger::Frame frame;
+    while (true) {
+        if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_FRAME), PREFIX_FRAME)) {
+            if (!parse_frame (cur, cur, frame)) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            got_frame = true;
+        } else {
+            if (!parse_attribute (cur, cur, name, value)) {break;}
+            attrs[name] = value;
+            name.clear (); value.clear ();
+        }
+
+        if (m_priv->index_passed_end (cur)) {break;}
+        if (RAW_CHAR_AT (cur) == ',') {++cur;}
+        if (m_priv->index_passed_end (cur)) {break;}
+    }
+
+    for (; !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n'; ++cur) {}
+
+    if (RAW_CHAR_AT (cur) != '\n') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+
+    a_got_frame = got_frame;
+    if (a_got_frame) {
+        a_frame = frame;
+    }
+    a_to = cur;
+    a_attrs = attrs;
+    return true;
+}
+
+bool
+GDBMIParser::parse_running_async_output (UString::size_type a_from,
+                                         UString::size_type &a_to,
+                                         int &a_thread_id)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur)) {return false;}
+
+    if (m_priv->input.raw ().compare (cur, strlen (PREFIX_RUNNING_ASYNC_OUTPUT),
+                                      PREFIX_RUNNING_ASYNC_OUTPUT)) {
+        LOG_PARSING_ERROR_MSG2 (cur, "was expecting : '*running,'");
+        return false;
+    }
+    cur += 9;
+    if (m_priv->index_passed_end (cur)) {return false;}
+
+    UString name, value;
+    if (!parse_attribute (cur, cur, name, value)) {
+        LOG_PARSING_ERROR_MSG2 (cur, "was expecting an attribute");
+        return false;
+    }
+    if (name != "thread-id") {
+        LOG_PARSING_ERROR_MSG2 (cur, "was expecting attribute 'thread-id'");
+        return false;
+    }
+    if (value == "all")
+        a_thread_id = -1;
+    else
+        a_thread_id = atoi (value.c_str ());
+
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_attribute (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              UString &a_name,
+                              UString &a_value)
+{
+    UString::size_type cur = a_from;
+
+    if (m_priv->index_passed_end (cur)
+        || !is_string_start (RAW_CHAR_AT (cur))) {return false;}
+
+    GDBMIResultSafePtr result;
+    if (!parse_gdbmi_result (cur, a_to, result)
+        || !result
+        || result->variable ().empty ()
+        || !result->value ()) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    a_name = result->variable ();
+    return gdbmi_value_to_string (result->value (), a_value);
+}
+
+bool
+GDBMIParser::parse_attributes (UString::size_type a_from,
+                               UString::size_type &a_to,
+                               map<UString, UString> &a_attrs)
+{
+    UString::size_type cur = a_from;
+
+    if (m_priv->index_passed_end (cur)) {return false;}
+
+    UString name, value;
+    map<UString, UString> attrs;
+
+    while (true) {
+        if (!parse_attribute (cur, cur, name, value)) {break;}
+        if (!name.empty () && !value.empty ()) {
+            attrs[name] = value;
+            name.clear (); value.clear ();
+        }
+
+        while (isspace (RAW_CHAR_AT (cur))) {++cur;}
+        if (m_priv->index_passed_end (cur) || RAW_CHAR_AT (cur) != ',') {break;}
+        if (m_priv->index_passed_end (++cur)) {break;}
+    }
+    a_attrs = attrs;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_frame (UString::size_type a_from,
+                          UString::size_type &a_to,
+                          IDebugger::Frame &a_frame)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (m_priv->input.compare (a_from, strlen (PREFIX_FRAME), PREFIX_FRAME)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIResultSafePtr result;
+    if (!parse_gdbmi_result (cur, cur, result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (result);
+
+    if (result->variable () != "frame") {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (!result->value ()
+        ||result->value ()->content_type ()
+                != GDBMIValue::TUPLE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMITupleSafePtr result_value_tuple =
+                                result->value ()->get_tuple_content ();
+    if (!result_value_tuple) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    list<GDBMIResultSafePtr>::const_iterator res_it;
+    GDBMIResultSafePtr tmp_res;
+    IDebugger::Frame frame;
+    UString name, value;
+    for (res_it = result_value_tuple->content ().begin ();
+         res_it != result_value_tuple->content ().end ();
+         ++res_it) {
+        if (!(*res_it)) {continue;}
+        tmp_res = *res_it;
+        if (!tmp_res->value ()
+            ||tmp_res->value ()->content_type () != GDBMIValue::STRING_TYPE) {
+            continue;
+        }
+        name = tmp_res->variable ();
+        value = tmp_res->value ()->get_string_content ();
+        if (name == "level") {
+            frame.level (atoi (value.c_str ()));
+        } else if (name == "addr") {
+            frame.address (value);
+        } else if (name == "func") {
+            frame.function_name (value);
+        } else if (name == "file") {
+            frame.file_name (value);
+        } else if (name == "fullname") {
+            frame.file_full_name (value);
+        } else if (name == "line") {
+            frame.line (atoi (value.c_str ()));
+        }
+    }
+    a_frame = frame;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_output_record (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  Output &a_output)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    Output output;
+
+    while (RAW_CHAR_AT (cur) == '*'
+         || RAW_CHAR_AT (cur) == '~'
+         || RAW_CHAR_AT (cur) == '@'
+         || RAW_CHAR_AT (cur) == '&'
+         || RAW_CHAR_AT (cur) == '+'
+         || RAW_CHAR_AT (cur) == '=') {
+        Output::OutOfBandRecord oo_record;
+        if (!parse_out_of_band_record (cur, cur, oo_record)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        output.has_out_of_band_record (true);
+        output.out_of_band_records ().push_back (oo_record);
+    }
+
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) == '^') {
+        Output::ResultRecord result_record;
+        if (parse_result_record (cur, cur, result_record)) {
+            output.has_result_record (true);
+            output.result_record (result_record);
+        }
+        if (m_priv->index_passed_end (cur)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+    }
+
+    while (!m_priv->index_passed_end (cur)
+           && isspace (RAW_CHAR_AT (cur))) {++cur;}
+
+    if (!m_priv->input.raw ().compare (cur, 5, "(gdb)")) {
+        cur += 5;
+    }
+
+    if (cur == a_from) {
+        //we didn't parse anything
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    while (m_priv->index_passed_end (cur)
+           && isspace (RAW_CHAR_AT (cur))) {++cur;}
+
+    a_output = output;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_out_of_band_record (UString::size_type a_from,
+                                       UString::size_type &a_to,
+                                       Output::OutOfBandRecord &a_record)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    Output::OutOfBandRecord record;
+    if (RAW_CHAR_AT (cur) == '~' ||
+        RAW_CHAR_AT (cur) == '@' ||
+        RAW_CHAR_AT (cur) == '&') {
+        Output::StreamRecord stream_record;
+        if (!parse_stream_record (cur, cur, stream_record)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        record.has_stream_record (true);
+        record.stream_record (stream_record);
+
+        while (m_priv->index_passed_end (cur)
+               && isspace (RAW_CHAR_AT (cur))) {++cur;}
+    } else if (RAW_CHAR_AT (cur) == '=') {
+        //this is a notification sent by gdb. For now, the only one
+        //I have seen like this is of the form:
+        //'=thread-created,id=1',
+        //and the notification ends with a '\n' character.
+        //Of course it is not documented
+        //Let's ignore this by now
+        while (RAW_CHAR_AT (cur) != '\n') {++cur;}
+        ++cur;//consume the '\n' character
+    }
+
+    if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_STOPPED_ASYNC_OUTPUT),
+                                       PREFIX_STOPPED_ASYNC_OUTPUT)) {
+        map<UString, UString> attrs;
+        bool got_frame (false);
+        IDebugger::Frame frame;
+        if (!parse_stopped_async_output (cur, cur, got_frame, frame, attrs)) {
+            LOG_PARSING_ERROR_MSG2 (cur,
+                                    "could not parse the expected "
+                                    "stopped async output");
+            return false;
+        }
+        record.is_stopped (true);
+        record.stop_reason (str_to_stopped_reason (attrs["reason"]));
+        if (got_frame) {
+            record.frame (frame);
+            record.has_frame (true);
+        }
+
+        if (attrs.find ("bkptno") != attrs.end ()) {
+            record.breakpoint_number (atoi (attrs["bkptno"].c_str ()));
+        }
+        record.thread_id (atoi (attrs["thread-id"].c_str ()));
+        record.signal_type (attrs["signal-name"]);
+        record.signal_meaning (attrs["signal-meaning"]);
+        goto end;
+    }
+
+    if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_RUNNING_ASYNC_OUTPUT),
+                                       PREFIX_RUNNING_ASYNC_OUTPUT)) {
+        int thread_id;
+        if (!parse_running_async_output (cur, cur, thread_id)) {
+            LOG_PARSING_ERROR_MSG2 (cur,
+                                    "could not parse the expected "
+                                    "running async output");
+            return false;
+        }
+        record.thread_id (thread_id);
+        goto end;
+    }
+
+end:
+
+    while (!m_priv->index_passed_end (cur)
+           && isspace (RAW_CHAR_AT (cur))) {++cur;}
+    a_to = cur;
+    a_record = record;
+    return true;
+}
+
+bool
+GDBMIParser::parse_result_record (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  Output::ResultRecord &a_record)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    UString::size_type cur=a_from;
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    UString name, value;
+    Output::ResultRecord result_record;
+    if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_DONE), PREFIX_DONE)) {
+        cur += 5;
+        result_record.kind (Output::ResultRecord::DONE);
+
+
+        if (!m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) == ',') {
+
+fetch_gdbmi_result:
+            cur++;
+            if (m_priv->index_passed_end (cur)) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+
+            if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_BKPT),
+                                                PREFIX_BKPT)) {
+                IDebugger::BreakPoint breakpoint;
+                if (parse_breakpoint (cur, cur, breakpoint)) {
+                    result_record.breakpoints ()[breakpoint.number ()] =
+                    breakpoint;
+                }
+            } else if (!m_priv->input.compare (cur,
+                                               strlen (PREFIX_BREAKPOINT_TABLE),
+                                               PREFIX_BREAKPOINT_TABLE)) {
+                map<int, IDebugger::BreakPoint> breaks;
+                if (parse_breakpoint_table (cur, cur, breaks)) {
+                    result_record.breakpoints () = breaks;
+                }
+            } else if (!m_priv->input.compare (cur, strlen (PREFIX_THREAD_IDS),
+                        PREFIX_THREAD_IDS)) {
+                std::list<int> thread_ids;
+                if (parse_threads_list (cur, cur, thread_ids)) {
+                    result_record.thread_list (thread_ids);
+                }
+            } else if (!m_priv->input.raw ().compare
+                                            (cur,
+                                             strlen (PREFIX_NEW_THREAD_ID),
+                                             PREFIX_NEW_THREAD_ID)) {
+                IDebugger::Frame frame;
+                int thread_id=0;
+                if (parse_new_thread_id (cur, cur, thread_id, frame)) {
+                    //finish this !
+                    result_record.thread_id_selected_info (thread_id, frame);
+                }
+            } else if (!m_priv->input.compare (cur, strlen (PREFIX_FILES),
+                        PREFIX_FILES)) {
+                vector<UString> files;
+                if (!parse_file_list (cur, cur, files)) {
+                    LOG_PARSING_ERROR2 (cur);
+                    return false;
+                }
+                result_record.file_list (files);
+                LOG_D ("parsed a list of files: "
+                       << (int) files.size (),
+                       GDBMI_PARSING_DOMAIN);
+            } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_STACK),
+                                                      PREFIX_STACK)) {
+                vector<IDebugger::Frame> call_stack;
+                if (!parse_call_stack (cur, cur, call_stack)) {
+                    LOG_PARSING_ERROR2 (cur);
+                    return false;
+                }
+                result_record.call_stack (call_stack);
+                LOG_D ("parsed a call stack of depth: "
+                       << (int) call_stack.size (),
+                       GDBMI_PARSING_DOMAIN);
+                vector<IDebugger::Frame>::iterator frame_iter;
+                for (frame_iter = call_stack.begin ();
+                     frame_iter != call_stack.end ();
+                     ++frame_iter) {
+                    LOG_D ("function-name: " << frame_iter->function_name (),
+                           GDBMI_PARSING_DOMAIN);
+                }
+            } else if (!m_priv->input.raw ().compare (cur,
+                                                strlen (PREFIX_FRAME),
+                                                        PREFIX_FRAME)) {
+                IDebugger::Frame frame;
+                if (!parse_frame (cur, cur, frame)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed result", GDBMI_PARSING_DOMAIN);
+                    result_record.current_frame_in_core_stack_trace (frame);
+                    //current_frame_signal.emit (frame, "");
+                }
+            } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_DEPTH),
+                                                      PREFIX_DEPTH)) {
+                GDBMIResultSafePtr result;
+                parse_gdbmi_result (cur, cur, result);
+                THROW_IF_FAIL (result);
+                LOG_D ("parsed result", GDBMI_PARSING_DOMAIN);
+            } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_STACK_ARGS),
+                                                      PREFIX_STACK_ARGS)) {
+                map<int, list<IDebugger::VariableSafePtr> > frames_args;
+                if (!parse_stack_arguments (cur, cur, frames_args)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed stack args", GDBMI_PARSING_DOMAIN);
+                }
+                result_record.frames_parameters (frames_args) ;
+            } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_LOCALS),
+                                                      PREFIX_LOCALS)) {
+                list<IDebugger::VariableSafePtr> vars;
+                if (!parse_local_var_list (cur, cur, vars)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed local vars", GDBMI_PARSING_DOMAIN);
+                    result_record.local_variables (vars);
+                }
+            } else if (!m_priv->input.raw ().compare (cur,
+                                                      strlen (PREFIX_VALUE),
+                                                      PREFIX_VALUE)) {
+                // FIXME: this case will parse any response from
+                // -data-evaluate-expression, including the response from
+                // setting the value of a register or any other expression
+                // evaluation.  Currently all of these cases can be parsed as a
+                // variable, but there's no guarantee that this is the case.
+                // Perhaps this needs to be reworked somehow
+                IDebugger::VariableSafePtr var;
+                if (!parse_variable_value (cur, cur, var)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed var value", GDBMI_PARSING_DOMAIN);
+                    THROW_IF_FAIL (var);
+                    result_record.variable_value (var);
+                }
+            } else if (!m_priv->input.raw ().compare (cur,
+                                                      strlen (PREFIX_REGISTER_NAMES),
+                                                      PREFIX_REGISTER_NAMES)) {
+                std::map<IDebugger::register_id_t, UString> regs;
+                if (!parse_register_names (cur, cur, regs)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed register names", GDBMI_PARSING_DOMAIN);
+                    result_record.register_names (regs);
+                }
+            } else if (!m_priv->input.raw ().compare (cur,
+                                                      strlen (PREFIX_CHANGED_REGISTERS),
+                                                      PREFIX_CHANGED_REGISTERS)) {
+                std::list<IDebugger::register_id_t> regs;
+                if (!parse_changed_registers (cur, cur, regs)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed changed register", GDBMI_PARSING_DOMAIN);
+                    result_record.changed_registers (regs);
+                }
+            } else if (!m_priv->input.raw ().compare (cur,
+                                                      strlen (PREFIX_REGISTER_VALUES),
+                                                      PREFIX_REGISTER_VALUES)) {
+                std::map<IDebugger::register_id_t, UString>  values;
+                if (!parse_register_values (cur, cur,  values)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed register values", GDBMI_PARSING_DOMAIN);
+                    result_record.register_values (values);
+                }
+            } else if (!m_priv->input.compare (cur, strlen (PREFIX_MEMORY_VALUES),
+                        PREFIX_MEMORY_VALUES)) {
+                size_t addr;
+                std::vector<uint8_t>  values;
+                if (!parse_memory_values (cur, cur, addr, values)) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed memory values", GDBMI_PARSING_DOMAIN);
+                    result_record.memory_values (addr, values);
+                }
+            } else {
+                GDBMIResultSafePtr result;
+                if (!parse_gdbmi_result (cur, cur, result)
+                    || !result) {
+                    LOG_PARSING_ERROR2 (cur);
+                } else {
+                    LOG_D ("parsed unknown gdbmi result",
+                           GDBMI_PARSING_DOMAIN);
+                }
+            }
+
+            if (RAW_CHAR_AT (cur) == ',') {
+                goto fetch_gdbmi_result;
+            }
+
+            //skip the remaining things we couldn't parse, until the
+            //'end of line' character.
+            for (;
+                 !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n';
+                 ++cur) {}
+        }
+    } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_RUNNING),
+                                              PREFIX_RUNNING)) {
+        result_record.kind (Output::ResultRecord::RUNNING);
+        cur += 8;
+        for (;
+             !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n';
+             ++cur) {}
+    } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_EXIT),
+                                              PREFIX_EXIT)) {
+        result_record.kind (Output::ResultRecord::EXIT);
+        cur += 5;
+        for (;
+             !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n';
+             ++cur) {}
+    } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_CONNECTED),
+                                              PREFIX_CONNECTED)) {
+        result_record.kind (Output::ResultRecord::CONNECTED);
+        cur += 10;
+        for (; !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n';++cur) {}
+    } else if (!m_priv->input.raw ().compare (cur, strlen (PREFIX_ERROR),
+                                              PREFIX_ERROR)) {
+        result_record.kind (Output::ResultRecord::ERROR);
+        cur += 6;
+        CHECK_END2 (cur);
+        if (!m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) == ',') {++cur;}
+        CHECK_END2 (cur);
+        if (!parse_attribute (cur, cur, name, value)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        if (name != "") {
+            LOG_DD ("got error with attribute: '"
+                    << name << "':'" << value << "'");
+            result_record.attrs ()[name] = value;
+        } else {
+            LOG_ERROR ("weird, got error with no attribute. continuing.");
+        }
+        for (; !m_priv->index_passed_end (cur) && RAW_CHAR_AT (cur) != '\n';++cur) {}
+    } else {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) != '\n') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    a_record = result_record;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_breakpoint (Glib::ustring::size_type a_from,
+                               Glib::ustring::size_type &a_to,
+                               IDebugger::BreakPoint &a_bkpt)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+
+    Glib::ustring::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_BKPT), PREFIX_BKPT)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    cur += 6;
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    map<UString, UString> attrs;
+    bool is_ok = parse_attributes (cur, cur, attrs);
+    if (!is_ok) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur) != '}') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+
+    if (attrs["addr"] == "<PENDING>") {
+        UString pending = attrs["pending"];
+        if (pending == "") {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        LOG_D ("got pending breakpoint: '" << pending << "'",
+               GDBMI_OUTPUT_DOMAIN);
+        vector<UString> str_tab;
+        //pending contains either the name of the function the breakpoint
+        //has been set on, or the filename:linenumber location of the
+        //breakpoint.
+        //So either pending has the form:
+        //"ns::functionname" or it has the form "filename:linenumber"
+        bool breakpoint_on_function_name = false;
+        if (pending.raw ().find ("::") != std::string::npos) {
+            breakpoint_on_function_name = true;
+        }
+        if (!breakpoint_on_function_name) {
+            str_tab = pending.split (":");
+        } else {
+            str_tab.push_back (pending);
+        }
+        //from now on, if str_tab.size () == 2 then it contains
+        //the filename and line number of the breakpoint.
+        //if it str_tab.size () == 1 then it contains the function name
+        //the breakpoint was set on.
+        //Otherwise an error occured
+        if (str_tab.size () > 1) {
+            LOG_D ("filepath: '" << str_tab[0] << "'", GDBMI_OUTPUT_DOMAIN);
+            LOG_D ("linenum: '" << str_tab[1] << "'", GDBMI_OUTPUT_DOMAIN);
+        }
+        if (str_tab.size () == 2) {
+            string path = Glib::locale_from_utf8 (str_tab[0]);
+            if (Glib::path_is_absolute (path)) {
+                attrs["file"] = Glib::locale_to_utf8
+                                        (Glib::path_get_basename (path));
+                attrs["fullname"] = Glib::locale_to_utf8 (path);
+            } else {
+                attrs["file"] = Glib::locale_to_utf8 (path);;
+            }
+            attrs["line"] = str_tab[1];
+        } else if (str_tab.size () == 1) {
+            attrs["func"] = str_tab[0];
+        } else {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+    }
+
+    map<UString, UString>::iterator iter, null_iter = attrs.end ();
+    //we use to require that the "fullname" property be present as
+    //well, but it seems that a lot debug info set got shipped without
+    //that property. Client code should do what they can with the
+    //file property only.
+    if (   (iter = attrs.find ("number"))  == null_iter
+            || (iter = attrs.find ("type"))    == null_iter
+            || (iter = attrs.find ("disp"))    == null_iter
+            || (iter = attrs.find ("enabled")) == null_iter
+            || (iter = attrs.find ("addr"))    == null_iter
+            || (iter = attrs.find ("times"))   == null_iter
+       ) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    a_bkpt.number (atoi (attrs["number"].c_str ()));
+    if (attrs["enabled"] == "y") {
+        a_bkpt.enabled (true);
+    } else {
+        a_bkpt.enabled (false);
+    }
+    a_bkpt.address (attrs["addr"]);
+    if (!attrs["func"].empty ()) {
+        a_bkpt.function (attrs["func"]);
+    } else if (!attrs["what"].empty ()) {
+        // catchpoints don't have a 'func' field, but they have a 'what' field
+        // that says something like "Exception throw"
+        a_bkpt.function (attrs["what"]);
+    }
+    a_bkpt.file_name (attrs["file"]); //may be nil
+    a_bkpt.file_full_name (attrs["fullname"]); //may be nil
+    a_bkpt.line (atoi (attrs["line"].c_str ())); //may be nil
+    if ((iter = attrs.find ("cond")) != null_iter) {
+        a_bkpt.condition (iter->second);
+    }
+    a_bkpt.nb_times_hit (atoi (attrs["times"].c_str ()));
+    //TODO: get the 'at' attribute that is present on targets that
+    //are not compiled with -g.
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_breakpoint_table (UString::size_type a_from,
+                                     UString::size_type &a_to,
+                                     map<int, IDebugger::BreakPoint> &a_breakpoints)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur=a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_BREAKPOINT_TABLE),
+                                      PREFIX_BREAKPOINT_TABLE)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += strlen (PREFIX_BREAKPOINT_TABLE);
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    //skip table headers and go to table body.
+    cur = RAW_INPUT.find ("body=[", 0) ;
+    if (!cur) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += 6;
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    map<int, IDebugger::BreakPoint> breakpoint_table;
+    if (RAW_CHAR_AT (cur) == ']') {
+        //there are zero breakpoints ...
+    } else if (!RAW_INPUT.compare (cur, strlen (PREFIX_BKPT),
+                                              PREFIX_BKPT)) {
+        //there are some breakpoints
+        IDebugger::BreakPoint breakpoint;
+        while (true) {
+            if (RAW_INPUT.compare (cur, strlen (PREFIX_BKPT),
+                                              PREFIX_BKPT)) {
+                break;
+            }
+            if (!parse_breakpoint (cur, cur, breakpoint)) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            breakpoint_table[breakpoint.number ()] = breakpoint;
+            if (RAW_CHAR_AT (cur) == ',') {
+                ++cur;
+                if (m_priv->index_passed_end (cur)) {
+                    LOG_PARSING_ERROR2 (cur);
+                    return false;
+                }
+            }
+            breakpoint.clear ();
+        }
+        if (breakpoint_table.empty ()) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+    } else {
+        //weird things are happening, get out.
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) != ']') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur) != '}') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+
+    a_to = cur;
+    a_breakpoints = breakpoint_table;
+    return true;
+}
+
+bool
+GDBMIParser::parse_threads_list (UString::size_type a_from,
+                                 UString::size_type &a_to,
+                                 std::list<int> &a_thread_ids)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_THREAD_IDS), PREFIX_THREAD_IDS)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIResultSafePtr gdbmi_result;
+    if (!parse_gdbmi_result (cur, cur, gdbmi_result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur) != ',') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+    CHECK_END2 (cur);
+
+    if (gdbmi_result->variable () != "thread-ids") {
+        LOG_ERROR ("expected gdbmi variable 'thread-ids', got: '"
+                   << gdbmi_result->variable () << "\'");
+        return false;
+    }
+    THROW_IF_FAIL (gdbmi_result->value ());
+    THROW_IF_FAIL ((gdbmi_result->value ()->content_type ()
+                       == GDBMIValue::TUPLE_TYPE)
+                   ||
+                   (gdbmi_result->value ()->content_type ()
+                        == GDBMIValue::EMPTY_TYPE));
+
+    GDBMITupleSafePtr gdbmi_tuple;
+    if (gdbmi_result->value ()->content_type ()
+         != GDBMIValue::EMPTY_TYPE) {
+        gdbmi_tuple = gdbmi_result->value ()->get_tuple_content ();
+        THROW_IF_FAIL (gdbmi_tuple);
+    }
+
+    list<GDBMIResultSafePtr> result_list;
+    if (gdbmi_tuple) {
+        result_list = gdbmi_tuple->content ();
+    }
+    list<GDBMIResultSafePtr>::const_iterator it;
+    int thread_id=0;
+    std::list<int> thread_ids;
+    for (it = result_list.begin (); it != result_list.end (); ++it) {
+        THROW_IF_FAIL (*it);
+        if ((*it)->variable () != "thread-id") {
+            LOG_ERROR ("expected a gdbmi value with variable name 'thread-id'"
+                       ". Got '" << (*it)->variable () << "'");
+            return false;
+        }
+        THROW_IF_FAIL ((*it)->value ()
+                       && ((*it)->value ()->content_type ()
+                           == GDBMIValue::STRING_TYPE));
+        thread_id = atoi ((*it)->value ()->get_string_content ().c_str ());
+        THROW_IF_FAIL (thread_id);
+        thread_ids.push_back (thread_id);
+    }
+
+    if (!parse_gdbmi_result (cur, cur, gdbmi_result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (gdbmi_result->variable () != "number-of-threads") {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (gdbmi_result->value ()
+                   && gdbmi_result->value ()->content_type ()
+                       == GDBMIValue::STRING_TYPE);
+    unsigned int num_threads =
+        atoi (gdbmi_result->value ()->get_string_content ().c_str ());
+
+    if (num_threads != thread_ids.size ()) {
+        LOG_ERROR ("num_threads: '"
+                   << (int) num_threads
+                   << "', thread_ids.size(): '"
+                   << (int) thread_ids.size ()
+                   << "'");
+        return false;
+    }
+
+    a_thread_ids = thread_ids;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_new_thread_id (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  int &a_thread_id,
+                                  IDebugger::Frame &a_frame)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_NEW_THREAD_ID),
+                           PREFIX_NEW_THREAD_ID)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    GDBMIResultSafePtr gdbmi_result;
+    if (!parse_gdbmi_result (cur, cur, gdbmi_result)
+        || !gdbmi_result) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (gdbmi_result->variable () != "new-thread-id") {
+        LOG_ERROR ("expected 'new-thread-id', got '"
+                   << gdbmi_result->variable () << "'");
+        return false;
+    }
+    THROW_IF_FAIL (gdbmi_result->value ());
+    THROW_IF_FAIL (gdbmi_result->value ()->content_type ()
+                   == GDBMIValue::STRING_TYPE);
+    CHECK_END2 (cur);
+
+    int thread_id =
+        atoi (gdbmi_result->value ()->get_string_content ().c_str ());
+    if (!thread_id) {
+        LOG_ERROR ("got null thread id");
+        return false;
+    }
+
+    SKIP_BLANK2 (cur);
+
+    if (RAW_CHAR_AT (cur) != ',') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    ++cur;
+    CHECK_END2 (cur);
+
+    IDebugger::Frame frame;
+    if (!parse_frame (cur, cur, frame)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    a_to = cur;
+    a_thread_id = thread_id;
+    a_frame = frame;
+    return true;
+}
+
+bool
+GDBMIParser::parse_file_list (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              std::vector<UString> &a_files)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_FILES), PREFIX_FILES)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += 7;
+
+    std::vector<GDBMITupleSafePtr> tuples;
+    while (m_priv->index_passed_end (cur)) {
+        GDBMITupleSafePtr tuple;
+        if (!parse_gdbmi_tuple (cur, cur, tuple)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        tuples.push_back(tuple);
+        if (RAW_CHAR_AT (cur) == ',') {
+            ++cur;
+        } else if (RAW_CHAR_AT (cur) == ']') {
+            //at the end of the list, just get out
+            break;
+        } else {
+            //unexpected data
+            LOG_PARSING_ERROR2 (cur);
+        }
+    }
+
+    std::vector<UString> files;
+    vector<GDBMITupleSafePtr>::const_iterator file_iter;
+    for (file_iter = tuples.begin (); file_iter != tuples.end (); ++file_iter) {
+        UString filename;
+        list<GDBMIResultSafePtr>::const_iterator attr_it;
+        for (attr_it = (*file_iter)->content ().begin ();
+             attr_it != (*file_iter)->content ().end (); ++attr_it) {
+             THROW_IF_FAIL ((*attr_it)->value ()
+                           && ((*attr_it)->value ()->content_type ()
+                               == GDBMIValue::STRING_TYPE));
+            if ((*attr_it)->variable () == "file") {
+                //only use the 'file' attribute if the
+                //fullname isn't already set
+                //FIXME: do we even want to list these at all?
+                if (filename.empty ()) {
+                    filename = (*attr_it)->value ()->get_string_content ();
+                }
+            } else if ((*attr_it)->variable () == "fullname") {
+                //use the fullname attribute,
+                //overwriting the 'file' attribute
+                //if necessary
+                filename = (*attr_it)->value ()->get_string_content ();
+            } else {
+                LOG_ERROR ("expected a gdbmi value with "
+                            "variable name 'file' or 'fullname'"
+                            ". Got '" << (*attr_it)->variable () << "'");
+                return false;
+            }
+        }
+        THROW_IF_FAIL (!filename.empty());
+        files.push_back (filename);
+    }
+
+    std::sort(files.begin(), files.end(), QuickUStringLess());
+    std::vector<UString>::iterator last_unique =
+        std::unique (files.begin (), files.end ());
+    a_files = std::vector<UString>(files.begin (), last_unique);
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_call_stack (const UString::size_type a_from,
+                               UString::size_type &a_to,
+                               vector<IDebugger::Frame> &a_stack)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    GDBMIResultSafePtr result;
+    if (!parse_gdbmi_result (cur, cur, result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (result);
+    CHECK_END2 (cur);
+
+    if (result->variable () != "stack") {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (!result->value ()
+        ||result->value ()->content_type ()
+                != GDBMIValue::LIST_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIListSafePtr result_value_list =
+        result->value ()->get_list_content ();
+    if (!result_value_list) {
+        a_to = cur;
+        a_stack.clear ();
+        return true;
+    }
+
+    if (result_value_list->content_type () != GDBMIList::RESULT_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    list<GDBMIResultSafePtr> result_list ;
+    result_value_list->get_result_content (result_list);
+
+    GDBMITupleSafePtr frame_tuple;
+    vector<IDebugger::Frame> stack;
+    list<GDBMIResultSafePtr>::const_iterator iter, frame_part_iter;
+    UString value;
+    for (iter = result_list.begin (); iter != result_list.end (); ++iter) {
+        if (!(*iter)) {continue;}
+        THROW_IF_FAIL ((*iter)->value ()
+                       && (*iter)->value ()->content_type ()
+                       == GDBMIValue::TUPLE_TYPE);
+
+        frame_tuple = (*iter)->value ()->get_tuple_content ();
+        THROW_IF_FAIL (frame_tuple);
+        IDebugger::Frame frame;
+        for (frame_part_iter = frame_tuple->content ().begin ();
+             frame_part_iter != frame_tuple->content ().end ();
+             ++frame_part_iter) {
+            THROW_IF_FAIL ((*frame_part_iter)->value ());
+            value = (*frame_part_iter)->value ()->get_string_content ();
+            if ((*frame_part_iter)->variable () == "addr") {
+                frame.address (value);
+            } else if ((*frame_part_iter)->variable () == "func") {
+                frame.function_name (value);
+            } else if ((*frame_part_iter)->variable () == "file") {
+                frame.file_name (value);
+            } else if ((*frame_part_iter)->variable () == "fullname") {
+                frame.file_full_name (value);
+            } else if ((*frame_part_iter)->variable () == "line") {
+                frame.line (atol (value.c_str ()));
+            }
+        }
+        THROW_IF_FAIL (frame.address () != "");
+        stack.push_back (frame);
+        frame.clear ();
+    }
+    a_stack = stack;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_local_var_list (UString::size_type a_from,
+                                   UString::size_type &a_to,
+                                   list<IDebugger::VariableSafePtr> &a_vars)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_LOCALS), PREFIX_LOCALS)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIResultSafePtr gdbmi_result;
+    if (!parse_gdbmi_result (cur, cur, gdbmi_result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (gdbmi_result
+                   && gdbmi_result->variable () == "locals");
+
+    if (!gdbmi_result->value ()
+        || gdbmi_result->value ()->content_type ()
+            != GDBMIValue::LIST_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIListSafePtr gdbmi_list =
+        gdbmi_result->value ()->get_list_content ();
+    if (!gdbmi_list
+        || gdbmi_list->content_type () == GDBMIList::UNDEFINED_TYPE) {
+        a_to = cur;
+        a_vars.clear ();
+        return true;
+    }
+    RETURN_VAL_IF_FAIL (gdbmi_list->content_type () == GDBMIList::VALUE_TYPE,
+                        false);
+
+    std::list<GDBMIValueSafePtr> gdbmi_value_list;
+    gdbmi_list->get_value_content (gdbmi_value_list);
+    RETURN_VAL_IF_FAIL (!gdbmi_value_list.empty (), false);
+
+    std::list<IDebugger::VariableSafePtr> variables;
+    std::list<GDBMIValueSafePtr>::const_iterator value_iter;
+    std::list<GDBMIResultSafePtr> tuple_content;
+    std::list<GDBMIResultSafePtr>::const_iterator tuple_iter;
+    for (value_iter = gdbmi_value_list.begin ();
+         value_iter != gdbmi_value_list.end ();
+         ++value_iter) {
+        if (!(*value_iter)) {continue;}
+        if ((*value_iter)->content_type () != GDBMIValue::TUPLE_TYPE) {
+            LOG_ERROR_D ("list of tuple should contain only tuples",
+                         GDBMI_PARSING_DOMAIN);
+            continue;
+        }
+        GDBMITupleSafePtr gdbmi_tuple = (*value_iter)->get_tuple_content ();
+        RETURN_VAL_IF_FAIL (gdbmi_tuple, false);
+        RETURN_VAL_IF_FAIL (!gdbmi_tuple->content ().empty (), false);
+
+        tuple_content.clear ();
+        tuple_content = gdbmi_tuple->content ();
+        RETURN_VAL_IF_FAIL (!tuple_content.empty (), false);
+        IDebugger::VariableSafePtr variable (new IDebugger::Variable);
+        for (tuple_iter = tuple_content.begin ();
+             tuple_iter != tuple_content.end ();
+             ++tuple_iter) {
+            if (!(*tuple_iter)) {
+                LOG_ERROR_D ("got and empty tuple member",
+                             GDBMI_PARSING_DOMAIN);
+                continue;
+            }
+
+            if (!(*tuple_iter)->value ()
+                ||(*tuple_iter)->value ()->content_type ()
+                    != GDBMIValue::STRING_TYPE) {
+                LOG_ERROR_D ("Got a tuple member which value is not a string",
+                             GDBMI_PARSING_DOMAIN);
+                continue;
+            }
+
+            UString variable_str = (*tuple_iter)->variable ();
+            UString value_str =
+                        (*tuple_iter)->value ()->get_string_content ();
+            value_str.chomp ();
+            if (variable_str == "name") {
+                variable->name (value_str);
+            } else if (variable_str == "type") {
+                variable->type (value_str);
+            } else if (variable_str == "value") {
+                variable->value (value_str);
+            } else {
+                LOG_ERROR_D ("got an unknown tuple member with name: '"
+                             << variable_str << "'",
+                             GDBMI_PARSING_DOMAIN)
+                continue;
+            }
+
+        }
+        variables.push_back (variable);
+    }
+
+    LOG_D ("got '" << (int)variables.size () << "' variables",
+           GDBMI_PARSING_DOMAIN);
+
+    a_vars = variables;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_stack_arguments (UString::size_type a_from,
+                                    UString::size_type &a_to,
+                                    map<int, list<IDebugger::VariableSafePtr> >
+                                                                            &a_params)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_STACK_ARGS),
+                           PREFIX_STACK_ARGS)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIResultSafePtr gdbmi_result;
+    if (!parse_gdbmi_result (cur, cur, gdbmi_result)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    THROW_IF_FAIL (gdbmi_result
+                   && gdbmi_result->variable () == "stack-args");
+
+    if (!gdbmi_result->value ()
+        || gdbmi_result->value ()->content_type ()
+            != GDBMIValue::LIST_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    GDBMIListSafePtr gdbmi_list =
+        gdbmi_result->value ()->get_list_content ();
+    if (!gdbmi_list) {
+        a_to = cur;
+        a_params.clear ();
+        return true;
+    }
+
+    if (gdbmi_list->content_type () != GDBMIList::RESULT_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    list<GDBMIResultSafePtr> frames_params_list;
+    gdbmi_list->get_result_content (frames_params_list);
+    LOG_D ("number of frames: " << (int) frames_params_list.size (),
+           GDBMI_PARSING_DOMAIN);
+
+    list<GDBMIResultSafePtr>::const_iterator frames_iter,
+                                        params_records_iter,
+                                        params_iter;
+    map<int, list<IDebugger::VariableSafePtr> > all_frames_args;
+    //walk through the list of frames
+    //each frame is a tuple of the form:
+    //{level="2", args=[list-of-arguments]}
+    for (frames_iter = frames_params_list.begin ();
+         frames_iter != frames_params_list.end ();
+         ++frames_iter) {
+        if (!(*frames_iter)) {
+            LOG_D ("Got a null frmae, skipping", GDBMI_PARSING_DOMAIN);
+            continue;
+        }
+        THROW_IF_FAIL ((*frames_iter)->variable () != "stack");
+        THROW_IF_FAIL ((*frames_iter)->value ()
+                        && (*frames_iter)->value ()->content_type ()
+                        == GDBMIValue::TUPLE_TYPE)
+
+        //params_record is a tuple that has the form:
+        //{level="2", args=[list-of-arguments]}
+        GDBMITupleSafePtr params_record;
+        params_record = (*frames_iter)->value ()->get_tuple_content ();
+        THROW_IF_FAIL (params_record);
+
+        //walk through the tuple {level="2", args=[list-of-arguments]}
+        int cur_frame_level=-1;
+        for (params_records_iter = params_record->content ().begin ();
+             params_records_iter != params_record->content ().end ();
+             ++params_records_iter) {
+            THROW_IF_FAIL ((*params_records_iter)->value ());
+
+            if ((*params_records_iter)->variable () == "level") {
+                THROW_IF_FAIL
+                ((*params_records_iter)->value ()
+                 && (*params_records_iter)->value ()->content_type ()
+                 == GDBMIValue::STRING_TYPE);
+                cur_frame_level = atoi
+                    ((*params_records_iter)->value
+                         ()->get_string_content ().c_str ());
+                LOG_D ("frame level '" << (int) cur_frame_level << "'",
+                       GDBMI_PARSING_DOMAIN);
+            } else if ((*params_records_iter)->variable () == "args") {
+                //this gdbmi result is of the form:
+                //args=[{name="foo0", value="bar0"},
+                //      {name="foo1", bar="bar1"}]
+
+                THROW_IF_FAIL
+                ((*params_records_iter)->value ()
+                 && (*params_records_iter)->value ()->get_list_content ());
+
+                GDBMIListSafePtr arg_list =
+                    (*params_records_iter)->value ()->get_list_content ();
+                list<GDBMIValueSafePtr>::const_iterator args_as_value_iter;
+                list<IDebugger::VariableSafePtr> cur_frame_args;
+                if (arg_list && !(arg_list->empty ())) {
+                    LOG_D ("arg list is *not* empty for frame level '"
+                           << (int)cur_frame_level,
+                           GDBMI_PARSING_DOMAIN);
+                    //walk each parameter.
+                    //Each parameter is a tuple (in a value)
+                    list<GDBMIValueSafePtr> arg_as_value_list;
+                    arg_list->get_value_content (arg_as_value_list);
+                    LOG_D ("arg list size: "
+                           << (int)arg_as_value_list.size (),
+                           GDBMI_PARSING_DOMAIN);
+                    for (args_as_value_iter=arg_as_value_list.begin();
+                         args_as_value_iter!=arg_as_value_list.end();
+                         ++args_as_value_iter) {
+                        if (!*args_as_value_iter) {
+                            LOG_D ("got NULL arg, skipping",
+                                   GDBMI_PARSING_DOMAIN);
+                            continue;
+                        }
+                        GDBMITupleSafePtr args =
+                            (*args_as_value_iter)->get_tuple_content ();
+                        list<GDBMIResultSafePtr>::const_iterator arg_iter;
+                        IDebugger::VariableSafePtr parameter
+                                                (new IDebugger::Variable);
+                        THROW_IF_FAIL (parameter);
+                        THROW_IF_FAIL (args);
+                        //walk the name and value of the parameter
+                        for (arg_iter = args->content ().begin ();
+                             arg_iter != args->content ().end ();
+                             ++arg_iter) {
+                            THROW_IF_FAIL (*arg_iter);
+                            if ((*arg_iter)->variable () == "name") {
+                                THROW_IF_FAIL ((*arg_iter)->value ());
+                                parameter->name
+                                ((*arg_iter)->value()->get_string_content ());
+                            } else if ((*arg_iter)->variable () == "value") {
+                                THROW_IF_FAIL ((*arg_iter)->value ());
+                                parameter->value
+                                    ((*arg_iter)->value
+                                                 ()->get_string_content());
+                                UString::size_type pos;
+                                pos = parameter->value ().find ("{");
+                                if (pos != Glib::ustring::npos) {
+                                    //in certain cases
+                                    //(gdbmi is not strict enough to be sure)
+                                    //having a '{' in the parameter value
+                                    //means the parameter has an anonymous
+                                    //member variable. So let's try to
+                                    //parse an anonymous member variable
+                                    //and in case of success,
+                                    //fill parameter->members()
+                                    //with the structured member
+                                    //embedded in parameter->value()
+                                    //and set parameter->value() to nothing
+                                    //This is shity performancewise
+                                    //(and is ugly) but that's the way
+                                    //of gdbmi
+                                    push_input (parameter->value ());
+                                    if (parse_member_variable (pos, pos,
+                                                               parameter,
+                                                               true)) {
+                                        parameter->value ("");
+                                    } else {
+                                        LOG_ERROR ("Oops, '{' was not for "
+                                                   "for an embedded variable");
+                                    }
+                                    pop_input ();
+                                }
+                            } else {
+                                THROW ("should not reach this line");
+                            }
+                        }
+                        LOG_D ("pushing arg '"
+                               <<parameter->name()
+                               <<"'='"<<parameter->value() <<"'"
+                               <<" for frame level='"
+                               <<(int)cur_frame_level
+                               <<"'",
+                               GDBMI_PARSING_DOMAIN);
+                        cur_frame_args.push_back (parameter);
+                    }
+                } else {
+                    LOG_D ("arg list is empty for frame level '"
+                           << (int)cur_frame_level,
+                           GDBMI_PARSING_DOMAIN);
+                }
+                THROW_IF_FAIL (cur_frame_level >= 0);
+                LOG_D ("cur_frame_level: '"
+                       << (int) cur_frame_level
+                       << "', NB Params: "
+                       << (int) cur_frame_args.size (),
+                       GDBMI_PARSING_DOMAIN);
+                all_frames_args[cur_frame_level] = cur_frame_args;
+            } else {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+        }
+
+    }
+
+    a_to = cur;
+    a_params = all_frames_args;
+    LOG_D ("number of frames parsed: " << (int)a_params.size (),
+           GDBMI_PARSING_DOMAIN);
+    return true;
+}
+
+bool
+GDBMIParser::parse_member_variable (const UString::size_type a_from,
+                                    UString::size_type &a_to,
+                                    IDebugger::VariableSafePtr &a_var,
+                                    bool a_in_unnamed_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    LOG_D ("in_unnamed_var = " <<(int)a_in_unnamed_var, GDBMI_PARSING_DOMAIN);
+    THROW_IF_FAIL (a_var);
+
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_CHAR_AT (cur) != '{') {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    ++cur;
+    CHECK_END2 (cur);
+
+    UString name, value;
+    UString::size_type name_start=0, name_end=0, value_start=0, value_end=0;
+
+    while (true /*fetch name*/) {
+        name_start=0, name_end=0, value_start=0, value_end=0;
+        name = "#unnamed#" , value = "";
+
+        SKIP_BLANK2 (cur);
+        LOG_D ("fetching name ...", GDBMI_PARSING_DOMAIN);
+        //we should be at the begining of A = B. lets try to parse A
+        if (RAW_CHAR_AT (cur) != '{') {
+            SKIP_BLANK2 (cur);
+            name_start = cur;
+            while (true) {
+                if (!m_priv->index_passed_end (cur)
+                    && RAW_CHAR_AT (cur) != '='
+                    && RAW_CHAR_AT (cur) != '}') {
+                    ++cur;
+                } else {
+                    //if we found an '}' character, make sure
+                    //it is not enclosed in sigle quotes. If it is in
+                    //single quotes then ignore it.
+                    if (cur > 0
+                        && !m_priv->index_passed_end (cur+1)
+                        && RAW_CHAR_AT (cur-1) == '\''
+                        && RAW_CHAR_AT (cur+1) == '\'') {
+                        ++cur;
+                        continue;
+                    }
+                    break;
+                }
+            }
+            //we should be at the end of A (as in A = B)
+            name_end = cur - 1;
+            name.assign (RAW_INPUT, name_start, name_end - name_start + 1);
+            LOG_D ("got name '" << name << "'", GDBMI_PARSING_DOMAIN);
+        }
+
+        IDebugger::VariableSafePtr cur_var (new IDebugger::Variable);
+        name.chomp ();
+        cur_var->name (name);
+
+        if (RAW_CHAR_AT (cur) == '}') {
+            ++cur;
+            cur_var->value ("");
+            a_var->append (cur_var);
+            LOG_D ("reached '}' after '"
+                   << name << "'",
+                   GDBMI_PARSING_DOMAIN);
+            break;
+        }
+
+        SKIP_BLANK2 (cur);
+        if (RAW_CHAR_AT (cur) != '{') {
+            ++cur;
+            CHECK_END2 (cur);
+            SKIP_BLANK2 (cur);
+        }
+
+        //if we are at a '{', (like in A = {B}),
+        //the B is said to be a member variable of A
+        //you can also call it a member attribute of A
+        //In this case, let's try to parse {B}
+        if (RAW_CHAR_AT (cur) == '{') {
+            bool in_unnamed = true;
+            if (name == "#unnamed#") {
+                in_unnamed = false;
+            }
+            if (!parse_member_variable (cur, cur, cur_var, in_unnamed)) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+        } else {
+            //else, we are at a B, (like in A = B),
+            //so let's try to parse B
+            SKIP_BLANK2 (cur);
+            value_start = cur;
+            while (true) {
+                UString str;
+                if ( RAW_CHAR_AT (cur) == '"'
+                    && RAW_CHAR_AT (cur -1) != '\\') {
+                    if (!parse_c_string (cur, cur, str)) {
+                        LOG_PARSING_ERROR2 (cur);
+                        return false;
+                    }
+                } else if (!m_priv->index_passed_end (cur+2)
+                           && RAW_CHAR_AT (cur) == '\\'
+                           && RAW_CHAR_AT (cur+1) == '"'
+                           && RAW_CHAR_AT (cur+2) != '\''
+                           && RAW_CHAR_AT (cur-1) != '\'') {
+                    if (!parse_embedded_c_string (cur, cur, str)){
+                        LOG_PARSING_ERROR2 (cur);
+                        return false;
+                    }
+                } else if ((RAW_CHAR_AT (cur) != ','
+                               || ((!m_priv->index_passed_end (cur+1))
+                                   && RAW_CHAR_AT (cur+1) != ' '))
+                           && RAW_CHAR_AT (cur) != '}') {
+                    ++cur;
+                    CHECK_END2 (cur);
+                } else {
+                    //if we found an '}' character, make sure
+                    //it is not enclosed in sigle quotes. If it is in
+                    //single quotes then ignore it.
+                    if (cur > 0
+                        && !m_priv->index_passed_end (cur+1)
+                        && RAW_CHAR_AT (cur-1) == '\''
+                        && RAW_CHAR_AT (cur+1) == '\'') {
+                        ++cur;
+                        continue;
+                    }
+                    //otherwise, getting out condition is either
+                    //", " or "}".  check out the the 'if' condition.
+                    break;
+                }
+            }
+            if (cur != value_start) {
+                value_end = cur - 1;
+                value.assign (RAW_INPUT, value_start,
+                              value_end - value_start + 1);
+                LOG_D ("got value: '"
+                       << value << "'",
+                       GDBMI_PARSING_DOMAIN);
+            } else {
+                value = "";
+                LOG_D ("got empty value", GDBMI_PARSING_DOMAIN);
+            }
+            cur_var->value (value);
+        }
+        a_var->append (cur_var);
+
+        LOG_D ("cur char: " << (char) RAW_CHAR_AT (cur),
+               GDBMI_PARSING_DOMAIN);
+
+end_of_block:
+        SKIP_BLANK2 (cur);
+
+        LOG_D ("cur char: " << (char) RAW_CHAR_AT (cur),
+                GDBMI_PARSING_DOMAIN);
+
+        if (m_priv->index_passed_end (cur) || RAW_CHAR_AT (cur) == '"') {
+            break;
+        } else if (RAW_CHAR_AT (cur) == '}') {
+            ++cur;
+            break;
+        } else if (RAW_CHAR_AT (cur) == ',') {
+            ++cur;
+            CHECK_END2 (cur);
+            LOG_D ("got ',' , going to fetch name",
+                   GDBMI_PARSING_DOMAIN);
+            continue /*goto fetch name*/;
+        } else if (!RAW_INPUT.compare (cur, 9, "<repeats ")) {
+            //TODO: we need to handle the <repeat N> format at some point.
+            //just skipping it for now.
+            bool skipped_repeat=false;
+            while (true) {
+                ++cur;
+                if (m_priv->index_passed_end (cur)) {break;}
+                if (RAW_CHAR_AT (cur) == '>') {
+                    ++cur;
+                    skipped_repeat = true;
+                    break;
+                }
+            }
+            if (skipped_repeat) {
+                LOG_D ("skipped repeat construct", GDBMI_PARSING_DOMAIN);
+                goto end_of_block;
+                break;
+            } else {
+                LOG_ERROR ("failed to skip repeat construct");
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+        } else if (!RAW_INPUT.compare (cur, 3, "...")) {
+            //hugh ? wtf does this '...' mean ? Anyway, skip it for now.
+            cur+= 3;
+            goto end_of_block;
+        }
+        LOG_PARSING_ERROR2 (cur);
+        THROW ("should not be reached");
+    }//end while
+
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_variable_value (const UString::size_type a_from,
+                                   UString::size_type &a_to,
+                                   IDebugger::VariableSafePtr &a_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+    CHECK_END2 (cur);
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_VALUE), PREFIX_VALUE)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    cur += 6;
+    CHECK_END2 (cur);
+    CHECK_END2 (cur+1);
+
+    a_var = IDebugger::VariableSafePtr (new IDebugger::Variable);
+    if (RAW_CHAR_AT (cur+1) == '{') {
+        ++cur;
+        if (!parse_member_variable (cur, cur, a_var)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        SKIP_BLANK2 (cur);
+        if (RAW_CHAR_AT (cur) != '"') {
+            UString value ;
+            if (!parse_c_string_body (cur, m_priv->end, value)) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            value = a_var->value () + " " + value;
+            a_var->value (value);
+        }
+    } else {
+        UString value;
+        if (!parse_c_string (cur, cur, value)) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        a_var->value (value);
+    }
+
+    ++cur;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_register_names (UString::size_type a_from,
+                                   UString::size_type &a_to,
+                                   std::map<IDebugger::register_id_t,
+                                   UString> &a_registers)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_REGISTER_NAMES),
+                           PREFIX_REGISTER_NAMES)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += strlen (PREFIX_REGISTER_NAMES);
+
+    GDBMIListSafePtr reg_list;
+    if (!parse_gdbmi_list (cur, cur, reg_list)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur-1) != ']') {
+        //unexpected data
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    std::map<IDebugger::register_id_t, UString> regs;
+    if (reg_list->content_type () != GDBMIList::VALUE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    std::list<GDBMIValueSafePtr> value_list;
+    reg_list->get_value_content (value_list);
+    IDebugger::register_id_t id = 0;
+    std::list<GDBMIValueSafePtr>::const_iterator val_iter;
+    for (val_iter = value_list.begin();
+         val_iter != value_list.end();
+         ++val_iter, ++id) {
+        UString regname = (*val_iter)->get_string_content ();
+        regs[id] = regname;
+    }
+
+    a_registers = regs;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_changed_registers (UString::size_type a_from,
+                                      UString::size_type &a_to,
+                                      std::list<IDebugger::register_id_t> &a_registers)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_CHANGED_REGISTERS),
+                           PREFIX_CHANGED_REGISTERS)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += strlen (PREFIX_CHANGED_REGISTERS);
+
+    GDBMIListSafePtr reg_list;
+    if (!parse_gdbmi_list (cur, cur, reg_list)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur-1) != ']') {
+        // unexpected data
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    std::list<IDebugger::register_id_t> regs;
+    if (!reg_list->empty () &&
+            reg_list->content_type () != GDBMIList::VALUE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    std::list<GDBMIValueSafePtr> value_list;
+    reg_list->get_value_content (value_list);
+    for (std::list<GDBMIValueSafePtr>::const_iterator val_iter =
+            value_list.begin ();
+            val_iter != value_list.end ();
+            ++val_iter) {
+        UString regname = (*val_iter)->get_string_content ();
+        regs.push_back (atoi (regname.c_str ()));
+    }
+
+    a_registers = regs;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_register_values (UString::size_type a_from,
+                                    UString::size_type &a_to,
+                                    std::map<IDebugger::register_id_t, UString>
+                                                                        &a_values)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_REGISTER_VALUES),
+                           PREFIX_REGISTER_VALUES)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += strlen (PREFIX_REGISTER_VALUES);
+
+    GDBMIListSafePtr gdbmi_list;
+    if (!parse_gdbmi_list (cur, cur, gdbmi_list)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    if (RAW_CHAR_AT (cur-1) != ']') {
+        // unexpected data
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    std::map<IDebugger::register_id_t, UString> vals;
+    if (gdbmi_list->content_type () != GDBMIList::VALUE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    std::list<GDBMIValueSafePtr> val_list;
+    gdbmi_list->get_value_content (val_list);
+    std::list<GDBMIValueSafePtr>::const_iterator val_iter;
+    for (val_iter = val_list.begin ();
+         val_iter != val_list.end ();
+         ++val_iter) {
+        UString value_str;
+        if ((*val_iter)->content_type ()
+            != GDBMIValue::TUPLE_TYPE) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        GDBMITupleSafePtr tuple = (*val_iter)->get_tuple_content ();
+        std::list<GDBMIResultSafePtr> result_list = tuple->content ();
+        if (result_list.size () != 2) {
+            // each tuple should have a 'number' and 'value' field
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        std::list<GDBMIResultSafePtr>::const_iterator res_iter =
+                                                result_list.begin ();
+        // get register number
+        GDBMIValueSafePtr reg_number_val = (*res_iter)->value ();
+        if ((*res_iter)->variable () != "number"
+            || reg_number_val->content_type () != GDBMIValue::STRING_TYPE) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        }
+        IDebugger::register_id_t id =
+                atoi (reg_number_val->get_string_content ().c_str ());
+
+        // get the new value of the register
+        ++res_iter;
+        GDBMIValueSafePtr reg_value_val = (*res_iter)->value ();
+        if ((*res_iter)->variable () != "value"
+            || reg_value_val->content_type () != GDBMIValue::STRING_TYPE) {
+            LOG_PARSING_ERROR2 (cur);
+            return false;
+        } else {
+            value_str = reg_value_val->get_string_content ();
+        }
+        vals[id] = value_str;
+    }
+
+    a_values = vals;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_memory_values (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  size_t& a_start_addr,
+                                  std::vector<uint8_t> &a_values)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_D (GDBMI_PARSING_DOMAIN);
+    UString::size_type cur = a_from;
+
+    if (RAW_INPUT.compare (cur, strlen (PREFIX_MEMORY_VALUES),
+                           PREFIX_MEMORY_VALUES)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    //skip to the actual list of memory values
+    const char* prefix_memory = "memory=";
+    cur = RAW_INPUT.find (prefix_memory);
+    if (!cur) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    cur += strlen (prefix_memory);
+
+    GDBMIListSafePtr mem_gdbmi_list;
+    if (!parse_gdbmi_list (cur, cur, mem_gdbmi_list)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur-1) != ']') {
+        //unexpected data
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (mem_gdbmi_list->content_type ()
+        != GDBMIList::VALUE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+    std::list<GDBMIValueSafePtr> mem_value_list;
+    mem_gdbmi_list->get_value_content (mem_value_list);
+
+    //there should only be one 'row'
+    if (mem_value_list.size () != 1) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    std::list<GDBMIValueSafePtr>::const_iterator mem_tuple_iter =
+                                                    mem_value_list.begin ();
+    if ((*mem_tuple_iter)->content_type ()
+        != GDBMIValue::TUPLE_TYPE) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    const GDBMITupleSafePtr gdbmi_tuple =
+                            (*mem_tuple_iter)->get_tuple_content ();
+
+    std::list<GDBMIResultSafePtr> result_list;
+    result_list = gdbmi_tuple->content ();
+    if (result_list.size () < 2) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    std::vector<uint8_t> memory_values;
+    bool seen_addr = false, seen_data = false;
+    std::list<GDBMIResultSafePtr>::const_iterator result_iter;
+    for (result_iter = result_list.begin ();
+         result_iter != result_list.end ();
+         ++result_iter) {
+        if ((*result_iter)->variable () == "addr") {
+            seen_addr = true;
+            if ((*result_iter)->value ()->content_type ()
+                != GDBMIValue::STRING_TYPE) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            std::istringstream istream
+                            ((*result_iter)->value ()-> get_string_content ());
+            istream >> std::hex >> a_start_addr;
+        } else if ((*result_iter)->variable () == "data") {
+            seen_data = true;
+            if ((*result_iter)->value ()->content_type ()
+                != GDBMIValue::LIST_TYPE) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            GDBMIListSafePtr gdbmi_list =
+                            (*result_iter)->value ()->get_list_content ();
+            if (gdbmi_list->content_type () != GDBMIList::VALUE_TYPE) {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            std::list<GDBMIValueSafePtr> gdbmi_values;
+            gdbmi_list->get_value_content (gdbmi_values);
+            std::list<GDBMIValueSafePtr>::const_iterator val_iter;
+            for (val_iter = gdbmi_values.begin ();
+                 val_iter != gdbmi_values.end ();
+                 ++val_iter) {
+                if ((*val_iter)->content_type ()
+                    != GDBMIValue::STRING_TYPE) {
+                    LOG_PARSING_ERROR2 (cur);
+                    return false;
+                }
+                std::istringstream istream
+                                        ((*val_iter)->get_string_content ());
+                //if I use a uint8_t type here, it doesn't seem to work, so
+                //using a 16-bit value that will be cast down to 8 bits
+                uint16_t byte_val;
+                istream >> std::hex >> byte_val;
+                memory_values.push_back (byte_val);
+            }
+        }
+        //else ignore it
+    }
+
+    if (!seen_addr || !seen_data) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    a_values = memory_values;
+    a_to = cur;
+    return true;
+}
+
+bool
+GDBMIParser::parse_overloads_choice_prompt
+                        (UString::size_type a_from,
+                         UString::size_type &a_to,
+                         vector<IDebugger::OverloadsChoiceEntry> &a_prompts)
+{
+    UString::size_type cur=a_from;
+    gunichar c = 0;
+
+    if (m_priv->index_passed_end (cur)) {
+        LOG_PARSING_ERROR2 (cur);
+        return false;
+    }
+
+    if (RAW_CHAR_AT (cur) != '[') {
+        LOG_PARSING_ERROR2 (cur);
+    }
+    c = RAW_CHAR_AT (cur);
+
+    string index_str;
+    vector<IDebugger::OverloadsChoiceEntry> prompts;
+    while (c == '[') {
+        ++cur;
+        CHECK_END2 (cur);
+        index_str.clear ();
+        c = RAW_CHAR_AT (cur);
+        //look for the numerical index of the current prompt entry
+        for (;;) {
+            CHECK_END2 (cur);
+            c = RAW_CHAR_AT (cur);
+            if (isdigit (c)) {
+                index_str += RAW_CHAR_AT (cur);
+            } else if (c == ']') {
+                break;
+            } else {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            ++cur;
+            if (m_priv->index_passed_end (cur))
+                break;
+            c = RAW_CHAR_AT (cur);
+        }
+        //we should have the numerical index of the current prompt entry
+        //by now.
+        if (index_str.empty ()) {
+            LOG_ERROR ("Could not parse prompt index");
+            return false;
+        }
+        LOG_DD ("prompt index: " << index_str);
+        ++cur;
+        CHECK_END2 (cur);
+        SKIP_WS2 (cur);
+        c = RAW_CHAR_AT (cur);
+
+        //now parse the prompt value.
+        //it is either  "all", "cancel", or a function name/file location.
+        IDebugger::OverloadsChoiceEntry entry;
+        entry.index (atoi (index_str.c_str ()));
+        if (m_priv->end - cur >= 3
+            && !RAW_INPUT.compare (cur, 3, "all")) {
+            entry.kind (IDebugger::OverloadsChoiceEntry::ALL);
+            cur += 3;
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+            LOG_DD ("pushing entry: " << (int) entry.index ()
+                    << ", all" );
+            prompts.push_back (entry);
+            if (!m_priv->index_passed_end (cur+1)
+                && c == '\\' && RAW_CHAR_AT (cur+1) == 'n') {
+                cur += 2;
+                c = RAW_CHAR_AT (cur);
+            }
+        } else if  (m_priv->end - cur >= 6
+                    && !RAW_INPUT.compare (cur, 6, "cancel")) {
+            entry.kind (IDebugger::OverloadsChoiceEntry::CANCEL);
+            cur += 6;
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+            LOG_DD ("pushing entry: " << (int) entry.index ()
+                    << ", cancel");
+            prompts.push_back (entry);
+            if (!m_priv->index_passed_end (cur+1)
+                && c == '\\' && RAW_CHAR_AT (cur+1) == 'n') {
+                cur += 2;
+                c = RAW_CHAR_AT (cur);
+            }
+        } else {
+            //try to parse a breakpoint location
+            UString function_name, file_name, line_num;
+            UString::size_type b=0, e=0;
+            b = cur;
+            while (!m_priv->index_passed_end (cur)
+                   && RAW_INPUT.compare (cur, 4, " at ")) {
+                ++cur;
+            }
+            c = RAW_CHAR_AT (cur);
+            if (!m_priv->index_passed_end (cur)
+                && !RAW_INPUT.compare (cur, 4, " at ")) {
+                e = cur;
+            } else {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            function_name.assign (RAW_INPUT, b, e-b);
+
+            cur += 4;
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+            b=cur; e=0;
+            while (c != ':') {
+                ++cur;
+                if (m_priv->index_passed_end (cur))
+                    break;
+                c = RAW_CHAR_AT (cur);
+            }
+            if (!m_priv->index_passed_end (cur) && c == ':') {
+                e = cur;
+            } else {
+                LOG_PARSING_ERROR2 (cur);
+                return false;
+            }
+            file_name.assign (RAW_INPUT, b, e-b);
+            ++cur;
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+
+            while (isdigit (c)) {
+                line_num += c;
+                ++cur;
+                if (m_priv->index_passed_end (cur))
+                    break;
+                c = RAW_CHAR_AT (cur);
+            }
+            entry.kind (IDebugger::OverloadsChoiceEntry::LOCATION);
+            entry.function_name (function_name);
+            entry.file_name (file_name);
+            entry.line_number (atoi (line_num.c_str ()));
+            LOG_DD ("pushing entry: " << (int) entry.index ()
+                    << ", " << entry.function_name ());
+            prompts.push_back (entry);
+            if (m_priv->index_passed_end (cur)) {
+                LOG_DD ("reached end, getting out");
+                break;
+            }
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+            if (!m_priv->index_passed_end (cur+1)
+                && c == '\\' && RAW_CHAR_AT (cur+1) == 'n') {
+                cur += 2;
+                c = RAW_CHAR_AT (cur);
+            }
+            SKIP_WS2 (cur);
+            c = RAW_CHAR_AT (cur);
+            if (m_priv->index_passed_end (cur))
+                break;
+        }
+    }//end while//parse a prompt entry
+    if (prompts.empty ())
+        return false;
+    a_prompts = prompts;
+    a_to = cur;
+    return true;
+}
+
+//******************************
+//</Parser methods>
+//******************************
 NEMIVER_END_NAMESPACE (nemiver)
 
 

Modified: trunk/src/dbgengine/nmv-gdbmi-parser.h
==============================================================================
--- trunk/src/dbgengine/nmv-gdbmi-parser.h	(original)
+++ trunk/src/dbgengine/nmv-gdbmi-parser.h	Sun Nov 30 13:27:49 2008
@@ -298,6 +298,13 @@
 //</gdbmi datastructure streaming operators>
 //******************************************
 
+bool gdbmi_result_to_string (GDBMIResultSafePtr a_result, UString &a_string);
+
+bool gdbmi_list_to_string (GDBMIListSafePtr a_list, UString &a_string);
+
+bool gdbmi_value_to_string (GDBMIValueSafePtr a_value, UString &a_string);
+
+bool gdbmi_tuple_to_string (GDBMITupleSafePtr a_result, UString &a_string);
 
 //**************************
 //GDBMI parsing functions
@@ -546,6 +553,10 @@
                           int &a_thread_id,
                           IDebugger::Frame &a_frame);
 
+bool parse_c_string_body (const UString &a_input,
+                          UString::size_type a_from,
+                          UString::size_type &a_to,
+                          UString &a_string);
 /// parses a string that has the form:
 /// \"blah\"
 bool parse_c_string (const UString &a_input,
@@ -594,6 +605,192 @@
                           size_t& a_start_addr,
                           std::vector<uint8_t> &a_values);
 
+class GDBMIParser {
+    // non copyable
+    GDBMIParser (const GDBMIParser &);
+    GDBMIParser& operator= (const GDBMIParser &);
+    struct Priv;
+    SafePtr<Priv> m_priv;
+
+public:
+
+    /// Parsing mode.
+    enum Mode {
+        UNDEFINED_MODE=0,
+        // This one means we adhere to the strict MI syntax.
+        STRICT_MODE,
+        // This one means we try to accept the broken MI ouptut from GDB,
+        // even those that are not MI compliant. This is implies best effort strategy.
+        BROKEN_MODE,
+    };
+    explicit GDBMIParser (Mode a_mode = STRICT_MODE);
+    explicit GDBMIParser (const UString &a_input, Mode a_mode = STRICT_MODE);
+    virtual ~GDBMIParser ();
+
+    void push_input (const UString &a_input);
+    void pop_input ();
+    const UString& get_input () const;
+
+    void set_mode (Mode);
+    Mode get_mode () const;
+
+    //*********************
+    //<Parsing entry points.>
+    //*********************
+
+    bool parse_string (UString::size_type a_from,
+                       UString::size_type &a_to,
+                       UString &a_string);
+
+    bool parse_octal_escape (UString::size_type a_from,
+                             UString::size_type &a_to,
+                             unsigned char &a_byte_value);
+
+    bool parse_octal_escape_sequence (UString::size_type a_from,
+                                      UString::size_type &a_to,
+                                      UString &a_result);
+
+    bool parse_c_string_body (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              UString &a_string);
+
+    bool parse_c_string (UString::size_type a_from,
+                         UString::size_type &a_to,
+                         UString &a_c_string);
+
+    bool parse_embedded_c_string_body (UString::size_type a_from,
+                                       UString::size_type &a_to,
+                                       UString &a_string);
+
+    bool parse_embedded_c_string (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  UString &a_string) ;
+
+    bool parse_gdbmi_result (UString::size_type a_from,
+                             UString::size_type &a_to,
+                             GDBMIResultSafePtr &a_value);
+
+    bool parse_gdbmi_value (UString::size_type a_from,
+                            UString::size_type &a_to,
+                            GDBMIValueSafePtr &a_value) ;
+
+    bool parse_gdbmi_tuple (UString::size_type a_from,
+                            UString::size_type &a_to,
+                            GDBMITupleSafePtr &a_tuple);
+
+    bool parse_gdbmi_list (UString::size_type a_from,
+                           UString::size_type &a_to,
+                           GDBMIListSafePtr &a_list);
+
+    bool parse_stream_record (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              Output::StreamRecord &a_record);
+
+    bool parse_stopped_async_output (UString::size_type a_from,
+                                     UString::size_type &a_to,
+                                     bool &a_got_frame,
+                                     IDebugger::Frame &a_frame,
+                                     map<UString, UString> &a_attrs);
+
+    bool parse_running_async_output (UString::size_type a_from,
+                                     UString::size_type &a_to,
+                                     int &a_thread_id);
+
+    bool parse_attribute (UString::size_type a_from,
+                          UString::size_type &a_to,
+                          UString &a_name,
+                          UString &a_value);
+
+    bool parse_attributes (UString::size_type a_from,
+                           UString::size_type &a_to,
+                           map<UString, UString> &a_attrs);
+
+    bool parse_frame (UString::size_type a_from,
+                      UString::size_type &a_to,
+                      IDebugger::Frame &a_frame);
+
+    bool parse_out_of_band_record (UString::size_type a_from,
+                                   UString::size_type &a_to,
+                                   Output::OutOfBandRecord &a_record);
+
+    bool parse_breakpoint (Glib::ustring::size_type a_from,
+                           Glib::ustring::size_type &a_to,
+                           IDebugger::BreakPoint &a_bkpt);
+
+    bool parse_breakpoint_table (UString::size_type a_from,
+                                 UString::size_type &a_to,
+                                 map<int, IDebugger::BreakPoint> &a_breakpoints);
+
+    bool parse_threads_list (UString::size_type a_from,
+                             UString::size_type &a_to,
+                             std::list<int> &a_thread_ids);
+
+    bool parse_new_thread_id (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              int &a_thread_id,
+                              IDebugger::Frame &a_frame);
+
+    bool parse_file_list (UString::size_type a_from,
+                          UString::size_type &a_to,
+                          std::vector<UString> &a_files);
+
+    bool parse_call_stack (const UString::size_type a_from,
+                           UString::size_type &a_to,
+                           vector<IDebugger::Frame> &a_stack);
+
+    bool parse_stack_arguments (UString::size_type a_from,
+                                UString::size_type &a_to,
+                                map<int, list<IDebugger::VariableSafePtr> > &a_params);
+
+    bool parse_local_var_list (UString::size_type a_from,
+                               UString::size_type &a_to,
+                               list<IDebugger::VariableSafePtr> &a_vars);
+
+    bool parse_member_variable (const UString::size_type a_from,
+                                UString::size_type &a_to,
+                                IDebugger::VariableSafePtr &a_var,
+                                bool a_in_unnamed_var=false);
+
+    bool parse_variable_value (const UString::size_type a_from,
+                               UString::size_type &a_to,
+                               IDebugger::VariableSafePtr &a_var);
+
+    bool parse_overloads_choice_prompt
+                        (UString::size_type a_from,
+                         UString::size_type &a_to,
+                         vector<IDebugger::OverloadsChoiceEntry> &a_prompts);
+
+    bool parse_register_names (UString::size_type a_from,
+                               UString::size_type &a_to,
+                               std::map<IDebugger::register_id_t,
+                                        UString> &a_registers);
+
+    bool parse_changed_registers (UString::size_type a_from,
+                                  UString::size_type &a_to,
+                                  std::list<IDebugger::register_id_t> &a_registers);
+
+    bool parse_register_values (UString::size_type a_from,
+                                UString::size_type &a_to,
+                                std::map<IDebugger::register_id_t, UString> &a_values);
+
+    bool parse_memory_values (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              size_t& a_start_addr,
+                              std::vector<uint8_t> &a_values);
+
+    bool parse_result_record (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              Output::ResultRecord &a_record);
+
+
+    bool parse_output_record (UString::size_type a_from,
+                              UString::size_type &a_to,
+                              Output &a_output);
+    //*********************
+    //</Parsing entry points.>
+    //*********************
+};//end class GDBMIParser
+
 NEMIVER_END_NAMESPACE (nemiver)
 #endif //__NMV_GDBMI_PARSER_H
 

Modified: trunk/tests/test-gdbmi.cc
==============================================================================
--- trunk/tests/test-gdbmi.cc	(original)
+++ trunk/tests/test-gdbmi.cc	Sun Nov 30 13:27:49 2008
@@ -13,6 +13,7 @@
 static const char* gv_str2 = "\"No symbol \\\"events_ecal\\\" in current context.\\n\"" ;
 
 static const char* gv_attrs0 = "msg=\"No symbol \\\"g_return_if_fail\\\" in current context.\"" ;
+static const char* gv_attrs1 = "script=[\"silent\",\"return\"]" ;
 
 static const char* gv_stopped_async_output0 =
 "*stopped,reason=\"breakpoint-hit\",bkptno=\"1\",thread-id=\"1\",frame={addr=\"0x0804afb0\",func=\"main\",args=[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\"0xbfc79ed4\"}],file=\"today-main.c\",fullname=\"/home/dodji/devel/gitstore/omoko.git/applications/openmoko-today/src/today-main.c\",line=\"285\"}\n" ;
@@ -102,6 +103,8 @@
 static const char* gv_memory_values =
 "addr=\"0x000013a0\",nr-bytes=\"32\",total-bytes=\"32\",next-row=\"0x000013c0\",prev-row=\"0x0000139c\",next-page=\"0x000013c0\",prev-page=\"0x00001380\",memory=[{addr=\"0x000013a0\",data=[\"0x10\",\"0x11\",\"0x12\",\"0x13\"],ascii=\"xxxx\"}]";
 
+static const char* gv_gdbmi_result0 = "variable=[\"foo\", \"bar\"]";
+
 static const char* gv_breakpoint_table0 =
 "BreakpointTable={nr_rows=\"1\",nr_cols=\"6\",hdr=[{width=\"3\",alignment=\"-1\",col_name=\"number\",colhdr=\"Num\"},{width=\"14\",alignment=\"-1\",col_name=\"type\",colhdr=\"Type\"},{width=\"4\",alignment=\"-1\",col_name=\"disp\",colhdr=\"Disp\"},{width=\"3\",alignment=\"-1\",col_name=\"enabled\",colhdr=\"Enb\"},{width=\"10\",alignment=\"-1\",col_name=\"addr\",colhdr=\"Address\"},{width=\"40\",alignment=\"2\",col_name=\"what\",colhdr=\"What\"}],body=[bkpt={number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"0x08081566\",func=\"main\",file=\"main.cc\",fullname=\"/home/jonathon/Projects/agave.git/src/main.cc\",line=\"70\",times=\"0\"}]}";
 
@@ -120,7 +123,9 @@
 
     UString res ;
     UString::size_type to=0 ;
-    is_ok = parse_c_string (gv_str0, 0, to, res) ;
+
+    GDBMIParser parser (gv_str0);
+    is_ok = parser.parse_c_string (0, to, res);
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE (res == "abracadabra") ;
 }
@@ -132,7 +137,10 @@
 
     UString res ;
     UString::size_type to=0 ;
-    is_ok = parse_c_string (gv_str1, 0, to, res) ;
+
+    GDBMIParser parser (gv_str1);
+    is_ok = parser.parse_c_string (0, to, res);
+
     BOOST_REQUIRE (is_ok) ;
     MESSAGE ("got string: '" << Glib::locale_from_utf8 (res) << "'") ;
     BOOST_REQUIRE_MESSAGE (res.size () == 32, "res size was: " << res.size ());
@@ -145,7 +153,10 @@
 
     UString res ;
     UString::size_type to=0 ;
-    is_ok = parse_c_string (gv_str2, 0, to, res) ;
+
+    GDBMIParser parser (gv_str2);
+    is_ok = parser.parse_c_string (0, to, res);
+
     BOOST_REQUIRE (is_ok) ;
     MESSAGE ("got string: '" << Glib::locale_from_utf8 (res) << "'") ;
     BOOST_REQUIRE_MESSAGE (res.size (), "res size was: " << res.size ());
@@ -158,10 +169,22 @@
 
     UString name,value ;
     UString::size_type to=0 ;
-    is_ok = parse_attribute (gv_attrs0, 0, to, name, value) ;
+
+    GDBMIParser parser (gv_attrs0);
+
+    name.clear (), value.clear ();
+    is_ok = parser.parse_attribute (0, to, name, value) ;
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE_MESSAGE (name == "msg", "got name: " << name) ;
     BOOST_REQUIRE_MESSAGE (value.size(), "got empty value") ;
+
+    name.clear (), value.clear ();
+    parser.push_input (gv_attrs1);
+    is_ok = parser.parse_attribute (0, to, name, value) ;
+    BOOST_REQUIRE (is_ok) ;
+    BOOST_REQUIRE_MESSAGE (name == "script", "got name: " << name) ;
+    BOOST_REQUIRE_MESSAGE (value == "[silent,return]", "got empty value") ;
+
 }
 
 void
@@ -172,18 +195,21 @@
     IDebugger::Frame frame ;
     map<UString, UString> attrs ;
 
-    is_ok = parse_stopped_async_output (gv_stopped_async_output0, 0, to,
-                                        got_frame, frame, attrs) ;
+    GDBMIParser parser (gv_stopped_async_output0);
+
+    is_ok = parser.parse_stopped_async_output (0, to,
+                                               got_frame,
+                                               frame, attrs);
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE (got_frame) ;
     BOOST_REQUIRE (attrs.size ()) ;
 
     to=0;
-    is_ok = parse_stopped_async_output (gv_stopped_async_output1, 0, to,
-                                        got_frame, frame, attrs) ;
-    BOOST_REQUIRE (is_ok) ;
-    BOOST_REQUIRE (got_frame) ;
-    BOOST_REQUIRE (attrs.size ()) ;
+    parser.push_input (gv_stopped_async_output1);
+    is_ok = parser.parse_stopped_async_output (0, to, got_frame, frame, attrs);
+    BOOST_REQUIRE (is_ok);
+    BOOST_REQUIRE (got_frame);
+    BOOST_REQUIRE (attrs.size ());
 }
 
 void
@@ -193,16 +219,18 @@
     UString::size_type to=0 ;
     int thread_id=0;
 
-    is_ok = parse_running_async_output (gv_running_async_output0, 0, to,
-                                        thread_id) ;
-    BOOST_REQUIRE (is_ok) ;
-    BOOST_REQUIRE (thread_id == -1) ;
+    GDBMIParser parser (gv_running_async_output0);
+
+    is_ok = parser.parse_running_async_output (0, to, thread_id);
+    BOOST_REQUIRE (is_ok);
+    BOOST_REQUIRE (thread_id == -1);
+
+    parser.push_input (gv_running_async_output1);
 
     to=0;
-    is_ok = parse_running_async_output (gv_running_async_output1, 0, to,
-                                        thread_id) ;
-    BOOST_REQUIRE (is_ok) ;
-    BOOST_REQUIRE (thread_id == 1) ;
+    is_ok = parser.parse_running_async_output (0, to, thread_id);
+    BOOST_REQUIRE (is_ok);
+    BOOST_REQUIRE (thread_id == 1);
 }
 
 void
@@ -212,10 +240,12 @@
     UString::size_type to=0;
     Output output;
 
-    is_ok = parse_output_record (gv_output_record0, 0, to, output);
+    GDBMIParser parser (gv_output_record0);
+    is_ok = parser.parse_output_record (0, to, output);
     BOOST_REQUIRE (is_ok) ;
 
-    is_ok = parse_output_record (gv_output_record1, 0, to, output);
+    parser.push_input (gv_output_record1);
+    is_ok = parser.parse_output_record (0, to, output);
     BOOST_REQUIRE (is_ok) ;
 }
 
@@ -225,8 +255,9 @@
     bool is_ok=false ;
     UString::size_type to ;
     map<int, list<IDebugger::VariableSafePtr> >params ;
-    is_ok = nemiver::parse_stack_arguments (gv_stack_arguments0,
-                                            0, to, params) ;
+
+    GDBMIParser parser (gv_stack_arguments0);
+    is_ok = parser.parse_stack_arguments (0, to, params) ;
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE (params.size () == 2) ;
     map<int, list<IDebugger::VariableSafePtr> >::iterator param_iter ;
@@ -244,8 +275,9 @@
     bool is_ok=false ;
     UString::size_type to ;
     map<int, list<IDebugger::VariableSafePtr> >params ;
-    is_ok = nemiver::parse_stack_arguments (gv_stack_arguments1,
-                                            0, to, params) ;
+
+    GDBMIParser parser (gv_stack_arguments1);
+    is_ok = parser.parse_stack_arguments (0, to, params) ;
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE_MESSAGE (params.size () == 18, "got nb params "
                            << params.size ()) ;
@@ -264,7 +296,9 @@
     bool is_ok=false ;
     UString::size_type to=0 ;
     list<IDebugger::VariableSafePtr> vars ;
-    is_ok = parse_local_var_list (gv_local_vars, 0, to, vars) ;
+
+    GDBMIParser parser (gv_local_vars);
+    is_ok = parser.parse_local_var_list (0, to, vars) ;
     BOOST_REQUIRE (is_ok) ;
     BOOST_REQUIRE (vars.size () == 1) ;
     IDebugger::VariableSafePtr var = *(vars.begin ()) ;
@@ -279,7 +313,9 @@
     {
         UString::size_type to = 0;
         IDebugger::VariableSafePtr var (new IDebugger::Variable) ;
-        BOOST_REQUIRE (parse_member_variable (gv_member_var, 0, to, var)) ;
+
+        GDBMIParser parser (gv_member_var);
+        BOOST_REQUIRE (parser.parse_member_variable (0, to, var)) ;
         BOOST_REQUIRE (var) ;
         BOOST_REQUIRE (!var->members ().empty ()) ;
     }
@@ -287,7 +323,9 @@
     {
         UString::size_type to = 0;
         IDebugger::VariableSafePtr var (new IDebugger::Variable) ;
-        BOOST_REQUIRE (parse_member_variable (gv_member_var2, 0, to, var)) ;
+
+        GDBMIParser parser (gv_member_var2);
+        BOOST_REQUIRE (parser.parse_member_variable (0, to, var)) ;
         BOOST_REQUIRE (var) ;
         BOOST_REQUIRE (!var->members ().empty ()) ;
     }
@@ -298,43 +336,51 @@
 {
     UString::size_type to = 0;
     IDebugger::VariableSafePtr var (new IDebugger::Variable) ;
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member, 0, to, var)) ;
+
+    GDBMIParser parser (gv_var_with_member);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member2, 0, to, var)) ;
+    parser.push_input (gv_var_with_member2);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member3, 0, to, var)) ;
+    parser.push_input (gv_var_with_member3);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member4, 0, to, var)) ;
+    parser.push_input (gv_var_with_member4);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member5, 0, to, var)) ;
+    parser.push_input (gv_var_with_member5);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member6, 0, to, var)) ;
+    parser.push_input (gv_var_with_member6);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 
     to = 0;
     var.reset (new IDebugger::Variable);
-    BOOST_REQUIRE (parse_variable_value (gv_var_with_member7, 0, to, var)) ;
+    parser.push_input (gv_var_with_member7);
+    BOOST_REQUIRE (parser.parse_variable_value (0, to, var)) ;
     BOOST_REQUIRE (var) ;
     BOOST_REQUIRE (!var->members ().empty ()) ;
 }
@@ -344,7 +390,8 @@
 {
     UString::size_type to = 0 ;
     UString str ;
-    BOOST_REQUIRE (parse_embedded_c_string (gv_emb_str, 0, to, str)) ;
+    GDBMIParser parser (gv_emb_str);
+    BOOST_REQUIRE (parser.parse_embedded_c_string (0, to, str)) ;
 }
 
 void
@@ -352,15 +399,16 @@
 {
     vector<IDebugger::OverloadsChoiceEntry> prompts ;
     UString::size_type cur = 0 ;
-    BOOST_REQUIRE (parse_overloads_choice_prompt (gv_overloads_prompt0,
-                                                  cur, cur, prompts)) ;
+
+    GDBMIParser parser (gv_overloads_prompt0);
+    BOOST_REQUIRE (parser.parse_overloads_choice_prompt (cur, cur, prompts)) ;
     BOOST_REQUIRE_MESSAGE (prompts.size () == 4,
                            "actually got " << prompts.size ()) ;
 
     cur=0 ;
     prompts.clear () ;
-    BOOST_REQUIRE (parse_overloads_choice_prompt (gv_overloads_prompt1,
-                                                  cur, cur, prompts)) ;
+    parser.push_input (gv_overloads_prompt1);
+    BOOST_REQUIRE (parser.parse_overloads_choice_prompt (cur, cur, prompts)) ;
     BOOST_REQUIRE_MESSAGE (prompts.size () == 4,
                            "actually got " << prompts.size ()) ;
 }
@@ -371,8 +419,9 @@
     std::map<IDebugger::register_id_t, UString> regs;
     UString::size_type cur = 0;
 
-    BOOST_REQUIRE (parse_register_names (gv_register_names,
-                cur, cur, regs)) ;
+    GDBMIParser parser (gv_register_names);
+
+    BOOST_REQUIRE (parser.parse_register_names (cur, cur, regs)) ;
     BOOST_REQUIRE_EQUAL (regs.size (), 50u);
     BOOST_REQUIRE_EQUAL (regs[0], "eax");
     BOOST_REQUIRE_EQUAL (regs[1], "ecx");
@@ -432,8 +481,8 @@
     std::list<IDebugger::register_id_t> regs;
     UString::size_type cur = 0;
 
-    BOOST_REQUIRE (parse_changed_registers (gv_changed_registers,
-                cur, cur, regs)) ;
+    GDBMIParser parser (gv_changed_registers);
+    BOOST_REQUIRE (parser.parse_changed_registers (cur, cur, regs)) ;
     BOOST_REQUIRE_EQUAL (regs.size (), 18u);
     std::list<IDebugger::register_id_t>::const_iterator reg_iter = regs.begin ();
     BOOST_REQUIRE_EQUAL (*reg_iter++, 0u);
@@ -462,10 +511,11 @@
     std::map<IDebugger::register_id_t, UString> reg_values;
     UString::size_type cur = 0;
 
-    BOOST_REQUIRE (parse_register_values (gv_register_values,
-                cur, cur, reg_values)) ;
+    GDBMIParser parser (gv_register_values);
+    BOOST_REQUIRE (parser.parse_register_values (cur, cur, reg_values));
     BOOST_REQUIRE_EQUAL (reg_values.size (), 11u);
-    std::map<IDebugger::register_id_t, UString>::const_iterator reg_iter = reg_values.begin ();
+    std::map<IDebugger::register_id_t, UString>::const_iterator
+                                                reg_iter = reg_values.begin ();
     BOOST_REQUIRE_EQUAL ((reg_iter)->first, 1u);
     BOOST_REQUIRE_EQUAL ((reg_iter)->second, "0xbfd10a60");
     ++reg_iter;
@@ -507,8 +557,8 @@
     size_t start_addr;
     UString::size_type cur = 0;
 
-    BOOST_REQUIRE (parse_memory_values (gv_memory_values,
-                cur, cur, start_addr, mem_values)) ;
+    GDBMIParser parser (gv_memory_values);
+    BOOST_REQUIRE (parser.parse_memory_values (cur, cur, start_addr, mem_values));
     BOOST_REQUIRE_EQUAL (start_addr, 0x000013a0u);
     BOOST_REQUIRE_EQUAL (mem_values.size (), 4u);
     std::vector<uint8_t>::const_iterator mem_iter = mem_values.begin ();
@@ -522,13 +572,24 @@
 }
 
 void
+test_gdbmi_result ()
+{
+    GDBMIResultSafePtr result;
+    UString::size_type cur = 0;
+
+    GDBMIParser parser (gv_gdbmi_result0);
+    bool is_ok = parser.parse_gdbmi_result (cur, cur, result);
+    BOOST_REQUIRE (is_ok && result);
+}
+
+void
 test_breakpoint_table ()
 {
     std::map<int, IDebugger::BreakPoint> breakpoints;
     UString::size_type cur = 0;
 
-    BOOST_REQUIRE (parse_breakpoint_table (gv_breakpoint_table0,
-                                           cur, cur, breakpoints)) ;
+    GDBMIParser parser (gv_breakpoint_table0);
+    BOOST_REQUIRE (parser.parse_breakpoint_table (cur, cur, breakpoints)) ;
     BOOST_REQUIRE_EQUAL (breakpoints.size (), 1u);
     std::map<int, IDebugger::BreakPoint>::const_iterator iter;
     iter = breakpoints.find (1);
@@ -543,12 +604,12 @@
     BOOST_REQUIRE_EQUAL (iter->second.line (), 70);
 
     cur = 0, cur = 0, breakpoints.clear();
-    BOOST_REQUIRE (parse_breakpoint_table (gv_breakpoint_table1,
-                                           cur, cur, breakpoints)) ;
+    parser.push_input (gv_breakpoint_table1);
+    BOOST_REQUIRE (parser.parse_breakpoint_table (cur, cur, breakpoints));
 
     cur = 0, cur = 0, breakpoints.clear();
-    BOOST_REQUIRE (parse_breakpoint_table (gv_breakpoint_table2,
-                                           cur, cur, breakpoints)) ;
+    parser.push_input (gv_breakpoint_table2);
+    BOOST_REQUIRE (parser.parse_breakpoint_table (cur, cur, breakpoints));
 }
 
 using boost::unit_test::test_suite ;
@@ -581,6 +642,7 @@
     suite->add (BOOST_TEST_CASE (&test_changed_registers));
     suite->add (BOOST_TEST_CASE (&test_register_values));
     suite->add (BOOST_TEST_CASE (&test_memory_values));
+    suite->add (BOOST_TEST_CASE (&test_gdbmi_result));
     suite->add (BOOST_TEST_CASE (&test_breakpoint_table));
     return suite ;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]