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, "<" );
471 d += 4;
472
473 } else if( *c == '>' ) {
474 strcpy( d, ">" );
475 d += 4;
476
477 } else if( *c == '"' ) {
478 strcpy( d, """ );
479 d += 6;
480
481 } else if( *c == '\'' ) {
482 strcpy( d, "'" );
483 d += 6;
484
485 } else if( *c == '&' ) {
486 strcpy( d, "&" );
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, "&", 5 ) ) {
5556 rc = '&';
5557 nc= 4;
5558
5559 } else if( !strncmp( c, "<", 4 ) ) {
5560 rc = '<';
5561 nc= 3;
5562
5563 } else if( !strncmp( c, ">", 4 ) ) {
5564 rc = '>';
5565 nc= 3;
5566
5567 } else if( !strncmp( c, "'", 6 ) ) {
5568 rc = '\'';
5569 nc= 5;
5570
5571 } else if( !strncmp( c, """, 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