/*   -*- coding: utf-8 -*-  */

/***********************************************************************
*
*      Module  : Sxml
*      Fichier : SxmlParser.c
*      Auteur  : J. Ducloy
*
*      Derniere mise a jour Decembre 2000
*      $Id: SxmlParser.c,v 1.4 2007/01/22 08:41:14 parmentf Exp $
*
************************************************************************
* 
*     Copyright (C) 2001 CNRS INIST
*
************************************************************************
 Programming rules: for most function returning a string, this one
                    will be covered at the next call. 
************************************************************************/

#include "SxmlNode.h"
#include "Buffer.h"
#include "Except.h"
#include <ctype.h>

/** The implicit SxmlParser for the file. */
SxmlParser *SxmlImplicitParser=NULL;

/**
   Creates an SxmlParser.

   Don't forget to free it using SxmlParserFree

   @returns the created SxmlParser.
 */

SxmlParser *SxmlParserCreate()
{
  SxmlParser *xp;
  if(!(xp=(SxmlParser *)malloc(sizeof(SxmlParser))))
    {
       ExceptSetError("SxmlParser","MA", "memory allocation failed in SxmlParserCreate","","",2);
      return NULL;
    }
  xp->bufText=BufferCreate(100,100);
  xp->bufName=BufferCreate(10,10);
  return xp;
}

/**
   Frees all @a xp's resources.

   @warning @a xp must have been initialized using @ref
   SxmlParserCreate.

   @param xp the SxmlParser to free
 */

void SxmlParserFree(SxmlParser *xp)
{
  BufferFree(xp->bufText);
  BufferFree(xp->bufName);
  free (xp);
}

/**
   Returns the text between the current point of @a xp and the next
   "<" character. Moves @a xp's point to "<". If there is no such
   character, returns the whole string (beginning at the current
   point), and set the point to NULL (course in @a xp is ended).

   @param xp

   @returns an SxmlText containing the text included between the
   current point of @a xp and the next '<' character, which needs to
   be freed!

   @warning Don't forget to free the returned SxmlText!
 */

SxmlText *SxmlParserGetText(SxmlParser *xp)
{
  SxmlText *x1;
  char *posNext;
  if((posNext=strchr(xp->nextStr,'<')))
    {
      BufferStrncpy(xp->bufText, xp->nextStr, posNext-(xp->nextStr));
      x1=SxmlTextCreate(BufferString(xp->bufText));
      xp->nextStr=posNext;
      return (x1);
    }
  else
    {
      x1=SxmlTextCreate(xp->nextStr);
      xp->nextStr=NULL;
      return (x1);
    }
}

/**
   Gets the value of the attribute which content is pointed by the
   current point of @a xp.

   Must be called on the quote character enclosing the value of the
   attribute.

   The point is set on the character next to the closing quote.

   @param xp

   @returns the value of the current attribute in @a xp (XML syntax)
 */
char *SxmlParserGetAttVal(SxmlParser *xp)
{
  int c;
  xp->nextStr++;
  
  BufferReset(xp->bufText);
  while ((c=*(xp->nextStr)))
    {
      xp->nextStr++;
      if(c=='\"')
	{
	  return BufferString(xp->bufText);
	}
      BufferCharCat(xp->bufText,c);
    }
  ExceptSetError("SxmlParser","SY","attribute val not terminated","","",2);
  return NULL;
}

char *SxmlParserGetAttValQ1(SxmlParser *xp)
{
  int c;
  xp->nextStr++;
  
  BufferReset(xp->bufText);
  while ((c=*(xp->nextStr)))
    {
      xp->nextStr++;
      if(c=='\'')
	{
	  return BufferString(xp->bufText);
	}
      BufferCharCat(xp->bufText,c);
    }
  ExceptSetError("SxmlParser","SY","attribute val not terminated","","",2);
  return NULL;
}

char *SxmlParserGetBetweenParenthesis(SxmlParser *xp,
				     char p1,
				     char p2)
     /*  xp->nextStr is on first p1  */
{
  int c;
  int level;
  level=0;
  xp->nextStr++;
  BufferReset(xp->bufText);
  while ((c=*(xp->nextStr)))
    {
      xp->nextStr++;
      if (c==p2)
	{
	  if(level)level--;
	  else return BufferString(xp->bufText);
	}
      else if(c==p1)level++;

      BufferCharCat(xp->bufText,c);
    }
  ExceptSetError("SxmlParser","SY","parenthesis expr not terminated","","",2);
  return NULL;
}

/**
   Gets the name of the tag currently read in @a xp.

   @param xp

   @returns all the characters from the current point of @a xp to the
   first character among space, >, =, ?, /
 */
char *SxmlParserGetName(SxmlParser *xp)
{
  int c;
  BufferReset(xp->bufName);

  while((c=*(xp->nextStr)))
    {
      switch(c)
	{
	case ' ':
	case '\n':
	case '\t':
	case '>':
	case '=':
	case '?':
	case '/':
	  return BufferString(xp->bufName);
	  break;
	default:
	  BufferCharCat(xp->bufName,c);
	  xp->nextStr++;
	  break;
	}
    }
  if (BufferLen(xp->bufName)==0)return NULL;
  return BufferString(xp->bufName);
}

char *SxmlParserGetInteger(SxmlParser *xp)
{
  int c;
  BufferReset(xp->bufName);

  while((c=*(xp->nextStr)))
    {
      if(isdigit(c))
	{
	  BufferCharCat(xp->bufName,c);
	  xp->nextStr++;
	}
      else break;
    }
  if (BufferLen(xp->bufName)==0)return NULL;
  return BufferString(xp->bufName);
}

/**
   Skips all characters in @a xp until the first breaking character
   (contained in @a str).

   Returns the position of the first character in @a xp which is in @a
   str.

   @remark @a xp state is changed.

   @param xp  
   @param str a break characters list (ex: @ref SxmlParserSkipSeparator)
   @returns 
	- the position of the next character of @a str in @a xp
	- NULL if there is none.
 */
char *SxmlParserSkipBrk(SxmlParser *xp,
		       char *str)
{
  char c;
  while((c=*(xp->nextStr)))
    {
      if(strchr(str,c))xp->nextStr++;
      else return xp->nextStr;
    }
  return NULL;
}

/**
   Returns the text included between the current point of @a xp and
   the first character of @a str encountered. Moves the point of @a xp
   to this character.

   @param xp  
   @param str list of breaking characters

   @returns the content of @a xp from the current point to the first
   character of @a str encountered in @a xp (until the end, if there
   is no such character)
 */
char *SxmlParserGetTextUntilBrk(SxmlParser *xp,
			       char *str)
{
  int c;
  BufferReset(xp->bufText);
  while((c=*(xp->nextStr)))
    {
      if(strchr(str,c))return BufferString(xp->bufText);
      BufferCharCat(xp->bufText,c);
      xp->nextStr++;
    }
  return BufferString(xp->bufText);
}

/**
   Returns the string from the current point in @a xp to the first
   occurrence of @a str (excluded), and moves @a xp's current point
   onto the character following @a str.

   Example:
   @code
   SxmlParser *xp = SxmlParserCreate();
   SxmlParserInit(xp, "<a>Lets</a><b>see</b>");
   printf("%s\n",SxmlParserGetTextUntilSkip(xp,"</a>"));
   @endcode
   Will print:
   @code
   <a>Lets
   @endcode
   And @a xp current point will be @c \<b\>...

   @param xp
   @param str string ending the wanted string (excluded)
   
   @returns the string included between current point in @a xp and the
   first occurrence of @a str.
 */
char *SxmlParserGetTextUntilSkip(SxmlParser *xp,
				char *str)
{
  int l1;
  char *posNext;
  l1=strlen(str);
  if((posNext=strstr(xp->nextStr,str)))
    {
      BufferStrncpy(xp->bufText, xp->nextStr, posNext-(xp->nextStr));
      xp->nextStr=posNext+l1;
      return BufferString(xp->bufText);
    }
  else return NULL;
}

/**
   Gets the value of the attribute which content is pointed by the
   current point of @a xp. The attribute value must not be enclosed in
   quotes (SGML-like).

   Must be called on the first character of the attribute value.

   The point is set on the character next to the value (@c space, @c >
   , or @c / when followed by @c > ).

   @param xp
   
   @returns the value of the current attribute in @a xp (no quote
   enclosing the value)

   @see @ref SxmlParserGetAttVal
 */
char *SxmlParserGetAttValNoQuote(SxmlParser *xp)
{

  char c;

  BufferReset(xp->bufText);
  while((c=*(xp->nextStr)))
    {
      switch(c)
	{
	case ' ':
	  return (BufferString(xp->bufText));
	case '>':
	  return (BufferString(xp->bufText));
	case '/':
	  if ((*((xp->nextStr)+1))=='>')
	    return (BufferString(xp->bufText));
	  break;
	default:
	  break;
	}
      BufferCharCat(xp->bufText,c);
      xp->nextStr++;
    }
  ExceptSetError("SxmlParser","SY", "unterminated unquoted attribute val","","",2);
      return NULL;
}

char *SxmlParserGetTextStrpbrk(SxmlParser *xp,
			      char *str)
{
  char *posNext;
  if((posNext=strpbrk(xp->nextStr,str)))
    {
      BufferStrncpy(xp->bufText, xp->nextStr,  posNext-(xp->nextStr));
      xp->nextStr=posNext;
      return BufferString(xp->bufText);
    }
  else return NULL;
}

SxmlNode *SxmlParserGetComment(SxmlParser *xp)
{
  SxmlNode *x1;
  char *v1;
  xp->nextStr+=4;
  if ((v1=SxmlParserGetTextUntilSkip(xp,"-->")))
    {
      x1=SxmlCommentCreate(v1);
      return (x1);
    }
  else
    {
      ExceptSetError("SxmlParser","SY", "Comment",BufferGetSubString(xp->nextStr,0,10), "unterminated",2); 
      return NULL;
    }
}

SxmlNode *SxmlParserGetProcessingInstruction(SxmlParser *xp)
{
  char *targetStr;
  char *dataStr;
  SxmlNode *resu;

  xp->nextStr+=2;
  if(!(targetStr=SxmlParserGetName(xp)))
    ExceptSetError("SxmlParser","SY","Empty target","","",2);
  if ((*xp->nextStr)==' ')xp->nextStr++;
  else if (strncmp(xp->nextStr,"?>",2)==0)
    return (SxmlProcessingInstructionCreate(targetStr,NULL));
  if ((dataStr=SxmlParserGetTextUntilSkip(xp,"?>")))
    {
      resu=SxmlProcessingInstructionCreate(targetStr,dataStr);
      return resu;
    }
  else   ExceptSetError("SxmlParser","SY", "Processing Instruction",BufferGetSubString(xp->nextStr,0,10), "unterminated",2); 
  return NULL;
}

SxmlNode *SxmlParserGetCdataOrContainer(SxmlParser *xp)
{
  SxmlNode *xc1;
  xp->nextStr+=3;
  if (strncmp(xp->nextStr, "double[",7)==0)
    {
      char *posEnd;
      xp->nextStr+=7;
      posEnd=strstr(xp->nextStr,"]]>");
      if (!posEnd)
	{
	  ExceptSetError("SxmlParser","SY", "CDATA or ...",BufferGetSubString(xp->nextStr,0,10), "section without end",2); 
	  return NULL;
	}
      BufferStrncpy(xp->bufText, xp->nextStr, posEnd-(xp->nextStr));
      xp->nextStr=posEnd+3;
      xc1=SxmlContainerDoubleCreate((double) strtod(BufferString(xp->bufText), NULL));
      return xc1;
    }
  else if  (strncmp(xp->nextStr, "CDATA[",6)==0)
    {
      char *posEnd;
      xp->nextStr+=6;
      posEnd=strstr(xp->nextStr,"]]>");
      if (!posEnd)
	{
	  ExceptSetError("SxmlParser","SY", "CDATA ",BufferGetSubString(xp->nextStr,0,10), "not termiated",2); 
	  return NULL;
	}
      BufferStrncpy(xp->bufText, xp->nextStr, posEnd-(xp->nextStr));
      xp->nextStr=posEnd+3;
      xc1=SxmlCdataCreate(BufferString(xp->bufText));
      return xc1;
    }
  else   ExceptSetError("SxmlParser","SY", "CDATA like or ...",BufferGetSubString(xp->nextStr,0,10), "not yet implemented",2); 
  return NULL;
}

SxmlNode *SxmlParserGetEntityDeclaration(SxmlParser *xp)
{
  char *nameStr;
  SxmlNode *entityDec;
  char *a1;

  xp->nextStr+=8;
  SxmlParserSkipSeparator(xp);
  if(!(nameStr=SxmlParserGetName(xp)))
    ExceptSetError("SxmlParser","SY","Empty entity declaration","","",2);
  entityDec=SxmlDocumentEntityDeclarationCreate(nameStr);
  SxmlParserSkipSeparator(xp);
  if (strncmp(xp->nextStr, "SYSTEM",6)==0)
    {
      xp->nextStr+=6;
      SxmlParserSkipSeparator(xp);
      a1=SxmlParserGetAttVal(xp);
      SxmlSetAttribute(entityDec, "SYSTEM", a1);
      SxmlParserSkipSeparator(xp);
      if (strncmp(xp->nextStr, "NDATA",5)==0)
	{
	  xp->nextStr+=5;
	  SxmlParserSkipSeparator(xp);
	  a1=SxmlParserGetName(xp);
	  SxmlSetAttribute(entityDec, "NDATA", a1);
	}
      SxmlParserSkipSeparator(xp);
      if (*xp->nextStr=='>')
	{
	  xp->nextStr++;
	  return entityDec;
	}
    ExceptSetError("SxmlParser","SY","ENTITY SYSTEM part not yet implemented","","",2);
    }
  if (strncmp(xp->nextStr, "PUBLIC",6)==0)
    {
      xp->nextStr+=6;
      SxmlParserSkipSeparator(xp);
      a1=SxmlParserGetAttVal(xp);
      SxmlSetAttribute(entityDec, "PUBLIC", a1);
      SxmlParserSkipSeparator(xp);
      if((*xp->nextStr)=='\"')
	{
	  a1=SxmlParserGetAttVal(xp);
	  SxmlSetAttribute(entityDec, "URL", a1);
	  SxmlParserSkipSeparator(xp);
	}
      if (strncmp(xp->nextStr, "NDATA",5)==0)
	{
	  xp->nextStr+=5;
	  SxmlParserSkipSeparator(xp);
	  a1=SxmlParserGetName(xp);
	  SxmlSetAttribute(entityDec, "NDATA", a1);
	}
      SxmlParserSkipSeparator(xp);
      if (*xp->nextStr=='>')
	{
	  xp->nextStr++;
	  return entityDec;
	}
      ExceptSetError("SxmlParser","SY","ENTITY PUBLIC part not yet implemented","","",2);
    }
  ExceptSetError("SxmlParser","SY","ENTITY part not yet implemented","","",2);
  return NULL;
}

SxmlNode *SxmlParserGetDocTypeItem(SxmlParser *xp)
{
  SxmlParserSkipSeparator(xp);
  if (*xp->nextStr==']') 
    {
      return NULL;
    }
  if (strncmp(xp->nextStr, "<!ENTITY", 8)==0)
    {
      return SxmlParserGetEntityDeclaration(xp);
    }
  if (strncmp(xp->nextStr, "<!--", 4)==0)
    {
      return SxmlParserGetComment(xp);
    }
  ExceptSetError("SxmlParser","SY","DOCTYPE item not implemented or not fit","","",2);
  return NULL;
}

