#include <xml/gnode.h>
#include <xml/from-xml.h>
#include <xml/attrnode.h>

typedef struct _xml_g_Doc xml_g_Doc;
#define ___ { #define ____ }
struct UserData
{
    GString*    text;
    xml_GNode*  node; /* current node */
}
;
/* Called for open tags <foo bar="baz"> */
void 
xml_g_on_start_element  (GMarkupParseContext *context,
			 const gchar         *element_name,
			 const gchar        **attribute_names,
			 const gchar        **attribute_values,
			 gpointer            user_data,
			 GError             **error)
{
    struct UserData* tree = user_data;
    xml_GNode* node = xml_g_node_new_data (element_name);
    if (tree->node)
    
{
	xml_g_node_append (tree->node, node);
	node->text = (tree->node->text ? tree->node->text : tree->text);
    }
else
{ 
	node->text = tree->text; 
    }
node->end = node->off = node->text->len; tree->node = node; /* descend */
{   /* foreach attribute, steal it and hang up our attributes hash */
	gchar** names = (gchar**) attribute_names;
	gchar** values = (gchar**) attribute_values;
	while (*names)
	
{
	    xml_node_attribute_insert (node, *names, *values);
	    *names++ = 0; *values++ = 0; /* steal it */
	}
}
}
/* Called for close tags </foo> */
void 
xml_g_on_end_element    (GMarkupParseContext *context,
			 const gchar         *element_name,
			 gpointer             user_data,
			 GError             **error)
{
    struct UserData* tree = user_data;
    xml_GNode* elem = tree->node;
    xml_GNode* parent = tree->node->parent;
   
    if (parent && parent->text && elem->text)
    
{
	parent->end = elem->end;
    }
if (tree->node->parent) tree->node = tree->node->parent; }
/* Called for character data */
/* text is not nul-terminated */
void 
xml_g_on_text           (GMarkupParseContext *context,
			 const gchar         *text,
			 gsize                text_len,  
			 gpointer             user_data,
			 GError             **error)
{
    struct UserData* tree = user_data;
    xml_GNode* elem = tree->node;
    if (! elem->text)
    
{
	elem->text = tree->text;
        ___ xml_GNode* node = elem->children;
	while (node && !node->text) 
{ node = node->next; }
if (node) /* some child already had some text attached */ elem->off = node->off; else elem->off = tree->text->len; ____; }
tree->text = g_string_append_len (tree->text, text, text_len); elem->end = tree->text->len; }
/* 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 
xml_g_on_passthrough    (GMarkupParseContext *context,
			 const gchar         *passthrough_text,
			 gsize                text_len,  
			 gpointer             user_data,
			 GError             **error)
{
    struct UserData* tree = user_data;
    xml_GNode* node = xml_g_node_new (g_strndup (passthrough_text, text_len));
    xml_g_node_append (tree->node, node);
    /* do not descend */
    node->text = (tree->node->text ? tree->node->text : tree->text);
    node->off = node->end = node->text->len;
}
/* Called on error, including one set by other
   methods in the vtable. The GError should not be freed.
 */
void 
xml_g_on_error          (GMarkupParseContext *context,
			 GError              *error,
			 gpointer             user_data)
{
    struct UserData* tree = user_data;
    /* xml_g_error_print (error); */
    g_message ("(error at %p)", tree);
}
xml_GNode*
xml_g_markup_parse_text (const xml_GNode* mine, 
			 const gchar* text, gsize off, gsize end,
			 const gchar* rootfilename, GError** error)
{
    static const GMarkupParser parser =
	
{
	    .start_element = xml_g_on_start_element,
	    .end_element =   xml_g_on_end_element,
	    .text =          xml_g_on_text,
	    .passthrough =   xml_g_on_passthrough,
	    .error =         xml_g_on_error
	}
; g_return_val_if_fail (! mine || mine->text, 0); ___ auto struct UserData user_data; register gchar* s; user_data.text = (mine) ? mine->text : g_string_new(0); user_data.node = 0; # if 0 user_data.node = xml_g_node_new_data (name); user_data.node->text = user_data.text; # endif ___ GMarkupParseContext* context = g_markup_parse_context_new (&parser, 0, &user_data, 0); if (rootfilename) s = g_strconcat ("<: filename=\"", rootfilename, "\">", 0); else s = g_strdup ("<: >"); g_markup_parse_context_parse (context, s, -1, error); g_free (s); g_markup_parse_context_parse (context, text+off, end-off, error); g_markup_parse_context_parse (context, "</:>", 4, error); g_markup_parse_context_end_parse (context, 0); g_markup_parse_context_free (context); ____; return user_data.node; ____; }
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */