#define USE_XML_ATTR_DATA
#include <xml/dumpnode.h>
#include <xml/attrnode.h>
#include <xml/from-xml.h>
#include <xml/attrdata.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>

#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif

#define ___ {
#define ____ }

/* or call xml_g_string_append ? it is exported ! */
GString* xml_g_string_append (GString* g, const gchar* txt, gsize len)
{
    register int i;
    for ( i = 0 ; i < len ; i++)
    
{
        switch (txt[i])
        
{
         case 0:   return g;
         case '<': g_string_append (g, "&lt;"); continue;
         case '>': g_string_append (g, "&gt;"); continue;
         case '"': g_string_append (g, "&quot;"); continue;
         case '&': g_string_append (g, "&amp;"); continue;
         default:  g_string_append_c (g, txt[i]); continue;
        }
}
return g; }
void xml_attr_data_string_append (GString* g, xml_AttrData* data)
{
    g = g_string_append_c (g, ' ');
    g = g_string_append (g, data->name);
    g = g_string_append (g, "=\"");
    g = xml_g_string_append (g, data->value, strlen (data->value));
    g = g_string_append_c (g, '"');
}
void xml_attr_list_string_append (GString* g, xml_AttrList* list)
{
    for (; list ; list = list->next)
    
{
	if (* list->data->name == ' ') continue;
	xml_attr_data_string_append (g, list->data);
    }
}
GString* g_string_append_newline_indent (GString* g, int indent)
{ /* not quite efficient but for now let us keep this source simple */
    g = g_string_append_c (g, '\n');
    while (indent--) g = g_string_append_len (g, "  ", 2);
    return g;
}
GString* xml_tree_dump_node_info (GString* g, xml_GNode* node)
{
    if (! node) return g;
    if (! g) g = g_string_new (0);
    if (! node->name || ! node->name[0])
    
{
	g_string_append (g, "[]");
    }
else if (node->name[0] == '<')
{
	g_string_append_c (g, '[');
	g_string_append_len (g, node->name, 2);
	g_string_append_c (g, ']');
    }
else
{
	g_string_append_c (g, '[');
	g_string_append (g, node->name);
	g_string_append_c (g, ']');
    }
if (node->text) g_string_append_printf (g, "%i/%i", node->off, node->end); return g; }
GString* xml_tree_dump_node_links (GString* g, xml_GNode* node)
{
    if (! node) return g; 
    if (! g) g = g_string_new (0);
    g_string_append (g, "  \"");
    if (node->prev)
	xml_tree_dump_node_info (g, node->prev);
    else
	g_string_append (g, "|");
    g_string_append (g, "--*--");
    if (node->next)
	xml_tree_dump_node_info (g, node->next);
    else
	g_string_append (g, "|");

    g_string_append (g, " _");
    if (node->children)
	xml_tree_dump_node_info (g, node->children);
    else
	g_string_append (g, "|");
    g_string_append (g, "_ ^");
    if (node->parent)
	xml_tree_dump_node_info (g, node->parent);
    else
	g_string_append (g, "|");
    g_string_append (g, "^");
    g_string_append (g, "\"");
    return g;
}
void xml_g_string_printerr (const gchar* prefix, GString* g)
{
    if (prefix) g_printerr (prefix);
    if (g)
    
{
	g_string_append_len (g, "\n", 2);
	g_printerr (g->str);
	g_string_free (g, 1);
    }
else
{
	g_printerr ("\n");
    }
}
GString*
xml_tree_dump_node_indent (GString* g, xml_GNode* node, gsize nl, int indent)
{
    if (! g) g = g_string_new(0);

    if (node->name)
    
{
        switch (node->name[0])
	
{
	case '<':
            g = g_string_append (g, node->name);
	    break;
	default:
            g = g_string_append_c (g, '<');
            g = g_string_append (g, node->name);
	    xml_attr_list_string_append (g, node->attributes);
            g = g_string_append_c (g, '>');
	    break;
        }
if (node->text) g_string_append_printf (g, "%i/%i", node->off, node->end); }
if (nl < g->len)
{
	g_string_append_newline_indent (g, indent);
	xml_tree_dump_node_links (g, node);
    }
if (node->children)
{
        xml_GNode* child = node->children;
        for (; child ; child = child->next)
        
{
	    if (nl < g->len) nl = g->len + 1;
            g = g_string_append_newline_indent (g, indent+1);
            g = xml_tree_dump_node_indent (g, child, nl, indent+1);
        }
if (nl < g->len) nl = g->len + 1; g = g_string_append_newline_indent (g, indent); }
if (! node->name) goto done; if (node->name[0] == '<') goto done; if (nl < g->len && ! node->children) g_string_append_newline_indent (g, indent); g = g_string_append (g, "</"); g = g_string_append (g, node->name); g = g_string_append_c (g, '>'); if (nl < g->len && node->children)
{
	g_string_append_newline_indent (g, indent);
	xml_tree_dump_node_links (g, node);
    }
done: return g; }
GString*
xml_tree_dump_node_append (GString* g, xml_GNode* node)
{
    return xml_tree_dump_node_indent (g, node, g ? 0 : (1<<(sizeof(int)*7)), 0);
}
gboolean
xml_tree_dump_to_file (xml_GNode* node, const gchar* file)
{
    if (! node) return FALSE;

    ___ int f;
    if (! file) 
{
	f = STDOUT_FILENO;
    }
else
{
	f = open (file, O_WRONLY|O_TRUNC|O_CREAT, 0666);
	if (f == -1) return FALSE;
    }
___ GString* g = xml_tree_dump_node_append (0, node); write (f, g->str, g->len); if (file) close (f); g_string_free (g, 1); return TRUE; ____;____; }
/* _________________________________________________________________ */
GString*
xml_tree_node_to_xml (xml_GNode* node, GString* g)
{
    if (! g) g = g_string_new(0);

    if (node->name)
    
{
        switch (node->name[0])
	
{
	case '<':
            g_string_append (g, node->name);
	    break;
	case ':':
	    if (! node->name[1]) break;
	    /*fallthrough*/
	default:
            g_string_append_c (g, '<');
            g_string_append (g, node->name);
	    xml_attr_list_string_append (g, node->attributes);
            g_string_append_c (g, '>');
	    break;
        }
}
if (node->children)
{
        xml_GNode* child = node->children;
        xml_GNode* print = 0;
                  
        for (; child ; child = child->next)
        
{
            if (child->text)
            
{ /* the text between nodes or just before */
                if (print)
                    xml_g_string_append (g,
                      print->text->str + print->end, child->off - print->end);
                else if (node->text)
                    xml_g_string_append (g, 
                      node->text->str + node->off, child->off - node->off);
                    print = child;
            }
g = xml_tree_node_to_xml (child, g); }
if (node->text)
{  /* text after or just the full of it */
            if (print) 
                xml_g_string_append (g,
                  node->text->str + print->end, node->end - print->end);
            else
                xml_g_string_append (g,
                  node->text->str + node->off,  node->end - node->off);
        }
}
else
{
        if (node->text)
            xml_g_string_append (g, 
              node->text->str + node->off,  node->end - node->off);
    }
if (! node->name) goto done; if (node->name[0] == '<') goto done; if (node->name[0] == ':' && ! node->name[1]) goto done; g_string_append (g, "</"); g_string_append (g, node->name); g_string_append_c (g, '>'); done: return g; }
gboolean
xml_tree_node_to_xml_file (xml_GNode* node, const gchar* file)
{
    if (! node) return FALSE;

    ___ int f;
    if (! file) 
{
	f = STDOUT_FILENO;
    }
else
{
	f = open (file, O_WRONLY|O_TRUNC|O_CREAT, 0666);
	if (f == -1) return FALSE;
    }
___ GString* g = xml_tree_node_to_xml (node, 0); write (f, g->str, g->len); if (file) close (f); g_string_free (g, 1); return TRUE; ____;____; }
/* _________________________________________________________________ */
gboolean
xml_tree_node_to_text_file (xml_GNode* node, const gchar* file)
{
    if (! node) return FALSE;
    while (! node->text && node->children) 
	node = node->children;
    if (! node->text)
	return FALSE;

    ___ int f;
    if (! file) 
{
	f = STDOUT_FILENO;
    }
else
{
	f = open (file, O_WRONLY|O_TRUNC|O_CREAT, 0666);
	if (f == -1) return FALSE;
    }
write (f, node->text->str, node->text->len); if (file) close (f); return TRUE; ____; }
gboolean
xml_g_string_to_file (GString* text, const gchar* file)
{
    if (! text) return FALSE;
    if (! text->len) return TRUE;

    ___ int f;
    if (! file) 
{
	f = STDOUT_FILENO;
    }
else
{
	f = open (file, O_WRONLY|O_TRUNC|O_CREAT, 0666);
	if (f == -1) return FALSE;
    }
write (f, text->str, text->len); if (file) close (f); return TRUE; ____; }
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */