/******************************************************************************
*
*               Projet   : DilibUnix
*               Module   : Buffer
*               Fichier  : BufferParserXml.c
*               Auteur   : J. DUCLOY
*               Date     : Septembre 2001
*
**********************************************************************
*
*   Copyleft  Jacques DUCLOY &  CNRS
*
******************************************************************************/

#include "BufferParserXml.h"
#include "Except.h"
#include <stdlib.h>
#include <string.h>

char *BufferParserAddXmlDataDocument(b1)
     BufferParser *b1;
{
  int c1;
  while ((c1=getc(b1->file))!=EOF)
    {
      switch(c1)
	{
	case '<':
	case '\t':
	case '\n':
	  b1->inputChar=c1;
	  return  BufferString(b1->output);
	default:
	  BufferCharCat(b1->output,c1);
	  break;
	}
    }
  return BufferString(b1->output);
}

char *BufferParserGetXmlProc(b1)
     BufferParser *b1;
{
  return BufferParserGetUntilStr(b1,"?>");
}

char *BufferParserGetXmlDOCTYPE(b1)
     BufferParser *b1;
{
  char *begElem;
  int c1;
  begElem=BufferString(b1->output)+BufferLen(b1->output)-2;
  if (!BufferParserGetMandStr(b1,"OCTYPE "))
    {
      ExceptSetError("BufferParserXml","SY", "looking for <!DOCTYPE and finding",begElem,"" ,2);
      exit (2);
    }
  while((c1=getc(b1->file))!=EOF)
    {
      BufferCharCat(b1->output,c1);
      switch(c1)
	{
	case '>':
	  return BufferString(b1->output);
	case '[':
	  if (BufferParserGetUntilChar(b1,']')) continue;
	  ExceptSetError("BufferParser","SY", "char ] missing for <!DOCTYPE","","" ,2);
	  return 0;
	default:
	  continue;
	}
    }
  ExceptSetError("BufferParser","SY", "premature EOF for <!DOCTYPE","","" ,2);
  return 0;
}

char *BufferParserGetXmlCo(b1)
     BufferParser *b1;
{
  int c1;
  if (((c1=getc(b1->file))!=EOF)
      &&(c1=='-'))
    {
      BufferCharCat(b1->output,c1);
      return BufferParserGetUntilStr(b1,"-->");
    }
  else
    {
      ExceptSetError("BufferParser","SY", "Bad syntax for comment start","","",2);
      exit (2);
    }    
}

char *BufferParserGetXmlCoDTD(b1)
     BufferParser *b1;
{
  int c1;

  if((c1=getc(b1->file))!=EOF)
    {
      BufferCharCat(b1->output,c1);      
      switch(c1)
	{
	case '-':
	  return BufferParserGetXmlCo(b1);
	  break;
	case 'D':
	  return BufferParserGetXmlDOCTYPE(b1);
	  break;
	default:
	  break;
	}
    }
  ExceptSetError("BufferParser","SY", "premature EOF for <!DOCTYPE or <!--","","" ,2);
  return 0;
}

int BufferParserGetTag(b1, bTag)
     BufferParser*b1;
     Buffer *bTag;
{
  int c1;
  while((c1=getc(b1->file))!=EOF)
    {
      switch(c1)
	{
	case ' ':
        case '\n':
	case '>':
	case '/':
	  BufferCharCat(b1->output,c1);
	  return c1;
	default:
	  BufferCharCat(b1->output,c1);
	  BufferCharCat(bTag,c1);
	  break;
	}
    }
  ExceptSetError("BufferParser","SY", "premature EOF, looking for tag","","" ,2);
  return 0;
}

int BufferParserXmlSkipAttVal(b1)
     BufferParser*b1;
     /*
       returns last stored value with
           space 
           doublequote
           >
       returns / after storing />
      */
{
  int c1;
  int c2;
  while((c1=getc(b1->file))!=EOF)
    {
      BufferCharCat(b1->output,c1);
      if(c1==' ')continue;
      if(c1=='\"')
	{
	  if (BufferParserGetUntilChar(b1,'\"'))return '\"';
	  ExceptSetError("BufferParserXml","SY", "premature EOF in attribute val","","",2);
	  exit (2);  
	}
      while((c2=getc(b1->file))!=EOF)
	{
	  BufferCharCat(b1->output,c2);
	  if ((c2==' ')||(c2=='>'))return c2;
	  if (c2=='/')
	    {
	      int c3;
	      c3=getc(b1->file);
	      if (c3==EOF)break;
	      BufferCharCat(b1->output,c3);
	      if (c3=='>')return '/';
	    }
	  continue;
	}
      break; 
    }
  ExceptSetError("BufferParserXml","SY", "premature EOF in attribute val","","",2);
  exit (2);  
}

int BufferParserXmlSkipAttributes(b1)
     BufferParser*b1;
     /* returns
          / if empty node after storing />
          > else
     */
{
  int c1;
  int c2;
  while((c1=getc(b1->file))!=EOF)
    {
      switch(c1)
	{
	case '>':
	  BufferCharCat(b1->output,c1);
	  return c1;
	case '/':
	  BufferCharCat(b1->output,c1);
	  c2=getc(b1->file);
	  if (c2=='>')
	    {
	      BufferCharCat(b1->output,c2);
	      return c1;
	    }
	  else
	    {
	      ExceptSetError("BufferParserXml","SY", "premature EOF or bad end tag","","",2);
	      exit (2);
	    }
	case '=':
	  BufferCharCat(b1->output,c1);
	  c2=BufferParserXmlSkipAttVal(b1);
	  if ((c2=='/')||(c2=='>'))return c2;
	  break;
	default:
	  BufferCharCat(b1->output,c1);
	  break;
	}
    }
  ExceptSetError("BufferParserXml","SY", "premature EOF, parsing attributes","","" ,2);
  return 0;
}

char *BufferParserXmlGetUntilEndDoc(b1)
     BufferParser*b1;
{
  int c1;
  int c2;
  int c3;
  while((c1=getc(b1->file))!=EOF)
    {
      if(c1=='<')
	{
	  if ((c2=getc(b1->file))!=EOF)
	    {
	      BufferCharCat(b1->output,c1);
	      BufferCharCat(b1->output,c2);
	      BufferReset(b1->tag2);
	      if(c2=='/')
		{
		  c3=BufferParserGetTag(b1, b1->tag2);
		  /*
		  if (strncmp(BufferString(b1->tag),
			      BufferString(b1->tag2),
			      BufferLen(b1->tag))==0) */
		  if (strcmp(BufferString(b1->tag),
			     BufferString(b1->tag2))==0)
		    {
		      switch(c3)
			{
			case '>':
			  return (BufferString(b1->output));
			case '/':
			  ExceptSetError("BufferParserXml","SY", "/ bad placed with ",BufferString (b1->tag),BufferString(b1->output),2);
			  exit (2);
			case ' ':
			    continue;
			}
		    }
		  else /* end tag not equal */
		    {
		      continue;
		    }
		}
	      else /* begin tag */
		{
		  BufferCharCat(b1->tag2,c2);
		  c3=BufferParserGetTag(b1, b1->tag2);
		  /*
		  if (strncmp(BufferString(b1->tag),
			      BufferString(b1->tag2),
			      BufferLen(b1->tag))==0)
		  */
		  if (strcmp(BufferString(b1->tag),
			     BufferString(b1->tag2))==0)
		    {
		      switch(c3)
			{
			case '>':
			case ' ':
			  BufferParserXmlGetUntilEndDoc(b1);
			  continue;
			case '/':
			  /* BufferParserXmlGetUntilEndDoc(b1); */
			  continue;
			  /* 
			  ExceptSetError("BufferParser","SY", "/ bad placed"," in:\n", BufferString(b1->output),2);
			  exit (2);
			  */
			}
		    }
		  else continue;
		}
	    }
	  else
	    {
	      ExceptSetError("BufferParserXml","SY", "premature EOF","","",2);
	      exit (2);
	    }
	}
      else BufferCharCat(b1->output,c1);
    }
  ExceptSetError("BufferParserXml","SY", "premature EOF dealing with: ",BufferString(b1->tag) ,"",2);
  exit (2);
}

char *BufferParserGetXmlItem(b1)
     BufferParser*b1;
{
  int c1;
  int c2;
  /*         b1->output contient '<' */

  if((c1=getc(b1->file))!=EOF)
    {
      switch(c1)
	{
	case '?':
	  BufferCharCat(b1->output,c1);
	  return BufferParserGetXmlProc(b1);
	  break;
	case '/':
	  ExceptSetError("BufferParserXml","SY", "premature </",BufferString(b1->output),"",2);
	  break;
	case '!':
	  BufferCharCat(b1->output,c1);
	  return BufferParserGetXmlCoDTD(b1);
	  break;
	default:
	  BufferReset (b1->tag);
	  BufferCharCat(b1->output,c1);
	  BufferCharCat(b1->tag,c1);
	  switch(BufferParserGetTag(b1, b1->tag))
	    {
	    case '>':
	      return BufferParserXmlGetUntilEndDoc(b1);
	      break;
	    case ' ':
	      c2=BufferParserXmlSkipAttributes(b1);
	      if (c2=='/') return (BufferString(b1->output));
	      return BufferParserXmlGetUntilEndDoc(b1);
	    case '/':
	      if ((c2=getc(b1->file))!=EOF)
		{
		  if (c2=='>')
		    {
		      BufferCharCat(b1->output,c2);
		      return (BufferString(b1->output));
		    }
		  else
		    {
		      ExceptSetError("BufferParserXml","SY", "/ bad placed",BufferString(b1->output),"",2);
		      exit (2);
		    }
		}
	      else
		{
		  ExceptSetError("BufferParserXml","SY", "premature EOF","","",2);
		  exit (2);
		}
	    }
	  break;
	}
    }
  ExceptSetError("BufferParser","SY", "premature EOF","","",2);
  return NULL;
}

char *BufferParserGetXmlUnit(b1)
     BufferParser*b1;
{
  int c1;
  BufferReset(b1->output);
  if((c1=b1->inputChar))
    {
      BufferCharCat(b1->output,c1);
      b1->inputChar='\0';
    }
  else
    {
      if ((c1=getc(b1->file))!=EOF)
	{
	  BufferCharCat(b1->output,c1);
	}
      else return NULL;
    }
  switch(c1)
    {
    case '<':
      return BufferParserGetXmlItem(b1);
      break;
    case '\015':  /* FPA: Utile uniquement sous Windows?*/
      return BufferParserGetXmlUnit(b1);
      break;
    case '\t':
    case '\n':
      return BufferString(b1->output);
      break;
    default:
      return BufferParserAddXmlDataDocument(b1);
      break;
    }
}

char *BufferParserStdinGetXmlUnit()
{
  /*
  if(!BufferParserStdin)
    {
      BufferParserStdin=BufferParserCreate();
      BufferParserStdin->file=stdin;
    }
  */
  if(!BufferParserStdin)BufferParserStdinCreate();
  return BufferParserGetXmlUnit(BufferParserStdin);
}

char *BufferParserStdinGetXmlElementStr()
{
  char *unitXml;
  while ((unitXml=BufferParserStdinGetXmlUnit()))
    {
      if (unitXml[0]!='<') continue;
      if (unitXml[1]=='?') continue;
      if (unitXml[1]=='!') continue;
      return unitXml;
    }
  return NULL;
}


/* Returns the concatenation of the XmlInputs of an
   XmlRecord. 

   Blank lines (containing only '\t' or blanks) are not considered,
   they are not added to XmlRecords read.
   
   Parameter: bpToRead is a BufferParser that must be created, and
              associated to a file. This file is not closed by the
	      function, but read.

   WARNING: the returned Buffer must be freed (using
   BufferFree). 
   
   Author: Francois PARMENTIER */
Buffer *BufferParserGetNextXmlRecord (BufferParser *bpToRead) {
  char   *bIn = NULL;
  Buffer *bToReturn = BufferCreate(50,50);
  Buffer *bTemp = NULL;
  int     xmlUnitSize;

  bIn         = BufferParserGetXmlUnit(bpToRead);
  bTemp       = BufferFromString(bIn);
  BufferStrRepl(bTemp," ","");
  xmlUnitSize = strlen(BufferString(bTemp));
  while(bIn && 
	(bIn[0] != '\n' || 
	 xmlUnitSize == 0 ||
	 strlen(BufferString(bToReturn)) == 0) ) 
  {
    if(xmlUnitSize && bIn[0] != '\n')
      BufferStrcat(bToReturn,bIn);

    bIn   = BufferParserGetXmlUnit(bpToRead);
    BufferFree(bTemp);
    bTemp = BufferFromString(bIn);
    BufferStrRepl(bTemp," ","");
    if(bIn && bIn[0] != '\n')
      xmlUnitSize = strlen(BufferString(bTemp));
  }
  
  if(bTemp)
    BufferFree(bTemp);

  if(!bIn) { 
    BufferFree(bToReturn);
    return NULL; 
  }
  return bToReturn;
} /* BufferParserGetNextXmlRecord */
