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 */
395 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", (*node)->type);
402 recursiveReadTemplate( ParseState *state, Template tmptmpl, char *filename ) {
404 char *fn = getFilename(state, filename);
406 if ( state->depth > MAXDEPTH ) {
407 tlog(TL_ALARM, "too many depth of included templates");
411 if ( tmptmpl == NULL )
412 tmptmpl = state->tmpl;
414 if ( (err=parseTemplateFile( tmptmpl, fn )) != 0 )
419 if ( (err=findIncludes(state, &(tmptmpl->tree))) != 0 )
428 qualifyVarname(Template tmpl, TemplateNode loopParentNode, char *varName, int *varNameLength) {
432 if ( ! loopParentNode )
435 len = loopParentNode->nodeData.loop.varNameLength + *varNameLength + 2;
436 tmp = mcalloc(tmpl->templateContext, len);
437 len = loopParentNode->nodeData.loop.varNameLength;
438 memcpy( tmp, loopParentNode->nodeData.loop.varName, len);
440 memcpy( tmp + len, varName, *varNameLength);
444 *varNameLength = len;
449 checkSpecialVariable(int flags, char *varName) {
450 if ( strcmp(varName, "__first") == 0 ) {
451 flags &= ~TND_GLOBAL; /* special vars cannot be global */
452 flags |= TND___FIRST;
453 } else if ( strcmp(varName, "__last") == 0 ) {
454 flags &= ~TND_GLOBAL; /* special vars cannot be global */
456 } else if ( strcmp(varName, "__counter") == 0 ) {
457 flags &= ~TND_GLOBAL; /* special vars cannot be global */
458 flags |= TND___COUNTER;
459 } else if ( strcmp(varName, "__odd") == 0 ) {
460 flags &= ~TND_GLOBAL; /* special vars cannot be global */
462 } else if ( strcmp(varName, "__even") == 0 ) {
463 flags &= ~TND_GLOBAL; /* special vars cannot be global */
465 } else if ( strcmp(varName, "__size") == 0 ) {
466 flags &= ~TND_GLOBAL; /* special vars cannot be global */
474 findVariable( Template tmpl, TemplateNode loopParentNode, int flags, char *varName, int varNameLength ) {
475 VariableValue *pvarval;
477 if ( (pvarval = SFSFindData(&tmpl->variables, varName, varNameLength)) == NULL ) {
478 VariableValue pdata = mc0alloc(tmpl->templateContext, sizeof(VariableValueData));
482 in.keylen = varNameLength;
485 SFSAdd(&tmpl->variables, &in);
487 if ( loopParentNode && (flags & TND_GLOBAL) == 0 ) {
489 * copy special flags to support new inform loopParentNode
491 pdata->flags |= flags & TND__SPECIALMASK;
492 pdata->type = valuePointer;
494 loopParentNode->nodeData.loop.listVarValues =
495 GListPush( loopParentNode->nodeData.loop.listVarValues, pdata );
505 addLoop(Template tmpl, TemplateNode node, TemplateNode loopParentNode) {
508 if ( SFSFindData(&tmpl->variables, node->nodeData.loop.varName, node->nodeData.loop.varNameLength) != NULL ) {
509 tlog(TL_CRIT,"Loop marked '%s' is already defined", node->nodeData.loop.varName);
513 in.key = node->nodeData.loop.varName;
514 in.keylen = node->nodeData.loop.varNameLength;
517 SFSAdd(&tmpl->variables, &in);
519 if ( loopParentNode ) {
520 loopParentNode->nodeData.loop.childrenLoop =
521 GListPush( loopParentNode->nodeData.loop.childrenLoop, node );
523 if ( loopParentNode->nodeData.loop.selfNode )
524 loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf =
525 GListPush( loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf, 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 node->nodeData.nest.loop = loopParentNode;
572 if ( loopParentNode ) {
573 if ( loopParentNode->nodeData.loop.selfNode )
574 tlog(TL_WARN,"Loop '%s' has duplicated nested call", node->nodeData.loop.varName);
576 loopParentNode->nodeData.loop.selfNode = node;
578 tlog(TL_WARN,"SELF tag without loop");
581 if ( compileTree(tmpl, node->nodeData.condition.expressionNode, loopParentNode) )
583 if ( compileTree(tmpl, node->nodeData.condition.ifNode, loopParentNode) )
585 if ( compileTree(tmpl, node->nodeData.condition.elseNode, loopParentNode) )
589 GListForeach(cell, node->nodeData.children) {
590 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
592 if ( compileTree(tmpl, chld, loopParentNode) )
597 node->nodeData.variable.flags = checkSpecialVariable(
598 node->nodeData.variable.flags,
599 node->nodeData.variable.varName );
601 if ( (node->nodeData.variable.flags & TND_GLOBAL) == 0 )
602 node->nodeData.variable.varName = qualifyVarname(tmpl, loopParentNode,
603 node->nodeData.variable.varName,
604 &node->nodeData.variable.varNameLength);
606 node->nodeData.variable.value = findVariable( tmpl, loopParentNode,
607 node->nodeData.variable.flags,
608 node->nodeData.variable.varName,
609 node->nodeData.variable.varNameLength );
612 if ( compileTree(tmpl, node->nodeData.print.expressionNode, loopParentNode) )
616 node->nodeData.expression.nargs = GLIST_LENGTH(node->nodeData.expression.argsNode);
617 findFunction(tmpl, node);
619 node->nodeData.expression.argsValue = mcalloc(tmpl->templateContext, sizeof(VariableValue) *
620 node->nodeData.expression.nargs );
622 GListForeach(cell, node->nodeData.expression.argsNode)
623 if ( compileTree(tmpl, (TemplateNode)GLCELL_DATA(cell), loopParentNode) )
627 tlog(TL_CRIT|TL_EXIT, "unexpected IncludeNode");
633 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
640 initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename ) {
646 state.basename = basedir;
648 memset(tmpl, 0, sizeof(TemplateData));
649 tmpl->templateContext = mc;
650 SFSInit_dp(&tmpl->variables, sizeof(void*), NULL);
653 executeFunctionDesc ptr = functions;
660 tmpl->functions = mcalloc(tmpl->templateContext,
661 sizeof(executeFunctionDescData) * n + sizeof(Functions));
663 memcpy( tmpl->functions, functions, sizeof(executeFunctionDescData) * n );
664 memcpy( tmpl->functions + n, Functions, sizeof(Functions));
666 tmpl->functions = Functions;
668 if ( (err=recursiveReadTemplate(&state, NULL, filename))!=0 )
670 if ( (err=compileTree( tmpl, tmpl->tree, NULL ))!=0 )
681 resetTemplate( Template tmpl ) {
685 SFSIteratorStart( &tmpl->variables );
687 while( SFSIterate( &tmpl->variables, &out ) ) {
688 VariableValue varval = *(VariableValue*) out.data;
690 if ( varval->type >= valueInt )
691 varval->flags &= ~TND_DEFINED;
692 else if ( varval->type == LoopNode ) {
693 TemplateNode node = (TemplateNode) varval;
695 GListForeach( cell, node->nodeData.loop.listVarValues ) {
696 varval = (VariableValue) GLCELL_DATA(cell);
698 if ( varval->type == valuePointer )
699 varval->value.ptrValue = NULL;
702 GListForeach( cell, node->nodeData.loop.listInstance ) {
703 LoopInstance instance = GLCELL_DATA(cell);
705 GListFree(instance->rowValues );
707 GListTruncate( node->nodeData.loop.listInstance, 0 );
713 freeNode( TemplateNode node ) {
719 switch (node->type) {
721 freeNode( node->nodeData.loop.bodyNode );
722 freeNode( node->nodeData.loop.selfNode );
723 GListFree( node->nodeData.loop.childrenLoop );
724 GListFree( node->nodeData.loop.listVarValues );
726 GListForeach( cell, node->nodeData.loop.listInstance ) {
727 LoopInstance instance = GLCELL_DATA(cell);
729 GListFree(instance->rowValues );
731 GListFree( node->nodeData.loop.listInstance );
734 GListForeach( cell, node->nodeData.children )
735 freeNode( (TemplateNode)GLCELL_DATA(cell) );
736 GListFree( node->nodeData.children );
739 freeNode( node->nodeData.condition.expressionNode );
740 freeNode( node->nodeData.condition.ifNode );
741 freeNode( node->nodeData.condition.elseNode );
744 freeNode( node->nodeData.print.expressionNode);
747 GListForeach(cell, node->nodeData.expression.argsNode)
748 freeNode( GLCELL_DATA(cell) );
749 GListFree( node->nodeData.expression.argsNode );
752 GListFree( node->nodeData.nest.childrenLoopAfterSelf );
764 freeTemplate( Template tmpl ) {
765 SFSFree( &tmpl->variables, NULL );
766 freeNode( tmpl->tree );
774 newLoopInstance( Template tmpl, TemplateNode node ) {
775 LoopInstance upper = NULL;
777 if ( node->nodeData.loop.currentInstance )
778 upper = node->nodeData.loop.currentInstance->upperInstance;
780 node->nodeData.loop.currentInstance =
781 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
782 node->nodeData.loop.currentInstance->upperInstance = upper;
784 node->nodeData.loop.listInstance = GListPush(
785 node->nodeData.loop.listInstance,
786 node->nodeData.loop.currentInstance );
788 node->nodeData.loop.lastRow = NULL;
792 addTemplateRow( Template tmpl, char * key) {
793 TemplateNode *pnode, node;
794 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
799 pnode = SFSFindData(&tmpl->variables, lkey, 0);
803 return TVAR_NOTFOUND;
807 if ( node->type != LoopNode )
808 return TVAR_FORBIDDEN;
810 nvar = GLIST_LENGTH( node->nodeData.loop.listVarValues );
812 /* loop without vars can not be looped */
815 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
816 newLoopInstance(tmpl, node);
818 GListForeach( cell, node->nodeData.loop.childrenLoop )
819 newLoopInstance( tmpl, GLCELL_DATA(cell) );
821 node->nodeData.loop.lastRow = rowData = mcalloc( tmpl->templateContext, LRDHDRSZ + sizeof(VariableValueData) * nvar );
822 rowData->loop = node;
823 rowData->nestedInstance = NULL;
825 GListForeach( cell, node->nodeData.loop.listVarValues ) {
826 VariableValue vv = GLCELL_DATA(cell);
828 vv->value.ptrValue = rowData->varvals + i;
829 rowData->varvals[i].flags = 0;
833 node->nodeData.loop.currentInstance->nrow++;
834 node->nodeData.loop.currentInstance->rowValues =
835 GListPush( node->nodeData.loop.currentInstance->rowValues, rowData );
841 addTemplateNestedLoop( Template tmpl, char * key) {
842 TemplateNode *pnode, node;
843 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
846 pnode = SFSFindData(&tmpl->variables, lkey, 0);
850 return TVAR_NOTFOUND;
854 if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
855 return TVAR_FORBIDDEN;
857 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 || node->nodeData.loop.lastRow == NULL )
860 GListForeach( cell, node->nodeData.loop.childrenLoop )
861 ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;
863 node->nodeData.loop.lastRow->nestedInstance =
864 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
865 node->nodeData.loop.lastRow->nestedInstance->upperInstance =
866 node->nodeData.loop.currentInstance;
867 node->nodeData.loop.currentInstance =
868 node->nodeData.loop.lastRow->nestedInstance;
869 node->nodeData.loop.lastRow = NULL;
875 returnTemplateNestedLoop( Template tmpl, char * key) {
876 TemplateNode *pnode, node;
877 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
880 pnode = SFSFindData(&tmpl->variables, lkey, 0);
884 return TVAR_NOTFOUND;
888 if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
889 return TVAR_FORBIDDEN;
891 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
894 if ( node->nodeData.loop.currentInstance == NULL )
897 GListForeach( cell, node->nodeData.loop.childrenLoop )
898 ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;
900 node->nodeData.loop.currentInstance = node->nodeData.loop.currentInstance->upperInstance;
901 node->nodeData.loop.lastRow = NULL;
907 static VariableValueData storage;
910 setTemplateValue( Template tmpl, char *key) {
911 VariableValue *pvarval, varval;
912 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
914 pvarval = SFSFindData(&tmpl->variables, lkey, 0);
917 if ( pvarval == NULL )
918 return TVAR_NOTFOUND;
922 if ( varval->type != 0 && varval->type < valueInt ) {
923 return TVAR_LOOPMARK;
924 } else if ( varval->type == valuePointer ) {
925 /* looped variable */
926 varval = varval->value.ptrValue;
928 if ( varval == NULL )
931 tassert( (varval->flags & TND_GLOBAL) == 0 );
934 if ( varval->flags & TND__SPECIALMASK )
935 return TVAR_FORBIDDEN;
937 if ( storage.flags & TND_DEFINED ) {
938 varval->flags |= TND_DEFINED;
939 varval->type = storage.type;
940 varval->value = storage.value;
942 varval->flags &= ~TND_DEFINED;
950 setTemplateValueInt( Template tmpl, char * key, int val ) {
951 storage.flags = TND_DEFINED;
952 storage.type = valueInt;
953 storage.value.intValue = val;
954 return setTemplateValue( tmpl, key );
958 setTemplateValueString( Template tmpl, char * key, char * val ) {
959 storage.flags = TND_DEFINED;
960 storage.type = valueString;
961 storage.value.stringValue = val;
962 return setTemplateValue( tmpl, key );
966 setTemplateValueTime( Template tmpl, char * key, time_t val ) {
967 storage.flags = TND_DEFINED;
968 storage.type = valueTime;
969 storage.value.timeValue = val;
970 return setTemplateValue( tmpl, key );
974 setTemplateValueBool( Template tmpl, char * key, int val ) {
975 storage.flags = TND_DEFINED;
976 storage.type = valueBool;
977 storage.value.boolValue = val;
978 return setTemplateValue( tmpl, key );
982 setTemplateValueDouble( Template tmpl, char * key, double val ) {
983 storage.flags = TND_DEFINED;
984 storage.type = valueDouble;
985 storage.value.boolValue = val;
986 return setTemplateValue( tmpl, key );
990 setTemplateValueUndefined( Template tmpl, char * key ) {
992 return setTemplateValue( tmpl, key );
1000 printVal( Template tmpl, VariableValue value, int *len, char *format ) {
1006 if ( value->type == valueTime ) {
1008 res = mcalloc( tmpl->templateContext, printedlen+1 );
1010 while ( (printedlen = strftime(NULL, 0, (format) ? format : "%Y-%m-%d %H:%M:%S",
1011 localtime(&value->value.timeValue))) == 0 ) {
1013 res=mcrealloc(res, printedlen);
1020 switch (value->type) {
1022 printedlen = snprintf(NULL, 0, (format) ? format : "%d", value->value.intValue);
1025 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
1027 printedlen = snprintf(NULL, 0, (format) ? format : "%s", value->value.stringValue);
1030 printedlen = snprintf(NULL, 0, "%s", (value->value.boolValue) ? "true" : "false" );
1033 printedlen = snprintf(NULL, 0, (format) ? format : "%f", value->value.doubleValue);
1041 res = mcalloc( tmpl->templateContext, printedlen+1 );
1043 switch (value->type) {
1045 printedlen = snprintf(res, printedlen+1, (format) ? format : "%d", value->value.intValue);
1048 printedlen = snprintf(res, printedlen+1, (format) ? format : "%s", value->value.stringValue);
1051 printedlen = snprintf(res, printedlen+1, "%s", (value->value.boolValue) ? "true" : "false" );
1054 printedlen = snprintf(res, printedlen+1, (format) ? format : "%f", value->value.doubleValue);
1068 static VariableValue
1069 executeExpression( Template tmpl, TemplateNode node ) {
1070 VariableValue outvalue = NULL;
1075 switch (node->type) {
1077 outvalue = &node->nodeData.value;
1080 if ( node->nodeData.variable.value->type == valuePointer )
1081 outvalue = node->nodeData.variable.value->value.ptrValue;
1083 outvalue = node->nodeData.variable.value;
1085 case ExpressionNode:
1086 GListForeach(cell, node->nodeData.expression.argsNode)
1087 node->nodeData.expression.argsValue[i++] =
1088 executeExpression( tmpl, (TemplateNode)GLCELL_DATA(cell) );
1090 outvalue = node->nodeData.expression.function->execFn(tmpl,
1091 node->nodeData.expression.nargs,
1092 node->nodeData.expression.argsValue);
1098 case CollectionNode:
1101 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1104 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1108 tassert( outvalue!=NULL );
1114 printNode( Template tmpl, TemplateNode node, LoopInstance loopInstance ) {
1116 VariableValue value;
1122 switch (node->type) {
1126 LoopInstance instance;
1128 if ( loopInstance ) {
1129 instance = loopInstance;
1131 cell = GListShift( node->nodeData.loop.listInstance );
1135 instance = GLCELL_DATA(cell);
1136 GListFreeCell( node->nodeData.loop.listInstance, cell );
1139 for(i=0; i<instance->nrow;i++) {
1142 VariableValue realValue;
1144 cell = GListShift( instance->rowValues );
1145 rowData = GLCELL_DATA(cell);
1146 GListFreeCell( instance->rowValues, cell );
1148 GListForeach( cell, node->nodeData.loop.listVarValues ) {
1149 value = (VariableValue)GLCELL_DATA(cell);
1151 tassert( value->type == valuePointer );
1152 realValue = value->value.ptrValue = rowData->varvals+j;
1154 if ( value->flags & TND___FIRST ) {
1155 realValue->type = valueInt;
1157 realValue->flags |= TND_DEFINED;
1158 realValue->value.intValue = 1;
1160 realValue->flags &= ~TND_DEFINED;
1161 realValue->value.intValue = 0;
1163 } else if ( value->flags & TND___LAST ) {
1164 realValue->type = valueInt;
1165 if ( i==instance->nrow - 1 ) {
1166 realValue->flags |= TND_DEFINED;
1167 realValue->value.intValue = 1;
1169 realValue->flags &= ~TND_DEFINED;
1170 realValue->value.intValue = 0;
1172 } else if ( value->flags & TND___COUNTER ) {
1173 realValue->type = valueInt;
1174 realValue->flags |= TND_DEFINED;
1175 realValue->value.intValue = i+1;
1176 } else if ( value->flags & TND___SIZE ) {
1177 realValue->type = valueInt;
1178 realValue->flags |= TND_DEFINED;
1179 realValue->value.intValue = instance->nrow;
1180 } else if ( value->flags & TND___ODD ) {
1181 realValue->type = valueBool;
1182 realValue->flags |= TND_DEFINED;
1183 realValue->value.boolValue = (i%2) ? 0 : 1 ;
1184 } else if ( value->flags & TND___EVEN ) {
1185 realValue->type = valueBool;
1186 realValue->flags |= TND_DEFINED;
1187 realValue->value.boolValue = (i%2) ? 1 : 0 ;
1193 if ( node->nodeData.loop.selfNode )
1194 node->nodeData.loop.selfNode->nodeData.nest.savedRowData = rowData;
1196 printNode( tmpl, node->nodeData.loop.bodyNode, NULL );
1199 GListFree( instance->rowValues );
1203 if ( node->nodeData.nest.loop && node->nodeData.nest.savedRowData ) {
1204 LoopRow savedRowData = node->nodeData.nest.savedRowData; /* save current row */
1205 LoopInstance *savedChildrenInstance = NULL;
1208 * Save child's instances for current loop
1210 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1211 savedChildrenInstance = mcalloc(tmpl->templateContext, sizeof(LoopInstance) *
1212 GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf));
1215 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1216 TemplateNode chld = GLCELL_DATA(cell);
1217 GListCell *cellInstance = GListShift( chld->nodeData.loop.listInstance );
1219 if ( cellInstance == NULL )
1220 savedChildrenInstance[i++] = NULL;
1222 savedChildrenInstance[i++] = GLCELL_DATA(cellInstance);
1223 GListFreeCell( chld->nodeData.loop.listInstance, cellInstance );
1228 printNode( tmpl, node->nodeData.nest.loop, savedRowData->nestedInstance );
1231 * Restore saved datas
1234 GListForeach( cell, node->nodeData.nest.loop->nodeData.loop.listVarValues ) {
1235 ((VariableValue)GLCELL_DATA(cell))->value.ptrValue = savedRowData->varvals + i;
1239 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1241 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1242 TemplateNode chld = GLCELL_DATA(cell);
1244 if ( savedChildrenInstance[i] )
1245 GListUnshift( chld->nodeData.loop.listInstance, savedChildrenInstance[i]);
1252 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1254 if ( isVariable(value) )
1255 printNode( tmpl, node->nodeData.condition.ifNode, loopInstance );
1257 printNode( tmpl, node->nodeData.condition.elseNode, loopInstance );
1259 case CollectionNode:
1260 GListForeach( cell, node->nodeData.children )
1261 printNode( tmpl, (TemplateNode)GLCELL_DATA(cell), loopInstance );
1264 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1266 if ( value && (value->flags & TND_DEFINED) != 0 ) {
1270 res = printVal(tmpl, value, &len, node->nodeData.print.formatValue);
1272 if ( (node->nodeData.variable.flags & TND_HTMLESCAPE) && tmpl->htmlEscape )
1273 res = tmpl->htmlEscape(res, &len);
1274 if ( (node->nodeData.variable.flags & TND_URLESCAPE) && tmpl->urlEscape )
1275 res = tmpl->urlEscape(res, &len);
1277 if ( res && len>0 ) {
1278 tmpl->printString( res, len );
1281 } else if ( node->nodeData.print.defaultValue ) {
1282 tmpl->printString( node->nodeData.print.defaultValue,
1283 strlen( node->nodeData.print.defaultValue ) );
1287 tmpl->printString( node->nodeData.text.value, node->nodeData.text.valueLength );
1292 case ExpressionNode:
1293 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1296 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1302 printTemplate( Template tmpl ) {
1303 if (!tmpl->printString)
1306 printNode(tmpl, tmpl->tree, NULL);
1312 void printLevel(int level) {
1317 recursiveDump(Template tmpl, TemplateNode node, int level) {
1321 if (node == NULL ) {
1326 switch(node->type) {
1328 printf("IncludeNode\n");
1331 printf("LoopNode '%s'\n", node->nodeData.loop.varName);
1332 recursiveDump(tmpl, node->nodeData.loop.bodyNode, level+1);
1335 printf("ConditionNode\n");
1336 recursiveDump(tmpl, node->nodeData.condition.expressionNode, level+1);
1337 recursiveDump(tmpl, node->nodeData.condition.ifNode, level+1);
1338 recursiveDump(tmpl, node->nodeData.condition.elseNode, level+1);
1340 case CollectionNode:
1341 printf("CollectionNode\n");
1342 GListForeach(cell, node->nodeData.children)
1343 recursiveDump(tmpl, (TemplateNode)GLCELL_DATA(cell), level+1);
1346 printf("TextNode len:%d\n", node->nodeData.text.valueLength);
1349 printf("VariableNode '%s'\n", node->nodeData.variable.varName);
1351 case ExpressionNode:
1352 printf("ExpressionNode '%s'\n", node->nodeData.expression.functionName);
1353 GListForeach(cell, node->nodeData.expression.argsNode)
1354 recursiveDump( tmpl, GLCELL_DATA(cell) ,level + 1);
1357 printf("PrintNode\n");
1358 recursiveDump( tmpl, node->nodeData.print.expressionNode, level + 1 );
1361 printf("ConstNode\n");
1364 printf("NestNode\n");
1367 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
1372 dumpTemplate( Template tmpl ) {
1373 recursiveDump(tmpl, tmpl->tree, 0);