libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmTextTemplate.c 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmText.h"
  10. #include "cmFile.h"
  11. #include "cmJson.h"
  12. #include "cmTextTemplate.h"
  13. /*
  14. $var$ // global var
  15. ${name$ $var0$ $var1$ $}$ // name.var0 name.var1
  16. ${name$ $var0$ $var1$ $}$ // name.var0 name.var1
  17. replace(tpl,"val","var0") // var0 = val
  18. replace(tpl,"val","name","var0",NULL) // name.var0 = val - named assignment
  19. replace(tpl,"val0","val0","name") // name.0=val0; name.1=val1 - place assignment
  20. repeat( tpl, "name" ) // create a copy of "name" just after name
  21. clean( tpl, "name" ) // remove unused variables from "name"
  22. */
  23. #define kVarBegChar '$'
  24. #define kVarEndChar '$'
  25. #define kSetBegChar '{'
  26. #define kSetEndChar '}'
  27. typedef enum
  28. {
  29. kTextTtId,
  30. kVarTtId,
  31. kSetTtId
  32. } cmTtId_t;
  33. typedef struct cmTtNode_str
  34. {
  35. cmTtId_t typeId;
  36. cmChar_t* label;
  37. cmChar_t* text;
  38. struct cmTtNode_str* parent;
  39. struct cmTtNode_str* children;
  40. struct cmTtNode_str* rsib;
  41. struct cmTtNode_str* lsib;
  42. } cmTtNode_t;
  43. typedef struct
  44. {
  45. cmCtx_t* ctx;
  46. cmErr_t err;
  47. cmLHeapH_t lhH;
  48. cmChar_t* buf;
  49. cmChar_t* fn;
  50. cmTtNode_t* tree;
  51. } cmTt_t;
  52. cmTtH_t cmTtNullHandle = cmSTATIC_NULL_HANDLE;
  53. cmTt_t* _cmTtHandleToPtr( cmTtH_t h )
  54. {
  55. cmTt_t* p = (cmTt_t*)h.h;
  56. assert( p != NULL );
  57. return p;
  58. }
  59. cmTtRC_t _cmTtFinalize( cmTt_t* p )
  60. {
  61. cmTtRC_t rc = kOkTtRC;
  62. if( p == NULL )
  63. return rc;
  64. cmLHeapDestroy(&p->lhH);
  65. cmMemPtrFree(&p->buf);
  66. cmMemFree(p);
  67. return rc;
  68. }
  69. void _cmTtAppendChild( cmTtNode_t* parent, cmTtNode_t* np )
  70. {
  71. np->parent = parent;
  72. np->rsib = NULL;
  73. if( parent->children == NULL )
  74. {
  75. parent->children = np;
  76. np->lsib = NULL;
  77. }
  78. else
  79. {
  80. cmTtNode_t* cnp = parent->children;
  81. while( cnp->rsib != NULL )
  82. cnp=cnp->rsib;
  83. cnp->rsib = np;
  84. np->lsib = cnp;
  85. }
  86. }
  87. void _cmTtCreateTokenNode( cmTt_t* p, cmTtId_t typeId, cmChar_t* s0, cmChar_t* s1 )
  88. {
  89. if( typeId == kVarTtId )
  90. {
  91. ++s0;
  92. --s1;
  93. }
  94. cmChar_t* s = cmLhAllocStrN(p->lhH,s0,s1-s0+1);
  95. cmTtNode_t* t = cmLhAllocZ(p->lhH,cmTtNode_t,1);
  96. t->typeId = typeId;
  97. t->text = typeId == kTextTtId ? s : NULL;
  98. t->label = typeId == kVarTtId ? s : NULL;
  99. _cmTtAppendChild(p->tree,t);
  100. }
  101. cmTtNode_t* _cmTtCreateSetNode( cmTt_t* p, cmTtNode_t* parent, cmTtNode_t* child )
  102. {
  103. cmTtNode_t* nnp = cmLhAllocZ(p->lhH,cmTtNode_t,1);
  104. nnp->typeId = kSetTtId;
  105. nnp->parent = parent;
  106. if( child != NULL )
  107. {
  108. nnp->children = child->rsib;
  109. // The set node's label is taken from the label of the first child.
  110. if( child->label != NULL && strlen(child->label)>0 )
  111. nnp->label = cmLhAllocStr(p->lhH,child->label+1); // (strip '{' from label)
  112. child->label = NULL;
  113. }
  114. return nnp;
  115. }
  116. cmTtRC_t _cmTtScan( cmTt_t* p, cmChar_t* s)
  117. {
  118. enum { kBeg, kEnd, kQuote };
  119. cmTtRC_t rc = kOkTtRC;
  120. unsigned i = 0;
  121. unsigned line = 1;
  122. unsigned state = kBeg;
  123. cmChar_t* s0 = s;
  124. for(; rc==kOkTtRC && s[i]; ++i)
  125. {
  126. cmChar_t c = s[i];
  127. if( c == '\n')
  128. ++line;
  129. switch(state)
  130. {
  131. case kBeg: // searching for begin '$'
  132. switch( c )
  133. {
  134. case kVarBegChar:
  135. {
  136. _cmTtCreateTokenNode(p,kTextTtId,s0,s+i-1);
  137. state = kEnd;
  138. s0 = s + i;
  139. }
  140. break;
  141. case '"':
  142. state = kQuote;
  143. break;
  144. }
  145. break;
  146. case kEnd: // searching for end '$'
  147. switch(c)
  148. {
  149. case kVarEndChar:
  150. {
  151. _cmTtCreateTokenNode(p,kVarTtId,s0,s+i);
  152. state = kBeg;
  153. s0 = s + i + 1;
  154. }
  155. break;
  156. case '\n':
  157. rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"A end-of-line was encountered inside a template variable on line %i in '%s'.",line,p->fn);
  158. break;
  159. case '"':
  160. rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"A double-quote character was found inside a template variable on line %i in '%s'.",line,p->fn);
  161. break;
  162. }
  163. break;
  164. case kQuote: // searching for '"'
  165. switch(c)
  166. {
  167. case '"':
  168. state = kBeg;
  169. break;
  170. case '\n':
  171. rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"A double-quote character was found inside a quoted string on line %i in '%s'.",line,p->fn);
  172. break;
  173. }
  174. break;
  175. default:
  176. { assert(0); }
  177. }
  178. }
  179. switch(state)
  180. {
  181. case kBeg: _cmTtCreateTokenNode(p,kTextTtId,s0,s0+strlen(s0)-1); break;
  182. case kEnd: rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing template variable ending '%c'.",kVarEndChar); break;
  183. case kQuote: rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing ending double-quote in quoated string."); break;
  184. default:
  185. { assert(0); }
  186. }
  187. return rc;
  188. }
  189. bool _cmTtTokenIsBegin( cmTtNode_t* tp )
  190. {
  191. return tp->typeId==kVarTtId && tp->label[0]==kSetBegChar;
  192. }
  193. bool _cmTtTokenIsEnd( cmTtNode_t* tp )
  194. {
  195. return tp->typeId==kVarTtId && tp->label[0]==kSetEndChar;
  196. }
  197. cmTtNode_t* _cmTtBuildTree( cmTt_t* p, cmTtNode_t* np, cmTtNode_t* tp )
  198. {
  199. while( tp != NULL )
  200. {
  201. tp->parent = np;
  202. if( _cmTtTokenIsBegin(tp) )
  203. {
  204. cmTtNode_t* nnp = _cmTtCreateSetNode(p,np,tp);
  205. tp->parent = nnp;
  206. nnp->lsib = tp->lsib;
  207. // break the token chain before the 'begin' token
  208. if( tp->lsib != NULL )
  209. tp->lsib->rsib = nnp;
  210. // create a new child variable node and advance to token string
  211. if((tp = _cmTtBuildTree(p, nnp, tp->rsib)) == NULL )
  212. break;
  213. nnp->rsib = tp;
  214. }
  215. if( _cmTtTokenIsEnd(tp) )
  216. {
  217. // break the token chain before the 'end' token
  218. if( tp->lsib != NULL )
  219. tp->lsib->rsib = NULL;
  220. // the token after 'end' become the current token
  221. tp = tp->rsib;
  222. if( tp != NULL )
  223. {
  224. if( tp->lsib != NULL )
  225. tp->lsib->rsib = NULL;
  226. tp->lsib = NULL;
  227. }
  228. break;
  229. }
  230. tp = tp->rsib;
  231. }
  232. return tp;
  233. }
  234. cmTtNode_t* _cmTtCloneNode( cmTt_t* p, const cmTtNode_t* snp )
  235. {
  236. cmTtNode_t* np = cmLhAllocZ(p->lhH,cmTtNode_t,1);
  237. np->typeId = snp->typeId;
  238. np->label = snp->label == NULL ? NULL : cmLhAllocStr(p->lhH,snp->label);
  239. np->text = snp->text == NULL ? NULL : cmLhAllocStr(p->lhH,snp->text);
  240. cmTtNode_t* csnp = snp->children;
  241. for(; csnp!=NULL; csnp=csnp->rsib)
  242. {
  243. cmTtNode_t* cnp = _cmTtCloneNode(p,csnp);
  244. _cmTtAppendChild(np,cnp);
  245. }
  246. return np;
  247. }
  248. cmTtNode_t* _cmTtRepeatNode( cmTt_t* p, cmTtNode_t* snp )
  249. {
  250. cmTtNode_t* stnp = _cmTtCloneNode(p,snp);
  251. stnp->parent = snp->parent;
  252. stnp->lsib = snp;
  253. stnp->rsib = snp->rsib;
  254. if( snp->rsib != NULL )
  255. snp->rsib->lsib = stnp;
  256. snp->rsib = stnp;
  257. return stnp;
  258. }
  259. cmTtNode_t* _cmTtFindNodeV( cmTt_t* p, const cmChar_t* label, unsigned index, va_list vl )
  260. {
  261. cmTtNode_t* np = p->tree;
  262. if( label == NULL )
  263. return NULL;
  264. assert( np!=NULL); // the tree should never be empty.
  265. while(1)
  266. {
  267. cmTtNode_t* cnp = np->children;
  268. // locate the label for the current path level
  269. for(; cnp!=NULL; cnp=cnp->rsib)
  270. if( cnp->label != NULL && strcmp(cnp->label,label)==0 )
  271. break;
  272. // the label at the current path level was not found
  273. if( cnp==NULL )
  274. return NULL;
  275. unsigned i;
  276. // locate the index at the current level - all labels
  277. // must match the current label
  278. for(i=0; cnp!=NULL && i<index; cnp=cnp->rsib,++i)
  279. if( cnp->label==NULL || strcmp(cnp->label,label) )
  280. {
  281. // a label mismatch occurred.
  282. return NULL;
  283. }
  284. // the index was not found
  285. if( cnp==NULL )
  286. return NULL;
  287. // cnp is the matched node at this level
  288. np = cnp;
  289. // the end of the path was located - success!
  290. if((label = va_arg(vl,const cmChar_t*)) == NULL )
  291. break;
  292. index = va_arg(vl,unsigned);
  293. }
  294. return np;
  295. }
  296. cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn )
  297. {
  298. cmTtRC_t rc;
  299. if((rc = cmTextTemplateFinalize(hp)) != kOkTtRC )
  300. return rc;
  301. cmTt_t* p = cmMemAllocZ(cmTt_t,1);
  302. cmErrSetup(&p->err,&ctx->rpt,"TextTemplate");
  303. // create the local linked heap
  304. if( cmLHeapIsValid(p->lhH = cmLHeapCreate(1024, ctx )) == false )
  305. {
  306. rc = cmErrMsg(&p->err,kLHeapFailTtRC,"Lheap Mgr. allocation failed.");
  307. goto errLabel;
  308. }
  309. // read the template file
  310. if((p->buf = cmFileFnToStr(fn,p->err.rpt,NULL)) == NULL )
  311. {
  312. rc = cmErrMsg(&p->err,kFileFailTtRC,"Unable to open the file '%s'.",cmStringNullGuard(fn));
  313. goto errLabel;
  314. }
  315. // store the template file name
  316. p->fn = cmLhAllocStr(p->lhH,fn);
  317. // create the root node
  318. p->tree = _cmTtCreateSetNode(p,NULL,NULL);
  319. // break the template file into tokens
  320. if((rc = _cmTtScan(p,p->buf)) != kOkTtRC )
  321. goto errLabel;
  322. // The tree now has two levels. The root node
  323. // and a flat linked list of token nodes which are the children
  324. // of the root node.
  325. // build the node tree
  326. _cmTtBuildTree(p,p->tree,p->tree->children);
  327. // check for errors
  328. rc = cmErrLastRC(&p->err);
  329. p->ctx = ctx;
  330. hp->h = p;
  331. errLabel:
  332. if( rc != kOkTtRC )
  333. _cmTtFinalize(p);
  334. return rc;
  335. }
  336. cmTtRC_t cmTextTemplateFinalize( cmTtH_t* hp )
  337. {
  338. cmTtRC_t rc = kOkTtRC;
  339. if( hp==NULL || cmTextTemplateIsValid(*hp)==false )
  340. return rc;
  341. cmTt_t* p = _cmTtHandleToPtr(*hp);
  342. if((rc = _cmTtFinalize(p)) != kOkTtRC )
  343. return rc;
  344. hp->h = NULL;
  345. return rc;
  346. }
  347. bool cmTextTemplateIsValid( cmTtH_t h )
  348. { return h.h != NULL; }
  349. cmTtRC_t _cmTtSetValue( cmTt_t* p, cmTtNode_t* np, const cmChar_t* label, unsigned index, const cmChar_t* value )
  350. {
  351. // only the value of variable nodes may be set
  352. if( np->typeId != kVarTtId )
  353. return cmErrMsg(&p->err,kInvalidTypeTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
  354. // set the value
  355. if( value != NULL )
  356. np->text = cmLhResizeStr(p->lhH,np->text,value);
  357. else
  358. {
  359. cmLhFree(p->lhH,np->text);
  360. np->text = NULL;
  361. }
  362. return kOkTtRC;
  363. }
  364. cmTtRC_t cmTextTemplateSetValueV( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, va_list vl )
  365. {
  366. cmTt_t* p = _cmTtHandleToPtr(h);
  367. cmTtNode_t* np;
  368. // locate the requested node
  369. if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL )
  370. return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
  371. return _cmTtSetValue(p,np,label,index,value);
  372. }
  373. cmTtRC_t cmTextTemplateSetValue( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, ... )
  374. {
  375. cmTtRC_t rc;
  376. va_list vl;
  377. va_start(vl,index);
  378. rc = cmTextTemplateSetValueV(h,value,label,index,vl);
  379. va_end(vl);
  380. return rc;
  381. }
  382. cmTtRC_t cmTextTemplateRepeatV( cmTtH_t h, const cmChar_t* label, unsigned index, va_list vl )
  383. {
  384. cmTt_t* p = _cmTtHandleToPtr(h);
  385. cmTtNode_t* np;
  386. // locate the requested node
  387. if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL )
  388. return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
  389. _cmTtRepeatNode(p,np);
  390. return kOkTtRC;
  391. }
  392. cmTtRC_t cmTextTemplateRepeat( cmTtH_t h, const cmChar_t* label, unsigned index, ... )
  393. {
  394. cmTtRC_t rc;
  395. va_list vl;
  396. va_start(vl,index);
  397. rc = cmTextTemplateRepeatV(h,label,index,vl);
  398. va_end(vl);
  399. return rc;
  400. }
  401. cmTtRC_t _cmTtWriteNode( cmTt_t* p, cmTtNode_t* np, cmFileH_t fh )
  402. {
  403. cmTtRC_t rc = kOkTtRC;
  404. cmFileRC_t frc = kOkFileRC;
  405. switch( np->typeId )
  406. {
  407. case kTextTtId:
  408. case kVarTtId:
  409. {
  410. if( np->text != NULL )
  411. if((frc = cmFilePrint(fh,np->text)) != kOkFileRC )
  412. rc = cmErrMsg(&p->err,kFileFailTtRC,"File write failed on '%s'.", cmFileName(fh));
  413. }
  414. break;
  415. case kSetTtId:
  416. {
  417. cmTtNode_t* cnp;
  418. for(cnp=np->children; cnp!=NULL && rc==kOkTtRC; cnp=cnp->rsib)
  419. rc = _cmTtWriteNode(p,cnp,fh);
  420. }
  421. break;
  422. default:
  423. { assert(0); }
  424. }
  425. return rc;
  426. }
  427. cmTtRC_t cmTextTemplateWrite( cmTtH_t h, const cmChar_t* fn )
  428. {
  429. cmTtRC_t rc = kOkTtRC;
  430. cmTt_t* p = _cmTtHandleToPtr(h);
  431. cmFileH_t fh;
  432. if( cmFileOpen(&fh,fn,kReadFileFl,p->err.rpt) != kOkFileRC )
  433. return cmErrMsg(&p->err,kFileFailTtRC,"The file '%s' could not be opened.",cmStringNullGuard(fn));
  434. rc = _cmTtWriteNode(p,p->tree,fh);
  435. if( cmFileClose(&fh) != kOkFileRC )
  436. rc = cmErrMsg(&p->err,kFileFailTtRC,"The output file '%s' failed on close.",cmStringNullGuard(fn));
  437. return rc;
  438. }
  439. typedef struct cmTtPath_str
  440. {
  441. const cmChar_t* label;
  442. unsigned index;
  443. struct cmTtPath_str* next;
  444. struct cmTtPath_str* prev;
  445. } cmTtPath_t;
  446. cmTtNode_t* _cmTtFindNode( cmTt_t* p, const cmTtPath_t* pp )
  447. {
  448. cmTtNode_t* np = p->tree;
  449. if( pp == NULL )
  450. return NULL;
  451. assert( np!=NULL); // the tree should never be empty.
  452. for(; pp!=NULL; pp=pp->next)
  453. {
  454. cmTtNode_t* cnp = np->children;
  455. // locate the label for the current path level
  456. for(; cnp!=NULL; cnp=cnp->rsib)
  457. if( cnp->label != NULL && strcmp(cnp->label,pp->label)==0 )
  458. break;
  459. // the label at the current path level was not found
  460. if( cnp==NULL )
  461. return NULL;
  462. unsigned i;
  463. // locate the index at the current level - all labels
  464. // must match the current label
  465. for(i=0; cnp!=NULL && i<pp->index; cnp=cnp->rsib,++i)
  466. if( cnp->label==NULL || strcmp(cnp->label,pp->label) )
  467. {
  468. // a label mismatch occurred.
  469. return NULL;
  470. }
  471. // the index was not found
  472. if( cnp==NULL )
  473. return NULL;
  474. // cnp is the matched node at this level
  475. np = cnp;
  476. }
  477. return np;
  478. }
  479. cmTtRC_t _cmTextTemplateSetValue(cmTt_t* p, const cmTtPath_t *pp, const cmChar_t* value)
  480. {
  481. cmTtNode_t* np;
  482. assert( pp != NULL );
  483. if((np = _cmTtFindNode(p,pp)) == NULL )
  484. return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index);
  485. return _cmTtSetValue(p,np,pp->label,pp->index,value);
  486. }
  487. cmTtRC_t _cmTextTemplateRepeatNodeN( cmTt_t* p, const cmTtPath_t* pp, unsigned n )
  488. {
  489. cmTtNode_t* np;
  490. unsigned i;
  491. // locate the requested node
  492. if((np = _cmTtFindNode(p,pp)) == NULL )
  493. return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index);
  494. for(i=0; i<n; ++i)
  495. _cmTtRepeatNode(p,np);
  496. return kOkTtRC;
  497. }
  498. cmTtPath_t* _cmTtPathAppend( cmTtPath_t* list, cmTtPath_t* ele, const cmChar_t* label, unsigned index )
  499. {
  500. cmTtPath_t* pp = list;
  501. if( pp == NULL )
  502. list = ele;
  503. else
  504. {
  505. while( pp->next!=NULL )
  506. pp=pp->next;
  507. pp->next = ele;
  508. }
  509. ele->label = label;
  510. ele->index = index;
  511. ele->prev = pp;
  512. ele->next = NULL;
  513. return list;
  514. }
  515. cmTtRC_t _cmTextTemplateApply( cmTt_t* p, cmJsonNode_t* jnp, cmTtPath_t* list, unsigned index )
  516. {
  517. cmTtRC_t rc = kOkTtRC;
  518. switch( jnp->typeId & kMaskTId )
  519. {
  520. case kPairTId:
  521. {
  522. const cmChar_t* label = cmJsonPairLabel(jnp);
  523. cmJsonNode_t* vjnp = cmJsonPairValue(jnp);
  524. cmTtPath_t ele0;
  525. // extend the path with the pair label
  526. list = _cmTtPathAppend(list,&ele0,label,index);
  527. switch( vjnp->typeId & kMaskTId )
  528. {
  529. case kStringTId:
  530. _cmTextTemplateSetValue(p,list,vjnp->u.stringVal);
  531. break;
  532. case kObjectTId:
  533. {
  534. cmJsonNode_t* mjnp = vjnp->u.childPtr;
  535. for(; mjnp!=NULL; mjnp=mjnp->siblingPtr)
  536. rc = _cmTextTemplateApply(p,mjnp,list,0);
  537. }
  538. break;
  539. case kArrayTId:
  540. {
  541. unsigned n = cmJsonChildCount(vjnp);
  542. unsigned i;
  543. if( n > 1 )
  544. _cmTextTemplateRepeatNodeN(p,list,n-1);
  545. for(i=0; i<n && rc==kOkTtRC; ++i)
  546. {
  547. ele0.index = i;
  548. rc = _cmTextTemplateApply(p,cmJsonArrayElement(vjnp,i),list,i);
  549. }
  550. }
  551. break;
  552. default:
  553. { assert(0); }
  554. }
  555. if( ele0.prev != NULL )
  556. ele0.prev->next = NULL;
  557. }
  558. break;
  559. case kObjectTId:
  560. {
  561. cmJsonNode_t* mjnp = jnp->u.childPtr;
  562. for(; mjnp!=NULL; mjnp=mjnp->siblingPtr)
  563. rc = _cmTextTemplateApply(p,mjnp,list,0);
  564. }
  565. break;
  566. default:
  567. { assert(0); }
  568. }
  569. return rc;
  570. }
  571. cmTtRC_t cmTextTemplateApply( cmTtH_t h, const cmChar_t* fn )
  572. {
  573. cmTtRC_t rc = kOkTtRC;
  574. cmTt_t* p = _cmTtHandleToPtr(h);
  575. cmJsonH_t jsH = cmJsonNullHandle;
  576. if( cmJsonInitializeFromFile(&jsH,fn,p->ctx) != kOkJsRC )
  577. return cmErrMsg(&p->err,kJsonFailTtRC,"A JSON tree could not be initialized from '%s'.",cmStringNullGuard(fn));
  578. cmJsonNode_t* jnp = cmJsonRoot(jsH);
  579. if( jnp!=NULL)
  580. for(jnp=jnp->u.childPtr; jnp!=NULL && rc==kOkTtRC; jnp=jnp->siblingPtr )
  581. rc = _cmTextTemplateApply(p,jnp,NULL,0);
  582. cmJsonFinalize(&jsH);
  583. return rc;
  584. }
  585. void _cmTtPrintNode( cmRpt_t* rpt, cmTtNode_t* np )
  586. {
  587. switch( np->typeId )
  588. {
  589. case kTextTtId:
  590. cmRptPrintf(rpt,"%s",np->text);
  591. break;
  592. case kVarTtId:
  593. if( np->text != NULL )
  594. cmRptPrintf(rpt,"|%s=%s|",np->label,np->text);
  595. else
  596. cmRptPrintf(rpt,"|%s|",np->label);
  597. break;
  598. case kSetTtId:
  599. {
  600. cmTtNode_t* cnp;
  601. cmRptPrintf(rpt,"{");
  602. if( np->label != NULL )
  603. cmRptPrintf(rpt,"%s:",np->label);
  604. for(cnp=np->children; cnp!=NULL; cnp=cnp->rsib)
  605. _cmTtPrintNode(rpt,cnp);
  606. cmRptPrintf(rpt,"}");
  607. }
  608. break;
  609. }
  610. }
  611. void cmTtPrintTree( cmTtH_t h, cmRpt_t* rpt )
  612. {
  613. cmTt_t* p = _cmTtHandleToPtr(h);
  614. _cmTtPrintNode(rpt,p->tree);
  615. }
  616. cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn )
  617. {
  618. cmTtRC_t rc;
  619. cmTtH_t h = cmTtNullHandle;
  620. if((rc = cmTextTemplateInitialize(ctx,&h,fn)) != kOkTtRC )
  621. return rc;
  622. if(0)
  623. {
  624. cmTextTemplateRepeat(h,"name",0,NULL);
  625. cmTextTemplateRepeat(h,"var2",0,NULL);
  626. cmTextTemplateSetValue(h, "val0", "var2", 0, NULL );
  627. }
  628. else
  629. {
  630. cmTextTemplateApply(h,"/home/kevin/src/cmtest/src/cmtest/data/tmpl_src.js");
  631. }
  632. cmTtPrintTree(h,&ctx->rpt);
  633. cmTextTemplateFinalize(&h);
  634. return rc;
  635. }