|
@@ -11,9 +11,10 @@
|
11
|
11
|
#include "cmLinkedHeap.h"
|
12
|
12
|
#include "cmFile.h"
|
13
|
13
|
#include "cmXml.h"
|
|
14
|
+#include "cmText.h"
|
14
|
15
|
|
15
|
16
|
/*
|
16
|
|
-To do:
|
|
17
|
+To Do:
|
17
|
18
|
1) Escape node data strings and attribute values.
|
18
|
19
|
2) Attribute values must be quoted by they may be quoted with either single or double quotes.
|
19
|
20
|
3) Consider not buffering the XML file and reading directly from the file.
|
|
@@ -131,38 +132,35 @@ cmXmlNode_t* _cmXmlNodeAlloc( cmXml_t* p, unsigned flags, const cmChar_t* label,
|
131
|
132
|
else
|
132
|
133
|
{
|
133
|
134
|
cmXmlNode_t* n0p = NULL;
|
134
|
|
- cmXmlNode_t* n1p = p->stack->children;
|
|
135
|
+ cmXmlNode_t* n1p = p->stack->children;
|
135
|
136
|
|
136
|
|
- for(; n1p != NULL; n1p=n1p->sibling )
|
137
|
|
- n0p = n1p;
|
|
137
|
+ for(; n1p != NULL; n1p=n1p->sibling )
|
|
138
|
+ n0p = n1p;
|
138
|
139
|
|
139
|
|
- n0p->sibling = np;
|
|
140
|
+ n0p->sibling = np;
|
140
|
141
|
}
|
141
|
142
|
}
|
142
|
|
-
|
|
143
|
+
|
|
144
|
+ // all new nodes are put on the top of the stack
|
143
|
145
|
p->stack = np;
|
144
|
|
-
|
|
146
|
+
|
|
147
|
+ // all nodes must have a valid 'type' flag
|
|
148
|
+ if( (flags & kTypeXmlFlags) == 0 )
|
|
149
|
+ {
|
|
150
|
+ _cmXmlSyntaxError(p);
|
|
151
|
+ return NULL;
|
|
152
|
+ }
|
|
153
|
+
|
|
154
|
+ // if this is the root node
|
145
|
155
|
if( cmIsFlag(flags,kRootXmlFl) )
|
146
|
|
- p->root = np;
|
147
|
|
- else
|
148
|
156
|
{
|
149
|
|
- if( cmIsFlag(flags,kDeclXmlFl) )
|
150
|
|
- {
|
151
|
|
- }
|
152
|
|
- else
|
153
|
|
- {
|
154
|
|
- if( cmIsFlag(flags,kDoctypeXmlFl ) )
|
155
|
|
- p->doctype = np;
|
156
|
|
- else
|
157
|
|
- {
|
158
|
|
- if( !cmIsFlag(flags,kNormalXmlFl ) )
|
159
|
|
- {
|
160
|
|
- _cmXmlSyntaxError(p);
|
161
|
|
- return NULL;
|
162
|
|
- }
|
163
|
|
- }
|
164
|
|
- }
|
|
157
|
+ assert( p->root == NULL );
|
|
158
|
+ p->root = np;
|
165
|
159
|
}
|
|
160
|
+
|
|
161
|
+ // if this is the 'doctype' node
|
|
162
|
+ if( cmIsFlag(flags,kDoctypeXmlFl ) )
|
|
163
|
+ p->doctype = np;
|
166
|
164
|
|
167
|
165
|
if( label != NULL )
|
168
|
166
|
np->label = cmLhAllocStrN(p->heapH,label,labelN);
|
|
@@ -674,8 +672,8 @@ cmXmlRC_t _cmXmlReadNode( cmXml_t* p, cmXmlNode_t* parent )
|
674
|
672
|
|
675
|
673
|
cmXmlRC_t cmXmlParse( cmXmlH_t h, const cmChar_t* fn )
|
676
|
674
|
{
|
677
|
|
- cmXmlRC_t rc = kOkXmlRC;
|
678
|
|
- cmXml_t* p = _cmXmlHandleToPtr(h);
|
|
675
|
+ cmXmlRC_t rc = kOkXmlRC;
|
|
676
|
+ cmXml_t* p = _cmXmlHandleToPtr(h);
|
679
|
677
|
cmXmlNode_t* np = NULL;
|
680
|
678
|
|
681
|
679
|
cmLHeapClear( p->heapH, false );
|
|
@@ -711,24 +709,35 @@ cmXmlRC_t cmXmlClear( cmXmlH_t h )
|
711
|
709
|
return rc;
|
712
|
710
|
}
|
713
|
711
|
|
|
712
|
+const cmXmlNode_t* cmXmlRoot( cmXmlH_t h )
|
|
713
|
+{
|
|
714
|
+ cmXml_t* p = _cmXmlHandleToPtr(h);
|
|
715
|
+ return p->root;
|
|
716
|
+}
|
|
717
|
+
|
|
718
|
+
|
714
|
719
|
void _cmXmlPrintNode( const cmXmlNode_t* np, cmRpt_t* rpt, unsigned indent )
|
715
|
720
|
{
|
716
|
721
|
cmChar_t s[ indent + 1 ];
|
717
|
722
|
memset(s,' ',indent);
|
718
|
723
|
s[indent] = 0;
|
|
724
|
+
|
|
725
|
+ // print indent and label
|
719
|
726
|
cmRptPrintf(rpt,"%s%s: ",s,np->label);
|
720
|
727
|
|
|
728
|
+ // print this node's attributes
|
721
|
729
|
cmXmlAttr_t* ap = np->attr;
|
722
|
730
|
for(; ap!=NULL; ap=ap->link)
|
723
|
731
|
cmRptPrintf(rpt,"%s='%s' ",ap->label,ap->value);
|
724
|
732
|
|
|
733
|
+ // print this nodes data string
|
725
|
734
|
if( np->dataStr != NULL )
|
726
|
735
|
cmRptPrintf(rpt," (%s)",np->dataStr);
|
727
|
736
|
|
728
|
737
|
cmRptPrintf(rpt,"\n");
|
729
|
738
|
|
|
739
|
+ // print this nodes children via recursion
|
730
|
740
|
cmXmlNode_t* cnp = np->children;
|
731
|
|
-
|
732
|
741
|
for(; cnp!=NULL; cnp=cnp->sibling )
|
733
|
742
|
_cmXmlPrintNode(cnp,rpt,indent+2);
|
734
|
743
|
|
|
@@ -742,6 +751,132 @@ void cmXmlPrint( cmXmlH_t h , cmRpt_t* rpt )
|
742
|
751
|
_cmXmlPrintNode(p->root,rpt,0);
|
743
|
752
|
}
|
744
|
753
|
|
|
754
|
+const cmXmlNode_t* cmXmlSearch( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN )
|
|
755
|
+{
|
|
756
|
+ // if the 'label' matches this node's label ...
|
|
757
|
+ if( cmTextCmp(np->label,label) == 0 )
|
|
758
|
+ {
|
|
759
|
+ unsigned matchN = 0;
|
|
760
|
+ const cmXmlAttr_t* a = np->attr;
|
|
761
|
+ unsigned i;
|
|
762
|
+
|
|
763
|
+ // ... then check for attribute matches also.
|
|
764
|
+ for(i=0; i<attrN; ++i)
|
|
765
|
+ {
|
|
766
|
+ for(; a!=NULL; a=a->link)
|
|
767
|
+ {
|
|
768
|
+ if( cmTextCmp(a->label,attrV[i].label) == 0 && cmTextCmp(a->value,attrV[i].value) == 0 )
|
|
769
|
+ {
|
|
770
|
+ ++matchN;
|
|
771
|
+
|
|
772
|
+ // if a match was found for all attributes then the return np as the solution
|
|
773
|
+ if( matchN == attrN )
|
|
774
|
+ return np;
|
|
775
|
+
|
|
776
|
+ break;
|
|
777
|
+ }
|
|
778
|
+ }
|
|
779
|
+ }
|
|
780
|
+ }
|
|
781
|
+
|
|
782
|
+ // this node did not match - try each of this nodes children
|
|
783
|
+ const cmXmlNode_t* cnp = np->children;
|
|
784
|
+ for(; cnp!=NULL; cnp=cnp->sibling)
|
|
785
|
+ if(( np = cmXmlSearch(cnp,label,attrV,attrN)) != NULL )
|
|
786
|
+ return np; // a child matched
|
|
787
|
+
|
|
788
|
+ // no match was found.
|
|
789
|
+ return NULL;
|
|
790
|
+}
|
|
791
|
+
|
|
792
|
+const cmXmlNode_t* cmXmlSearchV( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, va_list vl )
|
|
793
|
+{
|
|
794
|
+
|
|
795
|
+ while( label != NULL )
|
|
796
|
+ {
|
|
797
|
+ if((np = cmXmlSearch(np,label,attrV,attrN)) == NULL )
|
|
798
|
+ return NULL;
|
|
799
|
+
|
|
800
|
+ if((label = va_arg(vl,cmChar_t*)) != NULL)
|
|
801
|
+ {
|
|
802
|
+ attrV = va_arg(vl,const cmXmlAttr_t*);
|
|
803
|
+ attrN = va_arg(vl,unsigned);
|
|
804
|
+ }
|
|
805
|
+
|
|
806
|
+ }
|
|
807
|
+
|
|
808
|
+ return np;
|
|
809
|
+}
|
|
810
|
+
|
|
811
|
+const cmXmlNode_t* cmXmlSearchN( const cmXmlNode_t* np, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, ... )
|
|
812
|
+{
|
|
813
|
+ va_list vl;
|
|
814
|
+ va_start(vl,attrN);
|
|
815
|
+ np = cmXmlSearchV(np,label,attrV,attrN,vl);
|
|
816
|
+ va_end(vl);
|
|
817
|
+ return np;
|
|
818
|
+}
|
|
819
|
+
|
|
820
|
+cmXmlRC_t cmXmlGetInt( const cmXmlNode_t* np, int* retRef, const cmChar_t* label, const cmXmlAttr_t* attrV, unsigned attrN, ... )
|
|
821
|
+{
|
|
822
|
+ cmXmlRC_t rc = kNodeNotFoundXmlRC;
|
|
823
|
+ va_list vl;
|
|
824
|
+
|
|
825
|
+ va_start(vl,attrN);
|
|
826
|
+
|
|
827
|
+ // find the requsted node
|
|
828
|
+ if((np = cmXmlSearchV(np,label,attrV,attrN,vl)) != NULL )
|
|
829
|
+ {
|
|
830
|
+ // if the returned node does not have a data string
|
|
831
|
+ if( np->dataStr == NULL )
|
|
832
|
+ return kInvalidTypeXmlRC;
|
|
833
|
+
|
|
834
|
+ errno = 0;
|
|
835
|
+
|
|
836
|
+ // convert the string to an integer
|
|
837
|
+ strtol(np->dataStr,NULL,10);
|
|
838
|
+
|
|
839
|
+ if( errno != 0 )
|
|
840
|
+ return kInvalidTypeXmlRC;
|
|
841
|
+
|
|
842
|
+ rc = kOkXmlRC;
|
|
843
|
+ }
|
|
844
|
+
|
|
845
|
+ va_end(vl);
|
|
846
|
+
|
|
847
|
+ return rc;
|
|
848
|
+}
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+void _cmXmlPrintMeasure( const cmXmlNode_t* mnp )
|
|
852
|
+{
|
|
853
|
+}
|
|
854
|
+
|
|
855
|
+cmXmlRC_t _cmXmlPrintScore( cmXmlH_t h )
|
|
856
|
+{
|
|
857
|
+ cmXmlRC_t rc = kOkXmlRC;
|
|
858
|
+ const int sN = 32;
|
|
859
|
+ cmChar_t s[sN+1];
|
|
860
|
+ unsigned maxMeasNumb = 4;
|
|
861
|
+ unsigned i;
|
|
862
|
+ cmXml_t* p = _cmXmlHandleToPtr(h);
|
|
863
|
+
|
|
864
|
+ for(i=0; i<=maxMeasNumb; ++i)
|
|
865
|
+ {
|
|
866
|
+ snprintf(s,sN,"%i",i);
|
|
867
|
+ cmXmlAttr_t aV[] =
|
|
868
|
+ {
|
|
869
|
+ { "number",s }
|
|
870
|
+ };
|
|
871
|
+
|
|
872
|
+ const cmXmlNode_t* np;
|
|
873
|
+ if((np = cmXmlSearch(cmXmlRoot(h),"measure",aV,1)) == NULL )
|
|
874
|
+ return cmErrMsg(&p->err,kTestFailXmlRC,"Missing measure '%i'.",i);
|
|
875
|
+ }
|
|
876
|
+
|
|
877
|
+ return rc;
|
|
878
|
+}
|
|
879
|
+
|
745
|
880
|
|
746
|
881
|
cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
|
747
|
882
|
{
|
|
@@ -754,7 +889,18 @@ cmXmlRC_t cmXmlTest( cmCtx_t* ctx, const cmChar_t* fn )
|
754
|
889
|
if((rc = cmXmlParse(h,fn)) != kOkXmlRC )
|
755
|
890
|
goto errLabel;
|
756
|
891
|
|
757
|
|
- cmXmlPrint(h,&ctx->rpt);
|
|
892
|
+ cmXmlAttr_t aV[] =
|
|
893
|
+ {
|
|
894
|
+ { "id","P1"}
|
|
895
|
+ };
|
|
896
|
+
|
|
897
|
+ if( cmXmlSearch(cmXmlRoot(h),"part",aV,1) == NULL )
|
|
898
|
+ {
|
|
899
|
+ cmErrMsg(&ctx->err,kTestFailXmlRC,"Search failed.");
|
|
900
|
+ goto errLabel;
|
|
901
|
+ }
|
|
902
|
+
|
|
903
|
+ //cmXmlPrint(h,&ctx->rpt);
|
758
|
904
|
|
759
|
905
|
errLabel:
|
760
|
906
|
cmXmlFree(&h);
|