1 /*
2 *  Name:
3 *     xml.c
4 
5 *  Purpose:
6 *     Implement XML functions for AST.
7 
8 *  Description:
9 *     This file implements the Xml module which provides generic XML
10 *     reading and writing functions for the XmlChan class.
11 
12 *  Copyright:
13 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
14 *     Research Councils
15 
16 *  Licence:
17 *     This program is free software: you can redistribute it and/or
18 *     modify it under the terms of the GNU Lesser General Public
19 *     License as published by the Free Software Foundation, either
20 *     version 3 of the License, or (at your option) any later
21 *     version.
22 *
23 *     This program is distributed in the hope that it will be useful,
24 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
25 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26 *     GNU Lesser General Public License for more details.
27 *
28 *     You should have received a copy of the GNU Lesser General
29 *     License along with this program.  If not, see
30 *     <http://www.gnu.org/licenses/>.
31 
32 *  Authors:
33 *     DSB: David S. Berry (Starlink)
34 
35 *  History:
36 *     22-OCT-2003 (DSB):
37 *        Original version.
38 *     12-JAN-2004 (DSB):
39 *        Major revisions.
40 *     10-FEB-2004 (DSB):
41 *        - Added debug conditional code to keep track of memory leaks.
42 *        - Other minor bug fixes.
43 *     6-FEB-2004 (DSB):
44 *        DefaultURI and astXmlAddURI modified to allow a blank URI to be
45 *        used to ignore a default namespace URI provided by an enclosing
46 *        element.
47 *     29-NOV-2004 (DSB):
48 *        Added astXmlGetType method.
49 *     27-JAN-2005 (DSB):
50 *        - Move astXmlTrace and associated code into conditional
51 *        compilation blokc (included if DEBUG macro is defined). This
52 *        speeds up the create and destruction of XmlObjects in non-DEBUG code.
53 *        - Renamed the private Delete function as astXmlDelete and gave
54 *        it protected access.
55 *        - Modify astXmlDelete so that it can succesfully annul objects
56 *        which have no parent.
57 *        - Include extra info in some error messages.
58 *     1-MAR-2006 (DSB):
59 *        Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
60 *     10-DEC-2008 (DSB):
61 *        Allow a prefix to be included with the attribute name in
62 *        astXmlGetAttributeValue.
63 */
64 
65 
66 /* Module Constants. */
67 /* ----------------- */
68 /* Set the name of the module we are implementing. This indicates to
69    the header files that define class interfaces that they should make
70    "protected" symbols available. NB, this module is not a proper AST
71    class, but it defines this macro sanyway in order to get the protected
72    symbols defined in memory.h */
73 #define astCLASS Xml
74 
75 #define IND_INC 3
76 
77 
78 /* Include files. */
79 /* ============== */
80 /* Interface definitions. */
81 /* ---------------------- */
82 #include "memory.h"            /* Interface to the memory management module */
83 #include "error.h"             /* Interface to the error module */
84 #include "xml.h"               /* Interface to this module */
85 #include "globals.h"           /* Thread-safe global data access */
86 
87 /* Error code definitions. */
88 /* ----------------------- */
89 #include "ast_err.h"           /* AST error codes */
90 
91 /* C header files. */
92 /* --------------- */
93 #include <stdarg.h>
94 #include <stdio.h>
95 #include <string.h>
96 #include <ctype.h>
97 
98 
99 /*
100 *  Name:
101 *     MAKE_CHECK
102 
103 *  Type:
104 *     Private macro.
105 
106 *  Purpose:
107 *     Implement the astXmlCheck<type>_ function for XML structures.
108 
109 *  Synopsis:
110 *     #include "xml.h"
111 *     MAKE_CHECK(type,id)
112 
113 *  Class Membership:
114 *     Defined by the xml module.
115 
116 *  Description:
117 *     This macro expands to an implementation of the protected
118 *     astXmlCheck<type>_ function (q.v.) which validates membership of
119 *     a specified XML data type.
120 
121 *  Parameters:
122 *     type
123 *        The type whose membership is to be validated (e.g. "Element" not
124 *        "XmlElement").
125 *     id
126 *        The constant (e.g. "AST__XMLELEM") defining the data type.
127 
128 *  Notes:
129 *     -  To avoid problems with some compilers, you should not leave any white
130 *     space around the macro arguments.
131 */
132 
133 /* Define the macro. */
134 #define MAKE_CHECK(type,id) \
135 \
136 /* Declare the function */ \
137 AstXml##type *astXmlCheck##type##_( void *this, int nullok, int *status ) { \
138 \
139 /* Local Variables: */\
140    AstXml##type *result;    /* The returned pointer */\
141 \
142 /* Check the global error status. If an error has already occurred just\
143    return the supplied pointer. This is so that functions such as\
144    astXmlAnnul which do not check the inherited status receive the\
145    supplied pointer. */\
146    if( !astOK ) return this;\
147 \
148 /* Initialise */\
149    result = NULL;\
150 \
151 /* If the pointer is NULL issue an error if nullok is zero. */\
152    if( !this ) {\
153       if( !nullok ) astError( AST__PTRIN, "astXmlCheck"#type": Invalid "\
154                               "NULL pointer supplied." , status);\
155 \
156 /* Otherwise get the "type" component which holds a magic value for each\
157    different class of structure. Compare this value against all valid \
158    classes of structure. If no match is found, the pointer does not \
159    identify an suitable structure, and so report an error and return \
160    NULL. */\
161    } else {\
162       if( !astXmlCheckType( ( AstXmlObject * ) this, id ) ) {\
163          astError( AST__PTRIN, "astXmlCheck"#type": Invalid pointer "\
164                    "supplied; pointer to AstXml"#type" required." , status);\
165       } else {\
166          result = (AstXml##type *) this;\
167       }\
168    }\
169 \
170 /* Return the result. */\
171    return result;\
172 }
173 
174 
175 /* Module variables. */
176 /* ================= */
177 
178 /* Define macros for accessing all items of thread-safe global data
179    used by this module. */
180 #ifdef THREAD_SAFE
181 
182 #define next_id astGLOBAL(Xml,Next_ID)
183 #define gettag_buff astGLOBAL(Xml,GetTag_Buff)
184 #define GLOBAL_inits globals->Next_ID = 0;
185 astMAKE_INITGLOBALS(Xml)
186 
187 /* Set up mutexes */
188 static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
189 #define LOCK_MUTEX1 pthread_mutex_lock( &mutex1 );
190 #define UNLOCK_MUTEX1 pthread_mutex_unlock( &mutex1 );
191 
192 /* If thread safety is not needed, declare globals at static variables. */
193 #else
194 
195 static int next_id = 0;
196 static char gettag_buff[ AST__XML_GETTAG_BUFF_LEN + 1 ];
197 
198 #define LOCK_MUTEX1
199 #define UNLOCK_MUTEX1
200 
201 #ifdef DEBUG   /* Not available in thread-safe compilations */
202 static int nobj = 0;
203 static AstXmlObject **existing_objects = NULL;
204 #endif
205 
206 #endif
207 
208 
209 /* Function prototypes. */
210 /* ==================== */
211 
212 /* Private member functions. */
213 /* ------------------------- */
214 static AstXmlAttribute *FindAttribute( AstXmlElement *, const char *, int * );
215 static AstXmlAttribute *NewAttribute( const char *, const char *, const char *, int * );
216 static AstXmlDocument *NewDocument( int * );
217 static AstXmlPrologue *NewPrologue( AstXmlDocument *, int * );
218 static AstXmlNamespace *NewNamespace( const char *, const char *, int * );
219 static char *AppendChar( char *, int *, char, int * );
220 static char *AppendLine( char *, int *, const char *, int, int * );
221 static char *RemoveEscapes( const char *, int * );
222 static char *CleanText( const char *, int * );
223 static const char *AddEscapes( const char *, int * );
224 static const char *DefaultURI( AstXmlElement *, int * );
225 static const char *Format( AstXmlObject *, int, int * );
226 static char *FormatTag( AstXmlObject *, int, int * );
227 static const char *ResolvePrefix( const char *, AstXmlElement *, int * );
228 static int CheckType( long int, long int, int * );
229 static int MatchName( AstXmlElement *, const char *, int * );
230 static int Ustrcmp( const char *, const char *, int * );
231 static void AddContent( AstXmlParent *, int, AstXmlContentItem *, int * );
232 static void CheckName( const char *, const char *, const char *, int, int * );
233 static void CheckPrefName( char *, const char *, const char *, int * );
234 static void CleanXml( AstXmlObject *, long int, int * );
235 static void InitXmlAttribute( AstXmlAttribute *, int, const char *, const char *, const char *, int * );
236 static void InitXmlCDataSection( AstXmlCDataSection *, int, const char *, int * );
237 static void InitXmlWhite( AstXmlWhite *, int, const char *, int * );
238 static void InitXmlBlack( AstXmlBlack *, int, const char *, int * );
239 static void InitXmlComment( AstXmlComment *, int, const char *, int * );
240 static void InitXmlDocument( AstXmlDocument *, int, int * );
241 static void InitXmlPrologue( AstXmlPrologue *, int, int * );
242 static void InitXmlDeclPI( AstXmlDeclPI *, int, const char *, int * );
243 static void InitXmlDTDec( AstXmlDTDec *, int, const char *, const char *, const char *, int * );
244 static void InitXmlElement( AstXmlElement *, int, const char *, const char *, int * );
245 static void InitXmlNamespace( AstXmlNamespace *, int, const char *, const char *, int * );
246 static void InitXmlObject( AstXmlObject *, long int, int * );
247 static void InitXmlPI( AstXmlPI *, int, const char *, const char *, int * );
248 static AstXmlElement *ReadContent( AstXmlDocument **, int, int (*)( AstXmlElement *, int * ), int, char (*)( void *, int * ), void *, int, int * );
249 
250 #ifdef DEBUG
251 static void AddObjectToList( AstXmlObject * );
252 static void RemoveObjectFromList( AstXmlObject * );
253 #endif
254 
255 /* Function implementations. */
256 /* ========================= */
257 
258 /* Create the astXmlCheck... functiosn which check a pointer identifies
259    an XML structure of a given type. */
260 
MAKE_CHECK(Document,AST__XMLDOC)261 MAKE_CHECK(Document,AST__XMLDOC)
262 MAKE_CHECK(Object,AST__XMLOBJECT)
263 MAKE_CHECK(Element,AST__XMLELEM)
264 MAKE_CHECK(Attribute,AST__XMLATTR)
265 MAKE_CHECK(CDataSection,AST__XMLCDATA)
266 MAKE_CHECK(Comment,AST__XMLCOM)
267 MAKE_CHECK(PI,AST__XMLPI)
268 MAKE_CHECK(Namespace,AST__XMLNAME)
269 MAKE_CHECK(Prologue,AST__XMLPRO)
270 MAKE_CHECK(DeclPI,AST__XMLDEC)
271 MAKE_CHECK(DTDec,AST__XMLDTD)
272 MAKE_CHECK(White,AST__XMLWHITE)
273 MAKE_CHECK(Black,AST__XMLBLACK)
274 MAKE_CHECK(CharData,AST__XMLCHAR)
275 MAKE_CHECK(ContentItem,AST__XMLCONT)
276 MAKE_CHECK(MiscItem,AST__XMLMISC)
277 MAKE_CHECK(Parent,AST__XMLPAR)
278 
279 
280 static void AddContent( AstXmlParent *this, int where, AstXmlContentItem *item, int *status ){
281 /*
282 *  Name:
283 *     AddContent
284 
285 *  Purpose:
286 *     Add a content item to an XmlElement.
287 
288 *  Type:
289 *     Private function.
290 
291 *  Synopsis:
292 *     #include "xml.h"
293 *     void AddContent( AstXmlParent *this, int where, AstXmlContentItem *item, int *status )
294 
295 *  Description:
296 *     This function adds a supplied item to a specified XmlElement or
297 *     XmlDocument. An error is reported if the item is not appropriate.
298 
299 *  Parameters:
300 *     this
301 *        The pointer to the element or document to be modified.
302 *     where
303 *        Ignored if "this" is an XmlElement pointer. Otherwise, "where"
304 *        indicates where the item should be added to the document:
305 *          1 - In the prologue, after the XML declaration but before the DTD.
306 *          2 - In the prologue, after the DTD but before the root element.
307 *          3 - In the epilogue, after the root element.
308 *     item
309 *        Pointer to the content item to be added to the element. If
310 *        "this" is an XmlElement, this can be a pointer to any of the
311 *        following types: AstXmlElement, AstXmlWhite, AstXmlBlack,
312 *        AstXmlCDataSection, AstXmlComment, AstXmlPI. If "this" is a
313 *        document, the list is restricted to: AstXmlWhite, AstXmlComment,
314 *        AstXmlPI.
315 *     status
316 *        Pointer to the inherited status variable.
317 */
318 
319 /* Local Variables: */
320    AstXmlDocument *doc;   /* Document pointer */
321    AstXmlElement *elem;   /* Element pointer */
322    AstXmlPrologue *pro;   /* Prologue pointer */
323    int nitem;             /* Number of items in the parent */
324 
325 /* Check the global error status and the supplied pointers. */
326    if( !astOK || !this || !item ) return;
327 
328 /* Split for the two forms of parent. */
329    if( astXmlCheckType( this, AST__XMLELEM ) ) {
330       elem = (AstXmlElement *) this;
331 
332 /* Save the number of content items currently stored in the element. */
333       nitem = ( elem->items ) ? elem->nitem : 0;
334 
335 /* Attempt to extend the array to hold an extra item. */
336       elem->items = astGrow( elem->items, nitem + 1,
337                              sizeof( AstXmlContentItem * ) );
338 
339 /* Check the memory was allocated succesfully. */
340       if( astOK ) {
341 
342 /* Store the supplied pointer in the array of content items. */
343          elem->items[ nitem ] = item;
344 
345 /* Increment the number of content items in this element */
346          elem->nitem = nitem + 1;
347 
348 /* Indicate that the item is owned by the element. */
349          ( (AstXmlObject *) item )->parent = this;
350       }
351 
352 /* Now deal with cases where we are adding an item to the prologue or
353    epilogue of the document. */
354    } else {
355       if( !astXmlCheckType( item, AST__XMLMISC ) ){
356          astError( AST__INTER, "AddContent(xml): Inappropriate attempt to "
357                    "add an item of type %ld to an XML document (internal "
358                    "AST programming error).", status, ( (AstXmlObject *) item)->type );
359 
360       } else if( !astXmlCheckType( this, AST__XMLDOC ) ){
361          astError( AST__INTER, "AddContent(xml): Inappropriate attempt to "
362                    "add an item of type %ld to an XML object of type %ld "
363                    "(internal AST programming error).", status,
364                    ( (AstXmlObject *) item)->type,
365                    ( (AstXmlObject *) this)->type );
366 
367       } else {
368          doc = (AstXmlDocument *) this;
369 
370 /* Create a prologue if necessary. */
371          if( where < 3 && !doc->prolog ) doc->prolog = NewPrologue( doc, status );
372          pro = doc->prolog;
373 
374          if( where < 2 ) {
375             nitem = ( pro->misc1 ) ? pro->nmisc1 : 0;
376             pro->misc1 = astGrow( pro->misc1, nitem + 1, sizeof( AstXmlMiscItem * ) );
377             if( astOK ) {
378                pro->misc1[ nitem ] = item;
379                pro->nmisc1 = nitem + 1;
380                ( (AstXmlObject *) item )->parent = (AstXmlParent *) pro;
381             }
382 
383          } else if( where == 2 ) {
384             nitem = ( pro->misc2 ) ? pro->nmisc2 : 0;
385             pro->misc2 = astGrow( pro->misc2, nitem + 1, sizeof( AstXmlMiscItem * ) );
386             if( astOK ) {
387                pro->misc2[ nitem ] = item;
388                pro->nmisc2 = nitem + 1;
389                ( (AstXmlObject *) item )->parent = (AstXmlParent *) pro;
390             }
391 
392          } else {
393             nitem = ( doc->epilog ) ? doc->nepi : 0;
394             doc->epilog = astGrow( doc->epilog, nitem + 1, sizeof( AstXmlMiscItem * ) );
395             if( astOK ) {
396                doc->epilog[ nitem ] = item;
397                doc->nepi = nitem + 1;
398                ( (AstXmlObject *) item )->parent = this;
399             }
400          }
401       }
402    }
403 }
404 
AddEscapes(const char * text,int * status)405 static const char *AddEscapes( const char *text, int *status ){
406 /*
407 *  Name:
408 *     AddEscapes
409 
410 *  Purpose:
411 *     Replaces characters by corresponding entity references.
412 
413 *  Type:
414 *     Private function.
415 
416 *  Synopsis:
417 *     #include "xml.h"
418 *     const char *AddEscapes( const char *text, int *status )
419 
420 *  Description:
421 *     This function produces a dynamic copy of the supplied text in which
422 *     occurrences of "&", "<", ">", and "\"" are replaced by the corresponding
423 *     XML entity reference.
424 *
425 *     The "&" character is only replaced by an entity reference if it is
426 *     followed by a non-name character (i.e. anything except a letter
427 *     underscore or colon). If it is followed by a name character, it is
428 *     assumed to mark the start of an entity reference.
429 
430 *  Parameters:
431 *     text
432 *        A pointer to a text string.
433 *     status
434 *        Pointer to the inherited status variable.
435 
436 *  Returned Value:
437 *     A pointer to a dynamically allocated string containing the required
438 *     copy.
439 
440 *  Notes:
441 *     - NULL is returned if this function is called with the global error
442 *     status set, or if it should fail for any reason.
443 */
444 
445 /* Local Variables: */
446    char *result;             /* Returned pointer */
447    const char *c;            /* Pointer to next supplied character */
448    char *d;                  /* Pointer to next returned character */
449 
450 /* Initialise */
451    result = NULL;
452 
453 /* Return if the pointer is NULL or if an error has occurred. */
454    if( !astOK || !text ) return result;
455 
456 /* Allocate the maximum possible amount of memory that may be needed to
457    store the returned string. */
458    result = astMalloc( 6*strlen( text ) + 1 );
459 
460 /* Check the pointer can be used safely. */
461    if( astOK ) {
462 
463 /* Loop round every character in the supplied text. */
464       c = text - 1;
465       d = result;
466       while( *(++c) ) {
467 
468 /* We replace this character if it is a <, >, ', &, or ". */
469          if( *c == '<' ) {
470             strcpy( d, "&lt;" );
471             d += 4;
472 
473          } else if( *c == '>' ) {
474             strcpy( d, "&gt;" );
475             d += 4;
476 
477          } else if( *c == '"' ) {
478             strcpy( d, "&quot;" );
479             d += 6;
480 
481          } else if( *c == '\'' ) {
482             strcpy( d, "&apos;" );
483             d += 6;
484 
485          } else if( *c == '&' ) {
486             strcpy( d, "&amp;" );
487             d += 5;
488 
489 /* Otherwise just append the supplied character. */
490          } else {
491             *(d++) = *c;
492          }
493       }
494 
495 /* Terminate the returned string. */
496       *d = 0;
497 
498 /* Reallocate the string to free up any unused space. */
499       result = astRealloc( result, d - result + 1 );
500    }
501 
502 /* Return the result. */
503    return (const char *) result;
504 }
505 
506 
507 #ifdef DEBUG
AddObjectToList(AstXmlObject * obj)508 static void AddObjectToList( AstXmlObject *obj ){
509 /*
510 *  Name:
511 *     AddObjectToList
512 
513 *  Purpose:
514 *     Adds an XmlObject to a static list of all currently active XmlObjects.
515 
516 *  Type:
517 *     Private function.
518 
519 *  Synopsis:
520 *     #include "xml.h"
521 *     void AddObjectToList( AstXmlObject *obj )
522 
523 *  Description:
524 *     This function adds the supplied pointer to a static list of pointers,
525 *     and increments the number of elements in the list. This list holds
526 *     pointers to all the XmlObjects which currently exist.
527 
528 *  Parameters:
529 *     this
530 *        A pointer to a new XmlObject.
531 */
532 
533 /* Return if the pointer is NULL or if an error has occurred. */
534    if( !astOK || !obj ) return;
535 
536 /* Increment the number of objects in the list and increase the size of
537    the list. */
538    astBeginPM;
539    existing_objects = astGrow( existing_objects, ++nobj, sizeof( AstXmlObject *) );
540    astEndPM;
541 
542 /* Add the new pointer to the end of the list. */
543    existing_objects[ nobj - 1 ] = obj;
544 }
545 #endif
546 
AppendChar(char * str1,int * nc,char ch,int * status)547 static char *AppendChar( char *str1, int *nc, char ch, int *status ) {
548 /*
549 *  Name:
550 *     AppendChar
551 
552 *  Purpose:
553 *     Append a character to a string which grows dynamically.
554 
555 *  Type:
556 *     Private function.
557 
558 *  Synopsis:
559 *     #include "xml.h"
560 *     char *AppendChar( char *str1, int *nc, char ch, int *status )
561 
562 *  Description:
563 *     This function appends a character to a dynamically
564 *     allocated string, extending the dynamic string as necessary to
565 *     accommodate the new character (plus the final null).
566 
567 *  Parameters:
568 *     str1
569 *        Pointer to the null-terminated dynamic string, whose memory
570 *        has been allocated using the AST memory allocation functions
571 *        defined in "memory.h". If no space has yet been allocated for
572 *        this string, a NULL pointer may be given and fresh space will
573 *        be allocated by this function.
574 *     nc
575 *        Pointer to an integer containing the number of characters in
576 *        the dynamic string (excluding the final null). This is used
577 *        to save repeated searching of this string to determine its
578 *        length and it defines the point where the new string will be
579 *        appended. Its value is updated by this function to include
580 *        the extra characters appended.
581 *
582 *        If "str1" is NULL, the initial value supplied for "*nc" will
583 *        be ignored and zero will be used.
584 *     ch
585 *        The character which is to be appended to "str1".
586 *     status
587 *        Pointer to the inherited status variable.
588 
589 *  Returned Value:
590 *     A possibly new pointer to the dynamic string with the new character
591 *     appended (its location in memory may have to change if it has to
592 *     be extended, in which case the original memory is automatically
593 *     freed by this function). When the string is no longer required,
594 *     its memory should be freed using astFree.
595 
596 *  Notes:
597 *     - If this function is invoked with the global error status set
598 *     or if it should fail for any reason, then the returned pointer
599 *     will be equal to "str1" and the dynamic string contents will be
600 *     unchanged.
601 */
602 
603 /* Local Variables: */
604    char *result;                 /* Pointer value to return */
605    int len;                      /* Length of new string */
606 
607 /* Initialise. */
608    result = str1;
609 
610 /* If the first string pointer is NULL, also initialise the character
611    count to zero. */
612    if ( !str1 ) *nc = 0;
613 
614 /* Check the global error status. */
615    if ( !astOK ) return result;
616 
617 /* Calculate the total string length once the character has been added. */
618    len = *nc + 1;
619 
620 /* Extend the dynamic string to the required length, including
621    a final null. Save the resulting pointer, which will be
622    returned. */
623    result = astGrow( str1, len + 1, sizeof( char ) );
624 
625 /* If OK, append the second string and update the total character
626    count. */
627    if ( astOK ) {
628       result[ *nc ] = ch;
629       *nc = len;
630       result[ *nc ] = 0;
631    }
632 
633 /* Return the result pointer. */
634    return result;
635 }
636 
AppendLine(char * str1,int * nc,const char * str2,int ind,int * status)637 static char *AppendLine( char *str1, int *nc, const char *str2, int ind, int *status ) {
638 /*
639 *  Name:
640 *     AppendLine
641 
642 *  Purpose:
643 *     Append an indented new line to another string which grows dynamically.
644 
645 *  Type:
646 *     Private function.
647 
648 *  Synopsis:
649 *     #include "xml.h"
650 *     char *AppendLine( char *str1, int *nc, const char *str2, int ind, int *status )
651 
652 *  Description:
653 *     This function appends one string to another dynamically
654 *     allocated string, extending the dynamic string as necessary to
655 *     accommodate the new characters (plus the final null).
656 *
657 *     A newline character is inserted if necessary to ensure that the "str2"
658 *     string starts on a newline. If "ind" is positive, spaces are added
659 *     as necessary to ensure that "str2" begins with the specified number of
660 *     spaces.
661 
662 *  Parameters:
663 *     str1
664 *        Pointer to the null-terminated dynamic string, whose memory
665 *        has been allocated using the AST memory allocation functions
666 *        defined in "memory.h". If no space has yet been allocated for
667 *        this string, a NULL pointer may be given and fresh space will
668 *        be allocated by this function.
669 *     nc
670 *        Pointer to an integer containing the number of characters in
671 *        the dynamic string (excluding the final null). This is used
672 *        to save repeated searching of this string to determine its
673 *        length and it defines the point where the new string will be
674 *        appended. Its value is updated by this function to include
675 *        the extra characters appended.
676 *
677 *        If "str1" is NULL, the initial value supplied for "*nc" will
678 *        be ignored and zero will be used.
679 *     str2
680 *        Pointer to a constant null-terminated string, a copy of which
681 *        is to be appended to "str1".
682 *     ind
683 *        The number of spaces to use as the indentation string.
684 *     status
685 *        Pointer to the inherited status variable.
686 
687 *  Returned Value:
688 *     A possibly new pointer to the dynamic string with the new string
689 *     appended (its location in memory may have to change if it has to
690 *     be extended, in which case the original memory is automatically
691 *     freed by this function). When the string is no longer required,
692 *     its memory should be freed using astFree.
693 
694 *  Notes:
695 *     - If this function is invoked with the global error status set
696 *     or if it should fail for any reason, then the returned pointer
697 *     will be equal to "str1" and the dynamic string contents will be
698 *     unchanged.
699 */
700 
701 /* Local Variables: */
702    char *c;                      /* Point to next character */
703    char *result;                 /* Pointer value to return */
704    char *temp;                   /* Pointer to modified string */
705    int j;                        /* Loop count */
706 
707 /* Initialise. */
708    result = str1;
709 
710 /* If the first string pointer is NULL, also initialise the character
711    count to zero. */
712    if ( !str1 ) *nc = 0;
713 
714 /* Check the global error status. */
715    if ( !astOK || !str2 ) return result;
716 
717 /* Remove any trailing white space (except for newlines) from the supplied
718    string. */
719    if( *nc > 0 ) {
720       c = str1 + *nc - 1;
721       while( isspace( *c ) && *c != '\n' ) {
722          *(c--) = 0;
723          (*nc)--;
724       }
725 
726 /* If the last character in the returned string is not now a newline,
727    append a newline, so long as the new item does not start with a newline. */
728       if( str1[ *nc - 1 ] != '\n' ) {
729          temp = AppendChar( str1, nc, '\n', status );
730       } else {
731          temp = str1;
732       }
733 
734    } else {
735       temp = str1;
736    }
737 
738 /* If a fixed indentation is specified, skip over any leading spaces in
739    the second string. */
740    if( str2 ) {
741       if( ind > 0 ) {
742          while( isspace( *str2 ) ) str2++;
743       }
744 
745 /* If the first character of the second string is a newline, ignore it. */
746       if( str2[ 0 ] == '\n' ) str2++;
747    }
748 
749 /* Append the indentation string. */
750    for( j = 0; j < ind; j++ ) temp = AppendChar( temp, nc, ' ', status );
751 
752 /* Append the supplied string. */
753    return astAppendString( temp, nc, str2 );
754 }
755 
astXmlAddAttr_(AstXmlElement * this,const char * name,const char * value,const char * prefix,int * status)756 void astXmlAddAttr_( AstXmlElement *this, const char *name, const char *value,
757                      const char *prefix, int *status ){
758 /*
759 *+
760 *  Name:
761 *     astXmlAddAttr
762 
763 *  Purpose:
764 *     Add an attribute to an XmlElement.
765 
766 *  Type:
767 *     Protected function.
768 
769 *  Synopsis:
770 *     #include "xml.h"
771 *     void astXmlAddAttr( AstXmlElement *this, const char *name,
772 *                         const char *value, const char *prefix )
773 
774 *  Description:
775 *     This function adds an attribute to a specified XmlElement. If the
776 *     element already contains an attribute with the given name amd prefix,
777 *     then the value of the attribute is changed to be the supplied value.
778 
779 *  Parameters:
780 *     this
781 *        The pointer to the element to be modified.
782 *     name
783 *        Pointer to a null terminated string containing the attribute name.
784 *     value
785 *        Pointer to a null terminated string containing the attribute value.
786 *     prefix
787 *        The namespace prefix for the attribute. May be NULL or blank, in
788 *        which case any prefix at the start of "name" is used.
789 *-
790 */
791 
792 /* Local Variables: */
793    AstXmlAttribute *attr;    /* The new attribute. */
794    AstXmlAttribute *oldattr; /* Pointer to existing attribute */
795    int i;                    /* Loop index */
796    int nattr;                /* Number of attributes in the element */
797    int oldi;                 /* Index of existing attribute */
798    char *my_value;           /* Cleaned value text */
799 
800 /* Check the global error status. */
801    if( !astOK ) return;
802 
803 /* Initialise */
804    oldattr = NULL;
805 
806 /* Clean the value text. */
807    my_value = CleanText( value, status );
808 
809 /* Create a new XmlAttribute. */
810    attr = NewAttribute( name, my_value, prefix, status );
811 
812 /* Free the memory */
813    my_value = astFree( my_value );
814 
815 /* If OK, indicate that the attribute is owned by the element. */
816    if( astOK ) {
817       ( (AstXmlObject *) attr )->parent = (AstXmlParent *) this;
818 
819 /* Save the number of attributes currently stored in the element. */
820       nattr = ( this->attrs ) ? this->nattr : 0;
821 
822 /* Search the existing attributes to see if an attribute with the given
823    name and prefix already exists. */
824       oldi = -1;
825       for( i = 0; i < nattr; i++ ) {
826          oldattr = this->attrs[ i ];
827          if( !strcmp( oldattr->name, attr->name ) ) {
828             if( !oldattr->prefix && !attr->prefix ) {
829                oldi = i;
830                break;
831             } else if( oldattr->prefix && attr->prefix &&
832                        !strcmp( oldattr->prefix, attr->prefix ) ){
833                oldi = i;
834                break;
835             }
836          }
837       }
838 
839 /* If there is an existing attribute with the same name and prefix,
840    replace the old attribute with the new one created above. */
841       if( oldi > -1 ){
842          ((AstXmlObject *)oldattr)->parent = NULL;
843          oldattr = astXmlAnnul( oldattr );
844          this->attrs[ oldi ] = attr;
845 
846 /* Otherwise, attempt to extend the array to hold an extra attribute. */
847       } else {
848          this->attrs = astGrow( this->attrs, nattr + 1,
849                                 sizeof( AstXmlAttribute * ) );
850 
851 /* Check all has gone OK. */
852          if( astOK ) {
853 
854 /* Store the attribute pointer in the array of attribute pointers. */
855             this->attrs[ nattr ] = attr;
856 
857 /* Increment the number of content items in this element */
858             this->nattr = nattr + 1;
859 
860          }
861       }
862    }
863 }
864 
astXmlAddCDataSection_(AstXmlElement * this,const char * text,int * status)865 void astXmlAddCDataSection_( AstXmlElement *this, const char *text, int *status ){
866 /*
867 *+
868 *  Name:
869 *     astXmlAddCDataSection
870 
871 *  Purpose:
872 *     Create a new XmlCDataSection and add it to an XmlElement.
873 
874 *  Type:
875 *     Protected function.
876 
877 *  Synopsis:
878 *     #include "xml.h"
879 *     void astXmlAddCDataSection( AstXmlElement *this, const char *text )
880 
881 *  Description:
882 *     This function creates a new XmlCDataSection structure representing
883 *     an unparsed character data (CDATA) section, and adds it into an
884 *     existing element.
885 
886 *  Parameters:
887 *     this
888 *        A pointer to the element to be modified.
889 *     text
890 *        Pointer to a null terminated string containing the character data.
891 
892 *-
893 */
894 
895 /* Local Variables: */
896    AstXmlCDataSection *new;  /* Pointer to new structure */
897    char *my_text;            /* Cleaned text */
898 
899 /* Check the global error status. */
900    if( !astOK ) return;
901 
902 /* Allocate space for the new structure. */
903    new = (AstXmlCDataSection *) astMalloc( sizeof( AstXmlCDataSection ) );
904 
905 /* Clean the text. */
906    my_text = CleanText( text, status );
907 
908 /* Initialise it. */
909    InitXmlCDataSection( new, AST__XMLCDATA, my_text, status );
910 
911 /* Free the memory */
912    my_text = astFree( my_text );
913 
914 /* If an error occurred, delete the new structure. */
915    if( !astOK ) {
916       new = astXmlDelete( new );
917 
918 /* Otherwise, add the content item to the element. */
919    } else {
920       AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) new, status );
921    }
922 }
923 
astXmlAddCharData_(AstXmlParent * this,int where,const char * text,int * status)924 void astXmlAddCharData_( AstXmlParent *this, int where, const char *text, int *status ){
925 /*
926 *+
927 *  Name:
928 *     astXmlAddCharData
929 
930 *  Purpose:
931 *     Create a new XmlCharData and add it to an XmlElement or XmlDocument.
932 
933 *  Type:
934 *     Protected function.
935 
936 *  Synopsis:
937 *     #include "xml.h"
938 *     void astXmlAddCharData( AstXmlParent *this, int where, const char *text )
939 
940 *  Description:
941 *     This function creates a new XmlCharData structure representing
942 *     parsed character data, and adds it into an existing element or
943 *     document.
944 
945 *  Parameters:
946 *     this
947 *        Pointer to the element or document to be modified.
948 *     where
949 *        Ignored if "this" is an XmlElement pointer. Otherwise, "where"
950 *        indicates where the item should be added to the document:
951 *          1 - In the prologue, after the XML declaration but before the DTD.
952 *          2 - In the prologue, after the DTD but before the root element.
953 *          3 - In the epilogue, after the root element.
954 *     text
955 *        Pointer to a null terminated string containing the character data.
956 *        If "this" is a document, the text must consist entirely of white
957 *        space.
958 
959 *-
960 */
961 
962 /* Local Variables: */
963    AstXmlCharData *new;        /* Pointer to the new structure */
964    char *my_text;              /* Pointer to cleaned text */
965    char *c;                    /* Pointer to next character */
966 
967 /* Check the global error status. */
968    if( !astOK ) return;
969 
970 /* Initialise */
971    new = NULL;
972 
973 /* Clean the text by replacing "\r\n" by "\n". */
974    my_text = CleanText( text, status );
975 
976 /* See if the text is all white. */
977    c = my_text - 1;
978    while( *(++c) && isspace( *c ) );
979 
980 /* If the string contains a non-white character, allocate memory for
981    a XmlBlack structure, and initialise it to hold the supplied text.
982    Otherwise, allocate memory for a XmlWhite structure, and initialise it
983    to hold the supplied text. */
984    if( *c ) {
985       if( astXmlCheckType( this, AST__XMLDOC ) ) {
986          astError( AST__XMLCM, "astXmlAddCharData(xml): Illegal attempt "
987                    "to add non-white character data to the prologue or "
988                    "epilogue of an XML document: \"%s\".", status, my_text );
989       } else {
990          new = (AstXmlCharData *) astMalloc( sizeof( AstXmlBlack ) );
991          InitXmlBlack( (AstXmlBlack *) new, AST__XMLBLACK, my_text, status );
992       }
993 
994    } else {
995       new = (AstXmlCharData *) astMalloc( sizeof( AstXmlWhite ) );
996       InitXmlWhite( (AstXmlWhite *) new, AST__XMLWHITE, my_text, status );
997    }
998 
999 /* Free the memory holding the cleaned text */
1000    my_text = astFree( my_text );
1001 
1002 /* If an error occurred, delete the new structure. */
1003    if( !astOK ) {
1004       new = astXmlDelete( new );
1005 
1006 /* Otherwise, add the content item to the element. */
1007    } else {
1008       AddContent( this, where, (AstXmlContentItem *) new, status );
1009    }
1010 }
1011 
astXmlAddComment_(AstXmlParent * this,int where,const char * text,int * status)1012 void astXmlAddComment_( AstXmlParent *this, int where, const char *text, int *status ){
1013 /*
1014 *+
1015 *  Name:
1016 *     astXmlAddComment
1017 
1018 *  Purpose:
1019 *     Create a new XmlComment and add it to an XmlElement or XmlDocument.
1020 
1021 *  Type:
1022 *     Protected function.
1023 
1024 *  Synopsis:
1025 *     #include "xml.h"
1026 *     void astXmlAddComment( AstXmlParent *this, int where, const char *text )
1027 
1028 *  Description:
1029 *     This function creates a new XmlComment structure representing
1030 *     an XML comment, and adds it into an existing element or document.
1031 
1032 *  Parameters:
1033 *     this
1034 *        Pointer to the element or document to be modified.
1035 *     where
1036 *        Ignored if "this" is an XmlElement pointer. Otherwise, "where"
1037 *        indicates where the item should be added to the document:
1038 *          1 - In the prologue, after the XML declaration but before the DTD.
1039 *          2 - In the prologue, after the DTD but before the root element.
1040 *          3 - In the epilogue, after the root element.
1041 *     text
1042 *        Pointer to a null terminated string containing the comment text.
1043 
1044 *-
1045 */
1046 
1047 /* Local Variables: */
1048    AstXmlComment *new;        /* Pointer to the new structure */
1049    char *my_text;            /* Cleaned text */
1050 
1051 /* Check the global error status. */
1052    if( !astOK ) return;
1053 
1054 /* Allocate space for the new structure. */
1055    new = (AstXmlComment *) astMalloc( sizeof( AstXmlComment ) );
1056 
1057 /* Clean the text. */
1058    my_text = CleanText( text, status );
1059 
1060 /* Initialise it. */
1061    InitXmlComment( new, AST__XMLCOM, my_text, status );
1062 
1063 /* Free the memory */
1064    my_text = astFree( my_text );
1065 
1066 /* If an error occurred, delete the new structure. */
1067    if( !astOK ) {
1068       new = astXmlDelete( new );
1069 
1070 /* Otherwise, add the content item to the element. */
1071    } else {
1072       AddContent( this, where, (AstXmlContentItem *) new, status );
1073    }
1074 
1075 }
1076 
astXmlAddElement_(AstXmlElement * this,const char * name,const char * prefix,int * status)1077 AstXmlElement *astXmlAddElement_( AstXmlElement *this, const char *name,
1078                                   const char *prefix, int *status ){
1079 /*
1080 *+
1081 *  Name:
1082 *     astXmlAddElement
1083 
1084 *  Purpose:
1085 *     Create a new empty XmlElement and adds it to an XmlElement.
1086 
1087 *  Type:
1088 *     Protected function.
1089 
1090 *  Synopsis:
1091 *     #include "xml.h"
1092 *     AstXmlElement *astXmlAddElement( AstXmlElement *this, const char *name,
1093 *                                      const char *prefix )
1094 
1095 *  Description:
1096 *     This function creates a new XmlElement structure representing an
1097 *     empty XML element with the given name and namespace prefix, and
1098 *     adds it into an existing element.
1099 
1100 *  Parameters:
1101 *     this
1102 *        A pointer to the element to be modified. This may be NULL.
1103 *     name
1104 *        The name for the element.
1105 *     prefix
1106 *        The namespace prefix for the element. May be NULL or blank, in
1107 *        which case any prefix at the start of "name" is used.
1108 
1109 *  Returned Value:
1110 *     A pointer to the new structure is returned. This pointer should be
1111 *     freed using astXmlAnnul when no longer needed.
1112 
1113 *  Notes:
1114 *     - A NULL pointer is returned if the inherited status value
1115 *     indicates an error has occurred on entry, or if this function
1116 *     should fail for any reason.
1117 *-
1118 */
1119 
1120 /* Local Variables: */
1121    AstXmlElement *new;        /* The returned pointer */
1122 
1123 /* Initialise */
1124    new = NULL;
1125 
1126 /* Check the global error status. */
1127    if( !astOK ) return new;
1128 
1129 /* Allocate space for the new structure. */
1130    new = (AstXmlElement *) astMalloc( sizeof( AstXmlElement ) );
1131 
1132 /* Initialise it. */
1133    InitXmlElement( new, AST__XMLELEM, name, prefix, status );
1134 
1135 /* If an error occurred, delete the new structure. */
1136    if( !astOK ) {
1137       new = astXmlDelete( new );
1138 
1139 /* Otherwise, add the content item to the element. */
1140    } else {
1141       AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) new, status );
1142    }
1143 
1144 /* Return the result. */
1145    return new;
1146 
1147 }
1148 
astXmlAddPI_(AstXmlParent * this,int where,const char * target,const char * text,int * status)1149 void astXmlAddPI_( AstXmlParent *this, int where, const char *target, const char *text, int *status ){
1150 /*
1151 *+
1152 *  Name:
1153 *     astXmlAddPI
1154 
1155 *  Purpose:
1156 *     Create a new XmlPI and add it to an element or document.
1157 
1158 *  Type:
1159 *     Protected function.
1160 
1161 *  Synopsis:
1162 *     #include "xml.h"
1163 *     void astXmlAddPI( AstXmlParent *this, int where, const char *target,
1164 *                       const char *text )
1165 
1166 *  Description:
1167 *     This function creates a new XmlPI structure representing an
1168 *     XML "programming instruction", and adds it into an existing element
1169 *     or document.
1170 
1171 *  Parameters:
1172 *     this
1173 *        Pointer to the element or document to be modified. This should
1174 *        be a pointer to an XmlElement or an XmlDocument.
1175 *     where
1176 *        Ignored if "this" is an XmlElement pointer. Otherwise, "where"
1177 *        indicates where the PI should be added to the document:
1178 *          1 - In the prologue, after the XML declaration but before the DTD.
1179 *          2 - In the prologue, after the DTD but before the root element.
1180 *          3 - In the epilogue, after the root element.
1181 *     target
1182 *        Pointer to a null terminated string containing the PI target.
1183 *     text
1184 *        Pointer to a null terminated string containing the PI text.
1185 
1186 *-
1187 */
1188 
1189 /* Local Variables: */
1190    AstXmlPI *new;        /* Pointer to the new structure */
1191    char *my_text;            /* Cleaned text */
1192 
1193 /* Check the global error status. */
1194    if( !astOK ) return;
1195 
1196 /* Allocate space for the new structure. */
1197    new = (AstXmlPI *) astMalloc( sizeof( AstXmlPI ) );
1198 
1199 /* Clean the text. */
1200    my_text = CleanText( text, status );
1201 
1202 /* Initialise it. */
1203    InitXmlPI( new, AST__XMLPI, target, my_text, status );
1204 
1205 /* Free the memory */
1206    my_text = astFree( my_text );
1207 
1208 /* If an error occurred, delete the new structure. */
1209    if( !astOK ) {
1210       new = astXmlDelete( new );
1211 
1212 /* Otherwise, add the content item to the element. */
1213    } else {
1214       AddContent( this, where, (AstXmlContentItem *) new, status );
1215    }
1216 }
1217 
astXmlAddURI_(AstXmlElement * this,const char * prefix,const char * uri,int * status)1218 void astXmlAddURI_( AstXmlElement *this, const char *prefix, const char *uri, int *status ){
1219 /*
1220 *+
1221 *  Name:
1222 *     astXmlAddURI
1223 
1224 *  Purpose:
1225 *     Add a namespace prefix definition to an XmlElement, or change the
1226 *     default namespace.
1227 
1228 *  Type:
1229 *     Protected function.
1230 
1231 *  Synopsis:
1232 *     #include "xml.h"
1233 *     void astXmlAddURI( AstXmlElement *this, const char *prefix,
1234 *                        const char *uri )
1235 
1236 *  Description:
1237 *     This function adds a namespace prefix definition to a specified
1238 *     XmlElement, or changes the default namespace. If the suppliedprefix
1239 *     is already defined in the element, the associated URI is changed to
1240 *     the supplied URI.
1241 
1242 *  Parameters:
1243 *     this
1244 *        The pointer to the element to be modified.
1245 *     prefix
1246 *        Pointer to a null terminated string containing the namespace
1247 *        prefix. If this is NULL or blank, then the supplied URI is used
1248 *        as the default namespace for this element and all child elements
1249 *        (except for child elements which define their own default
1250 *        namespace).
1251 *     uri
1252 *        Pointer to a null terminated string containing the namespace URI.
1253 *        If this is NULL or blank, and "prefix" is also NULL or blank, then
1254 *        this has the same effect of there being no default namespace within
1255 *        the supplied element.
1256 *-
1257 */
1258 
1259 /* Local Variables: */
1260    AstXmlNamespace *ns;    /* The new namespace definition */
1261    AstXmlNamespace *oldns; /* The existing namespace definition */
1262    int i;                  /* Loop index */
1263    int nc;                 /* Length of namespace prefix */
1264    int nnspref;            /* Number of namespace defintions in the element */
1265    int oldi;               /* Index of existing attribute */
1266 
1267 /* Check the global error status. */
1268    if( !astOK ) return;
1269 
1270 /* Initialise */
1271    oldns = NULL;
1272 
1273 /* Store the used length of the namespace prefix. */
1274    nc = prefix ? astChrLen( prefix ) : 0;
1275 
1276 /* If no namespace prefix has been supplied, just change the default
1277    namespace URI. */
1278    if( !nc ) {
1279       if( uri ) {
1280          this->defns = astStore( this->defns, uri, strlen( uri ) + 1 );
1281       } else {
1282          this->defns = astStore( this->defns, "", 1 );
1283       }
1284 
1285 /* Otherwise, add the namespace definition to the element. */
1286    } else {
1287 
1288 /* Create a new XmlNamespace. */
1289       ns = NewNamespace( prefix, uri, status );
1290 
1291 /* If OK, indicate that the namespace is owned by the element. */
1292       if( astOK ) {
1293          ( (AstXmlObject *) ns )->parent = (AstXmlParent *) this;
1294 
1295 /* Save the number of namespace definitions currently stored in the element. */
1296          nnspref = ( this->nsprefs ) ? this->nnspref : 0;
1297 
1298 /* Search the existing prefixes to see if a namespace with the given
1299    prefix already exists. */
1300          oldi = -1;
1301          for( i = 0; i < nnspref; i++ ) {
1302             oldns = this->nsprefs[ i ];
1303             if( !strcmp( oldns->prefix, ns->prefix ) ) {
1304                oldi = i;
1305                break;
1306             }
1307          }
1308 
1309 /* If there is an existing namespace with the same prefix, replace the old
1310    namespace with the new one created above. */
1311          if( oldi > -1 ){
1312             ((AstXmlObject *)oldns)->parent = NULL;
1313             oldns = astXmlAnnul( oldns );
1314             this->nsprefs[ oldi ] = ns;
1315 
1316 /* Otherwise, attempt to extend the array to hold an extra namespace definition. */
1317          } else {
1318             this->nsprefs = astGrow( this->nsprefs, nnspref + 1,
1319                                      sizeof( AstXmlNamespace * ) );
1320 
1321 /* Check all has gone OK. */
1322             if( astOK ) {
1323 
1324 /* Store the Namespace pointer in the array of Namespace pointers. */
1325                this->nsprefs[ nnspref ] = ns;
1326 
1327 /* Increment the number of namespaces in this element */
1328                this->nnspref = nnspref + 1;
1329             }
1330          }
1331       }
1332    }
1333 }
1334 
astXmlAnnul_(AstXmlObject * this,int * status)1335 void *astXmlAnnul_( AstXmlObject *this, int *status ){
1336 /*
1337 *+
1338 *  Name:
1339 *     astXmlAnnul
1340 
1341 *  Purpose:
1342 *     Free the resources used by an XmlObject.
1343 
1344 *  Type:
1345 *     Protected function.
1346 
1347 *  Synopsis:
1348 *     #include "xml.h"
1349 *     void *astXmlAnnul( AstXmlObject *this )
1350 
1351 *  Description:
1352 *     This function frees the resources used to hold the XmlObject, together
1353 *     with any child objects contained within the supplied XmlObject. A NULL
1354 *     pointer is always returned. If the supplied object is still in use
1355 *     (that is, if its parent XmlElement still exists) then the resources
1356 *     are not freed, and a copy of the supplied pointer is returned.
1357 
1358 *  Parameters:
1359 *     this
1360 *        pointer to the XmlObject to be freed.
1361 
1362 *  Returned Value:
1363 *     A NULL pointer, or the supplied pointer if the XmlObject is still
1364 *     in use.
1365 
1366 *  Notes:
1367 *     - This function attempts to execute even if an error has already
1368 *     occurred.
1369 *-
1370 */
1371 
1372 /* Return if a NULL pointer has been suppplied. */
1373    if( !this ) return NULL;
1374 
1375 /* Return the supplied pointer if the objects parent still exists. */
1376    if( this->parent &&
1377        astXmlCheckType( this->parent, AST__XMLPAR ) ) return this;
1378 
1379 #ifdef DEBUG
1380 /* Remove the supplied object from the list of currently active XmlObjects. */
1381    RemoveObjectFromList( this );
1382 #endif
1383 
1384 /* Clean the objects contents, and free the memory holding the XmlObject. */
1385    CleanXml( this, this->type, status );
1386    astFree( this );
1387 
1388 /* Return a NULL pointer. */
1389    return NULL;
1390 }
1391 
astXmlAnnulTree_(AstXmlObject * this,int * status)1392 void *astXmlAnnulTree_( AstXmlObject *this, int *status ){
1393 /*
1394 *+
1395 *  Name:
1396 *     astXmlAnnulTree
1397 
1398 *  Purpose:
1399 *     Free the resources used by a tree of XmlObjects.
1400 
1401 *  Type:
1402 *     Protected function.
1403 
1404 *  Synopsis:
1405 *     #include "xml.h"
1406 *     void *astXmlAnnulTree( AstXmlObject *this )
1407 
1408 *  Description:
1409 *     This function finds the head of the tree containing the supplied
1410 *     XmlObject (either an XmlElement or an XmlDocument), and frees the
1411 *     resources associated with all members of the tree. A NULL pointer
1412 *     is always returned.
1413 
1414 *  Parameters:
1415 *     this
1416 *        Pointer to a member of the tree of XmlObjects to be freed.
1417 
1418 *  Returned Value:
1419 *     A NULL pointer.
1420 
1421 *  Notes:
1422 *     - This function attempts to execute even if an error has already
1423 *     occurred.
1424 *-
1425 */
1426 
1427 /* Return if a NULL pointer has been suppplied. */
1428    if( !this ) return NULL;
1429 
1430 /* Find the root and annull it. This will free all children (i.e.
1431    the entire tree). */
1432    return astXmlAnnul( astXmlGetRoot( this ) );
1433 }
1434 
astXmlCopy_(AstXmlObject * this,int * status)1435 AstXmlObject *astXmlCopy_( AstXmlObject *this, int *status ) {
1436 /*
1437 *+
1438 *  Name:
1439 *     astXmlCopy
1440 
1441 *  Purpose:
1442 *     Produce a deep copy of a supplied XmlObject.
1443 
1444 *  Type:
1445 *     Protected function.
1446 
1447 *  Synopsis:
1448 *     #include "xml.h"
1449 *     AstXmlObject *astXmlCopy( AstXmlObject *this )
1450 
1451 *  Description:
1452 *     This function returns a pointer to a deep copy of the supplied
1453 *     XmlObject.
1454 
1455 *  Parameters:
1456 *     this
1457 *        Pointer to the XmlObject to copy.
1458 
1459 *  Returned Value:
1460 *     Pointer to the new copy.
1461 
1462 *  Notes:
1463 *     - NULL is returned if NULL pointer is supplied.
1464 *     - NULL is returned if an error has already occurred, or if this
1465 *     function should fail for any reason.
1466 *-
1467 */
1468 
1469 
1470 /* Local Variables: */
1471    AstXmlAttribute *attr;
1472    AstXmlBlack *black;
1473    AstXmlCDataSection *cdata;
1474    AstXmlComment *comm;
1475    AstXmlDTDec *dtd;
1476    AstXmlDeclPI *dec;
1477    AstXmlDocument *doc, *newdoc;
1478    AstXmlElement *elem, *newelem;
1479    AstXmlNamespace *ns;
1480    AstXmlObject *new;
1481    AstXmlPI *pi;
1482    AstXmlPrologue *pro, *newpro;
1483    AstXmlWhite *white;
1484    int i, type;
1485 
1486 /* Initialise */
1487    new = NULL;
1488 
1489 /* Check the global error status. */
1490    if( !astOK || !this ) return new;
1491 
1492 /* Initialise a new XmlObject of the required class, and copy any
1493    sub-objects. */
1494    type = this->type;
1495    if( type == AST__XMLELEM  ){
1496       elem = (AstXmlElement *) this;
1497       new = astMalloc( sizeof( AstXmlElement ) );
1498       InitXmlElement( (AstXmlElement *) new, AST__XMLELEM,
1499                       elem->name, elem->prefix, status );
1500 
1501       newelem = (AstXmlElement *) new;
1502 
1503       newelem->attrs = astMalloc( sizeof( AstXmlAttribute *) * (size_t)elem->nattr );
1504       newelem->nattr = elem->nattr;
1505       for( i = 0; i < elem->nattr; i++ ) {
1506          newelem->attrs[ i ] = (AstXmlAttribute *) astXmlCopy( elem->attrs[ i ] );
1507          ((AstXmlObject *) newelem->attrs[ i ])->parent = (AstXmlParent *) newelem;
1508       }
1509 
1510       newelem->items = astMalloc( sizeof( AstXmlContentItem *) * (size_t)elem->nitem );
1511       newelem->nitem = elem->nitem;
1512       for( i = 0; i < elem->nitem; i++ ) {
1513          newelem->items[ i ] = (AstXmlContentItem *) astXmlCopy( elem->items[ i ] );
1514          ((AstXmlObject *) newelem->items[ i ])->parent = (AstXmlParent *) newelem;
1515       }
1516 
1517       newelem->nsprefs = astMalloc( sizeof( AstXmlNamespace *) * (size_t)elem->nnspref );
1518       newelem->nnspref = elem->nnspref;
1519       for( i = 0; i < elem->nnspref; i++ ) {
1520          newelem->nsprefs[ i ] = (AstXmlNamespace *) astXmlCopy( elem->nsprefs[ i ] );
1521          ((AstXmlObject *) newelem->nsprefs[ i ])->parent = (AstXmlParent *) newelem;
1522       }
1523 
1524       if( elem->defns ) {
1525          newelem->defns = astStore( NULL, elem->defns,
1526                                     strlen( elem->defns ) + 1 );
1527       }
1528 
1529       newelem->complete = elem->complete;
1530 
1531 
1532    } else if( type == AST__XMLATTR ){
1533       attr = (AstXmlAttribute *) this;
1534       new = astMalloc( sizeof( AstXmlAttribute ) );
1535       InitXmlAttribute( (AstXmlAttribute *) new, AST__XMLATTR,
1536                         attr->name, attr->value, attr->prefix, status );
1537 
1538    } else if( type == AST__XMLBLACK ){
1539       black = (AstXmlBlack *) this;
1540       new = astMalloc( sizeof( AstXmlBlack ) );
1541       InitXmlBlack( (AstXmlBlack *) new, AST__XMLBLACK,
1542                     black->text, status );
1543 
1544    } else if( type == AST__XMLWHITE ){
1545       white = (AstXmlWhite *) this;
1546       new = astMalloc( sizeof( AstXmlWhite ) );
1547       InitXmlWhite( (AstXmlWhite *) new, AST__XMLWHITE,
1548                     white->text, status );
1549 
1550    } else if( type == AST__XMLCDATA ){
1551       cdata = (AstXmlCDataSection *) this;
1552       new = astMalloc( sizeof( AstXmlCDataSection ) );
1553       InitXmlCDataSection( (AstXmlCDataSection *) new, AST__XMLCDATA,
1554                            cdata->text, status );
1555 
1556    } else if( type == AST__XMLCOM ){
1557       comm = (AstXmlComment *) this;
1558       new = astMalloc( sizeof( AstXmlComment ) );
1559       InitXmlComment( (AstXmlComment *) new, AST__XMLCOM,
1560                       comm->text, status );
1561 
1562    } else if( type == AST__XMLPI ){
1563       pi = (AstXmlPI *) this;
1564       new = astMalloc( sizeof( AstXmlPI ) );
1565       InitXmlPI( (AstXmlPI *) new, AST__XMLPI, pi->target, pi->text, status );
1566 
1567    } else if( type == AST__XMLNAME ){
1568       ns = (AstXmlNamespace *) this;
1569       new = astMalloc( sizeof( AstXmlNamespace ) );
1570       InitXmlNamespace( (AstXmlNamespace *) new, AST__XMLNAME, ns->prefix,
1571                          ns->uri, status );
1572 
1573    } else if( type == AST__XMLDOC ){
1574       doc = (AstXmlDocument *) this;
1575       new = astMalloc( sizeof( AstXmlDocument ) );
1576       InitXmlDocument( (AstXmlDocument *) new, AST__XMLDOC, status );
1577 
1578       newdoc = (AstXmlDocument *) new;
1579 
1580       if( doc->prolog ) {
1581          newdoc->prolog = (AstXmlPrologue *) astXmlCopy( doc->prolog );
1582          ((AstXmlObject *) newdoc->prolog)->parent = (AstXmlParent *) newdoc;
1583       }
1584 
1585       if( doc->root ) {
1586          newdoc->root = (AstXmlElement *) astXmlCopy( doc->root );
1587          ((AstXmlObject *) newdoc->root)->parent = (AstXmlParent *) newdoc;
1588       }
1589 
1590       newdoc->epilog = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)doc->nepi );
1591       newdoc->nepi = doc->nepi;
1592       for( i = 0; i < doc->nepi; i++ ) {
1593          newdoc->epilog[ i ] = (AstXmlMiscItem *) astXmlCopy( doc->epilog[ i ] );
1594          ((AstXmlObject *) newdoc->epilog[ i ])->parent = (AstXmlParent *) newdoc;
1595       }
1596 
1597       newdoc->current = NULL;
1598 
1599    } else if( type == AST__XMLPRO ){
1600       pro = (AstXmlPrologue *) this;
1601       new = astMalloc( sizeof( AstXmlPrologue ) );
1602       InitXmlPrologue( (AstXmlPrologue *) new, AST__XMLPRO, status );
1603 
1604       newpro = (AstXmlPrologue *) new;
1605 
1606       if( pro->xmldecl ) {
1607          newpro->xmldecl = (AstXmlDeclPI *) astXmlCopy( pro->xmldecl );
1608          ((AstXmlObject *) newpro->xmldecl)->parent = (AstXmlParent *) newpro;
1609       }
1610 
1611       if( pro->dtdec ) {
1612          newpro->dtdec = (AstXmlDTDec *) astXmlCopy( pro->dtdec );
1613          ((AstXmlObject *) newpro->dtdec)->parent = (AstXmlParent *) newpro;
1614       }
1615 
1616       newpro->misc1 = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)pro->nmisc1 );
1617       newpro->nmisc1 = pro->nmisc1;
1618       for( i = 0; i < pro->nmisc1; i++ ) {
1619          newpro->misc1[ i ] = (AstXmlMiscItem *) astXmlCopy( pro->misc1[ i ] );
1620          ((AstXmlObject *) newpro->misc1[ i ])->parent = (AstXmlParent *) newpro;
1621       }
1622 
1623       newpro->misc2 = astMalloc( sizeof( AstXmlMiscItem *) * (size_t)pro->nmisc2 );
1624       newpro->nmisc2 = pro->nmisc2;
1625       for( i = 0; i < pro->nmisc2; i++ ) {
1626          newpro->misc2[ i ] = (AstXmlMiscItem *) astXmlCopy( pro->misc2[ i ] );
1627          ((AstXmlObject *) newpro->misc2[ i ])->parent = (AstXmlParent *) newpro;
1628       }
1629 
1630    } else if( type == AST__XMLDEC ){
1631       dec = (AstXmlDeclPI *) this;
1632       new = astMalloc( sizeof( AstXmlDeclPI ) );
1633       InitXmlDeclPI( (AstXmlDeclPI *) new, AST__XMLDEC, dec->text, status );
1634 
1635    } else if( type == AST__XMLDTD ){
1636       dtd = (AstXmlDTDec *) this;
1637       new = astMalloc( sizeof( AstXmlDTDec ) );
1638       InitXmlDTDec( (AstXmlDTDec *) new, AST__XMLDTD, dtd->name,
1639                     dtd->external, dtd->internal, status );
1640 
1641    } else if( astOK ) {
1642       astError( AST__INTER, "CopyXml: Invalid object type (%d) supplied "
1643                 "(internal AST programming error).", status, type );
1644    }
1645 
1646 /* If an error occurred, delete the new structure. */
1647    if( !astOK ) new = astXmlDelete( new );
1648 
1649 /* Return the result. */
1650    return new;
1651 }
1652 
astXmlFormat_(AstXmlObject * this,int * status)1653 const char *astXmlFormat_( AstXmlObject *this, int *status ) {
1654 /*
1655 *+
1656 *  Name:
1657 *     astXmlFormat
1658 
1659 *  Purpose:
1660 *     Converts an XmlObject into a character string.
1661 
1662 *  Type:
1663 *     Protected function.
1664 
1665 *  Synopsis:
1666 *     #include "xml.h"
1667 *     const char *astXmlFormat( AstXmlObject *this )
1668 
1669 *  Description:
1670 *     This function returns a pointer to a dynamically allocated string
1671 *     containing a textual representation of the supplied XmlObject.
1672 
1673 *  Parameters:
1674 *     this
1675 *        Pointer to the XmlObject to format.
1676 
1677 *  Returned Value:
1678 *     Pointer to a null terminated string holding the formated XmlObject.
1679 *     This string should be freed when no longer needed using astFree.
1680 
1681 *  Notes:
1682 *     - No newlines or indentation strings are added to the returned string.
1683 *     - NULL is returned if NULL pointer is supplied.
1684 *     - NULL is returned if an error has already occurred, or if this
1685 *     function should fail for any reason.
1686 *-
1687 */
1688    return Format( this, -1, status );
1689 }
1690 
astXmlGetAttributeValue_(AstXmlElement * this,const char * name,int * status)1691 const char *astXmlGetAttributeValue_( AstXmlElement *this, const char *name, int *status ){
1692 /*
1693 *+
1694 *  Name:
1695 *     astXmlGetAttributeValue
1696 
1697 *  Purpose:
1698 *     Return a pointer to a string holding the value of a named attribute.
1699 
1700 *  Type:
1701 *     Protected function.
1702 
1703 *  Synopsis:
1704 *     #include "xml.h"
1705 *     const char *astXmlGetAttributeValue( AstXmlElement *this, const char *name )
1706 
1707 *  Description:
1708 *     This function returns a pointer to a constant string holding the
1709 *     value of a named attribute of a supplied element. If the element
1710 *     does not have the named attribute, a NULL pointer is returned but
1711 *     no error is reported.
1712 
1713 *  Parameters:
1714 *     this
1715 *        The pointer to the XmlElement.
1716 *     name
1717 *        Pointer to a string holding the name of the attribute. The name
1718 *        may be preceded with a "prefix:" string, in which case the
1719 *        prefix will also be matched. If no prefix is included, the first
1720 *        attribute with the specified name is returned, regardless of
1721 *        its prefix.
1722 
1723 *  Returned Value:
1724 *     Pointer to a string holding the value of the attribute within the
1725 *     supplied element, or NULL if the attribute was not found.
1726 
1727 *  Notes:
1728 *     - NULL is returned if an error has already occurred, or if this
1729 *     function should fail for any reason.
1730 *-
1731 */
1732 
1733 /* Local Variables: */
1734    const char *result;     /* Returned pointer */
1735    AstXmlAttribute *attr;  /* Pointer to the attribute */
1736 
1737 /* Initialise */
1738    result = NULL;
1739 
1740 /* Check the global error status. */
1741    if( !astOK ) return result;
1742 
1743 /* Find the attribute. */
1744    attr = FindAttribute( this, name, status );
1745 
1746 /* Get its value. */
1747    if( attr ) result = attr->value;
1748 
1749 /* Return the result. */
1750    return result;
1751 }
1752 
astXmlGetItem_(AstXmlElement * this,int item,int * status)1753 AstXmlContentItem *astXmlGetItem_( AstXmlElement *this, int item, int *status ){
1754 /*
1755 *+
1756 *  Name:
1757 *     astXmlGetItem
1758 
1759 *  Purpose:
1760 *     Return a specified item of the content of an element.
1761 
1762 *  Type:
1763 *     Protected function.
1764 
1765 *  Synopsis:
1766 *     #include "xml.h"
1767 *     AstXmlContentItem *astXmlGetItem( AstXmlElement *this, int item )
1768 
1769 *  Description:
1770 *     This function returns a pointer to an item of the content of the
1771 *     specified element.
1772 
1773 *  Parameters:
1774 *     this
1775 *        The pointer to the XmlElement.
1776 *     item
1777 *        The index of the required item, in the range zero to "nitem-1",
1778 *        where "nitem" is the number of items in the element as returned
1779 *        by astXmlGetNitem. An error is reported if the specified index
1780 *        is out of bounds.
1781 
1782 *  Returned Value:
1783 *     A pointer to the requested item.
1784 
1785 *  Notes:
1786 *     - NULL is returned if an error has already occurred, or if this
1787 *     function should fail for any reason.
1788 *-
1789 */
1790 
1791 /* Local Variables: */
1792    AstXmlContentItem *result;     /* The returned pointer */
1793 
1794 /* Initialise */
1795    result = NULL;
1796 
1797 /* Check the global error status. */
1798    if( !astOK ) return result;
1799 
1800 /* Report an error if the supplie dindex is bad. */
1801    if( this->nitem == 0 ) {
1802       astError( AST__XMLIT, "astXmlGetItem(xml): The supplied item index (%d) "
1803                 "is out of bounds. The supplied XmlObject has no content.", status,
1804                 item );
1805 
1806    } else if( item < 0 || item >= this->nitem ) {
1807       astError( AST__XMLIT, "astXmlGetItem(xml): The supplied item index (%d) "
1808                 "is out of bounds. Should be in the range 0 to %d.", status,
1809                 item, this->nitem-1 );
1810    } else {
1811       result = this->items[ item ];
1812    }
1813 
1814 /* Return the result. */
1815    return result;
1816 }
1817 
astXmlGetName_(AstXmlObject * this,int * status)1818 const char *astXmlGetName_( AstXmlObject *this, int *status ){
1819 /*
1820 *+
1821 *  Name:
1822 *     astXmlGetName
1823 
1824 *  Purpose:
1825 *     Return a pointer to a string holding the name of an XmlObject.
1826 
1827 *  Type:
1828 *     Protected function.
1829 
1830 *  Synopsis:
1831 *     #include "xml.h"
1832 *     const char *astXmlGetName( AstXmlObject *this )
1833 
1834 *  Description:
1835 *     This function returns a pointer to a constant string holding the
1836 *     name associated with an XmlObject. For elements and attributes, the
1837 *     "name" value is returned. For PI elements, the "target" value is
1838 *     returned. For namespace definitions, the "prefix" value is returned.
1839 *     An error is reported if the supplied XmlObject is of any other class.
1840 
1841 *  Parameters:
1842 *     this
1843 *        The pointer to the XmlObject.
1844 
1845 *  Returned Value:
1846 *     Pointer to the name string within the XML object.
1847 
1848 *  Notes:
1849 *     - NULL is returned if an error has already occurred, or if this
1850 *     function should fail for any reason.
1851 *-
1852 */
1853 
1854 /* Local Variables: */
1855    const char *result;     /* Returned pointer */
1856    int type;               /* Object type */
1857 
1858 /* Initialise */
1859    result = NULL;
1860 
1861 /* Check the global error status. */
1862    if( !astOK ) return result;
1863 
1864 /* Return the relevant component of the structure, depending on its type. */
1865    type = this->type;
1866    if( type == AST__XMLELEM  ){
1867       result = ( (AstXmlElement *) this )->name;
1868 
1869    } else if( type == AST__XMLATTR ){
1870       result = ( (AstXmlAttribute *) this )->name;
1871 
1872    } else if( type == AST__XMLPI ){
1873       result = ( (AstXmlPI *) this )->target;
1874 
1875    } else if( type == AST__XMLNAME ){
1876       result = ( (AstXmlNamespace *) this )->prefix;
1877 
1878    } else {
1879       astError( AST__INTER, "astXmlGetName: Inappropriate object type (%d) supplied "
1880                 "(internal AST programming error).", status, type );
1881    }
1882 
1883 /* Return the result. */
1884    return result;
1885 }
1886 
astXmlGetNattr_(AstXmlElement * this,int * status)1887 int astXmlGetNattr_( AstXmlElement *this, int *status ){
1888 /*
1889 *+
1890 *  Name:
1891 *     astXmlGetNattr
1892 
1893 *  Purpose:
1894 *     Return the number of attributes held by an element.
1895 
1896 *  Type:
1897 *     Protected function.
1898 
1899 *  Synopsis:
1900 *     #include "xml.h"
1901 *     int astXmlGetNattr( AstXmlElement *this )
1902 
1903 *  Description:
1904 *     This function returns the number of  attributes held by an element.
1905 
1906 *  Parameters:
1907 *     this
1908 *        The pointer to the XmlElement.
1909 
1910 *  Returned Value:
1911 *     The number of  attributes held by the supplied element.
1912 
1913 *  Notes:
1914 *     - Zero is returned if an error has already occurred, or if this
1915 *     function should fail for any reason.
1916 *-
1917 */
1918 
1919 /* Check the global error status. */
1920    if( !astOK ) return 0;
1921 
1922 /* Return the result. */
1923    return ( this->attrs ) ? this->nattr : 0;
1924 }
1925 
astXmlGetNitem_(AstXmlElement * this,int * status)1926 int astXmlGetNitem_( AstXmlElement *this, int *status ){
1927 /*
1928 *+
1929 *  Name:
1930 *     astXmlGetNitem
1931 
1932 *  Purpose:
1933 *     Return the number of items within the content of an element.
1934 
1935 *  Type:
1936 *     Protected function.
1937 
1938 *  Synopsis:
1939 *     #include "xml.h"
1940 *     int astXmlGetNitem( AstXmlElement *this )
1941 
1942 *  Description:
1943 *     This function returns the number of items within the content of an
1944 *     XmlElement.
1945 
1946 *  Parameters:
1947 *     this
1948 *        The pointer to the XmlElement.
1949 
1950 *  Returned Value:
1951 *     The number of items in the content of the supplied element.
1952 
1953 *  Notes:
1954 *     - Zero is returned if an error has already occurred, or if this
1955 *     function should fail for any reason.
1956 *-
1957 */
1958 
1959 /* Check the global error status. */
1960    if( !astOK ) return 0;
1961 
1962 /* Return the result. */
1963    return this->nitem;
1964 }
1965 
astXmlGetParent_(AstXmlObject * this,int * status)1966 AstXmlParent *astXmlGetParent_( AstXmlObject *this, int *status ){
1967 /*
1968 *+
1969 *  Name:
1970 *     astXmlGetParent
1971 
1972 *  Purpose:
1973 *     Return a pointer to the object which contains the supplied XmlObject.
1974 
1975 *  Type:
1976 *     Protected function.
1977 
1978 *  Synopsis:
1979 *     #include "xml.h"
1980 *     AstXmlParent *astXmlGetParent( AstXmlObject *this )
1981 
1982 *  Description:
1983 *     This function returns a pointer to the XmlParent object (either an
1984 *     XmlElement or an XmlDocument) which contains the specified XmlObject.
1985 *     The object can be a content item (an element, a comment, a CDATA
1986 *     section, a PI, or character data) in which case the enclosing
1987 *     XmlElement is returned, or an attribute or namespace definition in
1988 *     which case the XmlElement to which object refers is returned.
1989 *     If "this" is the root element of a document, a pointer to the
1990 *     XmlDocument is returned.
1991 
1992 
1993 *  Parameters:
1994 *     this
1995 *        The pointer to check.
1996 
1997 *  Returned Value:
1998 *     Pointer to the parent, or NULL if the object does not have a parent.
1999 
2000 *  Notes:
2001 *     - NULL is returned if an error has already occurred, or if this
2002 *     function should fail for any reason.
2003 *-
2004 */
2005 
2006 /* Check the global error status. */
2007    if( !astOK ) return NULL;
2008 
2009 /* Return the result. */
2010    return this->parent;
2011 }
2012 
astXmlGetRoot_(AstXmlObject * this,int * status)2013 AstXmlObject *astXmlGetRoot_( AstXmlObject *this, int *status ){
2014 /*
2015 *+
2016 *  Name:
2017 *     astXmlGetRoot
2018 
2019 *  Purpose:
2020 *     Return a pointer to the root XmlObject which contains the supplied
2021 *     XmlObject.
2022 
2023 *  Type:
2024 *     Protected function.
2025 
2026 *  Synopsis:
2027 *     #include "xml.h"
2028 *     AstXmlObject *astXmlGetRoot( AstXmlObject *this )
2029 
2030 *  Description:
2031 *     This function returns a pointer to the XmlObject which is the root of
2032 *     the tree containing the specified XmlObject. A pointer to the
2033 *     supplied XmlObject is returned if it has no parent.
2034 
2035 *  Parameters:
2036 *     this
2037 *        The pointer to check.
2038 
2039 *  Returned Value:
2040 *     Pointer to the root XmlObject, or a copy of the supplied pointer if
2041 *     the supplied XmlObject is the root.
2042 
2043 *  Notes:
2044 *     - NULL is returned if an error has already occurred, or if this
2045 *     function should fail for any reason.
2046 *-
2047 */
2048 
2049 /* Local Variables:  */
2050    AstXmlObject *result;
2051 
2052 /* Initialise */
2053    result = NULL;
2054 
2055 /* Check the global error status. */
2056    if( !astOK ) return result;
2057 
2058 /* If "this" is a document, check it has no parent. If not, return a
2059    pointer ot it. */
2060    if( astXmlCheckType( this, AST__XMLDOC ) ) {
2061       if( this->parent ) {
2062          astError( AST__INTER, "astXmlGetRoot(xml): An XmlDocument has a "
2063                    "non-null parent of type %ld (internal AST programming "
2064                    "error).", status, this->type );
2065       } else {
2066          result = (AstXmlObject *) this;
2067       }
2068 
2069 /* Otherwise... */
2070    } else if( this->parent ) {
2071       result = astXmlGetRoot( this->parent );
2072 
2073    } else {
2074       result = this;
2075    }
2076 
2077 /* Return the result. */
2078    return result;
2079 }
2080 
astXmlGetTag_(AstXmlObject * this,int opening,int * status)2081 const char *astXmlGetTag_( AstXmlObject *this, int opening, int *status ){
2082 /*
2083 *+
2084 *  Name:
2085 *     astXmlGetTag
2086 
2087 *  Purpose:
2088 *     Returns a string holding an XML tag describing the given XmlObject.
2089 
2090 *  Type:
2091 *     Protected function.
2092 
2093 *  Synopsis:
2094 *     #include "xml.h"
2095 *     const char *astXmlGetTag( AstXmlObject *this, int opening )
2096 
2097 *  Description:
2098 *     This function returns a pointer to a static string containing an
2099 *     XML tag describing the given XmlObject.
2100 
2101 *  Parameters:
2102 *     this
2103 *        Pointer to the XmlObject.
2104 *     opening
2105 *        Indicates which tag is to be returned; the start tag or the end
2106 *        tag. If non-zero the start tag is returned. Otherwise, the
2107 *        end tag is returned. If the supplied XmlObject has no end
2108 *        tag (i.e. if it is an empty element, or if it is not an element),
2109 *        then NULL is returned but no error is reported.
2110 
2111 *  Returned Value:
2112 *     Pointer to a null terminated string holding the tag. If the tag
2113 *     exceeds 200 characters, only the first 197 characters are returned
2114 *     and "..." is appended to the end.
2115 
2116 *  Notes:
2117 *     - Subsequent invocations of this function will over-write the
2118 *     buffer which used to hold the returned string.
2119 *     - Empty elements are represented as an start tag of the form <.../>,
2120 *     with no corresponding end tag.
2121 *     - NULL is returned if an error has already occurred, or if this
2122 *     function should fail for any reason.
2123 *-
2124 */
2125 
2126 /* Local Variables: */
2127    astDECLARE_GLOBALS        /* Pointer to thread-specific global data */
2128    char *result;             /* The returned pointer */
2129 
2130 /* Initialise */
2131    result = NULL;
2132 
2133 /* Check the global error status. */
2134    if( !astOK ) return result;
2135 
2136 /* If needed, get a pointer to the thread specific global data structure. */
2137    astGET_GLOBALS(NULL);
2138 
2139 /* Get a dynamic string holding the formatted tag. */
2140    result = FormatTag( this, opening, status );
2141 
2142 /* If OK, copy the result into the static buffer. */
2143    gettag_buff[ 0 ] = 0;
2144    if( result ) {
2145       if( astOK ) {
2146 
2147          if( strlen( result ) > AST__XML_GETTAG_BUFF_LEN ) {
2148             strncpy( gettag_buff, result, AST__XML_GETTAG_BUFF_LEN -3 );
2149             strcpy( gettag_buff + AST__XML_GETTAG_BUFF_LEN - 3, "..." );
2150          } else {
2151             strncpy( gettag_buff, result, AST__XML_GETTAG_BUFF_LEN );
2152          }
2153 
2154          gettag_buff[ AST__XML_GETTAG_BUFF_LEN ] = 0;
2155          astFree( result );
2156          result = gettag_buff;
2157       } else {
2158          result = astFree( result );
2159       }
2160    }
2161 
2162 /* Return the result. */
2163    return result;
2164 }
2165 
astXmlGetType_(AstXmlObject * this,int * status)2166 const char *astXmlGetType_( AstXmlObject *this, int *status ){
2167 /*
2168 *+
2169 *  Name:
2170 *     astXmlGetType
2171 
2172 *  Purpose:
2173 *     Returns a string holding the type of the given XmlObject.
2174 
2175 *  Type:
2176 *     Protected function.
2177 
2178 *  Synopsis:
2179 *     #include "xml.h"
2180 *     const char *astXmlGetType( AstXmlObject *this )
2181 
2182 *  Description:
2183 *     This function returns a pointer to a static string containing the
2184 *     type of the given XmlObject.
2185 
2186 *  Parameters:
2187 *     this
2188 *        Pointer to the XmlObject.
2189 
2190 *  Returned Value:
2191 *     Pointer to a null terminated string holding the type string.
2192 
2193 *  Notes:
2194 *     - NULL is returned if an error has already occurred, or if this
2195 *     function should fail for any reason.
2196 *-
2197 */
2198 
2199 /* Local Variables: */
2200    const char *result;             /* The returned pointer */
2201    int type;                       /* Element type */
2202 
2203 /* Initialise */
2204    result = NULL;
2205 
2206 /* Check the global error status. */
2207    if( !astOK ) return result;
2208 
2209    type = this->type;
2210    if( type == AST__XMLELEM ) {
2211       result = "element";
2212 
2213    } else if( type == AST__XMLATTR ) {
2214       result = "attribute";
2215 
2216    } else if( type == AST__XMLCDATA ) {
2217       result = "CDATA section";
2218 
2219    } else if( type == AST__XMLCOM ) {
2220       result = "comment";
2221 
2222    } else if( type == AST__XMLPI ) {
2223       result = "processing instruction";
2224 
2225    } else if( type == AST__XMLNAME ) {
2226       result = "namespace";
2227 
2228    } else if( type == AST__XMLDOC ) {
2229       result = "document";
2230 
2231    } else if( type == AST__XMLPRO ) {
2232       result = "prologue";
2233 
2234    } else if( type == AST__XMLDEC ) {
2235       result = "XML delaration PI";
2236 
2237    } else if( type == AST__XMLDTD ) {
2238       result = "DTD";
2239 
2240    } else if( type == AST__XMLWHITE ) {
2241       result = "white-space character data ";
2242 
2243    } else if( type == AST__XMLBLACK ) {
2244       result = "non-blank character data";
2245 
2246    } else {
2247       result = "unknown XML object";
2248    }
2249 
2250 /* Return the result. */
2251    return result;
2252 }
2253 
astXmlGetURI_(AstXmlObject * this,int * status)2254 const char *astXmlGetURI_( AstXmlObject *this, int *status ){
2255 /*
2256 *+
2257 *  Name:
2258 *     astXmlGetURI
2259 
2260 *  Purpose:
2261 *     Return a pointer to a string holding the namespace URI of an XmlObject.
2262 
2263 *  Type:
2264 *     Protected function.
2265 
2266 *  Synopsis:
2267 *     #include "xml.h"
2268 *     const char *astXmlGetURI( AstXmlObject *this )
2269 
2270 *  Description:
2271 *     This function returns a pointer to a constant string holding the
2272 *     namespace URI associated with an XmlObject. Only attributes,
2273 *     elements and namespaces have associated URIs, so a NULL pointer is
2274 *     returned for any other class of XmlObject. A NULL pointer is also
2275 *     returned if XmlObject does not belong to any namespace, or if it
2276 *     belongs to a unknown namespace (i.e. one for which no URI is
2277 *     available). Any namespace prefix attached to the supplied object is
2278 *     resolved first using any "xmlns" attributes contained in the same
2279 *     element, then using any "xmlns" attributes contained in the parent
2280 *     element, etc.
2281 
2282 *  Parameters:
2283 *     this
2284 *        The pointer to the XmlObject.
2285 
2286 *  Returned Value:
2287 *     Pointer to a string holding the namespace URI, or NULL.
2288 
2289 *  Notes:
2290 *     - NULL is returned if an error has already occurred, or if this
2291 *     function should fail for any reason.
2292 *-
2293 */
2294 
2295 /* Local Variables: */
2296    const char *prefix;     /* Namespace prefix */
2297    const char *result;     /* Returned pointer */
2298    int type;               /* Object type */
2299 
2300 /* Initialise */
2301    result = NULL;
2302 
2303 /* Check the global error status. */
2304    if( !astOK ) return result;
2305 
2306 /* Do each type of object separately. */
2307    type = this->type;
2308    if( type == AST__XMLATTR ){
2309       prefix = ( (AstXmlAttribute *) this )->prefix;
2310 
2311 /* Attributes have no default name space. Therefore if there is no prefix,
2312    return NULL. If there is a prefix, resolve it within the context of
2313    the attributes parent element. */
2314       if( prefix ) {
2315          result = ResolvePrefix( prefix, (AstXmlElement *) this->parent, status );
2316       }
2317 
2318    } else if( type == AST__XMLELEM ){
2319       prefix = ( (AstXmlElement *) this )->prefix;
2320 
2321 /* If there is a prefix, resolve it within the context of this element. */
2322       if( prefix ) {
2323          result = ResolvePrefix( prefix, (AstXmlElement *) this, status );
2324 
2325 /* Elements do have a default name space. Therefore if there is no prefix,
2326    return the default name space within the context of this element. */
2327       } else {
2328          result = DefaultURI( (AstXmlElement *) this, status );
2329       }
2330 
2331 /* If the supplied object is a namespace, just return the associated URI. */
2332    } else if( type == AST__XMLNAME ){
2333       result = ( (AstXmlNamespace *) this )->uri;
2334 
2335    }
2336 
2337 /* Return the result. */
2338    return result;
2339 }
2340 
astXmlGetValue_(AstXmlObject * this,int report,int * status)2341 const char *astXmlGetValue_( AstXmlObject *this, int report, int *status ){
2342 /*
2343 *+
2344 *  Name:
2345 *     astXmlGetValue
2346 
2347 *  Purpose:
2348 *     Return a pointer to a string holding the value of an XmlObject.
2349 
2350 *  Type:
2351 *     Protected function.
2352 
2353 *  Synopsis:
2354 *     #include "xml.h"
2355 *     const char *astXmlGetValue( AstXmlObject *this, int report )
2356 
2357 *  Description:
2358 *     This function returns a pointer to a constant string holding the
2359 *     value associated with an XmlObject. For attributes, the attribute value
2360 *     is returned. For PI elements, the "text" value is returned. For
2361 *     namespace definitions, the "URI" value is returned. For character
2362 *     data, the character data is returned. For CDATA sections the "text"
2363 *     value is returned. For comments, the "text" value is returned.
2364 *     If the XmlObject is an element, then a non-NULL value is returned
2365 *     only if the element contains a single content item holding character
2366 *     data. In this case a pointer to the character data is returned.
2367 *     A null value is returned in all other cases (but no error is
2368 *     reported unless "report" is non-zero).
2369 
2370 *  Parameters:
2371 *     this
2372 *        The pointer to the XmlObject.
2373 *     report
2374 *        Report an error if the supplied XmlObject does not have a value?
2375 
2376 *  Returned Value:
2377 *     Pointer to a string holding the value of the XML object.
2378 
2379 *  Notes:
2380 *     - NULL is returned if an error has already occurred, or if this
2381 *     function should fail for any reason.
2382 *-
2383 */
2384 
2385 /* Local Variables: */
2386    AstXmlContentItem *item;/* Element content */
2387    const char *result;     /* Returned pointer */
2388    int type;               /* Object type */
2389 
2390 /* Initialise */
2391    result = NULL;
2392 
2393 /* Check the global error status. */
2394    if( !astOK ) return result;
2395 
2396 /* Return the relevant component of the structure, depending on its type. */
2397    type = this->type;
2398    if( type == AST__XMLATTR ){
2399       result = ( (AstXmlAttribute *) this )->value;
2400 
2401    } else if( type == AST__XMLBLACK ){
2402       result = ( (AstXmlBlack *) this )->text;
2403 
2404    } else if( type == AST__XMLWHITE ){
2405       result = ( (AstXmlWhite *) this )->text;
2406 
2407    } else if( type == AST__XMLCDATA ){
2408       result = ( (AstXmlCDataSection *) this )->text;
2409 
2410    } else if( type == AST__XMLCOM ){
2411       result = ( (AstXmlComment *) this )->text;
2412 
2413    } else if( type == AST__XMLPI ){
2414       result = ( (AstXmlPI *) this )->text;
2415 
2416    } else if( type == AST__XMLNAME ){
2417       result = ( (AstXmlNamespace *) this )->uri;
2418 
2419    } else if( type == AST__XMLELEM ){
2420       if( astXmlGetNitem( (AstXmlElement *) this ) == 1 ) {
2421          item = astXmlGetItem( (AstXmlElement *) this, 0 );
2422          if( astXmlCheckType( item, AST__XMLCHAR ) ) {
2423             result = astXmlGetValue( item, report );
2424          }
2425       }
2426 
2427       if( !result && astOK && report ) {
2428          astError( AST__BADIN, "astRead(xml): Cannot get the value of "
2429                    "element \"<%s>\": its contents are not pure character "
2430                    "data.", status, astXmlGetName( this ) );
2431       }
2432 
2433    } else if( report ) {
2434       astError( AST__INTER, "astXmlGetValue(xml): Cannot get the value of "
2435                 "an XmlObject of type %d (internal AST programming "
2436                 "error).", status, type );
2437    }
2438 
2439 /* Return the result. */
2440    return result;
2441 }
2442 
astXmlInsertElement_(AstXmlElement * this,AstXmlElement * elem,int * status)2443 void astXmlInsertElement_( AstXmlElement *this, AstXmlElement *elem, int *status ){
2444 /*
2445 *+
2446 *  Name:
2447 *     astXmlInsertElement
2448 
2449 *  Purpose:
2450 *     Inserts an existing XmlElement into another XmlElement.
2451 
2452 *  Type:
2453 *     Protected function.
2454 
2455 *  Synopsis:
2456 *     #include "xml.h"
2457 *     void astXmlInsertElement( AstXmlElement *this, AstXmlElement *elem )
2458 
2459 *  Description:
2460 *     This function inserts a given XmlElement "elem" into another given
2461 *     XmlElement "this". An error is reported if "elem" already has a
2462 *     parent.
2463 
2464 *  Parameters:
2465 *     this
2466 *        A pointer to the element to be modified.
2467 *     elem
2468 *        The element to be inserted into "this".
2469 
2470 *-
2471 */
2472 
2473 /* Check the global error status. */
2474    if( !astOK ) return;
2475 
2476 /* Report AN error if "elem" has already been inserted into
2477    another element. */
2478    if( ((AstXmlObject *) elem)->parent ) {
2479       astError( AST__INTER, "astXmlInsertElement(xml): Cannot insert \"%s\" "
2480                 "into \"%s\" because it already has a parent (\"%s\") "
2481                 "(internal AST programming error).", status,
2482                 astXmlGetTag( elem, 1 ), astXmlGetTag( this, 1 ),
2483                 astXmlGetTag( ((AstXmlObject *) elem)->parent, 1 ) );
2484 
2485 /* Otherwise, add the content item to the element. */
2486    } else {
2487       AddContent( (AstXmlParent *) this, 0, (AstXmlContentItem *) elem, status );
2488    }
2489 }
2490 
astXmlPurge_(AstXmlParent * this,int * status)2491 void astXmlPurge_( AstXmlParent *this, int *status ) {
2492 /*
2493 *+
2494 *  Name:
2495 *     astXmlPurge
2496 
2497 *  Purpose:
2498 *     Remove blank content from a parent object.
2499 
2500 *  Type:
2501 *     Protected function.
2502 
2503 *  Synopsis:
2504 *     #include "xml.h"
2505 *     void astXmlPurge( AstXmlParent *this )
2506 
2507 *  Description:
2508 *     This function removes all character data containing only whitespace
2509 *     from the supplied document or element. It is recursive, in that it also
2510 *     removes white space from all children elements.
2511 
2512 *  Parameters:
2513 *     this
2514 *        Pointer to the document or element.
2515 
2516 *-
2517 */
2518 
2519 /* Local Variables: */
2520    int i;                    /* Content item index */
2521    AstXmlContentItem *item;  /* Next content item */
2522    AstXmlMiscItem *misc;     /* Nest miscalleneous item */
2523    AstXmlDocument *doc;      /* This document */
2524    AstXmlPrologue *pro;      /* This document prologue */
2525    AstXmlElement *elem;      /* This element */
2526 
2527 /* Check the global error status. */
2528    if( !astOK || !this ) return;
2529 
2530 /* If this is a a document.. */
2531    if( astXmlCheckType( this, AST__XMLDOC ) ) {
2532       doc = (AstXmlDocument *) this;
2533       astXmlPurge( doc->prolog );
2534       astXmlPurge( doc->root );
2535 
2536       i = -1;
2537       while( ++i < doc->nepi ) {
2538          misc = doc->epilog[ i ];
2539          if( astXmlCheckType( misc, AST__XMLWHITE ) ) {
2540             misc = astXmlDelete( misc );
2541             i--;
2542          }
2543       }
2544 
2545 /* If this is a prologue.. */
2546    } else if( astXmlCheckType( this, AST__XMLPRO ) ) {
2547       pro = (AstXmlPrologue *) this;
2548 
2549       i = -1;
2550       while( ++i < pro->nmisc1 ) {
2551          misc = pro->misc1[ i ];
2552          if( astXmlCheckType( misc, AST__XMLWHITE ) ) {
2553             misc = astXmlDelete( misc );
2554             i--;
2555          }
2556       }
2557 
2558       i = -1;
2559       while( ++i < pro->nmisc2 ) {
2560          misc = pro->misc2[ i ];
2561          if( astXmlCheckType( misc, AST__XMLWHITE ) ) {
2562             misc = astXmlDelete( misc );
2563             i--;
2564          }
2565       }
2566 
2567 
2568 /* If this is an element */
2569    } else if( astXmlCheckType( this, AST__XMLELEM ) ) {
2570       elem = (AstXmlElement *) this;
2571 
2572       i = -1;
2573       while( ++i < elem->nitem ) {
2574          item = elem->items[ i ];
2575 
2576          if( astXmlCheckType( item, AST__XMLWHITE ) ) {
2577             item = astXmlDelete( item );
2578             i--;
2579 
2580          } else if( astXmlCheckType( item, AST__XMLELEM ) ) {
2581             astXmlPurge( (AstXmlParent *) item );
2582          }
2583       }
2584    }
2585 }
2586 
astXmlRemoveAttr_(AstXmlElement * this,const char * name,const char * prefix,int * status)2587 void astXmlRemoveAttr_( AstXmlElement *this, const char *name,
2588                         const char *prefix, int *status ){
2589 /*
2590 *+
2591 *  Name:
2592 *     astXmlRemoveAttr
2593 
2594 *  Purpose:
2595 *     Removes an attribute from its parent element.
2596 
2597 *  Type:
2598 *     Protected function.
2599 
2600 *  Synopsis:
2601 *     #include "xml.h"
2602 *     void astXmlRemoveAttr( AstXmlElement *this, const char *name,
2603 *                            const char *prefix )
2604 
2605 *  Description:
2606 *     This function removes a named attribute from its parent element.
2607 
2608 *  Parameters:
2609 *     this
2610 *        The pointer to the element containing the attribute to be removed.
2611 *     name
2612 *        Pointer to a null terminated string containing the attribute name.
2613 *     prefix
2614 *        The namespace prefix for the attribute. May be NULL or blank, in
2615 *        which case any prefix at the start of "name" is used.
2616 *-
2617 */
2618 
2619 /* Local Variables: */
2620    AstXmlAttribute *attr;           /* Pointer to temporary attribute structure */
2621    AstXmlAttribute *oldattr;        /* Pointer to existing attribute */
2622    int i;                           /* Attribute index */
2623    int nattr;                       /* Number of attributes in parent */
2624    int oldi;                        /* Indexof existing attribute */
2625 
2626 /* Check the global error status. */
2627    if( !astOK ) return;
2628 
2629 /* Initialise */
2630    oldattr = NULL;
2631 
2632 /* Create a new XmlAttribute with blank value. */
2633    attr = NewAttribute( name, "", prefix, status );
2634    if( astOK ) {
2635 
2636 /* Get the number of attributes currently stored in the element. */
2637       nattr = ( this->attrs ) ? this->nattr : 0;
2638 
2639 /* Search the existing attributes to see if an attribute with the given
2640    name and prefix already exists. */
2641       oldi = -1;
2642       for( i = 0; i < nattr; i++ ) {
2643          oldattr = this->attrs[ i ];
2644          if( !strcmp( oldattr->name, attr->name ) ) {
2645             if( !oldattr->prefix && !attr->prefix ) {
2646                oldi = i;
2647                break;
2648             } else if( oldattr->prefix && attr->prefix &&
2649                        !strcmp( oldattr->prefix, attr->prefix ) ){
2650                oldi = i;
2651                break;
2652             }
2653          }
2654       }
2655 
2656 /* If there is an existing attribute with the same name and prefix,
2657    delete it. */
2658       if( oldi > -1 ) astXmlDelete( oldattr );
2659 
2660 /* Delete the temporary attribute structure. */
2661       attr = astXmlDelete( attr );
2662 
2663    }
2664 }
2665 
astXmlRemoveItem_(AstXmlContentItem * this,int * status)2666 void astXmlRemoveItem_( AstXmlContentItem *this, int *status ){
2667 /*
2668 *+
2669 *  Name:
2670 *     astXmlRemoveItem
2671 
2672 *  Purpose:
2673 *     Removes an item of content from its parent element or document.
2674 
2675 *  Type:
2676 *     Protected function.
2677 
2678 *  Synopsis:
2679 *     #include "xml.h"
2680 *     void astXmlRemoveItem( AstXmlContentItem *this )
2681 
2682 *  Description:
2683 *     This function removes an item of content from its parent element,
2684 *     or removes the root element from a document. The removed item is not
2685 *     annulled and may be subsequently added into another element.
2686 
2687 *  Parameters:
2688 *     this
2689 *        The pointer to the item to be removed form its parent.
2690 *-
2691 */
2692 
2693 /* Local Variables: */
2694    AstXmlDocument *doc;             /* Pointer to parent document */
2695    AstXmlElement *elem;             /* Pointer to parent element */
2696    AstXmlParent *parent;            /* Pointer to parent */
2697    int found;                       /* Was the item found within its parent? */
2698    int i;                           /* Item index */
2699    int j;                           /* Item index */
2700 
2701 /* Check the global error status. */
2702    if( !astOK ) return;
2703 
2704 /* Get a pointer to the items parent element, and check it is not null. */
2705    parent = ( (AstXmlObject *) this )->parent;
2706    if( parent && astXmlCheckType( parent, AST__XMLELEM ) ) {
2707       elem = (AstXmlElement *) parent;
2708 
2709 /* Search through all the items within the parent element looking for the
2710    supplied item. */
2711       found = 0;
2712       for( i = 0; i < elem->nitem; i++ ) {
2713          if( elem->items[ i ] == this ) {
2714 
2715 /* When found, decrement the number of items in the element, and shuffle
2716    all the remaining item pointers down one slot to over-write it, then
2717    nullify the parent pointer in the supplied object and leave the loop. */
2718             (elem->nitem)--;
2719             for( j = i; j < elem->nitem; j++ ) {
2720                elem->items[ j ] = elem->items[ j + 1 ];
2721             }
2722             ( (AstXmlObject *) this )->parent = NULL;
2723             found = 1;
2724             break;
2725          }
2726       }
2727 
2728 /* Report an error if the item was not found. */
2729       if( !found ) {
2730          astError( AST__INTER, "astXmlRemoveItem: The parent of the supplied "
2731                    "item does not contain the item (internal AST programming "
2732                    "error)." , status);
2733       }
2734 
2735 /* If the parent is an XmlDocument, check the item being removed is the
2736    root element. */
2737    } else if( parent && astXmlCheckType( parent, AST__XMLDOC ) ) {
2738       doc = (AstXmlDocument *) parent;
2739       if( (AstXmlElement *) this == doc->root ) {
2740          ( (AstXmlObject *) this )->parent = NULL;
2741          doc->root = NULL;
2742       }
2743    }
2744 }
2745 
astXmlRemoveURI_(AstXmlElement * this,const char * prefix,int * status)2746 void astXmlRemoveURI_( AstXmlElement *this, const char *prefix, int *status ){
2747 /*
2748 *+
2749 *  Name:
2750 *     astXmlRemoveURI
2751 
2752 *  Purpose:
2753 *     Removes an namespace prefix from its parent element.
2754 
2755 *  Type:
2756 *     Protected function.
2757 
2758 *  Synopsis:
2759 *     #include "xml.h"
2760 *     void astXmlRemoveURI( AstXmlElement *this, const char *prefix )
2761 
2762 *  Description:
2763 *     This function removes a named namespace prefix from its parent element.
2764 
2765 *  Parameters:
2766 *     this
2767 *        The pointer to the element containing the namespace prefix to be
2768 *        removed.
2769 *     prefix
2770 *        The namespace prefix to remove.
2771 *-
2772 */
2773 
2774 /* Local Variables: */
2775    AstXmlNamespace *ns;             /* Temporary namespace structure */
2776    AstXmlNamespace *oldns;          /* Pointer to existing namespace */
2777    int oldi;                        /* Index of namespace within its parent */
2778    int i;                           /* Namespace index */
2779    int nns;                         /* Number of existing namespaces */
2780 
2781 /* Check the global error status. */
2782    if( !astOK ) return;
2783 
2784 /* Initialise */
2785     oldns = NULL;
2786 
2787 /* Create a new XmlNamespace with blank URI. */
2788    ns = NewNamespace( prefix, "", status );
2789    if( astOK ) {
2790 
2791 /* Get the number of namespace prefixes currently stored in the element. */
2792       nns = ( this->nsprefs ) ? this->nnspref : 0;
2793 
2794 /* Search the list of existing namespace prefixes to see if the given prefix
2795    is included. */
2796       oldi = -1;
2797       for( i = 0; i < nns; i++ ) {
2798          oldns = this->nsprefs[ i ];
2799          if( !strcmp( oldns->prefix, ns->prefix ) ){
2800              oldi = i;
2801              break;
2802          }
2803       }
2804 
2805 /* If the supplied namespace prefix was found in the list, delete it. */
2806       if( oldi > -1 ) astXmlDelete( oldns );
2807 
2808 /* Delete the temporary namespace structure. */
2809       ns = astXmlDelete( ns );
2810 
2811    }
2812 }
2813 
astXmlSetDTDec_(AstXmlDocument * this,const char * text1,const char * text2,const char * text3,int * status)2814 void astXmlSetDTDec_( AstXmlDocument *this, const char *text1,
2815                       const char *text2, const char *text3, int *status ){
2816 /*
2817 *+
2818 *  Name:
2819 *     astXmlSetDTDec
2820 
2821 *  Purpose:
2822 *     Set the Document Type declaration for a document.
2823 
2824 *  Type:
2825 *     Protected function.
2826 
2827 *  Synopsis:
2828 *     #include "xml.h"
2829 *     void astXmlSetDTDEC( AstXmlDocument *this, const char *text1,
2830 *                          const char *text2, const char *text3 )
2831 
2832 *  Description:
2833 *     This function stores an Document Type declaration of the form
2834 *
2835 *        <!DOCTYPE text1 text2 [text3]>
2836 *
2837 *     in the supplied document. Any previous DTD is removed.
2838 
2839 *  Parameters:
2840 *     this
2841 *        The pointer to the document.
2842 *     text1
2843 *        The document type name.
2844 *     text2
2845 *        The text defining the external elements of the document type
2846 *        (may be NULL).
2847 *     text3
2848 *        The text defining the internal elements of the document type
2849 *        (may be NULL). Do not include delimiting "[" and "]" characters.
2850 *-
2851 */
2852 
2853 /* Local Variables: */
2854    AstXmlDTDec *new;             /* Pointer to new DT declaration */
2855    AstXmlPrologue *pro;          /* Pointer to prologue */
2856    char *my_text2;               /* Cleaned text2 */
2857    char *my_text3;               /* Cleaned text3 */
2858 
2859 /* Check the global error status. */
2860    if( !astOK ) return;
2861 
2862 /* Allocate space for the new structure. */
2863    new = (AstXmlDTDec *) astMalloc( sizeof( AstXmlDTDec ) );
2864 
2865 /* Clean the text. */
2866    my_text2 = CleanText( text2, status );
2867    my_text3 = CleanText( text3, status );
2868 
2869 /* Initialise it. */
2870    InitXmlDTDec( new, AST__XMLDTD, text1, my_text2, my_text3, status );
2871 
2872 /* Free the memory */
2873    my_text2 = astFree( my_text2 );
2874    my_text3 = astFree( my_text3 );
2875 
2876 /* If an error occurred, delete the new structure. */
2877    if( !astOK ) {
2878       new = astXmlDelete( new );
2879 
2880 /* Otherwise, store it in the document, deleting any existing declaration
2881    first. */
2882    } else {
2883 
2884 /* Create a prologue if necessary. */
2885       if( !this->prolog ) this->prolog = NewPrologue( this, status );
2886 
2887       pro = this->prolog;
2888       if( pro->dtdec ) astXmlDelete( pro->dtdec );
2889       pro->dtdec = new;
2890    }
2891 }
2892 
astXmlSetXmlDec_(AstXmlDocument * this,const char * text,int * status)2893 void astXmlSetXmlDec_( AstXmlDocument *this, const char *text, int *status ){
2894 /*
2895 *+
2896 *  Name:
2897 *     astXmlSetXmlDec
2898 
2899 *  Purpose:
2900 *     Set the XML declaration for a document.
2901 
2902 *  Type:
2903 *     Protected function.
2904 
2905 *  Synopsis:
2906 *     #include "xml.h"
2907 *     void astXmlSetXmlDec( AstXmlDocument *this, const char *text )
2908 
2909 *  Description:
2910 *     This function stores an XML declaration of the form
2911 *
2912 *        <?xml [text]?>
2913 *
2914 *     in the supplied document. Any previous XML declaration is removed.
2915 
2916 *  Parameters:
2917 *     this
2918 *        The pointer to the document.
2919 *     text
2920 *        The text to include in the XML declaration tag.
2921 *-
2922 */
2923 
2924 /* Local Variables: */
2925    AstXmlDeclPI *new;             /* Pointer to new XML delcaration */
2926    AstXmlPrologue *pro;           /* Pointer to prologue */
2927    char *my_text;                 /* Cleaned text */
2928 
2929 /* Check the global error status. */
2930    if( !astOK ) return;
2931 
2932 /* Allocate space for the new structure. */
2933    new = (AstXmlDeclPI *) astMalloc( sizeof( AstXmlDeclPI ) );
2934 
2935 /* Clean the text. */
2936    my_text = CleanText( text, status );
2937 
2938 /* Initialise it. */
2939    InitXmlDeclPI( new, AST__XMLDEC, my_text, status );
2940 
2941 /* Free the memory */
2942    my_text = astFree( my_text );
2943 
2944 /* If an error occurred, delete the new structure. */
2945    if( !astOK ) {
2946       new = astXmlDelete( new );
2947 
2948 /* Otherwise, store it in the document, deleting any existing declaration
2949    first. */
2950    } else {
2951 
2952 /* Create a prologue if necessary. */
2953       if( !this->prolog ) this->prolog = NewPrologue( this, status );
2954 
2955       pro = this->prolog;
2956       if( pro->xmldecl ) astXmlDelete( pro->xmldecl );
2957       pro->xmldecl = new;
2958    }
2959 }
2960 
astXmlShow_(AstXmlObject * this,int * status)2961 const char *astXmlShow_( AstXmlObject *this, int *status ) {
2962 /*
2963 *+
2964 *  Name:
2965 *     astXmlShow
2966 
2967 *  Purpose:
2968 *     Converts an XmlObject into a character string with indentation.
2969 
2970 *  Type:
2971 *     Protected function.
2972 
2973 *  Synopsis:
2974 *     #include "xml.h"
2975 *     const char *astXmlShow( AstXmlObject *this )
2976 
2977 *  Description:
2978 *     This function returns a pointer to a dynamically allocated string
2979 *     containing a textual representation of the supplied XmlObject.
2980 *     Newline characters are added to the string if needed to ensure that
2981 *     each item of content within an element starts on a new line, and all
2982 *     tags are preceded by an indentation string consisting of a number
2983 *     of spaces.
2984 
2985 *  Parameters:
2986 *     this
2987 *        Pointer to the XmlObject to format.
2988 
2989 *  Returned Value:
2990 *     Pointer to a null terminated string holding the formated XmlObject.
2991 *     This string should be freed when no longer needed using astFree.
2992 
2993 *  Notes:
2994 *     - NULL is returned if a NULL pointer is supplied.
2995 *     - NULL is returned if an error has already occurred, or if this
2996 *     function should fail for any reason.
2997 *-
2998 */
2999    return Format( this, 0, status );
3000 }
3001 
CheckName(const char * name,const char * noun,const char * method,int nullok,int * status)3002 static void CheckName( const char *name, const char *noun, const char *method,
3003                        int nullok, int *status ){
3004 /*
3005 *  Name:
3006 *     CheckName
3007 
3008 *  Purpose:
3009 *     Checks the supplied string is a valid XML name.
3010 
3011 *  Type:
3012 *     Private function.
3013 
3014 *  Synopsis:
3015 *     #include "xml.h"
3016 *     void CheckName( const char *name, const char *noun, const char *method,
3017 *                     int nullok, int *status )
3018 
3019 *  Description:
3020 *     This function checks that the supplied string is a valid XML name,
3021 *     and reports an error otherwise.
3022 
3023 *  Parameters:
3024 *     name
3025 *        The name string to check
3026 *     noun
3027 *        A word to describe the object which the name applies to - for use in
3028 *        error messages only.
3029 *     method
3030 *        The name of the calling method - for use in error messages only.
3031 *     nullok
3032 *        If non-zero, then a null or empty name is assumed to be
3033 *        acceptable.
3034 *     status
3035 *        Pointer to the inherited status variable.
3036 */
3037 
3038 /* Local Variables: */
3039    const char *c;       /* Pointer to next character to check */
3040 
3041 /* Check the global error status. */
3042    if( !astOK ) return;
3043 
3044 /* Check the string is not null. */
3045    if( !name ) {
3046       if( !nullok ) astError( AST__XMLNM, "%s: A NULL pointer was supplied "
3047                               "instead of an XML %s name.", status, method, noun );
3048    } else {
3049 
3050       c = name;
3051       if( *c == 0 ) {
3052          if( !nullok ) astError( AST__XMLNM, "%s: An empty string was supplied "
3053                                  "instead of an XML %s name.", status, method, noun );
3054       } else {
3055 
3056          if( !isalpha( *c ) && *c != '_' ) {
3057             astError( AST__XMLNM, "%s: The illegal XML %s name \"%s\" was "
3058                       "encountered.", status, method, noun, name );
3059 
3060          } else {
3061             while( *(++c) ) {
3062                if( !isalnum( *c ) && *c != '_' && *c != '-' && *c != '.' ){
3063                   astError( AST__XMLNM, "%s: The illegal XML %s name \"%s\" was "
3064                             "encountered.", status, method, noun, name );
3065                   break;
3066                }
3067             }
3068          }
3069       }
3070    }
3071 }
3072 
CheckPrefName(char * name,const char * noun,const char * method,int * status)3073 static void CheckPrefName( char *name, const char *noun, const char *method, int *status ){
3074 /*
3075 *  Name:
3076 *     CheckPrefName
3077 
3078 *  Purpose:
3079 *     Checks the supplied string is a valid XML (prefix:)name.
3080 
3081 *  Type:
3082 *     Private function.
3083 
3084 *  Synopsis:
3085 *     #include "xml.h"
3086 *     void CheckPrefName( char *name, const char *noun, const char *method, int *status )
3087 
3088 *  Description:
3089 *     This function checks that the supplied string is a valid XML
3090 *     (prefix:)name combination and reports an error otherwise.
3091 
3092 *  Parameters:
3093 *     name
3094 *        The string to check
3095 *     noun
3096 *        A word to describe the object which the name applies to - for use in
3097 *        error messages only.
3098 *     method
3099 *        The name of the calling method - for use in error messages only.
3100 *     status
3101 *        Pointer to the inherited status variable.
3102 */
3103 
3104 /* Local Variables: */
3105    char *colon;             /* Pointer to first colon */
3106    char *temp;              /* Pointer to temporary string */
3107    int nc;                  /* Length of temporary string */
3108 
3109 /* Check the global error status. */
3110    if( !astOK ) return;
3111 
3112 /* Search for a ":" character. */
3113    colon = strchr( name, ':' );
3114 
3115 /* If found, temporarily convert the colon into a null so that it
3116    terminates the prefix string. */
3117    if( colon ) {
3118       *colon = 0;
3119 
3120 /* Check the string before the colon is a valid name. */
3121       temp = NULL;
3122       temp = astAppendString( temp, &nc, noun );
3123       temp = astAppendString( temp, &nc, " prefix" );
3124       CheckName( name, temp, method, 0, status );
3125       temp = astFree( temp );
3126 
3127 /* Restore the colon. */
3128       *colon = ':';
3129 
3130 /* Check the string following the colon is a valid name. */
3131       CheckName( colon + 1, noun, method, 0, status );
3132 
3133 /* If not found, the whole supplied string must be a name. */
3134    } else {
3135       CheckName( name, noun, method, 0, status );
3136    }
3137 }
3138 
CheckType(long int given,long int want,int * status)3139 static int CheckType( long int given, long int want, int *status ){
3140 /*
3141 *  Name:
3142 *     CheckType
3143 
3144 *  Purpose:
3145 *     Check that the supplied type identifies an object of a given class.
3146 
3147 *  Type:
3148 *     Private function.
3149 
3150 *  Synopsis:
3151 *     #include "xml.h"
3152 *     int CheckType( long int given, long int want, int *status )
3153 
3154 *  Description:
3155 *     This function checks that the supplied type identifier identifies
3156 *     a specified class of XML object, or a derived class. A flag is
3157 *     returned indicating if the check succeeds. No error is reported if
3158 *     the check fails.
3159 
3160 *  Parameters:
3161 *     given
3162 *        The type value to be checked.
3163 *     want
3164 *        The type of the required class.
3165 *     status
3166 *        Pointer to the inherited status variable.
3167 
3168 *  Returned Value:
3169 *     Non-zero if the check is passed, zero if not of if an error has
3170 *     already occurred.
3171 
3172 *  Notes:
3173 *     - This function attempts to execute even if the error status is set.
3174 */
3175 
3176 /* Local Variables: */
3177    int result;              /* Returned value */
3178 
3179 /* Initialise */
3180    result = 0;
3181 
3182 /* Check the wanted type is recognised. Report an error if not. */
3183    if( want != AST__XMLOBJECT &&
3184        want != AST__XMLELEM  &&
3185        want != AST__XMLATTR  &&
3186        want != AST__XMLCHAR  &&
3187        want != AST__XMLCDATA &&
3188        want != AST__XMLCOM   &&
3189        want != AST__XMLPI    &&
3190        want != AST__XMLNAME  &&
3191        want != AST__XMLCONT  &&
3192        want != AST__XMLPRO   &&
3193        want != AST__XMLDEC   &&
3194        want != AST__XMLDTD   &&
3195        want != AST__XMLMISC  &&
3196        want != AST__XMLBLACK &&
3197        want != AST__XMLWHITE &&
3198        want != AST__XMLPAR   &&
3199        want != AST__XMLDOC ) {
3200       if( astOK ) {
3201          astError( AST__INTER, "CheckType(Xml): Unsupported XML object "
3202                    "type (%ld) supplied for parameter \"want\" (internal "
3203                    "AST programming error). ", status, want );
3204       }
3205 
3206 /* You should never be given a generic "interface" type since the
3207    "wanted" value comes from the "type" component of an XmlObject (an explicit
3208    class type should always be given). */
3209    } else if( given == AST__XMLPAR ||
3210               given == AST__XMLMISC ||
3211               given == AST__XMLCONT ||
3212               given == AST__XMLCHAR ) {
3213       if( astOK ) {
3214          astError( AST__INTER, "CheckType(Xml): Generic type (%ld) supplied for "
3215                    "parameter \"given\" (internal AST programming error).", status,
3216                    given );
3217       }
3218 
3219 /* If the above is OK, return a non-zero value if the type to be tested
3220    equals the wanted type. */
3221    } else if( want == given ) {
3222       result = 1;
3223 
3224 /* If any class of XmlObject is acceptable, check that he given class
3225    type is a valid XML class type. */
3226    } else if( want == AST__XMLOBJECT ) {
3227       result = ( given == AST__XMLELEM  ||
3228                  given == AST__XMLATTR  ||
3229                  given == AST__XMLCDATA ||
3230                  given == AST__XMLCOM   ||
3231                  given == AST__XMLPI    ||
3232                  given == AST__XMLNAME  ||
3233                  given == AST__XMLPRO   ||
3234                  given == AST__XMLDEC   ||
3235                  given == AST__XMLDTD   ||
3236                  given == AST__XMLWHITE ||
3237                  given == AST__XMLBLACK ||
3238                  given == AST__XMLDOC );
3239 
3240 /* Otherwise, for "interface" types, check if the given class "implements
3241    the interface". */
3242    } else if( want == AST__XMLCONT ) {
3243       result = ( given == AST__XMLELEM  ||
3244                  given == AST__XMLBLACK ||
3245                  given == AST__XMLWHITE ||
3246                  given == AST__XMLCDATA ||
3247                  given == AST__XMLCOM   ||
3248                  given == AST__XMLPI    );
3249 
3250    } else if( want == AST__XMLMISC ) {
3251       result = ( given == AST__XMLWHITE ||
3252                  given == AST__XMLCOM   ||
3253                  given == AST__XMLPI    );
3254 
3255    } else if( want == AST__XMLCHAR ) {
3256       result = ( given == AST__XMLWHITE ||
3257                  given == AST__XMLBLACK );
3258 
3259    } else if( want == AST__XMLPAR ) {
3260       result = ( given == AST__XMLDOC ||
3261                  given == AST__XMLPRO ||
3262                  given == AST__XMLELEM );
3263    }
3264 
3265 /* Return the result. */
3266    return result;
3267 }
3268 
astXmlCheckType_(void * this,long int want,int * status)3269 int astXmlCheckType_( void *this, long int want, int *status ){
3270 /*
3271 *+
3272 *  Name:
3273 *     astXmlCheckType
3274 
3275 *  Purpose:
3276 *     Check that the supplied object is of a given class.
3277 
3278 *  Type:
3279 *     Protected function.
3280 
3281 *  Synopsis:
3282 *     #include "xml.h"
3283 *     int astXmlCheckType( void *this, long int want )
3284 
3285 *  Description:
3286 *     This function checks that the supplied XmlObject is of a specified
3287 *     class of XML object, or a derived class. A flag is returned indicating
3288 *     if the check succeeds. No error is reported if the check fails.
3289 
3290 *  Parameters:
3291 *     this
3292 *        The object to check.
3293 *     want
3294 *        The type of the required class.
3295 
3296 *  Returned Value:
3297 *     Non-zero if the check is passed, zero if not of if an error has
3298 *     already occurred.
3299 
3300 *  Notes:
3301 *     - This function attempts to execute even if the error status is set.
3302 *-
3303 */
3304 
3305    if( this ) {
3306       return CheckType( ((AstXmlObject *) this)->type, want, status );
3307    } else {
3308       return 0;
3309    }
3310 }
3311 
CleanText(const char * text,int * status)3312 static char *CleanText( const char *text, int *status ){
3313 /*
3314 *  Name:
3315 *     CleanText
3316 
3317 *  Purpose:
3318 *     Normalise end-of-lines in the supplied text.
3319 
3320 *  Type:
3321 *     Private function.
3322 
3323 *  Synopsis:
3324 *     #include "xml.h"
3325 *     char *CleanText( const char *text, int *status )
3326 
3327 *  Description:
3328 *     This function returns a copy of "text in which "\r\n" has been
3329 *     replaced by "\n" and any remaining "\r" characters have been
3330 *     replaced by "\n".
3331 
3332 *  Parameters:
3333 *     text
3334 *        A pointer to a text string.
3335 *     status
3336 *        Pointer to the inherited status variable.
3337 
3338 *  Returned Value:
3339 *     A pointer to a dynamically allocated string containing the required
3340 *     copy.
3341 
3342 *  Notes:
3343 *     - NULL is returned if this function is called with the global error
3344 *     status set, or if it should fail for any reason.
3345 */
3346 
3347 /* Local Variables: */
3348    char *d;                  /* Pointer to next returned character */
3349    char *result;             /* Returned pointer */
3350    char *c;                  /* Pointer to next supplied character */
3351    char lc;                  /* Previous character */
3352 
3353 /* Initialise */
3354    result = NULL;
3355 
3356 /* Return if the pointer is NULL or if an error has occurred. */
3357    if( !astOK || !text ) return result;
3358 
3359 /* Take a copy of the supplied text */
3360    result = astStore( NULL, text, strlen( text ) + 1 );
3361 
3362 /* Clean the text by replacing "\r\n" by "\n". */
3363    c = result - 1;
3364    d = c;
3365    lc = 0;
3366    while( *(++c) ) {
3367       if( *c != '\n' || lc != '\r' ) d++;
3368       *d = ( lc = *c );
3369    }
3370    *(++d) = 0;
3371 
3372 /* Now further clean it by replacing "\r" by "\n". */
3373    c = result - 1;
3374    while( *(++c) ) {
3375       if( *c == '\r' ) *c = '\n';
3376    }
3377 
3378 /* Return the result. */
3379    return result;
3380 }
3381 
CleanXml(AstXmlObject * this,long int type,int * status)3382 static void CleanXml( AstXmlObject *this, long int type, int *status ){
3383 /*
3384 *  Name:
3385 *     CleanXml
3386 
3387 *  Purpose:
3388 *     Free the resources used within an XmlObject.
3389 
3390 *  Type:
3391 *     Private function.
3392 
3393 *  Synopsis:
3394 *     #include "xml.h"
3395 *     void CleanXml( AstXmlObject *this, long int type, int *status )
3396 
3397 *  Description:
3398 *     This function frees the resources used internally within the
3399 *     supplied XmlObject.
3400 
3401 *  Parameters:
3402 *     this
3403 *        pointer to the XmlObject to be cleaned.
3404 *     type
3405 *        The type of XmlObject being cleaned.
3406 *     status
3407 *        Pointer to the inherited status variable.
3408 
3409 *  Notes:
3410 *     This function attempts to execute even if an error has already
3411 *     occurred.
3412 *-
3413 */
3414 
3415 /* Local Variables: */
3416    AstXmlAttribute *attr;
3417    AstXmlBlack *black;
3418    AstXmlCDataSection *cdatasec;
3419    AstXmlComment *comm;
3420    AstXmlDTDec *dtd;
3421    AstXmlDeclPI *dec;
3422    AstXmlDocument *doc;
3423    AstXmlElement *elem;
3424    AstXmlNamespace *ns;
3425    AstXmlPI *pi;
3426    AstXmlPrologue *pro;
3427    AstXmlWhite *white;
3428 
3429 /* Return if a NULL pointer has been suppplied. */
3430    if( !this ) return;
3431 
3432 /* For the base XmlObject class, clear the object type, etc. */
3433    if( type == AST__XMLOBJECT  ){
3434       this->type = AST__XMLBAD;
3435       this->parent = NULL;
3436 
3437 /* For each derived class of XmlObject, first clean the parent component,
3438    then clean any further resources. */
3439    } else if( type == AST__XMLELEM  ){
3440 
3441       elem = (AstXmlElement *) this;
3442 
3443       elem->name = astFree( elem->name );
3444       elem->defns = astFree( elem->defns );
3445       elem->prefix = astFree( elem->prefix );
3446 
3447       while( elem->nattr > 0 ) astXmlDelete( elem->attrs[ 0 ] );
3448       elem->attrs = astFree( elem->attrs );
3449 
3450       while( elem->nitem > 0 ) astXmlDelete( elem->items[ 0 ] );
3451       elem->items = astFree( elem->items );
3452 
3453       while( elem->nnspref > 0 ) astXmlDelete( elem->nsprefs[ 0 ] );
3454       elem->nsprefs = astFree( elem->nsprefs );
3455 
3456       CleanXml( this, AST__XMLOBJECT, status );
3457 
3458    } else if( type == AST__XMLATTR ){
3459       attr = (AstXmlAttribute *) this;
3460       attr->name = astFree( attr->name );
3461       attr->value = astFree( attr->value );
3462       attr->prefix = astFree( attr->prefix );
3463       CleanXml( this, AST__XMLOBJECT, status );
3464 
3465    } else if( type == AST__XMLBLACK ){
3466       black = (AstXmlBlack *) this;
3467       black->text = astFree( black->text );
3468       CleanXml( this, AST__XMLOBJECT, status );
3469 
3470    } else if( type == AST__XMLWHITE ){
3471       white = (AstXmlWhite *) this;
3472       white->text = astFree( white->text );
3473       CleanXml( this, AST__XMLOBJECT, status );
3474 
3475    } else if( type == AST__XMLCDATA ){
3476       cdatasec = (AstXmlCDataSection *) this;
3477       cdatasec->text = astFree( cdatasec->text );
3478       CleanXml( this, AST__XMLOBJECT, status );
3479 
3480    } else if( type == AST__XMLCOM ){
3481       comm = (AstXmlComment *) this;
3482       comm->text = astFree( comm->text );
3483       CleanXml( this, AST__XMLOBJECT, status );
3484 
3485    } else if( type == AST__XMLPI ){
3486       pi = (AstXmlPI *) this;
3487       pi->target = astFree( pi->target );
3488       pi->text = astFree( pi->text );
3489       CleanXml( this, AST__XMLOBJECT, status );
3490 
3491    } else if( type == AST__XMLNAME ){
3492       ns = (AstXmlNamespace *) this;
3493       ns->prefix = astFree( ns->prefix );
3494       ns->uri = astFree( ns->uri );
3495       CleanXml( this, AST__XMLOBJECT, status );
3496 
3497    } else if( type == AST__XMLDOC ){
3498       doc = (AstXmlDocument *) this;
3499       doc->prolog = astXmlDelete( doc->prolog );
3500       doc->root = astXmlDelete( doc->root );
3501       while( doc->nepi > 0 ) astXmlDelete( doc->epilog[ 0 ] );
3502       doc->epilog = astFree( doc->epilog );
3503       doc->current = NULL;
3504       CleanXml( this, AST__XMLOBJECT, status );
3505 
3506    } else if( type == AST__XMLPRO ){
3507       pro = (AstXmlPrologue *) this;
3508       pro->xmldecl = astXmlDelete( pro->xmldecl );
3509       while( pro->nmisc1 > 0 ) astXmlDelete( pro->misc1[ 0 ] );
3510       pro->misc1 = astFree( pro->misc1 );
3511       pro->dtdec = astXmlDelete( pro->dtdec );
3512       while( pro->nmisc2 > 0 ) astXmlDelete( pro->misc2[ 0 ] );
3513       pro->misc2 = astFree( pro->misc2 );
3514       CleanXml( this, AST__XMLOBJECT, status );
3515 
3516    } else if( type == AST__XMLDEC ){
3517       dec = (AstXmlDeclPI *) this;
3518       dec->text = astFree( dec->text );
3519       CleanXml( this, AST__XMLOBJECT, status );
3520 
3521    } else if( type == AST__XMLDTD ){
3522       dtd = (AstXmlDTDec *) this;
3523       dtd->name = astFree( dtd->name );
3524       dtd->external = astFree( dtd->external );
3525       dtd->internal = astFree( dtd->internal );
3526       CleanXml( this, AST__XMLOBJECT, status );
3527 
3528    } else if( astOK ) {
3529       astError( AST__INTER, "CleanXml: Invalid object type (%ld) supplied "
3530                 "(internal AST programming error).", status, type );
3531    }
3532 
3533 }
3534 
DefaultURI(AstXmlElement * elem,int * status)3535 static const char *DefaultURI( AstXmlElement *elem, int *status ){
3536 /*
3537 *  Name:
3538 *     DefaultURI
3539 
3540 *  Purpose:
3541 *     Find the URI associated with the default namespace.
3542 
3543 *  Type:
3544 *     Private function.
3545 
3546 *  Synopsis:
3547 *     #include "xml.h"
3548 *     const char *DefaultURI( AstXmlElement *elem, int *status )
3549 
3550 *  Description:
3551 *     This function returns the default namespace URI defined within the
3552 *     given element. If the element does not define a default namespace URI,
3553 *     then this function is called recursively on the parent element. If
3554 *     there is no parent element, NULL is returned.
3555 
3556 *  Parameters:
3557 *     elem
3558 *        The pointer to the XmlElement.
3559 *     status
3560 *        Pointer to the inherited status variable.
3561 
3562 *  Returned Value:
3563 *     Pointer to a string holding the URI, or NULL if not found.
3564 
3565 *  Notes:
3566 *     - NULL is returned if an error has already occurred, or if this
3567 *     function should fail for any reason.
3568 */
3569 
3570 /* Local Variables: */
3571    AstXmlParent *parent;        /* Parent of "this" */
3572    const char *result;          /* Returned pointer */
3573 
3574 /* Initialise */
3575    result = NULL;
3576 
3577 /* Check the global error status, and the supplied element. */
3578    if( !astOK || !elem ) return result;
3579 
3580 /* If the supplied element defines a default namespace URI, return it.
3581    Otherwise, call this function to get the default namespace URI from the
3582    parent element. */
3583    result = elem->defns;
3584    if( !result ) {
3585       parent = ( (AstXmlObject *) elem )->parent;
3586       if( astXmlCheckType( parent, AST__XMLELEM ) ) {
3587          result = DefaultURI( (AstXmlElement *) parent, status );
3588       }
3589    }
3590 
3591 /* If the element has a blank default namespace URI, then return NULL
3592    since the XML namespaces specification says that "The default
3593    namespace can be set to the empty string. This has the same effect,
3594    within the scope of the declaration, of there being no default
3595    namespace". */
3596    if( result && astChrLen( result ) == 0 ) result = NULL;
3597 
3598 /* Return the result. */
3599    return result;
3600 }
3601 
astXmlDelete_(void * obj_ptr,int * status)3602 void *astXmlDelete_( void *obj_ptr, int *status ){
3603 /*
3604 *+
3605 *  Name:
3606 *     astXmlDelete
3607 
3608 *  Purpose:
3609 *     Remove the supplied XmlObject from its parent and delete it.
3610 
3611 *  Type:
3612 *     Protected function.
3613 
3614 *  Synopsis:
3615 *     #include "xml.h"
3616 *     void *astXmlDelete( void *obj )
3617 
3618 *  Description:
3619 *     This function removes the supplied XmlObject from its parent and
3620 *     deletes it using astXmlAnnul.
3621 
3622 *  Parameters:
3623 *     obj
3624 *        The pointer to the XmlObject to be deleted.
3625 
3626 *  Returned Value:
3627 *     NULL
3628 
3629 *  Notes:
3630 *     - This function attempts to execute even if an error has already
3631 *     occurred.
3632 *-
3633 */
3634 
3635 /* Local Variables: */
3636    AstXmlDocument *doc;         /* Pointer to XM document */
3637    AstXmlElement *elem;         /* Pointer to XML element */
3638    AstXmlObject *obj;           /* Pointer to XmlObject */
3639    AstXmlParent *parent;        /* Pointer to parent */
3640    AstXmlPrologue *pro;         /* Pointer to XML prologue */
3641    int i;                       /* Loop counter */
3642    int j;                       /* Loop counter */
3643    int n;                       /* Number of values in list */
3644    int ok;                      /* Is obj a child of its parent? */
3645    void *result;                /* Returned pointer */
3646 
3647 /* Initialise */
3648    result = NULL;
3649    ok = 0;
3650 
3651 /* Check we have an XmlObject. */
3652    if( !astXmlCheckType( obj_ptr, AST__XMLOBJECT ) ) return result;
3653 
3654 /* Get the parent of the supplied object. */
3655    obj = (AstXmlObject *) obj_ptr;
3656    parent = obj->parent;
3657    if( parent ) {
3658 
3659 /* First deal with cases where we are deleting items from a document. */
3660       if( astXmlCheckType( parent, AST__XMLDOC ) ) {
3661          doc = (AstXmlDocument *) parent;
3662 
3663          if( astXmlCheckType( obj, AST__XMLPRO ) ) {
3664             if( (AstXmlPrologue *) obj == doc->prolog ) {
3665                doc->prolog = NULL;
3666                ok = 1;
3667             }
3668 
3669          } else if( astXmlCheckType( obj, AST__XMLELEM ) ) {
3670             if( (AstXmlElement *) obj == doc->root ) {
3671                doc->root = NULL;
3672                ok = 1;
3673             }
3674 
3675          } else if( astXmlCheckType( obj, AST__XMLMISC ) ) {
3676             n = doc->nepi;
3677             for( i = 0; i < n; i++ ) {
3678                if( doc->epilog[ i ] == (AstXmlMiscItem *) obj ) {
3679                   for( j = i + 1; j < n; j++ ) {
3680                      doc->epilog[ j - 1 ] =  doc->epilog[ j ];
3681                   }
3682                   doc->epilog[ --doc->nepi ] = NULL;
3683                   ok = 1;
3684                   break;
3685                }
3686             }
3687 
3688          } else if( astOK ) {
3689             astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has "
3690                       "inappropriate parent of type %ld (internal AST "
3691                       "programming error).", status, obj->type, parent->type );
3692          }
3693 
3694 /* Now deal with cases where we are deleting items from a prologue. */
3695       } else if( astXmlCheckType( parent, AST__XMLPRO ) ) {
3696          pro = (AstXmlPrologue *) parent;
3697 
3698          if( astXmlCheckType( obj, AST__XMLDEC ) ) {
3699             if( (AstXmlDeclPI *) obj == pro->xmldecl ) {
3700                pro->xmldecl = NULL;
3701                ok = 1;
3702             }
3703 
3704          } else if( astXmlCheckType( obj, AST__XMLDTD ) ) {
3705             if( (AstXmlDTDec *) obj == pro->dtdec ) {
3706                pro->dtdec = NULL;
3707                ok = 1;
3708             }
3709 
3710          } else if( astXmlCheckType( obj, AST__XMLMISC ) ) {
3711             n = pro->nmisc1;
3712             for( i = 0; i < n; i++ ) {
3713                if( pro->misc1[ i ] == (AstXmlMiscItem *) obj ) {
3714                   for( j = i + 1; j < n; j++ ) {
3715                      pro->misc1[ j - 1 ] =  pro->misc1[ j ];
3716                   }
3717                   pro->misc1[ --pro->nmisc1 ] = NULL;
3718                   ok = 1;
3719                   break;
3720                }
3721             }
3722 
3723             if( !ok ) {
3724                n = pro->nmisc2;
3725                for( i = 0; i < n; i++ ) {
3726                   if( pro->misc2[ i ] == (AstXmlMiscItem *) obj ) {
3727                      for( j = i + 1; j < n; j++ ) {
3728                         pro->misc2[ j - 1 ] =  pro->misc2[ j ];
3729                      }
3730                      pro->misc2[ --pro->nmisc2 ] = NULL;
3731                      ok = 1;
3732                      break;
3733                   }
3734                }
3735             }
3736 
3737          } else if( astOK ) {
3738             astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has "
3739                       "inappropriate parent of type %ld (internal AST "
3740                       "programming error).", status, obj->type, parent->type );
3741          }
3742 
3743 /* Now deal with cases where we are deleting items from an element. */
3744       } else if( astXmlCheckType( parent, AST__XMLELEM ) ) {
3745          elem = (AstXmlElement *) parent;
3746 
3747 /* Remove the object form the appropriate list in the parent, and
3748    then shuffle down the remaining entries in the list and decrement the
3749    size of the list. */
3750          if( astXmlCheckType( obj, AST__XMLATTR ) ) {
3751             n = elem->nattr;
3752             for( i = 0; i < n; i++ ) {
3753                if( elem->attrs[ i ] == (AstXmlAttribute *) obj ) {
3754                   for( j = i + 1; j < n; j++ ) {
3755                      elem->attrs[ j - 1 ] =  elem->attrs[ j ];
3756                   }
3757                   elem->attrs[ --elem->nattr ] = NULL;
3758                   ok = 1;
3759                   break;
3760                }
3761             }
3762 
3763          } else if( astXmlCheckType( obj, AST__XMLNAME ) ) {
3764             n = elem->nnspref;
3765             for( i = 0; i < n; i++ ) {
3766                if( elem->nsprefs[ i ] == (AstXmlNamespace *) obj ) {
3767                   for( j = i + 1; j < n; j++ ) {
3768                      elem->nsprefs[ j - 1 ] =  elem->nsprefs[ j ];
3769                   }
3770                   elem->nsprefs[ --elem->nnspref ] = NULL;
3771                   ok = 1;
3772                   break;
3773                }
3774             }
3775 
3776          } else if( astXmlCheckType( obj, AST__XMLCONT ) ) {
3777             n = elem->nitem;
3778             for( i = 0; i < n; i++ ) {
3779                if( elem->items[ i ] == (AstXmlContentItem *) obj ) {
3780                   for( j = i + 1; j < n; j++ ) {
3781                      elem->items[ j - 1 ] =  elem->items[ j ];
3782                   }
3783                   elem->items[ --elem->nitem ] = NULL;
3784                   ok = 1;
3785                   break;
3786                }
3787             }
3788          }
3789 
3790       } else if( astOK ) {
3791          astError( AST__INTER, "astXmlDelete(xml): XmlObject of type %ld has "
3792                    "inappropriate parent of type %ld (internal AST "
3793                    "programming error).", status, obj->type, parent->type );
3794       }
3795 
3796 /* Nullify the parent pointer so that astXmlAnnul will delete the object. */
3797       obj->parent = NULL;
3798 
3799 /* If the supplied object has no parent, we can continue to annul it. */
3800    } else {
3801       ok = 1;
3802    }
3803 
3804 /* Report an error if required. */
3805    if( !ok && astOK ) {
3806       astError( AST__INTER, "astXmlDelete(xml): Supplied XmlObject (type %ld) "
3807                 "is not owned by its own parent (internal AST "
3808                 "programming error).", status, obj->type );
3809    }
3810 
3811 /* Delete the object. */
3812    result = astXmlAnnul( obj );
3813 
3814 /* Annul the object and return the resulting NULL pointer. */
3815    return result;
3816 }
3817 
FindAttribute(AstXmlElement * this,const char * name0,int * status)3818 static AstXmlAttribute *FindAttribute( AstXmlElement *this, const char *name0,
3819                                        int *status ){
3820 /*
3821 *  Name:
3822 *     FindAttribute
3823 
3824 *  Purpose:
3825 *     Search an XmlElement for a named attribute
3826 
3827 *  Type:
3828 *     Private function.
3829 
3830 *  Synopsis:
3831 *     #include "xml.h"
3832 *     AstXmlAttribute *FindAttribute( AstXmlElement *this, const char *name0,
3833 *                                     int *status )
3834 
3835 *  Description:
3836 *     This function searches the supplied XmlElement for an attribute
3837 *     with the given name. If found, a pointer to the XmlAttribute is
3838 *     returned. Otherwise NULL is returned.
3839 
3840 *  Parameters:
3841 *     this
3842 *        The pointer to the XmlElement.
3843 *     name0
3844 *        Pointer to a string holding the name of the attribute. The name
3845 *        may be preceded with a "prefix:" string, in which case the
3846 *        prefix will also be matched. If no prefix is included, the first
3847 *        attribute with the specified name is returned, regardless of
3848 *        its prefix.
3849 *     status
3850 *        Pointer to the inherited status variable.
3851 
3852 *  Returned Value:
3853 *     Pointer to the XmlAttribute, or NULL if not found.
3854 
3855 *  Notes:
3856 *     - NULL is returned if an error has already occurred, or if this
3857 *     function should fail for any reason.
3858 */
3859 
3860 /* Local Variables: */
3861    AstXmlAttribute *result;     /* Returned pointer */
3862    char name_buffer[ 50 ];      /* Buffer for name */
3863    char prefix_buffer[ 50 ];    /* Buffer for prefix */
3864    const char *colon;           /* Pointer to colon in supplied string */
3865    const char *name1;           /* Pointer to name to be checked */
3866    const char *name;            /* Pointer to name to be searched for */
3867    const char *prefix1;         /* Pointer to prefix to be checked */
3868    const char *prefix;          /* Pointer to prefix to be searched for */
3869    int i;                       /* Loop count */
3870    size_t len;                  /* Length of string */
3871 
3872 /* Initialise */
3873    result = NULL;
3874    name = name0;
3875    prefix = NULL;
3876 
3877 /* Check the global error status. */
3878    if( !astOK ) return result;
3879 
3880 /* If the supplied name string contains a colon, split it up into prefix
3881    and name. */
3882    if( ( colon = strchr( name0, ':' ) ) ) {
3883       len = colon - name0;
3884 
3885       if( len > 49 ) {
3886          astError( AST__XMLNM, "FindAttribute: The XML prefix in \"%s\" "
3887                    "is too long (> 49 characters).", status, name0 );
3888       } else {
3889          strncpy( prefix_buffer, name0, len );
3890          prefix_buffer[ len ] = 0;
3891          prefix = prefix_buffer;
3892          len = strlen( colon + 1 );
3893 
3894          if( len > 49 ) {
3895             astError( AST__XMLNM, "FindAttribute: The XML attribute name "
3896                       "in \"%s\" is too long (> 49 characters).", status, name0 );
3897          } else {
3898             strcpy( name_buffer, colon + 1 );
3899             name = name_buffer;
3900          }
3901 
3902       }
3903 
3904    }
3905 
3906 /* Loop round all the attributes in the element. */
3907    for( i = 0; i < this->nattr; i++ ) {
3908       name1 = this->attrs[ i ]->name;
3909       prefix1 = this->attrs[ i ]->prefix;
3910 
3911 /* Compare the attribute name (and prefix) with the supplied name (and
3912    prefix). Leave the loop if they match. */
3913       if( !strcmp( name1, name ) &&
3914           ( !prefix || ( prefix1 && !strcmp( prefix1, prefix ) ) ) ) {
3915          result = this->attrs[ i ];
3916          break;
3917       }
3918    }
3919 
3920 /* Return the result. */
3921    return result;
3922 }
3923 
Format(AstXmlObject * this,int ind,int * status)3924 static const char *Format( AstXmlObject *this, int ind, int *status ){
3925 /*
3926 *  Name:
3927 *     Format
3928 
3929 *  Purpose:
3930 *     Converts an XmlObject into a character string.
3931 
3932 *  Type:
3933 *     Private function.
3934 
3935 *  Synopsis:
3936 *     #include "xml.h"
3937 *     const char *Format( AstXmlObject *this, int ind, int *status )
3938 
3939 *  Description:
3940 *     This function returns a pointer to a dynamically allocated string
3941 *     containing a textual representation of the supplied XmlObject.
3942 
3943 *  Parameters:
3944 *     this
3945 *        Pointer to the XmlObject to format.
3946 *     ind
3947 *        If the XmlObject is an element, then each content item within
3948 *        the element will be prefixed by a string containing "ind" spaces
3949 *        (indenting the returned element itself is the responsibility of
3950 *        the caller and so "this" is not itself indented within this function).
3951 *        In addition, a newline character will be included at the start
3952 *        of the prefix if required, to ensure that each new item starts
3953 *        on a new line. If "ind" is less than zero, then no prefixes are
3954 *        added.
3955 *     status
3956 *        Pointer to the inherited status variable.
3957 
3958 *  Returned Value:
3959 *     Pointer to a null terminated string holding the formated XmlObject.
3960 *     This string should be freed when no longer needed using astFree.
3961 
3962 *  Notes:
3963 *     - NULL is returned if an error has already occurred, or if this
3964 *     function should fail for any reason.
3965 */
3966 
3967 /* Local Variables: */
3968    AstXmlPrologue *pro;      /* Pointer to XML prologue */
3969    AstXmlDocument *doc;      /* Pointer to XML document */
3970    AstXmlAttribute *attrib;  /* Pointer to XML attribute */
3971    AstXmlWhite *white;       /* Pointer to character data */
3972    AstXmlBlack *black;       /* Pointer to character data */
3973    AstXmlElement *elem;      /* Pointer to XML element */
3974    AstXmlNamespace *ns;      /* Pointer to XML namespace instruction */
3975    char *result;             /* The returned pointer */
3976    const char *temp;         /* A temporary string pointer */
3977    int i;                    /* Loop count */
3978    int nc;                   /* Length of returned string */
3979    int type;                 /* Object type */
3980 
3981 /* Initialise */
3982    result = NULL;
3983 
3984 /* Check the global error status. */
3985    if( !astOK || !this ) return result;
3986 
3987 /* Get the object type */
3988    type = this->type;
3989 
3990 /* If this is an element... */
3991    if( this->type == AST__XMLELEM ) {
3992       temp = FormatTag( this, 1, status );
3993       result = astAppendString( result, &nc, temp );
3994       temp = astFree( (void *) temp );
3995 
3996       elem = (AstXmlElement *) this;
3997       if( elem->nitem > 0 ) {
3998 
3999 /* Go round all the items of content. */
4000          for( i = 0; i < elem->nitem; i++ ) {
4001 
4002 /* Ignore whitespace elements unless we are not producing indentation. */
4003             if( !astXmlCheckType( elem->items[ i ], AST__XMLWHITE ) ||
4004                 ind < 0 ) {
4005 
4006 /* Format the item */
4007                temp = Format( (AstXmlObject *) elem->items[ i ], ( ( ind > -1 ) ? ind + IND_INC : -1 ), status );
4008                if( temp ) {
4009 
4010 /* Now append the next item of content, and free its memory. */
4011                   if( ind > -1 ) {
4012                      result = AppendLine( result, &nc, temp,
4013                                           ( (ind > -1) ? ind + IND_INC : -1 ), status );
4014                   } else {
4015                      result = astAppendString( result, &nc, temp );
4016                   }
4017                   temp = astFree( (void *) temp );
4018                }
4019             }
4020          }
4021 
4022 /* Finally append the end tag. */
4023          temp = FormatTag( this, 0, status );
4024          if( ind > -1 ) {
4025             result = AppendLine( result, &nc, temp, ind, status );
4026          } else {
4027             result = astAppendString( result, &nc, temp );
4028          }
4029          temp = astFree( (void *) temp );
4030 
4031       }
4032 
4033 /* If this is an attribute... */
4034    } else if( type == AST__XMLATTR ){
4035       attrib = (AstXmlAttribute *) this;
4036 
4037       if( attrib->prefix ) {
4038          result = astAppendString( result, &nc, attrib->prefix );
4039          result = astAppendString( result, &nc, ":" );
4040       }
4041 
4042       temp = AddEscapes( attrib->value, status );
4043       result = astAppendString( result, &nc, attrib->name );
4044       result = astAppendString( result, &nc, "=\"" );
4045       result = astAppendString( result, &nc, temp );
4046       result = astAppendString( result, &nc, "\"" );
4047       temp = astFree( (void *) temp );
4048 
4049    } else if( type == AST__XMLWHITE ){
4050       white = (AstXmlWhite *) this;
4051       temp = AddEscapes( white->text, status );
4052       result = astAppendString( result, &nc, temp );
4053       temp = astFree( (void *) temp );
4054 
4055    } else if( type == AST__XMLBLACK ){
4056       black = (AstXmlBlack *) this;
4057       temp = AddEscapes( black->text, status );
4058       result = astAppendString( result, &nc, temp );
4059       temp = astFree( (void *) temp );
4060 
4061    } else if( type == AST__XMLCDATA ||
4062               type == AST__XMLCOM ||
4063               type == AST__XMLPI ||
4064               type == AST__XMLDEC ||
4065               type == AST__XMLDTD ){
4066 
4067       temp = FormatTag( this, 1, status );
4068       result = astAppendString( result, &nc, temp );
4069       temp = astFree( (void *) temp );
4070 
4071    } else if( type == AST__XMLNAME ){
4072       ns = (AstXmlNamespace *) this;
4073       result = astAppendString( result, &nc, "xmlns:" );
4074       result = astAppendString( result, &nc, ns->prefix );
4075       result = astAppendString( result, &nc, "=\"" );
4076       result = astAppendString( result, &nc, ns->uri );
4077       result = astAppendString( result, &nc, "\"" );
4078 
4079    } else if( type == AST__XMLPRO ){
4080       pro = (AstXmlPrologue *) this;
4081       result = astAppendString( result, &nc,
4082                              Format( (AstXmlObject *) pro->xmldecl, ind, status ) );
4083 
4084 /* Append all the miscalleneous items before the DTD. */
4085       for( i = 0; i < pro->nmisc1; i++ ) {
4086          temp = Format( (AstXmlObject *) pro->misc1[ i ], ind, status );
4087          if( temp ) {
4088             if( ind > -1 ) {
4089                result = AppendLine( result, &nc, temp, ind, status );
4090             } else {
4091                result = astAppendString( result, &nc, temp );
4092             }
4093             temp = astFree( (void *) temp );
4094          }
4095       }
4096 
4097 /* Append the DTD. */
4098       temp = Format( (AstXmlObject *) pro->dtdec, ind, status );
4099       if( temp ) {
4100          if( ind > -1 ) {
4101             result = AppendLine( result, &nc, temp, ind, status );
4102          } else {
4103             result = astAppendString( result, &nc, temp );
4104          }
4105          temp = astFree( (void *) temp );
4106       }
4107 
4108 /* Append all the miscalleneous items after the DTD. */
4109       for( i = 0; i < pro->nmisc2; i++ ) {
4110          temp = Format( (AstXmlObject *) pro->misc2[ i ], ind, status );
4111          if( temp ) {
4112             if( ind > -1 ) {
4113                result = AppendLine( result, &nc, temp, ind, status );
4114             } else {
4115                result = astAppendString( result, &nc, temp );
4116             }
4117             temp = astFree( (void *) temp );
4118          }
4119       }
4120 
4121    } else if( type == AST__XMLDOC ){
4122       doc = (AstXmlDocument *) this;
4123 
4124 /* Format the prologue. */
4125       result = astAppendString( result, &nc,
4126                              Format( (AstXmlObject *) doc->prolog, ind, status ) );
4127 
4128 /* Append the root element. */
4129       temp = Format( (AstXmlObject *) doc->root, ind, status );
4130       if( temp ) {
4131          if( ind > -1 ) {
4132             result = AppendLine( result, &nc, temp, ind, status );
4133          } else {
4134             result = astAppendString( result, &nc, temp );
4135          }
4136          temp = astFree( (void *) temp );
4137       }
4138 
4139 /* Append all the miscalleneous items in the epilogue. */
4140       for( i = 0; i < doc->nepi; i++ ) {
4141          temp = Format( (AstXmlObject *) doc->epilog[ i ], ind, status );
4142          if( temp ) {
4143             if( ind > -1 ) {
4144                result = AppendLine( result, &nc, temp, ind, status );
4145             } else {
4146                result = astAppendString( result, &nc, temp );
4147             }
4148             temp = astFree( (void *) temp );
4149          }
4150       }
4151 
4152    } else if( astOK ) {
4153       astError( AST__INTER, "Format(xml): Invalid object type (%d) supplied "
4154                 "(internal AST programming error).", status, type );
4155    }
4156 
4157 /* Free the returned string if an error has occurred. */
4158    if( !astOK ) result = astFree( result );
4159 
4160 /* Return the result. */
4161    return result;
4162 }
4163 
FormatTag(AstXmlObject * this,int opening,int * status)4164 static char *FormatTag( AstXmlObject *this, int opening, int *status ){
4165 /*
4166 *  Name:
4167 *     FormatTag
4168 
4169 *  Purpose:
4170 *     Returns a string holding an XML tag describing the given XmlObject.
4171 
4172 *  Type:
4173 *     Private function.
4174 
4175 *  Synopsis:
4176 *     #include "xml.h"
4177 *     char *FormatTag( AstXmlObject *this, int opening, int *status )
4178 
4179 *  Description:
4180 *     This function returns a pointer to a dynamic string containing an
4181 *     XML tag describing the given XmlObject.
4182 
4183 *  Parameters:
4184 *     this
4185 *        Pointer to the XmlObject.
4186 *     opening
4187 *        Indicates which tag is to be returned; the start tag or the end
4188 *        tag. If non-zero the start tag is returned. Otherwise, the
4189 *        end tag is returned. If the supplied XmlObject has no end
4190 *        tag (i.e. if it is an empty element, or if it is not an element),
4191 *        then NULL is returned but no error is reported.
4192 *     status
4193 *        Pointer to the inherited status variable.
4194 
4195 *  Returned Value:
4196 *     Pointer to a dynamically allocated string holding the tag.
4197 
4198 *  Notes:
4199 *     - Empty elements are represented as an start tag of the form <.../>,
4200 *     with no corresponding end tag.
4201 *     - NULL is returned if an error has already occurred, or if this
4202 *     function should fail for any reason.
4203 *-
4204 */
4205 
4206 
4207 /* Local Variables: */
4208    AstXmlCDataSection *cdata;/* Pointer to XML CDATA section */
4209    AstXmlElement *elem;      /* Pointer to XML element */
4210    AstXmlComment *com;       /* Pointer to XML comment */
4211    AstXmlPI *pi;             /* Pointer to XML processing instruction */
4212    AstXmlDTDec *dtd;         /* Pointer to XML data type declaration */
4213    AstXmlDeclPI *xmlpi;      /* XML version declaration */
4214    char *result;             /* The returned pointer */
4215    const char *temp;         /* A temporary string pointer */
4216    int i;                    /* Loop count */
4217    int nc;                   /* Length of returned string */
4218    int type;                 /* Object type */
4219 
4220 /* Initialise */
4221    result = NULL;
4222 
4223 /* Check the global error status. */
4224    if( !astOK ) return result;
4225 
4226 /* Get the object type */
4227    type = this->type;
4228 
4229 /* If this is an element... */
4230    if( this->type == AST__XMLELEM ) {
4231       elem = (AstXmlElement *) this;
4232 
4233       if( opening ) {
4234          result = astAppendString( result, &nc, "<" );
4235          if( elem->prefix ) {
4236             result = astAppendString( result, &nc, elem->prefix );
4237             result = astAppendString( result, &nc, ":" );
4238          }
4239          result = astAppendString( result, &nc, elem->name );
4240 
4241          if( elem->defns ) {
4242             result = astAppendString( result, &nc, " xmlns=\"" );
4243             result = astAppendString( result, &nc, elem->defns );
4244             result = astAppendString( result, &nc, "\"" );
4245          }
4246 
4247          for( i = 0; i < elem->nnspref; i++ ) {
4248             temp = Format( (AstXmlObject *) elem->nsprefs[ i ], -1, status );
4249             if( temp ) {
4250                result = AppendChar( result, &nc, ' ', status );
4251                result = astAppendString( result, &nc, temp );
4252                temp = astFree( (void *) temp );
4253             }
4254          }
4255 
4256          for( i = 0; i < elem->nattr; i++ ) {
4257             temp = Format( (AstXmlObject *) elem->attrs[ i ], -1, status );
4258             if( temp ){
4259                result = AppendChar( result, &nc, ' ', status );
4260                result = astAppendString( result, &nc, temp );
4261                temp = astFree( (void *) temp );
4262             }
4263          }
4264 
4265          if( elem->nitem == 0 ) result = astAppendString( result, &nc, "/" );
4266          result = astAppendString( result, &nc, ">" );
4267 
4268       } else if( elem->nitem > 0 ) {
4269          result = astAppendString( result, &nc, "</" );
4270          if( elem->prefix ) {
4271             result = astAppendString( result, &nc, elem->prefix );
4272             result = astAppendString( result, &nc, ":" );
4273          }
4274          result = astAppendString( result, &nc, elem->name );
4275          result = astAppendString( result, &nc, ">" );
4276       }
4277 
4278    } else if( type == AST__XMLDTD ){
4279       dtd = (AstXmlDTDec *) this;
4280       if( opening && dtd->name && dtd->name[0] ) {
4281          result = astAppendString( result, &nc, "<!DOCTYPE " );
4282          result = astAppendString( result, &nc, dtd->name );
4283          if( dtd->external && dtd->external[ 0 ] ) {
4284             result = astAppendString( result, &nc, " " );
4285             result = astAppendString( result, &nc, dtd->external );
4286          }
4287          if( dtd->internal && dtd->internal[ 0 ] ) {
4288             result = astAppendString( result, &nc, " [" );
4289             result = astAppendString( result, &nc, dtd->internal );
4290             result = astAppendString( result, &nc, "]" );
4291          }
4292          result = astAppendString( result, &nc, ">" );
4293       }
4294 
4295    } else if( type == AST__XMLCDATA ){
4296       if( opening ) {
4297          cdata = (AstXmlCDataSection *) this;
4298          result = astAppendString( result, &nc, "<![CDATA[" );
4299          result = astAppendString( result, &nc, cdata->text );
4300          result = astAppendString( result, &nc, "]]>" );
4301       }
4302 
4303    } else if( type == AST__XMLCOM ){
4304       if( opening ) {
4305          com = (AstXmlComment *) this;
4306          result = astAppendString( result, &nc, "<!--" );
4307          result = astAppendString( result, &nc, com->text );
4308          result = astAppendString( result, &nc, "-->" );
4309       }
4310 
4311    } else if( type == AST__XMLPI ){
4312       pi = (AstXmlPI *) this;
4313       if( opening ) {
4314          result = astAppendString( result, &nc, "<?" );
4315          result = astAppendString( result, &nc, pi->target );
4316          if( pi->text && pi->text[0] ) {
4317             result = astAppendString( result, &nc, " " );
4318             result = astAppendString( result, &nc, pi->text );
4319          }
4320          result = astAppendString( result, &nc, "?>" );
4321       }
4322 
4323    } else if( type == AST__XMLDEC ){
4324       xmlpi = (AstXmlDeclPI *) this;
4325       if( opening && xmlpi->text && xmlpi->text[0] ) {
4326          result = astAppendString( result, &nc, "<?xml" );
4327          if( xmlpi->text && xmlpi->text[0] ) {
4328             result = astAppendString( result, &nc, " " );
4329             result = astAppendString( result, &nc, xmlpi->text );
4330          }
4331          result = astAppendString( result, &nc, "?>" );
4332       }
4333    }
4334 
4335 /* If notOK, free the rteurned string. */
4336    if( !astOK ) result = astFree( result );
4337 
4338 /* Return the result. */
4339    return result;
4340 }
4341 
InitXmlAttribute(AstXmlAttribute * new,int type,const char * name,const char * value,const char * prefix,int * status)4342 static void InitXmlAttribute( AstXmlAttribute *new, int type, const char *name,
4343                               const char *value, const char *prefix, int *status ){
4344 /*
4345 *  Name:
4346 *     InitXmlAttribute
4347 
4348 *  Purpose:
4349 *     Initialise a new XmlAttribute.
4350 
4351 *  Type:
4352 *     Private function.
4353 
4354 *  Synopsis:
4355 *     #include "xml.h"
4356 *     InitXmlAttribute( AstXmlAttribute *new, int type, const char *name,
4357 *                       const char *value, const char *prefix, int *status )
4358 
4359 *  Description:
4360 *     This function initialises supplied memory to hold an XmlAttribute
4361 *     structure.
4362 
4363 *  Parameters:
4364 *     new
4365 *        The memory in which to initialise the structure.
4366 *     type
4367 *        An identifier for the structure type.
4368 *     name
4369 *        The name for the attribute.
4370 *     value
4371 *        The value for the attribute
4372 *     prefix
4373 *        The namespace prefix for the attribute. May be NULL or blank, in
4374 *        which case any prefix at the start of "name" is used.
4375 *     status
4376 *        Pointer to the inherited status variable.
4377 */
4378 
4379 /* Local Variables: */
4380    const char *colon;         /* Pointer to colon within supplied name */
4381    char *newname;             /* Pointer to name string (no prefix) */
4382    char *newpref;             /* Pointer to name string */
4383    int nc;                    /* Length of prefix string */
4384 
4385 /* Check the global error status. */
4386    if( !astOK ) return;
4387 
4388 /* Check the supplied object type is appropriate for the class of
4389    structure being initialised. If not report an error. */
4390    if( !CheckType( type, AST__XMLATTR, status ) ){
4391       astError( AST__INTER, "InitXmlAttribute: Supplied object type (%d) "
4392                 "does not represent an XmlAttribute", status, type );
4393    }
4394 
4395 /* Ensure we have non-NULL pointers. */
4396    if( !name ) name = "";
4397    if( !value ) value = "";
4398 
4399 /* If no prefix was supplied, extract any prefix from the start of the
4400    supplied name. */
4401    newname = (char *) name;
4402    newpref = (char *) prefix;
4403    colon = NULL;
4404 
4405    if( !prefix || astChrLen( prefix ) == 0 ){
4406       colon = strchr( name, ':' );
4407       if( colon ) {
4408          nc = colon - name;
4409          newpref = astStore( NULL, name, nc + 1 );
4410          newpref[ nc ] = 0;
4411 
4412          nc = strlen( name ) - ( colon - name ) - 1;
4413          newname = astStore( NULL, colon + 1, nc + 1 );
4414          newname[ nc ] = 0;
4415       }
4416    }
4417 
4418 /* Check the supplied name and prefix are valid XML 'names'. */
4419    CheckName( newname, "attribute", "InitXmlAttribute", 0, status );
4420    CheckName( newpref, "attribute", "InitXmlAttribute", 1, status );
4421 
4422 /* Initialise the parent XmlObject component. */
4423    InitXmlObject( (AstXmlObject *) new, type, status );
4424 
4425 /* Initialise the items specific to this class of structure. */
4426    new->name = astStore( NULL, newname, strlen( newname ) + 1 );
4427    new->value = astStore( NULL, value, strlen( value ) + 1 );
4428    new->prefix = NULL;
4429    if( newpref ) {
4430       nc = strlen( newpref );
4431       if( nc > 0 ) new->prefix = astStore( NULL, newpref, nc + 1 );
4432    }
4433 
4434 /* Free any name and prefix extracted from the supplied name string */
4435    if( colon ) {
4436       newname = astFree( newname );
4437       newpref = astFree( newpref );
4438    }
4439 }
4440 
InitXmlCDataSection(AstXmlCDataSection * new,int type,const char * text,int * status)4441 static void InitXmlCDataSection( AstXmlCDataSection *new, int type,
4442                                  const char *text, int *status ){
4443 /*
4444 *  Name:
4445 *     InitXmlCDataSection
4446 
4447 *  Purpose:
4448 *     Initialise a new XmlCDataSection.
4449 
4450 *  Type:
4451 *     Private function.
4452 
4453 *  Synopsis:
4454 *     #include "xml.h"
4455 *     InitXmlCDataSection( AstXmlCDataSection *new, int type,
4456 *                          const char *text, int *status )
4457 
4458 *  Description:
4459 *     This function initialises supplied memory to hold an XmlCDataSection
4460 *     structure.
4461 
4462 *  Parameters:
4463 *     new
4464 *        The memory in which to initialise the structure.
4465 *     type
4466 *        An identifier for the structure type.
4467 *     text
4468 *        Pointer to a null terminated string holding the text.
4469 *     status
4470 *        Pointer to the inherited status variable.
4471 */
4472 
4473 /* Check the global error status. */
4474    if( !astOK ) return;
4475 
4476 /* Check the supplied object type is appropriate for the class of
4477    structure being initialised. If not report an error. */
4478    if( !CheckType( type, AST__XMLCDATA, status ) ){
4479       astError( AST__INTER, "InitXmlCDataSection: Supplied object type (%d) "
4480                 "does not represent an XmlCDataSection", status, type );
4481    }
4482 
4483 /* Initialise the parent XmlObject component. */
4484    InitXmlObject( (AstXmlObject *) new, type, status );
4485 
4486 /* Ensure we have non-NULL pointers. */
4487    if( !text ) text = "";
4488 
4489 /* Initialise the items specific to this class of structure. */
4490    new->text = astStore( NULL, text, strlen( text ) + 1 );
4491 }
4492 
InitXmlWhite(AstXmlWhite * new,int type,const char * text,int * status)4493 static void InitXmlWhite( AstXmlWhite *new, int type, const char *text, int *status ){
4494 /*
4495 *  Name:
4496 *     InitXmlWhite
4497 
4498 *  Purpose:
4499 *     Initialise a new XmlWhite.
4500 
4501 *  Type:
4502 *     Private function.
4503 
4504 *  Synopsis:
4505 *     #include "xml.h"
4506 *     InitXmlWhite( AstXmlWhite *new, int type, const char *text, int *status )
4507 
4508 *  Description:
4509 *     This function initialises supplied memory to hold an XmlWhite
4510 *     structure.
4511 
4512 *  Parameters:
4513 *     new
4514 *        The memory in which to initialise the structure.
4515 *     type
4516 *        An identifier for the structure type.
4517 *     text
4518 *        Pointer to a null terminated string holding the text.
4519 *     status
4520 *        Pointer to the inherited status variable.
4521 */
4522 
4523 /* Local Variables:  */
4524    const char *c;          /* Pointer to next character */
4525 
4526 /* Check the global error status. */
4527    if( !astOK ) return;
4528 
4529 /* Check the supplied object type is appropriate for the class of
4530    structure being initialised. If not report an error. */
4531    if( !CheckType( type, AST__XMLWHITE, status ) ){
4532       astError( AST__INTER, "InitXmlWhite: Supplied object type (%d) "
4533                 "does not represent an XmlWhite", status, type );
4534    }
4535 
4536 /* Initialise the parent XmlObject component. */
4537    InitXmlObject( (AstXmlObject *) new, type, status );
4538 
4539 /* Ensure we have non-NULL pointers. */
4540    if( !text ) text = "";
4541 
4542 /* Report an error if the text is not white. */
4543    c = text - 1;
4544    while( *(++c) ) {
4545       if( !isspace( *c ) ) {
4546          astError( AST__XMLCM, "InitXmlWhite(xml): Illegal XML whitespace "
4547                    "string supplied \"%s\" - not all characters are white.", status,
4548                     text );
4549          break;
4550       }
4551    }
4552 
4553 /* Initialise the items specific to this class of structure. */
4554    new->text = astStore( NULL, text, strlen( text ) + 1 );
4555 }
4556 
InitXmlBlack(AstXmlBlack * new,int type,const char * text,int * status)4557 static void InitXmlBlack( AstXmlBlack *new, int type, const char *text, int *status ){
4558 /*
4559 *  Name:
4560 *     InitXmlBlack
4561 
4562 *  Purpose:
4563 *     Initialise a new XmlBlack.
4564 
4565 *  Type:
4566 *     Private function.
4567 
4568 *  Synopsis:
4569 *     #include "xml.h"
4570 *     InitXmlBlack( AstXmlBlack *new, int type, const char *text, int *status )
4571 
4572 *  Description:
4573 *     This function initialises supplied memory to hold an XmlBlack
4574 *     structure.
4575 
4576 *  Parameters:
4577 *     new
4578 *        The memory in which to initialise the structure.
4579 *     type
4580 *        An identifier for the structure type.
4581 *     text
4582 *        Pointer to a null terminated string holding the text.
4583 *     status
4584 *        Pointer to the inherited status variable.
4585 */
4586 
4587 /* Check the global error status. */
4588    if( !astOK ) return;
4589 
4590 /* Check the supplied object type is appropriate for the class of
4591    structure being initialised. If not report an error. */
4592    if( !CheckType( type, AST__XMLBLACK, status ) ){
4593       astError( AST__INTER, "InitXmlBlack: Supplied object type (%d) "
4594                 "does not represent an XmlBlack", status, type );
4595    }
4596 
4597 /* Initialise the parent XmlObject component. */
4598    InitXmlObject( (AstXmlObject *) new, type, status );
4599 
4600 /* Ensure we have non-NULL pointers. */
4601    if( !text ) text = "";
4602 
4603 /* Initialise the items specific to this class of structure. */
4604    new->text = astStore( NULL, text, strlen( text ) + 1 );
4605 }
4606 
InitXmlComment(AstXmlComment * new,int type,const char * text,int * status)4607 static void InitXmlComment( AstXmlComment *new, int type, const char *text, int *status ){
4608 /*
4609 *  Name:
4610 *     InitXmlComment
4611 
4612 *  Purpose:
4613 *     Initialise a new XmlComment.
4614 
4615 *  Type:
4616 *     Private function.
4617 
4618 *  Synopsis:
4619 *     #include "xml.h"
4620 *     InitXmlComment( AstXmlComment *new, int type, const char *text, int *status )
4621 
4622 *  Description:
4623 *     This function initialises supplied memory to hold an XmlComment
4624 *     structure.
4625 
4626 *  Parameters:
4627 *     new
4628 *        The memory in which to initialise the structure.
4629 *     type
4630 *        An identifier for the structure type.
4631 *     text
4632 *        Pointer to a null terminated string holding the text.
4633 *     status
4634 *        Pointer to the inherited status variable.
4635 */
4636 
4637 /* Check the global error status. */
4638    if( !astOK ) return;
4639 
4640 /* Check the supplied object type is appropriate for the class of
4641    structure being initialised. If not report an error. */
4642    if( !CheckType( type, AST__XMLCOM, status ) ){
4643       astError( AST__INTER, "InitXmlComment: Supplied object type (%d) "
4644                 "does not represent an XmlComment", status, type );
4645    }
4646 
4647 /* Initialise the parent XmlObject component. */
4648    InitXmlObject( (AstXmlObject *) new, type, status );
4649 
4650 /* Ensure we have non-NULL pointers. */
4651    if( !text ) text = "";
4652 
4653 /* Initialise the items specific to this class of structure. Report an error
4654    if the comment is illegal. */
4655    if( strstr( text, "--" ) && astOK ) {
4656       astError( AST__XMLCM, "InitXmlCom(xml): Illegal XML comment "
4657                 "supplied \"%s\" - comments may not contain the "
4658                 "string \"--\".", status, text );
4659       new->text = NULL;
4660    } else {
4661       new->text = astStore( NULL, text, strlen( text ) + 1 );
4662    }
4663 }
4664 
InitXmlDeclPI(AstXmlDeclPI * new,int type,const char * text,int * status)4665 static void InitXmlDeclPI( AstXmlDeclPI *new, int type, const char *text, int *status ){
4666 /*
4667 *  Name:
4668 *     InitXmlDeclPI
4669 
4670 *  Purpose:
4671 *     Initialise a new XmlDeclPI.
4672 
4673 *  Type:
4674 *     Private function.
4675 
4676 *  Synopsis:
4677 *     #include "xml.h"
4678 *     InitXmlDeclPI( AstXmlDeclPI *new, int type, const char *text, int *status )
4679 
4680 *  Description:
4681 *     This function initialises supplied memory to hold an XmlDeclPI
4682 *     structure.
4683 
4684 *  Parameters:
4685 *     new
4686 *        The memory in which to initialise the structure.
4687 *     type
4688 *        An identifier for the structure type.
4689 *     text
4690 *        Pointer to a null terminated string holding the text.
4691 *     status
4692 *        Pointer to the inherited status variable.
4693 */
4694 
4695 /* Check the global error status. */
4696    if( !astOK ) return;
4697 
4698 /* Check the supplied object type is appropriate for the class of
4699    structure being initialised. If not report an error. */
4700    if( !CheckType( type, AST__XMLDEC, status ) ){
4701       astError( AST__INTER, "InitXmlDeclPI: Supplied object type (%d) "
4702                 "does not represent an XmlDeclPI", status, type );
4703    }
4704 
4705 /* Initialise the parent XmlObject component. */
4706    InitXmlObject( (AstXmlObject *) new, type, status );
4707 
4708 /* Ensure we have non-NULL pointers. */
4709    if( !text ) text = "";
4710 
4711 /* Initialise the items specific to this class of structure. */
4712    new->text = astStore( NULL, text, strlen( text ) + 1 );
4713 }
4714 
InitXmlDocument(AstXmlDocument * new,int type,int * status)4715 static void InitXmlDocument( AstXmlDocument *new, int type, int *status ){
4716 /*
4717 *  Name:
4718 *     InitXmlDocument
4719 
4720 *  Purpose:
4721 *     Initialise a new XmlDocument.
4722 
4723 *  Type:
4724 *     Private function.
4725 
4726 *  Synopsis:
4727 *     #include "xml.h"
4728 *     InitXmlDocument( AstXmlDocument *new, int type, int *status )
4729 
4730 *  Description:
4731 *     This function initialises supplied memory to hold an XmlDocument
4732 *     structure.
4733 
4734 *  Parameters:
4735 *     new
4736 *        The memory in which to initialise the structure.
4737 *     type
4738 *        An identifier for the structure type.
4739 *     status
4740 *        Pointer to the inherited status variable.
4741 */
4742 
4743 /* Check the global error status. */
4744    if( !astOK ) return;
4745 
4746 /* Check the supplied object type is appropriate for the class of
4747    structure being initialised. If not report an error. */
4748    if( !CheckType( type, AST__XMLDOC, status ) ){
4749       astError( AST__INTER, "InitXmlDocument: Supplied object type (%d) "
4750                 "does not represent an XmlDocument", status, type );
4751    }
4752 
4753 /* Initialise the parent XmlObject */
4754    InitXmlObject( (AstXmlObject *) new, type, status );
4755 
4756 /* Initialise the items specific to this class of structure. */
4757    new->prolog = NULL;
4758    new->root = NULL;
4759    new->epilog = NULL;
4760    new->nepi = 0;
4761    new->current = NULL;
4762 }
4763 
InitXmlDTDec(AstXmlDTDec * new,int type,const char * name,const char * external,const char * internal,int * status)4764 static void InitXmlDTDec( AstXmlDTDec *new, int type, const char *name,
4765                           const char *external, const char *internal, int *status ){
4766 /*
4767 *  Name:
4768 *     InitXmlDTDec
4769 
4770 *  Purpose:
4771 *     Initialise a new XmlDTDec.
4772 
4773 *  Type:
4774 *     Private function.
4775 
4776 *  Synopsis:
4777 *     #include "xml.h"
4778 *     void InitXmlDTDec( AstXmlDTDec *new, int type, const char *name,
4779 *                        const char *external, const char *internal, int *status )
4780 
4781 *  Description:
4782 *     This function initialises supplied memory to hold an XmlDTDec
4783 *     structure.
4784 
4785 *  Parameters:
4786 *     new
4787 *        The memory in which to initialise the structure.
4788 *     type
4789 *        An identifier for the structure type.
4790 *     name
4791 *        The document type name
4792 *     external
4793 *        The external SYSTEM id.
4794 *     internal
4795 *        The internal declaration markup text (this is not checked or
4796 *        parsed).
4797 *     status
4798 *        Pointer to the inherited status variable.
4799 */
4800 
4801 /* Check the global error status. */
4802    if( !astOK ) return;
4803 
4804 /* Check the supplied object type is appropriate for the class of
4805    structure being initialised. If not report an error. */
4806    if( !CheckType( type, AST__XMLDTD, status ) ){
4807       astError( AST__INTER, "InitXmlDTDec: Supplied object type (%d) "
4808                 "does not represent an XmlDTDec", status, type );
4809    }
4810 
4811 /* Initialise the parent XmlObject */
4812    InitXmlObject( (AstXmlObject *) new, type, status );
4813 
4814 /* Ensure we have non-NULL pointers. */
4815    if( !name ) name = "";
4816    if( !external ) external = "";
4817    if( !internal ) internal = "";
4818 
4819 /* Initialise the items specific to this class of structure. */
4820    new->name = astStore( NULL, name, strlen( name ) + 1 );
4821    new->external = astStore( NULL, external, strlen( external ) + 1 );
4822    new->internal = astStore( NULL, internal, strlen( internal ) + 1 );
4823 }
4824 
InitXmlElement(AstXmlElement * new,int type,const char * name,const char * prefix,int * status)4825 static void InitXmlElement( AstXmlElement *new, int type, const char *name,
4826                             const char *prefix, int *status ){
4827 /*
4828 *  Name:
4829 *     InitXmlElement
4830 
4831 *  Purpose:
4832 *     Initialise a new XmlElement.
4833 
4834 *  Type:
4835 *     Private function.
4836 
4837 *  Synopsis:
4838 *     #include "xml.h"
4839 *     InitXmlElement( AstXmlElement *new, int type, const char *name,
4840 *                     const char *prefix, int *status )
4841 
4842 *  Description:
4843 *     This function initialises supplied memory to hold an XmlElement
4844 *     structure.
4845 
4846 *  Parameters:
4847 *     new
4848 *        The memory in which to initialise the structure.
4849 *     type
4850 *        An identifier for the structure type.
4851 *     name
4852 *        The name for the element.
4853 *     prefix
4854 *        The namespace prefix for the element. May be NULL or blank, in
4855 *        which case any prefix at the start of "name" is used.
4856 *     status
4857 *        Pointer to the inherited status variable.
4858 */
4859 
4860 /* Local Variables: */
4861    const char *colon;         /* Pointer to colon within supplied name */
4862    char *newname;             /* Pointer to name string (no prefix) */
4863    char *newpref;             /* Pointer to name string */
4864    int nc;                    /* Length of prefix string */
4865 
4866 /* Check the global error status. */
4867    if( !astOK ) return;
4868 
4869 /* Check the supplied object type is appropriate for the class of
4870    structure being initialised. If not report an error. */
4871    if( !CheckType( type, AST__XMLELEM, status ) ){
4872       astError( AST__INTER, "InitXmlElement: Supplied object type (%d) "
4873                 "does not represent an XmlElement", status, type );
4874    }
4875 
4876 /* Ensure we have non-NULL pointers. */
4877    if( !name ) name = "";
4878 
4879 /* If no prefix was supplied, extract any prefix from the start of the
4880    supplied name. */
4881    newname = (char *) name;
4882    newpref = (char *) prefix;
4883    colon = NULL;
4884 
4885    if( !prefix || astChrLen( prefix ) == 0 ){
4886       colon = strchr( name, ':' );
4887       if( colon ) {
4888          nc = colon - name;
4889          newpref = astStore( NULL, name, nc + 1 );
4890          newpref[ nc ] = 0;
4891 
4892          nc = strlen( name ) - ( colon - name ) - 1;
4893          newname = astStore( NULL, colon + 1, nc + 1 );
4894          newname[ nc ] = 0;
4895       }
4896    }
4897 
4898 /* Check the supplied name and prefix are valid XML 'names'. */
4899    CheckName( newname, "element", "InitXmlElement", 0, status );
4900    CheckName( newpref, "element", "InitXmlElement", 1, status );
4901 
4902 /* Initialise the parent XmlObject component. */
4903    InitXmlObject( (AstXmlObject *) new, type, status );
4904 
4905 /* Initialise the items specific to this class of structure. */
4906    new->name = astStore( NULL, newname, strlen( newname ) + 1 );
4907    new->attrs = NULL;
4908    new->nattr = 0;
4909    new->items = NULL;
4910    new->nitem = 0;
4911    new->defns = NULL;
4912    new->nsprefs = NULL;
4913    new->nnspref = 0;
4914    new->complete = 0;
4915 
4916    new->prefix = NULL;
4917    if( newpref ) {
4918       nc = strlen( newpref );
4919       if( nc > 0 ) new->prefix = astStore( NULL, newpref, nc + 1 );
4920    }
4921 
4922 /* Free any name and prefix extracted from the supplied name string */
4923    if( colon ) {
4924       newname = astFree( newname );
4925       newpref = astFree( newpref );
4926    }
4927 }
4928 
InitXmlNamespace(AstXmlNamespace * new,int type,const char * prefix,const char * uri,int * status)4929 static void InitXmlNamespace( AstXmlNamespace *new, int type, const char *prefix,
4930                               const char *uri, int *status ){
4931 /*
4932 *  Name:
4933 *     InitXmlNamespace
4934 
4935 *  Purpose:
4936 *     Initialise a new XmlNamespace.
4937 
4938 *  Type:
4939 *     Private function.
4940 
4941 *  Synopsis:
4942 *     #include "xml.h"
4943 *     InitXmlNamespace( AstXmlNamespace *new, int type, const char *prefix,
4944 *                       const char *uri, int *status )
4945 
4946 *  Description:
4947 *     This function initialises supplied memory to hold an XmlNamespace
4948 *     structure.
4949 
4950 *  Parameters:
4951 *     new
4952 *        The memory in which to initialise the structure.
4953 *     type
4954 *        An identifier for the structure type.
4955 *     prefix
4956 *        Pointer to a null terminated string holding the namespace prefix.
4957 *     uri
4958 *        Pointer to a null terminated string holding the namespace URI.
4959 *     status
4960 *        Pointer to the inherited status variable.
4961 */
4962 
4963 /* Check the global error status. */
4964    if( !astOK ) return;
4965 
4966 /* Check the supplied object type is appropriate for the class of
4967    structure being initialised. If not report an error. */
4968    if( !CheckType( type, AST__XMLNAME, status ) ){
4969       astError( AST__INTER, "InitXmlNamespace: Supplied object type (%d) "
4970                 "does not represent an XmlNamespace", status, type );
4971    }
4972 
4973 /* Ensure we have non-NULL pointers. */
4974    if( !prefix ) prefix = "";
4975    if( !uri ) uri = "";
4976 
4977 /* Check the supplied prefix is a valid XML 'name'. */
4978    CheckName( prefix, "namespace prefix", "InitXmlNamespace", 0, status );
4979 
4980 /* Initialise the parent XmlObject component. */
4981    InitXmlObject( (AstXmlObject *) new, type, status );
4982 
4983 /* Initialise the items specific to this class of structure. */
4984    new->prefix = astStore( NULL, prefix, strlen( prefix ) + 1 );
4985    new->uri = astStore( NULL, uri, strlen( uri ) + 1 );
4986 }
4987 
InitXmlObject(AstXmlObject * new,long int type,int * status)4988 static void InitXmlObject( AstXmlObject *new, long int type, int *status ){
4989 /*
4990 *  Name:
4991 *     InitXmlObject
4992 
4993 *  Purpose:
4994 *     Initialise a new XmlObject.
4995 
4996 *  Type:
4997 *     Private function.
4998 
4999 *  Synopsis:
5000 *     #include "xml.h"
5001 *     InitXmlObject( AstXmlObject *new, long int type, int *status )
5002 
5003 *  Description:
5004 *     This function initialises supplied memory to hold an XmlObject
5005 *     structure.
5006 
5007 *  Parameters:
5008 *     new
5009 *        The memory in which to initialise the structure.
5010 *     type
5011 *        An identifier for the structure type.
5012 *     status
5013 *        Pointer to the inherited status variable.
5014 */
5015 
5016 /* Local Variables: */
5017    astDECLARE_GLOBALS        /* Pointer to thread-specific global data */
5018 
5019 /* Check the global error status. */
5020    if( !astOK ) return;
5021 
5022 /* If needed, get a pointer to the thread specific global data structure. */
5023    astGET_GLOBALS(NULL);
5024 
5025 /* Check the supplied object type is OK. Report an error if not. */
5026    if( !CheckType( type, AST__XMLOBJECT, status ) ){
5027       astError( AST__INTER, "InitXmlObject: Supplied object type (%ld) "
5028                 "is not appropriate for an XmlObject", status, type );
5029    }
5030 
5031 /* This class of structure is the base class for XML objects so it has no
5032    parent class to be initialised. So just initialise the items specific to
5033    this class of structure. */
5034    new->parent = NULL;
5035    new->type = type;
5036    new->id = next_id++;
5037 
5038 #ifdef DEBUG
5039 /* Add the new XmlObject to the list of all XmlObjects. */
5040    AddObjectToList( new );
5041 #endif
5042 
5043 }
5044 
InitXmlPI(AstXmlPI * new,int type,const char * target,const char * text,int * status)5045 static void InitXmlPI( AstXmlPI *new, int type, const char *target,
5046                        const char *text, int *status ){
5047 /*
5048 *  Name:
5049 *     InitXmlPI
5050 
5051 *  Purpose:
5052 *     Initialise a new XmlPI.
5053 
5054 *  Type:
5055 *     Private function.
5056 
5057 *  Synopsis:
5058 *     #include "xml.h"
5059 *     InitXmlPI( AstXmlPI *new, int type, const char *target,
5060 *                const char *text, int *status )
5061 
5062 *  Description:
5063 *     This function initialises supplied memory to hold an XmlPI
5064 *     structure.
5065 
5066 *  Parameters:
5067 *     new
5068 *        The memory in which to initialise the structure.
5069 *     type
5070 *        An identifier for the structure type.
5071 *     target
5072 *        Pointer to a null terminated string holding the PI target.
5073 *     text
5074 *        Pointer to a null terminated string holding the PI text.
5075 *     status
5076 *        Pointer to the inherited status variable.
5077 */
5078 
5079 /* Check the global error status. */
5080    if( !astOK ) return;
5081 
5082 /* Check the supplied object type is appropriate for the class of
5083    structure being initialised. If not report an error. */
5084    if( !CheckType( type, AST__XMLPI, status ) ){
5085       astError( AST__INTER, "InitXmlPI: Supplied object type (%d) "
5086                 "does not represent an XmlPI", status, type );
5087    }
5088 
5089 /* Initialise the parent XmlObject component. */
5090    InitXmlObject( (AstXmlObject *) new, type, status );
5091 
5092 /* Ensure we have non-NULL pointers. */
5093    if( !target ) target = "";
5094    if( !text ) text = "";
5095 
5096 /* Initialise the items specific to this class of structure. Report an error
5097    if anything is illegal. */
5098    new->target = NULL;
5099    new->text = NULL;
5100 
5101    if( !Ustrcmp( target, "XML", status ) && astOK ) {
5102       astError( AST__XMLPT, "InitXmlPI(xml): Illegal XML PI target \"%s\""
5103                 " supplied.", status, target );
5104    } else {
5105       new->target = astStore( NULL, target, strlen( target ) + 1 );
5106       new->text = astStore( NULL, text, strlen( text ) + 1 );
5107    }
5108 }
5109 
InitXmlPrologue(AstXmlPrologue * new,int type,int * status)5110 static void InitXmlPrologue( AstXmlPrologue *new, int type, int *status ){
5111 /*
5112 *  Name:
5113 *     InitXmlPrologue
5114 
5115 *  Purpose:
5116 *     Initialise a new XmlPrologue.
5117 
5118 *  Type:
5119 *     Private function.
5120 
5121 *  Synopsis:
5122 *     #include "xml.h"
5123 *     InitXmlPrologue( AstXmlPrologue *new, int type, int *status )
5124 
5125 *  Description:
5126 *     This function initialises supplied memory to hold an XmlPrologue
5127 *     structure.
5128 
5129 *  Parameters:
5130 *     new
5131 *        The memory in which to initialise the structure.
5132 *     type
5133 *        An identifier for the structure type.
5134 *     status
5135 *        Pointer to the inherited status variable.
5136 */
5137 
5138 /* Check the global error status. */
5139    if( !astOK ) return;
5140 
5141 /* Check the supplied object type is appropriate for the class of
5142    structure being initialised. If not report an error. */
5143    if( !CheckType( type, AST__XMLPRO, status ) ){
5144       astError( AST__INTER, "InitXmlPrologue: Supplied object type (%d) "
5145                 "does not represent an XmlPrologue", status, type );
5146    }
5147 
5148 /* Initialise the parent XmlObject */
5149    InitXmlObject( (AstXmlObject *) new, type, status );
5150 
5151 /* Initialise the items specific to this class of structure. */
5152    new->xmldecl = NULL;
5153    new->misc1 = NULL;
5154    new->nmisc1 = 0;
5155    new->dtdec = NULL;
5156    new->misc2 = NULL;
5157    new->nmisc2 = 0;
5158 }
5159 
MatchName(AstXmlElement * this,const char * name,int * status)5160 static int MatchName( AstXmlElement *this, const char *name, int *status ){
5161 /*
5162 *  Name:
5163 *     MatchName
5164 
5165 *  Purpose:
5166 *     Check that an element has a specified name and/or prefix.
5167 
5168 *  Type:
5169 *     Private function.
5170 
5171 *  Synopsis:
5172 *     #include "xml.h"
5173 *     int MatchName( AstXmlElement *this, const char *name, int *status )
5174 
5175 *  Description:
5176 *     This function checks that an element has a specified name and/or prefix.
5177 
5178 *  Parameters:
5179 *     this
5180 *        The XmlElement to check.
5181 *     name
5182 *        The name for the element (may include a namespace prefix).
5183 *     status
5184 *        Pointer to the inherited status variable.
5185 
5186 *  Returned Value:
5187 *     One if the supplied element has the supplie dname/prefix. Zero
5188 *     otherwise.
5189 
5190 */
5191 
5192 
5193 /* Local Variables: */
5194    const char *colon;         /* Pointer to colon within supplied name */
5195    char *newname;             /* Pointer to name string (no prefix) */
5196    char *newpref;             /* Pointer to name string */
5197    int nc;                    /* Length of prefix string */
5198    int result;                /* Returned value */
5199 
5200 /* Initialise */
5201    result = 0;
5202 
5203 /* Check the global error status. */
5204    if( !astOK ) return result;
5205 
5206 /* Extract any prefix from the start of the supplied name. */
5207    newpref = NULL;
5208    newname = (char *) name;
5209    colon = strchr( name, ':' );
5210    if( colon ) {
5211       nc = colon - name;
5212       newpref = astStore( NULL, name, nc + 1 );
5213       newpref[ nc ] = 0;
5214 
5215       nc = strlen( name ) - ( colon - name ) - 1;
5216       newname = astStore( NULL, colon + 1, nc + 1 );
5217       newname[ nc ] = 0;
5218    }
5219 
5220 /* Compare the prefix. */
5221    if( newpref && this->prefix ) {
5222       result = !strcmp( newpref, this->prefix );
5223 
5224    } else if( !newpref && !this->prefix ) {
5225       result = 1;
5226 
5227    } else {
5228       result = 0;
5229    }
5230 
5231 /* If the prefixes matches, compare the names */
5232    if( result ) {
5233       if( newname && this->name ) {
5234          result = !strcmp( newname, this->name );
5235 
5236       } else if( !newname && !this->name ) {
5237          result = 1;
5238 
5239       } else {
5240          result = 0;
5241       }
5242    }
5243 
5244 /* Free any name and prefix extracted from the supplied name string */
5245    if( colon ) {
5246       newname = astFree( newname );
5247       newpref = astFree( newpref );
5248    }
5249 
5250 /* Return the result. */
5251    return result;
5252 }
5253 
NewAttribute(const char * name,const char * value,const char * prefix,int * status)5254 static AstXmlAttribute *NewAttribute( const char *name, const char *value,
5255                                       const char *prefix, int *status ){
5256 /*
5257 *  Name:
5258 *     NewAttribute
5259 
5260 *  Purpose:
5261 *     Create a new XmlAttribute.
5262 
5263 *  Type:
5264 *     Private function.
5265 
5266 *  Synopsis:
5267 *     #include "xml.h"
5268 *     AstXmlAttribute *NewAttribute( const char *name, const char *value,
5269 *                                    const char *prefix, int *status )
5270 
5271 *  Description:
5272 *     This function creates a new XmlAttribute structure representing an
5273 *     XML attribute with the given name, value and namespace prefix.
5274 
5275 *  Parameters:
5276 *     name
5277 *        Pointer to a null terminated string containing the attribute name.
5278 *     value
5279 *        Pointer to a null terminated string containing the attribute value.
5280 *     prefix
5281 *        Pointer to a null terminated string containing the attribute
5282 *        namespace prefix (may be NULL or blank).
5283 *     status
5284 *        Pointer to the inherited status variable.
5285 
5286 *  Returned Value:
5287 *     A pointer to the new structure is returned.
5288 
5289 *  Notes:
5290 *     - A NULL pointer is returned if the inherited status value
5291 *     indicates an error has occurred on entry, or if this function
5292 *     should fail for any reason.
5293 */
5294 
5295 /* Local Variables: */
5296    AstXmlAttribute *new;        /* The returned pointer */
5297 
5298 /* Initialise */
5299    new = NULL;
5300 
5301 /* Check the global error status. */
5302    if( !astOK ) return new;
5303 
5304 /* Allocate space for the new structure. */
5305    new = (AstXmlAttribute *) astMalloc( sizeof( AstXmlAttribute ) );
5306 
5307 /* Initialise it. */
5308    InitXmlAttribute( new, AST__XMLATTR, name, value, prefix, status );
5309 
5310 /* If an error occurred, delete the new structure. */
5311    if( !astOK ) new = astXmlDelete( new );
5312 
5313 /* Return the result. */
5314    return new;
5315 
5316 }
5317 
NewDocument(int * status)5318 static AstXmlDocument *NewDocument( int *status ){
5319 /*
5320 *  Name:
5321 *     NewDocument
5322 
5323 *  Purpose:
5324 *     Create a new empty XmlDocument.
5325 
5326 *  Type:
5327 *     Private function.
5328 
5329 *  Synopsis:
5330 *     #include "xml.h"
5331 *     AstXmlDocument *NewDocument( int *status )
5332 
5333 *  Description:
5334 *     This function creates a new empty XmlDocument structure representing
5335 *     an entire XML Document.
5336 
5337 *  Parameters:
5338 *     status
5339 *        Pointer to the inherited status variable.
5340 
5341 *  Returned Value:
5342 *     A pointer to the new structure is returned.
5343 
5344 *  Notes:
5345 *     - A NULL pointer is returned if the inherited status value
5346 *     indicates an error has occurred on entry, or if this function
5347 *     should fail for any reason.
5348 */
5349 
5350 /* Local Variables: */
5351    AstXmlDocument *new;        /* The returned pointer */
5352 
5353 /* Initialise */
5354    new = NULL;
5355 
5356 /* Check the global error status. */
5357    if( !astOK ) return new;
5358 
5359 /* Allocate space for the new structure. */
5360    new = (AstXmlDocument *) astMalloc( sizeof( AstXmlDocument ) );
5361 
5362 /* Initialise it. */
5363    InitXmlDocument( new, AST__XMLDOC, status );
5364 
5365 /* If an error occurred, delete the new structure. */
5366    if( !astOK ) new = astXmlDelete( new );
5367 
5368 /* Return the result. */
5369    return new;
5370 
5371 }
5372 
NewNamespace(const char * prefix,const char * uri,int * status)5373 static AstXmlNamespace *NewNamespace( const char *prefix, const char *uri, int *status ){
5374 /*
5375 *  Name:
5376 *     NewNamespace
5377 
5378 *  Purpose:
5379 *     Create a new XmlNamespace.
5380 
5381 *  Type:
5382 *     Private function.
5383 
5384 *  Synopsis:
5385 *     #include "xml.h"
5386 *     AstXmlNamespace *NewNamespace( const char *prefix,
5387 *                                    const char *uri, int *status )
5388 
5389 *  Description:
5390 *     This function creates a new XmlNamespace structure representing an
5391 *     XML namespace with the given prefix and uri.
5392 
5393 *  Parameters:
5394 *     prefix
5395 *        Pointer to a null terminated string containing the namespace prefix.
5396 *     uri
5397 *        Pointer to a null terminated string containing the associated URI.
5398 *     status
5399 *        Pointer to the inherited status variable.
5400 
5401 *  Returned Value:
5402 *     A pointer to the new structure is returned.
5403 
5404 *  Notes:
5405 *     - A NULL pointer is returned if the inherited status value
5406 *     indicates an error has occurred on entry, or if this function
5407 *     should fail for any reason.
5408 */
5409 
5410 /* Local Variables: */
5411    AstXmlNamespace *new;        /* The returned pointer */
5412 
5413 /* Initialise */
5414    new = NULL;
5415 
5416 /* Check the global error status. */
5417    if( !astOK ) return new;
5418 
5419 /* Allocate space for the new structure. */
5420    new = (AstXmlNamespace *) astMalloc( sizeof( AstXmlNamespace ) );
5421 
5422 /* Initialise it. */
5423    InitXmlNamespace( new, AST__XMLNAME, prefix, uri, status );
5424 
5425 /* If an error occurred, delete the new structure. */
5426    if( !astOK ) new = astXmlDelete( new );
5427 
5428 /* Return the result. */
5429    return new;
5430 
5431 }
5432 
NewPrologue(AstXmlDocument * doc,int * status)5433 static AstXmlPrologue *NewPrologue( AstXmlDocument *doc, int *status ){
5434 /*
5435 *  Name:
5436 *     NewPrologue
5437 
5438 *  Purpose:
5439 *     Create a new empty XmlPrologue.
5440 
5441 *  Type:
5442 *     Private function.
5443 
5444 *  Synopsis:
5445 *     #include "xml.h"
5446 *     AstXmlPrologue *NewPrologue( AstXmlDocument *doc, int *status )
5447 
5448 *  Description:
5449 *     This function creates a new empty XmlPrologue structure representing
5450 *     an entire prologue.
5451 
5452 *  Parameters:
5453 *     doc
5454 *        A pointer to the XmlDocument to add the XmlPrologue to, or NULL.
5455 *     status
5456 *        Pointer to the inherited status variable.
5457 
5458 *  Returned Value:
5459 *     A pointer to the new structure is returned.
5460 
5461 *  Notes:
5462 *     - A NULL pointer is returned if the inherited status value
5463 *     indicates an error has occurred on entry, or if this function
5464 *     should fail for any reason.
5465 */
5466 
5467 /* Local Variables: */
5468    AstXmlPrologue *new;        /* The returned pointer */
5469 
5470 /* Initialise */
5471    new = NULL;
5472 
5473 /* Check the global error status. */
5474    if( !astOK ) return new;
5475 
5476 /* Allocate space for the new structure. */
5477    new = (AstXmlPrologue *) astMalloc( sizeof( AstXmlPrologue ) );
5478 
5479 /* Initialise it. */
5480    InitXmlPrologue( new, AST__XMLPRO, status );
5481 
5482 /* Set its parent. */
5483    ((AstXmlObject *) new )->parent = (AstXmlParent *) doc;
5484 
5485 /* If an error occurred, delete the new structure. */
5486    if( !astOK ) new = astXmlDelete( new );
5487 
5488 /* Return the result. */
5489    return new;
5490 
5491 }
5492 
RemoveEscapes(const char * text,int * status)5493 static char *RemoveEscapes( const char *text, int *status ){
5494 /*
5495 *  Name:
5496 *     RemoveEscapes
5497 
5498 *  Purpose:
5499 *     Replaces entity references by corresponding ascii characters.
5500 
5501 *  Type:
5502 *     Private function.
5503 
5504 *  Synopsis:
5505 *     #include "xml.h"
5506 *     char *RemoveEscapes( const char *text, int *status )
5507 
5508 *  Description:
5509 *     This function produces a dynamic copy of the supplied text in which
5510 *     occurrences of XML entity references are replaced by the corresponding
5511 *     ASCII text.
5512 
5513 *  Parameters:
5514 *     text
5515 *        A pointer to a text string.
5516 *     status
5517 *        Pointer to the inherited status variable.
5518 
5519 *  Returned Value:
5520 *     A pointer to a dynamically allocated string containing the required
5521 *     copy.
5522 
5523 *  Notes:
5524 *     - NULL is returned if this function is called with the global error
5525 *     status set, or if it should fail for any reason.
5526 */
5527 
5528 /* Local Variables: */
5529    char *d;                  /* Pointer to next returned character */
5530    char *result;             /* Returned pointer */
5531    char rc;                  /* Replacement character */
5532    const char *c;            /* Pointer to next supplied character */
5533    int nc;                   /* Number of characters to skip */
5534 
5535 /* Initialise */
5536    result = NULL;
5537    nc = 0;
5538 
5539 /* Return if the pointer is NULL or if an error has occurred. */
5540    if( !astOK || !text ) return result;
5541 
5542 /* Allocate memory to hold a copy of the supplied text. */
5543    result = astMalloc( strlen( text ) + 1 );
5544 
5545 /* Check the pointer can be used safely. */
5546    if( astOK ) {
5547 
5548 /* Loop round every character in the supplied text. */
5549       c = text - 1;
5550       d = result;
5551       while( *(++c) ) {
5552 
5553 /* If this character marks the start of a entity reference, replace it by
5554    the corresponding ascii character and shuffle the remaining text down. */
5555          if( !strncmp( c, "&amp;", 5 ) ) {
5556             rc = '&';
5557             nc= 4;
5558 
5559          } else if( !strncmp( c, "&lt;", 4 ) ) {
5560             rc = '<';
5561             nc= 3;
5562 
5563          } else if( !strncmp( c, "&gt;", 4 ) ) {
5564             rc = '>';
5565             nc= 3;
5566 
5567          } else if( !strncmp( c, "&apos;", 6 ) ) {
5568             rc = '\'';
5569             nc= 5;
5570 
5571          } else if( !strncmp( c, "&quot;", 6 ) ) {
5572             rc = '"';
5573             nc= 5;
5574 
5575          } else {
5576             rc = 0;
5577          }
5578 
5579          if( rc ) {
5580             *(d++) = rc;
5581             c += nc;
5582          } else {
5583             *(d++) = *c;
5584          }
5585 
5586       }
5587 
5588 /* Terminate the returned string. */
5589       *d = 0;
5590 
5591 /* Reallocate the string to free up any unused space. */
5592       result = astRealloc( result, d - result + 1 );
5593    }
5594 
5595 /* Return the result. */
5596    return result;
5597 }
5598 
5599 #ifdef DEBUG
RemoveObjectFromList(AstXmlObject * obj)5600 static void RemoveObjectFromList( AstXmlObject *obj ){
5601 /*
5602 *  Name:
5603 *     RemoveObjectFromList
5604 
5605 *  Purpose:
5606 *     Removes an XmlObject from a static list of all currently active XmlObjects.
5607 
5608 *  Type:
5609 *     Private function.
5610 
5611 *  Synopsis:
5612 *     #include "xml.h"
5613 *     void RemoveObjectFromList( AstXmlObject *obj )
5614 
5615 *  Description:
5616 *     This function removes the supplied pointer from a static list of
5617 *     pointers, and decrements the number of elements in the list. This list
5618 *     holds pointers to all the XmlObjects which currently exist. If the
5619 *     supplied pointer is not found in the list, this function returns
5620 *     without action.
5621 
5622 *  Parameters:
5623 *     this
5624 *        A pointer to the XmlObject.
5625 
5626 *  Notes:
5627 *     - This function attempts to execute even if an error has already
5628 *     occurred.
5629 */
5630 
5631 /* Local Variavles: */
5632    int i;
5633    int ii;
5634 
5635 /* Locate the supplied pointer within the list of pointers to all
5636    currently active XmlObjects. */
5637    ii = -1;
5638    for( i = 0; i < nobj; i++ ){
5639       if( existing_objects[ i ]->id == obj->id ) {
5640          ii = i;
5641          break;
5642       }
5643    }
5644 
5645 /* Check the pointer was found. */
5646    if( ii != -1 ) {
5647 
5648 /* Shuffle all higher index pointers down one in the list in order to fill
5649    the gap left by removing the supplied pointer. */
5650       for( ii++; ii < nobj; ii++ ){
5651          existing_objects[ ii - 1 ] = existing_objects[ ii ];
5652       }
5653 
5654 /* Decrement the number of pointers in the list. */
5655       nobj--;
5656 
5657 /* Nullify the pointer at the end of the list which is no longer used. */
5658       existing_objects[ nobj ] = NULL;
5659    }
5660 }
5661 #endif
5662 
ResolvePrefix(const char * prefix,AstXmlElement * elem,int * status)5663 static const char *ResolvePrefix( const char *prefix, AstXmlElement *elem, int *status ){
5664 /*
5665 *  Name:
5666 *     ResolvePrefix
5667 
5668 *  Purpose:
5669 *     Find the URI associated with a namespace prefix.
5670 
5671 *  Type:
5672 *     Private function.
5673 
5674 *  Synopsis:
5675 *     #include "xml.h"
5676 *     const char *ResolvePrefix( const char *prefix, AstXmlElement *elem, int *status)
5677 
5678 *  Description:
5679 *     This function searches the namespaces defined within the supplied
5680 *     element for a prefix which matches the supplied prefix. If found,
5681 *     it returns a pointer to the URI string associated with the prefix.
5682 *     If not found, it calls this function recursively on the parent
5683 *     element. If there is no parent element, NULL is returned.
5684 
5685 *  Parameters:
5686 *     prefix
5687 *        Pointer to a string holding the namespace prefix.
5688 *     elem
5689 *        The pointer to the XmlElement.
5690 *     status
5691 *        Pointer to the inherited status variable.
5692 
5693 *  Returned Value:
5694 *     Pointer to a string holding the URI, or NULL if not found.
5695 
5696 *  Notes:
5697 *     - NULL is returned if an error has already occurred, or if this
5698 *     function should fail for any reason.
5699 */
5700 
5701 /* Local Variables: */
5702    AstXmlParent *parent;        /* Parent object */
5703    AstXmlNamespace *ns;         /* Next namespace */
5704    const char *result;          /* Returned pointer */
5705    int i;                       /* Loop count */
5706 
5707 /* Initialise */
5708    result = NULL;
5709 
5710 /* Check the global error status, and the supplied element. */
5711    if( !astOK || !elem ) return result;
5712 
5713 /* Loop round all the namespace definitions in the element. */
5714    for( i = 0; i < elem->nnspref; i++ ) {
5715       ns = elem->nsprefs[ i ];
5716 
5717 /* Compare the namespace prefix with the supplied prefix (case sensitive).
5718    Store a pointer to the associated URI if they match, and leave the
5719    loop. */
5720       if( !strcmp( ns->prefix, prefix ) ) {
5721          result = ns->uri;
5722          break;
5723       }
5724    }
5725 
5726 /* If no matching namespace was found, attempt to resolve the prefix
5727    within the context of the parent element. */
5728    if( !result ) {
5729       parent = ((AstXmlObject *) elem )->parent;
5730       if( astXmlCheckType( parent, AST__XMLELEM ) ) {
5731          result = ResolvePrefix( prefix, (AstXmlElement *) parent, status );
5732       }
5733    }
5734 
5735 /* Return the result. */
5736    return result;
5737 }
5738 
Ustrcmp(const char * a,const char * b,int * status)5739 static int Ustrcmp( const char *a, const char *b, int *status ){
5740 /*
5741 *  Name:
5742 *     Ustrncmp
5743 
5744 *  Purpose:
5745 *     A case blind version of strcmp.
5746 
5747 *  Type:
5748 *     Private function.
5749 
5750 *  Synopsis:
5751 *     #include "xml.h"
5752 *     int Ustrcmp( const char *a, const char *b )
5753 
5754 *  Description:
5755 *     Returns 0 if there are no differences between the two strings, and 1
5756 *     otherwise. Comparisons are case blind.
5757 
5758 *  Parameters:
5759 *     a
5760 *        Pointer to first string.
5761 *     b
5762 *        Pointer to second string.
5763 
5764 *  Returned Value:
5765 *     Zero if the strings match, otherwise one.
5766 
5767 *  Notes:
5768 *     -  This function does not consider the sign of the difference between
5769 *     the two strings, whereas "strcmp" does.
5770 *     -  This function attempts to execute even if an error has occurred.
5771 
5772 */
5773 
5774 /* Local Variables: */
5775    const char *aa;         /* Pointer to next "a" character */
5776    const char *bb;         /* Pointer to next "b" character */
5777    int ret;                /* Returned value */
5778 
5779 /* Initialise the returned value to indicate that the strings match. */
5780    ret = 0;
5781 
5782 /* Initialise pointers to the start of each string. */
5783    aa = a;
5784    bb = b;
5785 
5786 /* Loop round each character. */
5787    while( 1 ){
5788 
5789 /* We leave the loop if either of the strings has been exhausted. */
5790       if( !(*aa ) || !(*bb) ){
5791 
5792 /* If one of the strings has not been exhausted, indicate that the
5793    strings are different. */
5794          if( *aa || *bb ) ret = 1;
5795 
5796 /* Break out of the loop. */
5797          break;
5798 
5799 /* If neither string has been exhausted, convert the next characters to
5800    upper case and compare them, incrementing the pointers to the next
5801    characters at the same time. If they are different, break out of the
5802    loop. */
5803       } else {
5804 
5805          if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){
5806             ret = 1;
5807             break;
5808          }
5809 
5810       }
5811 
5812    }
5813 
5814 /* Return the result. */
5815    return ret;
5816 
5817 }
5818 
5819 #ifdef DEBUG
astXmlTrace(int show)5820 int astXmlTrace( int show ){
5821 /*
5822 *+
5823 *  Name:
5824 *     astXmlTrace
5825 
5826 *  Purpose:
5827 *     List details of XML objects currently in existence.
5828 
5829 *  Type:
5830 *     Protected function.
5831 
5832 *  Synopsis:
5833 *     #include "xml.h"
5834 *     int astXmlTrace( int show )
5835 
5836 *  Description:
5837 *     Lists details of XML objects currently in existence. Details are
5838 *     written to standard output.
5839 
5840 *  Parameters:
5841 *     show
5842 *        - 0, the ID values of all currently active XmlObjects are
5843 *        listed. The objects themselves are unchanged.
5844 *        - 1, each object is displayed using astXmlShow unless it has
5845 *        already been included in the display of a previous object, and then
5846 *        annulled. Consequently, this mode is destructive, and none of the
5847 *        displayed XmlObjects will be acessable afterwards.
5848 *        - 2, each object is displayed using astXmlShow whether or not it
5849 *        has already been included in the display of a previous object.
5850 *        The objects are left unchanged.
5851 *        - 3, nothing is written to standard output, but the number of
5852 *        active XmlObjects is still returned.
5853 
5854 *  Returned Value:
5855 *     The number of XMLObjects which are in existence on entry to this
5856 *     function.
5857 
5858 *-
5859 */
5860 
5861 /* Local Variables: */
5862    AstXmlObject *root;
5863    int i, result, old_status;
5864 
5865    old_status = astStatus;
5866    astClearStatus;
5867 
5868    result = nobj;
5869 
5870    if( show == 0 ) {
5871       printf( "Current list of active XmlObject identifiers: " );
5872       for( i = 0; i < nobj; i++ ) printf( "%d ", existing_objects[ i ]->id );
5873       printf("\n");
5874 
5875    } else if( show ==1 ){
5876       while( nobj > 0 ) {
5877          root = astXmlGetRoot( existing_objects[0] );
5878          printf( "ID = %d (type %ld)\n%s\n------------\n",
5879                  root->id, root->type, astXmlShow( root ) );
5880          root = astXmlAnnulTree( root );
5881       }
5882 
5883    } else if( show == 2 ) {
5884       for( i = 0; i < nobj; i++ ) printf( "%d\n%s\n------------\n",
5885                                           existing_objects[ i ]->id,
5886                                           astXmlShow(existing_objects[ i ]) );
5887       printf("\n");
5888    }
5889 
5890    astSetStatus( old_status );
5891 
5892    return result;
5893 }
5894 #endif
5895 
astXmlReadDocument_(AstXmlDocument ** doc,int (* is_wanted)(AstXmlElement *,int *),int skip,char (* source)(void *,int *),void * data,int * status)5896 AstXmlElement *astXmlReadDocument_( AstXmlDocument **doc,
5897                                    int (*is_wanted)( AstXmlElement *, int * ),
5898                                    int skip, char (*source)( void *, int * ),
5899                                    void *data, int *status ){
5900 /*
5901 *+
5902 *  Name:
5903 *     astXmlReadDocument
5904 
5905 *  Purpose:
5906 *     Read and parse an XML document.
5907 
5908 *  Type:
5909 *     Protected function.
5910 
5911 *  Synopsis:
5912 *     #include "xml.h"
5913 *     AstXmlElement *astXmlReadDocument( AstXmlDocument **doc,
5914 *                                       int (*is_wanted)( AstXmlElement *, int * ),
5915 *                                       int skip, char (*source)( void *, int * ),
5916 *                                       void *data )
5917 
5918 *  Description:
5919 *     This function reads and parses text from an XML source. The text is
5920 *     obtained by calling the supplied "source" function, which returns
5921 *     the next character read from the external source on each invocation.
5922 *
5923 *     The reading scheme combines elements of the SAX and DOM schemes in
5924 *     an attempt to minimise memory requirements (a potential problem with
5925 *     DOM) whilst retaining a simple interface for accessing the XML
5926 *     elements of interest to the client (a potential problem for SAX).
5927 *
5928 *     When an element start tag is encountered in the source, the client
5929 *     is asked to indicate whether the element is of interest. This is
5930 *     done by calling the supplied "is_wanted" function. If the client
5931 *     indicates that the element is of interest, its contents are read
5932 *     and a pointer to a corresponding XmlElement structure is returned.
5933 *     Reading stops when the element has been read. If the client
5934 *     indicates that the element is not of interest, then (if "skip" is
5935 *     non-zero) the contents of the element are skipped over, and reading
5936 *     continues following the element end tag. When the next element is
5937 *     encountered the client will again be asked to indicate its interest
5938 *     in the element. This continues until either the client indicates that
5939 *     an element is of interest, or the end of the source is reached. If
5940 *     "skip" is zero, then an error is reported if the first element in
5941 *     the document is not of interest.
5942 *
5943 *     The client has an option to reply that an element is not itself of
5944 *     interest, but may possibly contain interesting elements. In this case,
5945 *     the sub-elements within the element are read and checked in the same
5946 *     way.
5947 *
5948 *     This function returns, and no more characters are read from the
5949 *     source, once the contents of the first "interesting" element has been
5950 *     read.
5951 *
5952 *     The function thus returns a pointer to an XmlElement containing the
5953 *     entire contents of the first interesting element encountered in the
5954 *     source. This function can then be invoked again to read further
5955 *     interesting elements from the source. In this case, the XmlDocument
5956 *     structure created by the initial invocation (see parameter "doc")
5957 *     must be supplied, as this indicates the point in the total document
5958 *     structure at which the previous "interesting" element was located.
5959 
5960 *  Parameters:
5961 *     doc
5962 *        Address of a location holding a pointer to an AstXmlDocument
5963 *        structure. The AstXmlDocument pointer should be supplied as NULL
5964 *        when invoking this function for the first time on a document
5965 *        source (i.e. when reading from the beginning of the document).
5966 *        In this case a new AstXmlDocument structure will be created and a
5967 *        pointer to it stored at the supplied address. This structure
5968 *        holds the context which enables subsequent invocations of this
5969 *        function to determine the point in the document structure at
5970 *        which to store any further text read from the source. It also
5971 *        holds the document prologue, root element, and epilogue.
5972 *     is_wanted
5973 *        Pointer to a function which is called to decide if the client is
5974 *        interested in each element start tag which has just been read.
5975 *        It has a single argument which is a pointer to the (empty) XmlElement
5976 *        corresponding to the element start tag which has just been read.
5977 *        It returns an integer:
5978 *           -1 : the element is not itself of interest but it may contain
5979 *                an interesting element, so look through the content and
5980 *                ask the client again about any elements found inside it.
5981 *            0 : the element definately contains nothing of interest to
5982 *                the client. kip its content and continue looking for new
5983 *                elements.
5984 *            1 : the element is definately of interest to the client so
5985 *                read its contents and return a pointer to it.
5986 *        If NULL is supplied, a value of "+1" is assumed.
5987 *     skip
5988 *        Indicates if any uninteresting elements may proceed the first
5989 *        element of interest. If zero, then an error is reported if the
5990 *        first element read from the source is not of interest to the client.
5991 *        If non-zero, then any uninteresting elements are simply skipped
5992 *        over until an interesting element is found or the document ends.
5993 *     source
5994 *        Pointer to a function which is called to return the next
5995 *        character from the source. It has a single argument which is
5996 *        used to pass any supplied data to it. It should return zero when
5997 *        the end of the source is reached.
5998 *     data
5999 *        Pointer to a structure to pass to the source function. This
6000 *        structure may contain any data needed by the source function.
6001 
6002 *  Returned Value:
6003 *     A pointer to the first element of interest, or NULL if there are no
6004 *     interesting elements in the source. The returned element will be a
6005 *     descendant of "*doc". For this reason, the returned pointer need not
6006 *     be annulled explicitly since it will be freed when the XmlDocument
6007 *     is annulled. However, if required (e.g. to save memory) it may be
6008 *     annulled before the document is annulled by using astXmlRemoveItem to
6009 *     remove it from its parent, and then using astXmlAnnul to annul it.
6010 
6011 *  Notes:
6012 *     - NULL is returned if an error has already occurred, or if this
6013 *     function should fail for any reason.
6014 *     - It is assumed that the read commences outside any tag (i.e.
6015 *     in between tags or within character data).
6016 *-
6017 */
6018 
6019 /* Local Variables: */
6020    AstXmlElement *result;
6021 
6022 /* Check any supplied pointer is for an XmlDocument. */
6023    astXmlCheckDocument( *doc, 1 );
6024 
6025 /* Read and parse the source text. Indicate that the element being read
6026    *may* contain items of interest to the client. Surround with a mutex
6027    since the supplied functions may not be thread-safe. */
6028    LOCK_MUTEX1;
6029    result = ReadContent( doc, -1, is_wanted, skip, source, data, 0, status );
6030    UNLOCK_MUTEX1;
6031 
6032 /* Return the result. */
6033    return result;
6034 }
6035 
6036 
ReadContent(AstXmlDocument ** doc,int wanted,int (* is_wanted)(AstXmlElement *,int *),int skip,char (* source)(void *,int *),void * data,int depth,int * status)6037 static AstXmlElement *ReadContent( AstXmlDocument **doc, int wanted,
6038                                    int (*is_wanted)( AstXmlElement *, int * ),
6039                                    int skip, char (*source)( void *, int * ),
6040                                    void *data, int depth, int *status ){
6041 /*
6042 *  Name:
6043 *     ReadContent
6044 
6045 *  Purpose:
6046 *     Read and parse an XML document.
6047 
6048 *  Type:
6049 *     Private function.
6050 
6051 *  Synopsis:
6052 *     #include "xml.h"
6053 *     AstXmlElement *ReadContent( AstXmlDocument **doc, int wanted,
6054 *                                 int (*is_wanted)( AstXmlElement *, int * ),
6055 *                                 int skip, char (*source)( void *, int * ),
6056 *                                 void *data, int depth, int *status )
6057 
6058 *  Description:
6059 *     This function reads and parses text from an XML source. The text is
6060 *     obtained by calling the supplied "source" function, which returns
6061 *     the next character read from the external source on each invocation.
6062 *
6063 *     See astXmlReadDocument for more details.
6064 
6065 *  Parameters:
6066 *     doc
6067 *        Address of a location holding a pointer to an AstXmlDocument
6068 *        structure. The AstXmlDocument pointer should be supplied as NULL
6069 *        when invoking this function for the first time on a document
6070 *        source (i.e. when reading from the beginning of the document).
6071 *        In this case a new AstXmlDocument structure will be created and a
6072 *        pointer to it stored at the supplied address. This structure
6073 *        holds the context which enables subsequent invocations of this
6074 *        function to determine the point in the document structure at
6075 *        which to store any further text read from the source. It also
6076 *        holds the document prologue, root element, and epilogue.
6077 *     wanted
6078 *        Indicates if the content read from the XML source is of interest
6079 *        to the client. If a positive value is supplied, all content read
6080 *        from the source (up to the end tag which corresponds to the
6081 *        supplied "parent") is added to the "parent" element (if supplied).
6082 *        If zero is supplied, then all content read from the source is
6083 *        discarded. If a negative value is supplied, then all content up
6084 *        to the first element start tag is discarded. When the first
6085 *        element start tag is encountered, it is passed back to the client
6086 *        by invoking the supplied "is_wanted" function. If this function
6087 *        returns a non-zero value, then the contents of the new element
6088 *        is read (by calling this function recursively) and a pointer to
6089 *        the new element is returned as the function value (reading then
6090 *        stops and the function returns). If the "is_wanted" function returns
6091 *        zero, then the contents of the new element is skipped over, and
6092 *        reading continues until the next element start tag is encountered,
6093 *        when the "is_wanted" function is again invoked.
6094 *     is_wanted
6095 *        Pointer to a function which is called to decide if the client is
6096 *        interested in the element start tag which has just been read.
6097 *        It has a single argument which is a pointer to the (empty) XmlElement
6098 *        corresponding to the element start tag which has just been read.
6099 *        It returns an integer:
6100 *           -1 : the element is not itself of interest but it may contain
6101 *                an interesting element, so look through the content and
6102 *                ask the client again about any elements found inside it.
6103 *            0 : the element definately contains nothing of interest to
6104 *                the client. kip its content and continue looking for new
6105 *                elements.
6106 *            1 : the element is definately of interest to the client so
6107 *                read its contents and return a pointer to it.
6108 *        If NULL is supplied, a value of "+1" is assumed.
6109 *     skip
6110 *        Indicates if any uninteresting elements may proceed the first
6111 *        element of interest. If zero, then an error is reported if the
6112 *        first element read from the source is not of interest to the client.
6113 *        If non-zero, then any uninteresting elements are simply skipped
6114 *        over until an interesting element is found or the document ends.
6115 *     source
6116 *        Pointer to a function which is called to return the next
6117 *        character from the source. It has a single argument which is
6118 *        used to pass any supplied data to it. It should return zero when
6119 *        the end of the source is reached.
6120 *     data
6121 *        Pointer to a structure to pass to the source function. This
6122 *        structure may contain any data needed by the source function.
6123 *     depth
6124 *        Depth of nesting (i.e. zero if this function was invoked from
6125 *        astXmlReadDocument, and a positive value if it was invoked
6126 *        recursively from within itself).
6127 *     status
6128 *        Pointer to the inherited status variable.
6129 
6130 *  Returned Value:
6131 *     A pointer to the first element of interest, or NULL if there are no
6132 *     interesting elements in the source. If the first element of
6133 *     interest has already been found (as indicated by "wanted" being +1)
6134 *     then NULL is returned. The returned element may be a child of a
6135 *     parent element containing namespace definitions (which may itself
6136 *     have a parent, etc). For this reason, the returned pointer should be
6137 *     freed using astXmlAnnulTree rather than astXmlAnnul.
6138 
6139 *  Notes:
6140 *     - NULL is returned if an error has already occurred, or if this
6141 *     function should fail for any reason.
6142 *     - It is assumed that the read commences outside any tag (i.e.
6143 *     in between tags or within character data).
6144 */
6145 
6146 /* Local Variables; */
6147    AstXmlElement *answer;       /* Result of reading a sub-element */
6148    AstXmlElement *parent;       /* Pointer to current parent element */
6149    AstXmlElement *elem;         /* A new element to be read */
6150    AstXmlElement *result;       /* The returned pointer */
6151    char *cc;                    /* Pointer to next character */
6152    char *msg;                   /* Pointer to message buffer */
6153    char *text1;                 /* Pointer to dynamic string */
6154    char *text2;                 /* Pointer to another dynamic string */
6155    char *text3;                 /* Pointer to another dynamic string */
6156    char *text4;                 /* Pointer to another dynamic string */
6157    char c;                      /* Current character read from source */
6158    char lc2;                    /* Last but one character read */
6159    char lc;                     /* Last character read */
6160    char quoted;                 /* Character which opened current quote */
6161    int nc1;                     /* No. of characters stored in text1 */
6162    int nc2;                     /* No. of characters stored in text2 */
6163    int nc3;                     /* No. of characters stored in text2 */
6164    int ncmsg;                   /* Length of "msg" */
6165    int newwanted;               /* Is the new element wanted? */
6166    int state;                   /* Current action being performed */
6167    int prolog_ok;               /* OK for source to start with a prolog? */
6168    int where;                   /* Where to add the item within the document */
6169 
6170 /* Initialise */
6171    result = NULL;
6172    elem = NULL;
6173 
6174 /* Check the global error status. */
6175    if( !astOK ) return result;
6176 
6177 /* If no XmlDocument was supplied, assume we are commencing to read a new
6178    document from the begining. Create a new XmlDocument to store the
6179    prologue, root element and epilogue, together with a pointer to the
6180    "current" element, i.e. the element whose content is currently being
6181    read. Also, since we have not yet asked the client if it is interested
6182    in anything, ignore the supplied "wanted" value and use -1 to ensure
6183    that we ask the client when the first element start tag is encountered. */
6184    if( !*doc ){
6185       prolog_ok = 1;
6186       *doc = NewDocument( status );
6187       wanted = -1;
6188    } else {
6189       prolog_ok = 0;
6190    }
6191 
6192 /* Any content read from the source (except for prologue and epilogue)
6193    will be placed into the "parent" element. A pointer to this element is
6194    stored in the XmlDocument structure. The parent element will always be
6195    a descendant of the root element, or the root element itself. */
6196    parent = (*doc)->current;
6197 
6198 /* If the supplied parent has already been completed (typically because
6199    it was read from an empty element tag), then just return without
6200    action. */
6201    if( parent && parent->complete ) {
6202 
6203 /* If an error has occurred, or if this invocation of ReadContent was
6204    made recursively (rather than by the client), or if we have something
6205    to return, return. */
6206       if( !astOK || depth > 0 || result ) {
6207          return result;
6208 
6209 /* Otherwise, returning would result in returning a null pointer to the
6210    client even though the end of the document may not have been reached.
6211    Revert to state 0 and search for further interesting elements. */
6212       } else {
6213          if( parent != (*doc)->root ) {
6214             (*doc)->current = (AstXmlElement *) ( (AstXmlObject *) parent )->parent;
6215          } else {
6216             (*doc)->current = NULL;
6217          }
6218          parent = (*doc)->current;
6219          state = 0;
6220       }
6221    }
6222 
6223 /* Initialise the previous two characters read. */
6224    lc = 0;
6225    lc2 = 0;
6226 
6227 /* Initialise pointer to dynamically allocated strings. */
6228    text1 = NULL;
6229    text2 = NULL;
6230    text3 = NULL;
6231    msg = NULL;
6232 
6233 /* We are not in a quote. */
6234    quoted = 0;
6235 
6236 /* Initialise the "state" variable which indicates what we are currently
6237    looking for. */
6238    state = 0;
6239 
6240 /* Loop round reading characters from the source. */
6241    while( 1 ) {
6242       c = (*source)( data, status );
6243 
6244 /* Leave the loop if an error occurred whilst reading the character. */
6245       if( !astOK ) break;
6246 
6247 /* If a parent element has been supplied, (i.e. if we are currently
6248    reading the content of an element), or if we are not in state zero,
6249    report an error and leave the loop if the end of the text has been
6250    reached. If no parent was supplied, just leave the loop. */
6251       if( !c ) {
6252          if( parent ) {
6253             astError( AST__XMLWF, "astRead(XmlChan): End of XML input text "
6254                       "reached whilst reading the content of element %s.", status,
6255                        astXmlGetTag( parent, 1 ) );
6256 
6257          } else if( state > 1 ) {
6258             if( msg ) {
6259                astError( AST__XMLWF, "astRead(XmlChan): End of XML input text "
6260                          "reached whilst reading the document epilogue "
6261                          "(\"%s\").", status, msg );
6262             } else {
6263                astError( AST__XMLWF, "astRead(XmlChan): End of XML input text "
6264                          "reached whilst reading the document epilogue." , status);
6265             }
6266          }
6267          break;
6268       }
6269 
6270 /* Save text which is not character data for use in error messages. */
6271       if( state < 2 ) {
6272          if( msg ) msg = astFree( msg );
6273       } else {
6274          msg = AppendChar( msg, &ncmsg, c, status );
6275       }
6276 
6277 /* State 0: Use the first character to decide what sort of content item
6278    follows (character data or a tag of some form). */
6279       if( state == 0 ) {
6280          if( c != '<' ) {
6281             state = 1;
6282             text1 = AppendChar( text1, &nc1, c, status );
6283          } else {
6284             msg = AppendChar( msg, &ncmsg, '<', status );
6285             state = 2;
6286          }
6287 
6288 /* State 1: We are reading character data. The character data ends at the
6289    first occurrence of "<", at which point the character data is added to
6290    the parent if required and we continue to state 2.*/
6291       } else if( state == 1 ) {
6292          if( c != '<' ) {
6293             text1 = AppendChar( text1, &nc1, c, status );
6294          } else {
6295             msg = AppendChar( msg, &ncmsg, '<', status );
6296             if( text1 ){
6297 
6298 /* If we have a parent element, just add it to the element. */
6299                if( parent ) {
6300                   if( wanted > 0 ) {
6301                      text4 = RemoveEscapes( text1, status );
6302                      astXmlAddCharData( (AstXmlParent *) parent, 0, text4 );
6303                      text4 = astFree( text4 );
6304 
6305 
6306 /* If we are not allowed to skip over non-blank content, report an
6307    error if the text is not blank. */
6308                   } else if( !skip ) {
6309                      cc = text1 - 1;
6310                      while( *(++cc) ) {
6311                         if( !isspace( *cc ) ) {
6312                            if( parent ) {
6313                               astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6314                                         "the input data \"%s\" within element %s.", status,
6315                                         text1, astXmlGetTag( parent, 1 ) );
6316                            } else {
6317                               astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6318                                         "the input data: \"%s\".", status, text1 );
6319                            }
6320                            break;
6321                         }
6322                      }
6323                   }
6324 
6325 /* Otherwise, add it to the document prologue or epilogue. */
6326                } else {
6327                   if( (*doc)->root ) {
6328                      where = 3;
6329                   } else if( (*doc)->prolog && (*doc)->prolog->dtdec ){
6330                      where = 2;
6331                   } else {
6332                      where = 1;
6333                   }
6334 
6335                   text4 = RemoveEscapes( text1, status );
6336                   astXmlAddCharData( (AstXmlParent *) *doc, where, text4 );
6337                   text4 = astFree( text4 );
6338                }
6339 
6340                text1 = astFree( text1 );
6341             }
6342             state = 2;
6343          }
6344 
6345 /* State 2: We are using the character following a "<" to determine what
6346    type of tag is commencing. */
6347       } else if( state == 2 ) {
6348 
6349 /* If the character is a ">", report an error. */
6350          if( c == '>' ) {
6351             if( parent ) {
6352                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"<>\" "
6353                          "encountered within element %s.", status, astXmlGetTag( parent, 1 ) );
6354             } else {
6355                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"<>\" "
6356                          "encountered." , status);
6357             }
6358             break;
6359 
6360 /* If the character is a "?", this must be a PI tag. */
6361          } else if( c == '?' ) {
6362             state = 3;
6363 
6364 /* If the character is a "!", it must be a comment or a CDATA section
6365    or a DTD. */
6366          } else if( c == '!' ) {
6367             state = 4;
6368 
6369 /* If the character is a "/", it must be an element end tag. */
6370          } else if( c == '/' ) {
6371             state = 5;
6372 
6373 /* Otherwise, this must be an element start tag. Append the character
6374    to "text1". */
6375          } else {
6376             state = 6;
6377             text1 = AppendChar( text1, &nc1, c, status );
6378          }
6379 
6380 /* State 3: We are reading the initial text following the opening "<?" string
6381    of a PI tag. The characters between the initial "<?" string and the first
6382    space or closing "?>" string is the target text. */
6383       } else if( state == 3 ) {
6384          if( c == '>' && lc == '?' ) {
6385             if( text1 ) text1[ --nc1 ] = 0;
6386             state = 100;
6387          } else if( isspace( c ) ) {
6388             state = 7;
6389          } else {
6390             text1 = AppendChar( text1, &nc1, c, status );
6391          }
6392 
6393 /* State 4: We are using the characters following the opening "<!" text to
6394    determine if the tag is a comment, DTD or CDATA section. */
6395       } else if( state == 4 ) {
6396          if( c == '-' ) {
6397             state = 8;
6398          } else if( c == 'D' ){
6399             state = 16;
6400             text1 = astAppendString( text1, &nc1, "<!D" );
6401          } else if( c == '[' ){
6402             state = 9;
6403             text1 = astAppendString( text1, &nc1, "<![" );
6404          } else {
6405             if( parent ) {
6406                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6407                          "starting with \"<!%c...\" encountered within "
6408                          "element %s.", status, c, astXmlGetTag( parent, 1 ) );
6409             } else {
6410                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6411                          "starting with \"<!%c...\" encountered.", status, c );
6412             }
6413             break;
6414          }
6415 
6416 /* State 5: We are looking for the end of an element end tag. */
6417       } else if( state == 5 ) {
6418          if( c == '>' ) {
6419             state = 101;
6420          } else {
6421             text1 = AppendChar( text1, &nc1, c, status );
6422          }
6423 
6424 /* State 6: We are looking for the (prefix:)name combination at the start of
6425    an element start tag. */
6426       } else if( state == 6 ) {
6427          if( c == '>' ) {
6428             state = ( lc != '/' ) ? 102 : 103;
6429          } else if( isspace( c ) ) {
6430             state = 104;
6431          } else if( c != '/' ){
6432             text1 = AppendChar( text1, &nc1, c, status );
6433          }
6434 
6435 /* State 7: We are reading the remaining text in a PI tag following the target
6436    text. */
6437       } else if( state == 7 ) {
6438          if( c == '>' && lc == '?' ) {
6439             if( text2 ) text2[ --nc2 ] = 0;
6440             state = 100;
6441          } else if( text2 || !isspace( c ) ) {
6442             text2 = AppendChar( text2, &nc2, c, status );
6443          }
6444 
6445 /* State 8: We are looking for the start of the text within a comment tag. */
6446       } else if( state == 8 ) {
6447          if( c == '-' ) {
6448             state = 10;
6449          } else {
6450             if( parent ) {
6451                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6452                          "starting with \"<!-%c...\" encountered within "
6453                          "element %s.", status, c, astXmlGetTag( parent, 1 ) );
6454             } else {
6455                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6456                          "starting with \"<!-%c...\" encountered.", status, c );
6457             }
6458             break;
6459          }
6460 
6461 /* State 9: We are looking for the start of the text within a CDATA tag. */
6462       } else if( state == 9 ) {
6463          if( c == '[' ) {
6464             if( !strcmp( text1, "<![CDATA" ) ) {
6465                state = 11;
6466                text1 = astFree( text1 );
6467             } else {
6468                if( parent ) {
6469                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6470                             "starting with \"%s%c...\" encountered within "
6471                             "element %s.", status, text1, c, astXmlGetTag( parent, 1 )  );
6472                } else {
6473                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6474                             "starting with \"%s%c...\" encountered.", status, text1, c );
6475                }
6476                text1 = astFree( text1 );
6477                break;
6478             }
6479 
6480          } else if( nc1 < 10 ) {
6481             text1 = AppendChar( text1, &nc1, c, status );
6482 
6483          } else {
6484             if( parent ) {
6485                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6486                          "starting with \"%s%c...\" encountered within "
6487                          "element %s.", status, text1, c, astXmlGetTag( parent, 1 )  );
6488             } else {
6489                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6490                          "starting with \"%s%c...\" encountered.", status, text1, c );
6491             }
6492             text1 = astFree( text1 );
6493             break;
6494          }
6495 
6496 /* State 10: We are reading the remaining text in a comment tag. When the end
6497    ">" is reached, check the previous 2 characters are "--" and then terminate
6498    the text1 string in order to remove these two characters from the comment
6499    text.  */
6500       } else if( state == 10 ) {
6501          if( c == '>' && lc == '-' && lc2 == '-' ) {
6502             text1[ nc1 - 2 ] = 0;
6503             state = 105;
6504          } else {
6505             text1 = AppendChar( text1, &nc1, c, status );
6506          }
6507 
6508 /* State 11: We are reading the remaining text in a CDATA tag. */
6509       } else if( state == 11 ) {
6510          if( c == '>' && lc == ']' && lc2 == ']' ) {
6511             text1[ nc1 - 2 ] = 0;
6512             state = 106;
6513          } else {
6514             text1 = AppendChar( text1, &nc1, c, status );
6515          }
6516 
6517 /* State 12: We are looking for an equals sign marking the end of an
6518    attribute name within an element start tag. */
6519       } else if( state == 12 ) {
6520          if( c == '=' ) {
6521             state = 13;
6522 
6523          } else if( c == '>' ) {
6524             if( text1 ) {
6525                if( parent ) {
6526                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6527                             " \"%s...\" encountered within element %s.", status, msg,
6528                             astXmlGetTag( parent, 1 )  );
6529                } else {
6530                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s...\" "
6531                             "encountered.", status, msg );
6532                }
6533                break;
6534             } else {
6535                if( lc == '/' ) {
6536                   state = 108;
6537                } else {
6538                   state = 200;
6539                }
6540             }
6541 
6542          } else if( text1 || !isspace( c ) ) {
6543             if( c != '/' ) text1 = AppendChar( text1, &nc1, c, status );
6544          }
6545 
6546 /* State 13: We are looking for a '"' or ''' marking the start of an attribute
6547    value within an element start tag. */
6548       } else if( state == 13 ) {
6549          if( c == '"' ) {
6550             state = 14;
6551 
6552          } else if( c == '\'' ) {
6553             state = 15;
6554 
6555          } else if( c == '>' ) {
6556             astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute "
6557                       "\"%s\" in XML tag \"%s...\".", status, text1, msg );
6558             break;
6559          }
6560 
6561 /* State 14: We are looking for a '"' marking the end of an attribute value
6562    within an element start tag. */
6563       } else if( state == 14 ) {
6564          if( c == '"' ) {
6565             state = 107;
6566 
6567          } else if( c == '>' ) {
6568             astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute "
6569                       "\"%s\" in XML tag \"%s...\".", status, text1, msg );
6570             break;
6571 
6572          } else {
6573             text2 = AppendChar( text2, &nc2, c, status );
6574          }
6575 
6576 /* State 15: We are looking for a ''' marking the end of an attribute value
6577    within an element start tag. */
6578       } else if( state == 15 ) {
6579          if( c == '\'' ) {
6580             state = 107;
6581 
6582          } else if( c == '>' ) {
6583             astError( AST__XMLWF, "astRead(XmlChan): Illegal value for attribute "
6584                       "\"%s\" in XML tag \"%s...\".", status, text1, msg );
6585             break;
6586 
6587          } else {
6588             text2 = AppendChar( text2, &nc2, c, status );
6589          }
6590 
6591 /* State 16: We are looking for the end of a DOCTYPE string. */
6592       } else if( state == 16 ) {
6593          if( isspace( c ) ) {
6594             if( !strcmp( text1, "<!DOCTYPE" ) ) {
6595                state = 17;
6596                text1 = astFree( text1 );
6597             } else {
6598                if( parent ) {
6599                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6600                             "starting with \"%s%c...\" encountered within "
6601                             "element %s.", status, text1, c, astXmlGetTag( parent, 1 )  );
6602                } else {
6603                   astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6604                             "starting with \"%s%c...\" encountered.", status, text1, c );
6605                }
6606                text1 = astFree( text1 );
6607                break;
6608             }
6609 
6610          } else if( nc1 < 15 ) {
6611             text1 = AppendChar( text1, &nc1, c, status );
6612 
6613          } else {
6614             if( parent ) {
6615                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6616                          "starting with \"%s%c...\" encountered within "
6617                          "element %s.", status, text1, c, astXmlGetTag( parent, 1 )  );
6618             } else {
6619                astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag "
6620                          "starting with \"%s%c...\" encountered.", status, text1, c );
6621             }
6622             text1 = astFree( text1 );
6623             break;
6624          }
6625 
6626 /* State 17: We are looking for the start of a DOCTYPE name string. */
6627       } else if( state == 17 ) {
6628          if( !isspace( c ) ) {
6629             text1 = AppendChar( text1, &nc1, c, status );
6630             state = 18;
6631          }
6632 
6633 /* State 18: We are looking for the end of a DOCTYPE name string. */
6634       } else if( state == 18 ) {
6635          if( isspace( c ) ) {
6636             state = 19;
6637          } else if( c == '>' ) {
6638             state = 109;
6639          } else {
6640             text1 = AppendChar( text1, &nc1, c, status );
6641          }
6642 
6643 /* State 19: We are looking for the start of a string following a DOCTYPE
6644    name string. */
6645       } else if( state == 19 ) {
6646          if( !isspace( c ) ) {
6647             if( c == '[' ) {
6648                state = 20;
6649             } else if( c == '>' ) {
6650                state = 109;
6651             } else {
6652                state = 21;
6653                text2 = AppendChar( text2, &nc2, c, status );
6654             }
6655          }
6656 
6657 /* State 20: We are looking for the "]" marking the end of the internal
6658    markup of a DOCTYPE element. Avoid the contents of quoted strings (such
6659    as #FIXED attribute values). */
6660       } else if( state == 20 ) {
6661          text3 = AppendChar( text3, &nc3, c, status );
6662          if( c == '\'' ) {
6663             if( quoted == '\'' ) {
6664                quoted = 0;
6665             } else if( !quoted ) {
6666                quoted = '\'';
6667             }
6668 
6669          } else if( c == '"' ) {
6670             if( quoted == '"' ) {
6671                quoted = 0;
6672             } else if( !quoted ) {
6673                quoted = '"';
6674             }
6675 
6676          } else if( !quoted && c == ']' ) {
6677             text3[ --nc3 ] = 0;
6678             state = 22;
6679          }
6680 
6681 /* State 21: We are looking for the start of a DOCTYPE internal section. */
6682       } else if( state == 21 ) {
6683          if( c == '[' ) {
6684             state = 20;
6685          } else if( c == '>' ) {
6686             state = 109;
6687          } else {
6688             text2 = AppendChar( text2, &nc2, c, status );
6689          }
6690 
6691 /* State 22: We are looking for the ">" at the end of a DOCTYPE. */
6692       } else if( state == 22 ) {
6693          if( !isspace( c ) ) {
6694             if( c == '>' ) {
6695                state = 109;
6696             } else {
6697                astError( AST__XMLWF, "astRead(XmlChan): Extra text found "
6698                          "at end of XML DOCTYPE tag \"%s\".", status, msg );
6699             }
6700          }
6701 
6702       } else {
6703          astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered "
6704                    "(AST internal programming error).", status, state );
6705       }
6706 
6707 /* The following states perform actions consequent on the decisons made
6708    above, but which must be performed before reading the next character. */
6709 
6710 /* In most cases there will be no actions to perform. Therefore check for
6711    this first (to avoid the time spent doing all the following usually
6712    irrelevant checks). */
6713       if( state < 23 ) {
6714 
6715 /* State 100: We have just reached the end of a PI tag. Create a new XmlPI and
6716    store it in the parent (if required). */
6717       } else if( state == 100 ) {
6718          if( text1 ){
6719 
6720 /* First deal with XML declaration PI's. These must be the first item in
6721    the source. */
6722             if( !strcmp( text1, "xml" ) ) {
6723                if( (*doc)->root || (*doc)->prolog || (*doc)->nepi > 0 ) {
6724                   astError( AST__XMLWF, "astRead(XmlChan): An XML "
6725                             "declaration \"%s\" was encountered within the "
6726                             "body of the document.", status, msg );
6727                } else {
6728                   astXmlSetXmlDec( *doc, text2 );
6729                }
6730 
6731 /* Now deal with other PI's. */
6732             } else {
6733 
6734 /* If we have a parent element, just add it to the element. */
6735                if( parent ) {
6736                   if( wanted > 0 ) {
6737                      astXmlAddPI( (AstXmlParent *) parent, 0, text1, text2 );
6738                   } else if( !skip ) {
6739                      if( parent ) {
6740                         astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6741                                   "the input data \"%s\" within element %s.", status,
6742                                   msg, astXmlGetTag( parent, 1 ) );
6743                      } else {
6744                         astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6745                                   "the input data: \"%s\".", status, msg );
6746                      }
6747                      break;
6748                   }
6749 
6750 /* Otherwise, add it to the document prologue or epilogue. */
6751                } else {
6752                   if( (*doc)->root ) {
6753                      where = 3;
6754                   } else if( (*doc)->prolog->dtdec ){
6755                      where = 2;
6756                   } else {
6757                      where = 1;
6758                   }
6759                   astXmlAddPI( (AstXmlParent *) *doc, where, text1, text2 );
6760 
6761                }
6762             }
6763             text1 = astFree( text1 );
6764             if( text2 ) text2 = astFree( text2 );
6765          } else {
6766             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6767                       "encountered.", status, msg );
6768             break;
6769          }
6770          state = 0;
6771 
6772 /* State 101: We have just reached the end of an element end tag. Check that
6773    the (prefix:)name is legal, and matches that of the current parent,
6774    re-instate the parent's parent as the current element in the document,
6775    and leave the loop if appropriate. */
6776       } else if( state == 101 ) {
6777          if( text1 ){
6778             CheckPrefName( text1, "element", "astRead(XmlChan)", status );
6779             if( parent ) {
6780                if( MatchName( parent, text1, status ) ) {
6781                   parent->complete = 1;
6782                   if( parent != (*doc)->root ) {
6783                      (*doc)->current = (AstXmlElement *) ( (AstXmlObject *) parent )->parent;
6784                   } else {
6785                      (*doc)->current = NULL;
6786                   }
6787                } else {
6788                   astError( AST__XMLWF, "astRead(XmlChan): Start tag \"%s\" "
6789                             "closed by end tag \"%s\".", status, astXmlGetTag( parent, 1 ),
6790                             msg );
6791                }
6792 
6793             } else {
6794                (*doc)->current = NULL;
6795                astError( AST__XMLWF, "astRead(XmlChan): Unmatched end tag "
6796                          "\"%s\" encountered.", status, msg );
6797             }
6798 
6799             text1 = astFree( text1 );
6800 
6801          } else {
6802             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6803                       "encountered.", status, msg );
6804          }
6805 
6806 /* If an error has occurred, or if this invocation of ReadContent was
6807    made recursively (rather tnan by the client), or if we have something
6808    to return, break out of the loop. */
6809          if( !astOK || depth > 0 || result ) {
6810             break;
6811 
6812 /* Otherwise, breaking would result in returning a null pointer to the
6813    client even though the end of the document may not have been reached.
6814    Revert to state 0 and search for further intersting elements. */
6815          } else {
6816             parent = (*doc)->current;
6817             state = 0;
6818          }
6819 
6820 /* State 102: We have just got the (prefix:)name for an element start tag, and
6821    the start tag contains no attributes, etc. Create a new XmlElement, adding
6822    it to the supplied parent, and then proceed to state 200 to read the
6823    content of the element. */
6824       } else if( state == 102 ) {
6825          if( text1 ){
6826             elem = astXmlAddElement( parent, text1, NULL );
6827             text1 = astFree( text1 );
6828             state = 200;
6829 
6830          } else {
6831             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6832                       "encountered.", status, msg );
6833             break;
6834          }
6835 
6836 /* State 103: We have just got the (prefix:)name for an empty element tag, and
6837    the tag does not contain further attributes, etc. Create a new XmlElement
6838    and store it in the container (if any). Indicate that there is no
6839    content to read, and then go on to state 200. */
6840       } else if( state == 103 ) {
6841          if( text1 ){
6842             elem = astXmlAddElement( parent, text1, NULL );
6843             elem->complete = 1;
6844             text1 = astFree( text1 );
6845             state = 200;
6846 
6847          } else {
6848             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6849                       "encountered.", status, msg );
6850             break;
6851          }
6852 
6853 /* State 104: We have just got the (prefix:)name for an element start tag, but
6854    the start tag may contain further attributes, etc. Create a new XmlElement
6855    and store it in the container (if any). Then go to state 12 in which we
6856    look for further attributes, etc. */
6857       } else if( state == 104 ) {
6858          if( text1 ){
6859             elem = astXmlAddElement( parent, text1, NULL );
6860             text1 = astFree( text1 );
6861             state = 12;
6862 
6863          } else {
6864             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6865                       "encountered.", status, msg );
6866             break;
6867          }
6868 
6869 /* State 105: We have just reached the end of a comment tag. Create a new
6870    XmlComment and  store it in the parent. */
6871       } else if( state == 105 ) {
6872          if( text1 ){
6873 
6874 /* If we have a parent element, just add it to the element. */
6875             if( parent ) {
6876                if( wanted > 0 ) {
6877                   astXmlAddComment( (AstXmlParent *) parent, 0, text1 );
6878                } else if( !skip ) {
6879                   if( parent ) {
6880                      astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6881                                "the input data \"%s\" within element %s.", status,
6882                                msg, astXmlGetTag( parent, 1 ) );
6883                   } else {
6884                      astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6885                                "the input data: \"%s\".", status, msg );
6886                   }
6887                   break;
6888                }
6889 
6890 /* Otherwise, add it to the document prologue or epilogue. */
6891             } else {
6892                if( (*doc)->root ) {
6893                   where = 3;
6894                } else if( (*doc)->prolog->dtdec ){
6895                   where = 2;
6896                } else {
6897                   where = 1;
6898                }
6899                astXmlAddComment( (AstXmlParent *) *doc, where, text1 );
6900             }
6901 
6902             text1 = astFree( text1 );
6903 
6904          } else {
6905             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6906                       "encountered.", status, msg );
6907             break;
6908          }
6909          state = 0;
6910 
6911 /* State 106: We have just reached the end of a CDATA tag. Create a new
6912    XmlCDATASection and store it in the container (if any). */
6913       } else if( state == 106 ) {
6914          if( text1 ){
6915             if( parent && wanted > 0 ) {
6916                astXmlAddCDataSection( parent, text1 );
6917             } else if( !skip ) {
6918                if( parent ) {
6919                   astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6920                             "the input data \"%s\" within element %s.", status,
6921                             msg, astXmlGetTag( parent, 1 ) );
6922                } else {
6923                   astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
6924                             "the input data: \"%s\".", status, msg );
6925                }
6926                break;
6927             }
6928             text1 = astFree( text1 );
6929          } else {
6930             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6931                       "encountered.", status, msg );
6932             break;
6933          }
6934          state = 0;
6935 
6936 /* State 107: We have just reached the end of an attribute or namespace
6937    setting. Create a new object and store it in the element created
6938    earlier. */
6939       } else if( state == 107 ) {
6940          if( text1 ){
6941             if( !elem ) {
6942                astError( AST__INTER, "ReadContent(xml): Container lost at state "
6943                          "107 (AST internal programming error).", status );
6944                break;
6945             }
6946 
6947             if( !strcmp( text1, "xmlns" ) ) {
6948                astXmlAddURI( elem, NULL, text2 );
6949 
6950             } else if( !strncmp( text1, "xmlns:", 6 ) ) {
6951                astXmlAddURI( elem, text1+6, text2 );
6952 
6953             } else {
6954                text4 = RemoveEscapes( text2, status );
6955                astXmlAddAttr( elem, text1, text4, NULL );
6956                text4 = astFree( text4 );
6957             }
6958 
6959             text1 = astFree( text1 );
6960             text2 = astFree( text2 );
6961 
6962          } else {
6963             astError( AST__XMLWF, "astRead(XmlChan): Illegal XML tag \"%s\" "
6964                       "encountered.", status, msg );
6965             break;
6966          }
6967          state = 12;
6968 
6969 /* State 108: We have just reached the end of an empty element tag to which
6970    we have been adding attributes, etc. */
6971       } else if( state == 108 ) {
6972          if( elem ) {
6973             elem->complete = 1;
6974             state = 200;
6975          } else {
6976             astError( AST__INTER, "Parse(xml): No container in state 108 "
6977                       "(AST internal programming error).", status );
6978             break;
6979          }
6980 
6981 /* State 109: We have just reached the end of a DOCTYPE tag. */
6982       } else if( state == 109 ) {
6983 
6984          if( (*doc)->root ){
6985             astError( AST__XMLWF, "astRead(XmlChan): An DOCTYPE tag "
6986                       "\"%s\" was encountered within the body of the "
6987                       "document.", status, msg );
6988             break;
6989 
6990          } else if( (*doc)->prolog->dtdec ){
6991             astError( AST__XMLWF, "astRead(XmlChan): Multiple DOCTYPE tags "
6992                       "encountered." , status);
6993             break;
6994 
6995          } else {
6996             astXmlSetDTDec( *doc, text1, text2, text3 );
6997             text1 = astFree( text1 );
6998             text2 = astFree( text2 );
6999             text3 = astFree( text3 );
7000             state = 0;
7001          }
7002 
7003       } else if( state != 200 ) {
7004          astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered "
7005                    "(AST internal programming error).", status, state );
7006       }
7007 
7008 
7009 
7010 /* State 200: We now have now read a complete element start tag and have
7011    a corresponding XmlElement ("elem"), with all attributes and namespaces,
7012    etc (but no content). Call the "is_wanted" function to see if the client
7013    is interested in the element. */
7014       if( state == 200 ) {
7015 
7016 /* If this element is found at the root level of the document, store a
7017    pointer to it as the root element. Report an error if there is already
7018    a root element. */
7019          if( !parent ) {
7020             if( (*doc)->root ){
7021                if( astOK ) {
7022                   astError( AST__XMLWF, "astRead(XmlChan): Multiple root "
7023                             "elements encountered." , status);
7024                   elem = astXmlDelete( elem );
7025                }
7026                break;
7027             } else {
7028                (*doc)->root = elem;
7029                ((AstXmlObject *) elem )->parent = (AstXmlParent *) (*doc);
7030             }
7031          }
7032 
7033 /* If we do not already know, ask the caller if it is interested in this new
7034    element. If no "is_wanted" function was supplied, assume all elements
7035    are interesting. */
7036          if( wanted == -1 ) {
7037             newwanted = is_wanted ? (*is_wanted)( elem, status ) : 1;
7038          } else {
7039             newwanted = wanted;
7040          }
7041 
7042 /* If it is not interested, report an error if skip is zero. */
7043          if( newwanted != 1 && !skip ) {
7044             if( parent ) {
7045                astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
7046                          "the input data \"%s\" within element %s.", status,
7047                          msg, astXmlGetTag( parent, 1 ) );
7048             } else {
7049                astError( AST__BADIN, "astRead(XmlChan): Cannot interpret "
7050                          "the input data: \"%s\".", status, msg );
7051             }
7052             break;
7053          }
7054 
7055 /* Make the new element the "current" element in the document. */
7056          (*doc)->current = elem;
7057 
7058 /* Read the contents of the new element from the source. If the client is
7059    interested in the element, the read contents will be added to the
7060    element, otherwise they will be discarded after being read. */
7061          answer = ReadContent( doc, newwanted, is_wanted, skip, source,
7062                                data, depth + 1, status );
7063 
7064 /* If the first interesting element was found inside "elem", then
7065    return it. If "elem" is not interesting and did not contain anything
7066    of interest, delete it and return the initialised NULL pointer. */
7067          if( newwanted < 0 ) {
7068             if( answer ) {
7069                result = answer;
7070             } else {
7071                elem = astXmlDelete( elem );
7072             }
7073 
7074 /* If the elem is of no interest, delete it and return the initialised
7075    NULL pointer. */
7076          } else if( newwanted == 0 ) {
7077             elem = astXmlDelete( elem );
7078 
7079 /* Otherwise, "elem" itself is definitely of interest. If "elem" is
7080    the first item of interest, return it. */
7081          } else if( wanted < 0 ) {
7082             result = elem;
7083          }
7084 
7085 /* If we have an answer to return, leave the loop, otherwise re-instate the
7086    original current element in the document and continue to read any text
7087    following the element. */
7088          if( result ) {
7089             break;
7090          } else {
7091             (*doc)->current = parent;
7092             state = 0;
7093          }
7094 
7095       } if( state > 22 ) {
7096          astError( AST__INTER, "ReadContent(xml): Illegal state (%d) encountered "
7097                    "(AST internal programming error).", status, state );
7098       }
7099 
7100 /* Remember the previous two character */
7101       lc2 = lc;
7102       lc = c;
7103    }
7104 
7105 /* Free any dynamic strings */
7106    text1 = astFree( text1 );
7107    text2 = astFree( text2 );
7108    text3 = astFree( text3 );
7109    if( msg ) msg = astFree( msg );
7110 
7111 /* Delete the returned object if an error occurred. */
7112    if( !astOK ) result = astXmlDelete( result );
7113 
7114 /* Return the result. */
7115    return result;
7116 }
7117 
7118 
7119 
7120