Index: glib/gmarkup.c =================================================================== --- glib/gmarkup.c (revision 5595) +++ glib/gmarkup.c (working copy) @@ -59,7 +59,7 @@ typedef enum struct _GMarkupParseContext { - const GMarkupParser *parser; + GMarkupVTable vtable; GMarkupParseFlags flags; @@ -119,13 +119,33 @@ g_markup_parse_context_new (const GMarku gpointer user_data, GDestroyNotify user_data_dnotify) { - GMarkupParseContext *context; + GMarkupVTable vtable = { 0, }; g_return_val_if_fail (parser != NULL, NULL); - context = g_new (GMarkupParseContext, 1); + vtable.start_element = parser->start_element; + vtable.end_element = parser->end_element; + vtable.text = parser->text; + vtable.passthrough = parser->passthrough; + vtable.error = parser->error; + + return g_markup_parse_context_foo (&vtable, flags, + user_data, user_data_dnotify); +} + +GMarkupParseContext * +g_markup_parse_context_foo (const GMarkupVTable *vtable, + GMarkupParseFlags flags, + gpointer user_data, + GDestroyNotify user_data_dnotify) +{ + GMarkupParseContext *context; + + g_return_val_if_fail (vtable != NULL, NULL); + + context = g_new0 (GMarkupParseContext, 1); - context->parser = parser; + context->vtable = *vtable; context->flags = flags; context->user_data = user_data; context->dnotify = user_data_dnotify; @@ -196,8 +216,8 @@ mark_error (GMarkupParseContext *context { context->state = STATE_ERROR; - if (context->parser->error) - (*context->parser->error) (context, error, context->user_data); + if (context->vtable.error) + (*context->vtable.error) (context, error, context->user_data); } static void set_error (GMarkupParseContext *context, @@ -500,15 +520,46 @@ unescape_text_state_inside_entity_name ( g_string_append_c (ucontext->str, '\''); else { - gchar *name; + GError *tmp_error = NULL; + gchar *entity = NULL; - name = g_strndup (ucontext->entity_start, len); - set_unescape_error (ucontext->context, error, - p, ucontext->text_end, - G_MARKUP_ERROR_PARSE, - _("Entity name '%s' is not known"), - name); - g_free (name); + if (ucontext->context->vtable.entity) + entity = (* ucontext->context->vtable.entity) (ucontext->context, + ucontext->entity_start, + len, + ucontext->context->user_data, + &tmp_error); + + if (entity) + { + g_string_append (ucontext->str, entity); + g_free (entity); + } + else if (tmp_error) + { + set_unescape_error (ucontext->context, error, + p, ucontext->text_end, + G_MARKUP_ERROR_PARSE, + "%s", tmp_error->message); + g_clear_error (&tmp_error); + } + else if (!ucontext->context->vtable.entity) + { + gchar *name; + + name = g_strndup (ucontext->entity_start, len); + + set_unescape_error (ucontext->context, error, + p, ucontext->text_end, + G_MARKUP_ERROR_PARSE, + _("Entity name '%s' is not known"), + name); + + g_free (name); + } + /* otherwise vtable.entity() returned NULL which means + * to simply ignore the entity + */ } } else @@ -1133,11 +1184,11 @@ g_markup_parse_context_parse (GMarkupPar g_assert (context->tag_stack != NULL); tmp_error = NULL; - if (context->parser->end_element) - (* context->parser->end_element) (context, - context->tag_stack->data, - context->user_data, - &tmp_error); + if (context->vtable.end_element) + (* context->vtable.end_element) (context, + context->tag_stack->data, + context->user_data, + &tmp_error); if (tmp_error) { @@ -1322,13 +1373,13 @@ g_markup_parse_context_parse (GMarkupPar } tmp_error = NULL; - if (context->parser->start_element) - (* context->parser->start_element) (context, - start_name, - (const gchar **)attr_names, - (const gchar **)attr_values, - context->user_data, - &tmp_error); + if (context->vtable.start_element) + (* context->vtable.start_element) (context, + start_name, + (const gchar **)attr_names, + (const gchar **)attr_values, + context->user_data, + &tmp_error); /* Go ahead and free the attributes. */ for (; context->cur_attr >= 0; context->cur_attr--) @@ -1470,7 +1521,7 @@ g_markup_parse_context_parse (GMarkupPar /* The text has ended at the open angle. Call the text * callback. */ - + if (unescape_text (context, context->partial_chunk->str, context->partial_chunk->str + @@ -1480,13 +1531,13 @@ g_markup_parse_context_parse (GMarkupPar { GError *tmp_error = NULL; - if (context->parser->text) - (*context->parser->text) (context, - unescaped->str, - unescaped->len, - context->user_data, - &tmp_error); - + if (context->vtable.text) + (*context->vtable.text) (context, + unescaped->str, + unescaped->len, + context->user_data, + &tmp_error); + g_string_free (unescaped, TRUE); if (tmp_error == NULL) @@ -1595,16 +1646,15 @@ g_markup_parse_context_parse (GMarkupPar advance_char (context); context->state = STATE_AFTER_CLOSE_ANGLE; context->start = NULL; - + /* call the end_element callback */ tmp_error = NULL; - if (context->parser->end_element) - (* context->parser->end_element) (context, - close_name, - context->user_data, - &tmp_error); - - + if (context->vtable.end_element) + (* context->vtable.end_element) (context, + close_name, + context->user_data, + &tmp_error); + /* Pop the tag stack */ g_free (context->tag_stack->data); context->tag_stack = g_slist_delete_link (context->tag_stack, @@ -1676,20 +1726,20 @@ g_markup_parse_context_parse (GMarkupPar if (context->flags & G_MARKUP_TREAT_CDATA_AS_TEXT && strncmp (context->partial_chunk->str, "parser->text) - (*context->parser->text) (context, - context->partial_chunk->str + 9, - context->partial_chunk->len - 12, - context->user_data, - &tmp_error); + if (context->vtable.text) + (*context->vtable.text) (context, + context->partial_chunk->str + 9, + context->partial_chunk->len - 12, + context->user_data, + &tmp_error); } - else if (context->parser->passthrough) - (*context->parser->passthrough) (context, - context->partial_chunk->str, - context->partial_chunk->len, - context->user_data, - &tmp_error); - + else if (context->vtable.passthrough) + (*context->vtable.passthrough) (context, + context->partial_chunk->str, + context->partial_chunk->len, + context->user_data, + &tmp_error); + truncate_partial (context); if (tmp_error == NULL) Index: glib/gmarkup.h =================================================================== --- glib/gmarkup.h (revision 5595) +++ glib/gmarkup.h (working copy) @@ -52,6 +52,7 @@ typedef enum typedef struct _GMarkupParseContext GMarkupParseContext; typedef struct _GMarkupParser GMarkupParser; +typedef struct _GMarkupVTable GMarkupVTable; struct _GMarkupParser { @@ -96,10 +97,68 @@ struct _GMarkupParser gpointer user_data); }; +struct _GMarkupVTable +{ + /* Called for open tags */ + void (*start_element) (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error); + + /* Called for close tags */ + void (*end_element) (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error); + + /* Called for character data */ + /* text is not nul-terminated */ + void (*text) (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error); + + /* Called for unknown entities &foo; */ + /* entity is not nul-terminated, returns a newly allocated string */ + gchar * (*entity) (GMarkupParseContext *context, + const gchar *entity, + gsize entity_len, + gpointer user_data, + GError **error); + + /* Called for strings that should be re-saved verbatim in this same + * position, but are not otherwise interpretable. At the moment + * this includes comments and processing instructions. + */ + /* text is not nul-terminated. */ + void (*passthrough) (GMarkupParseContext *context, + const gchar *passthrough_text, + gsize text_len, + gpointer user_data, + GError **error); + + /* Called on error, including one set by other + * methods in the vtable. The GError should not be freed. + */ + void (*error) (GMarkupParseContext *context, + GError *error, + gpointer user_data); + + /* padding */ + gpointer _reserved[8]; +}; + GMarkupParseContext *g_markup_parse_context_new (const GMarkupParser *parser, GMarkupParseFlags flags, gpointer user_data, GDestroyNotify user_data_dnotify); +GMarkupParseContext *g_markup_parse_context_foo (const GMarkupVTable *vtable, + GMarkupParseFlags flags, + gpointer user_data, + GDestroyNotify user_data_dnotify); void g_markup_parse_context_free (GMarkupParseContext *context); gboolean g_markup_parse_context_parse (GMarkupParseContext *context, const gchar *text,