2 * cOpyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
38 * Default operations and functions
42 isVariable(VariableValue value) {
46 if ( (value->flags & TND_DEFINED) == 0 ) {
49 switch (value->type) {
51 return value->value.intValue;
53 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
57 return ( value->value.timeValue > 0 ) ? 1 : 0;
59 return value->value.boolValue;
61 return (value->value.doubleValue == 0) ? 0 : 1;
72 makeBoolValue(Template tmpl, int v) {
73 VariableValue outvalue = mcalloc(tmpl->templateContext, sizeof(VariableValueData));
75 outvalue->type = valueBool;
76 outvalue->flags= TND_DEFINED;
77 outvalue->value.boolValue = (v) ? 1 : 0;
82 copyValue(Template tmpl, VariableValue in) {
83 VariableValue out= mcalloc(tmpl->templateContext, sizeof(VariableValueData));
86 memcpy(out, in, sizeof(VariableValueData));
88 out->type = valueBool; /* something */
95 isDefinedFn(Template tmpl, int n, VariableValue *vals) {
96 return makeBoolValue(tmpl, vals[0]->flags & TND_DEFINED );
100 strmblen(char *str) {
101 int len = strlen(str);
102 int totlen = 0, clen;
104 mblen(NULL,0); /* reset internal state */
106 clen = mblen( str, len );
116 LengthFn(Template tmpl, int n, VariableValue *vals) {
117 VariableValue outvalue = NULL;
119 outvalue = copyValue( tmpl, NULL );
120 outvalue->type = valueInt;
122 if ( vals[0]->type == valueString && vals[0]->value.stringValue &&
123 (vals[0]->flags & TND_DEFINED) ) {
124 outvalue->flags |= TND_DEFINED;
125 outvalue->value.intValue = strmblen( vals[0]->value.stringValue );
127 outvalue->flags &= ~TND_DEFINED;
133 NotFn(Template tmpl, int n, VariableValue *vals) {
134 return makeBoolValue(tmpl, !isVariable(vals[0]));
138 AndFn(Template tmpl, int n, VariableValue *vals) {
139 return makeBoolValue(tmpl, isVariable(vals[0]) && isVariable(vals[1]) );
143 OrFn(Template tmpl, int n, VariableValue *vals) {
144 return makeBoolValue(tmpl, isVariable(vals[0]) || isVariable(vals[1]) );
148 CondFn(Template tmpl, int n, VariableValue *vals) {
149 return isVariable(vals[0]) ? vals[1] : vals[2];
153 ModFn(Template tmpl, int n, VariableValue *vals) {
154 VariableValue outvalue = copyValue( tmpl, NULL );
156 outvalue->type = valueInt;
158 if ( (vals[0]->flags & vals[1]->flags & TND_DEFINED) &&
159 vals[0]->type == valueInt && vals[1]->type == valueInt) {
161 outvalue->flags |= TND_DEFINED;
162 outvalue->value.intValue = vals[0]->value.intValue % vals[1]->value.intValue;
164 outvalue->flags &= ~TND_DEFINED;
170 UnaryMinesFn(Template tmpl, int n, VariableValue *vals) {
171 VariableValue outvalue = copyValue( tmpl, vals[0] );
173 if (outvalue->type == valueInt)
174 outvalue->value.intValue = -outvalue->value.intValue;
175 else if (outvalue->type == valueDouble)
176 outvalue->value.doubleValue = -outvalue->value.doubleValue;
178 outvalue->flags &= ~TND_DEFINED;
183 #define ISNUM(v) ( ((v)->type == valueDouble || (v)->type == valueInt) && ((v)->flags & TND_DEFINED) )
185 #define ARIPHACT(OP) \
186 VariableValue outvalue = copyValue( tmpl, NULL ); \
187 if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
188 outvalue->flags &= ~TND_DEFINED; \
189 } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
190 outvalue->flags |= TND_DEFINED; \
191 outvalue->type = valueDouble; \
192 if ( vals[0]->type == valueDouble ) \
193 outvalue->value.doubleValue = vals[0]->value.doubleValue; \
195 outvalue->value.doubleValue = vals[0]->value.intValue; \
196 if ( vals[1]->type == valueDouble ) \
197 outvalue->value.doubleValue OP##= vals[1]->value.doubleValue; \
199 outvalue->value.doubleValue OP##= vals[1]->value.intValue; \
201 outvalue->flags |= TND_DEFINED; \
202 outvalue->type = valueInt; \
203 outvalue->value.intValue = vals[0]->value.intValue OP vals[1]->value.intValue; \
207 PlusFn(Template tmpl, int n, VariableValue *vals) {
213 MinesFn(Template tmpl, int n, VariableValue *vals) {
219 MulFn(Template tmpl, int n, VariableValue *vals) {
225 DivFn(Template tmpl, int n, VariableValue *vals) {
231 VariableValue outvalue = copyValue( tmpl, NULL ); \
232 outvalue->type = valueBool; \
233 if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
234 outvalue->flags &= ~TND_DEFINED; \
235 } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
236 outvalue->flags |= TND_DEFINED; \
237 if ( vals[0]->type == valueDouble && vals[1]->type == valueDouble ) \
238 outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.doubleValue) \
240 else if ( vals[0]->type == valueDouble ) \
241 outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.intValue) \
244 outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.doubleValue) \
247 outvalue->flags |= TND_DEFINED; \
248 outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.intValue) ? 1 : 0; \
252 LtFn(Template tmpl, int n, VariableValue *vals) {
258 LeFn(Template tmpl, int n, VariableValue *vals) {
264 EqFn(Template tmpl, int n, VariableValue *vals) {
270 GeFn(Template tmpl, int n, VariableValue *vals) {
276 GtFn(Template tmpl, int n, VariableValue *vals) {
282 NeFn(Template tmpl, int n, VariableValue *vals) {
287 static executeFunctionDescData Functions[] = {
288 {"defined", 1, isDefinedFn},
289 {"length", 1, LengthFn},
295 {"-", 1, UnaryMinesFn},
312 * Initialize functions
315 #define MAXDEPTH (128)
317 typedef struct ParseState {
324 getFilename(ParseState *state, char *filename) {
325 int len = 1 /* \0 */ + 1 /* / */ + strlen(filename);
328 if ( *filename == '/' )
331 if ( state->basename && *state->basename )
332 len += strlen(state->basename);
334 res = mcalloc(state->tmpl->templateContext, sizeof(char) * len);
337 if ( state->basename && *state->basename ) {
338 len = strlen(state->basename);
339 memcpy( res, state->basename, len );
343 memcpy( res+len, filename, strlen(filename));
344 res[ len + strlen(filename) ] = '\0';
349 static int recursiveReadTemplate( ParseState *state, Template tmptmpl, char *filename );
352 findIncludes(ParseState *state, TemplateNode *node) {
356 tmp.templateContext = state->tmpl->templateContext;
358 if (node == NULL || *node == NULL)
361 switch((*node)->type) {
364 if ( recursiveReadTemplate(state, &tmp, (*node)->nodeData.includeFile) != 0 )
369 if ( findIncludes(state, &( (*node)->nodeData.loop.bodyNode )) != 0 )
373 if ( findIncludes(state, &( (*node)->nodeData.condition.ifNode )) != 0 ||
374 findIncludes(state, &( (*node)->nodeData.condition.elseNode )) != 0 )
378 GListForeach(cell, (*node)->nodeData.children) {
379 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
381 if ( findIncludes(state, &chld) != 0 )
384 GLCELL_DATA(cell) = chld;
387 case ExpressionNode: /* any expression node can not include files */
394 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", (*node)->type);
401 recursiveReadTemplate( ParseState *state, Template tmptmpl, char *filename ) {
403 char *fn = getFilename(state, filename);
405 if ( state->depth > MAXDEPTH ) {
406 tlog(TL_ALARM, "too many depth of included templates");
410 if ( tmptmpl == NULL )
411 tmptmpl = state->tmpl;
413 if ( (err=parseTemplateFile( tmptmpl, fn )) != 0 )
418 if ( (err=findIncludes(state, &(tmptmpl->tree))) != 0 )
427 qualifyVarname(Template tmpl, TemplateNode loopParentNode, char *varName, int *varNameLength) {
431 if ( ! loopParentNode )
434 len = loopParentNode->nodeData.loop.varNameLength + *varNameLength + 2;
435 tmp = mcalloc(tmpl->templateContext, len);
436 len = loopParentNode->nodeData.loop.varNameLength;
437 memcpy( tmp, loopParentNode->nodeData.loop.varName, len);
439 memcpy( tmp + len, varName, *varNameLength);
443 *varNameLength = len;
448 checkSpecialVariable(int flags, char *varName) {
449 if ( strcmp(varName, "__first") == 0 ) {
450 flags &= ~TND_GLOBAL; /* special vars cannot be global */
451 flags |= TND___FIRST;
452 } else if ( strcmp(varName, "__last") == 0 ) {
453 flags &= ~TND_GLOBAL; /* special vars cannot be global */
455 } else if ( strcmp(varName, "__counter") == 0 ) {
456 flags &= ~TND_GLOBAL; /* special vars cannot be global */
457 flags |= TND___COUNTER;
458 } else if ( strcmp(varName, "__odd") == 0 ) {
459 flags &= ~TND_GLOBAL; /* special vars cannot be global */
461 } else if ( strcmp(varName, "__even") == 0 ) {
462 flags &= ~TND_GLOBAL; /* special vars cannot be global */
464 } else if ( strcmp(varName, "__size") == 0 ) {
465 flags &= ~TND_GLOBAL; /* special vars cannot be global */
473 findVariable( Template tmpl, TemplateNode loopParentNode, int flags, char *varName, int varNameLength ) {
474 VariableValue *pvarval;
476 if ( (pvarval = SFSFindData(&tmpl->variables, varName, varNameLength)) == NULL ) {
477 VariableValue pdata = mc0alloc(tmpl->templateContext, sizeof(VariableValueData));
481 in.keylen = varNameLength;
484 SFSAdd(&tmpl->variables, &in);
486 if ( loopParentNode && (flags & TND_GLOBAL) == 0 ) {
488 * copy special flags to support new inform loopParentNode
490 pdata->flags |= flags & TND__SPECIALMASK;
492 if ( flags & ( TND___FIRST | TND___LAST | TND___ODD | TND___EVEN ) )
493 pdata->type = valueBool;
494 else if ( flags & (TND___COUNTER | TND___SIZE) )
495 pdata->type = valueInt;
497 pdata->type = valuePointer;
499 loopParentNode->nodeData.loop.listVarValues =
500 GListPush( loopParentNode->nodeData.loop.listVarValues, pdata );
510 addLoop(Template tmpl, TemplateNode node, TemplateNode loopParentNode) {
513 if ( SFSFindData(&tmpl->variables, node->nodeData.loop.varName, node->nodeData.loop.varNameLength) != NULL ) {
514 tlog(TL_CRIT,"Loop marked '%s' is already defined", node->nodeData.loop.varName);
518 in.key = node->nodeData.loop.varName;
519 in.keylen = node->nodeData.loop.varNameLength;
522 SFSAdd(&tmpl->variables, &in);
524 if ( loopParentNode )
525 loopParentNode->nodeData.loop.childrenLoop =
526 GListPush( loopParentNode->nodeData.loop.childrenLoop, node );
532 findFunction(Template tmpl, TemplateNode node) {
533 executeFunctionDesc ptr = tmpl->functions;
535 tassert(ptr != NULL);
537 while(ptr && ptr->name) {
538 if ( node->nodeData.expression.nargs < 0 || node->nodeData.expression.nargs == ptr->nargs ) {
539 if ( strcmp( node->nodeData.expression.functionName, ptr->name ) == 0 ) {
540 node->nodeData.expression.function = ptr;
547 tlog(TL_CRIT|TL_EXIT, "Can not find function named '%s' with %d arguments",
548 node->nodeData.expression.functionName,
549 node->nodeData.expression.nargs);
553 compileTree( Template tmpl, TemplateNode node, TemplateNode loopParentNode ) {
561 node->nodeData.loop.varName = qualifyVarname(tmpl, loopParentNode,
562 node->nodeData.loop.varName,
563 &node->nodeData.loop.varNameLength);
564 if ( compileTree(tmpl, node->nodeData.loop.bodyNode, node) )
567 if ( addLoop( tmpl, node, loopParentNode ) )
571 if ( compileTree(tmpl, node->nodeData.condition.expressionNode, loopParentNode) )
573 if ( compileTree(tmpl, node->nodeData.condition.ifNode, loopParentNode) )
575 if ( compileTree(tmpl, node->nodeData.condition.elseNode, loopParentNode) )
579 GListForeach(cell, node->nodeData.children) {
580 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
582 if ( compileTree(tmpl, chld, loopParentNode) )
587 node->nodeData.variable.flags = checkSpecialVariable(
588 node->nodeData.variable.flags,
589 node->nodeData.variable.varName );
591 if ( (node->nodeData.variable.flags & TND_GLOBAL) == 0 )
592 node->nodeData.variable.varName = qualifyVarname(tmpl, loopParentNode,
593 node->nodeData.variable.varName,
594 &node->nodeData.variable.varNameLength);
596 node->nodeData.variable.value = findVariable( tmpl, loopParentNode,
597 node->nodeData.variable.flags,
598 node->nodeData.variable.varName,
599 node->nodeData.variable.varNameLength );
602 if ( compileTree(tmpl, node->nodeData.print.expressionNode, loopParentNode) )
606 node->nodeData.expression.nargs = GLIST_LENGTH(node->nodeData.expression.argsNode);
607 findFunction(tmpl, node);
609 node->nodeData.expression.argsValue = mcalloc(tmpl->templateContext, sizeof(VariableValue) *
610 node->nodeData.expression.nargs );
612 GListForeach(cell, node->nodeData.expression.argsNode)
613 if ( compileTree(tmpl, (TemplateNode)GLCELL_DATA(cell), loopParentNode) )
617 tlog(TL_CRIT|TL_EXIT, "unexpected IncludeNode");
623 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
630 initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename ) {
636 state.basename = basedir;
638 memset(tmpl, 0, sizeof(TemplateData));
639 tmpl->templateContext = mc;
640 SFSInit_dp(&tmpl->variables, sizeof(void*), NULL);
643 executeFunctionDesc ptr = functions;
650 tmpl->functions = mcalloc(tmpl->templateContext,
651 sizeof(executeFunctionDescData) * n + sizeof(Functions));
653 memcpy( tmpl->functions, functions, sizeof(executeFunctionDescData) * n );
654 memcpy( tmpl->functions + n, Functions, sizeof(Functions));
656 tmpl->functions = Functions;
658 if ( (err=recursiveReadTemplate(&state, NULL, filename))!=0 )
660 if ( (err=compileTree( tmpl, tmpl->tree, NULL ))!=0 )
671 resetTemplate( Template tmpl ) {
675 SFSIteratorStart( &tmpl->variables );
677 while( SFSIterate( &tmpl->variables, &out ) ) {
678 VariableValue varval = *(VariableValue*) out.data;
680 if ( varval->type >= valueInt )
681 varval->flags &= ~TND_DEFINED;
682 else if ( varval->type == LoopNode ) {
683 TemplateNode node = (TemplateNode) varval;
685 GListForeach( cell, node->nodeData.loop.listVarValues ) {
686 varval = (VariableValue) GLCELL_DATA(cell);
688 if ( varval->type == valuePointer )
689 varval->value.ptrValue = NULL;
692 GListForeach( cell, node->nodeData.loop.listInstance ) {
693 LoopInstance instance = GLCELL_DATA(cell);
695 GListFree(instance->rowValues );
697 GListTruncate( node->nodeData.loop.listInstance, 0 );
703 freeNode( TemplateNode node ) {
709 switch (node->type) {
711 freeNode( node->nodeData.loop.bodyNode );
712 GListFree( node->nodeData.loop.childrenLoop );
713 GListFree( node->nodeData.loop.listVarValues );
715 GListForeach( cell, node->nodeData.loop.listInstance ) {
716 LoopInstance instance = GLCELL_DATA(cell);
718 GListFree(instance->rowValues );
720 GListFree( node->nodeData.loop.listInstance );
723 GListForeach( cell, node->nodeData.children )
724 freeNode( (TemplateNode)GLCELL_DATA(cell) );
725 GListFree( node->nodeData.children );
728 freeNode( node->nodeData.condition.expressionNode );
729 freeNode( node->nodeData.condition.ifNode );
730 freeNode( node->nodeData.condition.elseNode );
733 freeNode( node->nodeData.print.expressionNode);
736 GListForeach(cell, node->nodeData.expression.argsNode)
737 freeNode( GLCELL_DATA(cell) );
738 GListFree( node->nodeData.expression.argsNode );
750 freeTemplate( Template tmpl ) {
751 SFSFree( &tmpl->variables, NULL );
752 freeNode( tmpl->tree );
760 newLoopInstance( Template tmpl, TemplateNode node ) {
761 node->nodeData.loop.listInstance = GListPush(
762 node->nodeData.loop.listInstance,
763 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) ) );
767 addTemplateRow( Template tmpl, char * key ) {
768 TemplateNode *pnode, node;
769 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
771 VariableValue varvals;
773 LoopInstance instance;
775 pnode = SFSFindData(&tmpl->variables, lkey, 0);
779 return TVAR_NOTFOUND;
783 if ( node->type != LoopNode )
784 return TVAR_FORBIDDEN;
786 nvar = GLIST_LENGTH( node->nodeData.loop.listVarValues );
788 /* loop without vars can not be looped */
791 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
792 newLoopInstance(tmpl, node);
794 GListForeach( cell, node->nodeData.loop.childrenLoop )
795 newLoopInstance( tmpl, GLCELL_DATA(cell) );
797 varvals = mcalloc( tmpl->templateContext, sizeof(VariableValueData) * nvar );
798 GListForeach( cell, node->nodeData.loop.listVarValues ) {
799 VariableValue vv = GLCELL_DATA(cell);
801 vv->value.ptrValue = varvals + i;
802 varvals[i].flags = 0;
806 instance = GLCELL_DATA(GLIST_TAIL(node->nodeData.loop.listInstance));
809 instance->rowValues = GListPush( instance->rowValues, varvals );
814 static VariableValueData storage;
817 setTemplateValue( Template tmpl, char *key) {
818 VariableValue *pvarval, varval;
819 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
821 pvarval = SFSFindData(&tmpl->variables, lkey, 0);
824 if ( pvarval == NULL )
825 return TVAR_NOTFOUND;
829 if ( varval->type != 0 && varval->type < valueInt ) {
830 return TVAR_LOOPMARK;
831 } else if ( varval->type == valuePointer ) {
832 /* looped variable */
833 varval = varval->value.ptrValue;
835 if ( varval == NULL )
838 tassert( (varval->type & TND_GLOBAL) == 0 );
841 if ( varval->flags & TND__SPECIALMASK )
842 return TVAR_FORBIDDEN;
844 if ( storage.flags & TND_DEFINED ) {
845 varval->flags |= TND_DEFINED;
846 varval->type = storage.type;
847 varval->value = storage.value;
849 varval->flags &= ~TND_DEFINED;
857 setTemplateValueInt( Template tmpl, char * key, int val ) {
858 storage.flags = TND_DEFINED;
859 storage.type = valueInt;
860 storage.value.intValue = val;
861 return setTemplateValue( tmpl, key );
865 setTemplateValueString( Template tmpl, char * key, char * val ) {
866 storage.flags = TND_DEFINED;
867 storage.type = valueString;
868 storage.value.stringValue = val;
869 return setTemplateValue( tmpl, key );
873 setTemplateValueTime( Template tmpl, char * key, time_t val ) {
874 storage.flags = TND_DEFINED;
875 storage.type = valueTime;
876 storage.value.timeValue = val;
877 return setTemplateValue( tmpl, key );
881 setTemplateValueBool( Template tmpl, char * key, int val ) {
882 storage.flags = TND_DEFINED;
883 storage.type = valueBool;
884 storage.value.boolValue = val;
885 return setTemplateValue( tmpl, key );
889 setTemplateValueDouble( Template tmpl, char * key, double val ) {
890 storage.flags = TND_DEFINED;
891 storage.type = valueDouble;
892 storage.value.boolValue = val;
893 return setTemplateValue( tmpl, key );
897 setTemplateValueUndefined( Template tmpl, char * key ) {
899 return setTemplateValue( tmpl, key );
907 printVal( Template tmpl, VariableValue value, int *len, char *format ) {
913 if ( value->type == valueTime ) {
915 res = mcalloc( tmpl->templateContext, printedlen+1 );
917 while ( (printedlen = strftime(NULL, 0, (format) ? format : "%Y-%m-%d %H:%M:%S",
918 localtime(&value->value.timeValue))) == 0 ) {
920 res=mcrealloc(res, printedlen);
927 switch (value->type) {
929 printedlen = snprintf(NULL, 0, (format) ? format : "%d", value->value.intValue);
932 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
934 printedlen = snprintf(NULL, 0, (format) ? format : "%s", value->value.stringValue);
937 printedlen = snprintf(NULL, 0, "%s", (value->value.boolValue) ? "true" : "false" );
940 printedlen = snprintf(NULL, 0, (format) ? format : "%f", value->value.doubleValue);
948 res = mcalloc( tmpl->templateContext, printedlen+1 );
950 switch (value->type) {
952 printedlen = snprintf(res, printedlen+1, (format) ? format : "%d", value->value.intValue);
955 printedlen = snprintf(res, printedlen+1, (format) ? format : "%s", value->value.stringValue);
958 printedlen = snprintf(res, printedlen+1, "%s", (value->value.boolValue) ? "true" : "false" );
961 printedlen = snprintf(res, printedlen+1, (format) ? format : "%f", value->value.doubleValue);
976 executeExpression( Template tmpl, TemplateNode node ) {
977 VariableValue outvalue = NULL;
982 switch (node->type) {
984 outvalue = &node->nodeData.value;
987 if ( node->nodeData.variable.value->type == valuePointer )
988 outvalue = node->nodeData.variable.value->value.ptrValue;
990 outvalue = node->nodeData.variable.value;
993 GListForeach(cell, node->nodeData.expression.argsNode)
994 node->nodeData.expression.argsValue[i++] =
995 executeExpression( tmpl, (TemplateNode)GLCELL_DATA(cell) );
997 outvalue = node->nodeData.expression.function->execFn(tmpl,
998 node->nodeData.expression.nargs,
999 node->nodeData.expression.argsValue);
1005 case CollectionNode:
1007 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1010 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1014 tassert( outvalue!=NULL );
1020 printNode( Template tmpl, TemplateNode node ) {
1022 VariableValue value;
1027 switch (node->type) {
1030 GListCell *cell = GListShift( node->nodeData.loop.listInstance );
1031 LoopInstance instance;
1037 instance = GLCELL_DATA(cell);
1038 GListFreeCell( node->nodeData.loop.listInstance, cell );
1040 for(i=0; i<instance->nrow;i++) {
1041 VariableValue varvals;
1044 cell = GListShift( instance->rowValues );
1045 varvals = GLCELL_DATA(cell);
1046 GListFreeCell( instance->rowValues, cell );
1048 GListForeach( cell, node->nodeData.loop.listVarValues ) {
1049 value = (VariableValue)GLCELL_DATA(cell);
1051 if ( value->flags & TND___FIRST ) {
1053 value->flags |= TND_DEFINED;
1054 value->value.intValue = 1;
1056 value->flags &= ~TND_DEFINED;
1057 value->value.intValue = 0;
1059 } else if ( value->flags & TND___LAST ) {
1060 if ( i==instance->nrow - 1 ) {
1061 value->flags |= TND_DEFINED;
1062 value->value.intValue = 1;
1064 value->flags &= ~TND_DEFINED;
1065 value->value.intValue = 0;
1067 } else if ( value->flags & TND___COUNTER ) {
1068 value->flags |= TND_DEFINED;
1069 value->value.intValue = i+1;
1070 } else if ( value->flags & TND___SIZE ) {
1071 value->flags |= TND_DEFINED;
1072 value->value.intValue = instance->nrow;
1073 } else if ( value->flags & TND___ODD ) {
1074 value->flags |= TND_DEFINED;
1075 value->value.boolValue = (i%2) ? 0 : 1 ;
1076 } else if ( value->flags & TND___EVEN ) {
1077 value->flags |= TND_DEFINED;
1078 value->value.boolValue = (i%2) ? 1 : 0 ;
1080 tassert( value->type == valuePointer );
1081 value->value.ptrValue = varvals+j;
1086 printNode( tmpl, node->nodeData.loop.bodyNode );
1091 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1093 if ( isVariable(value) )
1094 printNode( tmpl, node->nodeData.condition.ifNode );
1096 printNode( tmpl, node->nodeData.condition.elseNode );
1098 case CollectionNode:
1099 GListForeach( cell, node->nodeData.children )
1100 printNode( tmpl, (TemplateNode)GLCELL_DATA(cell) );
1103 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1105 if ( value && (value->flags & TND_DEFINED) != 0 ) {
1109 res = printVal(tmpl, value, &len, node->nodeData.print.formatValue);
1111 if ( (node->nodeData.variable.flags & TND_HTMLESCAPE) && tmpl->htmlEscape )
1112 res = tmpl->htmlEscape(res, &len);
1113 if ( (node->nodeData.variable.flags & TND_URLESCAPE) && tmpl->urlEscape )
1114 res = tmpl->urlEscape(res, &len);
1116 if ( res && len>0 ) {
1117 tmpl->printString( res, len );
1120 } else if ( node->nodeData.print.defaultValue ) {
1121 tmpl->printString( node->nodeData.print.defaultValue,
1122 strlen( node->nodeData.print.defaultValue ) );
1126 tmpl->printString( node->nodeData.text.value, node->nodeData.text.valueLength );
1131 case ExpressionNode:
1132 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1135 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1141 printTemplate( Template tmpl ) {
1142 if (!tmpl->printString)
1145 printNode(tmpl, tmpl->tree);
1151 void printLevel(int level) {
1156 recursiveDump(Template tmpl, TemplateNode node, int level) {
1160 if (node == NULL ) {
1165 switch(node->type) {
1167 printf("IncludeNode\n");
1170 printf("LoopNode '%s'\n", node->nodeData.loop.varName);
1171 recursiveDump(tmpl, node->nodeData.loop.bodyNode, level+1);
1174 printf("ConditionNode\n");
1175 recursiveDump(tmpl, node->nodeData.condition.expressionNode, level+1);
1176 recursiveDump(tmpl, node->nodeData.condition.ifNode, level+1);
1177 recursiveDump(tmpl, node->nodeData.condition.elseNode, level+1);
1179 case CollectionNode:
1180 printf("CollectionNode\n");
1181 GListForeach(cell, node->nodeData.children)
1182 recursiveDump(tmpl, (TemplateNode)GLCELL_DATA(cell), level+1);
1185 printf("TextNode len:%d\n", node->nodeData.text.valueLength);
1188 printf("VariableNode '%s'\n", node->nodeData.variable.varName);
1190 case ExpressionNode:
1191 printf("ExpressionNode '%s'\n", node->nodeData.expression.functionName);
1192 GListForeach(cell, node->nodeData.expression.argsNode)
1193 recursiveDump( tmpl, GLCELL_DATA(cell) ,level + 1);
1196 printf("PrintNode\n");
1197 recursiveDump( tmpl, node->nodeData.print.expressionNode, level + 1 );
1200 printf("ConstNode\n");
1203 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
1208 dumpTemplate( Template tmpl ) {
1209 recursiveDump(tmpl, tmpl->tree, 0);