2024-02-27 20:04:27 +00:00
//
// Test program for Mini-XML, a small XML file parsing library.
//
// Usage:
//
// ./testmxml input.xml [string-output.xml] >stdio-output.xml
// ./testmxml "<?xml ..." [string-output.xml] >stdio-output.xml
//
// https://www.msweet.org/mxml
//
// Copyright © 2003-2024 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
2024-03-06 19:45:10 +00:00
# include "mxml.h"
2019-02-10 15:40:53 +00:00
# ifndef _WIN32
2004-07-11 13:14:07 +00:00
# include <unistd.h>
2024-02-27 20:04:27 +00:00
# endif // !_WIN32
2005-04-24 23:33:13 +00:00
# include <fcntl.h>
# ifndef O_BINARY
# define O_BINARY 0
2024-02-27 20:04:27 +00:00
# endif // !O_BINARY
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
//
// Globals...
//
2007-04-23 21:48:03 +00:00
2024-03-02 23:47:57 +00:00
int event_counts [ 7 ] ;
2007-04-23 21:48:03 +00:00
2024-02-27 20:04:27 +00:00
//
// Local functions...
//
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
bool sax_cb ( void * cbdata , mxml_node_t * node , mxml_sax_event_t event ) ;
mxml_type_t type_cb ( void * cbdata , mxml_node_t * node ) ;
const char * whitespace_cb ( void * cbdata , mxml_node_t * node , mxml_ws_t where ) ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
//
// 'main()' - Main entry for test program.
//
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
int // O - Exit status
main ( int argc , // I - Number of command-line args
char * argv [ ] ) // I - Command-line args
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
int i ; // Looping var
FILE * fp ; // File to read
int fd ; // File descriptor
mxml_node_t * xml , // <?xml ...?> node
* tree , // Element tree
* node ; // Node which should be in test.xml
mxml_index_t * ind ; // XML index
2024-03-06 19:45:10 +00:00
mxml_type_t type ; // Node type
2024-02-27 20:04:27 +00:00
char buffer [ 16384 ] ; // Save string
2024-03-06 19:45:10 +00:00
const char * text ; // Text string
bool whitespace ; // Whitespace before text string
2024-02-27 20:04:27 +00:00
static const char * types [ ] = // Strings for node types
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
" MXML_TYPE_CDATA " ,
" MXML_TYPE_COMMENT " ,
" MXML_TYPE_DECLARATION " ,
" MXML_TYPE_DIRECTIVE " ,
2024-02-27 20:04:27 +00:00
" MXML_TYPE_ELEMENT " ,
" MXML_TYPE_INTEGER " ,
" MXML_TYPE_OPAQUE " ,
" MXML_TYPE_REAL " ,
2024-03-06 19:45:10 +00:00
" MXML_TYPE_TEXT " ,
" MXML_TYPE_CUSTOM "
2003-06-14 22:14:17 +00:00
} ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Check arguments...
2014-10-19 17:21:48 +00:00
if ( argc ! = 2 & & argc ! = 3 )
2003-06-03 19:46:29 +00:00
{
2014-10-19 17:21:48 +00:00
fputs ( " Usage: testmxml filename.xml [string-output.xml] \n " , stderr ) ;
2003-06-03 19:46:29 +00:00
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
// Test the basic functionality...
2019-07-04 02:27:11 +00:00
xml = mxmlNewXML ( " 1.0 " ) ;
tree = mxmlNewElement ( xml , " element " ) ;
2003-06-14 22:14:17 +00:00
if ( ! tree )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: No parent node in basic test. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( tree ) ! = MXML_TYPE_ELEMENT )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Parent has type %d(%s), expected MXML_TYPE_ELEMENT. \n " , mxmlGetType ( tree ) , types [ mxmlGetType ( tree ) ] ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( strcmp ( mxmlGetElement ( tree ) , " element " ) )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Parent value is \" %s \" , expected \" element \" . \n " , mxmlGetElement ( tree ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlNewInteger ( tree , 123 ) ;
mxmlNewOpaque ( tree , " opaque " ) ;
2024-03-02 23:47:57 +00:00
mxmlNewReal ( tree , 123.4 ) ;
2003-06-14 22:14:17 +00:00
mxmlNewText ( tree , 1 , " text " ) ;
2024-03-06 19:45:10 +00:00
type = MXML_TYPE_TEXT ;
mxmlLoadString ( tree , " <group type='string'>string string string</group> " , /*load_cb*/ NULL , /*load_cbdata*/ & type , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
type = MXML_TYPE_INTEGER ;
mxmlLoadString ( tree , " <group type='integer'>1 2 3</group> " , /*load_cb*/ NULL , /*load_cbdata*/ & type , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
type = MXML_TYPE_REAL ;
mxmlLoadString ( tree , " <group type='real'>1.0 2.0 3.0</group> " , /*load_cb*/ NULL , /*load_cbdata*/ & type , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
type = MXML_TYPE_OPAQUE ;
mxmlLoadString ( tree , " <group>opaque opaque opaque</group> " , /*load_cb*/ NULL , /*load_cbdata*/ & type , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
mxmlLoadString ( tree , " <foo><bar><one><two>value<two>value2</two></two></one></bar></foo> " , /*load_cb*/ NULL , /*load_cbdata*/ & type , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2024-02-27 20:04:27 +00:00
mxmlNewCDATA ( tree , " 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n " ) ;
2019-01-18 12:44:33 +00:00
mxmlNewCDATA ( tree ,
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n " ) ;
mxmlNewCDATA ( tree ,
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n "
" 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \n " ) ;
2003-12-13 16:32:42 +00:00
2024-03-06 19:45:10 +00:00
node = mxmlGetFirstChild ( tree ) ;
2003-06-14 22:14:17 +00:00
if ( ! node )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: No first child node in basic test. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_INTEGER )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: First child has type %d(%s), expected MXML_TYPE_INTEGER. \n " , mxmlGetType ( node ) , types [ mxmlGetType ( node ) ] ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetInteger ( node ) ! = 123 )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: First child value is %ld, expected 123. \n " , mxmlGetInteger ( node ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
node = mxmlGetNextSibling ( node ) ;
2003-06-14 22:14:17 +00:00
if ( ! node )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: No second child node in basic test. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_OPAQUE )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Second child has type %s (%d), expected MXML_TYPE_OPAQUE. \n " , mxmlGetType ( node ) < MXML_TYPE_ELEMENT | | mxmlGetType ( node ) > MXML_TYPE_TEXT ? " UNKNOWN " : types [ mxmlGetType ( node ) ] , mxmlGetType ( node ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( ! mxmlGetOpaque ( node ) | | strcmp ( mxmlGetOpaque ( node ) , " opaque " ) )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Second child value is \" %s \" , expected \" opaque \" . \n " , mxmlGetOpaque ( node ) ? mxmlGetOpaque ( node ) : " (null) " ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
node = mxmlGetNextSibling ( node ) ;
2003-06-14 22:14:17 +00:00
if ( ! node )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: No third child node in basic test. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_REAL )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Third child has type %s (%d), expected MXML_TYPE_REAL. \n " , mxmlGetType ( node ) < MXML_TYPE_ELEMENT | | mxmlGetType ( node ) > MXML_TYPE_TEXT ? " UNKNOWN " : types [ mxmlGetType ( node ) ] , mxmlGetType ( node ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetReal ( node ) ! = 123.4 )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Third child value is %f, expected 123.4. \n " , mxmlGetReal ( node ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
node = mxmlGetNextSibling ( node ) ;
2003-06-14 22:14:17 +00:00
if ( ! node )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: No fourth child node in basic test. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_TEXT )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Fourth child has type %s (%d), expected MXML_TYPE_TEXT. \n " , mxmlGetType ( node ) < MXML_TYPE_ELEMENT | | mxmlGetType ( node ) > MXML_TYPE_TEXT ? " UNKNOWN " : types [ mxmlGetType ( node ) ] , mxmlGetType ( node ) ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
text = mxmlGetText ( node , & whitespace ) ;
if ( ! whitespace | | ! text | | strcmp ( text , " text " ) )
2003-06-14 22:14:17 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Fourth child value is %s, \" %s \" , expected true, \" text \" . \n " , whitespace ? " true " : " false " , text ) ;
2003-06-14 22:14:17 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2003-12-13 16:32:42 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
2024-03-06 19:45:10 +00:00
node = mxmlGetNextSibling ( node ) ;
2003-12-13 16:32:42 +00:00
if ( ! node )
{
2016-06-13 00:27:11 +00:00
fprintf ( stderr , " ERROR: No group #%d child node in basic test. \n " , i + 1 ) ;
2003-12-13 16:32:42 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_ELEMENT )
2003-12-13 16:32:42 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Group child #%d has type %d(%s), expected MXML_TYPE_ELEMENT. \n " , i + 1 , mxmlGetType ( node ) , types [ mxmlGetType ( node ) ] ) ;
2003-12-13 16:32:42 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2004-05-16 18:25:20 +00:00
}
2024-02-27 20:04:27 +00:00
// Test mxmlFindPath...
2011-01-03 02:03:29 +00:00
node = mxmlFindPath ( tree , " */two " ) ;
2010-11-08 16:07:05 +00:00
if ( ! node )
{
fputs ( " ERROR: Unable to find value for \" */two \" . \n " , stderr ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
else if ( mxmlGetType ( node ) ! = MXML_TYPE_OPAQUE | | strcmp ( mxmlGetOpaque ( node ) , " value " ) )
2010-11-08 16:07:05 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Bad value for \" */two \" - node=%p(%s), opaque= \" %s \" \n " , node , types [ mxmlGetType ( node ) ] , mxmlGetOpaque ( node ) ) ;
2010-11-08 16:07:05 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2011-01-03 02:03:29 +00:00
node = mxmlFindPath ( tree , " foo/*/two " ) ;
2010-11-08 16:07:05 +00:00
if ( ! node )
{
fputs ( " ERROR: Unable to find value for \" foo/*/two \" . \n " , stderr ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
else if ( mxmlGetType ( node ) ! = MXML_TYPE_OPAQUE | | strcmp ( mxmlGetOpaque ( node ) , " value " ) )
2010-11-08 16:07:05 +00:00
{
fputs ( " ERROR: Bad value for \" foo/*/two \" . \n " , stderr ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2011-01-03 02:03:29 +00:00
node = mxmlFindPath ( tree , " foo/bar/one/two " ) ;
2010-11-08 16:07:05 +00:00
if ( ! node )
{
fputs ( " ERROR: Unable to find value for \" foo/bar/one/two \" . \n " , stderr ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
else if ( mxmlGetType ( node ) ! = MXML_TYPE_OPAQUE | | strcmp ( mxmlGetOpaque ( node ) , " value " ) )
2010-11-08 16:07:05 +00:00
{
fputs ( " ERROR: Bad value for \" foo/bar/one/two \" . \n " , stderr ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
// Test indices...
2004-05-16 18:25:20 +00:00
ind = mxmlIndexNew ( tree , NULL , NULL ) ;
if ( ! ind )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Unable to create index of all nodes. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlIndexGetCount ( ind ) ! = 10 )
2004-05-16 18:25:20 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Index of all nodes contains %lu nodes; expected 10. \n " , ( unsigned long ) mxmlIndexGetCount ( ind ) ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexReset ( ind ) ;
if ( ! mxmlIndexFind ( ind , " group " , NULL ) )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: mxmlIndexFind for \" group \" failed. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexDelete ( ind ) ;
ind = mxmlIndexNew ( tree , " group " , NULL ) ;
if ( ! ind )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Unable to create index of groups. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlIndexGetCount ( ind ) ! = 4 )
2004-05-16 18:25:20 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Index of groups contains %lu nodes; expected 4. \n " , ( unsigned long ) mxmlIndexGetCount ( ind ) ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexReset ( ind ) ;
if ( ! mxmlIndexEnum ( ind ) )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: mxmlIndexEnum failed. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexDelete ( ind ) ;
ind = mxmlIndexNew ( tree , NULL , " type " ) ;
if ( ! ind )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Unable to create index of type attributes. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlIndexGetCount ( ind ) ! = 3 )
2004-05-16 18:25:20 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Index of type attributes contains %lu nodes; expected 3. \n " , ( unsigned long ) mxmlIndexGetCount ( ind ) ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexReset ( ind ) ;
if ( ! mxmlIndexFind ( ind , NULL , " string " ) )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: mxmlIndexFind for \" string \" failed. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexDelete ( ind ) ;
ind = mxmlIndexNew ( tree , " group " , " type " ) ;
if ( ! ind )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Unable to create index of elements and attributes. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlIndexGetCount ( ind ) ! = 3 )
2004-05-16 18:25:20 +00:00
{
2024-03-06 19:45:10 +00:00
fprintf ( stderr , " ERROR: Index of elements and attributes contains %lu nodes; expected 3. \n " , ( unsigned long ) mxmlIndexGetCount ( ind ) ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexReset ( ind ) ;
if ( ! mxmlIndexFind ( ind , " group " , " string " ) )
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: mxmlIndexFind for \" string \" failed. \n " , stderr ) ;
2004-05-16 18:25:20 +00:00
mxmlIndexDelete ( ind ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
mxmlIndexDelete ( ind ) ;
2024-02-27 20:04:27 +00:00
// Check the mxmlDelete() works properly...
2019-01-18 12:44:33 +00:00
for ( i = 0 ; i < 12 ; i + + )
2003-12-13 16:32:42 +00:00
{
2024-03-06 19:45:10 +00:00
if ( mxmlGetFirstChild ( tree ) )
2024-02-27 20:04:27 +00:00
{
2024-03-06 19:45:10 +00:00
mxmlDelete ( mxmlGetFirstChild ( tree ) ) ;
2024-02-27 20:04:27 +00:00
}
2003-12-13 16:32:42 +00:00
else
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " ERROR: Child pointer prematurely NULL on child #%d \n " , i + 1 ) ;
2003-12-13 16:32:42 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
}
2003-06-14 22:14:17 +00:00
2024-03-06 19:45:10 +00:00
if ( mxmlGetFirstChild ( tree ) )
2003-06-14 22:14:17 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Child pointer not NULL after deleting all children. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetLastChild ( tree ) )
2003-06-14 22:14:17 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " ERROR: Last child pointer not NULL after deleting all children. \n " , stderr ) ;
2003-06-14 22:14:17 +00:00
return ( 1 ) ;
}
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2003-06-14 22:14:17 +00:00
2024-02-27 20:04:27 +00:00
// Open the file/string using the default (MXML_NO_CALLBACK) callback...
2014-10-19 17:21:48 +00:00
if ( argv [ 1 ] [ 0 ] = = ' < ' )
2024-03-06 19:45:10 +00:00
xml = mxmlLoadString ( /*top*/ NULL , argv [ 1 ] , /*load_cb*/ NULL , /*load_cbdata*/ NULL , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2014-10-19 17:21:48 +00:00
else
2024-03-06 19:45:10 +00:00
xml = mxmlLoadFilename ( /*top*/ NULL , argv [ 1 ] , /*load_cb*/ NULL , /*load_cbdata*/ NULL , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2014-10-19 17:21:48 +00:00
2019-07-04 02:27:11 +00:00
if ( ! xml )
2014-10-19 17:21:48 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " Unable to read XML file with default callback. \n " , stderr ) ;
2014-10-19 17:21:48 +00:00
return ( 1 ) ;
}
if ( ! strcmp ( argv [ 1 ] , " test.xml " ) )
{
2024-02-27 20:04:27 +00:00
// Verify that mxmlFindElement() and indirectly mxmlWalkNext() work properly...
2019-07-04 02:27:11 +00:00
if ( ( node = mxmlFindPath ( xml , " group/option/keyword " ) ) = = NULL )
2014-10-19 17:21:48 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " Unable to find group/option/keyword element in XML tree. \n " , stderr ) ;
2014-10-19 17:21:48 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-06 19:45:10 +00:00
if ( mxmlGetType ( node ) ! = MXML_TYPE_TEXT )
2014-10-19 17:21:48 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " No child node of group/option/keyword. \n " , stderr ) ;
2024-03-06 19:45:10 +00:00
mxmlSaveFile ( xml , stderr , /*save_cb*/ NULL , /*save_cbdata*/ NULL ) ;
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2014-10-19 17:21:48 +00:00
return ( 1 ) ;
}
if ( ( text = mxmlGetText ( node , NULL ) ) = = NULL | | strcmp ( text , " InputSlot " ) )
{
2016-06-13 00:27:11 +00:00
fprintf ( stderr , " Child node of group/option/value has value \" %s \" instead of \" InputSlot \" . \n " , text ? text : " (null) " ) ;
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2014-10-19 17:21:48 +00:00
return ( 1 ) ;
}
}
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2014-10-19 17:21:48 +00:00
2024-02-27 20:04:27 +00:00
// Open the file...
2003-06-19 03:20:41 +00:00
if ( argv [ 1 ] [ 0 ] = = ' < ' )
2024-03-06 19:45:10 +00:00
xml = mxmlLoadString ( /*top*/ NULL , argv [ 1 ] , /*load_cb*/ type_cb , /*load_cbdata*/ NULL , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2003-06-19 03:20:41 +00:00
else
2024-03-06 19:45:10 +00:00
xml = mxmlLoadFilename ( /*top*/ NULL , argv [ 1 ] , /*load_cb*/ type_cb , /*load_cbdata*/ NULL , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2003-06-03 19:46:29 +00:00
2019-07-04 02:27:11 +00:00
if ( ! xml )
2003-06-03 19:46:29 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " Unable to read XML file. \n " , stderr ) ;
2003-06-03 19:46:29 +00:00
return ( 1 ) ;
}
2003-06-04 01:23:21 +00:00
if ( ! strcmp ( argv [ 1 ] , " test.xml " ) )
2003-06-03 20:40:01 +00:00
{
2024-02-27 20:04:27 +00:00
// Verify that mxmlFindElement() and indirectly mxmlWalkNext() work properly...
2024-03-07 01:03:48 +00:00
if ( ( node = mxmlFindElement ( xml , xml , " choice " , NULL , NULL , MXML_DESCEND_ALL ) ) = = NULL )
2003-06-04 01:23:21 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " Unable to find first <choice> element in XML tree. \n " , stderr ) ;
2003-06-04 01:23:21 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-03-07 01:03:48 +00:00
if ( ! mxmlFindElement ( node , xml , " choice " , NULL , NULL , MXML_DESCEND_NONE ) )
2003-06-04 01:23:21 +00:00
{
2016-06-13 00:27:11 +00:00
fputs ( " Unable to find second <choice> element in XML tree. \n " , stderr ) ;
2003-06-04 01:23:21 +00:00
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2003-06-03 20:40:01 +00:00
}
2024-02-27 20:04:27 +00:00
// Print the XML tree...
2024-03-06 19:45:10 +00:00
mxmlSaveFile ( xml , stdout , whitespace_cb , /*save_cbdata*/ NULL ) ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Save the XML tree to a string and print it...
2024-03-06 19:45:10 +00:00
if ( mxmlSaveString ( xml , buffer , sizeof ( buffer ) , whitespace_cb , /*save_cbdata*/ NULL ) > 0 )
2014-10-19 17:21:48 +00:00
{
if ( argc = = 3 )
{
fp = fopen ( argv [ 2 ] , " w " ) ;
fputs ( buffer , fp ) ;
fclose ( fp ) ;
}
}
2003-07-20 13:49:09 +00:00
2024-02-27 20:04:27 +00:00
// Delete the tree...
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
// Read from/write to file descriptors...
2004-07-11 13:14:07 +00:00
if ( argv [ 1 ] [ 0 ] ! = ' < ' )
{
2024-02-27 20:04:27 +00:00
// Open the file again...
2005-04-24 23:33:13 +00:00
if ( ( fd = open ( argv [ 1 ] , O_RDONLY | O_BINARY ) ) < 0 )
2004-07-11 13:14:07 +00:00
{
perror ( argv [ 1 ] ) ;
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
// Read the file...
2024-03-06 19:45:10 +00:00
xml = mxmlLoadFd ( /*top*/ NULL , fd , type_cb , /*load_cbdata*/ NULL , /*sax_cb*/ NULL , /*sax_cbdata*/ NULL ) ;
2004-07-11 13:14:07 +00:00
close ( fd ) ;
2024-02-27 20:04:27 +00:00
// Create filename.xmlfd...
2004-07-11 13:14:07 +00:00
snprintf ( buffer , sizeof ( buffer ) , " %sfd " , argv [ 1 ] ) ;
2005-04-24 23:33:13 +00:00
if ( ( fd = open ( buffer , O_WRONLY | O_CREAT | O_TRUNC | O_BINARY , 0666 ) ) < 0 )
2004-07-11 13:14:07 +00:00
{
perror ( buffer ) ;
mxmlDelete ( tree ) ;
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
// Write the file...
2024-03-06 19:45:10 +00:00
mxmlSaveFd ( xml , fd , whitespace_cb , /*save_cbdata*/ NULL ) ;
2004-07-11 13:14:07 +00:00
close ( fd ) ;
2024-02-27 20:04:27 +00:00
// Delete the tree...
2019-07-04 02:27:11 +00:00
mxmlDelete ( xml ) ;
2004-07-11 13:14:07 +00:00
}
2024-02-27 20:04:27 +00:00
// Test SAX methods...
2007-04-23 21:48:03 +00:00
memset ( event_counts , 0 , sizeof ( event_counts ) ) ;
if ( argv [ 1 ] [ 0 ] = = ' < ' )
2024-03-06 19:45:10 +00:00
mxmlRelease ( mxmlLoadString ( /*top*/ NULL , argv [ 1 ] , type_cb , /*load_cbdata*/ NULL , sax_cb , /*sax_cbdata*/ NULL ) ) ;
2007-04-23 21:48:03 +00:00
else
2024-03-06 19:45:10 +00:00
mxmlRelease ( mxmlLoadFilename ( /*top*/ NULL , argv [ 1 ] , type_cb , /*load_cbdata*/ NULL , sax_cb , /*sax_cbdata*/ NULL ) ) ;
2007-04-23 21:48:03 +00:00
if ( ! strcmp ( argv [ 1 ] , " test.xml " ) )
{
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_CDATA ] ! = 1 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_CDATA seen %d times, expected 1 times. \n " , event_counts [ MXML_SAX_EVENT_CDATA ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_COMMENT ] ! = 1 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_COMMENT seen %d times, expected 1 times. \n " , event_counts [ MXML_SAX_EVENT_COMMENT ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_DATA ] ! = 61 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_DATA seen %d times, expected 61 times. \n " , event_counts [ MXML_SAX_EVENT_DATA ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
2024-03-02 23:47:57 +00:00
if ( event_counts [ MXML_SAX_EVENT_DECLARATION ] ! = 0 )
{
fprintf ( stderr , " MXML_SAX_EVENT_DECLARATION seen %d times, expected 0 times. \n " , event_counts [ MXML_SAX_EVENT_DECLARATION ] ) ;
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_DIRECTIVE ] ! = 1 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_DIRECTIVE seen %d times, expected 1 times. \n " , event_counts [ MXML_SAX_EVENT_DIRECTIVE ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_ELEMENT_CLOSE ] ! = 20 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_ELEMENT_CLOSE seen %d times, expected 20 times. \n " , event_counts [ MXML_SAX_EVENT_ELEMENT_CLOSE ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
2024-02-27 20:04:27 +00:00
if ( event_counts [ MXML_SAX_EVENT_ELEMENT_OPEN ] ! = 20 )
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
fprintf ( stderr , " MXML_SAX_EVENT_ELEMENT_OPEN seen %d times, expected 20 times. \n " , event_counts [ MXML_SAX_EVENT_ELEMENT_OPEN ] ) ;
2007-04-23 21:48:03 +00:00
return ( 1 ) ;
}
}
2019-02-10 15:40:53 +00:00
# ifndef _WIN32
2024-02-27 20:04:27 +00:00
// Debug hooks...
2017-03-29 23:04:41 +00:00
if ( getenv ( " TEST_DELAY " ) ! = NULL )
sleep ( atoi ( getenv ( " TEST_DELAY " ) ) ) ;
2024-02-27 20:04:27 +00:00
2017-06-27 17:06:25 +00:00
# ifdef __APPLE__
2017-03-29 23:10:59 +00:00
if ( getenv ( " TEST_LEAKS " ) ! = NULL )
{
char command [ 1024 ] ;
snprintf ( command , sizeof ( command ) , " leaks %d " , ( int ) getpid ( ) ) ;
2017-06-27 17:06:25 +00:00
if ( system ( command ) )
puts ( " Unable to check for leaks. " ) ;
2017-03-29 23:10:59 +00:00
}
2024-02-27 20:04:27 +00:00
# endif // __APPLE__
# endif // !_WIN32
2004-07-11 13:14:07 +00:00
2024-02-27 20:04:27 +00:00
// Return...
2003-06-03 19:46:29 +00:00
return ( 0 ) ;
}
2024-02-27 20:04:27 +00:00
//
// 'sax_cb()' - Process nodes via SAX.
//
2007-04-23 21:48:03 +00:00
2024-03-04 13:09:55 +00:00
bool // O - `true` to continue, `false` to stop
2024-03-06 19:45:10 +00:00
sax_cb ( void * cbdata , // I - SAX callback data (not used)
mxml_node_t * node , // I - Current node
mxml_sax_event_t event ) // I - SAX event
2007-04-23 21:48:03 +00:00
{
2024-02-27 20:04:27 +00:00
static const char * const events [ ] = // Events
{
" MXML_SAX_EVENT_CDATA " , // CDATA node
" MXML_SAX_EVENT_COMMENT " , // Comment node
" MXML_SAX_EVENT_DATA " , // Data node
2024-03-02 23:47:57 +00:00
" MXML_SAX_EVENT_DECLARATION " , // Declaration node
" MXML_SAX_EVENT_DIRECTIVE " , // Processing directive node
2024-02-27 20:04:27 +00:00
" MXML_SAX_EVENT_ELEMENT_CLOSE " , // Element closed
" MXML_SAX_EVENT_ELEMENT_OPEN " // Element opened
2016-06-13 00:27:11 +00:00
} ;
2024-03-06 19:45:10 +00:00
( void ) cbdata ;
2017-03-29 23:04:41 +00:00
2024-02-27 20:04:27 +00:00
// This SAX callback just counts the different events.
2016-06-13 00:27:11 +00:00
if ( ! node )
fprintf ( stderr , " ERROR: SAX callback for event %s has NULL node. \n " , events [ event ] ) ;
2007-04-23 21:48:03 +00:00
event_counts [ event ] + + ;
2024-03-04 13:09:55 +00:00
return ( true ) ;
2007-04-23 21:48:03 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'type_cb()' - XML data type callback for mxmlLoadFile()...
//
2003-06-03 19:46:29 +00:00
2024-02-27 20:04:27 +00:00
mxml_type_t // O - Data type
2024-03-06 19:45:10 +00:00
type_cb ( void * cbdata , // I - Callback data
mxml_node_t * node ) // I - Element node
2003-06-03 19:46:29 +00:00
{
2024-02-27 20:04:27 +00:00
const char * type ; // Type string
2003-06-03 19:46:29 +00:00
2024-03-06 19:45:10 +00:00
( void ) cbdata ;
2024-02-27 20:04:27 +00:00
// You can lookup attributes and/or use the element name, hierarchy, etc...
2003-06-03 19:46:29 +00:00
if ( ( type = mxmlElementGetAttr ( node , " type " ) ) = = NULL )
2024-03-06 19:45:10 +00:00
{
if ( ( type = mxmlGetElement ( node ) ) = = NULL )
type = " " ;
}
2003-06-03 19:46:29 +00:00
if ( ! strcmp ( type , " integer " ) )
2024-02-27 20:04:27 +00:00
return ( MXML_TYPE_INTEGER ) ;
2003-06-04 17:37:23 +00:00
else if ( ! strcmp ( type , " opaque " ) | | ! strcmp ( type , " pre " ) )
2024-02-27 20:04:27 +00:00
return ( MXML_TYPE_OPAQUE ) ;
2003-06-03 19:46:29 +00:00
else if ( ! strcmp ( type , " real " ) )
2024-02-27 20:04:27 +00:00
return ( MXML_TYPE_REAL ) ;
2003-06-03 19:46:29 +00:00
else
2024-02-27 20:04:27 +00:00
return ( MXML_TYPE_TEXT ) ;
2003-06-03 19:46:29 +00:00
}
2024-02-27 20:04:27 +00:00
//
// 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert
// newlines and tabs...
//
2003-06-04 17:37:23 +00:00
2024-02-27 20:04:27 +00:00
const char * // O - Whitespace string or NULL
2024-03-06 19:45:10 +00:00
whitespace_cb ( void * cbdata , // I - Callback data
mxml_node_t * node , // I - Element node
mxml_ws_t where ) // I - Open or close tag?
2003-06-04 17:37:23 +00:00
{
2024-02-27 20:04:27 +00:00
mxml_node_t * parent ; // Parent node
int level ; // Indentation level
const char * name ; // Name of element
2004-07-11 13:14:07 +00:00
static const char * tabs = " \t \t \t \t \t \t \t \t " ;
2024-02-27 20:04:27 +00:00
// Tabs for indentation
2004-07-11 13:14:07 +00:00
2003-06-04 17:37:23 +00:00
2024-03-06 19:45:10 +00:00
( void ) cbdata ;
2024-02-27 20:04:27 +00:00
// We can conditionally break to a new line before or after any element.
// These are just common HTML elements...
2024-03-02 23:47:57 +00:00
if ( ( name = mxmlGetElement ( node ) ) = = NULL )
name = " " ;
2003-06-04 17:37:23 +00:00
2024-02-27 20:04:27 +00:00
if ( ! strcmp ( name , " html " ) | | ! strcmp ( name , " head " ) | | ! strcmp ( name , " body " ) | | ! strcmp ( name , " pre " ) | | ! strcmp ( name , " p " ) | | ! strcmp ( name , " h1 " ) | | ! strcmp ( name , " h2 " ) | | ! strcmp ( name , " h3 " ) | | ! strcmp ( name , " h4 " ) | | ! strcmp ( name , " h5 " ) | | ! strcmp ( name , " h6 " ) )
2003-06-04 21:19:00 +00:00
{
2024-02-27 20:04:27 +00:00
// Newlines before open and after close...
2003-06-04 21:19:00 +00:00
if ( where = = MXML_WS_BEFORE_OPEN | | where = = MXML_WS_AFTER_CLOSE )
2004-05-01 15:20:05 +00:00
return ( " \n " ) ;
2003-06-04 21:19:00 +00:00
}
else if ( ! strcmp ( name , " dl " ) | | ! strcmp ( name , " ol " ) | | ! strcmp ( name , " ul " ) )
{
2024-02-27 20:04:27 +00:00
// Put a newline before and after list elements...
2004-05-01 15:20:05 +00:00
return ( " \n " ) ;
2003-06-04 21:19:00 +00:00
}
else if ( ! strcmp ( name , " dd " ) | | ! strcmp ( name , " dt " ) | | ! strcmp ( name , " li " ) )
2003-06-04 17:37:23 +00:00
{
2024-02-27 20:04:27 +00:00
// Put a tab before <li>'s, <dd>'s, and <dt>'s, and a newline after them...
2003-06-04 21:19:00 +00:00
if ( where = = MXML_WS_BEFORE_OPEN )
2004-05-01 15:20:05 +00:00
return ( " \t " ) ;
2003-06-04 21:19:00 +00:00
else if ( where = = MXML_WS_AFTER_CLOSE )
2004-05-01 15:20:05 +00:00
return ( " \n " ) ;
2003-06-04 17:37:23 +00:00
}
2024-03-02 23:47:57 +00:00
else if ( mxmlGetType ( node ) = = MXML_TYPE_DIRECTIVE )
2004-07-11 13:14:07 +00:00
{
2008-03-21 04:59:01 +00:00
if ( where = = MXML_WS_AFTER_OPEN )
return ( " \n " ) ;
else
return ( NULL ) ;
2004-07-11 13:14:07 +00:00
}
2024-02-27 20:04:27 +00:00
else if ( where = = MXML_WS_BEFORE_OPEN | | ( ( ! strcmp ( name , " choice " ) | | ! strcmp ( name , " option " ) ) & & where = = MXML_WS_BEFORE_CLOSE ) )
2004-07-11 13:14:07 +00:00
{
2024-03-06 19:45:10 +00:00
for ( level = - 1 , parent = mxmlGetParent ( node ) ; parent ; level + + , parent = mxmlGetParent ( parent ) ) ;
2004-07-11 13:14:07 +00:00
if ( level > 8 )
level = 8 ;
2005-01-29 07:19:38 +00:00
else if ( level < 0 )
level = 0 ;
2004-07-11 13:14:07 +00:00
return ( tabs + 8 - level ) ;
}
2024-02-27 20:04:27 +00:00
else if ( where = = MXML_WS_AFTER_CLOSE | | ( ( ! strcmp ( name , " group " ) | | ! strcmp ( name , " option " ) | | ! strcmp ( name , " choice " ) ) & & where = = MXML_WS_AFTER_OPEN ) )
2004-07-11 13:14:07 +00:00
return ( " \n " ) ;
2024-03-02 23:47:57 +00:00
else if ( where = = MXML_WS_AFTER_OPEN & & ! mxmlGetFirstChild ( node ) )
2004-07-11 13:14:07 +00:00
return ( " \n " ) ;
2003-06-04 21:19:00 +00:00
2024-02-27 20:04:27 +00:00
// Return NULL for no added whitespace...
2004-05-01 15:20:05 +00:00
return ( NULL ) ;
2003-06-04 17:37:23 +00:00
}