#include <xml/gmarkup.h>
#include <xml/gerror.h>
#include <xml/gstrfuncs.h>
#include <xml/dumpnode.h>
#include <xml/addsnode.h>
#include <xml/from-xmf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdio.h>
#include <string.h>
#include <errno.h>

#define ___ {
#define ____ }

struct UserData
{
    GString*    text;
    xml_GNode*  node; /* current node */
}
;
/* Called for open tags <foo bar="baz"> */
extern 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);
/* Called for close tags </foo> */
extern void 
xml_g_on_end_element    (GMarkupParseContext *context,
			 const gchar         *element_name,
			 gpointer             user_data,
			 GError             **error);
/* Called for character data */
/* text is not nul-terminated */
extern void 
xml_g_on_text           (GMarkupParseContext *context,
			 const gchar         *text,
			 gsize                text_len,  
			 gpointer             user_data,
			 GError             **error);
/* text is not nul-terminated. */
extern void 
xml_g_on_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.
 */
extern void 
xml_g_on_error          (GMarkupParseContext *context,
			 GError              *error,
			 gpointer             user_data);
xml_GNode*
xml_g_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; ___ xml_GParseContext* context = xml_g_parse_context_new (&parser, G_MARKUP_CONTINUE|G_MARKUP_SIMPLIFIED, &user_data, 0); if (rootfilename) s = g_strconcat ("<: filename=\"", rootfilename, "\">", 0); else s = g_strdup ("<: >"); xml_g_parse_context_parse (context, s, -1, error); g_free (s); xml_g_parse_context_parse (context, text+off, end-off, error); xml_g_parse_context_parse (context, "</:>", 4, error); xml_g_parse_context_end_parse (context, 0); xml_g_parse_context_free (context); ____; return user_data.node; ____; }
/* _____________________________________________________________ */
xml_GNode* 
xml_g_parse_postfix_markups (xml_GNode* node);
/**
   returns null on error and sets error info
 */
xml_GNode*
xml_g_parse_file (const xml_GNode* mine,
		  const gchar* file, GError** error)
{
    int e;
    xml_GNode* node = 0;
    int f;
    f = open (file, O_RDONLY);
    if (f < 0) goto _could_not_open_file_;
    ___ struct stat st;
    e = fstat (f, &st);
    if (e < 0) goto _could_not_stat_file_;
    ___ void* p = mmap (0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
    if (p == MAP_FAILED) goto _could_not_mmap_file_;
    node = xml_g_parse_text (mine, p, 0, st.st_size, file, error);
    node = xml_g_parse_postfix_markups (node);
 _unmap_:
    munmap (p, st.st_size);
    ____;____;
 _close_:
    close (f);
 _return_:
    return node;
 _could_not_open_file_:
    xml_g_set_error (error, errno, "could not open file: '%s': %s", 
		     file, g_strerror(errno));
    goto _return_;
 _could_not_stat_file_:
    xml_g_set_error (error, errno, "could not stat file: '%s': %s", 
		     file, g_strerror(errno));
    goto _close_;
 _could_not_mmap_file_:
    xml_g_set_error (error, errno, "could not mmap file: '%s': %s", 
		     file, g_strerror(errno));
    goto _unmap_;
}
/* _____________________________________________________________ */
static xml_GNode* undot (xml_GNode* mark)
{
    int len = strlen(mark->name);
    memcpy (mark->name+1, mark->name+2, len-2);
    mark->name[len-2] = '/';
    /* g_printerr ("{%s}", mark->name); */

    ___ xml_GNode* node = xml_g_parse_text (0, mark->name, 0, len, 0, 0);
    if (node && node->children)
    
{
#define SWAP(X,Y,PART) \
        { \
            void* x = X->PART; \
            X->PART = Y->PART; \
            Y->PART = x; \
        }

        SWAP(mark,node->children,name);
	SWAP(mark,node->children,attributes);
	xml_g_node_destroy (node);
#undef  SWAP  
    }
____; return mark; }
/**
   scans for <.markup> nodes and makes them bind up to the previous newline
 */
xml_GNode* 
xml_g_parse_postfix_markups (xml_GNode* node)
{
    xml_GNode* mark = node->children;
    if (! mark) return node;
    ___ gsize off = node->off; xml_GNode* bef = mark;
    
    do 
{ 
	
{
	    int o = (mark->prev ? mark->prev->end : node->off);
	    gchar* r = xml_g_memrchr (node->text->str + o,'\n', mark->off - o);
	    if (r) 
{ off = r - node->text->str + 1; bef = mark; }
}
if (mark->name && mark->name[0] == '<' && mark->name[1] == '.')
{
	    mark->off = off; undot (mark);
	    if (bef != mark)
	    
{
		xml_GNode* next = mark->next;
		xml_GNode* prev = mark->prev;
		xml_g_node_unlink (mark); 
		bef = xml_node_group_outer (bef, prev, mark);
		mark = next;
		goto done;
	    }
}
else
{
	    xml_g_parse_postfix_markups (mark);
	}
mark = mark->next; done: ; }
while (mark); ____; return node; }
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */