From 34029578d4f617c5488c816a9ce0f80a5a736d0b Mon Sep 17 00:00:00 2001 From: kpl Date: Fri, 9 Nov 2012 07:14:29 -0800 Subject: [PATCH] Many changes --- cmTextTemplate.c | 662 +++++++++++++++++++++++++++++++++++++++-------- cmTextTemplate.h | 34 ++- 2 files changed, 587 insertions(+), 109 deletions(-) diff --git a/cmTextTemplate.c b/cmTextTemplate.c index 03e3c00..233e6d1 100644 --- a/cmTextTemplate.c +++ b/cmTextTemplate.c @@ -8,6 +8,7 @@ #include "cmLinkedHeap.h" #include "cmText.h" #include "cmFile.h" +#include "cmJson.h" #include "cmTextTemplate.h" /* @@ -26,44 +27,41 @@ */ -cmTtH_t cmTtNullHandle = cmSTATIC_NULL_HANDLE; +#define kVarBegChar '$' +#define kVarEndChar '$' +#define kSetBegChar '{' +#define kSetEndChar '}' -enum +typedef enum { - kVarTtId, // variable node - kValTtId, // value (leaf) node - kTextTtId // text -}; - -typedef struct cmTtToken_str -{ - unsigned typeId; - cmChar_t* text; - cmChar_t* end; - struct cmTtToken_str* next; - struct cmTtToken_str* prev; -} cmTtToken_t; + kTextTtId, + kVarTtId, + kSetTtId +} cmTtId_t; typedef struct cmTtNode_str { - unsigned typeId; + cmTtId_t typeId; cmChar_t* label; - cmTtToken_t* token; + cmChar_t* text; struct cmTtNode_str* parent; struct cmTtNode_str* children; - struct cmTtNode_str* sibling; + struct cmTtNode_str* rsib; + struct cmTtNode_str* lsib; } cmTtNode_t; typedef struct { + cmCtx_t* ctx; cmErr_t err; cmLHeapH_t lhH; cmChar_t* buf; cmChar_t* fn; cmTtNode_t* tree; - cmTtToken_t* tokens; } cmTt_t; +cmTtH_t cmTtNullHandle = cmSTATIC_NULL_HANDLE; + cmTt_t* _cmTtHandleToPtr( cmTtH_t h ) { cmTt_t* p = (cmTt_t*)h.h; @@ -83,28 +81,63 @@ cmTtRC_t _cmTtFinalize( cmTt_t* p ) return rc; } -cmTtToken_t* _cmTtCreateToken( cmTt_t* p, unsigned typeId, cmChar_t* s0, cmChar_t* s1 ) +void _cmTtAppendChild( cmTtNode_t* parent, cmTtNode_t* np ) { - cmTtToken_t* tp = p->tokens; - cmTtToken_t* t = cmLhAllocZ(p->lhH,cmTtToken_t,1); - t->typeId = kVarTtId; - t->text = s0; - t->end = s1; - - if( tp == NULL ) - p->tokens = t; + np->parent = parent; + np->rsib = NULL; + + if( parent->children == NULL ) + { + parent->children = np; + np->lsib = NULL; + } else { - while( tp->next!=NULL ) - tp=tp->next; - - tp->next = t; - t->prev = tp; - } + cmTtNode_t* cnp = parent->children; + while( cnp->rsib != NULL ) + cnp=cnp->rsib; - return tp; + cnp->rsib = np; + np->lsib = cnp; + } } +void _cmTtCreateTokenNode( cmTt_t* p, cmTtId_t typeId, cmChar_t* s0, cmChar_t* s1 ) +{ + if( typeId == kVarTtId ) + { + ++s0; + --s1; + } + + cmChar_t* s = cmLhAllocStrN(p->lhH,s0,s1-s0+1); + + cmTtNode_t* t = cmLhAllocZ(p->lhH,cmTtNode_t,1); + t->typeId = typeId; + t->text = typeId == kTextTtId ? s : NULL; + t->label = typeId == kVarTtId ? s : NULL; + + _cmTtAppendChild(p->tree,t); +} + +cmTtNode_t* _cmTtCreateSetNode( cmTt_t* p, cmTtNode_t* parent, cmTtNode_t* child ) +{ + cmTtNode_t* nnp = cmLhAllocZ(p->lhH,cmTtNode_t,1); + nnp->typeId = kSetTtId; + nnp->parent = parent; + if( child != NULL ) + { + nnp->children = child->rsib; + + // The set node's label is taken from the label of the first child. + if( child->label != NULL && strlen(child->label)>0 ) + nnp->label = cmLhAllocStr(p->lhH,child->label+1); // (strip '{' from label) + + child->label = NULL; + } + + return nnp; +} cmTtRC_t _cmTtScan( cmTt_t* p, cmChar_t* s) { @@ -128,9 +161,9 @@ cmTtRC_t _cmTtScan( cmTt_t* p, cmChar_t* s) case kBeg: // searching for begin '$' switch( c ) { - case '$': + case kVarBegChar: { - _cmTtCreateToken(p,kTextTtId,s0,s+i-1); + _cmTtCreateTokenNode(p,kTextTtId,s0,s+i-1); state = kEnd; s0 = s + i; } @@ -140,13 +173,14 @@ cmTtRC_t _cmTtScan( cmTt_t* p, cmChar_t* s) state = kQuote; break; } + break; case kEnd: // searching for end '$' switch(c) { - case '$': + case kVarEndChar: { - _cmTtCreateToken(p,kVarTtId,s0,s+i); + _cmTtCreateTokenNode(p,kVarTtId,s0,s+i); state = kBeg; s0 = s + i + 1; } @@ -180,93 +214,162 @@ cmTtRC_t _cmTtScan( cmTt_t* p, cmChar_t* s) } } + switch(state) + { + case kBeg: _cmTtCreateTokenNode(p,kTextTtId,s0,s0+strlen(s0)-1); break; + case kEnd: rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing template variable ending '%c'.",kVarEndChar); break; + case kQuote: rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing ending double-quote in quoated string."); break; + default: + { assert(0); } + } + + return rc; } -bool _cmTtTokenIsBegin( cmTtToken_t* tp ) +bool _cmTtTokenIsBegin( cmTtNode_t* tp ) { - assert(tp->text!=NULL && tp->text[0]=='$'); - return tp->typeId==kVarTtId && tp->text[1]=='{'; + return tp->typeId==kVarTtId && tp->label[0]==kSetBegChar; } -bool _cmTtTokenIsEnd( cmTtToken_t* tp ) +bool _cmTtTokenIsEnd( cmTtNode_t* tp ) { - assert(tp->text!=NULL && tp->text[0]=='$'); - return tp->typeId==kVarTtId && tp->text[1]=='}'; + return tp->typeId==kVarTtId && tp->label[0]==kSetEndChar; } -cmTtNode_t* _cmTtCreateNode( cmTt_t* p, cmTtNode_t* parent, unsigned typeId, cmTtToken_t* tp ) -{ - cmTtNode_t* nnp = cmLhAllocZ(p->lhH,cmTtNode_t,1); - nnp->typeId = typeId; - nnp->token = tp; - nnp->parent = parent; - - if( parent != NULL ) - { - if( parent->children == NULL ) - parent->children = nnp; - else - { - cmTtNode_t* np = nnp->children; - while( np->sibling != NULL ) - np=np->sibling; - - np->sibling = nnp; - } - } - return nnp; -} - -cmTtToken_t* _cmTtBuildTree( cmTt_t* p, cmTtNode_t* np, cmTtToken_t* tp ) +cmTtNode_t* _cmTtBuildTree( cmTt_t* p, cmTtNode_t* np, cmTtNode_t* tp ) { - cmTtToken_t* ftp = tp; - int cnt = 0; + while( tp != NULL ) { + tp->parent = np; + if( _cmTtTokenIsBegin(tp) ) { - // attach preceding text to new right-most leaf-node on 'np'. - _cmTtCreateNode(p,np,kTextTtId,ftp); + cmTtNode_t* nnp = _cmTtCreateSetNode(p,np,tp); + tp->parent = nnp; + nnp->lsib = tp->lsib; // break the token chain before the 'begin' token - if( tp->prev != NULL ) - tp->prev->next = NULL; - tp->prev = NULL; + if( tp->lsib != NULL ) + tp->lsib->rsib = nnp; + // create a new child variable node and advance to token string - tp = _cmTtBuildTree(p, _cmTtCreateNode(p,np,kVarTtId,NULL), tp->next ); - ftp = tp; - ++cnt; + if((tp = _cmTtBuildTree(p, nnp, tp->rsib)) == NULL ) + break; + + nnp->rsib = tp; } if( _cmTtTokenIsEnd(tp) ) { - --cnt; + // break the token chain before the 'end' token + if( tp->lsib != NULL ) + tp->lsib->rsib = NULL; + + + // the token after 'end' become the current token + tp = tp->rsib; + if( tp != NULL ) + { + if( tp->lsib != NULL ) + tp->lsib->rsib = NULL; + tp->lsib = NULL; + } - // break the token chain after the 'end' token - if( tp->next != NULL ) - tp->next->prev = NULL; - tp->next = NULL; - - // create a new right-most leaf-node - _cmTtCreateNode(p,np,kTextTtId,ftp); - - tp = tp->next; break; } - tp = tp->next; + tp = tp->rsib; } - if( cnt != 0 ) - cmErrMsg(&p->err,kSyntaxErrTtRC,"The template file '%s' appears to have unbalanced begin/end markers.",cmStringNullGuard(p->fn)); return tp; } +cmTtNode_t* _cmTtCloneNode( cmTt_t* p, const cmTtNode_t* snp ) +{ + cmTtNode_t* np = cmLhAllocZ(p->lhH,cmTtNode_t,1); + np->typeId = snp->typeId; + np->label = snp->label == NULL ? NULL : cmLhAllocStr(p->lhH,snp->label); + np->text = snp->text == NULL ? NULL : cmLhAllocStr(p->lhH,snp->text); + + + cmTtNode_t* csnp = snp->children; + for(; csnp!=NULL; csnp=csnp->rsib) + { + cmTtNode_t* cnp = _cmTtCloneNode(p,csnp); + _cmTtAppendChild(np,cnp); + } + + return np; +} + +cmTtNode_t* _cmTtRepeatNode( cmTt_t* p, cmTtNode_t* snp ) +{ + cmTtNode_t* stnp = _cmTtCloneNode(p,snp); + stnp->parent = snp->parent; + stnp->lsib = snp; + stnp->rsib = snp->rsib; + if( snp->rsib != NULL ) + snp->rsib->lsib = stnp; + snp->rsib = stnp; + return stnp; +} + +cmTtNode_t* _cmTtFindNodeV( cmTt_t* p, const cmChar_t* label, unsigned index, va_list vl ) +{ + cmTtNode_t* np = p->tree; + + if( label == NULL ) + return NULL; + + assert( np!=NULL); // the tree should never be empty. + + while(1) + { + cmTtNode_t* cnp = np->children; + + // locate the label for the current path level + for(; cnp!=NULL; cnp=cnp->rsib) + if( cnp->label != NULL && strcmp(cnp->label,label)==0 ) + break; + + // the label at the current path level was not found + if( cnp==NULL ) + return NULL; + + unsigned i; + // locate the index at the current level - all labels + // must match the current label + for(i=0; cnp!=NULL && irsib,++i) + if( cnp->label==NULL || strcmp(cnp->label,label) ) + { + // a label mismatch occurred. + return NULL; + } + + // the index was not found + if( cnp==NULL ) + return NULL; + + // cnp is the matched node at this level + np = cnp; + + // the end of the path was located - success! + if((label = va_arg(vl,const cmChar_t*)) == NULL ) + break; + + index = va_arg(vl,unsigned); + + } + + return np; +} + cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn ) @@ -288,7 +391,7 @@ cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn } // read the template file - if((p->buf = cmFileFnToBuf(fn,p->err.rpt,NULL)) == NULL ) + if((p->buf = cmFileFnToStr(fn,p->err.rpt,NULL)) == NULL ) { rc = cmErrMsg(&p->err,kFileFailTtRC,"Unable to open the file '%s'.",cmStringNullGuard(fn)); goto errLabel; @@ -297,18 +400,25 @@ cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn // store the template file name p->fn = cmLhAllocStr(p->lhH,fn); + // create the root node + p->tree = _cmTtCreateSetNode(p,NULL,NULL); + // break the template file into tokens if((rc = _cmTtScan(p,p->buf)) != kOkTtRC ) goto errLabel; - // create the root node - p->tree = _cmTtCreateNode(p,NULL,kVarTtId,NULL); + // The tree now has two levels. The root node + // and a flat linked list of token nodes which are the children + // of the root node. // build the node tree - _cmTtBuildTree(p,p->tree,p->tokens); + _cmTtBuildTree(p,p->tree,p->tree->children); // check for errors rc = cmErrLastRC(&p->err); + + p->ctx = ctx; + hp->h = p; errLabel: @@ -338,24 +448,349 @@ cmTtRC_t cmTextTemplateFinalize( cmTtH_t* hp ) bool cmTextTemplateIsValid( cmTtH_t h ) { return h.h != NULL; } -void cmTextTemplatePrintTokens( cmTtH_t h, cmRpt_t* rpt ) +cmTtRC_t _cmTtSetValue( cmTt_t* p, cmTtNode_t* np, const cmChar_t* label, unsigned index, const cmChar_t* value ) { - cmTt_t* p = _cmTtHandleToPtr(h); + // only the value of variable nodes may be set + if( np->typeId != kVarTtId ) + return cmErrMsg(&p->err,kInvalidTypeTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index); - cmTtToken_t* tp = p->tokens; - cmChar_t* ep = p->buf + strlen(p->buf); - for(; tp!=NULL; tp=tp->next) + // set the value + if( value != NULL ) + np->text = cmLhResizeStr(p->lhH,np->text,value); + else { - bool fl = tp->end < ep; - cmChar_t c = fl ? tp->end[1] : 0; + cmLhFree(p->lhH,np->text); + np->text = NULL; + } - cmRptPrintf(rpt,"%s",tp->text); + return kOkTtRC; +} - if( fl ) - tp->end[1] = c; +cmTtRC_t cmTextTemplateSetValueV( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, va_list vl ) +{ + cmTt_t* p = _cmTtHandleToPtr(h); + cmTtNode_t* np; + + // locate the requested node + if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL ) + return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index); + + return _cmTtSetValue(p,np,label,index,value); +} + +cmTtRC_t cmTextTemplateSetValue( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, ... ) +{ + cmTtRC_t rc; + va_list vl; + va_start(vl,index); + rc = cmTextTemplateSetValueV(h,value,label,index,vl); + va_end(vl); + return rc; +} + +cmTtRC_t cmTextTemplateRepeatV( cmTtH_t h, const cmChar_t* label, unsigned index, va_list vl ) +{ + cmTt_t* p = _cmTtHandleToPtr(h); + cmTtNode_t* np; + + // locate the requested node + if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL ) + return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index); + + _cmTtRepeatNode(p,np); + + return kOkTtRC; +} + +cmTtRC_t cmTextTemplateRepeat( cmTtH_t h, const cmChar_t* label, unsigned index, ... ) +{ + cmTtRC_t rc; + va_list vl; + va_start(vl,index); + rc = cmTextTemplateRepeatV(h,label,index,vl); + va_end(vl); + return rc; +} + +cmTtRC_t _cmTtWriteNode( cmTt_t* p, cmTtNode_t* np, cmFileH_t fh ) +{ + cmTtRC_t rc = kOkTtRC; + cmFileRC_t frc = kOkFileRC; + + switch( np->typeId ) + { + case kTextTtId: + case kVarTtId: + { + if( np->text != NULL ) + if((frc = cmFilePrint(fh,np->text)) != kOkFileRC ) + rc = cmErrMsg(&p->err,kFileFailTtRC,"File write failed on '%s'.", cmFileName(fh)); + } + break; + + case kSetTtId: + { + cmTtNode_t* cnp; + for(cnp=np->children; cnp!=NULL && rc==kOkTtRC; cnp=cnp->rsib) + rc = _cmTtWriteNode(p,cnp,fh); + } + break; + + default: + { assert(0); } + } + + return rc; +} + +cmTtRC_t cmTextTemplateWrite( cmTtH_t h, const cmChar_t* fn ) +{ + cmTtRC_t rc = kOkTtRC; + cmTt_t* p = _cmTtHandleToPtr(h); + cmFileH_t fh; + + if( cmFileOpen(&fh,fn,kReadFileFl,p->err.rpt) != kOkFileRC ) + return cmErrMsg(&p->err,kFileFailTtRC,"The file '%s' could not be opened.",cmStringNullGuard(fn)); + + rc = _cmTtWriteNode(p,p->tree,fh); + + if( cmFileClose(&fh) != kOkFileRC ) + rc = cmErrMsg(&p->err,kFileFailTtRC,"The output file '%s' failed on close.",cmStringNullGuard(fn)); + + return rc; +} + +typedef struct cmTtPath_str +{ + const cmChar_t* label; + unsigned index; + struct cmTtPath_str* next; + struct cmTtPath_str* prev; +} cmTtPath_t; + + +cmTtNode_t* _cmTtFindNode( cmTt_t* p, const cmTtPath_t* pp ) +{ + cmTtNode_t* np = p->tree; + + if( pp == NULL ) + return NULL; + + assert( np!=NULL); // the tree should never be empty. + + for(; pp!=NULL; pp=pp->next) + { + cmTtNode_t* cnp = np->children; + + // locate the label for the current path level + for(; cnp!=NULL; cnp=cnp->rsib) + if( cnp->label != NULL && strcmp(cnp->label,pp->label)==0 ) + break; + + // the label at the current path level was not found + if( cnp==NULL ) + return NULL; + + unsigned i; + // locate the index at the current level - all labels + // must match the current label + for(i=0; cnp!=NULL && iindex; cnp=cnp->rsib,++i) + if( cnp->label==NULL || strcmp(cnp->label,pp->label) ) + { + // a label mismatch occurred. + return NULL; + } + + // the index was not found + if( cnp==NULL ) + return NULL; + + // cnp is the matched node at this level + np = cnp; + + } + + return np; +} + +cmTtRC_t _cmTextTemplateSetValue(cmTt_t* p, const cmTtPath_t *pp, const cmChar_t* value) +{ + cmTtNode_t* np; + + assert( pp != NULL ); + + if((np = _cmTtFindNode(p,pp)) == NULL ) + return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index); + + return _cmTtSetValue(p,np,pp->label,pp->index,value); +} + +cmTtRC_t _cmTextTemplateRepeatNodeN( cmTt_t* p, const cmTtPath_t* pp, unsigned n ) +{ + cmTtNode_t* np; + unsigned i; + + // locate the requested node + if((np = _cmTtFindNode(p,pp)) == NULL ) + return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index); + + for(i=0; inext!=NULL ) + pp=pp->next; + + pp->next = ele; + } + + ele->label = label; + ele->index = index; + ele->prev = pp; + ele->next = NULL; + + return list; +} + +cmTtRC_t _cmTextTemplateApply( cmTt_t* p, cmJsonNode_t* jnp, cmTtPath_t* list, unsigned index ) +{ + cmTtRC_t rc = kOkTtRC; + switch( jnp->typeId & kMaskTId ) + { + case kPairTId: + { + const cmChar_t* label = cmJsonPairLabel(jnp); + cmJsonNode_t* vjnp = cmJsonPairValue(jnp); + cmTtPath_t ele0; + + // extend the path with the pair label + list = _cmTtPathAppend(list,&ele0,label,index); + + switch( vjnp->typeId & kMaskTId ) + { + case kStringTId: + _cmTextTemplateSetValue(p,list,vjnp->u.stringVal); + break; + + case kObjectTId: + { + cmJsonNode_t* mjnp = vjnp->u.childPtr; + for(; mjnp!=NULL; mjnp=mjnp->siblingPtr) + rc = _cmTextTemplateApply(p,mjnp,list,0); + } + break; + + case kArrayTId: + { + unsigned n = cmJsonChildCount(vjnp); + unsigned i; + + if( n > 1 ) + _cmTextTemplateRepeatNodeN(p,list,n-1); + + for(i=0; inext = NULL; + } + break; + + case kObjectTId: + { + cmJsonNode_t* mjnp = jnp->u.childPtr; + for(; mjnp!=NULL; mjnp=mjnp->siblingPtr) + rc = _cmTextTemplateApply(p,mjnp,list,0); + } + break; + + default: + { assert(0); } + } + + + return rc; +} + +cmTtRC_t cmTextTemplateApply( cmTtH_t h, const cmChar_t* fn ) +{ + cmTtRC_t rc = kOkTtRC; + cmTt_t* p = _cmTtHandleToPtr(h); + cmJsonH_t jsH = cmJsonNullHandle; + + if( cmJsonInitializeFromFile(&jsH,fn,p->ctx) != kOkJsRC ) + return cmErrMsg(&p->err,kJsonFailTtRC,"A JSON tree could not be initialized from '%s'.",cmStringNullGuard(fn)); + + cmJsonNode_t* jnp = cmJsonRoot(jsH); + + if( jnp!=NULL) + for(jnp=jnp->u.childPtr; jnp!=NULL && rc==kOkTtRC; jnp=jnp->siblingPtr ) + rc = _cmTextTemplateApply(p,jnp,NULL,0); + + cmJsonFinalize(&jsH); + return rc; +} + +void _cmTtPrintNode( cmRpt_t* rpt, cmTtNode_t* np ) +{ + switch( np->typeId ) + { + case kTextTtId: + cmRptPrintf(rpt,"%s",np->text); + break; + + case kVarTtId: + if( np->text != NULL ) + cmRptPrintf(rpt,"|%s=%s|",np->label,np->text); + else + cmRptPrintf(rpt,"|%s|",np->label); + break; + + case kSetTtId: + { + cmTtNode_t* cnp; + cmRptPrintf(rpt,"{"); + + if( np->label != NULL ) + cmRptPrintf(rpt,"%s:",np->label); + + for(cnp=np->children; cnp!=NULL; cnp=cnp->rsib) + _cmTtPrintNode(rpt,cnp); + + cmRptPrintf(rpt,"}"); + } + break; } } +void cmTtPrintTree( cmTtH_t h, cmRpt_t* rpt ) +{ + cmTt_t* p = _cmTtHandleToPtr(h); + _cmTtPrintNode(rpt,p->tree); +} + + cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn ) { @@ -365,7 +800,20 @@ cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn ) if((rc = cmTextTemplateInitialize(ctx,&h,fn)) != kOkTtRC ) return rc; - cmTextTemplatePrintTokens(h,&ctx->rpt); + if(0) + { + cmTextTemplateRepeat(h,"name",0,NULL); + + cmTextTemplateRepeat(h,"var2",0,NULL); + + cmTextTemplateSetValue(h, "val0", "var2", 0, NULL ); + } + else + { + cmTextTemplateApply(h,"/home/kevin/src/cmtest/src/cmtest/data/tmpl_src.js"); + } + + cmTtPrintTree(h,&ctx->rpt); cmTextTemplateFinalize(&h); diff --git a/cmTextTemplate.h b/cmTextTemplate.h index 533c4b1..4a139fb 100644 --- a/cmTextTemplate.h +++ b/cmTextTemplate.h @@ -7,17 +7,47 @@ enum kOkTtRC = cmOkRC, kFileFailTtRC, kLHeapFailTtRC, - kSyntaxErrTtRC + kSyntaxErrTtRC, + kFindFailTtRC, + kInvalidTypeTtRC, + kJsonFailTtRC }; typedef cmHandle_t cmTtH_t; typedef unsigned cmTtRC_t; extern cmTtH_t cmTtNullHandle; - +// Initialize a template file. cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn ); + +// Finalize a template file cmTtRC_t cmTextTemplateFinalize( cmTtH_t* hp ); + +// Return true if the template file is intialized. bool cmTextTemplateIsValid( cmTtH_t h ); + +// Set the value of a template variable. +// The node identified by { label,index, label, index ... } must +// be a variable node. The function will fail if a 'set' or 'text' node +// is identified. +// Set 'value' to NULL to erase a previously set value. +cmTtRC_t cmTextTemplateSetValue( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, ... ); + +// Create a copy of the sub-tree identified by the variable path +// and insert it as the left sibling of the sub-tree's root. +cmTtRC_t cmTextTemplateRepeat( cmTtH_t h, const cmChar_t* label, unsigned index, ... ); + +// Write the template file. +cmTtRC_t cmTextTemplateWrite( cmTtH_t h, const cmChar_t* fn ); + +// Apply a template value JSON file to this template +cmTtRC_t cmTextTemplateApply( cmTtH_t h, const cmChar_t* fn ); + + +// Print an annotated template tree. +void cmTtPrintTree( cmTtH_t h, cmRpt_t* rpt ); + + cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn );