summaryrefslogtreecommitdiffstats
path: root/ast/xml.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-17 15:22:52 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-17 15:22:52 (GMT)
commit7dd9b970cec6832b8f6118dc2dd91a08d2836648 (patch)
tree4b3c86596ab87f35a3c6213397da07afe1e24d3e /ast/xml.c
parentd7bf7c61e8507e3cf51f195392c0f41f27ae18d8 (diff)
parent7fde2daeed593684120d75de07598154f3ddaf2c (diff)
downloadblt-7dd9b970cec6832b8f6118dc2dd91a08d2836648.zip
blt-7dd9b970cec6832b8f6118dc2dd91a08d2836648.tar.gz
blt-7dd9b970cec6832b8f6118dc2dd91a08d2836648.tar.bz2
Merge commit '7fde2daeed593684120d75de07598154f3ddaf2c' as 'ast'
Diffstat (limited to 'ast/xml.c')
-rw-r--r--ast/xml.c7119
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, "&lt;" );
+ d += 4;
+
+ } else if( *c == '>' ) {
+ strcpy( d, "&gt;" );
+ d += 4;
+
+ } else if( *c == '"' ) {
+ strcpy( d, "&quot;" );
+ d += 6;
+
+ } else if( *c == '\'' ) {
+ strcpy( d, "&apos;" );
+ d += 6;
+
+ } else if( *c == '&' ) {
+ strcpy( d, "&amp;" );
+ 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, "&amp;", 5 ) ) {
+ rc = '&';
+ nc= 4;
+
+ } else if( !strncmp( c, "&lt;", 4 ) ) {
+ rc = '<';
+ nc= 3;
+
+ } else if( !strncmp( c, "&gt;", 4 ) ) {
+ rc = '>';
+ nc= 3;
+
+ } else if( !strncmp( c, "&apos;", 6 ) ) {
+ rc = '\'';
+ nc= 5;
+
+ } else if( !strncmp( c, "&quot;", 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;
+}
+
+
+