/******************************************************************************/
/* MODUL  : expat - XML parser toolkit                                        */
/* AUTHOR : Andreas Sorgatz (sorgatz@sciface.com)                             */
/* CREATED: 2003-07-17                                                        */
/* CHANGED: 2003-07-23                                                        */
/*                                                                            */
/* bufLen       : gets/sets size of file read buffer: positive integer        */
/* col          : returns the current column number                           */
/* libCallBack  : gets/sets library callback status flag: true or false       */
/* line         : returns the current line number                             */
/* parse        : parses an XML file                                          */
/* stripCharData: gets/sets strip character data status flag: true or false   */
/******************************************************************************/

MMG( attribute = "secure" )
MMG( info = "Module: XML parser toolkit" )

MMG( windows: coption="-I..\\..\\..\\EXPAT\\xmlparse" )
MMG( windows: loption="..\\..\\..\\EXPAT\lib\\xmlparse_al.lib" )

MMG( linux: coption="-I../../../EXPAT/xmlparse" )
MMG( linux: loption="../../../EXPAT/linux/lean/xmlparse.o" )
MMG( linux: loption="../../../EXPAT/linux/lean/hashtable.o" )
MMG( linux: loption="../../../EXPAT/linux/lean/xmlrole.o" )
MMG( linux: loption="../../../EXPAT/linux/lean/xmltok.o" )


#include <string.h>

#include "xmlparse.h"

// if active, then all callback functions are verbose
//#define DEBUG

///////////////////////////////////////////////////////////////////////////////
// configuration flags ////////////////////////////////////////////////////////
// strip leading and trailing whitespaces from character data
static int         xmlStripCharData = true;

// call the mupad library callback function
static int         xmlLibCallback   = true;

///////////////////////////////////////////////////////////////////////////////
// global parser context //////////////////////////////////////////////////////
// is true if the function expat::read is parsing a file
static int         xmlReading = false;

// size of file read buffer
static size_t      xmlBufLen = 8*1024;

// current character data string
static char*       xmlCharData = NULL;

// current character data string start line number
static int         xmlCharDataLine;

// handle of input file
static FILE*       xmlFile;

// expat parser context
static XML_Parser  xmlParser;

// current depth of nested tags
static int         xmlLevel;

///////////////////////////////////////////////////////////////////////////////
// references to library callbacks (DOM_PROC) /////////////////////////////////
static MTcell      xmlLibStartElement          = NULL;
static MTcell      xmlLibEndElement            = NULL;
static MTcell      xmlLibCharacterData         = NULL;
//static MTcell      xmlLibProcessingInstruction = NULL;
//static MTcell      xmlLibComment               = NULL;
//static MTcell      xmlLibStartCdataSection     = NULL;
//static MTcell      xmlLibEndCdataSection       = NULL;
//static MTcell      xmlLibDefaultHandler        = NULL;
//static MTcell      xmlLibUnparsedEntityDecl    = NULL;
//static MTcell      xmlLibNotationDecl          = NULL;
//static MTcell      xmlLibStartNamespaceDecl    = NULL;
//static MTcell      xmlLibEndNamespaceDecl      = NULL;
//static MTcell      xmlLibNotStandalone         = NULL;
//static MTcell      xmlLibExternalEntityRef     = NULL;
//static MTcell      xmlLibUnknownEncoding       = NULL;

///////////////////////////////////////////////////////////////////////////////
// internal callback function to collect character data ///////////////////////
static void characterDataCollect (void *userData, const XML_Char *s, int length)
{
  // Note that due to any limted size of the file read buffer, expat may
  // call the character data callback function several times to complete
  // the transfer. Thus we have to collect all of these calls before for-
  // warding the character data to the library callback function. Refer
  // to 'characterDataForward()' for further information.

  if (length == 0) {
     return ;
  }

  if (xmlCharData==NULL) {
    xmlCharDataLine = XML_GetCurrentLineNumber(xmlParser);
    xmlCharData = (char*) malloc(length+1);
    memcpy(xmlCharData, s, length) ;
    xmlCharData[length] = '\0' ;
  } else {
    int oldlength = strlen(xmlCharData);
    xmlCharData = (char*) realloc(xmlCharData, oldlength+length+1);
    memcpy(xmlCharData+oldlength, s, length) ;
    xmlCharData[oldlength+length] = '\0' ;
  }
}

///////////////////////////////////////////////////////////////////////////////
// internal callback function to forward character data ///////////////////////
static void characterDataForward (void *userData)
{
  // This function forwards a character data string to a mupad library
  // callback function. This function should be called at the top of
  // the functions 'endElement()' and 'startElement()' to ensure that
  // all parts of the character data string has been collected by the
  // function 'characterDataCollect()'.

  if (xmlCharData==NULL) {
    return;
  }

  if (xmlStripCharData) // strip leading and trailing whitespaces?
  {
    // remove white space at the left hand side of the string
    char* p = xmlCharData;
    while (*p!='\0' && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) {
      p++;
    }

    // remove white space at the right hand side of the string
    char* q = xmlCharData + strlen(xmlCharData) - 1 ;
    while ((q > p) && (*p==' ' || *p=='\n' || *p=='\r' || *p=='\t')) {
      *q-- = '\0';
    }

    if (*p=='\0') {
      free(xmlCharData);
      xmlCharData = NULL;
      return;
    }
  }

#ifdef DEBUG
  MFprintf("CallBack: characterData\n");
  MFprintf("L%05d: ", xmlCharDataLine);
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n", xmlCharData);
#endif

  if (xmlLibCallback && xmlLibCharacterData != NULL) {
    MFfree(MFcall(MFcopy(xmlLibCharacterData), 2, MFint(xmlLevel), MFstring(xmlCharData)));
  }

  free(xmlCharData);
  xmlCharData = NULL;
}

///////////////////////////////////////////////////////////////////////////////
// internal callback function for start tags //////////////////////////////////
static void startElement (void *userData, const char *name, const char **attr)
{
  // forward previous character data string if available
  characterDataForward(userData);

  xmlLevel++;

#ifdef DEBUG
  MFprintf("CallBack: startElement\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("<%s", name );

  for (int i = 0; attr[i]; i += 2) {
    assert( attr[i+1]!=NULL ) ;
    MFprintf(" %s=\"%s\"", attr[i], attr[i+1]);
  }
  MFprintf(">\n");
#endif

  if (xmlLibCallback && xmlLibStartElement != NULL) {
    MTcell table = MFnewTable();
    for (int i = 0; attr[i]; i += 2) {
      assert( attr[i+1]!=NULL ) ;
      MFinsTable( &table, MFstring(attr[i]), MFstring(attr[i+1]) );
    }
    MFfree(MFcall(MFcopy(xmlLibStartElement), 3, MFint(xmlLevel), MFstring(name), table));
  }
}

///////////////////////////////////////////////////////////////////////////////
// internal callback function for end tags ////////////////////////////////////
static void endElement (void *userData, const char *name)
{
  // forward previous character data string if available
  characterDataForward(userData);

#ifdef DEBUG
  MFprintf("CallBack: endElement\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("</%s>\n", name );
#endif

  if (xmlLibCallback && xmlLibEndElement != NULL) {
    MFfree(MFcall(MFcopy(xmlLibEndElement), 2, MFint(xmlLevel), MFstring(name)));
  }

  xmlLevel--;
}

///////////////////////////////////////////////////////////////////////////////
// internal callback function processing instructions /////////////////////////
/*
static void processingInstruction (void *userData, 
                                   const XML_Char *target, 
                                   const XML_Char *data)
{
#ifdef DEBUG
  MFprintf("CallBack: processingInstruction\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s=%s\n", target,data );
#endif

  if (xmlLibCallback && xmlLibProcessingInstruction != NULL) {
    MFfree(MFcall(MFcopy(xmlLibProcessingInstruction), 3, MFint(xmlLevel), MFstring(target), MFstring(data)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for comments ////////////////////////////////////
/*
static void comment (void *userData, const XML_Char *data)
{
#ifdef DEBUG
  MFprintf("CallBack: comment\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("<!-- %s -->\n", data );
#endif

  if (xmlLibCallback && xmlLibComment != NULL) {
    MFfree(MFcall(MFcopy(xmlLibComment), 2, MFint(xmlLevel), MFstring(data)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for start of cdata section //////////////////////
/*static void startCdataSection (void *userData)
{
#ifdef DEBUG
  MFprintf("CallBack: startCdataSection\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
#endif

  if (xmlLibCallback && xmlLibStartCdataSection != NULL) {
    MFfree(MFcall(MFcopy(xmlLibStartCdataSection), 1, MFint(xmlLevel)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for end of cdata section ////////////////////////
/*
static void endCdataSection (void *userData)
{
#ifdef DEBUG
  MFprintf("CallBack: endCdataSection\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
#endif

  if (xmlLibCallback && xmlLibEndCdataSection != NULL) {
    MFfree(MFcall(MFcopy(xmlLibEndCdataSection), 1, MFint(xmlLevel)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for characters with no applicable handler ///////
/*
static void defaultHandler (void *userData, const XML_Char *s, int length)
{
#ifdef DEBUG
  MFprintf("CallBack: defaultHandler\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  for (int c=0; c<l; c++) {
    MFprintf("%c", s[c]);
  }
  MFprintf("\n");
#endif

  char *data = (char*) malloc(length+1);
  memcpy(data, s, length) ;
  data[length] = '\0' ;

  if (xmlLibCallback && xmlLibDefaultHandler != NULL) {
    MFfree(MFcall(MFcopy(xmlLibDefaultHandler), 2, MFint(xmlLevel), MFstring(data)));
  }
  
  free(data);
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for a declaration of an unparsed (NDATA) entity /
/*
static void unparsedEntityDecl (void *userData,
                                const XML_Char *entityName,
                                const XML_Char *base,
                                const XML_Char *systemId,
                                const XML_Char *publicId,
                                const XML_Char *notationName)
{
#ifdef DEBUG
  MFprintf("CallBack: unparsedEntityDecl\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n", entityName);
  }
#endif

  if (xmlLibCallback && xmlLibUnparsedEntityDecl != NULL) {
    MFfree(MFcall(MFcopy(xmlLibUnparsedEntityDecl), 2, MFint(xmlLevel), MFstring(entityName)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for a declaration of notation ///////////////////
/*
static void notationDecl (void *userData,
                          const XML_Char *notationName,
                          const XML_Char *base,
                          const XML_Char *systemId,
                          const XML_Char *publicId)
{
#ifdef DEBUG
  MFprintf("CallBack: notationDecl\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n",notationName);
  }
#endif

  if (xmlLibCallback && xmlLibNotationDecl != NULL) {
    MFfree(MFcall(MFcopy(xmlLibNotationDecl), 2, MFint(xmlLevel), MFstring(notationName)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for start of namespace declaration //////////////
/*
static void startNamespaceDecl (void *userData, 
                                const XML_Char *prefix, 
                                const XML_Char *uri)
{
#ifdef DEBUG
  MFprintf("CallBack: startNamespaceDecl\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s, %s\n", prefix, uri);
#endif

  if (xmlLibCallback && xmlLibStartNamespaceDecl != NULL) {
    MFfree(MFcall(MFcopy(xmlLibStartNamespaceDecl), 3, MFint(xmlLevel), MFstring(prefix), MFstring(uri)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for end of namespace declaration ////////////////
/*
static void endNamespaceDecl (void *userData, const XML_Char *prefix)
{
#ifdef DEBUG
  MFprintf("CallBack: endNamespaceDecl\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n", prefix);
#endif

  if (xmlLibCallback && xmlLibEndNamespaceDecl != NULL) {
    MFfree(MFcall(MFcopy(xmlLibEndNamespaceDecl), 2, MFint(xmlLevel), MFstring(prefix)));
  }
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for not standalone document /////////////////////
/*
static int notStandalone (void *userData)
{
#ifdef DEBUG
  MFprintf("CallBack: notStandalone\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
#endif

  if (xmlLibCallback && xmlLibNotStandalone != NULL) {
    MFfree(MFcall(MFcopy(xmlLibNotStandalone), 1, MFint(xmlLevel)));
  }
  return(0);
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for external entity references //////////////////
/*
static int externalEntityRef (XML_Parser parser,
                              const XML_Char *context, 
                              const XML_Char *base,
					          const XML_Char *systemId, 
					          const XML_Char *publicId)
{
#ifdef DEBUG
  MFprintf("CallBack: externalEntityRef\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n", context);
  }
#endif
  return(0);
}
*/

///////////////////////////////////////////////////////////////////////////////
// internal callback function for unknown encoding ////////////////////////////
/*
static int unknownEncoding (void *encodingHandlerData, 
                            const XML_Char *name, 
                            XML_Encoding *info)
{
#ifdef DEBUG
  MFprintf("CallBack: unknownEncoding\n");
  MFprintf("L%05d:", XML_GetCurrentLineNumber(xmlParser));
  for (int l=xmlLevel; l; l--) {
    MFprintf(" ");
  }
  MFprintf("%s\n", name);
  }
#endif
}
*/

/******************************************************************************/
/* FUNCTION: parse( file : DOM_STRING, start,end,data : DOM_PROC ) : DOM_BOOL */
/* Parses 'file' using the library callback functions 'start', 'end', 'data': */
/*     start:= proc( depth, name, tableOfAttributes )                         */
/*     end  := proc( depth, name )                                            */
/*     data := proc( depth, data )                                            */
/* Returns FALSE if an error occured or if 'libCallBack' was set to 'FALSE'.  */
/******************************************************************************/
MFUNC( parse, MCnop )
{
  if (MVnargs < 4) {
    MFerror("File, startElement, endElement and characterData expected.");
  }
  if (!MFisString(MFarg(1))) {
    MFerror("File name (DOM_STRING) expected as first argument.");
  }  

  if (!MFisSecureFileAccess(MFstring(MFarg(1)),"r")) {
    MFreturn( MFcopy(MVfalse) );
  }

  char *buf = (char*) malloc(xmlBufLen);
  if (buf == NULL) {
    MFreturn( MFcopy(MVfalse) );
  }

  xmlFile = fopen(MFstring(MFarg(1)), "r");
  if (xmlFile == NULL) {
    free(buf);
    MFreturn( MFcopy(MVfalse) );
  }

  xmlLevel  = 0;
  xmlParser = XML_ParserCreate(NULL);
  if (xmlParser == NULL) {
    free(buf);
    fclose(xmlFile);
    MFreturn( MFcopy(MVfalse) );
  }

  int depth = 0;
  XML_SetUserData(xmlParser, &depth);
  XML_SetElementHandler(xmlParser, startElement, endElement);
  XML_SetCharacterDataHandler(xmlParser, characterDataCollect);

  for (int n=2; n<=MVnargs; n++) 
  {
    MTcell arg = MFarg(n);
    if (MFnops(arg) != 3 || !MFisString(MFop(arg,1)) || !MFisProc(MFop(arg,2))) {
      XML_ParserFree(xmlParser);
      fclose(xmlFile);
      free(buf);
      MFerror("Option \"handler\"=proc()...end_proc expected.");
    }
    
    char *handlerName = MFstring(MFop(arg,1));
    arg = MFop(arg,2);
    
    if     (strcmp(handlerName,"startElement")==0) {
      xmlLibStartElement          = arg;
    } else if (strcmp(handlerName,"endElement")==0) {
      xmlLibEndElement            = arg;
    } else if (strcmp(handlerName,"characterData")==0) {
      xmlLibCharacterData         = arg;
    //} else if (strcmp(handlerName,"processingInstruction")==0) {
    //  xmlLibProcessingInstruction = arg;
    //  XML_SetProcessingInstructionHandler (xmlParser, processingInstruction);
    //} else if (strcmp(handlerName,"comment")==0) {
    //  xmlLibComment               = arg;
    //  XML_SetCommentHandler (xmlParser, comment);
    //} else if (strcmp(handlerName,"startCdataSection")==0) {
    //  xmlLibStartCdataSection     = arg;
    //  if (xmlLibEndCdataSectionHandler == NULL) continue;
    //  XML_SetCdataSectionHandler (xmlParser, startCdataSectionHandler, endCdataSectionHandler);
    //} else if (strcmp(handlerName,"endCdataSection")==0) {
    //  xmlLibEndCdataSection       = arg;
    //  if (xmlLibStartCdataSectionHandler == NULL) continue;
    //  XML_SetCdataSectionHandler (xmlParser, startCdataSectionHandler, endCdataSectionHandler);
    //} else if (strcmp(handlerName,"default")==0) {
    //  xmlLibDefaultHandler        = arg;
    //  XML_SetDefaultHandler (xmlParser, defaultHandler);
    //} else if (strcmp(handlerName,"defaultExpand")==0) {
    //  xmlLibDefaultHandler        = arg;
    //  XML_SetDefaultHandlerExpand (xmlParser, defaultHandler);
    //} else if (strcmp(handlerName,"unparsedEntityDecl")==0) {
    //  xmlLibUnparsedEntityDecl    = arg;
    //  XML_SetUnparsedEntityDeclHandler (xmlParser, unparsedEntityDecl);
    //} else if (strcmp(handlerName,"notationDecl")==0) {
    //  xmlLibNotationDecl          = arg;
    //  XML_SetNotationDeclHandler (xmlParser, notationDecl);
    //} else if (strcmp(handlerName,"startNamespaceDecl")==0) {
    //  xmlLibStartNamespaceDecl    = arg;
    //  if (xmlLibEndNamespaceDecl == NULL) continue;
    //  XML_SetNamespaceDeclHandler (xmlParser, startNamespaceDecl, endNamespaceDecl);
    //} else if (strcmp(handlerName,"endNamespaceDecl")==0) {
    //  xmlLibEndNamespaceDecl      = arg;
    //  if (xmlLibStartNamespaceDecl == NULL) continue;
    //  XML_SetNamespaceDeclHandler (xmlParser, startNamespaceDecl, endNamespaceDecl);
    //} else if (strcmp(handlerName,"notStandalone")==0) {
    //  xmlLibNotStandalone         = arg;
    //  XML_SetNotStandaloneHandler (xmlParser, notStandalone);
    //} else if (strcmp(handlerName,"externalEntityRef")==0) {
    //  xmlLibExternalEntityRef     = arg;
    //  XML_SetExternalEntityRefHandler (xmlParser, externalEntityRef);
    //} else if (strcmp(handlerName,"unknownEncoding")==0) {
    //  xmlLibUnknownEncoding       = arg;
    //  XML_SetUnknownEncodingHandler(XML_Parser parser, unknownEncoding, encodingHandlerData);
    } else {
      XML_ParserFree(xmlParser);
      fclose(xmlFile);
      free(buf);
      MFerror("Unexpected name of callback function.");
    }
  }

  if (xmlLibStartElement  == NULL || 
      xmlLibEndElement    == NULL ||
      xmlLibCharacterData == NULL ){
    XML_ParserFree(xmlParser);
    fclose(xmlFile);
    free(buf);
    MFerror("Missing startElement, endElement or characterData.");
  }

  xmlReading = true;

  int done;
  do {
    size_t len = fread(buf, 1, xmlBufLen, xmlFile);
    done = len < xmlBufLen;
    if (!XML_Parse(xmlParser, buf, len, done)) {
      MFprintf("%s at line %d\n",
	           XML_ErrorString(XML_GetErrorCode(xmlParser)),
	           XML_GetCurrentLineNumber(xmlParser)
	  );
      fclose(xmlFile);
      free(buf);
      MFreturn( MFcopy(MVfalse) );
    }
  } while (!done);

  xmlReading = false;

  XML_ParserFree(xmlParser);
  fclose( xmlFile );
  free(buf);

  MFreturn( MFbool(xmlLibCallback) );
} MFEND

/******************************************************************************/
/* FUNCTION: line( ) : DOM_INT                                                */
/* Returns the current line number or 0 if no XML file is currently read.     */
/******************************************************************************/
MFUNC( line, MCnop )
{
  int line = 0;

  if (xmlReading) {
    line = XML_GetCurrentLineNumber(xmlParser);
  }
  MFreturn( MFint(line) );
} MFEND

/******************************************************************************/
/* FUNCTION: col( ) : DOM_INT                                                 */
/* Returns the current column number or 0 if no XML file is currently read.   */
/******************************************************************************/
MFUNC( col, MCnop )
{
  int col = 0;

  if (xmlReading) {
    col = XML_GetCurrentColumnNumber(xmlParser);
  }
  MFreturn( MFint(col) );
} MFEND

/******************************************************************************/
/* FUNCTION: libCallBack( [yesno : DOM_BOOL] ) : DOM_BOOL                     */
/* If 'yesno' is TRUE then the library callback procedures given to parse(..) */
/* are called when an XML file is parsed. If it is set to FALSE then they are */
/* ignored. If no argument is given, the function returns the current setting */
/* only.                                                                      */
/* Default: libCallBack = TRUE.                                               */
/******************************************************************************/
MFUNC( libCallBack, MCnop )
{
  MFnargsCheckRange(0,1);

  int old = xmlLibCallback;

  if (MVnargs>0) {
    MFargCheck(1,DOM_BOOL);

    if (MFisTrue(MFarg(1))) {
      xmlLibCallback = true;
    } else if(MFisFalse(MFarg(1))) {
      xmlLibCallback = false;
    } else {
      MFerror("TRUE or FALSE expected.");
    }
  }

  MFreturn( MFbool(old) );
} MFEND

/******************************************************************************/
/* FUNCTION: stripCharData( [yesno : DOM_BOOL] ) : DOM_BOOL                   */
/* If 'yesno' is TRUE then all leading and trailing whitespaces are stripped  */
/* from the character data strings. If it is set to FALSE then the character  */
/* data is not changed before it is passed to the library callback function.  */
/* If no argument is given, the function returns the current setting only.    */
/* Default: stripCharData = TRUE.                                             */
/******************************************************************************/
MFUNC( stripCharData, MCnop )
{
  MFnargsCheckRange(0,1);

  int old = xmlStripCharData;

  if (MVnargs>0) {
    MFargCheck(1,DOM_BOOL);

    if (MFisTrue(MFarg(1))) {
      xmlStripCharData = true;
    } else if(MFisFalse(MFarg(1))) {
      xmlStripCharData = false;
    } else {
      MFerror("TRUE or FALSE expected.");
    }
  }

  MFreturn( MFbool(old) );
} MFEND

/******************************************************************************/
/* FUNCTION: bufLen( [length : DOM_INT] ) : DOM_INT                           */
/* If 'length' is a positve number less than 2^31 then the length of the file */
/* read buffer is set to this number. If no argument is given, the function   */
/* returns the current setting only.                                          */
/* Default: bufLen = 8*1024.                                                  */
/******************************************************************************/
MFUNC( bufLen, MCnop )
{
  MFnargsCheckRange(0,1);

  int old = xmlBufLen;

  if (MVnargs>0) {
    MFargCheck(1,DOM_INT);

    int num = MFint(MFarg(1));
    if (num<=0) {
      MFerror("Positive number expected.");
    }
    xmlBufLen = num;
  }

  MFreturn( MFint(old) );
} MFEND