SxmlNode *SxmlParserGetDocType(SxmlParser *xp)
{
  char *targetStr;
  SxmlNode *docType;

  char *a1;
  char *a2;
  xp->nextStr+=9;
  SxmlParserSkipSeparator(xp);
  if(!(targetStr=SxmlParserGetName(xp)))
    ExceptSetError("SxmlParser","SY","Empty doc type","","",2);
  docType=SxmlDocumentTypeCreate(targetStr);
  SxmlParserSkipSeparator(xp);
  if (strncmp(xp->nextStr, "PUBLIC ",7)==0)
    {
      xp->nextStr+=7;
      SxmlParserSkipSeparator(xp);
      if (!(a2=SxmlParserGetAttVal(xp)))
	ExceptSetError("SxmlParser","SY","empty DOCTYPE PUBLIC",SxmlNodeName(docType),"",2);
      if(!(a1=strdup(a2)))
	ExceptSetError("SxmlParser","MA","memory allocation","","",2);
      SxmlParserSkipSeparator(xp);
      if((*xp->nextStr)=='\"')
	 a2=SxmlParserGetAttVal(xp);
      else a2=NULL;
      SxmlDocumentTypeSetPublic(docType,a1,a2);
      free (a1);
    }
  else if (strncmp(xp->nextStr, "SYSTEM ",7)==0)
    {
      xp->nextStr+=7;
      SxmlParserSkipSeparator(xp);
      a1=SxmlParserGetAttVal(xp);
      SxmlDocumentTypeSetSystem(docType,a1);
    }
  else if (*xp->nextStr=='[');
  else if (strcmp(targetStr,"html")==0)
    {
      SxmlDocumentTypeSetHtml(docType);
    }
  else
    {
      ExceptSetError("SxmlParser","SY","DOCTYPE ID not implemented or not fit",SxmlNodeName(docType),"",2);
    }

  SxmlParserSkipSeparator(xp);
  if (*xp->nextStr=='>')
    {
      xp->nextStr++;
      return docType;
    }
  if (*xp->nextStr=='[')
    {
      SxmlNode *itemDtd;
      xp->nextStr++;
      while ((itemDtd=SxmlParserGetDocTypeItem(xp)))
	{
	  SxmlDocumentTypeAppendChild(docType,itemDtd); 
	}
      if(*xp->nextStr!=']')
	{
	  ExceptSetError("SxmlParser","SY","DOCTYPE ] missing","","",2);
	}
      xp->nextStr++;
      SxmlParserSkipSeparator(xp);
      if(*xp->nextStr!='>')
	{
	  ExceptSetError("SxmlParser","SY","DOCTYPE > missing after ]","","",2);
	}
      xp->nextStr++;
      return docType;
    }
  /*
  while ((*xp->nextStr)!='>')xp->nextStr++;
  xp->nextStr++;
  return docType;
  */
  return docType;
}

/**
   @param xp the SxmlParser
   @param x1 where to set the attribute
   @return 
   - NULL if no attribute is read from @a xp
   - @a x1, completed with found attribute name and value.
 */
SxmlNode *SxmlParserGetAttribute(SxmlParser *xp,
			       SxmlNode *x1)  /* if null return xpath
						test attribute */
{
  int c;
  char *attName;
  char *attVal;
  while((c=*(xp->nextStr)))
    {
      switch(c)
	{
	case ' ':
	case '\n':
	case '\t':
	case '\015':
	  xp->nextStr++;
	  continue;
	case '>':
	case '/':
	  return NULL;
	default:
	  break;
	}
      break;
    }
  attName=SxmlParserGetName(xp);
  while((c=*(xp->nextStr)))
    {
      switch(c)
	{
	case ' ':
	case '\n':
	case '\t':
	case '\015':
	  xp->nextStr++;
	  if(isalpha((int)(*(xp->nextStr))))
	    {
	      SxmlSetAttribute(x1,attName,"");
	      return x1;
	    }
	  continue;
	case '=':
	  xp->nextStr++;
	  break;
	case '>':
	case '/':
	  SxmlSetAttribute(x1,attName,"");
	  return x1;

	default:
	  ExceptSetError("SxmlParser","SY","Attribute not fit for",attName,"",2);
	  break;
	}
      break;
    }
  while((c=*(xp->nextStr)))
    {
      switch(c)
	{
	case ' ':
	case '\n':
	case '\t':
	case '\015':
	  xp->nextStr++;
	  continue;
	case '\"':
	  attVal=SxmlParserGetAttVal(xp);
	  break;
	case '\'':
	  attVal=SxmlParserGetAttValQ1(xp);
	  break;
	default:
	  attVal=SxmlParserGetAttValNoQuote(xp);
	  break;
	}
      break;
    }
  if(x1)
    {
      SxmlSetAttribute(x1,attName,attVal);
      return x1;
    }
  else
    {
      SxmlNode *x2;
      x2=SxmlLeafCreate("testAttribute",attVal);
      SxmlSetAttribute(x2,"name",attName);
      return x2;
    }
}

