cmXml.h/c : Completed initial implementation.

This commit is contained in:
Kevin Larke 2015-12-13 09:09:50 -05:00
parent d13de045f7
commit dbd3da490e
2 changed files with 303 additions and 243 deletions

534
cmXml.c
View File

@ -13,106 +13,13 @@
#include "cmXml.h" #include "cmXml.h"
/* /*
file -> decl doctype node To do:
decl -> "<?" attr-list "?>" 1) Escape node data strings and attribute values.
doctype -> "<!DOCTYPE" dt-text ">" 2) Attribute values must be quoted by they may be quoted with either single or double quotes.
node -> beg-node node-body end-node 3) Consider not buffering the XML file and reading directly from the file.
| "<!--" cmmt-text "-->"
node-body -> data-text
| node
beg-node -> "<" tag-label attr-list {"/"} ">"
end-node -> "<" tag-label "/>"
attr-list -> attr*
attr -> attr-label "=" qstring
attr-label -> A string of characters ending with an '=' or <space>.
Attribute labels may not contain '<' or '>'.
tag-label -> A string of characters ending with:
<space>, '>' or '/>'.
Tag labels may not contain '<' or '>'.
data-text -> A string of characters ending with '<'.
dt-text -> A string of characters beginning with a non-whitespace
and ending with '>'
cmmt-text -> A string of characters ending with '-->'
*/
/*
t = get_next_attr_token(p,end_char, tn* )
{
}
parse_attr_list(p,end_char)
{
}
read_beg_tag(p)
{
c = goto_next_non_white_char(p)
if( c != '<' )
error();
c = goto_next_non_white_char(p)
if c == '?'
{
end_tag_str = "?";
if( scan_past(p,"xml") == false )
error();
parse_attr_list(p,'?');
}
if c == '!'
{
if( scan_past(p,"--") )
{
if(go_past(p,"-->")==false)
error();
}
if( scan_past(p,"DOCTYPE") )
{
while( s = get_next_attr_token(p,'>') != NULL )
store_attr(p,s,"");
}
}
}
read_body( p )
{
c = goto_next_non_white_char(p);
if c == '<'
read_node(p)
else
read_data_string(p)
}
n = read_node( p )
{
t = read_beg_tag(p);
if( is_beg_tag(t) )
{
read_body()
read_end_tag()
}
}
*/ */
cmXmlH_t cmXmlNullHandle = cmSTATIC_NULL_HANDLE; cmXmlH_t cmXmlNullHandle = cmSTATIC_NULL_HANDLE;
typedef struct typedef struct
@ -123,9 +30,9 @@ typedef struct
cmChar_t* b; // base of the text buffer cmChar_t* b; // base of the text buffer
unsigned bn; // length of the text buffer in characters unsigned bn; // length of the text buffer in characters
cmChar_t* c; // current lexer position cmChar_t* c; // current lexer position
unsigned line; // lexer line number
cmXmlNode_t* root; // root XML tree node cmXmlNode_t* root; // root XML tree node
cmXmlNode_t* decl; // xml declaratoin node <? ... ?>
cmXmlNode_t* doctype; // DOCTYPE node cmXmlNode_t* doctype; // DOCTYPE node
cmXmlNode_t* stack; // parsing stack cmXmlNode_t* stack; // parsing stack
@ -140,41 +47,17 @@ cmXml_t* _cmXmlHandleToPtr( cmXmlH_t h )
} }
cmXmlRC_t _cmXmlFree( cmXml_t* p ) cmXmlRC_t _cmXmlFree( cmXml_t* p )
{
cmLHeapDestroy( &p->heapH );
cmLexDestroy( &p->lexH );
}
cmXmlRC_t _cmXmlParse( cmXml_t* p, const cmChar_t* fn )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
if( cmLexReset( p->lexH ) != kOkLexRC ) cmLHeapDestroy( &p->heapH );
{
rc = cmErrMsg(&p->err,kLexErrXmlRC,"Lexer reset failed.");
goto errLabel:
}
if( cmLexSetFile( p->lexH, fn ) != kOkLexRC ) cmMemPtrFree(&p->b);
{ p->bn = 0;
rc = cmErrMsg(&p->err,kLexErrXmlRC,"Lexer parse failed on '%s'.",cmStringNullGuard(fn)); p->c = NULL;
goto errLabel;
}
unsigned tokId;
while((tokId = cmLexGetNextToken( cmLexH h )) != kEofRC && tokId != kErrorLexTId ) cmMemFree(p);
{
switch(tokId)
{
case kTagBegLexTId:
case kTagEndLexTid:
case kEqualLexTId:
case kQStrLexTId:
}
}
errLabel:
return rc; return rc;
} }
@ -200,26 +83,8 @@ cmXmlRC_t cmXmlAlloc( cmCtx_t* ctx, cmXmlH_t* hp, const cmChar_t* fn )
goto errLabel; goto errLabel;
} }
// allocate the lexer
if(cmLexIsValid(p->lexH = cmLexInit(NULL,0,0,&ctx->rpt)) == false )
{
rc = cmErrMsg(&p->err,kLexErrXmlRC,"Lex allocation failed.");
goto errLabel;
}
// register xml specific tokens with the lexer
for(i=0; _cmXmlTokenArray[i].id != kErrorLexTId; ++i)
{
cmRC_t lexRC;
if( (lexRC = cmLexRegisterToken(p->lexH, _cmXmlTokenArray[i].id, _cmXmlTokenArray[i].text )) != kOkLexRC )
{
rc = cmErrMsg(&p->err,kLexErrXmlRC,"Lex token registration failed for:'%s'.",_cmXmlTokenArray[i].text );
goto errLabel;
}
}
hp->h = p; hp->h = p;
errLabel: errLabel:
if(rc != kOkXmlRC ) if(rc != kOkXmlRC )
_cmXmlFree(p); _cmXmlFree(p);
@ -231,7 +96,7 @@ cmXmlRC_t cmXmlFree( cmXmlH_t* hp )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
if( hp!=NULL || cmXmlIsValid(*hp)==false ) if( hp==NULL || cmXmlIsValid(*hp)==false )
return kOkXmlRC; return kOkXmlRC;
cmXml_t* p = _cmXmlHandleToPtr(*hp); cmXml_t* p = _cmXmlHandleToPtr(*hp);
@ -248,60 +113,53 @@ bool cmXmlIsValid( cmXmlH_t h )
{ return h.h != NULL; } { return h.h != NULL; }
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn )
{
}
cmXmlRC_t cmXmlClear( cmXmlH_t h )
{
}
cmXmlRC_t _cmXmlSyntaxError( cmXml_t* p ) cmXmlRC_t _cmXmlSyntaxError( cmXml_t* p )
{ {
return _cmErrMsg(&p->err,kSyntaxErrorXmlRC,"Syntax error on line '%i.",p->line); return cmErrMsg(&p->err,kSyntaxErrorXmlRC,"Syntax error on line '%i.",p->line);
} }
cmXmlNode_t* _cmXmlNodeAlloc( cmXml_t* p, unsigned flags, const cmChar_t* label, unsigned labelN ) cmXmlNode_t* _cmXmlNodeAlloc( cmXml_t* p, unsigned flags, const cmChar_t* label, unsigned labelN )
{ {
cmXmlNode_t* np = cmLhAllocZ(p->heapH,cmXmlNode_t,1); cmXmlNode_t* np = cmLhAllocZ(p->heapH,cmXmlNode_t,1);
if( cmIsFlag(kNormalXmlFl) ) np->parent = p->stack;
{
if( p->root == NULL )
p->root = np;
if( p->stack == NULL ) if( p->stack != NULL )
p->stack = np; {
if( p->stack->children == NULL )
p->stack->children = np;
else else
{ {
np->parent = p->stack; cmXmlNode_t* n0p = NULL;
cmXmlNode_t* n1p = p->stack->children;
if( p->stack->children == NULL )
p->stack->children = np; for(; n1p != NULL; n1p=n1p->sibling )
else n0p = n1p;
{
cmXmlNode_t* n0p = NULL; n0p->sibling = np;
cmXmlNode_t* n1p = p->stack->children;
for(; n1p != NULL; n1p=n1p->sibling )
n0p = n1p;
n0p->sibling = np;
}
} }
} }
p->stack = np;
if( cmIsFlag(flags,kRootXmlFl) )
p->root = np;
else else
{ {
if( cmIsFlag(kDeclXmlFl) ) if( cmIsFlag(flags,kDeclXmlFl) )
p->decl = np; {
}
else else
{ {
if( cmIsFlag(kDoctypeXmlF0 ) ) if( cmIsFlag(flags,kDoctypeXmlFl ) )
p->doctype = np; p->doctype = np;
else else
{ {
_cmXmlSyntaxError(p); if( !cmIsFlag(flags,kNormalXmlFl ) )
return NULL; {
_cmXmlSyntaxError(p);
return NULL;
}
} }
} }
} }
@ -309,6 +167,8 @@ cmXmlNode_t* _cmXmlNodeAlloc( cmXml_t* p, unsigned flags, const cmChar_t* label,
if( label != NULL ) if( label != NULL )
np->label = cmLhAllocStrN(p->heapH,label,labelN); np->label = cmLhAllocStrN(p->heapH,label,labelN);
np->flags = flags;
return np; return np;
} }
@ -317,10 +177,10 @@ cmXmlNode_t* _cmXmlAttrAlloc( cmXml_t* p, cmXmlNode_t* np, const cmChar_t* label
cmXmlAttr_t* ap = cmLhAllocZ(p->heapH, cmXmlAttr_t,1); cmXmlAttr_t* ap = cmLhAllocZ(p->heapH, cmXmlAttr_t,1);
if( label != NULL && labelN > 0 ) if( label != NULL && labelN > 0 )
ap->label = cmLhAllocStr(p->heapH,label,labelN); ap->label = cmLhAllocStrN(p->heapH,label,labelN);
if( value != NULL and valueN > 0 ) if( value != NULL && valueN > 0 )
ap->value = cmLhAllocStr(p->attrH,value,valueN); ap->value = cmLhAllocStrN(p->heapH,value,valueN);
ap->link = np->attr; ap->link = np->attr;
np->attr = ap; np->attr = ap;
@ -403,16 +263,17 @@ const cmChar_t* _cmXmlAdvanceToNext( cmXml_t* p, cmChar_t* s )
unsigned i = 0; unsigned i = 0;
unsigned n = strlen(s); unsigned n = strlen(s);
while( _cmXmlAdvance(p) ) while( i<n && _cmXmlAdvance(p) )
{ {
if( *p->c != s[i] ) if( i>0 && *p->c == s[i] )
i = 0; {
i += 1;
}
else else
{ {
i+= 1; i = *p->c==s[0];
if( i == n )
break;
} }
} }
return p->c; return p->c;
} }
@ -428,7 +289,7 @@ const cmChar_t* _cmXmlAdvanceOne( cmXml_t* p )
return _cmXmlIsEof(p) ? NULL : p->c; return _cmXmlIsEof(p) ? NULL : p->c;
} }
cmXmlRC_t _cmXmlParseAttr( cmXml_t* p, cmChar_t endChar ) cmXmlRC_t _cmXmlParseAttr( cmXml_t* p, cmChar_t endChar, cmXmlNode_t* np )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
const cmChar_t* l0 = NULL; const cmChar_t* l0 = NULL;
@ -453,44 +314,62 @@ cmXmlRC_t _cmXmlParseAttr( cmXml_t* p, cmChar_t endChar )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// advance to the next non-white character // advance to the next non-white character
if( (v0 = _cmXmlAdvanceToNextNonWhite(p)) == NULL ) if((v0 = _cmXmlAdvanceToNextNonWhite(p)) == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// the first character in the value must be a single quote // the first character in the value must be a single quote
if( *p->c != '\'' ) if( *p->c == '\'' )
return _cmXmlSyntaxError(p); {
if((v0 = _cmXmlAdvanceOne(p)) == NULL )
// advance to the next single quote return _cmXmlSyntaxError(p);
if( (v1 = _cmXmlAdvanceToNext(p,"'")) == NULL )
// advance to the next single quote
v1 = _cmXmlAdvanceToNext(p,"'");
}
else
{
v1 = _cmXmlAdvanceToNextWhiteOr(p,endChar,' ');
}
if( v1 == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// advance past the ending single quote // advance past the ending single quote
if( _cmXmlAdvanceOne(p) == NULL ) if( *p->c != endChar )
return _cmXmlSyntaxError(p); if( _cmXmlAdvanceOne(p) == NULL )
return _cmXmlSyntaxError(p);
_cmXmlAttrAlloc(p, np, l0, l1-l0, v0, v1-v0 );
// p->c now points just past the ending single quote // p->c now points just past the ending single quote
return rc; return rc;
} }
cmXmlRC_t _cmXmlParseAttrList( cmXml_t* p, cmChar_t endChar ) cmXmlRC_t _cmXmlParseAttrList( cmXml_t* p, cmChar_t endChar, cmXmlNode_t* np )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
while( *p->c != endChar && *p->c != '>' ) while( *p->c != endChar && *p->c != '>' )
if((rc = _cmXmlParseAttr(p,endChar)) != kOkXmlRC ) if((rc = _cmXmlParseAttr(p,endChar,np)) != kOkXmlRC )
break; break;
if( *p->c == endChar ) if( *p->c == endChar )
{ {
if( endChar = '/' ) // if this node is terminated at the end of its beginning tag
if( endChar == '/' )
{ {
// this is a simple node np->flags = cmSetFlag(np->flags,kClosedXmlFl);
//p->stack = p->stack->parent;
} }
if( _cmXmlAdvanceOne(p) == NULL ) if( _cmXmlAdvanceOne(p) == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
} }
if( *p->c != '>' ) if( *p->c != '>' )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
@ -524,6 +403,10 @@ cmXmlRC_t _cmXmlParseDoctypeToken( cmXml_t* p, cmXmlNode_t* np )
{ {
if((t1 = _cmXmlAdvanceToNext(p,"'")) == NULL ) if((t1 = _cmXmlAdvanceToNext(p,"'")) == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
if( _cmXmlAdvanceOne(p) == NULL )
return _cmXmlSyntaxError(p);
} }
else else
{ {
@ -533,27 +416,29 @@ cmXmlRC_t _cmXmlParseDoctypeToken( cmXml_t* p, cmXmlNode_t* np )
// t1 and p->c now point just past the last character in the token // t1 and p->c now point just past the last character in the token
return rc; return kOkXmlRC;
} }
cmXmlRC_t _cmXmlParseDoctype( cmXml_t* p ) cmXmlRC_t _cmXmlParseDoctype( cmXml_t* p, cmXmlNode_t** newNodeRef )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
cmXmlNode_t* np;
if((np = _cmXmlNodeAlloc(p,kDoctypeXmlFl,"DOCTYPE",strlen("DOCTYPE"))) == NULL ) if((*newNodeRef = _cmXmlNodeAlloc(p,kDoctypeXmlFl | kClosedXmlFl,"DOCTYPE",strlen("DOCTYPE"))) == NULL )
return cmErrLastRC(&p->err); return cmErrLastRC(&p->err);
while( *p->c != '>' ) while( *p->c != '>' )
if((rc = _cmXmlParseDoctypeToken(p,np)) != kOkXmlRC ) if((rc = _cmXmlParseDoctypeToken(p,*newNodeRef)) != kOkXmlRC )
break; break;
if( *p->c == '>' )
_cmXmlAdvanceOne(p);
return rc; return rc;
} }
// Node tags are tags that begin with a '<' and are not // Node tags are tags that begin with a '<' and are not
// followed by any special character. // followed by any special character.
cmXmlRC_t _cmXmlParseNodeTag( cmXml_t* p ) cmXmlRC_t _cmXmlParseNodeTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
const cmChar_t* l0 = NULL; const cmChar_t* l0 = NULL;
@ -567,8 +452,12 @@ cmXmlRC_t _cmXmlParseNodeTag( cmXml_t* p )
if((l1 = _cmXmlAdvanceToNextWhiteOr(p,'/','>')) == NULL ) if((l1 = _cmXmlAdvanceToNextWhiteOr(p,'/','>')) == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// Create the node.
if( (*newNodeRef = _cmXmlNodeAlloc(p,kNormalXmlFl,l0,l1-l0)) == NULL )
return cmErrLastRC(&p->err);
// look for attributes // look for attributes
if((rc = _cmXmlParseAttrList(p,'/')) != kOkXmlRC ) if((rc = _cmXmlParseAttrList(p,'/',*newNodeRef)) != kOkXmlRC )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// p->c is now past the ending '>' // p->c is now past the ending '>'
@ -576,7 +465,26 @@ cmXmlRC_t _cmXmlParseNodeTag( cmXml_t* p )
return rc; return rc;
} }
cmXmlRC_t _cmXmlReadEndTag( cmXml_t* p ) cmXmlRC_t _cmXmlParseDeclTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
{
assert( *p->c == '?' );
const cmChar_t* l0 = NULL;
const cmChar_t* l1 = NULL;
if((l0 = _cmXmlAdvanceOne(p)) == NULL)
return _cmXmlSyntaxError(p);
if((l1 = _cmXmlAdvanceToNextWhiteOr(p,'?',' ')) == NULL )
return _cmXmlSyntaxError(p);
if( (*newNodeRef = _cmXmlNodeAlloc(p,kDeclXmlFl | kClosedXmlFl,l0,l1-l0)) == NULL )
return cmErrLastRC(&p->err);
return _cmXmlParseAttrList(p,'?',*newNodeRef);
}
cmXmlRC_t _cmXmlReadEndTag( cmXml_t* p, cmXmlNode_t* np )
{ {
const cmChar_t* l0 = NULL; const cmChar_t* l0 = NULL;
const cmChar_t* l1 = NULL; const cmChar_t* l1 = NULL;
@ -606,23 +514,26 @@ cmXmlRC_t _cmXmlReadEndTag( cmXml_t* p )
assert( !isspace(*l1) ); assert( !isspace(*l1) );
// the label should match the node on the top of the stack // if the label on the top of the stack does not match this label
if( strncmp( p->stack->label, l0, (l1-l0)+1 ) ) if( strncmp( p->stack->label, l0, (l1-l0)+1 ) )
return _cmXmlSyntaxError(p); return kOkXmlRC;
// since we just parsed an end-tag there should be at least one node on the stack // since we just parsed an end-tag there should be at least one node on the stack
if( p->stack == NULL ) if( p->stack == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
p->stack->flags = cmSetFlag(p->stack->flags,kClosedXmlFl);
// pop the stack // pop the stack
p->stack = p->stack->parent; //p->stack = p->stack->parent;
return kOkXmlRC; return kOkXmlRC;
} }
// *newNodeRef will be NULL on error or if the
// the parsed tag was an end tag, or if the last line is comment node.
//
cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef ) cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
{ {
cmXmlRC_t rc = kOkXmlRC; cmXmlRC_t rc = kOkXmlRC;
@ -634,7 +545,8 @@ cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
if( _cmXmlAdvancePast(p,"<") == NULL ) if( _cmXmlAdvancePast(p,"<") == NULL )
{ {
// error or EOF // error or EOF
return NULL;
return _cmXmlIsEof(p) ? kOkXmlRC : cmErrLastRC(&p->err);
} }
// examine the character following the opening '<' // examine the character following the opening '<'
@ -642,41 +554,43 @@ cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
{ {
// node end tag // node end tag
case '/': case '/':
return _cmXmlReadEndTag(p); return _cmXmlReadEndTag(p,*newNodeRef);
// declaration tag // declaration tag
case '?': case '?':
if( _cmXmlAdvancePast(p,"xml") == NULL ) rc = _cmXmlParseDeclTag(p,newNodeRef);
return _cmXmlSyntaxError(p);
if( _cmXmlNodeAlloc(p,kDeclXmlFl, "xml",strlen("xml") ) == NULL )
return cmErrLastRC(&p->err);
if((rc = _cmXmlParseAttrList(p,'?')) != kOkXmlRC )
return rc;
break; break;
case '!': case '!':
switch( *(p->c+1) )
if( _cmXmlAdvanceOne(p) == NULL )
return _cmXmlSyntaxError(p);
switch( *p->c )
{ {
// comment node // comment node
case '-': case '-':
if( _cmXmlAdvancePast(p,"--") == NULL ) if( _cmXmlAdvancePast(p,"--") == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
if( _cmXmlAdvanceToNext("->") == NULL ) if( _cmXmlAdvanceToNext(p,"->") == NULL )
return _cmXmlSyntaxError(p);
if( _cmXmlAdvanceOne(p) == NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// p->c is just after "-->" // p->c is just after "-->"
break;
// Recurse to avoid returning NULL in newNodeRef.
// (*newNodeRef can only be NULL if we just parsed an end-tag).
return _cmXmlReadTag(p,newNodeRef);
// DOCTYPE node // DOCTYPE node
case 'D': case 'D':
if( _cmXmlAdvancePast(P,"DOCTYPE")==NULL ) if( _cmXmlAdvancePast(p,"DOCTYPE")==NULL )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
if((rc = _cmXmlParseDocType(p)) != kOkXmlRC ) if((rc = _cmXmlParseDoctype(p,newNodeRef)) != kOkXmlRC )
return _cmXmlSyntaxError(p); return _cmXmlSyntaxError(p);
// p->c is just after ">" // p->c is just after ">"
@ -690,7 +604,7 @@ cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
default: default:
// normal node // normal node
if((rc = _cmXmlParseNodeTag(p)) != kOkXmlRC ) if((rc = _cmXmlParseNodeTag(p,newNodeRef)) != kOkXmlRC )
return rc; return rc;
// p->c is just after ">" // p->c is just after ">"
@ -700,6 +614,150 @@ cmXmlRC_t _cmXmlReadTag( cmXml_t* p, cmXmlNode_t** newNodeRef )
return rc; return rc;
} }
cmXmlRC_t _cmXmlReadNode( cmXml_t* p ) cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent )
{ {
cmXmlRC_t rc;
while( !_cmXmlIsEof(p) )
{
cmXmlNode_t* np = NULL;
// Read a tag.
if((rc = _cmXmlReadTag(p,&np)) != kOkXmlRC )
return rc;
// If we just read the parents end-tag
if( cmIsFlag(parent->flags,kClosedXmlFl) )
{
assert(np==NULL && parent == p->stack );
p->stack = p->stack->parent;
return rc;
}
// if an end-tag was just read or node was created but closed then pop the stack
if( np==NULL || (np==p->stack && cmIsFlag(np->flags,kClosedXmlFl)) )
p->stack = p->stack->parent;
// if we just read an end-tag or a special node then there is no node-body
if( np == NULL || cmIsFlag(np->flags,kClosedXmlFl) )
continue;
// Advance to the node body.
if( _cmXmlAdvanceToNextNonWhite(p) == NULL )
return _cmXmlSyntaxError(p);
// if the the node body contains nodes
if( *p->c == '<' )
{
if((rc = _cmXmlReadNode(p,np)) != kOkXmlRC )
return rc;
}
else // the node body contains a string
{
const cmChar_t* s0 = p->c;
const cmChar_t* s1 = NULL;
if((s1 = _cmXmlAdvanceToNext(p,"<")) == NULL )
return _cmXmlSyntaxError(p);
np->dataStr = cmLhAllocStrN(p->heapH,s0,s1-s0);
}
}
return rc;
}
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn )
{
cmXmlRC_t rc = kOkXmlRC;
cmXml_t* p = _cmXmlHandleToPtr(h);
cmXmlNode_t* np = NULL;
cmLHeapClear( p->heapH, false );
cmMemPtrFree(&p->b);
if( (p->b = cmFileFnToBuf(fn, p->err.rpt, &p->bn )) == NULL )
{
rc = cmErrMsg(&p->err,kMemAllocErrXmlRC,"Unable to buffer the file '%s'.",cmStringNullGuard(fn));
goto errLabel;
}
p->c = p->b;
p->line = 1;
if((np = _cmXmlNodeAlloc(p,kRootXmlFl,"root",strlen("root"))) == NULL )
{
rc = cmErrMsg(&p->err,kMemAllocErrXmlRC,"Root node alloc failed.");
goto errLabel;
}
if((rc = _cmXmlReadNode(p,np)) != kOkXmlRC )
goto errLabel;
errLabel:
return rc;
}
cmXmlRC_t cmXmlClear( cmXmlH_t h )
{
cmXmlRC_t rc = kOkXmlRC;
return rc;
}
void _cmXmlPrintNode( const cmXmlNode_t* np, cmRpt_t* rpt, unsigned indent )
{
cmChar_t s[ indent + 1 ];
memset(s,' ',indent);
s[indent] = 0;
cmRptPrintf(rpt,"%s%s: ",s,np->label);
cmXmlAttr_t* ap = np->attr;
for(; ap!=NULL; ap=ap->link)
cmRptPrintf(rpt,"%s='%s' ",ap->label,ap->value);
if( np->dataStr != NULL )
cmRptPrintf(rpt," (%s)",np->dataStr);
cmRptPrintf(rpt,"\n");
cmXmlNode_t* cnp = np->children;
for(; cnp!=NULL; cnp=cnp->sibling )
_cmXmlPrintNode(cnp,rpt,indent+2);
}
void cmXmlPrint( cmXmlH_t h , cmRpt_t* rpt )
{
cmXml_t* p = _cmXmlHandleToPtr(h);
if( p->root != NULL )
_cmXmlPrintNode(p->root,rpt,0);
}
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
{
cmXmlRC_t rc = kOkXmlRC;
cmXmlH_t h = cmXmlNullHandle;
if((rc = cmXmlAlloc(ctx, &h, fn )) != kOkXmlRC )
return cmErrMsg(&ctx->err,rc,"XML alloc failed.");
if((rc = cmXmlParse(h,fn)) != kOkXmlRC )
goto errLabel;
cmXmlPrint(h,&ctx->rpt);
errLabel:
cmXmlFree(&h);
return rc;
} }

12
cmXml.h
View File

@ -23,10 +23,11 @@ extern "C" {
enum enum
{ {
kDeclXmlFl = 0x0001, kRootXmlFl = 0x0001,
kDoctypeXmlFl = 0x0002, kDeclXmlFl = 0x0002,
kNormalXmlFl = 0x0004, kDoctypeXmlFl = 0x0004,
kNormalXmlFl = 0x0008,
kClosedXmlFl = 0x0010
}; };
typedef struct cmXmlNode_str typedef struct cmXmlNode_str
@ -56,8 +57,9 @@ extern "C" {
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn ); cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn );
cmXmlRC_t cmXmlClear( cmXmlH_t h ); cmXmlRC_t cmXmlClear( cmXmlH_t h );
void cmXmlPrint( cmXmlH_t h , cmRpt_t* rpt );
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn );
#ifdef __cpluspus #ifdef __cpluspus
} }