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 ); /* selfNode is somewhere inside bodyNode */
722 GListFree( node->nodeData.loop.childrenLoop );
723 GListFree( node->nodeData.loop.listVarValues );
725 GListForeach( cell, node->nodeData.loop.listInstance ) {
726 LoopInstance instance = GLCELL_DATA(cell);
728 GListFree(instance->rowValues );
730 GListFree( node->nodeData.loop.listInstance );
733 GListForeach( cell, node->nodeData.children )
734 freeNode( (TemplateNode)GLCELL_DATA(cell) );
735 GListFree( node->nodeData.children );
738 freeNode( node->nodeData.condition.expressionNode );
739 freeNode( node->nodeData.condition.ifNode );
740 freeNode( node->nodeData.condition.elseNode );
743 freeNode( node->nodeData.print.expressionNode);
746 GListForeach(cell, node->nodeData.expression.argsNode)
747 freeNode( GLCELL_DATA(cell) );
748 GListFree( node->nodeData.expression.argsNode );
751 GListFree( node->nodeData.nest.childrenLoopAfterSelf );
763 freeTemplate( Template tmpl ) {
764 SFSFree( &tmpl->variables, NULL );
765 freeNode( tmpl->tree );
773 newLoopInstance( Template tmpl, TemplateNode node ) {
774 LoopInstance upper = NULL;
776 if ( node->nodeData.loop.currentInstance )
777 upper = node->nodeData.loop.currentInstance->upperInstance;
779 node->nodeData.loop.currentInstance =
780 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
781 node->nodeData.loop.currentInstance->upperInstance = upper;
783 node->nodeData.loop.listInstance = GListPush(
784 node->nodeData.loop.listInstance,
785 node->nodeData.loop.currentInstance );
787 node->nodeData.loop.lastRow = NULL;
791 addTemplateRow( Template tmpl, char * key) {
792 TemplateNode *pnode, node;
793 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
798 pnode = SFSFindData(&tmpl->variables, lkey, 0);
802 return TVAR_NOTFOUND;
806 if ( node->type != LoopNode )
807 return TVAR_FORBIDDEN;
809 nvar = GLIST_LENGTH( node->nodeData.loop.listVarValues );
811 /* loop without vars can not be looped */
814 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
815 newLoopInstance(tmpl, node);
817 GListForeach( cell, node->nodeData.loop.childrenLoop )
818 newLoopInstance( tmpl, GLCELL_DATA(cell) );
820 node->nodeData.loop.lastRow = rowData = mcalloc( tmpl->templateContext, LRDHDRSZ + sizeof(VariableValueData) * nvar );
821 rowData->loop = node;
822 rowData->nestedInstance = NULL;
824 GListForeach( cell, node->nodeData.loop.listVarValues ) {
825 VariableValue vv = GLCELL_DATA(cell);
827 vv->value.ptrValue = rowData->varvals + i;
828 rowData->varvals[i].flags = 0;
832 node->nodeData.loop.currentInstance->nrow++;
833 node->nodeData.loop.currentInstance->rowValues =
834 GListPush( node->nodeData.loop.currentInstance->rowValues, rowData );
840 addTemplateNestedLoop( Template tmpl, char * key) {
841 TemplateNode *pnode, node;
842 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
845 pnode = SFSFindData(&tmpl->variables, lkey, 0);
849 return TVAR_NOTFOUND;
853 if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
854 return TVAR_FORBIDDEN;
856 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 || node->nodeData.loop.lastRow == NULL )
859 GListForeach( cell, node->nodeData.loop.childrenLoop )
860 ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;
862 node->nodeData.loop.lastRow->nestedInstance =
863 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
864 node->nodeData.loop.lastRow->nestedInstance->upperInstance =
865 node->nodeData.loop.currentInstance;
866 node->nodeData.loop.currentInstance =
867 node->nodeData.loop.lastRow->nestedInstance;
868 node->nodeData.loop.lastRow = NULL;
874 returnTemplateNestedLoop( Template tmpl, char * key) {
875 TemplateNode *pnode, node;
876 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
879 pnode = SFSFindData(&tmpl->variables, lkey, 0);
883 return TVAR_NOTFOUND;
887 if ( node->type != LoopNode || node->nodeData.loop.selfNode == 0 )
888 return TVAR_FORBIDDEN;
890 if ( GLIST_LENGTH(node->nodeData.loop.listInstance) == 0 )
893 if ( node->nodeData.loop.currentInstance == NULL )
896 GListForeach( cell, node->nodeData.loop.childrenLoop )
897 ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.lastRow = NULL;
899 node->nodeData.loop.currentInstance = node->nodeData.loop.currentInstance->upperInstance;
900 node->nodeData.loop.lastRow = NULL;
906 static VariableValueData storage;
909 setTemplateValue( Template tmpl, char *key) {
910 VariableValue *pvarval, varval;
911 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
913 pvarval = SFSFindData(&tmpl->variables, lkey, 0);
916 if ( pvarval == NULL )
917 return TVAR_NOTFOUND;
921 if ( varval->type != 0 && varval->type < valueInt ) {
922 return TVAR_LOOPMARK;
923 } else if ( varval->type == valuePointer ) {
924 /* looped variable */
925 varval = varval->value.ptrValue;
927 if ( varval == NULL )
930 tassert( (varval->flags & TND_GLOBAL) == 0 );
933 if ( varval->flags & TND__SPECIALMASK )
934 return TVAR_FORBIDDEN;
936 if ( storage.flags & TND_DEFINED ) {
937 varval->flags |= TND_DEFINED;
938 varval->type = storage.type;
939 varval->value = storage.value;
941 varval->flags &= ~TND_DEFINED;
949 setTemplateValueInt( Template tmpl, char * key, int val ) {
950 storage.flags = TND_DEFINED;
951 storage.type = valueInt;
952 storage.value.intValue = val;
953 return setTemplateValue( tmpl, key );
957 setTemplateValueString( Template tmpl, char * key, char * val ) {
958 storage.flags = TND_DEFINED;
959 storage.type = valueString;
960 storage.value.stringValue = val;
961 return setTemplateValue( tmpl, key );
965 setTemplateValueTime( Template tmpl, char * key, time_t val ) {
966 storage.flags = TND_DEFINED;
967 storage.type = valueTime;
968 storage.value.timeValue = val;
969 return setTemplateValue( tmpl, key );
973 setTemplateValueBool( Template tmpl, char * key, int val ) {
974 storage.flags = TND_DEFINED;
975 storage.type = valueBool;
976 storage.value.boolValue = val;
977 return setTemplateValue( tmpl, key );
981 setTemplateValueDouble( Template tmpl, char * key, double val ) {
982 storage.flags = TND_DEFINED;
983 storage.type = valueDouble;
984 storage.value.boolValue = val;
985 return setTemplateValue( tmpl, key );
989 setTemplateValueUndefined( Template tmpl, char * key ) {
991 return setTemplateValue( tmpl, key );
999 printVal( Template tmpl, VariableValue value, int *len, char *format ) {
1005 if ( value->type == valueTime ) {
1007 res = mcalloc( tmpl->templateContext, printedlen+1 );
1009 while ( (printedlen = strftime(NULL, 0, (format) ? format : "%Y-%m-%d %H:%M:%S",
1010 localtime(&value->value.timeValue))) == 0 ) {
1012 res=mcrealloc(res, printedlen);
1019 switch (value->type) {
1021 printedlen = snprintf(NULL, 0, (format) ? format : "%d", value->value.intValue);
1024 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
1026 printedlen = snprintf(NULL, 0, (format) ? format : "%s", value->value.stringValue);
1029 printedlen = snprintf(NULL, 0, "%s", (value->value.boolValue) ? "true" : "false" );
1032 printedlen = snprintf(NULL, 0, (format) ? format : "%f", value->value.doubleValue);
1040 res = mcalloc( tmpl->templateContext, printedlen+1 );
1042 switch (value->type) {
1044 printedlen = snprintf(res, printedlen+1, (format) ? format : "%d", value->value.intValue);
1047 printedlen = snprintf(res, printedlen+1, (format) ? format : "%s", value->value.stringValue);
1050 printedlen = snprintf(res, printedlen+1, "%s", (value->value.boolValue) ? "true" : "false" );
1053 printedlen = snprintf(res, printedlen+1, (format) ? format : "%f", value->value.doubleValue);
1067 static VariableValue
1068 executeExpression( Template tmpl, TemplateNode node ) {
1069 VariableValue outvalue = NULL;
1074 switch (node->type) {
1076 outvalue = &node->nodeData.value;
1079 if ( node->nodeData.variable.value->type == valuePointer )
1080 outvalue = node->nodeData.variable.value->value.ptrValue;
1082 outvalue = node->nodeData.variable.value;
1084 case ExpressionNode:
1085 GListForeach(cell, node->nodeData.expression.argsNode)
1086 node->nodeData.expression.argsValue[i++] =
1087 executeExpression( tmpl, (TemplateNode)GLCELL_DATA(cell) );
1089 outvalue = node->nodeData.expression.function->execFn(tmpl,
1090 node->nodeData.expression.nargs,
1091 node->nodeData.expression.argsValue);
1097 case CollectionNode:
1100 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1103 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1107 tassert( outvalue!=NULL );
1113 printNode( Template tmpl, TemplateNode node, LoopInstance loopInstance ) {
1115 VariableValue value;
1121 switch (node->type) {
1125 LoopInstance instance;
1127 if ( loopInstance ) {
1128 instance = loopInstance;
1130 cell = GListShift( node->nodeData.loop.listInstance );
1134 instance = GLCELL_DATA(cell);
1135 GListFreeCell( node->nodeData.loop.listInstance, cell );
1138 for(i=0; i<instance->nrow;i++) {
1141 VariableValue realValue;
1143 cell = GListShift( instance->rowValues );
1144 rowData = GLCELL_DATA(cell);
1145 GListFreeCell( instance->rowValues, cell );
1147 GListForeach( cell, node->nodeData.loop.listVarValues ) {
1148 value = (VariableValue)GLCELL_DATA(cell);
1150 tassert( value->type == valuePointer );
1151 realValue = value->value.ptrValue = rowData->varvals+j;
1153 if ( value->flags & TND___FIRST ) {
1154 realValue->type = valueInt;
1156 realValue->flags |= TND_DEFINED;
1157 realValue->value.intValue = 1;
1159 realValue->flags &= ~TND_DEFINED;
1160 realValue->value.intValue = 0;
1162 } else if ( value->flags & TND___LAST ) {
1163 realValue->type = valueInt;
1164 if ( i==instance->nrow - 1 ) {
1165 realValue->flags |= TND_DEFINED;
1166 realValue->value.intValue = 1;
1168 realValue->flags &= ~TND_DEFINED;
1169 realValue->value.intValue = 0;
1171 } else if ( value->flags & TND___COUNTER ) {
1172 realValue->type = valueInt;
1173 realValue->flags |= TND_DEFINED;
1174 realValue->value.intValue = i+1;
1175 } else if ( value->flags & TND___SIZE ) {
1176 realValue->type = valueInt;
1177 realValue->flags |= TND_DEFINED;
1178 realValue->value.intValue = instance->nrow;
1179 } else if ( value->flags & TND___ODD ) {
1180 realValue->type = valueBool;
1181 realValue->flags |= TND_DEFINED;
1182 realValue->value.boolValue = (i%2) ? 0 : 1 ;
1183 } else if ( value->flags & TND___EVEN ) {
1184 realValue->type = valueBool;
1185 realValue->flags |= TND_DEFINED;
1186 realValue->value.boolValue = (i%2) ? 1 : 0 ;
1192 if ( node->nodeData.loop.selfNode )
1193 node->nodeData.loop.selfNode->nodeData.nest.savedRowData = rowData;
1195 printNode( tmpl, node->nodeData.loop.bodyNode, NULL );
1198 GListFree( instance->rowValues );
1202 if ( node->nodeData.nest.loop && node->nodeData.nest.savedRowData ) {
1203 LoopRow savedRowData = node->nodeData.nest.savedRowData; /* save current row */
1204 LoopInstance *savedChildrenInstance = NULL;
1207 * Save child's instances for current loop
1209 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1210 savedChildrenInstance = mcalloc(tmpl->templateContext, sizeof(LoopInstance) *
1211 GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf));
1214 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1215 TemplateNode chld = GLCELL_DATA(cell);
1216 GListCell *cellInstance = GListShift( chld->nodeData.loop.listInstance );
1218 if ( cellInstance == NULL )
1219 savedChildrenInstance[i++] = NULL;
1221 savedChildrenInstance[i++] = GLCELL_DATA(cellInstance);
1222 GListFreeCell( chld->nodeData.loop.listInstance, cellInstance );
1227 printNode( tmpl, node->nodeData.nest.loop, savedRowData->nestedInstance );
1230 * Restore saved datas
1233 GListForeach( cell, node->nodeData.nest.loop->nodeData.loop.listVarValues ) {
1234 ((VariableValue)GLCELL_DATA(cell))->value.ptrValue = savedRowData->varvals + i;
1238 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1240 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1241 TemplateNode chld = GLCELL_DATA(cell);
1243 if ( savedChildrenInstance[i] )
1244 GListUnshift( chld->nodeData.loop.listInstance, savedChildrenInstance[i]);
1251 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1253 if ( isVariable(value) )
1254 printNode( tmpl, node->nodeData.condition.ifNode, loopInstance );
1256 printNode( tmpl, node->nodeData.condition.elseNode, loopInstance );
1258 case CollectionNode:
1259 GListForeach( cell, node->nodeData.children )
1260 printNode( tmpl, (TemplateNode)GLCELL_DATA(cell), loopInstance );
1263 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1265 if ( value && (value->flags & TND_DEFINED) != 0 ) {
1269 res = printVal(tmpl, value, &len, node->nodeData.print.formatValue);
1271 if ( (node->nodeData.variable.flags & TND_HTMLESCAPE) && tmpl->htmlEscape )
1272 res = tmpl->htmlEscape(res, &len);
1273 if ( (node->nodeData.variable.flags & TND_URLESCAPE) && tmpl->urlEscape )
1274 res = tmpl->urlEscape(res, &len);
1276 if ( res && len>0 ) {
1277 tmpl->printString( res, len );
1280 } else if ( node->nodeData.print.defaultValue ) {
1281 tmpl->printString( node->nodeData.print.defaultValue,
1282 strlen( node->nodeData.print.defaultValue ) );
1286 tmpl->printString( node->nodeData.text.value, node->nodeData.text.valueLength );
1291 case ExpressionNode:
1292 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1295 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1301 printTemplate( Template tmpl ) {
1302 if (!tmpl->printString)
1305 printNode(tmpl, tmpl->tree, NULL);
1311 void printLevel(int level) {
1316 recursiveDump(Template tmpl, TemplateNode node, int level) {
1320 if (node == NULL ) {
1325 switch(node->type) {
1327 printf("IncludeNode\n");
1330 printf("LoopNode '%s'\n", node->nodeData.loop.varName);
1331 recursiveDump(tmpl, node->nodeData.loop.bodyNode, level+1);
1334 printf("ConditionNode\n");
1335 recursiveDump(tmpl, node->nodeData.condition.expressionNode, level+1);
1336 recursiveDump(tmpl, node->nodeData.condition.ifNode, level+1);
1337 recursiveDump(tmpl, node->nodeData.condition.elseNode, level+1);
1339 case CollectionNode:
1340 printf("CollectionNode\n");
1341 GListForeach(cell, node->nodeData.children)
1342 recursiveDump(tmpl, (TemplateNode)GLCELL_DATA(cell), level+1);
1345 printf("TextNode len:%d\n", node->nodeData.text.valueLength);
1348 printf("VariableNode '%s'\n", node->nodeData.variable.varName);
1350 case ExpressionNode:
1351 printf("ExpressionNode '%s'\n", node->nodeData.expression.functionName);
1352 GListForeach(cell, node->nodeData.expression.argsNode)
1353 recursiveDump( tmpl, GLCELL_DATA(cell) ,level + 1);
1356 printf("PrintNode\n");
1357 recursiveDump( tmpl, node->nodeData.print.expressionNode, level + 1 );
1360 printf("ConstNode\n");
1363 printf("NestNode\n");
1366 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
1371 dumpTemplate( Template tmpl ) {
1372 recursiveDump(tmpl, tmpl->tree, 0);