SxmlNode *SxmlParserGetBeginElement(SxmlParser *xp)
{
  char *t1;
  int c;
  SxmlNode *x1;
  xp->nextStr++;
  if(!(t1=SxmlParserGetName(xp)))
    ExceptSetError("SxmlParser","SY","Empty tag","","",2);
  x1=SxmlElementCreate(t1);
  while ((c=*xp->nextStr))
    {
      switch(c)
	{
	case '>':
	  xp->nextStr++;
	  SxmlSetNodeType(x1, XML_NODE_BEGIN_ELEMENT);
	  return x1;
	case '/':
	  xp->nextStr++;
	  if(*(xp->nextStr++)=='>')
	    {
	      SxmlElementSetEmpty(x1);
	      return x1;
	    }
	  if (strlen(xp->nextStr)>10)
	    {
	      Buffer *b1;
	      b1=BufferCreate(10,10);
	      BufferStrncpy(b1, xp->nextStr,50);
	      ExceptSetError("SxmlParser","SY","syntax error after / in ",BufferString(b1),"",3);
	    }
	  else
	    {
	      ExceptSetError("SxmlParser","SY","syntax error after / in ",xp->nextStr,"",3);
	    }
	
	case ' ':
	case '\n':
	case '\t':
	  xp->nextStr++;
	  while(SxmlParserGetAttribute(xp,x1));
	  continue;
	}
    }
  return NULL;
}

SxmlNode *SxmlParserGetEndElement(SxmlParser *xp)
{
  SxmlNode *x1;
  char *t1;
  xp->nextStr+=2;
  if(!(t1=SxmlParserGetName(xp)))
    ExceptSetError("SxmlParser","SY","Emptytag in end mark","","",2);
  x1=SxmlElementCreate(t1);
  SxmlSetNodeType(x1, XML_NODE_END_ELEMENT);
  if(*(xp->nextStr)=='>')
    {
      xp->nextStr++;
      return x1;
    }
  SxmlParserSkipSeparator(xp);     /*  in case of </aa      > */
  if(*(xp->nextStr)=='>')
    {
      xp->nextStr++;
      return x1;
    }
  ExceptSetError("SxmlParser","SY","Bad end mark ",t1,"",2);
  return x1;
}

SxmlNode *SxmlParserGetSxmlUnit(SxmlParser *xp)
{
  SxmlNode *resu;

  if (!xp)return NULL;
  if (!(xp->nextStr))return NULL;
  switch (*xp->nextStr)
    {
    case '\0':
	return NULL;
    case '<':
      if (strncmp(xp->nextStr, "<!--",4)==0)
	return SxmlParserGetComment(xp);
      else if  (strncmp(xp->nextStr, "<!DOCTYPE",9)==0)
	{
	  resu= SxmlParserGetDocType(xp);
	  return resu;
	}
      else if  (strncmp(xp->nextStr, "<![",3)==0)
	return SxmlParserGetCdataOrContainer(xp);
      else if (*(xp->nextStr+1)=='?')
	{
	  resu=SxmlParserGetProcessingInstruction(xp);
	  return resu;
	}
      else if (strncmp(xp->nextStr, "<!ENTITY",8)==0) /* ENTITY out of DTD */
	{
	  resu=SxmlParserGetEntityDeclaration(xp);
	  return resu;
	}
      else if (*(xp->nextStr+1)=='/')
	return SxmlParserGetEndElement(xp);
      return SxmlParserGetBeginElement(xp);
 
    default:
      return SxmlParserGetText(xp);
    }
}

/**
   Initializes @a xp with @a str.

   @warning Don't forget to call @ref SxmlParserCreate once before
   calling this function.

   @warning @a str should not be freed until the end of using @a xp.

   @warning @a str have to be freed after the end of use of @a xp.

   @param xp the parser
   @param str ? to complete ?
   @return @a xp initialized.
 */
SxmlParser *SxmlParserInit(SxmlParser *xp,
			 char *str)
{
  xp->nextStr=str;
  xp->lastTag=NULL;
  return xp;
}

int SxmlParserNextDomType(SxmlParser *xp)
{
  if(!xp->nextStr)return 0;
  switch(xp->nextStr[0])
    {
    case '\0':
      return 0;
    case '<':
      switch(xp->nextStr[1])
	{
	case '\0':
	  return 0;
	case '?':
	  return  SXML_NODE_PROCESSING_INSTRUCTION;
	case '!':
	  switch(xp->nextStr[2])
	    {
	    case '\0':
	      return 0;
	    case 'D':
	      if (strncmp(xp->nextStr, "<!DOCTYPE", 9)==0) return SXML_NODE_DOCUMENT_TYPE;
	      return 0;
	    case '-':
	      return SXML_NODE_COMMENT;
	    default:
	      return 0;
	    }
	default:
	  return SXML_NODE_ELEMENT;
	}
    default:
      return SXML_NODE_TEXT;
      
    }
}

SxmlNode *SxmlFromString(char *str)
{
  if(!str)return NULL;
  if(!SxmlImplicitParser)SxmlImplicitParser=SxmlParserCreate();
  SxmlParserInit(SxmlImplicitParser,str);
  return SxmlParserGetRootNode(SxmlImplicitParser);
}

SxmlParser *SxmlFromStringInit(char *str)
{
  if(!str)return NULL;
  if(!SxmlImplicitParser)SxmlImplicitParser=SxmlParserCreate();
  SxmlParserInit(SxmlImplicitParser,str);
  return SxmlImplicitParser;
}

SxmlNode *SxmlFromStringNext()
{
  return SxmlParserGetRootNode(SxmlImplicitParser);
}

SxmlNode *SxmlDocumentFromString(char * str)
{
  SxmlNode *itemNode;
  if(!str)return NULL;
  SxmlFromStringInit(str);
  while ((itemNode=SxmlFromStringNext()))
    {
      switch(SxmlNodeType(itemNode))
	{
	case XML_NODE_ELEMENT:
	  return itemNode;
	default:
	  continue;
	}
    }
  return NULL;
}


SxmlNode *SxmlParserGetElementContent(SxmlParser *xp,
				    SxmlNode *x1)
{
  SxmlNode *x2;
  char *t1;

  t1=SxmlNodeName(x1);
  while((x2=SxmlParserGetSxmlUnit(xp)))
    {
      switch(SxmlNodeType(x2))
	{
	case SXML_NODE_COMMENT:
	case SXML_NODE_TEXT:
	case SXML_NODE_CDATA_SECTION:
	case SXML_NODE_ELEMENT:
	case SXML_NODE_PROCESSING_INSTRUCTION:
	case SXML_NODE_DOCUMENT_TYPE:
	  SxmlAppendChild(x1,x2);
	  continue;
	case SXML_NODE_BEGIN_ELEMENT:
	  SxmlAppendChild(x1,x2);
	  if(SxmlParserGetElementContent(xp,x2))continue;
	  else
	    {
	      SxmlNode *x3;
	      SxmlReset(x2);
	      while((x3=SxmlNextNode(x2)))
		SxmlAppendChild(x1,SxmlRemoveChild(x3));
	      SxmlElementSetEmpty(x2);
	      SxmlSetNodeType(x2,XML_NODE_ELEMENT);
	      if(strcmp(t1,SxmlNodeName(xp->lastTag))==0)
		{
		  SxmlFree(xp->lastTag);
		  SxmlSetNodeType(x1,XML_NODE_ELEMENT);
		  return x1;
		}
	      return NULL;
	    }
	case SXML_NODE_END_ELEMENT:
	  if(strcmp(SxmlNodeName(x2),t1)==0)
	    {
	      SxmlFree(x2);
	      SxmlSetNodeType(x1,XML_NODE_ELEMENT);
	      return x1;
	    }
	  else
	    {
	      xp->lastTag=x2;
	      return NULL;
	    }
	case SXML_NODE_CONTAINER:
	  switch(SxmlNodeSubType(x2))
	    {
	    case SXML_CONTAINER_DOUBLE:
	      	  SxmlAppendChild(x1,x2);
		  break;
	    default:
	      break;;
	    }
	  continue;
	}
    }
  return NULL;
}

SxmlNode *SxmlParserGetRootNode(SxmlParser *xp)
{
  SxmlNode *x1;
  Buffer *bErr;
  if (!(x1=SxmlParserGetSxmlUnit(xp)))return NULL;
  switch(SxmlNodeType(x1))
    {
    case XML_NODE_COMMENT:
    case XML_NODE_TEXT:
    case XML_NODE_ELEMENT:
    case XML_NODE_PROCESSING_INSTRUCTION:
    case XML_NODE_DOCUMENT_TYPE:
      return x1;
    case XML_NODE_BEGIN_ELEMENT:
      xp->rootElem=x1;
      if(SxmlParserGetElementContent(xp,x1))return x1;
      bErr=BufferFromString("> and finding :");
      BufferStrncat(bErr,  xp->nextStr-10, 40);
      ExceptSetError("SxmlParser","SY","looking for </",SxmlNodeName(x1), BufferString(bErr),2);
    case XML_NODE_END_ELEMENT:
       ExceptSetError("SxmlParser","SY","premature end mark </",SxmlNodeName(x1),">",2);
    }
  return NULL;
}
