kpl преди 12 години
родител
ревизия
34029578d4
променени са 2 файла, в които са добавени 585 реда и са изтрити 107 реда
  1. 553
    105
      cmTextTemplate.c
  2. 32
    2
      cmTextTemplate.h

+ 553
- 105
cmTextTemplate.c Целия файл

@@ -8,6 +8,7 @@
8 8
 #include "cmLinkedHeap.h"
9 9
 #include "cmText.h"
10 10
 #include "cmFile.h"
11
+#include "cmJson.h"
11 12
 #include "cmTextTemplate.h"
12 13
 
13 14
 /*
@@ -26,44 +27,41 @@
26 27
 */
27 28
 
28 29
 
29
-cmTtH_t cmTtNullHandle = cmSTATIC_NULL_HANDLE;
30
-
31
-enum
32
-{
33
-  kVarTtId,   // variable node
34
-  kValTtId,   // value (leaf) node
35
-  kTextTtId   // text
36
-};
30
+#define kVarBegChar '$'
31
+#define kVarEndChar '$'
32
+#define kSetBegChar '{'
33
+#define kSetEndChar '}'
37 34
 
38
-typedef struct cmTtToken_str
35
+typedef enum
39 36
 {
40
-  unsigned              typeId;
41
-  cmChar_t*             text;
42
-  cmChar_t*             end;
43
-  struct cmTtToken_str* next;
44
-  struct cmTtToken_str* prev;
45
-} cmTtToken_t;
37
+  kTextTtId,
38
+  kVarTtId,
39
+  kSetTtId
40
+} cmTtId_t;
46 41
 
47 42
 typedef struct cmTtNode_str
48 43
 {
49
-  unsigned             typeId;
44
+  cmTtId_t             typeId;
50 45
   cmChar_t*            label;
51
-  cmTtToken_t*         token;
46
+  cmChar_t*            text;
52 47
   struct cmTtNode_str* parent;
53 48
   struct cmTtNode_str* children;
54
-  struct cmTtNode_str* sibling;
49
+  struct cmTtNode_str* rsib;
50
+  struct cmTtNode_str* lsib;
55 51
 } cmTtNode_t;
56 52
 
57 53
 typedef struct
58 54
 {
55
+  cmCtx_t*     ctx;
59 56
   cmErr_t      err;
60 57
   cmLHeapH_t   lhH;
61 58
   cmChar_t*    buf;
62 59
   cmChar_t*    fn;
63 60
   cmTtNode_t*  tree;
64
-  cmTtToken_t* tokens;
65 61
 } cmTt_t;
66 62
 
63
+cmTtH_t cmTtNullHandle = cmSTATIC_NULL_HANDLE;
64
+
67 65
 cmTt_t* _cmTtHandleToPtr( cmTtH_t h )
68 66
 {
69 67
   cmTt_t* p = (cmTt_t*)h.h;
@@ -83,28 +81,63 @@ cmTtRC_t _cmTtFinalize( cmTt_t* p )
83 81
   return rc;
84 82
 }
85 83
 
86
-cmTtToken_t*  _cmTtCreateToken( cmTt_t* p, unsigned typeId, cmChar_t* s0, cmChar_t* s1 )
84
+void _cmTtAppendChild( cmTtNode_t* parent, cmTtNode_t* np )
87 85
 {
88
-  cmTtToken_t* tp = p->tokens;
89
-  cmTtToken_t* t = cmLhAllocZ(p->lhH,cmTtToken_t,1);
90
-  t->typeId      = kVarTtId;
91
-  t->text        = s0;
92
-  t->end         = s1;
93
-  
94
-  if( tp == NULL )
95
-    p->tokens = t;
86
+  np->parent = parent;
87
+  np->rsib   = NULL;
88
+
89
+  if( parent->children == NULL )
90
+  {
91
+    parent->children = np;
92
+    np->lsib         = NULL;
93
+  }
96 94
   else
97 95
   {
98
-    while( tp->next!=NULL )
99
-      tp=tp->next;
100
-      
101
-    tp->next = t;
102
-    t->prev  = tp;
96
+    cmTtNode_t* cnp = parent->children;
97
+    while( cnp->rsib != NULL )
98
+      cnp=cnp->rsib;
99
+
100
+    cnp->rsib = np;
101
+    np->lsib  = cnp;
103 102
   }
103
+}
104 104
 
105
-  return tp;
105
+void  _cmTtCreateTokenNode( cmTt_t* p, cmTtId_t typeId, cmChar_t* s0, cmChar_t* s1 )
106
+{
107
+  if( typeId == kVarTtId )
108
+  {
109
+    ++s0;
110
+    --s1;    
111
+  }
112
+
113
+  cmChar_t* s = cmLhAllocStrN(p->lhH,s0,s1-s0+1);
114
+
115
+  cmTtNode_t* t  = cmLhAllocZ(p->lhH,cmTtNode_t,1);
116
+  t->typeId      = typeId;
117
+  t->text        = typeId == kTextTtId ? s : NULL;
118
+  t->label       = typeId == kVarTtId  ? s : NULL;
119
+
120
+  _cmTtAppendChild(p->tree,t);  
106 121
 }
107 122
 
123
+cmTtNode_t* _cmTtCreateSetNode( cmTt_t* p, cmTtNode_t* parent, cmTtNode_t* child )
124
+{
125
+  cmTtNode_t* nnp = cmLhAllocZ(p->lhH,cmTtNode_t,1);
126
+  nnp->typeId  = kSetTtId;
127
+  nnp->parent  = parent;
128
+  if( child != NULL )
129
+  {
130
+    nnp->children = child->rsib;
131
+      
132
+    // The set node's label is taken from the label of the first child.
133
+    if( child->label != NULL && strlen(child->label)>0 )
134
+      nnp->label = cmLhAllocStr(p->lhH,child->label+1);  // (strip '{' from label)
135
+
136
+    child->label  = NULL;
137
+  }
138
+
139
+  return nnp;
140
+}
108 141
 
109 142
 cmTtRC_t  _cmTtScan( cmTt_t* p, cmChar_t* s)
110 143
 {
@@ -128,9 +161,9 @@ cmTtRC_t  _cmTtScan( cmTt_t* p, cmChar_t* s)
128 161
       case kBeg:  // searching for begin '$'
129 162
         switch( c )
130 163
         {
131
-          case '$':
164
+          case kVarBegChar:
132 165
             {
133
-              _cmTtCreateToken(p,kTextTtId,s0,s+i-1);          
166
+              _cmTtCreateTokenNode(p,kTextTtId,s0,s+i-1);          
134 167
               state = kEnd;
135 168
               s0    = s + i;
136 169
             }
@@ -140,13 +173,14 @@ cmTtRC_t  _cmTtScan( cmTt_t* p, cmChar_t* s)
140 173
             state = kQuote;
141 174
             break;
142 175
         }
176
+        break;
143 177
 
144 178
       case kEnd:  // searching for end '$'
145 179
         switch(c)
146 180
         {
147
-          case '$':
181
+          case kVarEndChar:
148 182
             {
149
-              _cmTtCreateToken(p,kVarTtId,s0,s+i);
183
+              _cmTtCreateTokenNode(p,kVarTtId,s0,s+i);
150 184
               state = kBeg;
151 185
               s0    = s + i + 1;
152 186
             }
@@ -180,93 +214,162 @@ cmTtRC_t  _cmTtScan( cmTt_t* p, cmChar_t* s)
180 214
     }
181 215
   }
182 216
 
217
+  switch(state)
218
+  {
219
+    case kBeg: _cmTtCreateTokenNode(p,kTextTtId,s0,s0+strlen(s0)-1); break;        
220
+    case kEnd:   rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing template variable ending '%c'.",kVarEndChar); break;
221
+    case kQuote: rc = cmErrMsg(&p->err,kSyntaxErrTtRC,"Missing ending double-quote in quoated string."); break;
222
+    default:
223
+      { assert(0); }
224
+  }
225
+  
226
+
183 227
   return rc;
184 228
 }
185 229
 
186
-bool _cmTtTokenIsBegin( cmTtToken_t* tp ) 
230
+bool _cmTtTokenIsBegin( cmTtNode_t* tp ) 
187 231
 { 
188
-  assert(tp->text!=NULL && tp->text[0]=='$'); 
189
-  return tp->typeId==kVarTtId && tp->text[1]=='{'; 
232
+  return tp->typeId==kVarTtId && tp->label[0]==kSetBegChar; 
190 233
 }
191 234
 
192
-bool _cmTtTokenIsEnd( cmTtToken_t* tp ) 
235
+bool _cmTtTokenIsEnd( cmTtNode_t* tp ) 
193 236
 { 
194
-  assert(tp->text!=NULL && tp->text[0]=='$'); 
195
-  return tp->typeId==kVarTtId && tp->text[1]=='}'; 
237
+  return tp->typeId==kVarTtId && tp->label[0]==kSetEndChar; 
196 238
 }
197 239
 
198
-cmTtNode_t* _cmTtCreateNode( cmTt_t* p, cmTtNode_t* parent, unsigned typeId, cmTtToken_t* tp )
199
-{
200
-  cmTtNode_t* nnp = cmLhAllocZ(p->lhH,cmTtNode_t,1);
201
-  nnp->typeId = typeId;
202
-  nnp->token  = tp;
203
-  nnp->parent = parent;
204
-  
205
-  if( parent != NULL )
206
-  {
207
-    if( parent->children == NULL )
208
-      parent->children = nnp;
209
-    else
210
-    {
211
-      cmTtNode_t* np = nnp->children;
212
-      while( np->sibling != NULL )
213
-        np=np->sibling;
214
-      
215
-      np->sibling = nnp;
216
-    }
217
-  }
218
-
219
-  return nnp;
220
-}
221 240
 
222
-cmTtToken_t*  _cmTtBuildTree( cmTt_t* p, cmTtNode_t* np, cmTtToken_t* tp )
241
+cmTtNode_t*  _cmTtBuildTree( cmTt_t* p, cmTtNode_t* np, cmTtNode_t* tp )
223 242
 {
224
-  cmTtToken_t* ftp = tp;
225
-  int          cnt = 0;
243
+
226 244
   while( tp != NULL )
227 245
   {
246
+    tp->parent = np;
247
+
228 248
     if( _cmTtTokenIsBegin(tp) )
229 249
     {      
230
-      // attach preceding text to new right-most leaf-node on 'np'.
231
-      _cmTtCreateNode(p,np,kTextTtId,ftp); 
250
+      cmTtNode_t* nnp = _cmTtCreateSetNode(p,np,tp);
251
+      tp->parent = nnp;
252
+      nnp->lsib  = tp->lsib;
232 253
 
233 254
       // break the token chain before the 'begin' token
234
-      if( tp->prev != NULL )
235
-        tp->prev->next = NULL;
236
-      tp->prev = NULL;
255
+      if( tp->lsib != NULL )
256
+        tp->lsib->rsib = nnp;
237 257
       
258
+
238 259
       // create a new child variable node and advance to token string
239
-      tp  = _cmTtBuildTree(p, _cmTtCreateNode(p,np,kVarTtId,NULL), tp->next );
240
-      ftp = tp;
241
-      ++cnt;
260
+      if((tp  = _cmTtBuildTree(p, nnp, tp->rsib)) == NULL )
261
+        break;      
262
+
263
+      nnp->rsib = tp;
242 264
     }
243 265
 
244 266
     
245 267
     if( _cmTtTokenIsEnd(tp) )
246 268
     {
247
-      --cnt;
248
-
249
-      // break the token chain after the 'end' token
250
-      if( tp->next != NULL )
251
-        tp->next->prev = NULL;
252
-      tp->next = NULL;
253
-
254
-      // create a new right-most leaf-node 
255
-      _cmTtCreateNode(p,np,kTextTtId,ftp);
269
+      // break the token chain before the 'end' token
270
+      if( tp->lsib != NULL )
271
+        tp->lsib->rsib = NULL;
272
+      
273
+      
274
+      // the token after 'end' become the current token
275
+      tp = tp->rsib;
276
+      if( tp != NULL )
277
+      {
278
+        if( tp->lsib != NULL )
279
+          tp->lsib->rsib = NULL;
280
+        tp->lsib = NULL;
281
+      }
256 282
 
257
-      tp = tp->next;
258 283
       break;
259 284
     }
260 285
 
261
-    tp = tp->next;
286
+    tp = tp->rsib;
262 287
   }
263 288
 
264
-  if( cnt != 0 )
265
-    cmErrMsg(&p->err,kSyntaxErrTtRC,"The template file '%s' appears to have unbalanced begin/end markers.",cmStringNullGuard(p->fn));
266 289
   
267 290
   return tp;
268 291
 }
269 292
 
293
+cmTtNode_t* _cmTtCloneNode( cmTt_t* p, const cmTtNode_t* snp )
294
+{
295
+  cmTtNode_t* np = cmLhAllocZ(p->lhH,cmTtNode_t,1);
296
+  np->typeId = snp->typeId;
297
+  np->label  = snp->label == NULL ? NULL : cmLhAllocStr(p->lhH,snp->label);
298
+  np->text   = snp->text  == NULL ? NULL : cmLhAllocStr(p->lhH,snp->text);
299
+  
300
+  
301
+  cmTtNode_t* csnp = snp->children;
302
+  for(; csnp!=NULL; csnp=csnp->rsib)
303
+  {
304
+    cmTtNode_t* cnp = _cmTtCloneNode(p,csnp);
305
+    _cmTtAppendChild(np,cnp);
306
+  }
307
+  
308
+  return np;
309
+}
310
+
311
+cmTtNode_t* _cmTtRepeatNode( cmTt_t* p, cmTtNode_t* snp )
312
+{
313
+  cmTtNode_t* stnp = _cmTtCloneNode(p,snp);
314
+  stnp->parent = snp->parent;
315
+  stnp->lsib   = snp;
316
+  stnp->rsib   = snp->rsib;
317
+  if( snp->rsib != NULL )
318
+    snp->rsib->lsib = stnp;
319
+  snp->rsib = stnp;
320
+  return stnp;
321
+}
322
+
323
+cmTtNode_t* _cmTtFindNodeV( cmTt_t* p, const cmChar_t* label, unsigned index, va_list vl )
324
+{
325
+  cmTtNode_t* np = p->tree;
326
+
327
+  if( label == NULL )
328
+    return NULL;
329
+
330
+  assert( np!=NULL); // the tree should never be empty.
331
+
332
+  while(1)
333
+  {
334
+    cmTtNode_t* cnp = np->children;
335
+
336
+    // locate the label for the current path level
337
+    for(; cnp!=NULL; cnp=cnp->rsib)
338
+      if( cnp->label != NULL && strcmp(cnp->label,label)==0 )
339
+        break;
340
+
341
+    // the label at the current path level was not found
342
+    if( cnp==NULL )
343
+      return NULL;
344
+
345
+    unsigned i;
346
+    // locate the index at the current level - all labels
347
+    // must match the current label 
348
+    for(i=0; cnp!=NULL && i<index; cnp=cnp->rsib,++i)
349
+      if( cnp->label==NULL || strcmp(cnp->label,label) )
350
+      {
351
+        // a label mismatch occurred.
352
+        return NULL;
353
+      }
354
+
355
+    // the index was not found
356
+    if( cnp==NULL )
357
+      return NULL;
358
+
359
+    // cnp is the matched node at this level
360
+    np = cnp;
361
+
362
+    // the end of the path was located - success!
363
+    if((label = va_arg(vl,const cmChar_t*)) == NULL )
364
+      break;
365
+      
366
+    index = va_arg(vl,unsigned);
367
+
368
+  }
369
+
370
+  return np;
371
+}
372
+
270 373
 
271 374
 
272 375
 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
288 391
   }
289 392
   
290 393
   // read the template file 
291
-  if((p->buf = cmFileFnToBuf(fn,p->err.rpt,NULL)) == NULL )
394
+  if((p->buf = cmFileFnToStr(fn,p->err.rpt,NULL)) == NULL )
292 395
   {
293 396
     rc = cmErrMsg(&p->err,kFileFailTtRC,"Unable to open the file '%s'.",cmStringNullGuard(fn));
294 397
     goto errLabel;
@@ -297,18 +400,25 @@ cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn
297 400
   // store the template file name
298 401
   p->fn   = cmLhAllocStr(p->lhH,fn);
299 402
 
403
+  // create the root node
404
+  p->tree = _cmTtCreateSetNode(p,NULL,NULL);
405
+
300 406
   // break the template file into tokens
301 407
   if((rc = _cmTtScan(p,p->buf)) != kOkTtRC )
302 408
     goto errLabel;
303 409
 
304
-  // create the root node
305
-  p->tree = _cmTtCreateNode(p,NULL,kVarTtId,NULL);
410
+  // The tree now has two levels. The root node
411
+  // and a flat linked list of token nodes which are the children
412
+  // of the root node.
306 413
 
307 414
   // build the node tree
308
-  _cmTtBuildTree(p,p->tree,p->tokens);
415
+  _cmTtBuildTree(p,p->tree,p->tree->children);
309 416
 
310 417
   // check for errors
311 418
   rc = cmErrLastRC(&p->err);
419
+
420
+  p->ctx = ctx;
421
+  hp->h = p;
312 422
   
313 423
  errLabel:
314 424
 
@@ -338,24 +448,349 @@ cmTtRC_t cmTextTemplateFinalize( cmTtH_t* hp )
338 448
 bool     cmTextTemplateIsValid( cmTtH_t h )
339 449
 { return h.h != NULL; }
340 450
 
341
-void cmTextTemplatePrintTokens( cmTtH_t h, cmRpt_t* rpt )
451
+cmTtRC_t _cmTtSetValue( cmTt_t* p, cmTtNode_t* np, const cmChar_t* label, unsigned index, const cmChar_t* value )
342 452
 {
453
+  // only the value of variable nodes may be set
454
+  if( np->typeId != kVarTtId )
455
+    return cmErrMsg(&p->err,kInvalidTypeTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
456
+
457
+  // set the value 
458
+  if( value != NULL )
459
+    np->text = cmLhResizeStr(p->lhH,np->text,value);
460
+  else
461
+  {
462
+    cmLhFree(p->lhH,np->text);
463
+    np->text = NULL;
464
+  }
465
+
466
+  return kOkTtRC;
467
+}
468
+
469
+cmTtRC_t cmTextTemplateSetValueV( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, va_list vl )
470
+{
471
+  cmTt_t*     p = _cmTtHandleToPtr(h);
472
+  cmTtNode_t* np;
473
+
474
+  // locate the requested node
475
+  if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL )
476
+    return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
477
+
478
+  return _cmTtSetValue(p,np,label,index,value);
479
+}
480
+
481
+cmTtRC_t cmTextTemplateSetValue( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, ... )
482
+{
483
+  cmTtRC_t rc;
484
+  va_list vl;
485
+  va_start(vl,index);
486
+  rc = cmTextTemplateSetValueV(h,value,label,index,vl);
487
+  va_end(vl);
488
+  return rc;
489
+}
490
+
491
+cmTtRC_t cmTextTemplateRepeatV( cmTtH_t h, const cmChar_t* label, unsigned index, va_list vl )
492
+{
493
+  cmTt_t*     p = _cmTtHandleToPtr(h);
494
+  cmTtNode_t* np;
495
+
496
+  // locate the requested node
497
+  if((np = _cmTtFindNodeV(p,label,index,vl)) == NULL )
498
+    return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(label),index);
499
+
500
+   _cmTtRepeatNode(p,np);
501
+
502
+   return kOkTtRC;
503
+}
504
+
505
+cmTtRC_t cmTextTemplateRepeat( cmTtH_t h, const cmChar_t* label, unsigned index, ... )
506
+{
507
+  cmTtRC_t rc;
508
+  va_list vl;
509
+  va_start(vl,index);
510
+  rc = cmTextTemplateRepeatV(h,label,index,vl);
511
+  va_end(vl);
512
+  return rc;
513
+}
514
+
515
+cmTtRC_t  _cmTtWriteNode( cmTt_t* p, cmTtNode_t* np, cmFileH_t fh )
516
+{
517
+  cmTtRC_t   rc  = kOkTtRC;
518
+  cmFileRC_t frc = kOkFileRC;
519
+
520
+  switch( np->typeId )
521
+  {
522
+    case kTextTtId:
523
+    case kVarTtId:
524
+      {
525
+        if( np->text != NULL )
526
+          if((frc = cmFilePrint(fh,np->text)) != kOkFileRC )
527
+            rc = cmErrMsg(&p->err,kFileFailTtRC,"File write failed on '%s'.", cmFileName(fh));
528
+      }
529
+      break;
530
+
531
+    case kSetTtId:
532
+      {
533
+        cmTtNode_t* cnp;
534
+        for(cnp=np->children; cnp!=NULL && rc==kOkTtRC; cnp=cnp->rsib)
535
+          rc = _cmTtWriteNode(p,cnp,fh);
536
+      }
537
+      break;
538
+
539
+    default:
540
+      { assert(0); }
541
+  }
542
+
543
+  return rc;
544
+}
545
+
546
+cmTtRC_t cmTextTemplateWrite( cmTtH_t h, const cmChar_t* fn )
547
+{
548
+  cmTtRC_t rc = kOkTtRC;
549
+  cmTt_t* p = _cmTtHandleToPtr(h);
550
+  cmFileH_t fh;
551
+
552
+  if( cmFileOpen(&fh,fn,kReadFileFl,p->err.rpt) != kOkFileRC )
553
+    return cmErrMsg(&p->err,kFileFailTtRC,"The file '%s' could not be opened.",cmStringNullGuard(fn));
554
+
555
+  rc = _cmTtWriteNode(p,p->tree,fh);
556
+
557
+  if( cmFileClose(&fh) != kOkFileRC )
558
+    rc = cmErrMsg(&p->err,kFileFailTtRC,"The output file '%s' failed on close.",cmStringNullGuard(fn));
559
+
560
+  return rc;      
561
+}
562
+
563
+typedef struct cmTtPath_str
564
+{
565
+  const cmChar_t*      label;
566
+  unsigned             index;
567
+  struct cmTtPath_str* next;
568
+  struct cmTtPath_str* prev;
569
+} cmTtPath_t;
570
+
571
+
572
+cmTtNode_t* _cmTtFindNode( cmTt_t* p, const cmTtPath_t* pp  )
573
+{
574
+  cmTtNode_t* np = p->tree;
575
+ 
576
+  if( pp == NULL )
577
+    return NULL;
578
+
579
+  assert( np!=NULL); // the tree should never be empty.
580
+
581
+  for(; pp!=NULL; pp=pp->next)
582
+  {
583
+    cmTtNode_t* cnp = np->children;
584
+
585
+    // locate the label for the current path level
586
+    for(; cnp!=NULL; cnp=cnp->rsib)
587
+      if( cnp->label != NULL && strcmp(cnp->label,pp->label)==0 )
588
+        break;
589
+
590
+    // the label at the current path level was not found
591
+    if( cnp==NULL )
592
+      return NULL;
593
+
594
+    unsigned i;
595
+    // locate the index at the current level - all labels
596
+    // must match the current label 
597
+    for(i=0; cnp!=NULL && i<pp->index; cnp=cnp->rsib,++i)
598
+      if( cnp->label==NULL || strcmp(cnp->label,pp->label) )
599
+      {
600
+        // a label mismatch occurred.
601
+        return NULL;
602
+      }
603
+
604
+    // the index was not found
605
+    if( cnp==NULL )
606
+      return NULL;
607
+
608
+    // cnp is the matched node at this level
609
+    np = cnp;
610
+
611
+  }
612
+
613
+  return np;
614
+}
615
+
616
+cmTtRC_t _cmTextTemplateSetValue(cmTt_t* p, const cmTtPath_t *pp, const cmChar_t* value)
617
+{
618
+  cmTtNode_t* np;
619
+
620
+  assert( pp != NULL );
621
+
622
+  if((np = _cmTtFindNode(p,pp)) == NULL )
623
+    return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index);
624
+ 
625
+  return _cmTtSetValue(p,np,pp->label,pp->index,value);
626
+}
627
+
628
+cmTtRC_t _cmTextTemplateRepeatNodeN( cmTt_t* p, const cmTtPath_t* pp, unsigned n )
629
+{
630
+  cmTtNode_t* np;
631
+  unsigned i;
632
+
633
+  // locate the requested node
634
+  if((np = _cmTtFindNode(p,pp)) == NULL )
635
+    return cmErrMsg(&p->err,kFindFailTtRC,"The template variable beginning at the path '%s' index:%i could not be found.",cmStringNullGuard(pp->label),pp->index);
636
+
637
+  for(i=0; i<n; ++i)
638
+    _cmTtRepeatNode(p,np);
639
+
640
+   return kOkTtRC;
641
+}
642
+
643
+
644
+cmTtPath_t*  _cmTtPathAppend( cmTtPath_t* list, cmTtPath_t* ele, const cmChar_t* label, unsigned index )
645
+{
646
+  cmTtPath_t* pp = list;
647
+
648
+  if( pp == NULL )
649
+    list = ele;
650
+  else
651
+  {
652
+    while( pp->next!=NULL )
653
+      pp=pp->next;
654
+    
655
+    pp->next   = ele;
656
+  }
657
+
658
+  ele->label = label;
659
+  ele->index = index;
660
+  ele->prev  = pp;
661
+  ele->next  = NULL;
662
+
663
+  return list;
664
+}
665
+
666
+cmTtRC_t  _cmTextTemplateApply( cmTt_t* p, cmJsonNode_t* jnp, cmTtPath_t* list, unsigned index )
667
+{
668
+  cmTtRC_t      rc   = kOkTtRC;
669
+  switch( jnp->typeId & kMaskTId )
670
+  {
671
+    case kPairTId:     
672
+      {
673
+        const cmChar_t*  label = cmJsonPairLabel(jnp);
674
+        cmJsonNode_t*    vjnp  = cmJsonPairValue(jnp);
675
+        cmTtPath_t       ele0;
676
+
677
+        // extend the path with the pair label
678
+        list = _cmTtPathAppend(list,&ele0,label,index);
679
+
680
+        switch( vjnp->typeId & kMaskTId )
681
+        {
682
+          case kStringTId: 
683
+            _cmTextTemplateSetValue(p,list,vjnp->u.stringVal);
684
+            break;
685
+
686
+          case kObjectTId:
687
+            {
688
+              cmJsonNode_t* mjnp = vjnp->u.childPtr;
689
+              for(; mjnp!=NULL; mjnp=mjnp->siblingPtr)
690
+                rc = _cmTextTemplateApply(p,mjnp,list,0);
691
+            }
692
+            break;
693
+
694
+          case kArrayTId:
695
+            {
696
+              unsigned n = cmJsonChildCount(vjnp);
697
+              unsigned i;
698
+
699
+              if( n > 1 )
700
+                _cmTextTemplateRepeatNodeN(p,list,n-1);
701
+
702
+              for(i=0; i<n && rc==kOkTtRC; ++i)
703
+              {
704
+                ele0.index = i;
705
+                rc = _cmTextTemplateApply(p,cmJsonArrayElement(vjnp,i),list,i);
706
+              }
707
+            }
708
+            break;
709
+
710
+          default:
711
+            { assert(0); }
712
+
713
+        }
714
+
715
+        if( ele0.prev != NULL )
716
+          ele0.prev->next = NULL;
717
+      }
718
+      break;
719
+
720
+    case kObjectTId:
721
+      {
722
+        cmJsonNode_t* mjnp = jnp->u.childPtr;
723
+        for(; mjnp!=NULL; mjnp=mjnp->siblingPtr)
724
+          rc = _cmTextTemplateApply(p,mjnp,list,0);
725
+      }
726
+      break;
727
+
728
+    default:
729
+      { assert(0); }
730
+  }
731
+  
732
+
733
+  return rc;
734
+}
735
+
736
+cmTtRC_t cmTextTemplateApply( cmTtH_t h, const cmChar_t* fn )
737
+{
738
+  cmTtRC_t rc = kOkTtRC;
343 739
   cmTt_t* p = _cmTtHandleToPtr(h);
740
+  cmJsonH_t jsH = cmJsonNullHandle;
741
+  
742
+  if( cmJsonInitializeFromFile(&jsH,fn,p->ctx) != kOkJsRC )
743
+    return cmErrMsg(&p->err,kJsonFailTtRC,"A JSON tree could not be initialized from '%s'.",cmStringNullGuard(fn));
744
+
745
+  cmJsonNode_t* jnp = cmJsonRoot(jsH);
746
+
747
+  if( jnp!=NULL)
748
+    for(jnp=jnp->u.childPtr; jnp!=NULL && rc==kOkTtRC; jnp=jnp->siblingPtr )
749
+      rc =  _cmTextTemplateApply(p,jnp,NULL,0);
750
+
751
+  cmJsonFinalize(&jsH);
752
+  return rc;
753
+}
344 754
 
