#include <xml/nextnode.h>
#include <string.h>
#include <stdarg.h>

#define ___ {
#define ____ }

/*
                                                          // assert(node) 
   #define xml_node_hasname_(node,txtXP) \
         (!(txtXP) || (node)->name && (*(txtXP) != '*' \
                                      ? 0 == strcmp ((node)->name, (txtXP)) \
                                      : 0 != strstr ((node)->name, (txtXP)+1))
 */
gboolean
xml_node_hasname (xml_GNode* node, const gchar* nameXE)
{
    if (! node) return FALSE;
    return xml_node_hasname_(node, nameXE);
}
gboolean
xml_node_hasname_of (xml_GNode* node, ... )
{
    g_return_val_if_fail (node, FALSE);
    ___ gboolean done = FALSE;
    ___ va_list args; 
    va_start (args, node);
    ___ const gchar* nameXE;
    while (( nameXE = va_arg (args, const gchar*) ))
    
{
        if (xml_node_hasname_ (node, nameXE))
        
{ done = TRUE; break; }
}
____; va_end (args); ____; return done; ____; }
gboolean
xml_strstr_match1 (const gchar* text, gssize off, gssize end, 
		   const gchar* txtXE)
{
    if (! txtXE || ! *txtXE)
	return TRUE;
    if (! text || off >= end)
	return FALSE;

    end -= off;
    text += off;
    if (*txtXE != '*')
	return ! memcmp (text, txtXE, end) && ! txtXE[end];
    else
        return ! *(txtXE+1) || g_strstr_len (text, end, (txtXE+1));
}
/* a.k.a. xml_strstr_match_or_empty */
gboolean
xml_strstr_match0 (const gchar* text, gssize off, gssize end, 
  const gchar* txtXE)
{
    if (! text || off == end)
	return TRUE;
    return xml_strstr_match1 (text, off, end, txtXE);
}
gboolean
xml_strstr_empty (const gchar* text, gssize off, gssize end)
{
    if (! text) return TRUE;

    while (off < end)
    
{
        if (! g_ascii_isspace (text[off])) 
            return FALSE;
        off++;
    }
return TRUE; }
gboolean
xml_node_contains (xml_GNode* node, 
  const gchar* keyXP, const gchar* txtXP)
{
    if (! node || !node->text)
	return FALSE;
    if (! xml_node_hasname_ (node, keyXP))
	return FALSE;
    return xml_strstr_match1 (node->text->str, node->off, node->end, txtXP);
}
gboolean
xml_node_followedby (xml_GNode* node, 
  const gchar* keyXP, const gchar* txtXP)
{
    if (! node || !node->text || !node->name || !node->next)
	return FALSE;
    if (! xml_node_hasname_ (node, keyXP))
	return FALSE;
    return xml_strstr_match1 (node->text->str, node->end, node->next->off,
			      txtXP);
}
gboolean
xml_node_contains0 (xml_GNode* node, 
  const gchar* keyXP, const gchar* txtXP)
{
    if (! node || !node->text)
	return FALSE;
    if (! xml_node_hasname_ (node, keyXP))
	return FALSE;
    return xml_strstr_match0 (node->text->str, node->off, node->end, txtXP);
}
gboolean
xml_node_followedby0 (xml_GNode* node, 
  const gchar* keyXP, const gchar* txtXP)
{
    if (! node || !node->name || !node->next)
	return FALSE;
    if (! xml_node_hasname_ (node, keyXP))
	return FALSE;
    return xml_strstr_match0 (node->text->str, node->end, node->next->off,
			      txtXP);
}
gboolean
xml_node_this_text_has1 (xml_GNode* node,  const gchar* txtXE)
{
    if (! node || node->text || node->end >= node->off)
        return FALSE;
    return xml_strstr_match1 (node->text->str, node->off, node->end, txtXE);
}
gboolean
xml_node_next_text_has1 (xml_GNode* node,  const gchar* txtXE)
{
    if (! node || !node->text) 
        return FALSE;
    if (node->next)
    
{
        if (! node->next->text || node->end >= node->next->off)
            return FALSE;
        return xml_strstr_match1 (node->text->str, node->end, node->next->off,
				  txtXE);
    }
else if (node->parent)
{
        if (! node->parent->text || node->end >= node->parent->end)
            return FALSE;
        return xml_strstr_match1 (
            node->text->str, node->end, node->parent->end, txtXE);
    }
else return FALSE; }
gboolean
xml_node_prev_text_has1 (xml_GNode* node,  const gchar* txtXE)
{
    if (! node || !node->text) 
        return FALSE;
    if (node->prev)
    
{
        if (! node->prev->text || node->off <= node->prev->end)
            return FALSE;
        return xml_strstr_match1 (
            node->text->str, node->prev->end, node->off, txtXE);
    }
else if (node->parent)
{
        if (! node->parent->text || node->off <= node->parent->off)
            return FALSE;
        return xml_strstr_match1 (
            node->text->str, node->parent->off, node->off, txtXE);
    }
else return FALSE; }
gboolean
xml_node_this_text_empty (xml_GNode* node)
{
    if (! node || node->text)
        return FALSE;
    if (node->end >= node->off)
        return TRUE;
    return xml_strstr_empty (node->text->str, node->off, node->end);
}
gboolean
xml_node_next_text_empty (xml_GNode* node)
{
    if (! node || !node->text) 
        return FALSE;
    if (node->next)
    
{
        if (! node->next->text || node->end >= node->next->off)
            return TRUE;
        return xml_strstr_empty (
            node->text->str, node->end, node->next->off);
    }
else if (node->parent)
{
        if (! node->parent->text || node->end >= node->parent->end)
            return TRUE;
        return xml_strstr_empty (
            node->text->str, node->end, node->parent->end);
    }
else return TRUE; }
gboolean
xml_node_prev_text_empty (xml_GNode* node)
{
    if (! node || !node->text) 
        return FALSE;
    if (node->prev)
    
{
        if (! node->prev->text || node->off <= node->prev->end)
            return TRUE;
        return xml_strstr_empty (
            node->text->str, node->prev->end, node->off);
    }
else if (node->parent)
{
        if (! node->parent->text || node->off <= node->parent->off)
            return TRUE;
        return xml_strstr_empty (
            node->text->str, node->parent->off, node->off);
    }
else return TRUE; }
gboolean
xml_node_hasnextnode (xml_GNode* node, const gchar* keyXP)
{
    if (! node || !node->next)
	return FALSE;
    return xml_node_hasname_ (node->next, keyXP);
}
xml_GNode*
xml_node_next_with_name (xml_GNode* node, const gchar* keyRE)
{
    if (! node) return node; /* return 0 */
    if (! keyRE) return node->next; /* match any */
# if 0
    do 
{
	node = node->next;
	if (! node) return node;
    }
while (! xml_node_hasname_ (node, keyRE)); return node; # else /* optimized for exact match */ if (*keyRE == '*') goto strstrs; /* else goto strcmps; */ strcmps: node = node->next; if (! node) return node; if (! node->name) goto strcmps; if ( strcmp (node->name, keyRE)) goto strcmps; return node; strstrs: node = node->next; if (! node) return node; if (! node->name) goto strstrs; if (! strstr (node->name, keyRE)) goto strstrs; return node; # endif }
xml_GNode*
xml_node_next_or_last (xml_GNode* node, const gchar* keyRE)
{
    if (! node) return node; /* return 0 */
    if (! keyRE) return node->next; /* match any */
# if 0
    do 
{
	node = node->next;
	if (! node || ! node->next) return node;
    }
while (! xml_node_hasname_ (node, keyRE)); return node; # else /* optimized for exact match */ if (! node->next) return node->next; /* return 0; */ if (*keyRE == '*') goto strstrs; /* else goto strcmps; */ strcmps: node = node->next; if (! node->next) return node; if (! node->name) goto strcmps; if ( strcmp (node->name, keyRE)) goto strcmps; return node; strstrs: node = node->next; if (! node->next) return node; if (! node->name) goto strstrs; if (! strstr (node->name, keyRE)) goto strstrs; return node; # endif }
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */