diff options
Diffstat (limited to 'ast/xml.c')
-rw-r--r-- | ast/xml.c | 7119 |
1 files changed, 7119 insertions, 0 deletions
diff --git a/ast/xml.c b/ast/xml.c new file mode 100644 index 0000000..541132d --- /dev/null +++ b/ast/xml.c @@ -0,0 +1,7119 @@ +/* +* Name: +* xml.c + +* Purpose: +* Implement XML functions for AST. + +* Description: +* This file implements the Xml module which provides generic XML +* reading and writing functions for the XmlChan class. + +* Copyright: +* Copyright (C) 1997-2006 Council for the Central Laboratory of the +* Research Councils + +* Licence: +* This program is free software: you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* DSB: David S. Berry (Starlink) + +* History: +* 22-OCT-2003 (DSB): +* Original version. +* 12-JAN-2004 (DSB): +* Major revisions. +* 10-FEB-2004 (DSB): +* - Added debug conditional code to keep track of memory leaks. +* - Other minor bug fixes. +* 6-FEB-2004 (DSB): +* DefaultURI and astXmlAddURI modified to allow a blank URI to be +* used to ignore a default namespace URI provided by an enclosing +* element. +* 29-NOV-2004 (DSB): +* Added astXmlGetType method. +* 27-JAN-2005 (DSB): +* - Move astXmlTrace and associated code into conditional +* compilation blokc (included if DEBUG macro is defined). This +* speeds up the create and destruction of XmlObjects in non-DEBUG code. +* - Renamed the private Delete function as astXmlDelete and gave +* it protected access. +* - Modify astXmlDelete so that it can succesfully annul objects +* which have no parent. +* - Include extra info in some error messages. +* 1-MAR-2006 (DSB): +* Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM. +* 10-DEC-2008 (DSB): +* Allow a prefix to be included with the attribute name in +* astXmlGetAttributeValue. +*/ + + +/* Module Constants. */ +/* ----------------- */ +/* Set the name of the module we are implementing. This indicates to + the header files that define class interfaces that they should make + "protected" symbols available. NB, this module is not a proper AST + class, but it defines this macro sanyway in order to get the protected + symbols defined in memory.h */ +#define astCLASS Xml + +#define IND_INC 3 + + +/* Include files. */ +/* ============== */ +/* Interface definitions. */ +/* ---------------------- */ +#include "memory.h" /* Interface to the memory management module */ +#include "error.h" /* Interface to the error module */ +#include "xml.h" /* Interface to this module */ +#include "globals.h" /* Thread-safe global data access */ + +/* Error code definitions. */ +/* ----------------------- */ +#include "ast_err.h" /* AST error codes */ + +/* C header files. */ +/* --------------- */ +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + + +/* +* Name: +* MAKE_CHECK + +* Type: +* Private macro. + +* Purpose: +* Implement the astXmlCheck<type>_ function for XML structures. + +* Synopsis: +* #include "xml.h" +* MAKE_CHECK(type,id) + +* Class Membership: +* Defined by the xml module. + +* Description: +* This macro expands to an implementation of the protected +* astXmlCheck<type>_ function (q.v.) which validates membership of +* a specified XML data type. + +* Parameters: +* type +* The type whose membership is to be validated (e.g. "Element" not +* "XmlElement"). +* id +* The constant (e.g. "AST__XMLELEM") defining the data type. + +* Notes: +* - To avoid problems with some compilers, you should not leave any white +* space around the macro arguments. +*/ + +/* Define the macro. */ +#define MAKE_CHECK(type,id) \ +\ +/* Declare the function */ \ +AstXml##type *astXmlCheck##type##_( void *this, int nullok, int *status ) { \ +\ +/* Local Variables: */\ + AstXml##type *result; /* The returned pointer */\ +\ +/* Check the global error status. If an error has already occurred just\ + return the supplied pointer. This is so that functions such as\ + astXmlAnnul which do not check the inherited status receive the\ + supplied pointer. */\ + if( !astOK ) return this;\ +\ +/* Initialise */\ + result = NULL;\ +\ +/* If the pointer is NULL issue an error if nullok is zero. */\ + if( !this ) {\ + if( !nullok ) astError( AST__PTRIN, "astXmlCheck"#type": Invalid "\ + "NULL pointer supplied." , status);\ +\ +/* Otherwise get the "type" component which holds a magic value for each\ + different class of structure. Compare this value against all valid \ + classes of structure. If no match is found, the pointer does not \ + identify an suitable structure, and so report an error and return \ + NULL. */\ + } else {\ + if( !astXmlCheckType( ( AstXmlObject * ) this, id ) ) {\ + astError( AST__PTRIN, "astXmlCheck"#type": Invalid pointer "\ + "supplied; pointer to AstXml"#type" required." , status);\ + } else {\ + result = (AstXml##type *) this;\ + }\ + }\ +\ +/* Return the result. */\ + return result;\ +} + + +/* Module variables. */ +/* ================= */ + +/* Define macros for accessing all items of thread-safe global data + used by this module. */ +#ifdef THREAD_SAFE + +#define next_id astGLOBAL(Xml,Next_ID) +#define gettag_buff astGLOBAL(Xml,GetTag_Buff) +#define GLOBAL_inits globals->Next_ID = 0; +astMAKE_INITGLOBALS(Xml) + +/* Set up mutexes */ +static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_MUTEX1 pthread_mutex_lock( &mutex1 ); +#define UNLOCK_MUTEX1 pthread_mutex_unlock( &mutex1 ); + +/* If thread safety is not needed, declare globals at static variables. */ +#else + +static int next_id = 0; +static char gettag_buff[ AST__XML_GETTAG_BUFF_LEN + 1 ]; + +#define LOCK_MUTEX1 +#define UNLOCK_MUTEX1 + +#ifdef DEBUG /* Not available in thread-safe compilations */ +static int nobj = 0; +static AstXmlObject **existing_objects = NULL; +#endif + +#endif + + +/* Function prototypes. */ +/* ==================== */ + +/* Private member functions. */ +/* ------------------------- */ +static AstXmlAttribute *FindAttribute( AstXmlElement *, const char *, int * ); +static AstXmlAttribute *NewAttribute( const char *, const char *, const char *, int * ); +static AstXmlDocument *NewDocument( int * ); +static AstXmlPrologue *NewPrologue( AstXmlDocument *, int * ); +static AstXmlNamespace *NewNamespace( const char *, const char *, int * ); +static char *AppendChar( char *, int *, char, int * ); +static char *AppendLine( char *, int *, const char *, int, int * ); +static char *RemoveEscapes( const char *, int * ); +static char *CleanText( const char *, int * ); +static const char *AddEscapes( const char *, int * ); +static const char *DefaultURI( AstXmlElement *, int * ); +static const char *Format( AstXmlObject *, int, int * ); +static char *FormatTag( AstXmlObject *, int, int * ); +static const char *ResolvePrefix( const char *, AstXmlElement *, int * ); +static int CheckType( long int, long int, int * ); +static int MatchName( AstXmlElement *, const char *, int * ); +static int Ustrcmp( const char *, const char *, int * ); +static void AddContent( AstXmlParent *, int, AstXmlContentItem *, int * ); +static void CheckName( const char *, const char *, const char *, int, int * ); +static void CheckPrefName( char *, const char *, const char *, int * ); +static void CleanXml( AstXmlObject *, long int, int * ); +static void InitXmlAttribute( AstXmlAttribute *, int, const char *, const char *, const char *, int * ); +static void InitXmlCDataSection( AstXmlCDataSection *, int, const char *, int * ); +static void InitXmlWhite( AstXmlWhite *, int, const char *, int * ); +static void InitXmlBlack( AstXmlBlack *, int, const char *, int * ); +static void InitXmlComment( AstXmlComment *, int, const char *, int * ); +static void InitXmlDocument( AstXmlDocument *, int, int * ); +static void InitXmlPrologue( AstXmlPrologue *, int, int * ); +static void InitXmlDeclPI( AstXmlDeclPI *, int, const char *, int * ); +static void InitXmlDTDec( AstXmlDTDec *, int, const char *, const char *, const char *, int * ); +static void InitXmlElement( AstXmlElement *, int, const char *, const char *, int * ); +static void InitXmlNamespace( AstXmlNamespace *, int, const char *, const char *, int * ); +static void InitXmlObject( AstXmlObject *, long int, int * ); +static void InitXmlPI( AstXmlPI *, int, const char *, const char *, int * ); +static AstXmlElement *ReadContent( AstXmlDocument **, int, int (*)( AstXmlElement *, int * ), int, char (*)( void *, int * ), void *, int, int * ); + +#ifdef DEBUG +static void AddObjectToList( AstXmlObject * ); +static void RemoveObjectFromList( AstXmlObject * ); +#endif + +/* Function implementations. */ +/* ========================= */ + +/* Create the astXmlCheck... functiosn which check a pointer identifies + an XML structure of a given type. */ + +MAKE_CHECK(Document,AST__XMLDOC) +MAKE_CHECK(Object,AST__XMLOBJECT) +MAKE_CHECK(Element,AST__XMLELEM) +MAKE_CHECK(Attribute,AST__XMLATTR) +MAKE_CHECK(CDataSection,AST__XMLCDATA) +MAKE_CHECK(Comment,AST__XMLCOM) +MAKE_CHECK(PI,AST__XMLPI) +MAKE_CHECK(Namespace,AST__XMLNAME) +MAKE_CHECK(Prologue,AST__XMLPRO) +MAKE_CHECK(DeclPI,AST__XMLDEC) +MAKE_CHECK(DTDec,AST__XMLDTD) +MAKE_CHECK(White,AST__XMLWHITE) +MAKE_CHECK(Black,AST__XMLBLACK) +MAKE_CHECK(CharData,AST__XMLCHAR) +MAKE_CHECK(ContentItem,AST__XMLCONT) +MAKE_CHECK(MiscItem,AST__XMLMISC) +MAKE_CHECK(Parent,AST__XMLPAR) + + +static void AddContent( AstXmlParent *this, int where, AstXmlContentItem *item, int *status ){ +/* +* Name: +* AddContent + +* Purpose: +* Add a content item to an XmlElement. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void AddContent( AstXmlParent *this, int where, AstXmlContentItem *item, int *status ) + +* Description: +* This function adds a supplied item to a specified XmlElement or +* XmlDocument. An error is reported if the item is not appropriate. + +* Parameters: +* this +* The pointer to the element or document to be modified. +* where +* Ignored if "this" is an XmlElement pointer. Otherwise, "where" +* indicates where the item should be added to the document: +* 1 - In the prologue, after the XML declaration but before the DTD. +* 2 - In the prologue, after the DTD but before the root element. +* 3 - In the epilogue, after the root element. +* item +* Pointer to the content item to be added to the element. If +* "this" is an XmlElement, this can be a pointer to any of the +* following types: AstXmlElement, AstXmlWhite, AstXmlBlack, +* AstXmlCDataSection, AstXmlComment, AstXmlPI. If "this" is a +* document, the list is restricted to: AstXmlWhite, AstXmlComment, +* AstXmlPI. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstXmlDocument *doc; /* Document pointer */ + AstXmlElement *elem; /* Element pointer */ + AstXmlPrologue *pro; /* Prologue pointer */ + int nitem; /* Number of items in the parent */ + +/* Check the global error status and the supplied pointers. */ + if( !astOK || !this || !item ) return; + +/* Split for the two forms of parent. */ + if( astXmlCheckType( this, AST__XMLELEM ) ) { + elem = (AstXmlElement *) this; + +/* Save the number of content items currently stored in the element. */ + nitem = ( elem->items ) ? elem->nitem : 0; + +/* Attempt to extend the array to hold an extra item. */ + elem->items = astGrow( elem->items, nitem + 1, + sizeof( AstXmlContentItem * ) ); + +/* Check the memory was allocated succesfully. */ + if( astOK ) { + +/* Store the supplied pointer in the array of content items. */ + elem->items[ nitem ] = item; + +/* Increment the number of content items in this element */ + elem->nitem = nitem + 1; + +/* Indicate that the item is owned by the element. */ + ( (AstXmlObject *) item )->parent = this; + } + +/* Now deal with cases where we are adding an item to the prologue or + epilogue of the document. */ + } else { + if( !astXmlCheckType( item, AST__XMLMISC ) ){ + astError( AST__INTER, "AddContent(xml): Inappropriate attempt to " + "add an item of type %ld to an XML document (internal " + "AST programming error).", status, ( (AstXmlObject *) item)->type ); + + } else if( !astXmlCheckType( this, AST__XMLDOC ) ){ + astError( AST__INTER, "AddContent(xml): Inappropriate attempt to " + "add an item of type %ld to an XML object of type %ld " + "(internal AST programming error).", status, + ( (AstXmlObject *) item)->type, + ( (AstXmlObject *) this)->type ); + + } else { + doc = (AstXmlDocument *) this; + +/* Create a prologue if necessary. */ + if( where < 3 && !doc->prolog ) doc->prolog = NewPrologue( doc, status ); + pro = doc->prolog; + + if( where < 2 ) { + nitem = ( pro->misc1 ) ? pro->nmisc1 : 0; + pro->misc1 = astGrow( pro->misc1, nitem + 1, sizeof( AstXmlMiscItem * ) ); + if( astOK ) { + pro->misc1[ nitem ] = item; + pro->nmisc1 = nitem + 1; + ( (AstXmlObject *) item )->parent = (AstXmlParent *) pro; + } + + } else if( where == 2 ) { + nitem = ( pro->misc2 ) ? pro->nmisc2 : 0; + pro->misc2 = astGrow( pro->misc2, nitem + 1, sizeof( AstXmlMiscItem * ) ); + if( astOK ) { + pro->misc2[ nitem ] = item; + pro->nmisc2 = nitem + 1; + ( (AstXmlObject *) item )->parent = (AstXmlParent *) pro; + } + + } else { + nitem = ( doc->epilog ) ? doc->nepi : 0; + doc->epilog = astGrow( doc->epilog, nitem + 1, sizeof( AstXmlMiscItem * ) ); + if( astOK ) { + doc->epilog[ nitem ] = item; + doc->nepi = nitem + 1; + ( (AstXmlObject *) item )->parent = this; + } + } + } + } +} + +static const char *AddEscapes( const char *text, int *status ){ +/* +* Name: +* AddEscapes + +* Purpose: +* Replaces characters by corresponding entity references. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* const char *AddEscapes( const char *text, int *status ) + +* Description: +* This function produces a dynamic copy of the supplied text in which +* occurrences of "&", "<", ">", and "\"" are replaced by the corresponding +* XML entity reference. +* +* The "&" character is only replaced by an entity reference if it is +* followed by a non-name character (i.e. anything except a letter +* underscore or colon). If it is followed by a name character, it is +* assumed to mark the start of an entity reference. + +* Parameters: +* text +* A pointer to a text string. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated string containing the required +* copy. + +* Notes: +* - NULL is returned if this function is called with the global error +* status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + char *result; /* Returned pointer */ + const char *c; /* Pointer to next supplied character */ + char *d; /* Pointer to next returned character */ + +/* Initialise */ + result = NULL; + +/* Return if the pointer is NULL or if an error has occurred. */ + if( !astOK || !text ) return result; + +/* Allocate the maximum possible amount of memory that may be needed to + store the returned string. */ + result = astMalloc( 6*strlen( text ) + 1 ); + +/* Check the pointer can be used safely. */ + if( astOK ) { + +/* Loop round every character in the supplied text. */ + c = text - 1; + d = result; + while( *(++c) ) { + +/* We replace this character if it is a <, >, ', &, or ". */ + if( *c == '<' ) { + strcpy( d, "<" ); + d += 4; + + } else if( *c == '>' ) { + strcpy( d, ">" ); + d += 4; + + } else if( *c == '"' ) { + strcpy( d, """ ); + d += 6; + + } else if( *c == '\'' ) { + strcpy( d, "'" ); + d += 6; + + } else if( *c == '&' ) { + strcpy( d, "&" ); + d += 5; + +/* Otherwise just append the supplied character. */ + } else { + *(d++) = *c; + } + } + +/* Terminate the returned string. */ + *d = 0; + +/* Reallocate the string to free up any unused space. */ + result = astRealloc( result, d - result + 1 ); + } + +/* Return the result. */ + return (const char *) result; +} + + +#ifdef DEBUG +static void AddObjectToList( AstXmlObject *obj ){ +/* +* Name: +* AddObjectToList + +* Purpose: +* Adds an XmlObject to a static list of all currently active XmlObjects. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void AddObjectToList( AstXmlObject *obj ) + +* Description: +* This function adds the supplied pointer to a static list of pointers, +* and increments the number of elements in the list. This list holds +* pointers to all the XmlObjects which currently exist. + +* Parameters: +* this +* A pointer to a new XmlObject. +*/ + +/* Return if the pointer is NULL or if an error has occurred. */ + if( !astOK || !obj ) return; + +/* Increment the number of objects in the list and increase the size of + the list. */ + astBeginPM; + existing_objects = astGrow( existing_objects, ++nobj, sizeof( AstXmlObject *) ); + astEndPM; + +/* Add the new pointer to the end of the list. */ + existing_objects[ nobj - 1 ] = obj; +} +#endif + +static char *AppendChar( char *str1, int *nc, char ch, int *status ) { +/* +* Name: +* AppendChar + +* Purpose: +* Append a character to a string which grows dynamically. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* char *AppendChar( char *str1, int *nc, char ch, int *status ) + +* Description: +* This function appends a character to a dynamically +* allocated string, extending the dynamic string as necessary to +* accommodate the new character (plus the final null). + +* Parameters: +* str1 +* Pointer to the null-terminated dynamic string, whose memory +* has been allocated using the AST memory allocation functions +* defined in "memory.h". If no space has yet been allocated for +* this string, a NULL pointer may be given and fresh space will +* be allocated by this function. +* nc +* Pointer to an integer containing the number of characters in +* the dynamic string (excluding the final null). This is used +* to save repeated searching of this string to determine its +* length and it defines the point where the new string will be +* appended. Its value is updated by this function to include +* the extra characters appended. +* +* If "str1" is NULL, the initial value supplied for "*nc" will +* be ignored and zero will be used. +* ch +* The character which is to be appended to "str1". +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A possibly new pointer to the dynamic string with the new character +* appended (its location in memory may have to change if it has to +* be extended, in which case the original memory is automatically +* freed by this function). When the string is no longer required, +* its memory should be freed using astFree. + +* Notes: +* - If this function is invoked with the global error status set +* or if it should fail for any reason, then the returned pointer +* will be equal to "str1" and the dynamic string contents will be +* unchanged. +*/ + +/* Local Variables: */ + char *result; /* Pointer value to return */ + int len; /* Length of new string */ + +/* Initialise. */ + result = str1; + +/* If the first string pointer is NULL, also initialise the character + count to zero. */ + if ( !str1 ) *nc = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Calculate the total string length once the character has been added. */ + len = *nc + 1; + +/* Extend the dynamic string to the required length, including + a final null. Save the resulting pointer, which will be + returned. */ + result = astGrow( str1, len + 1, sizeof( char ) ); + +/* If OK, append the second string and update the total character + count. */ + if ( astOK ) { + result[ *nc ] = ch; + *nc = len; + result[ *nc ] = 0; + } + +/* Return the result pointer. */ + return result; +} + +static char *AppendLine( char *str1, int *nc, const char *str2, int ind, int *status ) { +/* +* Name: +* AppendLine + +* Purpose: +* Append an indented new line to another string which grows dynamically. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* char *AppendLine( char *str1, int *nc, const char *str2, int ind, int *status ) + +* Description: +* This function appends one string to another dynamically +* allocated string, extending the dynamic string as necessary to +* accommodate the new characters (plus the final null). +* +* A newline character is inserted if necessary to ensure that the "str2" +* string starts on a newline. If "ind" is positive, spaces are added +* as necessary to ensure that "str2" begins with the specified number of +* spaces. + +* Parameters: +* str1 +* Pointer to the null-terminated dynamic string, whose memory +* has been allocated using the AST memory allocation functions +* defined in "memory.h". If no space has yet been allocated for +* this string, a NULL pointer may be given and fresh space will +* be allocated by this function. +* nc +* Pointer to an integer containing the number of characters in +* the dynamic string (excluding the final null). This is used +* to save repeated searching of this string to determine its +* length and it defines the point where the new string will be +* appended. Its value is updated by this function to include +* the extra characters appended. +* +* If "str1" is NULL, the initial value supplied for "*nc" will +* be ignored and zero will be used. +* str2 +* Pointer to a constant null-terminated string, a copy of which +* is to be appended to "str1". +* ind +* The number of spaces to use as the indentation string. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A possibly new pointer to the dynamic string with the new string +* appended (its location in memory may have to change if it has to +* be extended, in which case the original memory is automatically +* freed by this function). When the string is no longer required, +* its memory should be freed using astFree. + +* Notes: +* - If this function is invoked with the global error status set +* or if it should fail for any reason, then the returned pointer +* will be equal to "str1" and the dynamic string contents will be +* unchanged. +*/ + +/* Local Variables: */ + char *c; /* Point to next character */ + char *result; /* Pointer value to return */ + char *temp; /* Pointer to modified string */ + int j; /* Loop count */ + +/* Initialise. */ + result = str1; + +/* If the first string pointer is NULL, also initialise the character + count to zero. */ + if ( !str1 ) *nc = 0; + +/* Check the global error status. */ + if ( !astOK || !str2 ) return result; + +/* Remove any trailing white space (except for newlines) from the supplied + string. */ + if( *nc > 0 ) { + c = str1 + *nc - 1; + while( isspace( *c ) && *c != '\n' ) { + *(c--) = 0; + (*nc)--; + } + +/* If the last character in the returned string is not now a newline, + append a newline, so long as the new item does not start with a newline. */ + if( str1[ *nc - 1 ] != '\n' ) { + temp = AppendChar( str1, nc, '\n', status ); + } else { + temp = str1; + } + + } else { + temp = str1; + } + +/* If a fixed indentation is specified, skip over any leading spaces in + the second string. */ + if( str2 ) { + if( ind > 0 ) { + while( isspace( *str2 ) ) str2++; + } + +/* If the first character of the second string is a newline, ignore it. */ + if( str2[ 0 ] == '\n' ) str2++; + } + +/* Append the indentation string. */ + for( j = 0; j < ind; j++ ) temp = AppendChar( temp, nc, ' ', status ); + +/* Append the supplied string. */ + return astAppendString( temp, nc, str2 ); +} + +void astXmlAddAttr_( AstXmlElement *this, const char *name, const char *value, + const char *prefix, int *status ){ +/* +*+ +* Name: +* astXmlAddAttr + +* Purpose: +* Add an attribute to an XmlElement. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddAttr( AstXmlElement *this, const char *name, +* const char *value, const char *prefix ) + +* Description: +* This function adds an attribute to a specified XmlElement. If the +* element already contains an attribute with the given name amd prefix, +* then the value of the attribute is changed to be the supplied value. + +* Parameters: +* this +* The pointer to the element to be modified. +* name +* Pointer to a null terminated string containing the attribute name. +* value +* Pointer to a null terminated string containing the attribute value. +* prefix +* The namespace prefix for the attribute. May be NULL or blank, in +* which case any prefix at the start of "name" is used. +*- +*/ + +/* Local Variables: */ + AstXmlAttribute *attr; /* The new attribute. */ + AstXmlAttribute *oldattr; /* Pointer to existing attribute */ + int i; /* Loop index */ + int nattr; /* Number of attributes in the element */ + int oldi; /* Index of existing attribute */ + char *my_value; /* Cleaned value text */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Initialise */ + oldattr = NULL; + +/* Clean the value text. */ + my_value = CleanText( value, status ); + +/* Create a new XmlAttribute. */ + attr = NewAttribute( name, my_value, prefix, status ); + +/* Free the memory */ + my_value = astFree( my_value ); + +/* If OK, indicate that the attribute is owned by the element. */ + if( astOK ) { + ( (AstXmlObject *) attr )->parent = (AstXmlParent *) this; + +/* Save the number of attributes currently stored in the element. */ + nattr = ( this->attrs ) ? this->nattr : 0; + +/* Search the existing attributes to see if an attribute with the given + name and prefix already exists. */ + oldi = -1; + for( i = 0; i < nattr; i++ ) { + oldattr = this->attrs[ i ]; + if( !strcmp( oldattr->name, attr->name ) ) { + if( !oldattr->prefix && !attr->prefix ) { + oldi = i; + break; + } else if( oldattr->prefix && attr->prefix && + !strcmp( oldattr->prefix, attr->prefix ) ){ + oldi = i; + break; + } + } + } + +/* If there is an existing attribute with the same name and prefix, + replace the old attribute with the new one created above. */ + if( oldi > -1 ){ + ((AstXmlObject *)oldattr)->parent = NULL; + oldattr = astXmlAnnul( oldattr ); + this->attrs[ oldi ] = attr; + +/* Otherwise, attempt to extend the array to hold an extra attribute. */ + } else { + this->attrs = astGrow( this->attrs, nattr + 1, + sizeof( AstXmlAttribute * ) ); + +/* Check all has gone OK. */ + if( astOK ) { + +/* Store the attribute pointer in the array of attribute pointers. */ + this->attrs[ nattr ] = attr; + +/* Increment the number of content items in this element */ + this->nattr = nattr + 1; + + } + } + } +} + +void astXmlAddCDataSection_( AstXmlElement *this, const char *text, int *status ){ +/* +*+ +* Name: +* astXmlAddCDataSection + +* Purpose: +* Create a new XmlCDataSection and add it to an XmlElement. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddCDataSection( AstXmlElement *this, const char *text ) + +* Description: +* This function creates a new XmlCDataSection structure representing +* an unparsed character data (CDATA) section, and adds it into an +* existing element. + +* Parameters: +* this +* A pointer to the element to be modified. +* text +* Pointer to a null terminated string containing the character data. + +*- +*/ + +/* Local Variables: */ + AstXmlCDataSection *new; /* Pointer to new structure */ + char *my_text; /* Cleaned text */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Allocate space for the new structure. */ + new = (AstXmlCDataSection *) astMalloc( sizeof( AstXmlCDataSection ) ); + +/* Clean the text. */ + my_text = CleanText( text, status ); + +/* Initialise it. */ + InitXmlCDataSection( new, AST__XMLCDATA, my_text, status ); + +/* Free the memory */ + my_text = astFree( my_text ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) new, status ); + } +} + +void astXmlAddCharData_( AstXmlParent *this, int where, const char *text, int *status ){ +/* +*+ +* Name: +* astXmlAddCharData + +* Purpose: +* Create a new XmlCharData and add it to an XmlElement or XmlDocument. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddCharData( AstXmlParent *this, int where, const char *text ) + +* Description: +* This function creates a new XmlCharData structure representing +* parsed character data, and adds it into an existing element or +* document. + +* Parameters: +* this +* Pointer to the element or document to be modified. +* where +* Ignored if "this" is an XmlElement pointer. Otherwise, "where" +* indicates where the item should be added to the document: +* 1 - In the prologue, after the XML declaration but before the DTD. +* 2 - In the prologue, after the DTD but before the root element. +* 3 - In the epilogue, after the root element. +* text +* Pointer to a null terminated string containing the character data. +* If "this" is a document, the text must consist entirely of white +* space. + +*- +*/ + +/* Local Variables: */ + AstXmlCharData *new; /* Pointer to the new structure */ + char *my_text; /* Pointer to cleaned text */ + char *c; /* Pointer to next character */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Initialise */ + new = NULL; + +/* Clean the text by replacing "\r\n" by "\n". */ + my_text = CleanText( text, status ); + +/* See if the text is all white. */ + c = my_text - 1; + while( *(++c) && isspace( *c ) ); + +/* If the string contains a non-white character, allocate memory for + a XmlBlack structure, and initialise it to hold the supplied text. + Otherwise, allocate memory for a XmlWhite structure, and initialise it + to hold the supplied text. */ + if( *c ) { + if( astXmlCheckType( this, AST__XMLDOC ) ) { + astError( AST__XMLCM, "astXmlAddCharData(xml): Illegal attempt " + "to add non-white character data to the prologue or " + "epilogue of an XML document: \"%s\".", status, my_text ); + } else { + new = (AstXmlCharData *) astMalloc( sizeof( AstXmlBlack ) ); + InitXmlBlack( (AstXmlBlack *) new, AST__XMLBLACK, my_text, status ); + } + + } else { + new = (AstXmlCharData *) astMalloc( sizeof( AstXmlWhite ) ); + InitXmlWhite( (AstXmlWhite *) new, AST__XMLWHITE, my_text, status ); + } + +/* Free the memory holding the cleaned text */ + my_text = astFree( my_text ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( this, where, (AstXmlContentItem *) new, status ); + } +} + +void astXmlAddComment_( AstXmlParent *this, int where, const char *text, int *status ){ +/* +*+ +* Name: +* astXmlAddComment + +* Purpose: +* Create a new XmlComment and add it to an XmlElement or XmlDocument. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddComment( AstXmlParent *this, int where, const char *text ) + +* Description: +* This function creates a new XmlComment structure representing +* an XML comment, and adds it into an existing element or document. + +* Parameters: +* this +* Pointer to the element or document to be modified. +* where +* Ignored if "this" is an XmlElement pointer. Otherwise, "where" +* indicates where the item should be added to the document: +* 1 - In the prologue, after the XML declaration but before the DTD. +* 2 - In the prologue, after the DTD but before the root element. +* 3 - In the epilogue, after the root element. +* text +* Pointer to a null terminated string containing the comment text. + +*- +*/ + +/* Local Variables: */ + AstXmlComment *new; /* Pointer to the new structure */ + char *my_text; /* Cleaned text */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Allocate space for the new structure. */ + new = (AstXmlComment *) astMalloc( sizeof( AstXmlComment ) ); + +/* Clean the text. */ + my_text = CleanText( text, status ); + +/* Initialise it. */ + InitXmlComment( new, AST__XMLCOM, my_text, status ); + +/* Free the memory */ + my_text = astFree( my_text ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( this, where, (AstXmlContentItem *) new, status ); + } + +} + +AstXmlElement *astXmlAddElement_( AstXmlElement *this, const char *name, + const char *prefix, int *status ){ +/* +*+ +* Name: +* astXmlAddElement + +* Purpose: +* Create a new empty XmlElement and adds it to an XmlElement. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlElement *astXmlAddElement( AstXmlElement *this, const char *name, +* const char *prefix ) + +* Description: +* This function creates a new XmlElement structure representing an +* empty XML element with the given name and namespace prefix, and +* adds it into an existing element. + +* Parameters: +* this +* A pointer to the element to be modified. This may be NULL. +* name +* The name for the element. +* prefix +* The namespace prefix for the element. May be NULL or blank, in +* which case any prefix at the start of "name" is used. + +* Returned Value: +* A pointer to the new structure is returned. This pointer should be +* freed using astXmlAnnul when no longer needed. + +* Notes: +* - A NULL pointer is returned if the inherited status value +* indicates an error has occurred on entry, or if this function +* should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstXmlElement *new; /* The returned pointer */ + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK ) return new; + +/* Allocate space for the new structure. */ + new = (AstXmlElement *) astMalloc( sizeof( AstXmlElement ) ); + +/* Initialise it. */ + InitXmlElement( new, AST__XMLELEM, name, prefix, status ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) new, status ); + } + +/* Return the result. */ + return new; + +} + +void astXmlAddPI_( AstXmlParent *this, int where, const char *target, const char *text, int *status ){ +/* +*+ +* Name: +* astXmlAddPI + +* Purpose: +* Create a new XmlPI and add it to an element or document. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddPI( AstXmlParent *this, int where, const char *target, +* const char *text ) + +* Description: +* This function creates a new XmlPI structure representing an +* XML "programming instruction", and adds it into an existing element +* or document. + +* Parameters: +* this +* Pointer to the element or document to be modified. This should +* be a pointer to an XmlElement or an XmlDocument. +* where +* Ignored if "this" is an XmlElement pointer. Otherwise, "where" +* indicates where the PI should be added to the document: +* 1 - In the prologue, after the XML declaration but before the DTD. +* 2 - In the prologue, after the DTD but before the root element. +* 3 - In the epilogue, after the root element. +* target +* Pointer to a null terminated string containing the PI target. +* text +* Pointer to a null terminated string containing the PI text. + +*- +*/ + +/* Local Variables: */ + AstXmlPI *new; /* Pointer to the new structure */ + char *my_text; /* Cleaned text */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Allocate space for the new structure. */ + new = (AstXmlPI *) astMalloc( sizeof( AstXmlPI ) ); + +/* Clean the text. */ + my_text = CleanText( text, status ); + +/* Initialise it. */ + InitXmlPI( new, AST__XMLPI, target, my_text, status ); + +/* Free the memory */ + my_text = astFree( my_text ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( this, where, (AstXmlContentItem *) new, status ); + } +} + +void astXmlAddURI_( AstXmlElement *this, const char *prefix, const char *uri, int *status ){ +/* +*+ +* Name: +* astXmlAddURI + +* Purpose: +* Add a namespace prefix definition to an XmlElement, or change the +* default namespace. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlAddURI( AstXmlElement *this, const char *prefix, +* const char *uri ) + +* Description: +* This function adds a namespace prefix definition to a specified +* XmlElement, or changes the default namespace. If the suppliedprefix +* is already defined in the element, the associated URI is changed to +* the supplied URI. + +* Parameters: +* this +* The pointer to the element to be modified. +* prefix +* Pointer to a null terminated string containing the namespace +* prefix. If this is NULL or blank, then the supplied URI is used +* as the default namespace for this element and all child elements +* (except for child elements which define their own default +* namespace). +* uri +* Pointer to a null terminated string containing the namespace URI. +* If this is NULL or blank, and "prefix" is also NULL or blank, then +* this has the same effect of there being no default namespace within +* the supplied element. +*- +*/ + +/* Local Variables: */ + AstXmlNamespace *ns; /* The new namespace definition */ + AstXmlNamespace *oldns; /* The existing namespace definition */ + int i; /* Loop index */ + int nc; /* Length of namespace prefix */ + int nnspref; /* Number of namespace defintions in the element */ + int oldi; /* Index of existing attribute */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Initialise */ + oldns = NULL; + +/* Store the used length of the namespace prefix. */ + nc = prefix ? astChrLen( prefix ) : 0; + +/* If no namespace prefix has been supplied, just change the default + namespace URI. */ + if( !nc ) { + if( uri ) { + this->defns = astStore( this->defns, uri, strlen( uri ) + 1 ); + } else { + this->defns = astStore( this->defns, "", 1 ); + } + +/* Otherwise, add the namespace definition to the element. */ + } else { + +/* Create a new XmlNamespace. */ + ns = NewNamespace( prefix, uri, status ); + +/* If OK, indicate that the namespace is owned by the element. */ + if( astOK ) { + ( (AstXmlObject *) ns )->parent = (AstXmlParent *) this; + +/* Save the number of namespace definitions currently stored in the element. */ + nnspref = ( this->nsprefs ) ? this->nnspref : 0; + +/* Search the existing prefixes to see if a namespace with the given + prefix already exists. */ + oldi = -1; + for( i = 0; i < nnspref; i++ ) { + oldns = this->nsprefs[ i ]; + if( !strcmp( oldns->prefix, ns->prefix ) ) { + oldi = i; + break; + } + } + +/* If there is an existing namespace with the same prefix, replace the old + namespace with the new one created above. */ + if( oldi > -1 ){ + ((AstXmlObject *)oldns)->parent = NULL; + oldns = astXmlAnnul( oldns ); + this->nsprefs[ oldi ] = ns; + +/* Otherwise, attempt to extend the array to hold an extra namespace definition. */ + } else { + this->nsprefs = astGrow( this->nsprefs, nnspref + 1, + sizeof( AstXmlNamespace * ) ); + +/* Check all has gone OK. */ + if( astOK ) { + +/* Store the Namespace pointer in the array of Namespace pointers. */ + this->nsprefs[ nnspref ] = ns; + +/* Increment the number of namespaces in this element */ + this->nnspref = nnspref + 1; + } + } + } + } +} + +void *astXmlAnnul_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlAnnul + +* Purpose: +* Free the resources used by an XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void *astXmlAnnul( AstXmlObject *this ) + +* Description: +* This function frees the resources used to hold the XmlObject, together +* with any child objects contained within the supplied XmlObject. A NULL +* pointer is always returned. If the supplied object is still in use +* (that is, if its parent XmlElement still exists) then the resources +* are not freed, and a copy of the supplied pointer is returned. + +* Parameters: +* this +* pointer to the XmlObject to be freed. + +* Returned Value: +* A NULL pointer, or the supplied pointer if the XmlObject is still +* in use. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*- +*/ + +/* Return if a NULL pointer has been suppplied. */ + if( !this ) return NULL; + +/* Return the supplied pointer if the objects parent still exists. */ + if( this->parent && + astXmlCheckType( this->parent, AST__XMLPAR ) ) return this; + +#ifdef DEBUG +/* Remove the supplied object from the list of currently active XmlObjects. */ + RemoveObjectFromList( this ); +#endif + +/* Clean the objects contents, and free the memory holding the XmlObject. */ + CleanXml( this, this->type, status ); + astFree( this ); + +/* Return a NULL pointer. */ + return NULL; +} + +void *astXmlAnnulTree_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlAnnulTree + +* Purpose: +* Free the resources used by a tree of XmlObjects. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void *astXmlAnnulTree( AstXmlObject *this ) + +* Description: +* This function finds the head of the tree containing the supplied +* XmlObject (either an XmlElement or an XmlDocument), and frees the +* resources associated with all members of the tree. A NULL pointer +* is always returned. + +* Parameters: +* this +* Pointer to a member of the tree of XmlObjects to be freed. + +* Returned Value: +* A NULL pointer. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*- +*/ + +/* Return if a NULL pointer has been suppplied. */ + if( !this ) return NULL; + +/* Find the root and annull it. This will free all children (i.e. + the entire tree). */ + return astXmlAnnul( astXmlGetRoot( this ) ); +} + +AstXmlObject *astXmlCopy_( AstXmlObject *this, int *status ) { +/* +*+ +* Name: +* astXmlCopy + +* Purpose: +* Produce a deep copy of a supplied XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlObject *astXmlCopy( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a deep copy of the supplied +* XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject to copy. + +* Returned Value: +* Pointer to the new copy. + +* Notes: +* - NULL is returned if NULL pointer is supplied. +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + + +/* Local Variables: */ + AstXmlAttribute *attr; + AstXmlBlack *black; + AstXmlCDataSection *cdata; + AstXmlComment *comm; + AstXmlDTDec *dtd; + AstXmlDeclPI *dec; + AstXmlDocument *doc, *newdoc; + AstXmlElement *elem, *newelem; + AstXmlNamespace *ns; + AstXmlObject *new; + AstXmlPI *pi; + AstXmlPrologue *pro, *newpro; + AstXmlWhite *white; + int i, type; + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK || !this ) return new; + +/* Initialise a new XmlObject of the required class, and copy any + sub-objects. */ + type = this->type; + if( type == AST__XMLELEM ){ + elem = (AstXmlElement *) this; + new = astMalloc( sizeof( AstXmlElement ) ); + InitXmlElement( (AstXmlElement *) new, AST__XMLELEM, + elem->name, elem->prefix, status ); + + newelem = (AstXmlElement *) new; + + newelem->attrs = astMalloc( sizeof( AstXmlAttribute *) * (size_t)elem->nattr ); + newelem->nattr = elem->nattr; + for( i = 0; i < elem->nattr; i++ ) { + newelem->attrs[ i ] = (AstXmlAttribute *) astXmlCopy( elem->attrs[ i ] ); + ((AstXmlObject *) newelem->attrs[ i ])->parent = (AstXmlParent *) newelem; + } + + newelem->items = astMalloc( sizeof( AstXmlContentItem *) * (size_t)elem->nitem ); + newelem->nitem = elem->nitem; + for( i = 0; i < elem->nitem; i++ ) { + newelem->items[ i ] = (AstXmlContentItem *) astXmlCopy( elem->items[ i ] ); + ((AstXmlObject *) newelem->items[ i ])->parent = (AstXmlParent *) newelem; + } + + newelem->nsprefs = astMalloc( sizeof( AstXmlNamespace *) * (size_t)elem->nnspref ); + newelem->nnspref = elem->nnspref; + for( i = 0; i < elem->nnspref; i++ ) { + newelem->nsprefs[ i ] = (AstXmlNamespace *) astXmlCopy( elem->nsprefs[ i ] ); + ((AstXmlObject *) newelem->nsprefs[ i ])->parent = (AstXmlParent *) newelem; + } + + if( elem->defns ) { + newelem->defns = astStore( NULL, elem->defns, + strlen( elem->defns ) + 1 ); + } + + newelem->complete = elem->complete; + + + } else if( type == AST__XMLATTR ){ + attr = (AstXmlAttribute *) this; + new = astMalloc( sizeof( AstXmlAttribute ) ); + InitXmlAttribute( (AstXmlAttribute *) new, AST__XMLATTR, + attr->name, attr->value, attr->prefix, status ); + + } else if( type == AST__XMLBLACK ){ + black = (AstXmlBlack *) this; + new = astMalloc( sizeof( AstXmlBlack ) ); + InitXmlBlack( (AstXmlBlack *) new, AST__XMLBLACK, + black->text, status ); + + } else if( type == AST__XMLWHITE ){ + white = (AstXmlWhite *) this; + new = astMalloc( sizeof( AstXmlWhite ) ); + InitXmlWhite( (AstXmlWhite *) new, AST__XMLWHITE, + white->text, status ); + + } else if( type == AST__XMLCDATA ){ + cdata = (AstXmlCDataSection *) this; + new = astMalloc( sizeof( AstXmlCDataSection ) ); + InitXmlCDataSection( (AstXmlCDataSection *) new, AST__XMLCDATA, + cdata->text, status ); + + } else if( type == AST__XMLCOM ){ + comm = (AstXmlComment *) this; + new = astMalloc( sizeof( AstXmlComment ) ); + InitXmlComment( (AstXmlComment *) new, AST__XMLCOM, + comm->text, status ); + + } else if( type == AST__XMLPI ){ + pi = (AstXmlPI *) this; + new = astMalloc( sizeof( AstXmlPI ) ); + InitXmlPI( (AstXmlPI *) new, AST__XMLPI, pi->target, pi->text, status ); + + } else if( type == AST__XMLNAME ){ + ns = (AstXmlNamespace *) this; + new = astMalloc( sizeof( AstXmlNamespace ) ); + InitXmlNamespace( (AstXmlNamespace *) new, AST__XMLNAME, ns->prefix, + ns->uri, status ); + + } else if( type == AST__XMLDOC ){ + doc = (AstXmlDocument *) this; + new = astMalloc( sizeof( AstXmlDocument ) ); + InitXmlDocument( (AstXmlDocument *) new, AST__XMLDOC, status ); + + newdoc = (AstXmlDocument *) new; + + if( doc->prolog ) { + newdoc->prolog = (AstXmlPrologue *) astXmlCopy( doc->prolog ); + ((AstXmlObject *) newdoc->prolog)->parent = (AstXmlParent *) newdoc; + } + + if( doc->root ) { + newdoc->root = (AstXmlElement *) astXmlCopy( doc->root ); + ((AstXmlObject *) newdoc->root)->parent = (AstXmlParent *) newdoc; + } + + newdoc->epilog = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)doc->nepi ); + newdoc->nepi = doc->nepi; + for( i = 0; i < doc->nepi; i++ ) { + newdoc->epilog[ i ] = (AstXmlMiscItem *) astXmlCopy( doc->epilog[ i ] ); + ((AstXmlObject *) newdoc->epilog[ i ])->parent = (AstXmlParent *) newdoc; + } + + newdoc->current = NULL; + + } else if( type == AST__XMLPRO ){ + pro = (AstXmlPrologue *) this; + new = astMalloc( sizeof( AstXmlPrologue ) ); + InitXmlPrologue( (AstXmlPrologue *) new, AST__XMLPRO, status ); + + newpro = (AstXmlPrologue *) new; + + if( pro->xmldecl ) { + newpro->xmldecl = (AstXmlDeclPI *) astXmlCopy( pro->xmldecl ); + ((AstXmlObject *) newpro->xmldecl)->parent = (AstXmlParent *) newpro; + } + + if( pro->dtdec ) { + newpro->dtdec = (AstXmlDTDec *) astXmlCopy( pro->dtdec ); + ((AstXmlObject *) newpro->dtdec)->parent = (AstXmlParent *) newpro; + } + + newpro->misc1 = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)pro->nmisc1 ); + newpro->nmisc1 = pro->nmisc1; + for( i = 0; i < pro->nmisc1; i++ ) { + newpro->misc1[ i ] = (AstXmlMiscItem *) astXmlCopy( pro->misc1[ i ] ); + ((AstXmlObject *) newpro->misc1[ i ])->parent = (AstXmlParent *) newpro; + } + + newpro->misc2 = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)pro->nmisc2 ); + newpro->nmisc2 = pro->nmisc2; + for( i = 0; i < pro->nmisc2; i++ ) { + newpro->misc2[ i ] = (AstXmlMiscItem *) astXmlCopy( pro->misc2[ i ] ); + ((AstXmlObject *) newpro->misc2[ i ])->parent = (AstXmlParent *) newpro; + } + + } else if( type == AST__XMLDEC ){ + dec = (AstXmlDeclPI *) this; + new = astMalloc( sizeof( AstXmlDeclPI ) ); + InitXmlDeclPI( (AstXmlDeclPI *) new, AST__XMLDEC, dec->text, status ); + + } else if( type == AST__XMLDTD ){ + dtd = (AstXmlDTDec *) this; + new = astMalloc( sizeof( AstXmlDTDec ) ); + InitXmlDTDec( (AstXmlDTDec *) new, AST__XMLDTD, dtd->name, + dtd->external, dtd->internal, status ); + + } else if( astOK ) { + astError( AST__INTER, "CopyXml: Invalid object type (%d) supplied " + "(internal AST programming error).", status, type ); + } + +/* If an error occurred, delete the new structure. */ + if( !astOK ) new = astXmlDelete( new ); + +/* Return the result. */ + return new; +} + +const char *astXmlFormat_( AstXmlObject *this, int *status ) { +/* +*+ +* Name: +* astXmlFormat + +* Purpose: +* Converts an XmlObject into a character string. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlFormat( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a dynamically allocated string +* containing a textual representation of the supplied XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject to format. + +* Returned Value: +* Pointer to a null terminated string holding the formated XmlObject. +* This string should be freed when no longer needed using astFree. + +* Notes: +* - No newlines or indentation strings are added to the returned string. +* - NULL is returned if NULL pointer is supplied. +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + return Format( this, -1, status ); +} + +const char *astXmlGetAttributeValue_( AstXmlElement *this, const char *name, int *status ){ +/* +*+ +* Name: +* astXmlGetAttributeValue + +* Purpose: +* Return a pointer to a string holding the value of a named attribute. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetAttributeValue( AstXmlElement *this, const char *name ) + +* Description: +* This function returns a pointer to a constant string holding the +* value of a named attribute of a supplied element. If the element +* does not have the named attribute, a NULL pointer is returned but +* no error is reported. + +* Parameters: +* this +* The pointer to the XmlElement. +* name +* Pointer to a string holding the name of the attribute. The name +* may be preceded with a "prefix:" string, in which case the +* prefix will also be matched. If no prefix is included, the first +* attribute with the specified name is returned, regardless of +* its prefix. + +* Returned Value: +* Pointer to a string holding the value of the attribute within the +* supplied element, or NULL if the attribute was not found. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + const char *result; /* Returned pointer */ + AstXmlAttribute *attr; /* Pointer to the attribute */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Find the attribute. */ + attr = FindAttribute( this, name, status ); + +/* Get its value. */ + if( attr ) result = attr->value; + +/* Return the result. */ + return result; +} + +AstXmlContentItem *astXmlGetItem_( AstXmlElement *this, int item, int *status ){ +/* +*+ +* Name: +* astXmlGetItem + +* Purpose: +* Return a specified item of the content of an element. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlContentItem *astXmlGetItem( AstXmlElement *this, int item ) + +* Description: +* This function returns a pointer to an item of the content of the +* specified element. + +* Parameters: +* this +* The pointer to the XmlElement. +* item +* The index of the required item, in the range zero to "nitem-1", +* where "nitem" is the number of items in the element as returned +* by astXmlGetNitem. An error is reported if the specified index +* is out of bounds. + +* Returned Value: +* A pointer to the requested item. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstXmlContentItem *result; /* The returned pointer */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Report an error if the supplie dindex is bad. */ + if( this->nitem == 0 ) { + astError( AST__XMLIT, "astXmlGetItem(xml): The supplied item index (%d) " + "is out of bounds. The supplied XmlObject has no content.", status, + item ); + + } else if( item < 0 || item >= this->nitem ) { + astError( AST__XMLIT, "astXmlGetItem(xml): The supplied item index (%d) " + "is out of bounds. Should be in the range 0 to %d.", status, + item, this->nitem-1 ); + } else { + result = this->items[ item ]; + } + +/* Return the result. */ + return result; +} + +const char *astXmlGetName_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlGetName + +* Purpose: +* Return a pointer to a string holding the name of an XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetName( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a constant string holding the +* name associated with an XmlObject. For elements and attributes, the +* "name" value is returned. For PI elements, the "target" value is +* returned. For namespace definitions, the "prefix" value is returned. +* An error is reported if the supplied XmlObject is of any other class. + +* Parameters: +* this +* The pointer to the XmlObject. + +* Returned Value: +* Pointer to the name string within the XML object. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + const char *result; /* Returned pointer */ + int type; /* Object type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Return the relevant component of the structure, depending on its type. */ + type = this->type; + if( type == AST__XMLELEM ){ + result = ( (AstXmlElement *) this )->name; + + } else if( type == AST__XMLATTR ){ + result = ( (AstXmlAttribute *) this )->name; + + } else if( type == AST__XMLPI ){ + result = ( (AstXmlPI *) this )->target; + + } else if( type == AST__XMLNAME ){ + result = ( (AstXmlNamespace *) this )->prefix; + + } else { + astError( AST__INTER, "astXmlGetName: Inappropriate object type (%d) supplied " + "(internal AST programming error).", status, type ); + } + +/* Return the result. */ + return result; +} + +int astXmlGetNattr_( AstXmlElement *this, int *status ){ +/* +*+ +* Name: +* astXmlGetNattr + +* Purpose: +* Return the number of attributes held by an element. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* int astXmlGetNattr( AstXmlElement *this ) + +* Description: +* This function returns the number of attributes held by an element. + +* Parameters: +* this +* The pointer to the XmlElement. + +* Returned Value: +* The number of attributes held by the supplied element. + +* Notes: +* - Zero is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Check the global error status. */ + if( !astOK ) return 0; + +/* Return the result. */ + return ( this->attrs ) ? this->nattr : 0; +} + +int astXmlGetNitem_( AstXmlElement *this, int *status ){ +/* +*+ +* Name: +* astXmlGetNitem + +* Purpose: +* Return the number of items within the content of an element. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* int astXmlGetNitem( AstXmlElement *this ) + +* Description: +* This function returns the number of items within the content of an +* XmlElement. + +* Parameters: +* this +* The pointer to the XmlElement. + +* Returned Value: +* The number of items in the content of the supplied element. + +* Notes: +* - Zero is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Check the global error status. */ + if( !astOK ) return 0; + +/* Return the result. */ + return this->nitem; +} + +AstXmlParent *astXmlGetParent_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlGetParent + +* Purpose: +* Return a pointer to the object which contains the supplied XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlParent *astXmlGetParent( AstXmlObject *this ) + +* Description: +* This function returns a pointer to the XmlParent object (either an +* XmlElement or an XmlDocument) which contains the specified XmlObject. +* The object can be a content item (an element, a comment, a CDATA +* section, a PI, or character data) in which case the enclosing +* XmlElement is returned, or an attribute or namespace definition in +* which case the XmlElement to which object refers is returned. +* If "this" is the root element of a document, a pointer to the +* XmlDocument is returned. + + +* Parameters: +* this +* The pointer to check. + +* Returned Value: +* Pointer to the parent, or NULL if the object does not have a parent. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Check the global error status. */ + if( !astOK ) return NULL; + +/* Return the result. */ + return this->parent; +} + +AstXmlObject *astXmlGetRoot_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlGetRoot + +* Purpose: +* Return a pointer to the root XmlObject which contains the supplied +* XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlObject *astXmlGetRoot( AstXmlObject *this ) + +* Description: +* This function returns a pointer to the XmlObject which is the root of +* the tree containing the specified XmlObject. A pointer to the +* supplied XmlObject is returned if it has no parent. + +* Parameters: +* this +* The pointer to check. + +* Returned Value: +* Pointer to the root XmlObject, or a copy of the supplied pointer if +* the supplied XmlObject is the root. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstXmlObject *result; + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* If "this" is a document, check it has no parent. If not, return a + pointer ot it. */ + if( astXmlCheckType( this, AST__XMLDOC ) ) { + if( this->parent ) { + astError( AST__INTER, "astXmlGetRoot(xml): An XmlDocument has a " + "non-null parent of type %ld (internal AST programming " + "error).", status, this->type ); + } else { + result = (AstXmlObject *) this; + } + +/* Otherwise... */ + } else if( this->parent ) { + result = astXmlGetRoot( this->parent ); + + } else { + result = this; + } + +/* Return the result. */ + return result; +} + +const char *astXmlGetTag_( AstXmlObject *this, int opening, int *status ){ +/* +*+ +* Name: +* astXmlGetTag + +* Purpose: +* Returns a string holding an XML tag describing the given XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetTag( AstXmlObject *this, int opening ) + +* Description: +* This function returns a pointer to a static string containing an +* XML tag describing the given XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject. +* opening +* Indicates which tag is to be returned; the start tag or the end +* tag. If non-zero the start tag is returned. Otherwise, the +* end tag is returned. If the supplied XmlObject has no end +* tag (i.e. if it is an empty element, or if it is not an element), +* then NULL is returned but no error is reported. + +* Returned Value: +* Pointer to a null terminated string holding the tag. If the tag +* exceeds 200 characters, only the first 197 characters are returned +* and "..." is appended to the end. + +* Notes: +* - Subsequent invocations of this function will over-write the +* buffer which used to hold the returned string. +* - Empty elements are represented as an start tag of the form <.../>, +* with no corresponding end tag. +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + char *result; /* The returned pointer */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* If needed, get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Get a dynamic string holding the formatted tag. */ + result = FormatTag( this, opening, status ); + +/* If OK, copy the result into the static buffer. */ + gettag_buff[ 0 ] = 0; + if( result ) { + if( astOK ) { + + if( strlen( result ) > AST__XML_GETTAG_BUFF_LEN ) { + strncpy( gettag_buff, result, AST__XML_GETTAG_BUFF_LEN -3 ); + strcpy( gettag_buff + AST__XML_GETTAG_BUFF_LEN - 3, "..." ); + } else { + strncpy( gettag_buff, result, AST__XML_GETTAG_BUFF_LEN ); + } + + gettag_buff[ AST__XML_GETTAG_BUFF_LEN ] = 0; + astFree( result ); + result = gettag_buff; + } else { + result = astFree( result ); + } + } + +/* Return the result. */ + return result; +} + +const char *astXmlGetType_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlGetType + +* Purpose: +* Returns a string holding the type of the given XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetType( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a static string containing the +* type of the given XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject. + +* Returned Value: +* Pointer to a null terminated string holding the type string. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + const char *result; /* The returned pointer */ + int type; /* Element type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + + type = this->type; + if( type == AST__XMLELEM ) { + result = "element"; + + } else if( type == AST__XMLATTR ) { + result = "attribute"; + + } else if( type == AST__XMLCDATA ) { + result = "CDATA section"; + + } else if( type == AST__XMLCOM ) { + result = "comment"; + + } else if( type == AST__XMLPI ) { + result = "processing instruction"; + + } else if( type == AST__XMLNAME ) { + result = "namespace"; + + } else if( type == AST__XMLDOC ) { + result = "document"; + + } else if( type == AST__XMLPRO ) { + result = "prologue"; + + } else if( type == AST__XMLDEC ) { + result = "XML delaration PI"; + + } else if( type == AST__XMLDTD ) { + result = "DTD"; + + } else if( type == AST__XMLWHITE ) { + result = "white-space character data "; + + } else if( type == AST__XMLBLACK ) { + result = "non-blank character data"; + + } else { + result = "unknown XML object"; + } + +/* Return the result. */ + return result; +} + +const char *astXmlGetURI_( AstXmlObject *this, int *status ){ +/* +*+ +* Name: +* astXmlGetURI + +* Purpose: +* Return a pointer to a string holding the namespace URI of an XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetURI( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a constant string holding the +* namespace URI associated with an XmlObject. Only attributes, +* elements and namespaces have associated URIs, so a NULL pointer is +* returned for any other class of XmlObject. A NULL pointer is also +* returned if XmlObject does not belong to any namespace, or if it +* belongs to a unknown namespace (i.e. one for which no URI is +* available). Any namespace prefix attached to the supplied object is +* resolved first using any "xmlns" attributes contained in the same +* element, then using any "xmlns" attributes contained in the parent +* element, etc. + +* Parameters: +* this +* The pointer to the XmlObject. + +* Returned Value: +* Pointer to a string holding the namespace URI, or NULL. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + const char *prefix; /* Namespace prefix */ + const char *result; /* Returned pointer */ + int type; /* Object type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Do each type of object separately. */ + type = this->type; + if( type == AST__XMLATTR ){ + prefix = ( (AstXmlAttribute *) this )->prefix; + +/* Attributes have no default name space. Therefore if there is no prefix, + return NULL. If there is a prefix, resolve it within the context of + the attributes parent element. */ + if( prefix ) { + result = ResolvePrefix( prefix, (AstXmlElement *) this->parent, status ); + } + + } else if( type == AST__XMLELEM ){ + prefix = ( (AstXmlElement *) this )->prefix; + +/* If there is a prefix, resolve it within the context of this element. */ + if( prefix ) { + result = ResolvePrefix( prefix, (AstXmlElement *) this, status ); + +/* Elements do have a default name space. Therefore if there is no prefix, + return the default name space within the context of this element. */ + } else { + result = DefaultURI( (AstXmlElement *) this, status ); + } + +/* If the supplied object is a namespace, just return the associated URI. */ + } else if( type == AST__XMLNAME ){ + result = ( (AstXmlNamespace *) this )->uri; + + } + +/* Return the result. */ + return result; +} + +const char *astXmlGetValue_( AstXmlObject *this, int report, int *status ){ +/* +*+ +* Name: +* astXmlGetValue + +* Purpose: +* Return a pointer to a string holding the value of an XmlObject. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlGetValue( AstXmlObject *this, int report ) + +* Description: +* This function returns a pointer to a constant string holding the +* value associated with an XmlObject. For attributes, the attribute value +* is returned. For PI elements, the "text" value is returned. For +* namespace definitions, the "URI" value is returned. For character +* data, the character data is returned. For CDATA sections the "text" +* value is returned. For comments, the "text" value is returned. +* If the XmlObject is an element, then a non-NULL value is returned +* only if the element contains a single content item holding character +* data. In this case a pointer to the character data is returned. +* A null value is returned in all other cases (but no error is +* reported unless "report" is non-zero). + +* Parameters: +* this +* The pointer to the XmlObject. +* report +* Report an error if the supplied XmlObject does not have a value? + +* Returned Value: +* Pointer to a string holding the value of the XML object. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstXmlContentItem *item;/* Element content */ + const char *result; /* Returned pointer */ + int type; /* Object type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Return the relevant component of the structure, depending on its type. */ + type = this->type; + if( type == AST__XMLATTR ){ + result = ( (AstXmlAttribute *) this )->value; + + } else if( type == AST__XMLBLACK ){ + result = ( (AstXmlBlack *) this )->text; + + } else if( type == AST__XMLWHITE ){ + result = ( (AstXmlWhite *) this )->text; + + } else if( type == AST__XMLCDATA ){ + result = ( (AstXmlCDataSection *) this )->text; + + } else if( type == AST__XMLCOM ){ + result = ( (AstXmlComment *) this )->text; + + } else if( type == AST__XMLPI ){ + result = ( (AstXmlPI *) this )->text; + + } else if( type == AST__XMLNAME ){ + result = ( (AstXmlNamespace *) this )->uri; + + } else if( type == AST__XMLELEM ){ + if( astXmlGetNitem( (AstXmlElement *) this ) == 1 ) { + item = astXmlGetItem( (AstXmlElement *) this, 0 ); + if( astXmlCheckType( item, AST__XMLCHAR ) ) { + result = astXmlGetValue( item, report ); + } + } + + if( !result && astOK && report ) { + astError( AST__BADIN, "astRead(xml): Cannot get the value of " + "element \"<%s>\": its contents are not pure character " + "data.", status, astXmlGetName( this ) ); + } + + } else if( report ) { + astError( AST__INTER, "astXmlGetValue(xml): Cannot get the value of " + "an XmlObject of type %d (internal AST programming " + "error).", status, type ); + } + +/* Return the result. */ + return result; +} + +void astXmlInsertElement_( AstXmlElement *this, AstXmlElement *elem, int *status ){ +/* +*+ +* Name: +* astXmlInsertElement + +* Purpose: +* Inserts an existing XmlElement into another XmlElement. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlInsertElement( AstXmlElement *this, AstXmlElement *elem ) + +* Description: +* This function inserts a given XmlElement "elem" into another given +* XmlElement "this". An error is reported if "elem" already has a +* parent. + +* Parameters: +* this +* A pointer to the element to be modified. +* elem +* The element to be inserted into "this". + +*- +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Report AN error if "elem" has already been inserted into + another element. */ + if( ((AstXmlObject *) elem)->parent ) { + astError( AST__INTER, "astXmlInsertElement(xml): Cannot insert \"%s\" " + "into \"%s\" because it already has a parent (\"%s\") " + "(internal AST programming error).", status, + astXmlGetTag( elem, 1 ), astXmlGetTag( this, 1 ), + astXmlGetTag( ((AstXmlObject *) elem)->parent, 1 ) ); + +/* Otherwise, add the content item to the element. */ + } else { + AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) elem, status ); + } +} + +void astXmlPurge_( AstXmlParent *this, int *status ) { +/* +*+ +* Name: +* astXmlPurge + +* Purpose: +* Remove blank content from a parent object. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlPurge( AstXmlParent *this ) + +* Description: +* This function removes all character data containing only whitespace +* from the supplied document or element. It is recursive, in that it also +* removes white space from all children elements. + +* Parameters: +* this +* Pointer to the document or element. + +*- +*/ + +/* Local Variables: */ + int i; /* Content item index */ + AstXmlContentItem *item; /* Next content item */ + AstXmlMiscItem *misc; /* Nest miscalleneous item */ + AstXmlDocument *doc; /* This document */ + AstXmlPrologue *pro; /* This document prologue */ + AstXmlElement *elem; /* This element */ + +/* Check the global error status. */ + if( !astOK || !this ) return; + +/* If this is a a document.. */ + if( astXmlCheckType( this, AST__XMLDOC ) ) { + doc = (AstXmlDocument *) this; + astXmlPurge( doc->prolog ); + astXmlPurge( doc->root ); + + i = -1; + while( ++i < doc->nepi ) { + misc = doc->epilog[ i ]; + if( astXmlCheckType( misc, AST__XMLWHITE ) ) { + misc = astXmlDelete( misc ); + i--; + } + } + +/* If this is a prologue.. */ + } else if( astXmlCheckType( this, AST__XMLPRO ) ) { + pro = (AstXmlPrologue *) this; + + i = -1; + while( ++i < pro->nmisc1 ) { + misc = pro->misc1[ i ]; + if( astXmlCheckType( misc, AST__XMLWHITE ) ) { + misc = astXmlDelete( misc ); + i--; + } + } + + i = -1; + while( ++i < pro->nmisc2 ) { + misc = pro->misc2[ i ]; + if( astXmlCheckType( misc, AST__XMLWHITE ) ) { + misc = astXmlDelete( misc ); + i--; + } + } + + +/* If this is an element */ + } else if( astXmlCheckType( this, AST__XMLELEM ) ) { + elem = (AstXmlElement *) this; + + i = -1; + while( ++i < elem->nitem ) { + item = elem->items[ i ]; + + if( astXmlCheckType( item, AST__XMLWHITE ) ) { + item = astXmlDelete( item ); + i--; + + } else if( astXmlCheckType( item, AST__XMLELEM ) ) { + astXmlPurge( (AstXmlParent *) item ); + } + } + } +} + +void astXmlRemoveAttr_( AstXmlElement *this, const char *name, + const char *prefix, int *status ){ +/* +*+ +* Name: +* astXmlRemoveAttr + +* Purpose: +* Removes an attribute from its parent element. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlRemoveAttr( AstXmlElement *this, const char *name, +* const char *prefix ) + +* Description: +* This function removes a named attribute from its parent element. + +* Parameters: +* this +* The pointer to the element containing the attribute to be removed. +* name +* Pointer to a null terminated string containing the attribute name. +* prefix +* The namespace prefix for the attribute. May be NULL or blank, in +* which case any prefix at the start of "name" is used. +*- +*/ + +/* Local Variables: */ + AstXmlAttribute *attr; /* Pointer to temporary attribute structure */ + AstXmlAttribute *oldattr; /* Pointer to existing attribute */ + int i; /* Attribute index */ + int nattr; /* Number of attributes in parent */ + int oldi; /* Indexof existing attribute */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Initialise */ + oldattr = NULL; + +/* Create a new XmlAttribute with blank value. */ + attr = NewAttribute( name, "", prefix, status ); + if( astOK ) { + +/* Get the number of attributes currently stored in the element. */ + nattr = ( this->attrs ) ? this->nattr : 0; + +/* Search the existing attributes to see if an attribute with the given + name and prefix already exists. */ + oldi = -1; + for( i = 0; i < nattr; i++ ) { + oldattr = this->attrs[ i ]; + if( !strcmp( oldattr->name, attr->name ) ) { + if( !oldattr->prefix && !attr->prefix ) { + oldi = i; + break; + } else if( oldattr->prefix && attr->prefix && + !strcmp( oldattr->prefix, attr->prefix ) ){ + oldi = i; + break; + } + } + } + +/* If there is an existing attribute with the same name and prefix, + delete it. */ + if( oldi > -1 ) astXmlDelete( oldattr ); + +/* Delete the temporary attribute structure. */ + attr = astXmlDelete( attr ); + + } +} + +void astXmlRemoveItem_( AstXmlContentItem *this, int *status ){ +/* +*+ +* Name: +* astXmlRemoveItem + +* Purpose: +* Removes an item of content from its parent element or document. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlRemoveItem( AstXmlContentItem *this ) + +* Description: +* This function removes an item of content from its parent element, +* or removes the root element from a document. The removed item is not +* annulled and may be subsequently added into another element. + +* Parameters: +* this +* The pointer to the item to be removed form its parent. +*- +*/ + +/* Local Variables: */ + AstXmlDocument *doc; /* Pointer to parent document */ + AstXmlElement *elem; /* Pointer to parent element */ + AstXmlParent *parent; /* Pointer to parent */ + int found; /* Was the item found within its parent? */ + int i; /* Item index */ + int j; /* Item index */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Get a pointer to the items parent element, and check it is not null. */ + parent = ( (AstXmlObject *) this )->parent; + if( parent && astXmlCheckType( parent, AST__XMLELEM ) ) { + elem = (AstXmlElement *) parent; + +/* Search through all the items within the parent element looking for the + supplied item. */ + found = 0; + for( i = 0; i < elem->nitem; i++ ) { + if( elem->items[ i ] == this ) { + +/* When found, decrement the number of items in the element, and shuffle + all the remaining item pointers down one slot to over-write it, then + nullify the parent pointer in the supplied object and leave the loop. */ + (elem->nitem)--; + for( j = i; j < elem->nitem; j++ ) { + elem->items[ j ] = elem->items[ j + 1 ]; + } + ( (AstXmlObject *) this )->parent = NULL; + found = 1; + break; + } + } + +/* Report an error if the item was not found. */ + if( !found ) { + astError( AST__INTER, "astXmlRemoveItem: The parent of the supplied " + "item does not contain the item (internal AST programming " + "error)." , status); + } + +/* If the parent is an XmlDocument, check the item being removed is the + root element. */ + } else if( parent && astXmlCheckType( parent, AST__XMLDOC ) ) { + doc = (AstXmlDocument *) parent; + if( (AstXmlElement *) this == doc->root ) { + ( (AstXmlObject *) this )->parent = NULL; + doc->root = NULL; + } + } +} + +void astXmlRemoveURI_( AstXmlElement *this, const char *prefix, int *status ){ +/* +*+ +* Name: +* astXmlRemoveURI + +* Purpose: +* Removes an namespace prefix from its parent element. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlRemoveURI( AstXmlElement *this, const char *prefix ) + +* Description: +* This function removes a named namespace prefix from its parent element. + +* Parameters: +* this +* The pointer to the element containing the namespace prefix to be +* removed. +* prefix +* The namespace prefix to remove. +*- +*/ + +/* Local Variables: */ + AstXmlNamespace *ns; /* Temporary namespace structure */ + AstXmlNamespace *oldns; /* Pointer to existing namespace */ + int oldi; /* Index of namespace within its parent */ + int i; /* Namespace index */ + int nns; /* Number of existing namespaces */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Initialise */ + oldns = NULL; + +/* Create a new XmlNamespace with blank URI. */ + ns = NewNamespace( prefix, "", status ); + if( astOK ) { + +/* Get the number of namespace prefixes currently stored in the element. */ + nns = ( this->nsprefs ) ? this->nnspref : 0; + +/* Search the list of existing namespace prefixes to see if the given prefix + is included. */ + oldi = -1; + for( i = 0; i < nns; i++ ) { + oldns = this->nsprefs[ i ]; + if( !strcmp( oldns->prefix, ns->prefix ) ){ + oldi = i; + break; + } + } + +/* If the supplied namespace prefix was found in the list, delete it. */ + if( oldi > -1 ) astXmlDelete( oldns ); + +/* Delete the temporary namespace structure. */ + ns = astXmlDelete( ns ); + + } +} + +void astXmlSetDTDec_( AstXmlDocument *this, const char *text1, + const char *text2, const char *text3, int *status ){ +/* +*+ +* Name: +* astXmlSetDTDec + +* Purpose: +* Set the Document Type declaration for a document. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlSetDTDEC( AstXmlDocument *this, const char *text1, +* const char *text2, const char *text3 ) + +* Description: +* This function stores an Document Type declaration of the form +* +* <!DOCTYPE text1 text2 [text3]> +* +* in the supplied document. Any previous DTD is removed. + +* Parameters: +* this +* The pointer to the document. +* text1 +* The document type name. +* text2 +* The text defining the external elements of the document type +* (may be NULL). +* text3 +* The text defining the internal elements of the document type +* (may be NULL). Do not include delimiting "[" and "]" characters. +*- +*/ + +/* Local Variables: */ + AstXmlDTDec *new; /* Pointer to new DT declaration */ + AstXmlPrologue *pro; /* Pointer to prologue */ + char *my_text2; /* Cleaned text2 */ + char *my_text3; /* Cleaned text3 */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Allocate space for the new structure. */ + new = (AstXmlDTDec *) astMalloc( sizeof( AstXmlDTDec ) ); + +/* Clean the text. */ + my_text2 = CleanText( text2, status ); + my_text3 = CleanText( text3, status ); + +/* Initialise it. */ + InitXmlDTDec( new, AST__XMLDTD, text1, my_text2, my_text3, status ); + +/* Free the memory */ + my_text2 = astFree( my_text2 ); + my_text3 = astFree( my_text3 ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, store it in the document, deleting any existing declaration + first. */ + } else { + +/* Create a prologue if necessary. */ + if( !this->prolog ) this->prolog = NewPrologue( this, status ); + + pro = this->prolog; + if( pro->dtdec ) astXmlDelete( pro->dtdec ); + pro->dtdec = new; + } +} + +void astXmlSetXmlDec_( AstXmlDocument *this, const char *text, int *status ){ +/* +*+ +* Name: +* astXmlSetXmlDec + +* Purpose: +* Set the XML declaration for a document. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void astXmlSetXmlDec( AstXmlDocument *this, const char *text ) + +* Description: +* This function stores an XML declaration of the form +* +* <?xml [text]?> +* +* in the supplied document. Any previous XML declaration is removed. + +* Parameters: +* this +* The pointer to the document. +* text +* The text to include in the XML declaration tag. +*- +*/ + +/* Local Variables: */ + AstXmlDeclPI *new; /* Pointer to new XML delcaration */ + AstXmlPrologue *pro; /* Pointer to prologue */ + char *my_text; /* Cleaned text */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Allocate space for the new structure. */ + new = (AstXmlDeclPI *) astMalloc( sizeof( AstXmlDeclPI ) ); + +/* Clean the text. */ + my_text = CleanText( text, status ); + +/* Initialise it. */ + InitXmlDeclPI( new, AST__XMLDEC, my_text, status ); + +/* Free the memory */ + my_text = astFree( my_text ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) { + new = astXmlDelete( new ); + +/* Otherwise, store it in the document, deleting any existing declaration + first. */ + } else { + +/* Create a prologue if necessary. */ + if( !this->prolog ) this->prolog = NewPrologue( this, status ); + + pro = this->prolog; + if( pro->xmldecl ) astXmlDelete( pro->xmldecl ); + pro->xmldecl = new; + } +} + +const char *astXmlShow_( AstXmlObject *this, int *status ) { +/* +*+ +* Name: +* astXmlShow + +* Purpose: +* Converts an XmlObject into a character string with indentation. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* const char *astXmlShow( AstXmlObject *this ) + +* Description: +* This function returns a pointer to a dynamically allocated string +* containing a textual representation of the supplied XmlObject. +* Newline characters are added to the string if needed to ensure that +* each item of content within an element starts on a new line, and all +* tags are preceded by an indentation string consisting of a number +* of spaces. + +* Parameters: +* this +* Pointer to the XmlObject to format. + +* Returned Value: +* Pointer to a null terminated string holding the formated XmlObject. +* This string should be freed when no longer needed using astFree. + +* Notes: +* - NULL is returned if a NULL pointer is supplied. +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + return Format( this, 0, status ); +} + +static void CheckName( const char *name, const char *noun, const char *method, + int nullok, int *status ){ +/* +* Name: +* CheckName + +* Purpose: +* Checks the supplied string is a valid XML name. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void CheckName( const char *name, const char *noun, const char *method, +* int nullok, int *status ) + +* Description: +* This function checks that the supplied string is a valid XML name, +* and reports an error otherwise. + +* Parameters: +* name +* The name string to check +* noun +* A word to describe the object which the name applies to - for use in +* error messages only. +* method +* The name of the calling method - for use in error messages only. +* nullok +* If non-zero, then a null or empty name is assumed to be +* acceptable. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + const char *c; /* Pointer to next character to check */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the string is not null. */ + if( !name ) { + if( !nullok ) astError( AST__XMLNM, "%s: A NULL pointer was supplied " + "instead of an XML %s name.", status, method, noun ); + } else { + + c = name; + if( *c == 0 ) { + if( !nullok ) astError( AST__XMLNM, "%s: An empty string was supplied " + "instead of an XML %s name.", status, method, noun ); + } else { + + if( !isalpha( *c ) && *c != '_' ) { + astError( AST__XMLNM, "%s: The illegal XML %s name \"%s\" was " + "encountered.", status, method, noun, name ); + + } else { + while( *(++c) ) { + if( !isalnum( *c ) && *c != '_' && *c != '-' && *c != '.' ){ + astError( AST__XMLNM, "%s: The illegal XML %s name \"%s\" was " + "encountered.", status, method, noun, name ); + break; + } + } + } + } + } +} + +static void CheckPrefName( char *name, const char *noun, const char *method, int *status ){ +/* +* Name: +* CheckPrefName + +* Purpose: +* Checks the supplied string is a valid XML (prefix:)name. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void CheckPrefName( char *name, const char *noun, const char *method, int *status ) + +* Description: +* This function checks that the supplied string is a valid XML +* (prefix:)name combination and reports an error otherwise. + +* Parameters: +* name +* The string to check +* noun +* A word to describe the object which the name applies to - for use in +* error messages only. +* method +* The name of the calling method - for use in error messages only. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + char *colon; /* Pointer to first colon */ + char *temp; /* Pointer to temporary string */ + int nc; /* Length of temporary string */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Search for a ":" character. */ + colon = strchr( name, ':' ); + +/* If found, temporarily convert the colon into a null so that it + terminates the prefix string. */ + if( colon ) { + *colon = 0; + +/* Check the string before the colon is a valid name. */ + temp = NULL; + temp = astAppendString( temp, &nc, noun ); + temp = astAppendString( temp, &nc, " prefix" ); + CheckName( name, temp, method, 0, status ); + temp = astFree( temp ); + +/* Restore the colon. */ + *colon = ':'; + +/* Check the string following the colon is a valid name. */ + CheckName( colon + 1, noun, method, 0, status ); + +/* If not found, the whole supplied string must be a name. */ + } else { + CheckName( name, noun, method, 0, status ); + } +} + +static int CheckType( long int given, long int want, int *status ){ +/* +* Name: +* CheckType + +* Purpose: +* Check that the supplied type identifies an object of a given class. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* int CheckType( long int given, long int want, int *status ) + +* Description: +* This function checks that the supplied type identifier identifies +* a specified class of XML object, or a derived class. A flag is +* returned indicating if the check succeeds. No error is reported if +* the check fails. + +* Parameters: +* given +* The type value to be checked. +* want +* The type of the required class. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if the check is passed, zero if not of if an error has +* already occurred. + +* Notes: +* - This function attempts to execute even if the error status is set. +*/ + +/* Local Variables: */ + int result; /* Returned value */ + +/* Initialise */ + result = 0; + +/* Check the wanted type is recognised. Report an error if not. */ + if( want != AST__XMLOBJECT && + want != AST__XMLELEM && + want != AST__XMLATTR && + want != AST__XMLCHAR && + want != AST__XMLCDATA && + want != AST__XMLCOM && + want != AST__XMLPI && + want != AST__XMLNAME && + want != AST__XMLCONT && + want != AST__XMLPRO && + want != AST__XMLDEC && + want != AST__XMLDTD && + want != AST__XMLMISC && + want != AST__XMLBLACK && + want != AST__XMLWHITE && + want != AST__XMLPAR && + want != AST__XMLDOC ) { + if( astOK ) { + astError( AST__INTER, "CheckType(Xml): Unsupported XML object " + "type (%ld) supplied for parameter \"want\" (internal " + "AST programming error). ", status, want ); + } + +/* You should never be given a generic "interface" type since the + "wanted" value comes from the "type" component of an XmlObject (an explicit + class type should always be given). */ + } else if( given == AST__XMLPAR || + given == AST__XMLMISC || + given == AST__XMLCONT || + given == AST__XMLCHAR ) { + if( astOK ) { + astError( AST__INTER, "CheckType(Xml): Generic type (%ld) supplied for " + "parameter \"given\" (internal AST programming error).", status, + given ); + } + +/* If the above is OK, return a non-zero value if the type to be tested + equals the wanted type. */ + } else if( want == given ) { + result = 1; + +/* If any class of XmlObject is acceptable, check that he given class + type is a valid XML class type. */ + } else if( want == AST__XMLOBJECT ) { + result = ( given == AST__XMLELEM || + given == AST__XMLATTR || + given == AST__XMLCDATA || + given == AST__XMLCOM || + given == AST__XMLPI || + given == AST__XMLNAME || + given == AST__XMLPRO || + given == AST__XMLDEC || + given == AST__XMLDTD || + given == AST__XMLWHITE || + given == AST__XMLBLACK || + given == AST__XMLDOC ); + +/* Otherwise, for "interface" types, check if the given class "implements + the interface". */ + } else if( want == AST__XMLCONT ) { + result = ( given == AST__XMLELEM || + given == AST__XMLBLACK || + given == AST__XMLWHITE || + given == AST__XMLCDATA || + given == AST__XMLCOM || + given == AST__XMLPI ); + + } else if( want == AST__XMLMISC ) { + result = ( given == AST__XMLWHITE || + given == AST__XMLCOM || + given == AST__XMLPI ); + + } else if( want == AST__XMLCHAR ) { + result = ( given == AST__XMLWHITE || + given == AST__XMLBLACK ); + + } else if( want == AST__XMLPAR ) { + result = ( given == AST__XMLDOC || + given == AST__XMLPRO || + given == AST__XMLELEM ); + } + +/* Return the result. */ + return result; +} + +int astXmlCheckType_( void *this, long int want, int *status ){ +/* +*+ +* Name: +* astXmlCheckType + +* Purpose: +* Check that the supplied object is of a given class. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* int astXmlCheckType( void *this, long int want ) + +* Description: +* This function checks that the supplied XmlObject is of a specified +* class of XML object, or a derived class. A flag is returned indicating +* if the check succeeds. No error is reported if the check fails. + +* Parameters: +* this +* The object to check. +* want +* The type of the required class. + +* Returned Value: +* Non-zero if the check is passed, zero if not of if an error has +* already occurred. + +* Notes: +* - This function attempts to execute even if the error status is set. +*- +*/ + + if( this ) { + return CheckType( ((AstXmlObject *) this)->type, want, status ); + } else { + return 0; + } +} + +static char *CleanText( const char *text, int *status ){ +/* +* Name: +* CleanText + +* Purpose: +* Normalise end-of-lines in the supplied text. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* char *CleanText( const char *text, int *status ) + +* Description: +* This function returns a copy of "text in which "\r\n" has been +* replaced by "\n" and any remaining "\r" characters have been +* replaced by "\n". + +* Parameters: +* text +* A pointer to a text string. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated string containing the required +* copy. + +* Notes: +* - NULL is returned if this function is called with the global error +* status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + char *d; /* Pointer to next returned character */ + char *result; /* Returned pointer */ + char *c; /* Pointer to next supplied character */ + char lc; /* Previous character */ + +/* Initialise */ + result = NULL; + +/* Return if the pointer is NULL or if an error has occurred. */ + if( !astOK || !text ) return result; + +/* Take a copy of the supplied text */ + result = astStore( NULL, text, strlen( text ) + 1 ); + +/* Clean the text by replacing "\r\n" by "\n". */ + c = result - 1; + d = c; + lc = 0; + while( *(++c) ) { + if( *c != '\n' || lc != '\r' ) d++; + *d = ( lc = *c ); + } + *(++d) = 0; + +/* Now further clean it by replacing "\r" by "\n". */ + c = result - 1; + while( *(++c) ) { + if( *c == '\r' ) *c = '\n'; + } + +/* Return the result. */ + return result; +} + +static void CleanXml( AstXmlObject *this, long int type, int *status ){ +/* +* Name: +* CleanXml + +* Purpose: +* Free the resources used within an XmlObject. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void CleanXml( AstXmlObject *this, long int type, int *status ) + +* Description: +* This function frees the resources used internally within the +* supplied XmlObject. + +* Parameters: +* this +* pointer to the XmlObject to be cleaned. +* type +* The type of XmlObject being cleaned. +* status +* Pointer to the inherited status variable. + +* Notes: +* This function attempts to execute even if an error has already +* occurred. +*- +*/ + +/* Local Variables: */ + AstXmlAttribute *attr; + AstXmlBlack *black; + AstXmlCDataSection *cdatasec; + AstXmlComment *comm; + AstXmlDTDec *dtd; + AstXmlDeclPI *dec; + AstXmlDocument *doc; + AstXmlElement *elem; + AstXmlNamespace *ns; + AstXmlPI *pi; + AstXmlPrologue *pro; + AstXmlWhite *white; + +/* Return if a NULL pointer has been suppplied. */ + if( !this ) return; + +/* For the base XmlObject class, clear the object type, etc. */ + if( type == AST__XMLOBJECT ){ + this->type = AST__XMLBAD; + this->parent = NULL; + +/* For each derived class of XmlObject, first clean the parent component, + then clean any further resources. */ + } else if( type == AST__XMLELEM ){ + + elem = (AstXmlElement *) this; + + elem->name = astFree( elem->name ); + elem->defns = astFree( elem->defns ); + elem->prefix = astFree( elem->prefix ); + + while( elem->nattr > 0 ) astXmlDelete( elem->attrs[ 0 ] ); + elem->attrs = astFree( elem->attrs ); + + while( elem->nitem > 0 ) astXmlDelete( elem->items[ 0 ] ); + elem->items = astFree( elem->items ); + + while( elem->nnspref > 0 ) astXmlDelete( elem->nsprefs[ 0 ] ); + elem->nsprefs = astFree( elem->nsprefs ); + + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLATTR ){ + attr = (AstXmlAttribute *) this; + attr->name = astFree( attr->name ); + attr->value = astFree( attr->value ); + attr->prefix = astFree( attr->prefix ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLBLACK ){ + black = (AstXmlBlack *) this; + black->text = astFree( black->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLWHITE ){ + white = (AstXmlWhite *) this; + white->text = astFree( white->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLCDATA ){ + cdatasec = (AstXmlCDataSection *) this; + cdatasec->text = astFree( cdatasec->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLCOM ){ + comm = (AstXmlComment *) this; + comm->text = astFree( comm->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLPI ){ + pi = (AstXmlPI *) this; + pi->target = astFree( pi->target ); + pi->text = astFree( pi->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLNAME ){ + ns = (AstXmlNamespace *) this; + ns->prefix = astFree( ns->prefix ); + ns->uri = astFree( ns->uri ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLDOC ){ + doc = (AstXmlDocument *) this; + doc->prolog = astXmlDelete( doc->prolog ); + doc->root = astXmlDelete( doc->root ); + while( doc->nepi > 0 ) astXmlDelete( doc->epilog[ 0 ] ); + doc->epilog = astFree( doc->epilog ); + doc->current = NULL; + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLPRO ){ + pro = (AstXmlPrologue *) this; + pro->xmldecl = astXmlDelete( pro->xmldecl ); + while( pro->nmisc1 > 0 ) astXmlDelete( pro->misc1[ 0 ] ); + pro->misc1 = astFree( pro->misc1 ); + pro->dtdec = astXmlDelete( pro->dtdec ); + while( pro->nmisc2 > 0 ) astXmlDelete( pro->misc2[ 0 ] ); + pro->misc2 = astFree( pro->misc2 ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLDEC ){ + dec = (AstXmlDeclPI *) this; + dec->text = astFree( dec->text ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( type == AST__XMLDTD ){ + dtd = (AstXmlDTDec *) this; + dtd->name = astFree( dtd->name ); + dtd->external = astFree( dtd->external ); + dtd->internal = astFree( dtd->internal ); + CleanXml( this, AST__XMLOBJECT, status ); + + } else if( astOK ) { + astError( AST__INTER, "CleanXml: Invalid object type (%ld) supplied " + "(internal AST programming error).", status, type ); + } + +} + +static const char *DefaultURI( AstXmlElement *elem, int *status ){ +/* +* Name: +* DefaultURI + +* Purpose: +* Find the URI associated with the default namespace. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* const char *DefaultURI( AstXmlElement *elem, int *status ) + +* Description: +* This function returns the default namespace URI defined within the +* given element. If the element does not define a default namespace URI, +* then this function is called recursively on the parent element. If +* there is no parent element, NULL is returned. + +* Parameters: +* elem +* The pointer to the XmlElement. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a string holding the URI, or NULL if not found. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlParent *parent; /* Parent of "this" */ + const char *result; /* Returned pointer */ + +/* Initialise */ + result = NULL; + +/* Check the global error status, and the supplied element. */ + if( !astOK || !elem ) return result; + +/* If the supplied element defines a default namespace URI, return it. + Otherwise, call this function to get the default namespace URI from the + parent element. */ + result = elem->defns; + if( !result ) { + parent = ( (AstXmlObject *) elem )->parent; + if( astXmlCheckType( parent, AST__XMLELEM ) ) { + result = DefaultURI( (AstXmlElement *) parent, status ); + } + } + +/* If the element has a blank default namespace URI, then return NULL + since the XML namespaces specification says that "The default + namespace can be set to the empty string. This has the same effect, + within the scope of the declaration, of there being no default + namespace". */ + if( result && astChrLen( result ) == 0 ) result = NULL; + +/* Return the result. */ + return result; +} + +void *astXmlDelete_( void *obj_ptr, int *status ){ +/* +*+ +* Name: +* astXmlDelete + +* Purpose: +* Remove the supplied XmlObject from its parent and delete it. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* void *astXmlDelete( void *obj ) + +* Description: +* This function removes the supplied XmlObject from its parent and +* deletes it using astXmlAnnul. + +* Parameters: +* obj +* The pointer to the XmlObject to be deleted. + +* Returned Value: +* NULL + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*- +*/ + +/* Local Variables: */ + AstXmlDocument *doc; /* Pointer to XM document */ + AstXmlElement *elem; /* Pointer to XML element */ + AstXmlObject *obj; /* Pointer to XmlObject */ + AstXmlParent *parent; /* Pointer to parent */ + AstXmlPrologue *pro; /* Pointer to XML prologue */ + int i; /* Loop counter */ + int j; /* Loop counter */ + int n; /* Number of values in list */ + int ok; /* Is obj a child of its parent? */ + void *result; /* Returned pointer */ + +/* Initialise */ + result = NULL; + ok = 0; + +/* Check we have an XmlObject. */ + if( !astXmlCheckType( obj_ptr, AST__XMLOBJECT ) ) return result; + +/* Get the parent of the supplied object. */ + obj = (AstXmlObject *) obj_ptr; + parent = obj->parent; + if( parent ) { + +/* First deal with cases where we are deleting items from a document. */ + if( astXmlCheckType( parent, AST__XMLDOC ) ) { + doc = (AstXmlDocument *) parent; + + if( astXmlCheckType( obj, AST__XMLPRO ) ) { + if( (AstXmlPrologue *) obj == doc->prolog ) { + doc->prolog = NULL; + ok = 1; + } + + } else if( astXmlCheckType( obj, AST__XMLELEM ) ) { + if( (AstXmlElement *) obj == doc->root ) { + doc->root = NULL; + ok = 1; + } + + } else if( astXmlCheckType( obj, AST__XMLMISC ) ) { + n = doc->nepi; + for( i = 0; i < n; i++ ) { + if( doc->epilog[ i ] == (AstXmlMiscItem *) obj ) { + for( j = i + 1; j < n; j++ ) { + doc->epilog[ j - 1 ] = doc->epilog[ j ]; + } + doc->epilog[ --doc->nepi ] = NULL; + ok = 1; + break; + } + } + + } else if( astOK ) { + astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has " + "inappropriate parent of type %ld (internal AST " + "programming error).", status, obj->type, parent->type ); + } + +/* Now deal with cases where we are deleting items from a prologue. */ + } else if( astXmlCheckType( parent, AST__XMLPRO ) ) { + pro = (AstXmlPrologue *) parent; + + if( astXmlCheckType( obj, AST__XMLDEC ) ) { + if( (AstXmlDeclPI *) obj == pro->xmldecl ) { + pro->xmldecl = NULL; + ok = 1; + } + + } else if( astXmlCheckType( obj, AST__XMLDTD ) ) { + if( (AstXmlDTDec *) obj == pro->dtdec ) { + pro->dtdec = NULL; + ok = 1; + } + + } else if( astXmlCheckType( obj, AST__XMLMISC ) ) { + n = pro->nmisc1; + for( i = 0; i < n; i++ ) { + if( pro->misc1[ i ] == (AstXmlMiscItem *) obj ) { + for( j = i + 1; j < n; j++ ) { + pro->misc1[ j - 1 ] = pro->misc1[ j ]; + } + pro->misc1[ --pro->nmisc1 ] = NULL; + ok = 1; + break; + } + } + + if( !ok ) { + n = pro->nmisc2; + for( i = 0; i < n; i++ ) { + if( pro->misc2[ i ] == (AstXmlMiscItem *) obj ) { + for( j = i + 1; j < n; j++ ) { + pro->misc2[ j - 1 ] = pro->misc2[ j ]; + } + pro->misc2[ --pro->nmisc2 ] = NULL; + ok = 1; + break; + } + } + } + + } else if( astOK ) { + astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has " + "inappropriate parent of type %ld (internal AST " + "programming error).", status, obj->type, parent->type ); + } + +/* Now deal with cases where we are deleting items from an element. */ + } else if( astXmlCheckType( parent, AST__XMLELEM ) ) { + elem = (AstXmlElement *) parent; + +/* Remove the object form the appropriate list in the parent, and + then shuffle down the remaining entries in the list and decrement the + size of the list. */ + if( astXmlCheckType( obj, AST__XMLATTR ) ) { + n = elem->nattr; + for( i = 0; i < n; i++ ) { + if( elem->attrs[ i ] == (AstXmlAttribute *) obj ) { + for( j = i + 1; j < n; j++ ) { + elem->attrs[ j - 1 ] = elem->attrs[ j ]; + } + elem->attrs[ --elem->nattr ] = NULL; + ok = 1; + break; + } + } + + } else if( astXmlCheckType( obj, AST__XMLNAME ) ) { + n = elem->nnspref; + for( i = 0; i < n; i++ ) { + if( elem->nsprefs[ i ] == (AstXmlNamespace *) obj ) { + for( j = i + 1; j < n; j++ ) { + elem->nsprefs[ j - 1 ] = elem->nsprefs[ j ]; + } + elem->nsprefs[ --elem->nnspref ] = NULL; + ok = 1; + break; + } + } + + } else if( astXmlCheckType( obj, AST__XMLCONT ) ) { + n = elem->nitem; + for( i = 0; i < n; i++ ) { + if( elem->items[ i ] == (AstXmlContentItem *) obj ) { + for( j = i + 1; j < n; j++ ) { + elem->items[ j - 1 ] = elem->items[ j ]; + } + elem->items[ --elem->nitem ] = NULL; + ok = 1; + break; + } + } + } + + } else if( astOK ) { + astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has " + "inappropriate parent of type %ld (internal AST " + "programming error).", status, obj->type, parent->type ); + } + +/* Nullify the parent pointer so that astXmlAnnul will delete the object. */ + obj->parent = NULL; + +/* If the supplied object has no parent, we can continue to annul it. */ + } else { + ok = 1; + } + +/* Report an error if required. */ + if( !ok && astOK ) { + astError( AST__INTER, "astXmlDelete(xml): Supplied XmlObject (type %ld) " + "is not owned by its own parent (internal AST " + "programming error).", status, obj->type ); + } + +/* Delete the object. */ + result = astXmlAnnul( obj ); + +/* Annul the object and return the resulting NULL pointer. */ + return result; +} + +static AstXmlAttribute *FindAttribute( AstXmlElement *this, const char *name0, + int *status ){ +/* +* Name: +* FindAttribute + +* Purpose: +* Search an XmlElement for a named attribute + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlAttribute *FindAttribute( AstXmlElement *this, const char *name0, +* int *status ) + +* Description: +* This function searches the supplied XmlElement for an attribute +* with the given name. If found, a pointer to the XmlAttribute is +* returned. Otherwise NULL is returned. + +* Parameters: +* this +* The pointer to the XmlElement. +* name0 +* Pointer to a string holding the name of the attribute. The name +* may be preceded with a "prefix:" string, in which case the +* prefix will also be matched. If no prefix is included, the first +* attribute with the specified name is returned, regardless of +* its prefix. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to the XmlAttribute, or NULL if not found. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlAttribute *result; /* Returned pointer */ + char name_buffer[ 50 ]; /* Buffer for name */ + char prefix_buffer[ 50 ]; /* Buffer for prefix */ + const char *colon; /* Pointer to colon in supplied string */ + const char *name1; /* Pointer to name to be checked */ + const char *name; /* Pointer to name to be searched for */ + const char *prefix1; /* Pointer to prefix to be checked */ + const char *prefix; /* Pointer to prefix to be searched for */ + int i; /* Loop count */ + size_t len; /* Length of string */ + +/* Initialise */ + result = NULL; + name = name0; + prefix = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* If the supplied name string contains a colon, split it up into prefix + and name. */ + if( ( colon = strchr( name0, ':' ) ) ) { + len = colon - name0; + + if( len > 49 ) { + astError( AST__XMLNM, "FindAttribute: The XML prefix in \"%s\" " + "is too long (> 49 characters).", status, name0 ); + } else { + strncpy( prefix_buffer, name0, len ); + prefix_buffer[ len ] = 0; + prefix = prefix_buffer; + len = strlen( colon + 1 ); + + if( len > 49 ) { + astError( AST__XMLNM, "FindAttribute: The XML attribute name " + "in \"%s\" is too long (> 49 characters).", status, name0 ); + } else { + strcpy( name_buffer, colon + 1 ); + name = name_buffer; + } + + } + + } + +/* Loop round all the attributes in the element. */ + for( i = 0; i < this->nattr; i++ ) { + name1 = this->attrs[ i ]->name; + prefix1 = this->attrs[ i ]->prefix; + +/* Compare the attribute name (and prefix) with the supplied name (and + prefix). Leave the loop if they match. */ + if( !strcmp( name1, name ) && + ( !prefix || ( prefix1 && !strcmp( prefix1, prefix ) ) ) ) { + result = this->attrs[ i ]; + break; + } + } + +/* Return the result. */ + return result; +} + +static const char *Format( AstXmlObject *this, int ind, int *status ){ +/* +* Name: +* Format + +* Purpose: +* Converts an XmlObject into a character string. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* const char *Format( AstXmlObject *this, int ind, int *status ) + +* Description: +* This function returns a pointer to a dynamically allocated string +* containing a textual representation of the supplied XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject to format. +* ind +* If the XmlObject is an element, then each content item within +* the element will be prefixed by a string containing "ind" spaces +* (indenting the returned element itself is the responsibility of +* the caller and so "this" is not itself indented within this function). +* In addition, a newline character will be included at the start +* of the prefix if required, to ensure that each new item starts +* on a new line. If "ind" is less than zero, then no prefixes are +* added. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a null terminated string holding the formated XmlObject. +* This string should be freed when no longer needed using astFree. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlPrologue *pro; /* Pointer to XML prologue */ + AstXmlDocument *doc; /* Pointer to XML document */ + AstXmlAttribute *attrib; /* Pointer to XML attribute */ + AstXmlWhite *white; /* Pointer to character data */ + AstXmlBlack *black; /* Pointer to character data */ + AstXmlElement *elem; /* Pointer to XML element */ + AstXmlNamespace *ns; /* Pointer to XML namespace instruction */ + char *result; /* The returned pointer */ + const char *temp; /* A temporary string pointer */ + int i; /* Loop count */ + int nc; /* Length of returned string */ + int type; /* Object type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK || !this ) return result; + +/* Get the object type */ + type = this->type; + +/* If this is an element... */ + if( this->type == AST__XMLELEM ) { + temp = FormatTag( this, 1, status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + + elem = (AstXmlElement *) this; + if( elem->nitem > 0 ) { + +/* Go round all the items of content. */ + for( i = 0; i < elem->nitem; i++ ) { + +/* Ignore whitespace elements unless we are not producing indentation. */ + if( !astXmlCheckType( elem->items[ i ], AST__XMLWHITE ) || + ind < 0 ) { + +/* Format the item */ + temp = Format( (AstXmlObject *) elem->items[ i ], ( ( ind > -1 ) ? ind + IND_INC : -1 ), status ); + if( temp ) { + +/* Now append the next item of content, and free its memory. */ + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, + ( (ind > -1) ? ind + IND_INC : -1 ), status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + } + } + +/* Finally append the end tag. */ + temp = FormatTag( this, 0, status ); + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + + } + +/* If this is an attribute... */ + } else if( type == AST__XMLATTR ){ + attrib = (AstXmlAttribute *) this; + + if( attrib->prefix ) { + result = astAppendString( result, &nc, attrib->prefix ); + result = astAppendString( result, &nc, ":" ); + } + + temp = AddEscapes( attrib->value, status ); + result = astAppendString( result, &nc, attrib->name ); + result = astAppendString( result, &nc, "=\"" ); + result = astAppendString( result, &nc, temp ); + result = astAppendString( result, &nc, "\"" ); + temp = astFree( (void *) temp ); + + } else if( type == AST__XMLWHITE ){ + white = (AstXmlWhite *) this; + temp = AddEscapes( white->text, status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + + } else if( type == AST__XMLBLACK ){ + black = (AstXmlBlack *) this; + temp = AddEscapes( black->text, status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + + } else if( type == AST__XMLCDATA || + type == AST__XMLCOM || + type == AST__XMLPI || + type == AST__XMLDEC || + type == AST__XMLDTD ){ + + temp = FormatTag( this, 1, status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + + } else if( type == AST__XMLNAME ){ + ns = (AstXmlNamespace *) this; + result = astAppendString( result, &nc, "xmlns:" ); + result = astAppendString( result, &nc, ns->prefix ); + result = astAppendString( result, &nc, "=\"" ); + result = astAppendString( result, &nc, ns->uri ); + result = astAppendString( result, &nc, "\"" ); + + } else if( type == AST__XMLPRO ){ + pro = (AstXmlPrologue *) this; + result = astAppendString( result, &nc, + Format( (AstXmlObject *) pro->xmldecl, ind, status ) ); + +/* Append all the miscalleneous items before the DTD. */ + for( i = 0; i < pro->nmisc1; i++ ) { + temp = Format( (AstXmlObject *) pro->misc1[ i ], ind, status ); + if( temp ) { + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + } + +/* Append the DTD. */ + temp = Format( (AstXmlObject *) pro->dtdec, ind, status ); + if( temp ) { + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + +/* Append all the miscalleneous items after the DTD. */ + for( i = 0; i < pro->nmisc2; i++ ) { + temp = Format( (AstXmlObject *) pro->misc2[ i ], ind, status ); + if( temp ) { + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + } + + } else if( type == AST__XMLDOC ){ + doc = (AstXmlDocument *) this; + +/* Format the prologue. */ + result = astAppendString( result, &nc, + Format( (AstXmlObject *) doc->prolog, ind, status ) ); + +/* Append the root element. */ + temp = Format( (AstXmlObject *) doc->root, ind, status ); + if( temp ) { + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + +/* Append all the miscalleneous items in the epilogue. */ + for( i = 0; i < doc->nepi; i++ ) { + temp = Format( (AstXmlObject *) doc->epilog[ i ], ind, status ); + if( temp ) { + if( ind > -1 ) { + result = AppendLine( result, &nc, temp, ind, status ); + } else { + result = astAppendString( result, &nc, temp ); + } + temp = astFree( (void *) temp ); + } + } + + } else if( astOK ) { + astError( AST__INTER, "Format(xml): Invalid object type (%d) supplied " + "(internal AST programming error).", status, type ); + } + +/* Free the returned string if an error has occurred. */ + if( !astOK ) result = astFree( result ); + +/* Return the result. */ + return result; +} + +static char *FormatTag( AstXmlObject *this, int opening, int *status ){ +/* +* Name: +* FormatTag + +* Purpose: +* Returns a string holding an XML tag describing the given XmlObject. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* char *FormatTag( AstXmlObject *this, int opening, int *status ) + +* Description: +* This function returns a pointer to a dynamic string containing an +* XML tag describing the given XmlObject. + +* Parameters: +* this +* Pointer to the XmlObject. +* opening +* Indicates which tag is to be returned; the start tag or the end +* tag. If non-zero the start tag is returned. Otherwise, the +* end tag is returned. If the supplied XmlObject has no end +* tag (i.e. if it is an empty element, or if it is not an element), +* then NULL is returned but no error is reported. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a dynamically allocated string holding the tag. + +* Notes: +* - Empty elements are represented as an start tag of the form <.../>, +* with no corresponding end tag. +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*- +*/ + + +/* Local Variables: */ + AstXmlCDataSection *cdata;/* Pointer to XML CDATA section */ + AstXmlElement *elem; /* Pointer to XML element */ + AstXmlComment *com; /* Pointer to XML comment */ + AstXmlPI *pi; /* Pointer to XML processing instruction */ + AstXmlDTDec *dtd; /* Pointer to XML data type declaration */ + AstXmlDeclPI *xmlpi; /* XML version declaration */ + char *result; /* The returned pointer */ + const char *temp; /* A temporary string pointer */ + int i; /* Loop count */ + int nc; /* Length of returned string */ + int type; /* Object type */ + +/* Initialise */ + result = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Get the object type */ + type = this->type; + +/* If this is an element... */ + if( this->type == AST__XMLELEM ) { + elem = (AstXmlElement *) this; + + if( opening ) { + result = astAppendString( result, &nc, "<" ); + if( elem->prefix ) { + result = astAppendString( result, &nc, elem->prefix ); + result = astAppendString( result, &nc, ":" ); + } + result = astAppendString( result, &nc, elem->name ); + + if( elem->defns ) { + result = astAppendString( result, &nc, " xmlns=\"" ); + result = astAppendString( result, &nc, elem->defns ); + result = astAppendString( result, &nc, "\"" ); + } + + for( i = 0; i < elem->nnspref; i++ ) { + temp = Format( (AstXmlObject *) elem->nsprefs[ i ], -1, status ); + if( temp ) { + result = AppendChar( result, &nc, ' ', status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + } + } + + for( i = 0; i < elem->nattr; i++ ) { + temp = Format( (AstXmlObject *) elem->attrs[ i ], -1, status ); + if( temp ){ + result = AppendChar( result, &nc, ' ', status ); + result = astAppendString( result, &nc, temp ); + temp = astFree( (void *) temp ); + } + } + + if( elem->nitem == 0 ) result = astAppendString( result, &nc, "/" ); + result = astAppendString( result, &nc, ">" ); + + } else if( elem->nitem > 0 ) { + result = astAppendString( result, &nc, "</" ); + if( elem->prefix ) { + result = astAppendString( result, &nc, elem->prefix ); + result = astAppendString( result, &nc, ":" ); + } + result = astAppendString( result, &nc, elem->name ); + result = astAppendString( result, &nc, ">" ); + } + + } else if( type == AST__XMLDTD ){ + dtd = (AstXmlDTDec *) this; + if( opening && dtd->name && dtd->name[0] ) { + result = astAppendString( result, &nc, "<!DOCTYPE " ); + result = astAppendString( result, &nc, dtd->name ); + if( dtd->external && dtd->external[ 0 ] ) { + result = astAppendString( result, &nc, " " ); + result = astAppendString( result, &nc, dtd->external ); + } + if( dtd->internal && dtd->internal[ 0 ] ) { + result = astAppendString( result, &nc, " [" ); + result = astAppendString( result, &nc, dtd->internal ); + result = astAppendString( result, &nc, "]" ); + } + result = astAppendString( result, &nc, ">" ); + } + + } else if( type == AST__XMLCDATA ){ + if( opening ) { + cdata = (AstXmlCDataSection *) this; + result = astAppendString( result, &nc, "<![CDATA[" ); + result = astAppendString( result, &nc, cdata->text ); + result = astAppendString( result, &nc, "]]>" ); + } + + } else if( type == AST__XMLCOM ){ + if( opening ) { + com = (AstXmlComment *) this; + result = astAppendString( result, &nc, "<!--" ); + result = astAppendString( result, &nc, com->text ); + result = astAppendString( result, &nc, "-->" ); + } + + } else if( type == AST__XMLPI ){ + pi = (AstXmlPI *) this; + if( opening ) { + result = astAppendString( result, &nc, "<?" ); + result = astAppendString( result, &nc, pi->target ); + if( pi->text && pi->text[0] ) { + result = astAppendString( result, &nc, " " ); + result = astAppendString( result, &nc, pi->text ); + } + result = astAppendString( result, &nc, "?>" ); + } + + } else if( type == AST__XMLDEC ){ + xmlpi = (AstXmlDeclPI *) this; + if( opening && xmlpi->text && xmlpi->text[0] ) { + result = astAppendString( result, &nc, "<?xml" ); + if( xmlpi->text && xmlpi->text[0] ) { + result = astAppendString( result, &nc, " " ); + result = astAppendString( result, &nc, xmlpi->text ); + } + result = astAppendString( result, &nc, "?>" ); + } + } + +/* If notOK, free the rteurned string. */ + if( !astOK ) result = astFree( result ); + +/* Return the result. */ + return result; +} + +static void InitXmlAttribute( AstXmlAttribute *new, int type, const char *name, + const char *value, const char *prefix, int *status ){ +/* +* Name: +* InitXmlAttribute + +* Purpose: +* Initialise a new XmlAttribute. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlAttribute( AstXmlAttribute *new, int type, const char *name, +* const char *value, const char *prefix, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlAttribute +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* name +* The name for the attribute. +* value +* The value for the attribute +* prefix +* The namespace prefix for the attribute. May be NULL or blank, in +* which case any prefix at the start of "name" is used. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + const char *colon; /* Pointer to colon within supplied name */ + char *newname; /* Pointer to name string (no prefix) */ + char *newpref; /* Pointer to name string */ + int nc; /* Length of prefix string */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLATTR, status ) ){ + astError( AST__INTER, "InitXmlAttribute: Supplied object type (%d) " + "does not represent an XmlAttribute", status, type ); + } + +/* Ensure we have non-NULL pointers. */ + if( !name ) name = ""; + if( !value ) value = ""; + +/* If no prefix was supplied, extract any prefix from the start of the + supplied name. */ + newname = (char *) name; + newpref = (char *) prefix; + colon = NULL; + + if( !prefix || astChrLen( prefix ) == 0 ){ + colon = strchr( name, ':' ); + if( colon ) { + nc = colon - name; + newpref = astStore( NULL, name, nc + 1 ); + newpref[ nc ] = 0; + + nc = strlen( name ) - ( colon - name ) - 1; + newname = astStore( NULL, colon + 1, nc + 1 ); + newname[ nc ] = 0; + } + } + +/* Check the supplied name and prefix are valid XML 'names'. */ + CheckName( newname, "attribute", "InitXmlAttribute", 0, status ); + CheckName( newpref, "attribute", "InitXmlAttribute", 1, status ); + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Initialise the items specific to this class of structure. */ + new->name = astStore( NULL, newname, strlen( newname ) + 1 ); + new->value = astStore( NULL, value, strlen( value ) + 1 ); + new->prefix = NULL; + if( newpref ) { + nc = strlen( newpref ); + if( nc > 0 ) new->prefix = astStore( NULL, newpref, nc + 1 ); + } + +/* Free any name and prefix extracted from the supplied name string */ + if( colon ) { + newname = astFree( newname ); + newpref = astFree( newpref ); + } +} + +static void InitXmlCDataSection( AstXmlCDataSection *new, int type, + const char *text, int *status ){ +/* +* Name: +* InitXmlCDataSection + +* Purpose: +* Initialise a new XmlCDataSection. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlCDataSection( AstXmlCDataSection *new, int type, +* const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlCDataSection +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* text +* Pointer to a null terminated string holding the text. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLCDATA, status ) ){ + astError( AST__INTER, "InitXmlCDataSection: Supplied object type (%d) " + "does not represent an XmlCDataSection", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !text ) text = ""; + +/* Initialise the items specific to this class of structure. */ + new->text = astStore( NULL, text, strlen( text ) + 1 ); +} + +static void InitXmlWhite( AstXmlWhite *new, int type, const char *text, int *status ){ +/* +* Name: +* InitXmlWhite + +* Purpose: +* Initialise a new XmlWhite. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlWhite( AstXmlWhite *new, int type, const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlWhite +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* text +* Pointer to a null terminated string holding the text. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + const char *c; /* Pointer to next character */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLWHITE, status ) ){ + astError( AST__INTER, "InitXmlWhite: Supplied object type (%d) " + "does not represent an XmlWhite", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !text ) text = ""; + +/* Report an error if the text is not white. */ + c = text - 1; + while( *(++c) ) { + if( !isspace( *c ) ) { + astError( AST__XMLCM, "InitXmlWhite(xml): Illegal XML whitespace " + "string supplied \"%s\" - not all characters are white.", status, + text ); + break; + } + } + +/* Initialise the items specific to this class of structure. */ + new->text = astStore( NULL, text, strlen( text ) + 1 ); +} + +static void InitXmlBlack( AstXmlBlack *new, int type, const char *text, int *status ){ +/* +* Name: +* InitXmlBlack + +* Purpose: +* Initialise a new XmlBlack. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlBlack( AstXmlBlack *new, int type, const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlBlack +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* text +* Pointer to a null terminated string holding the text. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLBLACK, status ) ){ + astError( AST__INTER, "InitXmlBlack: Supplied object type (%d) " + "does not represent an XmlBlack", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !text ) text = ""; + +/* Initialise the items specific to this class of structure. */ + new->text = astStore( NULL, text, strlen( text ) + 1 ); +} + +static void InitXmlComment( AstXmlComment *new, int type, const char *text, int *status ){ +/* +* Name: +* InitXmlComment + +* Purpose: +* Initialise a new XmlComment. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlComment( AstXmlComment *new, int type, const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlComment +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* text +* Pointer to a null terminated string holding the text. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLCOM, status ) ){ + astError( AST__INTER, "InitXmlComment: Supplied object type (%d) " + "does not represent an XmlComment", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !text ) text = ""; + +/* Initialise the items specific to this class of structure. Report an error + if the comment is illegal. */ + if( strstr( text, "--" ) && astOK ) { + astError( AST__XMLCM, "InitXmlCom(xml): Illegal XML comment " + "supplied \"%s\" - comments may not contain the " + "string \"--\".", status, text ); + new->text = NULL; + } else { + new->text = astStore( NULL, text, strlen( text ) + 1 ); + } +} + +static void InitXmlDeclPI( AstXmlDeclPI *new, int type, const char *text, int *status ){ +/* +* Name: +* InitXmlDeclPI + +* Purpose: +* Initialise a new XmlDeclPI. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlDeclPI( AstXmlDeclPI *new, int type, const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlDeclPI +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* text +* Pointer to a null terminated string holding the text. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLDEC, status ) ){ + astError( AST__INTER, "InitXmlDeclPI: Supplied object type (%d) " + "does not represent an XmlDeclPI", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !text ) text = ""; + +/* Initialise the items specific to this class of structure. */ + new->text = astStore( NULL, text, strlen( text ) + 1 ); +} + +static void InitXmlDocument( AstXmlDocument *new, int type, int *status ){ +/* +* Name: +* InitXmlDocument + +* Purpose: +* Initialise a new XmlDocument. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlDocument( AstXmlDocument *new, int type, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlDocument +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLDOC, status ) ){ + astError( AST__INTER, "InitXmlDocument: Supplied object type (%d) " + "does not represent an XmlDocument", status, type ); + } + +/* Initialise the parent XmlObject */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Initialise the items specific to this class of structure. */ + new->prolog = NULL; + new->root = NULL; + new->epilog = NULL; + new->nepi = 0; + new->current = NULL; +} + +static void InitXmlDTDec( AstXmlDTDec *new, int type, const char *name, + const char *external, const char *internal, int *status ){ +/* +* Name: +* InitXmlDTDec + +* Purpose: +* Initialise a new XmlDTDec. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void InitXmlDTDec( AstXmlDTDec *new, int type, const char *name, +* const char *external, const char *internal, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlDTDec +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* name +* The document type name +* external +* The external SYSTEM id. +* internal +* The internal declaration markup text (this is not checked or +* parsed). +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLDTD, status ) ){ + astError( AST__INTER, "InitXmlDTDec: Supplied object type (%d) " + "does not represent an XmlDTDec", status, type ); + } + +/* Initialise the parent XmlObject */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !name ) name = ""; + if( !external ) external = ""; + if( !internal ) internal = ""; + +/* Initialise the items specific to this class of structure. */ + new->name = astStore( NULL, name, strlen( name ) + 1 ); + new->external = astStore( NULL, external, strlen( external ) + 1 ); + new->internal = astStore( NULL, internal, strlen( internal ) + 1 ); +} + +static void InitXmlElement( AstXmlElement *new, int type, const char *name, + const char *prefix, int *status ){ +/* +* Name: +* InitXmlElement + +* Purpose: +* Initialise a new XmlElement. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlElement( AstXmlElement *new, int type, const char *name, +* const char *prefix, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlElement +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* name +* The name for the element. +* prefix +* The namespace prefix for the element. May be NULL or blank, in +* which case any prefix at the start of "name" is used. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + const char *colon; /* Pointer to colon within supplied name */ + char *newname; /* Pointer to name string (no prefix) */ + char *newpref; /* Pointer to name string */ + int nc; /* Length of prefix string */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLELEM, status ) ){ + astError( AST__INTER, "InitXmlElement: Supplied object type (%d) " + "does not represent an XmlElement", status, type ); + } + +/* Ensure we have non-NULL pointers. */ + if( !name ) name = ""; + +/* If no prefix was supplied, extract any prefix from the start of the + supplied name. */ + newname = (char *) name; + newpref = (char *) prefix; + colon = NULL; + + if( !prefix || astChrLen( prefix ) == 0 ){ + colon = strchr( name, ':' ); + if( colon ) { + nc = colon - name; + newpref = astStore( NULL, name, nc + 1 ); + newpref[ nc ] = 0; + + nc = strlen( name ) - ( colon - name ) - 1; + newname = astStore( NULL, colon + 1, nc + 1 ); + newname[ nc ] = 0; + } + } + +/* Check the supplied name and prefix are valid XML 'names'. */ + CheckName( newname, "element", "InitXmlElement", 0, status ); + CheckName( newpref, "element", "InitXmlElement", 1, status ); + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Initialise the items specific to this class of structure. */ + new->name = astStore( NULL, newname, strlen( newname ) + 1 ); + new->attrs = NULL; + new->nattr = 0; + new->items = NULL; + new->nitem = 0; + new->defns = NULL; + new->nsprefs = NULL; + new->nnspref = 0; + new->complete = 0; + + new->prefix = NULL; + if( newpref ) { + nc = strlen( newpref ); + if( nc > 0 ) new->prefix = astStore( NULL, newpref, nc + 1 ); + } + +/* Free any name and prefix extracted from the supplied name string */ + if( colon ) { + newname = astFree( newname ); + newpref = astFree( newpref ); + } +} + +static void InitXmlNamespace( AstXmlNamespace *new, int type, const char *prefix, + const char *uri, int *status ){ +/* +* Name: +* InitXmlNamespace + +* Purpose: +* Initialise a new XmlNamespace. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlNamespace( AstXmlNamespace *new, int type, const char *prefix, +* const char *uri, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlNamespace +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* prefix +* Pointer to a null terminated string holding the namespace prefix. +* uri +* Pointer to a null terminated string holding the namespace URI. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLNAME, status ) ){ + astError( AST__INTER, "InitXmlNamespace: Supplied object type (%d) " + "does not represent an XmlNamespace", status, type ); + } + +/* Ensure we have non-NULL pointers. */ + if( !prefix ) prefix = ""; + if( !uri ) uri = ""; + +/* Check the supplied prefix is a valid XML 'name'. */ + CheckName( prefix, "namespace prefix", "InitXmlNamespace", 0, status ); + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Initialise the items specific to this class of structure. */ + new->prefix = astStore( NULL, prefix, strlen( prefix ) + 1 ); + new->uri = astStore( NULL, uri, strlen( uri ) + 1 ); +} + +static void InitXmlObject( AstXmlObject *new, long int type, int *status ){ +/* +* Name: +* InitXmlObject + +* Purpose: +* Initialise a new XmlObject. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlObject( AstXmlObject *new, long int type, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlObject +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + +/* Check the global error status. */ + if( !astOK ) return; + +/* If needed, get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the supplied object type is OK. Report an error if not. */ + if( !CheckType( type, AST__XMLOBJECT, status ) ){ + astError( AST__INTER, "InitXmlObject: Supplied object type (%ld) " + "is not appropriate for an XmlObject", status, type ); + } + +/* This class of structure is the base class for XML objects so it has no + parent class to be initialised. So just initialise the items specific to + this class of structure. */ + new->parent = NULL; + new->type = type; + new->id = next_id++; + +#ifdef DEBUG +/* Add the new XmlObject to the list of all XmlObjects. */ + AddObjectToList( new ); +#endif + +} + +static void InitXmlPI( AstXmlPI *new, int type, const char *target, + const char *text, int *status ){ +/* +* Name: +* InitXmlPI + +* Purpose: +* Initialise a new XmlPI. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlPI( AstXmlPI *new, int type, const char *target, +* const char *text, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlPI +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* target +* Pointer to a null terminated string holding the PI target. +* text +* Pointer to a null terminated string holding the PI text. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLPI, status ) ){ + astError( AST__INTER, "InitXmlPI: Supplied object type (%d) " + "does not represent an XmlPI", status, type ); + } + +/* Initialise the parent XmlObject component. */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Ensure we have non-NULL pointers. */ + if( !target ) target = ""; + if( !text ) text = ""; + +/* Initialise the items specific to this class of structure. Report an error + if anything is illegal. */ + new->target = NULL; + new->text = NULL; + + if( !Ustrcmp( target, "XML", status ) && astOK ) { + astError( AST__XMLPT, "InitXmlPI(xml): Illegal XML PI target \"%s\"" + " supplied.", status, target ); + } else { + new->target = astStore( NULL, target, strlen( target ) + 1 ); + new->text = astStore( NULL, text, strlen( text ) + 1 ); + } +} + +static void InitXmlPrologue( AstXmlPrologue *new, int type, int *status ){ +/* +* Name: +* InitXmlPrologue + +* Purpose: +* Initialise a new XmlPrologue. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* InitXmlPrologue( AstXmlPrologue *new, int type, int *status ) + +* Description: +* This function initialises supplied memory to hold an XmlPrologue +* structure. + +* Parameters: +* new +* The memory in which to initialise the structure. +* type +* An identifier for the structure type. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if( !astOK ) return; + +/* Check the supplied object type is appropriate for the class of + structure being initialised. If not report an error. */ + if( !CheckType( type, AST__XMLPRO, status ) ){ + astError( AST__INTER, "InitXmlPrologue: Supplied object type (%d) " + "does not represent an XmlPrologue", status, type ); + } + +/* Initialise the parent XmlObject */ + InitXmlObject( (AstXmlObject *) new, type, status ); + +/* Initialise the items specific to this class of structure. */ + new->xmldecl = NULL; + new->misc1 = NULL; + new->nmisc1 = 0; + new->dtdec = NULL; + new->misc2 = NULL; + new->nmisc2 = 0; +} + +static int MatchName( AstXmlElement *this, const char *name, int *status ){ +/* +* Name: +* MatchName + +* Purpose: +* Check that an element has a specified name and/or prefix. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* int MatchName( AstXmlElement *this, const char *name, int *status ) + +* Description: +* This function checks that an element has a specified name and/or prefix. + +* Parameters: +* this +* The XmlElement to check. +* name +* The name for the element (may include a namespace prefix). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if the supplied element has the supplie dname/prefix. Zero +* otherwise. + +*/ + + +/* Local Variables: */ + const char *colon; /* Pointer to colon within supplied name */ + char *newname; /* Pointer to name string (no prefix) */ + char *newpref; /* Pointer to name string */ + int nc; /* Length of prefix string */ + int result; /* Returned value */ + +/* Initialise */ + result = 0; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* Extract any prefix from the start of the supplied name. */ + newpref = NULL; + newname = (char *) name; + colon = strchr( name, ':' ); + if( colon ) { + nc = colon - name; + newpref = astStore( NULL, name, nc + 1 ); + newpref[ nc ] = 0; + + nc = strlen( name ) - ( colon - name ) - 1; + newname = astStore( NULL, colon + 1, nc + 1 ); + newname[ nc ] = 0; + } + +/* Compare the prefix. */ + if( newpref && this->prefix ) { + result = !strcmp( newpref, this->prefix ); + + } else if( !newpref && !this->prefix ) { + result = 1; + + } else { + result = 0; + } + +/* If the prefixes matches, compare the names */ + if( result ) { + if( newname && this->name ) { + result = !strcmp( newname, this->name ); + + } else if( !newname && !this->name ) { + result = 1; + + } else { + result = 0; + } + } + +/* Free any name and prefix extracted from the supplied name string */ + if( colon ) { + newname = astFree( newname ); + newpref = astFree( newpref ); + } + +/* Return the result. */ + return result; +} + +static AstXmlAttribute *NewAttribute( const char *name, const char *value, + const char *prefix, int *status ){ +/* +* Name: +* NewAttribute + +* Purpose: +* Create a new XmlAttribute. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlAttribute *NewAttribute( const char *name, const char *value, +* const char *prefix, int *status ) + +* Description: +* This function creates a new XmlAttribute structure representing an +* XML attribute with the given name, value and namespace prefix. + +* Parameters: +* name +* Pointer to a null terminated string containing the attribute name. +* value +* Pointer to a null terminated string containing the attribute value. +* prefix +* Pointer to a null terminated string containing the attribute +* namespace prefix (may be NULL or blank). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the new structure is returned. + +* Notes: +* - A NULL pointer is returned if the inherited status value +* indicates an error has occurred on entry, or if this function +* should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlAttribute *new; /* The returned pointer */ + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK ) return new; + +/* Allocate space for the new structure. */ + new = (AstXmlAttribute *) astMalloc( sizeof( AstXmlAttribute ) ); + +/* Initialise it. */ + InitXmlAttribute( new, AST__XMLATTR, name, value, prefix, status ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) new = astXmlDelete( new ); + +/* Return the result. */ + return new; + +} + +static AstXmlDocument *NewDocument( int *status ){ +/* +* Name: +* NewDocument + +* Purpose: +* Create a new empty XmlDocument. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlDocument *NewDocument( int *status ) + +* Description: +* This function creates a new empty XmlDocument structure representing +* an entire XML Document. + +* Parameters: +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the new structure is returned. + +* Notes: +* - A NULL pointer is returned if the inherited status value +* indicates an error has occurred on entry, or if this function +* should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlDocument *new; /* The returned pointer */ + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK ) return new; + +/* Allocate space for the new structure. */ + new = (AstXmlDocument *) astMalloc( sizeof( AstXmlDocument ) ); + +/* Initialise it. */ + InitXmlDocument( new, AST__XMLDOC, status ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) new = astXmlDelete( new ); + +/* Return the result. */ + return new; + +} + +static AstXmlNamespace *NewNamespace( const char *prefix, const char *uri, int *status ){ +/* +* Name: +* NewNamespace + +* Purpose: +* Create a new XmlNamespace. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlNamespace *NewNamespace( const char *prefix, +* const char *uri, int *status ) + +* Description: +* This function creates a new XmlNamespace structure representing an +* XML namespace with the given prefix and uri. + +* Parameters: +* prefix +* Pointer to a null terminated string containing the namespace prefix. +* uri +* Pointer to a null terminated string containing the associated URI. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the new structure is returned. + +* Notes: +* - A NULL pointer is returned if the inherited status value +* indicates an error has occurred on entry, or if this function +* should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlNamespace *new; /* The returned pointer */ + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK ) return new; + +/* Allocate space for the new structure. */ + new = (AstXmlNamespace *) astMalloc( sizeof( AstXmlNamespace ) ); + +/* Initialise it. */ + InitXmlNamespace( new, AST__XMLNAME, prefix, uri, status ); + +/* If an error occurred, delete the new structure. */ + if( !astOK ) new = astXmlDelete( new ); + +/* Return the result. */ + return new; + +} + +static AstXmlPrologue *NewPrologue( AstXmlDocument *doc, int *status ){ +/* +* Name: +* NewPrologue + +* Purpose: +* Create a new empty XmlPrologue. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlPrologue *NewPrologue( AstXmlDocument *doc, int *status ) + +* Description: +* This function creates a new empty XmlPrologue structure representing +* an entire prologue. + +* Parameters: +* doc +* A pointer to the XmlDocument to add the XmlPrologue to, or NULL. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the new structure is returned. + +* Notes: +* - A NULL pointer is returned if the inherited status value +* indicates an error has occurred on entry, or if this function +* should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlPrologue *new; /* The returned pointer */ + +/* Initialise */ + new = NULL; + +/* Check the global error status. */ + if( !astOK ) return new; + +/* Allocate space for the new structure. */ + new = (AstXmlPrologue *) astMalloc( sizeof( AstXmlPrologue ) ); + +/* Initialise it. */ + InitXmlPrologue( new, AST__XMLPRO, status ); + +/* Set its parent. */ + ((AstXmlObject *) new )->parent = (AstXmlParent *) doc; + +/* If an error occurred, delete the new structure. */ + if( !astOK ) new = astXmlDelete( new ); + +/* Return the result. */ + return new; + +} + +static char *RemoveEscapes( const char *text, int *status ){ +/* +* Name: +* RemoveEscapes + +* Purpose: +* Replaces entity references by corresponding ascii characters. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* char *RemoveEscapes( const char *text, int *status ) + +* Description: +* This function produces a dynamic copy of the supplied text in which +* occurrences of XML entity references are replaced by the corresponding +* ASCII text. + +* Parameters: +* text +* A pointer to a text string. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a dynamically allocated string containing the required +* copy. + +* Notes: +* - NULL is returned if this function is called with the global error +* status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + char *d; /* Pointer to next returned character */ + char *result; /* Returned pointer */ + char rc; /* Replacement character */ + const char *c; /* Pointer to next supplied character */ + int nc; /* Number of characters to skip */ + +/* Initialise */ + result = NULL; + nc = 0; + +/* Return if the pointer is NULL or if an error has occurred. */ + if( !astOK || !text ) return result; + +/* Allocate memory to hold a copy of the supplied text. */ + result = astMalloc( strlen( text ) + 1 ); + +/* Check the pointer can be used safely. */ + if( astOK ) { + +/* Loop round every character in the supplied text. */ + c = text - 1; + d = result; + while( *(++c) ) { + +/* If this character marks the start of a entity reference, replace it by + the corresponding ascii character and shuffle the remaining text down. */ + if( !strncmp( c, "&", 5 ) ) { + rc = '&'; + nc= 4; + + } else if( !strncmp( c, "<", 4 ) ) { + rc = '<'; + nc= 3; + + } else if( !strncmp( c, ">", 4 ) ) { + rc = '>'; + nc= 3; + + } else if( !strncmp( c, "'", 6 ) ) { + rc = '\''; + nc= 5; + + } else if( !strncmp( c, """, 6 ) ) { + rc = '"'; + nc= 5; + + } else { + rc = 0; + } + + if( rc ) { + *(d++) = rc; + c += nc; + } else { + *(d++) = *c; + } + + } + +/* Terminate the returned string. */ + *d = 0; + +/* Reallocate the string to free up any unused space. */ + result = astRealloc( result, d - result + 1 ); + } + +/* Return the result. */ + return result; +} + +#ifdef DEBUG +static void RemoveObjectFromList( AstXmlObject *obj ){ +/* +* Name: +* RemoveObjectFromList + +* Purpose: +* Removes an XmlObject from a static list of all currently active XmlObjects. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* void RemoveObjectFromList( AstXmlObject *obj ) + +* Description: +* This function removes the supplied pointer from a static list of +* pointers, and decrements the number of elements in the list. This list +* holds pointers to all the XmlObjects which currently exist. If the +* supplied pointer is not found in the list, this function returns +* without action. + +* Parameters: +* this +* A pointer to the XmlObject. + +* Notes: +* - This function attempts to execute even if an error has already +* occurred. +*/ + +/* Local Variavles: */ + int i; + int ii; + +/* Locate the supplied pointer within the list of pointers to all + currently active XmlObjects. */ + ii = -1; + for( i = 0; i < nobj; i++ ){ + if( existing_objects[ i ]->id == obj->id ) { + ii = i; + break; + } + } + +/* Check the pointer was found. */ + if( ii != -1 ) { + +/* Shuffle all higher index pointers down one in the list in order to fill + the gap left by removing the supplied pointer. */ + for( ii++; ii < nobj; ii++ ){ + existing_objects[ ii - 1 ] = existing_objects[ ii ]; + } + +/* Decrement the number of pointers in the list. */ + nobj--; + +/* Nullify the pointer at the end of the list which is no longer used. */ + existing_objects[ nobj ] = NULL; + } +} +#endif + +static const char *ResolvePrefix( const char *prefix, AstXmlElement *elem, int *status ){ +/* +* Name: +* ResolvePrefix + +* Purpose: +* Find the URI associated with a namespace prefix. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* const char *ResolvePrefix( const char *prefix, AstXmlElement *elem, int *status) + +* Description: +* This function searches the namespaces defined within the supplied +* element for a prefix which matches the supplied prefix. If found, +* it returns a pointer to the URI string associated with the prefix. +* If not found, it calls this function recursively on the parent +* element. If there is no parent element, NULL is returned. + +* Parameters: +* prefix +* Pointer to a string holding the namespace prefix. +* elem +* The pointer to the XmlElement. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a string holding the URI, or NULL if not found. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +*/ + +/* Local Variables: */ + AstXmlParent *parent; /* Parent object */ + AstXmlNamespace *ns; /* Next namespace */ + const char *result; /* Returned pointer */ + int i; /* Loop count */ + +/* Initialise */ + result = NULL; + +/* Check the global error status, and the supplied element. */ + if( !astOK || !elem ) return result; + +/* Loop round all the namespace definitions in the element. */ + for( i = 0; i < elem->nnspref; i++ ) { + ns = elem->nsprefs[ i ]; + +/* Compare the namespace prefix with the supplied prefix (case sensitive). + Store a pointer to the associated URI if they match, and leave the + loop. */ + if( !strcmp( ns->prefix, prefix ) ) { + result = ns->uri; + break; + } + } + +/* If no matching namespace was found, attempt to resolve the prefix + within the context of the parent element. */ + if( !result ) { + parent = ((AstXmlObject *) elem )->parent; + if( astXmlCheckType( parent, AST__XMLELEM ) ) { + result = ResolvePrefix( prefix, (AstXmlElement *) parent, status ); + } + } + +/* Return the result. */ + return result; +} + +static int Ustrcmp( const char *a, const char *b, int *status ){ +/* +* Name: +* Ustrncmp + +* Purpose: +* A case blind version of strcmp. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* int Ustrcmp( const char *a, const char *b ) + +* Description: +* Returns 0 if there are no differences between the two strings, and 1 +* otherwise. Comparisons are case blind. + +* Parameters: +* a +* Pointer to first string. +* b +* Pointer to second string. + +* Returned Value: +* Zero if the strings match, otherwise one. + +* Notes: +* - This function does not consider the sign of the difference between +* the two strings, whereas "strcmp" does. +* - This function attempts to execute even if an error has occurred. + +*/ + +/* Local Variables: */ + const char *aa; /* Pointer to next "a" character */ + const char *bb; /* Pointer to next "b" character */ + int ret; /* Returned value */ + +/* Initialise the returned value to indicate that the strings match. */ + ret = 0; + +/* Initialise pointers to the start of each string. */ + aa = a; + bb = b; + +/* Loop round each character. */ + while( 1 ){ + +/* We leave the loop if either of the strings has been exhausted. */ + if( !(*aa ) || !(*bb) ){ + +/* If one of the strings has not been exhausted, indicate that the + strings are different. */ + if( *aa || *bb ) ret = 1; + +/* Break out of the loop. */ + break; + +/* If neither string has been exhausted, convert the next characters to + upper case and compare them, incrementing the pointers to the next + characters at the same time. If they are different, break out of the + loop. */ + } else { + + if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){ + ret = 1; + break; + } + + } + + } + +/* Return the result. */ + return ret; + +} + +#ifdef DEBUG +int astXmlTrace( int show ){ +/* +*+ +* Name: +* astXmlTrace + +* Purpose: +* List details of XML objects currently in existence. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* int astXmlTrace( int show ) + +* Description: +* Lists details of XML objects currently in existence. Details are +* written to standard output. + +* Parameters: +* show +* - 0, the ID values of all currently active XmlObjects are +* listed. The objects themselves are unchanged. +* - 1, each object is displayed using astXmlShow unless it has +* already been included in the display of a previous object, and then +* annulled. Consequently, this mode is destructive, and none of the +* displayed XmlObjects will be acessable afterwards. +* - 2, each object is displayed using astXmlShow whether or not it +* has already been included in the display of a previous object. +* The objects are left unchanged. +* - 3, nothing is written to standard output, but the number of +* active XmlObjects is still returned. + +* Returned Value: +* The number of XMLObjects which are in existence on entry to this +* function. + +*- +*/ + +/* Local Variables: */ + AstXmlObject *root; + int i, result, old_status; + + old_status = astStatus; + astClearStatus; + + result = nobj; + + if( show == 0 ) { + printf( "Current list of active XmlObject identifiers: " ); + for( i = 0; i < nobj; i++ ) printf( "%d ", existing_objects[ i ]->id ); + printf("\n"); + + } else if( show ==1 ){ + while( nobj > 0 ) { + root = astXmlGetRoot( existing_objects[0] ); + printf( "ID = %d (type %ld)\n%s\n------------\n", + root->id, root->type, astXmlShow( root ) ); + root = astXmlAnnulTree( root ); + } + + } else if( show == 2 ) { + for( i = 0; i < nobj; i++ ) printf( "%d\n%s\n------------\n", + existing_objects[ i ]->id, + astXmlShow(existing_objects[ i ]) ); + printf("\n"); + } + + astSetStatus( old_status ); + + return result; +} +#endif + +AstXmlElement *astXmlReadDocument_( AstXmlDocument **doc, + int (*is_wanted)( AstXmlElement *, int * ), + int skip, char (*source)( void *, int * ), + void *data, int *status ){ +/* +*+ +* Name: +* astXmlReadDocument + +* Purpose: +* Read and parse an XML document. + +* Type: +* Protected function. + +* Synopsis: +* #include "xml.h" +* AstXmlElement *astXmlReadDocument( AstXmlDocument **doc, +* int (*is_wanted)( AstXmlElement *, int * ), +* int skip, char (*source)( void *, int * ), +* void *data ) + +* Description: +* This function reads and parses text from an XML source. The text is +* obtained by calling the supplied "source" function, which returns +* the next character read from the external source on each invocation. +* +* The reading scheme combines elements of the SAX and DOM schemes in +* an attempt to minimise memory requirements (a potential problem with +* DOM) whilst retaining a simple interface for accessing the XML +* elements of interest to the client (a potential problem for SAX). +* +* When an element start tag is encountered in the source, the client +* is asked to indicate whether the element is of interest. This is +* done by calling the supplied "is_wanted" function. If the client +* indicates that the element is of interest, its contents are read +* and a pointer to a corresponding XmlElement structure is returned. +* Reading stops when the element has been read. If the client +* indicates that the element is not of interest, then (if "skip" is +* non-zero) the contents of the element are skipped over, and reading +* continues following the element end tag. When the next element is +* encountered the client will again be asked to indicate its interest +* in the element. This continues until either the client indicates that +* an element is of interest, or the end of the source is reached. If +* "skip" is zero, then an error is reported if the first element in +* the document is not of interest. +* +* The client has an option to reply that an element is not itself of +* interest, but may possibly contain interesting elements. In this case, +* the sub-elements within the element are read and checked in the same +* way. +* +* This function returns, and no more characters are read from the +* source, once the contents of the first "interesting" element has been +* read. +* +* The function thus returns a pointer to an XmlElement containing the +* entire contents of the first interesting element encountered in the +* source. This function can then be invoked again to read further +* interesting elements from the source. In this case, the XmlDocument +* structure created by the initial invocation (see parameter "doc") +* must be supplied, as this indicates the point in the total document +* structure at which the previous "interesting" element was located. + +* Parameters: +* doc +* Address of a location holding a pointer to an AstXmlDocument +* structure. The AstXmlDocument pointer should be supplied as NULL +* when invoking this function for the first time on a document +* source (i.e. when reading from the beginning of the document). +* In this case a new AstXmlDocument structure will be created and a +* pointer to it stored at the supplied address. This structure +* holds the context which enables subsequent invocations of this +* function to determine the point in the document structure at +* which to store any further text read from the source. It also +* holds the document prologue, root element, and epilogue. +* is_wanted +* Pointer to a function which is called to decide if the client is +* interested in each element start tag which has just been read. +* It has a single argument which is a pointer to the (empty) XmlElement +* corresponding to the element start tag which has just been read. +* It returns an integer: +* -1 : the element is not itself of interest but it may contain +* an interesting element, so look through the content and +* ask the client again about any elements found inside it. +* 0 : the element definately contains nothing of interest to +* the client. kip its content and continue looking for new +* elements. +* 1 : the element is definately of interest to the client so +* read its contents and return a pointer to it. +* If NULL is supplied, a value of "+1" is assumed. +* skip +* Indicates if any uninteresting elements may proceed the first +* element of interest. If zero, then an error is reported if the +* first element read from the source is not of interest to the client. +* If non-zero, then any uninteresting elements are simply skipped +* over until an interesting element is found or the document ends. +* source +* Pointer to a function which is called to return the next +* character from the source. It has a single argument which is +* used to pass any supplied data to it. It should return zero when +* the end of the source is reached. +* data +* Pointer to a structure to pass to the source function. This +* structure may contain any data needed by the source function. + +* Returned Value: +* A pointer to the first element of interest, or NULL if there are no +* interesting elements in the source. The returned element will be a +* descendant of "*doc". For this reason, the returned pointer need not +* be annulled explicitly since it will be freed when the XmlDocument +* is annulled. However, if required (e.g. to save memory) it may be +* annulled before the document is annulled by using astXmlRemoveItem to +* remove it from its parent, and then using astXmlAnnul to annul it. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +* - It is assumed that the read commences outside any tag (i.e. +* in between tags or within character data). +*- +*/ + +/* Local Variables: */ + AstXmlElement *result; + +/* Check any supplied pointer is for an XmlDocument. */ + astXmlCheckDocument( *doc, 1 ); + +/* Read and parse the source text. Indicate that the element being read + *may* contain items of interest to the client. Surround with a mutex + since the supplied functions may not be thread-safe. */ + LOCK_MUTEX1; + result = ReadContent( doc, -1, is_wanted, skip, source, data, 0, status ); + UNLOCK_MUTEX1; + +/* Return the result. */ + return result; +} + + +static AstXmlElement *ReadContent( AstXmlDocument **doc, int wanted, + int (*is_wanted)( AstXmlElement *, int * ), + int skip, char (*source)( void *, int * ), + void *data, int depth, int *status ){ +/* +* Name: +* ReadContent + +* Purpose: +* Read and parse an XML document. + +* Type: +* Private function. + +* Synopsis: +* #include "xml.h" +* AstXmlElement *ReadContent( AstXmlDocument **doc, int wanted, +* int (*is_wanted)( AstXmlElement *, int * ), +* int skip, char (*source)( void *, int * ), +* void *data, int depth, int *status ) + +* Description: +* This function reads and parses text from an XML source. The text is +* obtained by calling the supplied "source" function, which returns +* the next character read from the external source on each invocation. +* +* See astXmlReadDocument for more details. + +* Parameters: +* doc +* Address of a location holding a pointer to an AstXmlDocument +* structure. The AstXmlDocument pointer should be supplied as NULL +* when invoking this function for the first time on a document +* source (i.e. when reading from the beginning of the document). +* In this case a new AstXmlDocument structure will be created and a +* pointer to it stored at the supplied address. This structure +* holds the context which enables subsequent invocations of this +* function to determine the point in the document structure at +* which to store any further text read from the source. It also +* holds the document prologue, root element, and epilogue. +* wanted +* Indicates if the content read from the XML source is of interest +* to the client. If a positive value is supplied, all content read +* from the source (up to the end tag which corresponds to the +* supplied "parent") is added to the "parent" element (if supplied). +* If zero is supplied, then all content read from the source is +* discarded. If a negative value is supplied, then all content up +* to the first element start tag is discarded. When the first +* element start tag is encountered, it is passed back to the client +* by invoking the supplied "is_wanted" function. If this function +* returns a non-zero value, then the contents of the new element +* is read (by calling this function recursively) and a pointer to +* the new element is returned as the function value (reading then +* stops and the function returns). If the "is_wanted" function returns +* zero, then the contents of the new element is skipped over, and +* reading continues until the next element start tag is encountered, +* when the "is_wanted" function is again invoked. +* is_wanted +* Pointer to a function which is called to decide if the client is +* interested in the element start tag which has just been read. +* It has a single argument which is a pointer to the (empty) XmlElement +* corresponding to the element start tag which has just been read. +* It returns an integer: +* -1 : the element is not itself of interest but it may contain +* an interesting element, so look through the content and +* ask the client again about any elements found inside it. +* 0 : the element definately contains nothing of interest to +* the client. kip its content and continue looking for new +* elements. +* 1 : the element is definately of interest to the client so +* read its contents and return a pointer to it. +* If NULL is supplied, a value of "+1" is assumed. +* skip +* Indicates if any uninteresting elements may proceed the first +* element of interest. If zero, then an error is reported if the +* first element read from the source is not of interest to the client. +* If non-zero, then any uninteresting elements are simply skipped +* over until an interesting element is found or the document ends. +* source +* Pointer to a function which is called to return the next +* character from the source. It has a single argument which is +* used to pass any supplied data to it. It should return zero when +* the end of the source is reached. +* data +* Pointer to a structure to pass to the source function. This +* structure may contain any data needed by the source function. +* depth +* Depth of nesting (i.e. zero if this function was invoked from +* astXmlReadDocument, and a positive value if it was invoked +* recursively from within itself). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to the first element of interest, or NULL if there are no +* interesting elements in the source. If the first element of +* interest has already been found (as indicated by "wanted" being +1) +* then NULL is returned. The returned element may be a child of a +* parent element containing namespace definitions (which may itself +* have a parent, etc). For this reason, the returned pointer should be +* freed using astXmlAnnulTree rather than astXmlAnnul. + +* Notes: +* - NULL is returned if an error has already occurred, or if this +* function should fail for any reason. +* - It is assumed that the read commences outside any tag (i.e. +* in between tags or within character data). +*/ + +/* Local Variables; */ + AstXmlElement *answer; /* Result of reading a sub-element */ + AstXmlElement *parent; /* Pointer to current parent element */ + AstXmlElement *elem; /* A new element to be read */ + AstXmlElement *result; /* The returned pointer */ + char *cc; /* Pointer to next character */ + char *msg; /* Pointer to message buffer */ + char *text1; /* Pointer to dynamic string */ + char *text2; /* Pointer to another dynamic string */ + char *text3; /* Pointer to another dynamic string */ + char *text4; /* Pointer to another dynamic string */ + char c; /* Current character read from source */ + char lc2; /* Last but one character read */ + char lc; /* Last character read */ + char quoted; /* Character which opened current quote */ + int nc1; /* No. of characters stored in text1 */ + int nc2; /* No. of characters stored in text2 */ + int nc3; /* No. of characters stored in text2 */ + int ncmsg; /* Length of "msg" */ + int newwanted; /* Is the new element wanted? */ + int state; /* Current action being performed */ + int prolog_ok; /* OK for source to start with a prolog? */ + int where; /* Where to add the item within the document */ + +/* Initialise */ + result = NULL; + elem = NULL; + +/* Check the global error status. */ + if( !astOK ) return result; + +/* If no XmlDocument was supplied, assume we are commencing to read a new + document from the begining. Create a new XmlDocument to store the + prologue, root element and epilogue, together with a pointer to the + "current" element, i.e. the element whose content is currently being + read. Also, since we have not yet asked the client if it is interested + in anything, ignore the supplied "wanted" value and use -1 to ensure + that we ask the client when the first element start tag is encountered. */ + if( !*doc ){ + prolog_ok = 1; + *doc = NewDocument( status ); + wanted = -1; + } else { + prolog_ok = 0; + } + +/* Any content read from the source (except for prologue and epilogue) + will be placed into the "parent" element. A pointer to this element is + stored in the XmlDocument structure. The parent element will always be + a descendant of the root element, or the root element itself. */ + parent = (*doc)->current; + +/* If the supplied parent has already been completed (typically because + it was read from an empty element tag), then just return without + action. */ + if( parent && parent->complete ) { + +/* If an error has occurred, or if this invocation of ReadContent was + made recursively (rather than by the client), or if we have something + to return, return. */ + if( !astOK || depth > 0 || result ) { + return result; + +/* Otherwise, returning would result in returning a null pointer to the + client even though the end of the document may not have been reached. + Revert to state 0 and search for further interesting elements. */ + } else { + if( parent != (*doc)->root ) { + (*doc)->current = (AstXmlElement *) ( (AstXmlObject *) parent )->parent; + } else { + (*doc)->current = NULL; + } + parent = (*doc)->current; + state = 0; + } + } + +/* Initialise the previous two characters read. */ + lc = 0; + lc2 = 0; + +/* Initialise pointer to dynamically allocated strings. */ + text1 = NULL; + text2 = NULL; + text3 = NULL; + msg = NULL; + +/* We are not in a quote. */ + quoted = 0; + +/* Initialise the "state" variable which indicates what we are currently + looking for. */ + state = 0; + +/* Loop round reading characters from the source. */ + while( 1 ) { + c = (*source)( data, status ); + +/* Leave the loop if an error occurred whilst reading the character. */ + if( !astOK ) break; + +/* If a parent element has been supplied, (i.e. if we are currently + reading the content of an element), or if we are not in state zero, + report an error and leave the loop if the end of the text has been + reached. If no parent was supplied, just leave the loop. */ + if( !c ) { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): End of XML input text " + "reached whilst reading the content of element %s.", status, + astXmlGetTag( parent, 1 ) ); + + } else if( state > 1 ) { + if( msg ) { + astError( AST__XMLWF, "astRead(XmlChan): End of XML input text " + "reached whilst reading the document epilogue " + "(\"%s\").", status, msg ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): End of XML input text " + "reached whilst reading the document epilogue." , status); + } + } + break; + } + +/* Save text which is not character data for use in error messages. */ + if( state < 2 ) { + if( msg ) msg = astFree( msg ); + } else { + msg = AppendChar( msg, &ncmsg, c, status ); + } + +/* State 0: Use the first character to decide what sort of content item + follows (character data or a tag of some form). */ + if( state == 0 ) { + if( c != '<' ) { + state = 1; + text1 = AppendChar( text1, &nc1, c, status ); + } else { + msg = AppendChar( msg, &ncmsg, '<', status ); + state = 2; + } + +/* State 1: We are reading character data. The character data ends at the + first occurrence of "<", at which point the character data is added to + the parent if required and we continue to state 2.*/ + } else if( state == 1 ) { + if( c != '<' ) { + text1 = AppendChar( text1, &nc1, c, status ); + } else { + msg = AppendChar( msg, &ncmsg, '<', status ); + if( text1 ){ + +/* If we have a parent element, just add it to the element. */ + if( parent ) { + if( wanted > 0 ) { + text4 = RemoveEscapes( text1, status ); + astXmlAddCharData( (AstXmlParent *) parent, 0, text4 ); + text4 = astFree( text4 ); + + +/* If we are not allowed to skip over non-blank content, report an + error if the text is not blank. */ + } else if( !skip ) { + cc = text1 - 1; + while( *(++cc) ) { + if( !isspace( *cc ) ) { + if( parent ) { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data \"%s\" within element %s.", status, + text1, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data: \"%s\".", status, text1 ); + } + break; + } + } + } + +/* Otherwise, add it to the document prologue or epilogue. */ + } else { + if( (*doc)->root ) { + where = 3; + } else if( (*doc)->prolog && (*doc)->prolog->dtdec ){ + where = 2; + } else { + where = 1; + } + + text4 = RemoveEscapes( text1, status ); + astXmlAddCharData( (AstXmlParent *) *doc, where, text4 ); + text4 = astFree( text4 ); + } + + text1 = astFree( text1 ); + } + state = 2; + } + +/* State 2: We are using the character following a "<" to determine what + type of tag is commencing. */ + } else if( state == 2 ) { + +/* If the character is a ">", report an error. */ + if( c == '>' ) { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"<>\" " + "encountered within element %s.", status, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"<>\" " + "encountered." , status); + } + break; + +/* If the character is a "?", this must be a PI tag. */ + } else if( c == '?' ) { + state = 3; + +/* If the character is a "!", it must be a comment or a CDATA section + or a DTD. */ + } else if( c == '!' ) { + state = 4; + +/* If the character is a "/", it must be an element end tag. */ + } else if( c == '/' ) { + state = 5; + +/* Otherwise, this must be an element start tag. Append the character + to "text1". */ + } else { + state = 6; + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 3: We are reading the initial text following the opening "<?" string + of a PI tag. The characters between the initial "<?" string and the first + space or closing "?>" string is the target text. */ + } else if( state == 3 ) { + if( c == '>' && lc == '?' ) { + if( text1 ) text1[ --nc1 ] = 0; + state = 100; + } else if( isspace( c ) ) { + state = 7; + } else { + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 4: We are using the characters following the opening "<!" text to + determine if the tag is a comment, DTD or CDATA section. */ + } else if( state == 4 ) { + if( c == '-' ) { + state = 8; + } else if( c == 'D' ){ + state = 16; + text1 = astAppendString( text1, &nc1, "<!D" ); + } else if( c == '[' ){ + state = 9; + text1 = astAppendString( text1, &nc1, "<![" ); + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"<!%c...\" encountered within " + "element %s.", status, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"<!%c...\" encountered.", status, c ); + } + break; + } + +/* State 5: We are looking for the end of an element end tag. */ + } else if( state == 5 ) { + if( c == '>' ) { + state = 101; + } else { + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 6: We are looking for the (prefix:)name combination at the start of + an element start tag. */ + } else if( state == 6 ) { + if( c == '>' ) { + state = ( lc != '/' ) ? 102 : 103; + } else if( isspace( c ) ) { + state = 104; + } else if( c != '/' ){ + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 7: We are reading the remaining text in a PI tag following the target + text. */ + } else if( state == 7 ) { + if( c == '>' && lc == '?' ) { + if( text2 ) text2[ --nc2 ] = 0; + state = 100; + } else if( text2 || !isspace( c ) ) { + text2 = AppendChar( text2, &nc2, c, status ); + } + +/* State 8: We are looking for the start of the text within a comment tag. */ + } else if( state == 8 ) { + if( c == '-' ) { + state = 10; + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"<!-%c...\" encountered within " + "element %s.", status, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"<!-%c...\" encountered.", status, c ); + } + break; + } + +/* State 9: We are looking for the start of the text within a CDATA tag. */ + } else if( state == 9 ) { + if( c == '[' ) { + if( !strcmp( text1, "<![CDATA" ) ) { + state = 11; + text1 = astFree( text1 ); + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered within " + "element %s.", status, text1, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered.", status, text1, c ); + } + text1 = astFree( text1 ); + break; + } + + } else if( nc1 < 10 ) { + text1 = AppendChar( text1, &nc1, c, status ); + + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered within " + "element %s.", status, text1, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered.", status, text1, c ); + } + text1 = astFree( text1 ); + break; + } + +/* State 10: We are reading the remaining text in a comment tag. When the end + ">" is reached, check the previous 2 characters are "--" and then terminate + the text1 string in order to remove these two characters from the comment + text. */ + } else if( state == 10 ) { + if( c == '>' && lc == '-' && lc2 == '-' ) { + text1[ nc1 - 2 ] = 0; + state = 105; + } else { + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 11: We are reading the remaining text in a CDATA tag. */ + } else if( state == 11 ) { + if( c == '>' && lc == ']' && lc2 == ']' ) { + text1[ nc1 - 2 ] = 0; + state = 106; + } else { + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 12: We are looking for an equals sign marking the end of an + attribute name within an element start tag. */ + } else if( state == 12 ) { + if( c == '=' ) { + state = 13; + + } else if( c == '>' ) { + if( text1 ) { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + " \"%s...\" encountered within element %s.", status, msg, + astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s...\" " + "encountered.", status, msg ); + } + break; + } else { + if( lc == '/' ) { + state = 108; + } else { + state = 200; + } + } + + } else if( text1 || !isspace( c ) ) { + if( c != '/' ) text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 13: We are looking for a '"' or ''' marking the start of an attribute + value within an element start tag. */ + } else if( state == 13 ) { + if( c == '"' ) { + state = 14; + + } else if( c == '\'' ) { + state = 15; + + } else if( c == '>' ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute " + "\"%s\" in XML tag \"%s...\".", status, text1, msg ); + break; + } + +/* State 14: We are looking for a '"' marking the end of an attribute value + within an element start tag. */ + } else if( state == 14 ) { + if( c == '"' ) { + state = 107; + + } else if( c == '>' ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute " + "\"%s\" in XML tag \"%s...\".", status, text1, msg ); + break; + + } else { + text2 = AppendChar( text2, &nc2, c, status ); + } + +/* State 15: We are looking for a ''' marking the end of an attribute value + within an element start tag. */ + } else if( state == 15 ) { + if( c == '\'' ) { + state = 107; + + } else if( c == '>' ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute " + "\"%s\" in XML tag \"%s...\".", status, text1, msg ); + break; + + } else { + text2 = AppendChar( text2, &nc2, c, status ); + } + +/* State 16: We are looking for the end of a DOCTYPE string. */ + } else if( state == 16 ) { + if( isspace( c ) ) { + if( !strcmp( text1, "<!DOCTYPE" ) ) { + state = 17; + text1 = astFree( text1 ); + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered within " + "element %s.", status, text1, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered.", status, text1, c ); + } + text1 = astFree( text1 ); + break; + } + + } else if( nc1 < 15 ) { + text1 = AppendChar( text1, &nc1, c, status ); + + } else { + if( parent ) { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered within " + "element %s.", status, text1, c, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag " + "starting with \"%s%c...\" encountered.", status, text1, c ); + } + text1 = astFree( text1 ); + break; + } + +/* State 17: We are looking for the start of a DOCTYPE name string. */ + } else if( state == 17 ) { + if( !isspace( c ) ) { + text1 = AppendChar( text1, &nc1, c, status ); + state = 18; + } + +/* State 18: We are looking for the end of a DOCTYPE name string. */ + } else if( state == 18 ) { + if( isspace( c ) ) { + state = 19; + } else if( c == '>' ) { + state = 109; + } else { + text1 = AppendChar( text1, &nc1, c, status ); + } + +/* State 19: We are looking for the start of a string following a DOCTYPE + name string. */ + } else if( state == 19 ) { + if( !isspace( c ) ) { + if( c == '[' ) { + state = 20; + } else if( c == '>' ) { + state = 109; + } else { + state = 21; + text2 = AppendChar( text2, &nc2, c, status ); + } + } + +/* State 20: We are looking for the "]" marking the end of the internal + markup of a DOCTYPE element. Avoid the contents of quoted strings (such + as #FIXED attribute values). */ + } else if( state == 20 ) { + text3 = AppendChar( text3, &nc3, c, status ); + if( c == '\'' ) { + if( quoted == '\'' ) { + quoted = 0; + } else if( !quoted ) { + quoted = '\''; + } + + } else if( c == '"' ) { + if( quoted == '"' ) { + quoted = 0; + } else if( !quoted ) { + quoted = '"'; + } + + } else if( !quoted && c == ']' ) { + text3[ --nc3 ] = 0; + state = 22; + } + +/* State 21: We are looking for the start of a DOCTYPE internal section. */ + } else if( state == 21 ) { + if( c == '[' ) { + state = 20; + } else if( c == '>' ) { + state = 109; + } else { + text2 = AppendChar( text2, &nc2, c, status ); + } + +/* State 22: We are looking for the ">" at the end of a DOCTYPE. */ + } else if( state == 22 ) { + if( !isspace( c ) ) { + if( c == '>' ) { + state = 109; + } else { + astError( AST__XMLWF, "astRead(XmlChan): Extra text found " + "at end of XML DOCTYPE tag \"%s\".", status, msg ); + } + } + + } else { + astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered " + "(AST internal programming error).", status, state ); + } + +/* The following states perform actions consequent on the decisons made + above, but which must be performed before reading the next character. */ + +/* In most cases there will be no actions to perform. Therefore check for + this first (to avoid the time spent doing all the following usually + irrelevant checks). */ + if( state < 23 ) { + +/* State 100: We have just reached the end of a PI tag. Create a new XmlPI and + store it in the parent (if required). */ + } else if( state == 100 ) { + if( text1 ){ + +/* First deal with XML declaration PI's. These must be the first item in + the source. */ + if( !strcmp( text1, "xml" ) ) { + if( (*doc)->root || (*doc)->prolog || (*doc)->nepi > 0 ) { + astError( AST__XMLWF, "astRead(XmlChan): An XML " + "declaration \"%s\" was encountered within the " + "body of the document.", status, msg ); + } else { + astXmlSetXmlDec( *doc, text2 ); + } + +/* Now deal with other PI's. */ + } else { + +/* If we have a parent element, just add it to the element. */ + if( parent ) { + if( wanted > 0 ) { + astXmlAddPI( (AstXmlParent *) parent, 0, text1, text2 ); + } else if( !skip ) { + if( parent ) { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data \"%s\" within element %s.", status, + msg, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data: \"%s\".", status, msg ); + } + break; + } + +/* Otherwise, add it to the document prologue or epilogue. */ + } else { + if( (*doc)->root ) { + where = 3; + } else if( (*doc)->prolog->dtdec ){ + where = 2; + } else { + where = 1; + } + astXmlAddPI( (AstXmlParent *) *doc, where, text1, text2 ); + + } + } + text1 = astFree( text1 ); + if( text2 ) text2 = astFree( text2 ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + state = 0; + +/* State 101: We have just reached the end of an element end tag. Check that + the (prefix:)name is legal, and matches that of the current parent, + re-instate the parent's parent as the current element in the document, + and leave the loop if appropriate. */ + } else if( state == 101 ) { + if( text1 ){ + CheckPrefName( text1, "element", "astRead(XmlChan)", status ); + if( parent ) { + if( MatchName( parent, text1, status ) ) { + parent->complete = 1; + if( parent != (*doc)->root ) { + (*doc)->current = (AstXmlElement *) ( (AstXmlObject *) parent )->parent; + } else { + (*doc)->current = NULL; + } + } else { + astError( AST__XMLWF, "astRead(XmlChan): Start tag \"%s\" " + "closed by end tag \"%s\".", status, astXmlGetTag( parent, 1 ), + msg ); + } + + } else { + (*doc)->current = NULL; + astError( AST__XMLWF, "astRead(XmlChan): Unmatched end tag " + "\"%s\" encountered.", status, msg ); + } + + text1 = astFree( text1 ); + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + } + +/* If an error has occurred, or if this invocation of ReadContent was + made recursively (rather tnan by the client), or if we have something + to return, break out of the loop. */ + if( !astOK || depth > 0 || result ) { + break; + +/* Otherwise, breaking would result in returning a null pointer to the + client even though the end of the document may not have been reached. + Revert to state 0 and search for further intersting elements. */ + } else { + parent = (*doc)->current; + state = 0; + } + +/* State 102: We have just got the (prefix:)name for an element start tag, and + the start tag contains no attributes, etc. Create a new XmlElement, adding + it to the supplied parent, and then proceed to state 200 to read the + content of the element. */ + } else if( state == 102 ) { + if( text1 ){ + elem = astXmlAddElement( parent, text1, NULL ); + text1 = astFree( text1 ); + state = 200; + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + +/* State 103: We have just got the (prefix:)name for an empty element tag, and + the tag does not contain further attributes, etc. Create a new XmlElement + and store it in the container (if any). Indicate that there is no + content to read, and then go on to state 200. */ + } else if( state == 103 ) { + if( text1 ){ + elem = astXmlAddElement( parent, text1, NULL ); + elem->complete = 1; + text1 = astFree( text1 ); + state = 200; + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + +/* State 104: We have just got the (prefix:)name for an element start tag, but + the start tag may contain further attributes, etc. Create a new XmlElement + and store it in the container (if any). Then go to state 12 in which we + look for further attributes, etc. */ + } else if( state == 104 ) { + if( text1 ){ + elem = astXmlAddElement( parent, text1, NULL ); + text1 = astFree( text1 ); + state = 12; + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + +/* State 105: We have just reached the end of a comment tag. Create a new + XmlComment and store it in the parent. */ + } else if( state == 105 ) { + if( text1 ){ + +/* If we have a parent element, just add it to the element. */ + if( parent ) { + if( wanted > 0 ) { + astXmlAddComment( (AstXmlParent *) parent, 0, text1 ); + } else if( !skip ) { + if( parent ) { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data \"%s\" within element %s.", status, + msg, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data: \"%s\".", status, msg ); + } + break; + } + +/* Otherwise, add it to the document prologue or epilogue. */ + } else { + if( (*doc)->root ) { + where = 3; + } else if( (*doc)->prolog->dtdec ){ + where = 2; + } else { + where = 1; + } + astXmlAddComment( (AstXmlParent *) *doc, where, text1 ); + } + + text1 = astFree( text1 ); + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + state = 0; + +/* State 106: We have just reached the end of a CDATA tag. Create a new + XmlCDATASection and store it in the container (if any). */ + } else if( state == 106 ) { + if( text1 ){ + if( parent && wanted > 0 ) { + astXmlAddCDataSection( parent, text1 ); + } else if( !skip ) { + if( parent ) { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data \"%s\" within element %s.", status, + msg, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data: \"%s\".", status, msg ); + } + break; + } + text1 = astFree( text1 ); + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + state = 0; + +/* State 107: We have just reached the end of an attribute or namespace + setting. Create a new object and store it in the element created + earlier. */ + } else if( state == 107 ) { + if( text1 ){ + if( !elem ) { + astError( AST__INTER, "ReadContent(xml): Container lost at state " + "107 (AST internal programming error).", status ); + break; + } + + if( !strcmp( text1, "xmlns" ) ) { + astXmlAddURI( elem, NULL, text2 ); + + } else if( !strncmp( text1, "xmlns:", 6 ) ) { + astXmlAddURI( elem, text1+6, text2 ); + + } else { + text4 = RemoveEscapes( text2, status ); + astXmlAddAttr( elem, text1, text4, NULL ); + text4 = astFree( text4 ); + } + + text1 = astFree( text1 ); + text2 = astFree( text2 ); + + } else { + astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" " + "encountered.", status, msg ); + break; + } + state = 12; + +/* State 108: We have just reached the end of an empty element tag to which + we have been adding attributes, etc. */ + } else if( state == 108 ) { + if( elem ) { + elem->complete = 1; + state = 200; + } else { + astError( AST__INTER, "Parse(xml): No container in state 108 " + "(AST internal programming error).", status ); + break; + } + +/* State 109: We have just reached the end of a DOCTYPE tag. */ + } else if( state == 109 ) { + + if( (*doc)->root ){ + astError( AST__XMLWF, "astRead(XmlChan): An DOCTYPE tag " + "\"%s\" was encountered within the body of the " + "document.", status, msg ); + break; + + } else if( (*doc)->prolog->dtdec ){ + astError( AST__XMLWF, "astRead(XmlChan): Multiple DOCTYPE tags " + "encountered." , status); + break; + + } else { + astXmlSetDTDec( *doc, text1, text2, text3 ); + text1 = astFree( text1 ); + text2 = astFree( text2 ); + text3 = astFree( text3 ); + state = 0; + } + + } else if( state != 200 ) { + astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered " + "(AST internal programming error).", status, state ); + } + + + +/* State 200: We now have now read a complete element start tag and have + a corresponding XmlElement ("elem"), with all attributes and namespaces, + etc (but no content). Call the "is_wanted" function to see if the client + is interested in the element. */ + if( state == 200 ) { + +/* If this element is found at the root level of the document, store a + pointer to it as the root element. Report an error if there is already + a root element. */ + if( !parent ) { + if( (*doc)->root ){ + if( astOK ) { + astError( AST__XMLWF, "astRead(XmlChan): Multiple root " + "elements encountered." , status); + elem = astXmlDelete( elem ); + } + break; + } else { + (*doc)->root = elem; + ((AstXmlObject *) elem )->parent = (AstXmlParent *) (*doc); + } + } + +/* If we do not already know, ask the caller if it is interested in this new + element. If no "is_wanted" function was supplied, assume all elements + are interesting. */ + if( wanted == -1 ) { + newwanted = is_wanted ? (*is_wanted)( elem, status ) : 1; + } else { + newwanted = wanted; + } + +/* If it is not interested, report an error if skip is zero. */ + if( newwanted != 1 && !skip ) { + if( parent ) { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data \"%s\" within element %s.", status, + msg, astXmlGetTag( parent, 1 ) ); + } else { + astError( AST__BADIN, "astRead(XmlChan): Cannot interpret " + "the input data: \"%s\".", status, msg ); + } + break; + } + +/* Make the new element the "current" element in the document. */ + (*doc)->current = elem; + +/* Read the contents of the new element from the source. If the client is + interested in the element, the read contents will be added to the + element, otherwise they will be discarded after being read. */ + answer = ReadContent( doc, newwanted, is_wanted, skip, source, + data, depth + 1, status ); + +/* If the first interesting element was found inside "elem", then + return it. If "elem" is not interesting and did not contain anything + of interest, delete it and return the initialised NULL pointer. */ + if( newwanted < 0 ) { + if( answer ) { + result = answer; + } else { + elem = astXmlDelete( elem ); + } + +/* If the elem is of no interest, delete it and return the initialised + NULL pointer. */ + } else if( newwanted == 0 ) { + elem = astXmlDelete( elem ); + +/* Otherwise, "elem" itself is definitely of interest. If "elem" is + the first item of interest, return it. */ + } else if( wanted < 0 ) { + result = elem; + } + +/* If we have an answer to return, leave the loop, otherwise re-instate the + original current element in the document and continue to read any text + following the element. */ + if( result ) { + break; + } else { + (*doc)->current = parent; + state = 0; + } + + } if( state > 22 ) { + astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered " + "(AST internal programming error).", status, state ); + } + +/* Remember the previous two character */ + lc2 = lc; + lc = c; + } + +/* Free any dynamic strings */ + text1 = astFree( text1 ); + text2 = astFree( text2 ); + text3 = astFree( text3 ); + if( msg ) msg = astFree( msg ); + +/* Delete the returned object if an error occurred. */ + if( !astOK ) result = astXmlDelete( result ); + +/* Return the result. */ + return result; +} + + + |