345
-  cmTtToken_t* tp = p->tokens;
346
-  cmChar_t* ep = p->buf + strlen(p->buf);
347
-  for(; tp!=NULL; tp=tp->next)
755
+void _cmTtPrintNode( cmRpt_t* rpt, cmTtNode_t* np )
756
+{
757
+  switch( np->typeId )
348 758
   {
349
-    bool     fl = tp->end < ep;
350
-    cmChar_t c  =  fl ? tp->end[1] : 0;
759
+    case kTextTtId:
760
+      cmRptPrintf(rpt,"%s",np->text);
761
+      break;
762
+
763
+    case kVarTtId:
764
+      if( np->text != NULL )
765
+        cmRptPrintf(rpt,"|%s=%s|",np->label,np->text);
766
+      else
767
+        cmRptPrintf(rpt,"|%s|",np->label);
768
+      break;
769
+
770
+    case kSetTtId:
771
+      {
772
+        cmTtNode_t* cnp;
773
+        cmRptPrintf(rpt,"{");
774
+
775
+        if( np->label != NULL )
776
+          cmRptPrintf(rpt,"%s:",np->label);
351 777
 
352
-    cmRptPrintf(rpt,"%s",tp->text);
778
+        for(cnp=np->children; cnp!=NULL; cnp=cnp->rsib)
779
+          _cmTtPrintNode(rpt,cnp);
353 780
 
354
-    if( fl )
355
-      tp->end[1] = c;    
781
+        cmRptPrintf(rpt,"}");
782
+      }
783
+      break;
356 784
   }
357 785
 }
358 786
 
787
+void cmTtPrintTree( cmTtH_t h, cmRpt_t* rpt )
788
+{
789
+  cmTt_t* p = _cmTtHandleToPtr(h);
790
+  _cmTtPrintNode(rpt,p->tree);
791
+}
792
+
793
+
359 794
 
360 795
 cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn )
361 796
 {
@@ -365,7 +800,20 @@ cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn )
365 800
   if((rc = cmTextTemplateInitialize(ctx,&h,fn)) != kOkTtRC )
366 801
     return rc;
367 802
 
368
-  cmTextTemplatePrintTokens(h,&ctx->rpt);
803
+  if(0)
804
+  {
805
+    cmTextTemplateRepeat(h,"name",0,NULL);
806
+
807
+    cmTextTemplateRepeat(h,"var2",0,NULL);
808
+
809
+    cmTextTemplateSetValue(h, "val0", "var2", 0, NULL );
810
+  }
811
+  else
812
+  {
813
+    cmTextTemplateApply(h,"/home/kevin/src/cmtest/src/cmtest/data/tmpl_src.js");
814
+  }
815
+
816
+  cmTtPrintTree(h,&ctx->rpt);
369 817
 
370 818
   cmTextTemplateFinalize(&h);
371 819
 

+ 32
- 2
cmTextTemplate.h Целия файл

@@ -7,17 +7,47 @@ enum
7 7
   kOkTtRC = cmOkRC,
8 8
   kFileFailTtRC,
9 9
   kLHeapFailTtRC,
10
-  kSyntaxErrTtRC
10
+  kSyntaxErrTtRC,
11
+  kFindFailTtRC,
12
+  kInvalidTypeTtRC,
13
+  kJsonFailTtRC
11 14
 };
12 15
 
13 16
 typedef cmHandle_t cmTtH_t;
14 17
 typedef unsigned   cmTtRC_t;
15 18
 extern cmTtH_t cmTtNullHandle;
16 19
 
17
-
20
+// Initialize a template file.
18 21
 cmTtRC_t cmTextTemplateInitialize( cmCtx_t* ctx, cmTtH_t* hp, const cmChar_t* fn );
22
+
23
+// Finalize a template file
19 24
 cmTtRC_t cmTextTemplateFinalize( cmTtH_t* hp );
25
+
26
+// Return true if the template file is intialized.
20 27
 bool     cmTextTemplateIsValid( cmTtH_t h );
28
+
29
+// Set the value of a template variable.
30
+// The node identified by { label,index, label, index ... } must
31
+// be a variable node.  The function will fail if a 'set' or 'text' node
32
+// is identified.
33
+// Set 'value' to NULL to erase a previously set value.
34
+cmTtRC_t cmTextTemplateSetValue( cmTtH_t h, const cmChar_t* value, const cmChar_t* label, unsigned index, ... );
35
+
36
+// Create a copy of the sub-tree identified by the variable path
37
+// and insert it as the left sibling of the sub-tree's root.
38
+cmTtRC_t cmTextTemplateRepeat( cmTtH_t h, const cmChar_t* label, unsigned index, ... );
39
+
40
+// Write the template file.
41
+cmTtRC_t cmTextTemplateWrite( cmTtH_t h, const cmChar_t* fn );
42
+
43
+// Apply a template value JSON file to this template
44
+cmTtRC_t cmTextTemplateApply( cmTtH_t h, const cmChar_t* fn );
45
+
46
+
47
+// Print an annotated template tree.
48
+void cmTtPrintTree( cmTtH_t h, cmRpt_t* rpt );
49
+
50
+
21 51
 cmTtRC_t cmTextTemplateTest( cmCtx_t* ctx, const cmChar_t* fn );
22 52
 
23 53
 

Loading…
Отказ
Запис