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 * Simple list implementation
40 #define TListPush(l,c) do { \
41 (c)->nextCell = NULL; \
42 if ( (l)->tailList == NULL ) { \
43 (l)->headList = (l)->tailList = (c); \
45 (l)->tailList->nextCell = (c); \
46 (l)->tailList = (c); \
50 #define TListUnShift(l,c) do { \
51 (c)->nextCell = (l)->headList; \
52 if ( (l)->headList == NULL ) { \
53 (l)->headList = (l)->tailList = (c); \
55 (l)->headList = (c); \
59 #define TListShift(l,c) do { \
60 (c) = (l)->headList; \
61 if ( (c) != NULL ) { \
62 (l)->headList = (c)->nextCell; \
63 if ( (l)->headList == NULL ) \
64 (l)->tailList = NULL; \
68 #define TListIsEmpty(l) ( (l)->headList == NULL )
71 * Default operations and functions
75 isVariable(VariableValue value) {
79 if ( (value->flags & TND_DEFINED) == 0 ) {
82 switch (value->type) {
84 return (value->value.intValue == 0) ? 0 : 1;
86 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
90 return ( value->value.timeValue > 0 ) ? 1 : 0;
92 return value->value.boolValue;
94 return (value->value.doubleValue == 0) ? 0 : 1;
105 makeBoolValue(TemplateInstance tmpl, int v) {
106 VariableValue outvalue = mcalloc(tmpl->templateContext, sizeof(VariableValueData));
108 outvalue->type = valueBool;
109 outvalue->flags= TND_DEFINED;
110 outvalue->value.boolValue = (v) ? 1 : 0;
115 copyValue(TemplateInstance tmpl, VariableValue in) {
116 VariableValue out= mcalloc(tmpl->templateContext, sizeof(VariableValueData));
119 memcpy(out, in, sizeof(VariableValueData));
121 out->type = valueBool; /* something */
128 isDefinedFn(TemplateInstance tmpl, int n, VariableValue *vals) {
129 return makeBoolValue(tmpl, vals[0]->flags & TND_DEFINED );
133 strmblen(char *str) {
134 int len = strlen(str);
135 int totlen = 0, clen;
137 mblen(NULL,0); /* reset internal state */
139 clen = mblen( str, len );
149 LengthFn(TemplateInstance tmpl, int n, VariableValue *vals) {
150 VariableValue outvalue = NULL;
152 outvalue = copyValue( tmpl, NULL );
153 outvalue->type = valueInt;
155 if ( vals[0]->type == valueString && vals[0]->value.stringValue &&
156 (vals[0]->flags & TND_DEFINED) ) {
157 outvalue->flags |= TND_DEFINED;
158 outvalue->value.intValue = strmblen( vals[0]->value.stringValue );
160 outvalue->flags &= ~TND_DEFINED;
166 NotFn(TemplateInstance tmpl, int n, VariableValue *vals) {
167 return makeBoolValue(tmpl, !isVariable(vals[0]));
171 AndFn(TemplateInstance tmpl, int n, VariableValue *vals) {
172 return makeBoolValue(tmpl, isVariable(vals[0]) && isVariable(vals[1]) );
176 OrFn(TemplateInstance tmpl, int n, VariableValue *vals) {
177 return makeBoolValue(tmpl, isVariable(vals[0]) || isVariable(vals[1]) );
181 CondFn(TemplateInstance tmpl, int n, VariableValue *vals) {
182 return isVariable(vals[0]) ? vals[1] : vals[2];
186 ModFn(TemplateInstance tmpl, int n, VariableValue *vals) {
187 VariableValue outvalue = copyValue( tmpl, NULL );
189 outvalue->type = valueInt;
191 if ( (vals[0]->flags & vals[1]->flags & TND_DEFINED) &&
192 vals[0]->type == valueInt && vals[1]->type == valueInt) {
194 outvalue->flags |= TND_DEFINED;
195 outvalue->value.intValue = vals[0]->value.intValue % vals[1]->value.intValue;
197 outvalue->flags &= ~TND_DEFINED;
203 UnaryMinesFn(TemplateInstance tmpl, int n, VariableValue *vals) {
204 VariableValue outvalue = copyValue( tmpl, vals[0] );
206 if (outvalue->type == valueInt)
207 outvalue->value.intValue = -outvalue->value.intValue;
208 else if (outvalue->type == valueDouble)
209 outvalue->value.doubleValue = -outvalue->value.doubleValue;
211 outvalue->flags &= ~TND_DEFINED;
216 #define ISNUM(v) ( ((v)->type == valueDouble || (v)->type == valueInt) && ((v)->flags & TND_DEFINED) )
218 #define ARIPHACT(OP) \
219 VariableValue outvalue = copyValue( tmpl, NULL ); \
220 if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
221 outvalue->flags &= ~TND_DEFINED; \
222 } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
223 outvalue->flags |= TND_DEFINED; \
224 outvalue->type = valueDouble; \
225 if ( vals[0]->type == valueDouble ) \
226 outvalue->value.doubleValue = vals[0]->value.doubleValue; \
228 outvalue->value.doubleValue = vals[0]->value.intValue; \
229 if ( vals[1]->type == valueDouble ) \
230 outvalue->value.doubleValue OP##= vals[1]->value.doubleValue; \
232 outvalue->value.doubleValue OP##= vals[1]->value.intValue; \
234 outvalue->flags |= TND_DEFINED; \
235 outvalue->type = valueInt; \
236 outvalue->value.intValue = vals[0]->value.intValue OP vals[1]->value.intValue; \
240 PlusFn(TemplateInstance tmpl, int n, VariableValue *vals) {
246 MinesFn(TemplateInstance tmpl, int n, VariableValue *vals) {
252 MulFn(TemplateInstance tmpl, int n, VariableValue *vals) {
258 DivFn(TemplateInstance tmpl, int n, VariableValue *vals) {
264 VariableValue outvalue = copyValue( tmpl, NULL ); \
265 outvalue->type = valueBool; \
266 if ( !(ISNUM(vals[0]) && ISNUM(vals[1])) ) { \
267 outvalue->flags &= ~TND_DEFINED; \
268 } else if ( vals[0]->type == valueDouble || vals[1]->type == valueDouble ) { \
269 outvalue->flags |= TND_DEFINED; \
270 if ( vals[0]->type == valueDouble && vals[1]->type == valueDouble ) \
271 outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.doubleValue) \
273 else if ( vals[0]->type == valueDouble ) \
274 outvalue->value.boolValue = (vals[0]->value.doubleValue OP vals[1]->value.intValue) \
277 outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.doubleValue) \
280 outvalue->flags |= TND_DEFINED; \
281 outvalue->value.boolValue = (vals[0]->value.intValue OP vals[1]->value.intValue) ? 1 : 0; \
285 LtFn(TemplateInstance tmpl, int n, VariableValue *vals) {
291 LeFn(TemplateInstance tmpl, int n, VariableValue *vals) {
297 EqFn(TemplateInstance tmpl, int n, VariableValue *vals) {
303 GeFn(TemplateInstance tmpl, int n, VariableValue *vals) {
309 GtFn(TemplateInstance tmpl, int n, VariableValue *vals) {
315 NeFn(TemplateInstance tmpl, int n, VariableValue *vals) {
320 static executeFunctionDescData Functions[] = {
321 {"defined", 1, isDefinedFn},
322 {"length", 1, LengthFn},
328 {"-", 1, UnaryMinesFn},
345 * Initialize functions
348 #define MAXDEPTH (128)
350 typedef struct ParseState {
357 getFilename(ParseState *state, char *filename) {
358 int len = 1 /* \0 */ + 1 /* / */ + strlen(filename);
361 if ( *filename == '/' )
364 if ( state->basename && *state->basename )
365 len += strlen(state->basename);
367 res = mcalloc(state->tmpl->templateContext, sizeof(char) * len);
370 if ( state->basename && *state->basename ) {
371 len = strlen(state->basename);
372 memcpy( res, state->basename, len );
376 memcpy( res+len, filename, strlen(filename));
377 res[ len + strlen(filename) ] = '\0';
382 static int recursiveReadTemplate( ParseState *state, Template tmptmpl, char *filename );
385 findIncludes(ParseState *state, TemplateNode *node) {
389 tmp.templateContext = state->tmpl->templateContext;
391 if (node == NULL || *node == NULL)
394 switch((*node)->type) {
397 if ( recursiveReadTemplate(state, &tmp, (*node)->nodeData.includeFile) != 0 )
402 state->tmpl->templateInstanceSize += sizeof( LoopTemplateInstanceData );
403 if ( findIncludes(state, &( (*node)->nodeData.loop.bodyNode )) != 0 )
407 if ( findIncludes(state, &( (*node)->nodeData.condition.ifNode )) != 0 ||
408 findIncludes(state, &( (*node)->nodeData.condition.elseNode )) != 0 ||
409 findIncludes(state, &( (*node)->nodeData.condition.expressionNode )) != 0 )
413 GListForeach(cell, (*node)->nodeData.children) {
414 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
416 if ( findIncludes(state, &chld) != 0 )
419 GLCELL_DATA(cell) = chld;
423 state->tmpl->templateInstanceSize += sizeof( VariableValueData );
426 GListForeach(cell, (*node)->nodeData.expression.argsNode) {
427 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
429 if ( findIncludes(state, &chld) != 0 )
431 GLCELL_DATA(cell) = chld;
435 if ( findIncludes(state, &( (*node)->nodeData.print.expressionNode )) )
443 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", (*node)->type);
450 recursiveReadTemplate( ParseState *state, Template tmptmpl, char *filename ) {
452 char *fn = getFilename(state, filename);
454 if ( state->depth > MAXDEPTH ) {
455 tlog(TL_ALARM, "too many depth of included templates");
459 if ( tmptmpl == NULL )
460 tmptmpl = state->tmpl;
462 if ( (err=parseTemplateFile( tmptmpl, fn )) != 0 )
467 if ( (err=findIncludes(state, &(tmptmpl->tree))) != 0 )
476 qualifyVarname(Template tmpl, TemplateNode loopParentNode, char *varName, int *varNameLength) {
480 if ( ! loopParentNode )
483 len = loopParentNode->nodeData.loop.varNameLength + *varNameLength + 2;
484 tmp = mcalloc(tmpl->templateContext, len);
485 len = loopParentNode->nodeData.loop.varNameLength;
486 memcpy( tmp, loopParentNode->nodeData.loop.varName, len);
488 memcpy( tmp + len, varName, *varNameLength);
492 *varNameLength = len;
497 checkSpecialVariable(int flags, char *varName) {
498 if ( strcmp(varName, "__first") == 0 ) {
499 flags &= ~TND_GLOBAL; /* special vars cannot be global */
500 flags |= TND___FIRST;
501 } else if ( strcmp(varName, "__last") == 0 ) {
502 flags &= ~TND_GLOBAL; /* special vars cannot be global */
504 } else if ( strcmp(varName, "__counter") == 0 ) {
505 flags &= ~TND_GLOBAL; /* special vars cannot be global */
506 flags |= TND___COUNTER;
507 } else if ( strcmp(varName, "__odd") == 0 ) {
508 flags &= ~TND_GLOBAL; /* special vars cannot be global */
510 } else if ( strcmp(varName, "__even") == 0 ) {
511 flags &= ~TND_GLOBAL; /* special vars cannot be global */
513 } else if ( strcmp(varName, "__size") == 0 ) {
514 flags &= ~TND_GLOBAL; /* special vars cannot be global */
516 } else if ( strcmp(varName, "__level") == 0 ) {
517 flags &= ~TND_GLOBAL; /* special vars cannot be global */
518 flags |= TND___LEVEL;
525 findVariable( Template tmpl, TemplateNode loopParentNode, int flags, char *varName, int varNameLength ) {
528 if ( (pOffset = SFSFindData(&tmpl->variables, varName, varNameLength)) == NULL ) {
529 Offset offset = tmpl->templateInstanceSize;
530 VariableValue pdata = (VariableValue)(tmpl->templateInstance + tmpl->templateInstanceSize);
534 in.keylen = varNameLength;
537 tmpl->templateInstanceSize += sizeof(VariableValueData);
539 SFSAdd(&tmpl->variables, &in);
543 if ( loopParentNode && (flags & TND_GLOBAL) == 0 ) {
545 * copy special flags to support loopParentNode
547 pdata->flags |= flags & TND__SPECIALMASK;
548 pdata->type = valuePointer;
549 pdata->value.ptrValue = NULL;
551 loopParentNode->nodeData.loop.listVarValues =
552 GListPush( loopParentNode->nodeData.loop.listVarValues, (void*)offset );
562 addLoop(Template tmpl, TemplateNode node, TemplateNode loopParentNode) {
564 LoopTemplateInstance lti;
566 if ( SFSFindData(&tmpl->variables, node->nodeData.loop.varName, node->nodeData.loop.varNameLength) != NULL ) {
567 tlog(TL_CRIT,"Loop marked '%s' is already defined", node->nodeData.loop.varName);
571 in.key = node->nodeData.loop.varName;
572 in.keylen = node->nodeData.loop.varNameLength;
573 in.data = &tmpl->templateInstanceSize;
575 SFSAdd(&tmpl->variables, &in);
577 node->nodeData.loop.loopDataOffset = tmpl->templateInstanceSize;
578 lti = (LoopTemplateInstance)(tmpl->templateInstance + tmpl->templateInstanceSize);
579 memset(lti, 0, sizeof( LoopTemplateInstanceData ));
580 lti->type = LoopData;
581 lti->loopNode = node;
583 tmpl->templateInstanceSize += sizeof( LoopTemplateInstanceData );
585 if ( loopParentNode ) {
586 loopParentNode->nodeData.loop.childrenLoop =
587 GListPush( loopParentNode->nodeData.loop.childrenLoop, node );
589 if ( loopParentNode->nodeData.loop.selfNode )
590 loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf =
591 GListPush( loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf, node );
598 findFunction(Template tmpl, TemplateNode node) {
599 executeFunctionDesc ptr = tmpl->functions;
601 tassert(ptr != NULL);
603 while(ptr && ptr->name) {
604 if ( node->nodeData.expression.nargs < 0 || node->nodeData.expression.nargs == ptr->nargs ) {
605 if ( strcmp( node->nodeData.expression.functionName, ptr->name ) == 0 ) {
606 node->nodeData.expression.function = ptr;
613 tlog(TL_CRIT|TL_EXIT, "Can not find function named '%s' with %d arguments",
614 node->nodeData.expression.functionName,
615 node->nodeData.expression.nargs);
619 compileTree( Template tmpl, TemplateNode node, TemplateNode loopParentNode ) {
627 node->nodeData.loop.varName = qualifyVarname(tmpl, loopParentNode,
628 node->nodeData.loop.varName,
629 &node->nodeData.loop.varNameLength);
630 if ( compileTree(tmpl, node->nodeData.loop.bodyNode, node) )
633 if ( addLoop( tmpl, node, loopParentNode ) )
637 node->nodeData.nest.loop = loopParentNode;
638 if ( loopParentNode ) {
639 if ( loopParentNode->nodeData.loop.selfNode )
640 tlog(TL_WARN,"Loop '%s' has duplicated nested call", node->nodeData.loop.varName);
642 loopParentNode->nodeData.loop.selfNode = node;
644 tlog(TL_WARN,"SELF tag without loop");
647 if ( compileTree(tmpl, node->nodeData.condition.expressionNode, loopParentNode) )
649 if ( compileTree(tmpl, node->nodeData.condition.ifNode, loopParentNode) )
651 if ( compileTree(tmpl, node->nodeData.condition.elseNode, loopParentNode) )
655 GListForeach(cell, node->nodeData.children) {
656 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
658 if ( compileTree(tmpl, chld, loopParentNode) )
663 node->nodeData.variable.flags = checkSpecialVariable(
664 node->nodeData.variable.flags,
665 node->nodeData.variable.varName );
667 if ( (node->nodeData.variable.flags & TND_GLOBAL) == 0 )
668 node->nodeData.variable.varName = qualifyVarname(tmpl, loopParentNode,
669 node->nodeData.variable.varName,
670 &node->nodeData.variable.varNameLength);
672 node->nodeData.variable.varValueOffset = findVariable( tmpl, loopParentNode,
673 node->nodeData.variable.flags,
674 node->nodeData.variable.varName,
675 node->nodeData.variable.varNameLength );
678 if ( compileTree(tmpl, node->nodeData.print.expressionNode, loopParentNode) )
682 node->nodeData.expression.nargs = GLIST_LENGTH(node->nodeData.expression.argsNode);
683 findFunction(tmpl, node);
685 node->nodeData.expression.argsValue = mcalloc(tmpl->templateContext, sizeof(VariableValue) *
686 node->nodeData.expression.nargs );
688 GListForeach(cell, node->nodeData.expression.argsNode)
689 if ( compileTree(tmpl, (TemplateNode)GLCELL_DATA(cell), loopParentNode) )
693 tlog(TL_CRIT|TL_EXIT, "unexpected IncludeNode");
699 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
706 initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename ) {
712 state.basename = basedir;
714 memset(tmpl, 0, sizeof(TemplateData));
715 tmpl->templateContext = mc;
716 SFSInit_dp(&tmpl->variables, sizeof(Offset), NULL);
719 executeFunctionDesc ptr = functions;
726 tmpl->functions = mcalloc(tmpl->templateContext,
727 sizeof(executeFunctionDescData) * n + sizeof(Functions));
729 memcpy( tmpl->functions, functions, sizeof(executeFunctionDescData) * n );
730 memcpy( tmpl->functions + n, Functions, sizeof(Functions));
732 tmpl->functions = Functions;
734 if ( (err=recursiveReadTemplate(&state, NULL, filename))!=0 )
737 tmpl->templateInstance = mcalloc( tmpl->templateContext, tmpl->templateInstanceSize );
738 tmpl->templateInstanceSize = 0;
739 if ( (err=compileTree( tmpl, tmpl->tree, NULL ))!=0 )
750 freeNode( TemplateNode node ) {
756 switch (node->type) {
758 freeNode( node->nodeData.loop.bodyNode ); /* selfNode is somewhere inside bodyNode */
759 GListFree( node->nodeData.loop.childrenLoop );
760 GListFree( node->nodeData.loop.listVarValues );
763 GListForeach( cell, node->nodeData.children )
764 freeNode( (TemplateNode)GLCELL_DATA(cell) );
765 GListFree( node->nodeData.children );
768 freeNode( node->nodeData.condition.expressionNode );
769 freeNode( node->nodeData.condition.ifNode );
770 freeNode( node->nodeData.condition.elseNode );
773 freeNode( node->nodeData.print.expressionNode);
776 GListForeach(cell, node->nodeData.expression.argsNode)
777 freeNode( GLCELL_DATA(cell) );
778 GListFree( node->nodeData.expression.argsNode );
781 GListFree( node->nodeData.nest.childrenLoopAfterSelf );
793 freeTemplate( Template tmpl ) {
794 SFSFree( &tmpl->variables, NULL );
795 freeNode( tmpl->tree );
803 newTemplateInstance(Template tmpl, MemoryContext *mc) {
807 mc = tmpl->templateContext;
809 ti = mcalloc(mc, sizeof(TemplateInstanceData) + tmpl->templateInstanceSize);
811 ti->templateContext = mc;
812 memcpy( ti->instanceData, tmpl->templateInstance, tmpl->templateInstanceSize);
818 newLoopInstance( TemplateInstance tmpl, TemplateNode node ) {
819 LoopInstance upper = NULL;
820 LoopTemplateInstance loopData = (LoopTemplateInstance)
821 (tmpl->instanceData + node->nodeData.loop.loopDataOffset);
823 if ( loopData->currentInstance )
824 upper = loopData->currentInstance->upperInstance;
826 loopData->currentInstance =
827 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
828 loopData->currentInstance->upperInstance = upper;
830 TListPush( loopData, loopData->currentInstance );
832 loopData->lastRow = NULL;
836 addTemplateRow( TemplateInstance tmpl, char * key) {
839 LoopTemplateInstance loopData;
840 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
845 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
848 if ( pOffset == NULL )
849 return TVAR_NOTFOUND;
851 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
853 if ( loopData->type != LoopData )
854 return TVAR_FORBIDDEN;
855 node = loopData->loopNode;
857 tassert( *pOffset == node->nodeData.loop.loopDataOffset );
859 nvar = GLIST_LENGTH( node->nodeData.loop.listVarValues );
861 /* loop without vars can not be looped */
864 if ( TListIsEmpty(loopData) )
865 newLoopInstance(tmpl, node);
867 GListForeach( cell, node->nodeData.loop.childrenLoop )
868 newLoopInstance( tmpl, GLCELL_DATA(cell) );
870 loopData->lastRow = rowData = mcalloc( tmpl->templateContext, LRDHDRSZ + sizeof(VariableValueData) * nvar );
871 rowData->loop = node;
872 rowData->nestedInstance = NULL;
874 GListForeach( cell, node->nodeData.loop.listVarValues ) {
875 VariableValue vv = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
877 vv->value.ptrValue = rowData->varvals + i;
878 rowData->varvals[i].flags = 0;
882 loopData->currentInstance->nrow++;
883 TListPush( loopData->currentInstance, rowData );
889 addTemplateNestedLoop( TemplateInstance tmpl, char * key) {
892 LoopTemplateInstance loopData;
893 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
896 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
899 if ( pOffset == NULL )
900 return TVAR_NOTFOUND;
902 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
904 if ( loopData->type != LoopData )
905 return TVAR_FORBIDDEN;
906 node = loopData->loopNode;
908 if ( node->nodeData.loop.selfNode == NULL )
909 return TVAR_FORBIDDEN;
911 if ( TListIsEmpty(loopData) || loopData->lastRow == NULL )
914 GListForeach( cell, node->nodeData.loop.childrenLoop ) {
915 LoopTemplateInstance childData = (LoopTemplateInstance)
916 (tmpl->instanceData + ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.loopDataOffset);
918 childData->lastRow = NULL;
921 loopData->lastRow->nestedInstance =
922 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
923 loopData->lastRow->nestedInstance->upperInstance =
924 loopData->currentInstance;
925 loopData->currentInstance =
926 loopData->lastRow->nestedInstance;
927 loopData->lastRow = NULL;
933 returnTemplateNestedLoop( TemplateInstance tmpl, char * key) {
936 LoopTemplateInstance loopData;
937 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
940 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
943 if ( pOffset == NULL )
944 return TVAR_NOTFOUND;
946 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
948 if ( loopData->type != LoopData )
949 return TVAR_FORBIDDEN;
950 node = loopData->loopNode;
952 if ( node->nodeData.loop.selfNode == NULL )
953 return TVAR_FORBIDDEN;
955 if ( TListIsEmpty(loopData) )
958 if ( loopData->currentInstance == NULL )
961 GListForeach( cell, node->nodeData.loop.childrenLoop ) {
962 LoopTemplateInstance childData = (LoopTemplateInstance)
963 (tmpl->instanceData + ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.loopDataOffset);
965 childData->lastRow = NULL;
968 loopData->currentInstance = loopData->currentInstance->upperInstance;
969 loopData->lastRow = NULL;
975 static VariableValueData storage;
978 setTemplateValue( TemplateInstance tmpl, char *key) {
980 VariableValue varval;
981 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
983 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
986 if ( pOffset == NULL )
987 return TVAR_NOTFOUND;
989 varval = (VariableValue)(tmpl->instanceData + *pOffset);
991 if ( varval->type != 0 && varval->type < valueInt ) {
992 return TVAR_LOOPMARK;
993 } else if ( varval->type == valuePointer ) {
994 /* looped variable */
995 varval = varval->value.ptrValue;
997 if ( varval == NULL )
1000 tassert( (varval->flags & TND_GLOBAL) == 0 );
1003 if ( varval->flags & TND__SPECIALMASK )
1004 return TVAR_FORBIDDEN;
1006 if ( storage.flags & TND_DEFINED ) {
1007 varval->flags |= TND_DEFINED;
1008 varval->type = storage.type;
1009 varval->value = storage.value;
1011 varval->flags &= ~TND_DEFINED;
1019 setTemplateValueInt( TemplateInstance tmpl, char * key, int64_t val ) {
1020 storage.flags = TND_DEFINED;
1021 storage.type = valueInt;
1022 storage.value.intValue = val;
1023 return setTemplateValue( tmpl, key );
1027 setTemplateValueString( TemplateInstance tmpl, char * key, char * val ) {
1028 storage.flags = TND_DEFINED;
1029 storage.type = valueString;
1030 storage.value.stringValue = val;
1031 return setTemplateValue( tmpl, key );
1035 setTemplateValueTime( TemplateInstance tmpl, char * key, time_t val ) {
1036 storage.flags = TND_DEFINED;
1037 storage.type = valueTime;
1038 storage.value.timeValue = val;
1039 return setTemplateValue( tmpl, key );
1043 setTemplateValueBool( TemplateInstance tmpl, char * key, int val ) {
1044 storage.flags = TND_DEFINED;
1045 storage.type = valueBool;
1046 storage.value.boolValue = val;
1047 return setTemplateValue( tmpl, key );
1051 setTemplateValueDouble( TemplateInstance tmpl, char * key, double val ) {
1052 storage.flags = TND_DEFINED;
1053 storage.type = valueDouble;
1054 storage.value.boolValue = val;
1055 return setTemplateValue( tmpl, key );
1059 setTemplateValueUndefined( TemplateInstance tmpl, char * key ) {
1061 return setTemplateValue( tmpl, key );
1069 printVal( TemplateInstance tmpl, VariableValue value, int *len, char *format ) {
1075 if ( value->type == valueTime ) {
1077 res = mcalloc( tmpl->templateContext, printedlen+1 );
1079 while ( (printedlen = strftime(NULL, 0, (format) ? format : "%Y-%m-%d %H:%M:%S",
1080 localtime(&value->value.timeValue))) == 0 ) {
1082 res=mcrealloc(res, printedlen);
1089 switch (value->type) {
1091 printedlen = snprintf(NULL, 0, (format) ? format : "%lld", value->value.intValue);
1094 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
1096 printedlen = snprintf(NULL, 0, (format) ? format : "%s", value->value.stringValue);
1099 printedlen = snprintf(NULL, 0, "%s", (value->value.boolValue) ? "true" : "false" );
1102 printedlen = snprintf(NULL, 0, (format) ? format : "%f", value->value.doubleValue);
1110 res = mcalloc( tmpl->templateContext, printedlen+1 );
1112 switch (value->type) {
1114 printedlen = snprintf(res, printedlen+1, (format) ? format : "%lld", value->value.intValue);
1117 printedlen = snprintf(res, printedlen+1, (format) ? format : "%s", value->value.stringValue);
1120 printedlen = snprintf(res, printedlen+1, "%s", (value->value.boolValue) ? "true" : "false" );
1123 printedlen = snprintf(res, printedlen+1, (format) ? format : "%f", value->value.doubleValue);
1137 static VariableValue
1138 executeExpression( TemplateInstance tmpl, TemplateNode node ) {
1139 VariableValue outvalue = NULL;
1144 switch (node->type) {
1146 outvalue = &node->nodeData.value;
1149 outvalue = (VariableValue)(tmpl->instanceData + node->nodeData.variable.varValueOffset);
1151 tassert( (outvalue->flags & TND_DEFINED) == 0 || (outvalue->type >= valueInt && outvalue->type <= valuePointer) );
1153 if ( outvalue->type == valuePointer )
1154 outvalue = outvalue->value.ptrValue;
1156 case ExpressionNode:
1157 GListForeach(cell, node->nodeData.expression.argsNode)
1158 node->nodeData.expression.argsValue[i++] =
1159 executeExpression( tmpl, (TemplateNode)GLCELL_DATA(cell) );
1161 outvalue = node->nodeData.expression.function->execFn(tmpl,
1162 node->nodeData.expression.nargs,
1163 node->nodeData.expression.argsValue);
1169 case CollectionNode:
1172 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1175 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1179 tassert( outvalue!=NULL );
1185 printNode( TemplateInstance tmpl, TemplateNode node, LoopInstance loopInstance, int level ) {
1187 VariableValue value;
1193 switch (node->type) {
1196 LoopTemplateInstance loopData = (LoopTemplateInstance)
1197 (tmpl->instanceData + node->nodeData.loop.loopDataOffset);
1199 LoopInstance instance;
1201 if ( loopInstance ) {
1202 instance = loopInstance;
1204 TListShift( loopData, instance );
1205 if ( instance == NULL )
1209 for(i=0; i<instance->nrow;i++) {
1212 VariableValue realValue;
1214 TListShift( instance, rowData );
1216 GListForeach( cell, node->nodeData.loop.listVarValues ) {
1217 value = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
1219 tassert( value->type == valuePointer );
1220 realValue = value->value.ptrValue = rowData->varvals+j;
1222 if ( value->flags & TND___FIRST ) {
1223 realValue->type = valueInt;
1225 realValue->flags |= TND_DEFINED;
1226 realValue->value.intValue = 1;
1228 realValue->flags &= ~TND_DEFINED;
1229 realValue->value.intValue = 0;
1231 } else if ( value->flags & TND___LAST ) {
1232 realValue->type = valueInt;
1233 if ( i==instance->nrow - 1 ) {
1234 realValue->flags |= TND_DEFINED;
1235 realValue->value.intValue = 1;
1237 realValue->flags &= ~TND_DEFINED;
1238 realValue->value.intValue = 0;
1240 } else if ( value->flags & TND___COUNTER ) {
1241 realValue->type = valueInt;
1242 realValue->flags |= TND_DEFINED;
1243 realValue->value.intValue = i+1;
1244 } else if ( value->flags & TND___LEVEL ) {
1245 realValue->type = valueInt;
1246 realValue->flags |= TND_DEFINED;
1247 realValue->value.intValue = level;
1248 } else if ( value->flags & TND___SIZE ) {
1249 realValue->type = valueInt;
1250 realValue->flags |= TND_DEFINED;
1251 realValue->value.intValue = instance->nrow;
1252 } else if ( value->flags & TND___ODD ) {
1253 realValue->type = valueBool;
1254 realValue->flags |= TND_DEFINED;
1255 realValue->value.boolValue = (i%2) ? 0 : 1 ;
1256 } else if ( value->flags & TND___EVEN ) {
1257 realValue->type = valueBool;
1258 realValue->flags |= TND_DEFINED;
1259 realValue->value.boolValue = (i%2) ? 1 : 0 ;
1265 if ( node->nodeData.loop.selfNode )
1266 node->nodeData.loop.selfNode->nodeData.nest.savedRowData = rowData;
1268 printNode( tmpl, node->nodeData.loop.bodyNode, NULL, level );
1273 if ( node->nodeData.nest.loop && node->nodeData.nest.savedRowData ) {
1274 LoopRow savedRowData = node->nodeData.nest.savedRowData; /* save current row */
1275 LoopInstance *savedChildrenInstance = NULL;
1278 * Save child's instances for current loop
1280 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1281 savedChildrenInstance = mcalloc(tmpl->templateContext, sizeof(LoopInstance) *
1282 GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf));
1285 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1286 TemplateNode chld = GLCELL_DATA(cell);
1287 LoopTemplateInstance loopData = (LoopTemplateInstance)
1288 (tmpl->instanceData + chld->nodeData.loop.loopDataOffset);
1289 LoopInstance cellInstance;
1291 TListShift( loopData, cellInstance );
1293 savedChildrenInstance[i++] = cellInstance;
1297 printNode( tmpl, node->nodeData.nest.loop, savedRowData->nestedInstance, level+1 );
1300 * Restore saved datas
1303 GListForeach( cell, node->nodeData.nest.loop->nodeData.loop.listVarValues ) {
1304 value = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
1305 value->value.ptrValue = savedRowData->varvals + i;
1309 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1311 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1312 TemplateNode chld = GLCELL_DATA(cell);
1313 LoopTemplateInstance loopData = (LoopTemplateInstance)
1314 (tmpl->instanceData + chld->nodeData.loop.loopDataOffset);
1316 if ( savedChildrenInstance[i] )
1317 TListUnShift( loopData, savedChildrenInstance[i] );
1324 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1326 if ( isVariable(value) )
1327 printNode( tmpl, node->nodeData.condition.ifNode, loopInstance, level );
1329 printNode( tmpl, node->nodeData.condition.elseNode, loopInstance, level );
1331 case CollectionNode:
1332 GListForeach( cell, node->nodeData.children )
1333 printNode( tmpl, (TemplateNode)GLCELL_DATA(cell), loopInstance, level );
1336 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1338 if ( value && (value->flags & TND_DEFINED) != 0 ) {
1342 res = printVal(tmpl, value, &len, node->nodeData.print.formatValue);
1344 if ( (node->nodeData.variable.flags & TND_HTMLESCAPE) && tmpl->tmpl->htmlEscape )
1345 res = tmpl->tmpl->htmlEscape(res, &len);
1346 if ( (node->nodeData.variable.flags & TND_URLESCAPE) && tmpl->tmpl->urlEscape )
1347 res = tmpl->tmpl->urlEscape(res, &len);
1349 if ( res && len>0 ) {
1350 tmpl->tmpl->printString( res, len );
1353 } else if ( node->nodeData.print.defaultValue ) {
1354 tmpl->tmpl->printString( node->nodeData.print.defaultValue,
1355 strlen( node->nodeData.print.defaultValue ) );
1359 tmpl->tmpl->printString( node->nodeData.text.value, node->nodeData.text.valueLength );
1364 case ExpressionNode:
1365 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1368 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1374 printTemplate( TemplateInstance tmpl ) {
1375 if (!tmpl->tmpl->printString)
1378 printNode(tmpl, tmpl->tmpl->tree, NULL, 0);
1384 void printLevel(int level) {
1389 recursiveDump(Template tmpl, TemplateNode node, int level) {
1393 if (node == NULL ) {
1398 switch(node->type) {
1400 printf("IncludeNode\n");
1403 printf("LoopNode '%s'\n", node->nodeData.loop.varName);
1404 recursiveDump(tmpl, node->nodeData.loop.bodyNode, level+1);
1407 printf("ConditionNode\n");
1408 recursiveDump(tmpl, node->nodeData.condition.expressionNode, level+1);
1409 recursiveDump(tmpl, node->nodeData.condition.ifNode, level+1);
1410 recursiveDump(tmpl, node->nodeData.condition.elseNode, level+1);
1412 case CollectionNode:
1413 printf("CollectionNode\n");
1414 GListForeach(cell, node->nodeData.children)
1415 recursiveDump(tmpl, (TemplateNode)GLCELL_DATA(cell), level+1);
1418 printf("TextNode len:%d\n", node->nodeData.text.valueLength);
1421 printf("VariableNode '%s'\n", node->nodeData.variable.varName);
1423 case ExpressionNode:
1424 printf("ExpressionNode '%s'\n", node->nodeData.expression.functionName);
1425 GListForeach(cell, node->nodeData.expression.argsNode)
1426 recursiveDump( tmpl, GLCELL_DATA(cell) ,level + 1);
1429 printf("PrintNode\n");
1430 recursiveDump( tmpl, node->nodeData.print.expressionNode, level + 1 );
1433 printf("ConstNode\n");
1436 printf("NestNode\n");
1439 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
1444 dumpTemplate( Template tmpl ) {
1445 recursiveDump(tmpl, tmpl->tree, 0);