#include <xml/pdoc-src.h>
#include <xml/nextpcre.h>
#include <xml/addsnode.h>
#include <xml/nextnode.h>
#include <xml/attrnode.h>
#include <string.h>
#include <stdlib.h>

#define ___ {
#define ____ }

#ifdef PFE
# define CDOC "c_comment"
# define CXXC "c_comment"
# define CCHR "c_character"
# define CSTR "c_string"
# define CPRE "c_preprocessor"
# define CERR "c_malformed"
# define CBRK "br"
#else
# define CDOC "ccomment"
# define CXXC "pcomment"
# define CCHR "cliteral"
# define CSTR "sliteral"
# define CPRE "cpreproc"
# define CERR "xxsyntax"
# define CBRK "br"
#endif

# define LINE "line" /* attribute */

# define CCO 1 /* C comment */
# define CXX 2 /* C++ comment */
# define CHR 4 /* char literal */
# define STR 8 /* string literal */

# define COM (CCO|CXX) /* any comment */
# define LIT (CHR|STR) /* any literal */

/*
   scan for literals in the following text and mark them as subnodes
   of the given node - the return value is the node itself. Only a very
   limited subset is marked, named "sliteral", "cliteral", "ccomment"
   and "pcomment" plus "br"-markups around each newline or backslashnewline.
  
   Implementation note: this routine is faster than using a pair
   of regex and callback that has to check what has matched. It is 
   actually allowed to pass sub-node of another tree - you must simply
   ensure that it does not yet have any other children-node.
  
   The resulting tree can be further examined and callbacks will then be
   able to check for _inside1("*comment") and similar.
  
   n.b.: if not tree->parent then add <br> for start and end of text.
 */
xml_GNode*
xml_pdoc_preparse_c_strings (xml_GNode* tree)
{
    if (! tree || !tree->text || tree->children) return tree;
    ___ int off = tree->off; /* the current char to look at */
    gchar C = 0; /* pushback or previous char */
    gchar X = 0; /* the parsing state */
    xml_GNode* node = 0; /* the current node to parse to */
    gchar c; /* the next char to process */

    if (! tree->parent && ! tree->off && tree->end)
    
{
	xml_GNode* newr = xml_g_node_append_data (tree, CBRK);
	newr->text = tree->text; /* newr->off = newr->end = 0 */
    }
goto start; next_new_node_2: node->text = tree->text; node->end = off; node->off = off-1; goto next; next_new_node: node->text = tree->text; node->end = off; node->off = off; goto next; /* for (i = 0; i < textlen; i++) : */ next: C = c; next2: off++; if (off >= tree->end) goto returns; /* break loop */ if (node) node->end++; start: switch ((c = tree->text->str[off]))
{
    case '\"':
	if (X&(CHR|COM) || C=='\\') goto next;
	if (X&STR) 
{ X = 0; node->end++; node = 0; goto next; }
X = STR; node = xml_g_node_append_data (tree, CSTR); goto next_new_node; case '\'': if (X&(STR|COM) || C=='\\') goto next; if (X&CHR)
{ X = 0; node->end++; node = 0; goto next; }
X = CHR; node = xml_g_node_append_data (tree, CCHR); goto next_new_node; case '\\': if (C != '\\') goto next; C = ' '; goto next2; case '\n': case '\f': if (C!='\\' && X&CXX)
{ X = 0; node = 0; }
___ xml_GNode* newr; newr = xml_g_node_append_data ((node ? node : tree), CBRK); newr->text = tree->text; newr->off = off; newr->end = off+1; if (C=='\\') newr->off--; ____; goto next; case '/': if (C=='*' && X&CCO)
{ X = 0; node->end++; node = 0; goto next; }
if (C!='/') goto next; if (X&(COM|CHR|STR)) goto next; X = CXX; node = xml_g_node_append_data (tree, CXXC); goto next_new_node_2; case '*': if (C!='/') goto next; if (X&(COM|CHR|STR)) goto next; X = CCO; node = xml_g_node_append_data (tree, CDOC); goto next_new_node_2; default: goto next; }
; returns: if (! tree->parent && tree->children && C!='\n' && C!='\f')
{
	xml_GNode* newr = xml_g_node_append_data (tree, CBRK);
	newr->text = tree->text;  newr->off = newr->end = off;
    }
return tree; ____; }
xml_GNode*
xml_pdoc_preparse_c (xml_GNode* tree)
{
    if (! tree) return tree;
    if (! tree->children)
	tree = xml_pdoc_preparse_c_strings (tree);

    ___ gchar* filename = 
	g_strdup (xml_node_attribute_lookup (tree, "filename"));

    ___ xml_GNode* preproc = 0;
    ___ xml_GNode* node = tree->children; long line = 1;
    /* we don't use foreach here which would be able to walk to
     * deeper levels - instead we assume all the interesting nodes
     * are at the top level just as preparse_c_strings would return.
     */
    for (; node ; node = node->next)
    
{
	if (! node->name) continue;
	if (! xml_node_hasname_eq_(node, CBRK))
	
{   /* some other node, perhaps multiline comment */
	    xml_GNode* part = node->children;
	    for (; part ; part = part->next)
	    
{
		if (! xml_node_hasname_eq_(part, CBRK)) 
		    continue;

		xml_node_attribute_add_value (part, "line", 
		    g_strdup_printf("%li %s", line, filename));
		line++;
	    }
continue; }
xml_node_attribute_add_value (node, "line", g_strdup_printf("%li %s", line, filename)); line++; ___ gchar* txt = node->text->str + node->end; ___ gchar* end = node->text->str + tree->end; if (preproc && (txt >= end || node->text->str[node->off] != '\\'))
{ xml_tree_add2 (tree, CPRE, preproc->end, node->off); preproc = 0; }
if (node->next) end = node->text->str + node->next->off; # define skip_whitespace(LABEL) { LABEL: \ if (txt >= end) continue; \ if (g_ascii_isspace (*txt)) { txt++; goto LABEL; }} skip_whitespace(A) g_assert (txt < end); if (*txt != '#') continue; preproc = node; txt++; skip_whitespace(B) if (txt+5 < end && !memcmp (txt, "line ", 5))
{ txt+=5; skip_whitespace(C); }
if (! g_ascii_isdigit (*txt)) continue; line = strtol (txt, &txt, 0); if (! node->next || strcmp (node->next->name, CSTR)) continue; g_free (filename); filename = g_strndup (node->text->str + node->next->off + 1, node->next->end - node->next->off - 2); continue; ____;____; }
return tree; ____;____;____; }
/* _____________________________________________________________________ */
#define EXTERNC_A "externc_opens" #define EXTERNC_E "externc_close" #define X(A) /* g_printerr A */ /* debugging */
xml_GNode*
xml_pdoc_c_read (xml_GNode* tree)
{
    if (! tree) return tree;
    if (! tree->children)
	tree = xml_pdoc_preparse_c (tree);

    /* recognize ifdefcplusplus..extern..endif blocks */

    ___ xml_GNode* node = tree->children;
    for (; node ; node = node->next)
    
{
	if (! xml_pcre_contains (
		node, CPRE, "?" "\\s*#\\s*ifdef\\s+__cplusplus\\b.*"))
	    continue;
	X(("A"));
	___ xml_GNode* with = node->next;
	while (xml_pcre_followedby0 (with, 0, "?" "\\s*") &&
	       xml_pcre_hasnextnode (with, "?" ".comment|br"))
	
{ with = with->next; }
X(("B[%s]", with->name)); ___ int opens = 0; if (! xml_pcre_followedby (with, 0, "?" "\\s*}\\s*"))
{
	    opens = 1;
	    X(("M[%s]", with->name));
	    if (! xml_pcre_followedby (with, 0, "?" "\\s*extern\\s*"))
		continue;
	    X(("MM[%s[%s:%s]]\n", with->name, with->next->name, CSTR));
	    // if (! xml_pcre_hasnextnode (with, CSTR))
	    //   continue;
	    if (! with->next) continue;
	    X(("N[%s]", with->name));
	    with = with->next; /* it's a CSTR */
	    if (! xml_pcre_contains (with, CSTR, "?" "\"C\"") ||
		! xml_pcre_followedby (with, 0, "?" "\\s*{\\s*"))
		continue;
	    X(("X[%s]", with->name));
	}
with = with->next; X(("C[%s]", with->name)); while (xml_pcre_followedby0 (with, 0, "?" "\\s*") && xml_pcre_hasnextnode (with, "?" ".comment|br"))
{ with = with->next; }
X(("E[%s]", with->name)); if (! xml_pcre_contains ( with, CPRE, "?" "\\s*#\\s*endif\\b.*")) continue; X(("F[%s][%s]", with->name, node->name)); /* found */ if (opens) node = xml_node_group_outer_new (node, with, EXTERNC_A); else node = xml_node_group_outer_new (node, with, EXTERNC_E); ____;____; }
____; return tree; }
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */