1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Naba Kumar 2005 <naba@gnome.org>
6 * gdbmi.c is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2, or (at your option) any later version.
12 * gdbmi.c is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with main.c. See the file "COPYING". If not,
19 * write to: The Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
31 #define GDBMI_DUMP_INDENT_SIZE 4
44 struct _GDBMIForeachHashData
50 static guint GDBMI_deleted_hash_value
= 0;
53 gdbmi_value_free (GDBMIValue
*val
)
55 g_return_if_fail (val
!= NULL
);
57 if (val
->type
== GDBMI_DATA_LITERAL
)
59 g_string_free (val
->data
.literal
, TRUE
);
61 else if (val
->type
== GDBMI_DATA_LIST
)
63 gdbmi_value_foreach (val
, (GFunc
)gdbmi_value_free
, NULL
);
64 g_queue_free (val
->data
.list
);
68 g_hash_table_destroy (val
->data
.hash
);
75 gdbmi_value_new (GDBMIDataType data_type
, const gchar
*name
)
77 GDBMIValue
*val
= g_new0 (GDBMIValue
, 1);
79 val
->type
= data_type
;
81 val
->name
= g_strdup (name
);
87 g_hash_table_new_full (g_str_hash
, g_str_equal
,
88 (GDestroyNotify
)g_free
,
89 (GDestroyNotify
)gdbmi_value_free
);
92 val
->data
.list
= g_queue_new ();
94 case GDBMI_DATA_LITERAL
:
95 val
->data
.literal
= g_string_new (NULL
);
98 g_warning ("Unknow MI data type. Should not reach here");
105 gdbmi_value_literal_new (const gchar
*name
, const gchar
*data
)
108 val
= gdbmi_value_new (GDBMI_DATA_LITERAL
, name
);
109 gdbmi_value_literal_set (val
, data
);
114 gdbmi_value_get_name (const GDBMIValue
*val
)
116 g_return_val_if_fail (val
!= NULL
, NULL
);
121 gdbmi_value_get_type (const GDBMIValue
*val
)
127 gdbmi_value_set_name (GDBMIValue
*val
, const gchar
*name
)
129 g_return_if_fail (val
!= NULL
);
130 g_return_if_fail (name
!= NULL
);
132 val
->name
= g_strdup (name
);
136 gdbmi_value_get_size (const GDBMIValue
* val
)
138 g_return_val_if_fail (val
!= NULL
, 0);
140 if (val
->type
== GDBMI_DATA_LITERAL
)
142 if (val
->data
.literal
->str
)
147 else if (val
->type
== GDBMI_DATA_LIST
)
148 return g_queue_get_length (val
->data
.list
);
149 else if (val
->type
== GDBMI_DATA_HASH
)
150 return g_hash_table_size (val
->data
.hash
);
156 gdbmi_value_hash_foreach (const gchar
*key
, GDBMIValue
* val
,
157 struct _GDBMIForeachHashData
*hash_data
)
159 hash_data
->user_callback (val
, hash_data
->user_data
);
163 gdbmi_value_foreach (const GDBMIValue
* val
, GFunc func
, gpointer user_data
)
165 g_return_if_fail (val
!= NULL
);
166 g_return_if_fail (func
!= NULL
);
168 if (val
->type
== GDBMI_DATA_LIST
)
170 g_queue_foreach (val
->data
.list
, func
, user_data
);
172 else if (val
->type
== GDBMI_DATA_HASH
)
174 struct _GDBMIForeachHashData hash_data
= {NULL
, NULL
};
176 hash_data
.user_callback
= func
;
177 hash_data
.user_data
= user_data
;
178 g_hash_table_foreach (val
->data
.hash
, (GHFunc
)gdbmi_value_hash_foreach
,
183 g_warning ("Can not do foreach for GDBMIValue this type");
187 /* Literal operations */
189 gdbmi_value_literal_set (GDBMIValue
* val
, const gchar
*data
)
191 g_return_if_fail (val
!= NULL
);
192 g_return_if_fail (val
->type
== GDBMI_DATA_LITERAL
);
193 g_string_assign (val
->data
.literal
, data
);
197 gdbmi_value_literal_get (const GDBMIValue
* val
)
199 g_return_val_if_fail (val
!= NULL
, NULL
);
200 g_return_val_if_fail (val
->type
== GDBMI_DATA_LITERAL
, NULL
);
201 return val
->data
.literal
->str
;
204 /* Hash operations */
206 gdbmi_value_hash_insert (GDBMIValue
* val
, const gchar
*key
, GDBMIValue
*value
)
211 g_return_if_fail (val
!= NULL
);
212 g_return_if_fail (key
!= NULL
);
213 g_return_if_fail (value
!= NULL
);
214 g_return_if_fail (val
->type
== GDBMI_DATA_HASH
);
216 /* GDBMI hash table could contains several data with the same
217 * key (output of -thread-list-ids)
218 * Keep old value under a random name, we get them using
219 * foreach function */
220 if (g_hash_table_lookup_extended (val
->data
.hash
, key
, &orig_key
, &orig_value
))
222 /* Key already exist, remove it and insert value with
224 g_hash_table_steal (val
->data
.hash
, key
);
226 gchar
*new_key
= g_strdup_printf("[%d]", GDBMI_deleted_hash_value
++);
227 g_hash_table_insert (val
->data
.hash
, new_key
, orig_value
);
230 g_hash_table_insert (val
->data
.hash
, g_strdup (key
), value
);
234 gdbmi_value_hash_lookup (const GDBMIValue
* val
, const gchar
*key
)
236 g_return_val_if_fail (val
!= NULL
, NULL
);
237 g_return_val_if_fail (key
!= NULL
, NULL
);
238 g_return_val_if_fail (val
->type
== GDBMI_DATA_HASH
, NULL
);
240 return g_hash_table_lookup (val
->data
.hash
, key
);
243 /* List operations */
245 gdbmi_value_list_append (GDBMIValue
* val
, GDBMIValue
*value
)
247 g_return_if_fail (val
!= NULL
);
248 g_return_if_fail (value
!= NULL
);
249 g_return_if_fail (val
->type
== GDBMI_DATA_LIST
);
251 g_queue_push_tail (val
->data
.list
, value
);
255 gdbmi_value_list_get_nth (const GDBMIValue
* val
, gint idx
)
257 g_return_val_if_fail (val
!= NULL
, NULL
);
258 g_return_val_if_fail (val
->type
== GDBMI_DATA_LIST
, NULL
);
261 return g_queue_peek_nth (val
->data
.list
, idx
);
263 return g_queue_peek_tail (val
->data
.list
);
267 gdbmi_value_dump_foreach (const GDBMIValue
*val
, gpointer indent_level
)
269 gdbmi_value_dump (val
, GPOINTER_TO_INT (indent_level
));
273 gdbmi_value_dump (const GDBMIValue
*val
, gint indent_level
)
277 g_return_if_fail (val
!= NULL
);
279 for (i
= 0; i
< indent_level
; i
++)
282 next_indent
= indent_level
+ GDBMI_DUMP_INDENT_SIZE
;
283 if (val
->type
== GDBMI_DATA_LITERAL
)
287 v
= g_strescape (val
->data
.literal
->str
, NULL
);
289 printf ("%s = \"%s\",\n", val
->name
, v
);
291 printf ("\"%s\",\n", v
);
294 else if (val
->type
== GDBMI_DATA_LIST
)
297 printf ("%s = [\n", val
->name
);
300 gdbmi_value_foreach (val
, (GFunc
)gdbmi_value_dump_foreach
,
301 GINT_TO_POINTER (next_indent
));
302 for (i
= 0; i
< indent_level
; i
++)
306 else if (val
->type
== GDBMI_DATA_HASH
)
309 printf ("%s = {\n", val
->name
);
312 gdbmi_value_foreach (val
, (GFunc
)gdbmi_value_dump_foreach
,
313 GINT_TO_POINTER (next_indent
));
314 for (i
= 0; i
< indent_level
; i
++)
321 gdbmi_value_parse_real (gchar
**ptr
)
323 GDBMIValue
*val
= NULL
;
328 g_warning ("Parse error: Reached end of stream");
330 else if (**ptr
== '"')
332 /* Value is literal */
336 gchar
*value
, *compressed_value
;
339 *ptr
= g_utf8_next_char (*ptr
);
341 buff
= g_string_new ("");
342 while (escaped
|| **ptr
!= '"')
346 g_warning ("Parse error: Invalid literal value");
353 else if (**ptr
== '\\')
357 p
= g_utf8_next_char (*ptr
);
358 for (i
= 0; i
< (p
- *ptr
); i
++)
359 g_string_append_c (buff
, *(*ptr
+ i
));
362 /* Get pass the closing quote */
363 *ptr
= g_utf8_next_char (*ptr
);
365 value
= g_string_free (buff
, FALSE
);
366 compressed_value
= g_strcompress (value
);
367 val
= gdbmi_value_literal_new (NULL
, compressed_value
);
369 g_free (compressed_value
);
371 else if (isalpha (**ptr
))
373 /* Value is assignment */
377 /* Get assignment name */
383 g_warning ("Parse error: Invalid assignment name");
386 *ptr
= g_utf8_next_char (*ptr
);
388 name
= g_strndup (p
, *ptr
- p
);
390 /* Skip pass assignment operator */
391 *ptr
= g_utf8_next_char (*ptr
);
393 /* Retrieve assignment value */
394 val
= gdbmi_value_parse_real (ptr
);
397 gdbmi_value_set_name (val
, name
);
401 g_warning ("Parse error: From parent");
405 else if (**ptr
== '{')
408 gboolean error
= FALSE
;
410 *ptr
= g_utf8_next_char (*ptr
);
411 val
= gdbmi_value_new (GDBMI_DATA_HASH
, NULL
);
415 element
= gdbmi_value_parse_real (ptr
);
418 g_warning ("Parse error: From parent");
422 if (gdbmi_value_get_name(element
) == NULL
)
424 g_warning ("Parse error: Hash element has no name => '%s'",
427 gdbmi_value_free (element
);
430 if (**ptr
!= ',' && **ptr
!= '}')
432 g_warning ("Parse error: Invalid element separator => '%s'",
435 gdbmi_value_free (element
);
438 gdbmi_value_hash_insert (val
, gdbmi_value_get_name (element
),
441 /* Get pass the comma separator */
443 *ptr
= g_utf8_next_char (*ptr
);
447 gdbmi_value_free (val
);
450 /* Get pass the closing hash */
451 *ptr
= g_utf8_next_char (*ptr
);
453 else if (**ptr
== '[')
456 gboolean error
= FALSE
;
458 *ptr
= g_utf8_next_char (*ptr
);
459 val
= gdbmi_value_new (GDBMI_DATA_LIST
, NULL
);
463 element
= gdbmi_value_parse_real (ptr
);
466 g_warning ("Parse error: From parent");
470 if (**ptr
!= ',' && **ptr
!= ']')
472 g_warning ("Parse error: Invalid element separator => '%s'",
475 gdbmi_value_free (element
);
478 gdbmi_value_list_append (val
, element
);
480 /* Get pass the comma separator */
482 *ptr
= g_utf8_next_char (*ptr
);
486 gdbmi_value_free (val
);
489 /* Get pass the closing list */
490 *ptr
= g_utf8_next_char (*ptr
);
494 /* Should not be here -- Error */
495 g_warning ("Parse error: Should not be here => '%s'", *ptr
);
500 G_MODULE_EXPORT GDBMIValue
*
501 gdbmi_value_parse (const gchar
*message
)
506 g_return_val_if_fail (message
!= NULL
, NULL
);
508 if (strcasecmp(message
, "^error") == 0)
510 g_warning ("GDB reported error without any error message");
511 return NULL
; /* No message */
515 if (strchr (message
, ','))
517 msg
= g_strconcat ("{", strchr (message
, ',') + 1, "}", NULL
);
519 val
= gdbmi_value_parse_real (&ptr
);