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;
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 */
522 findVariable( Template tmpl, TemplateNode loopParentNode, int flags, char *varName, int varNameLength ) {
525 if ( (pOffset = SFSFindData(&tmpl->variables, varName, varNameLength)) == NULL ) {
526 Offset offset = tmpl->templateInstanceSize;
527 VariableValue pdata = (VariableValue)(tmpl->templateInstance + tmpl->templateInstanceSize);
531 in.keylen = varNameLength;
534 tmpl->templateInstanceSize += sizeof(VariableValueData);
536 SFSAdd(&tmpl->variables, &in);
540 if ( loopParentNode && (flags & TND_GLOBAL) == 0 ) {
542 * copy special flags to support loopParentNode
544 pdata->flags |= flags & TND__SPECIALMASK;
545 pdata->type = valuePointer;
546 pdata->value.ptrValue = NULL;
548 loopParentNode->nodeData.loop.listVarValues =
549 GListPush( loopParentNode->nodeData.loop.listVarValues, (void*)offset );
559 addLoop(Template tmpl, TemplateNode node, TemplateNode loopParentNode) {
561 LoopTemplateInstance lti;
563 if ( SFSFindData(&tmpl->variables, node->nodeData.loop.varName, node->nodeData.loop.varNameLength) != NULL ) {
564 tlog(TL_CRIT,"Loop marked '%s' is already defined", node->nodeData.loop.varName);
568 in.key = node->nodeData.loop.varName;
569 in.keylen = node->nodeData.loop.varNameLength;
570 in.data = &tmpl->templateInstanceSize;
572 SFSAdd(&tmpl->variables, &in);
574 node->nodeData.loop.loopDataOffset = tmpl->templateInstanceSize;
575 lti = (LoopTemplateInstance)(tmpl->templateInstance + tmpl->templateInstanceSize);
576 memset(lti, 0, sizeof( LoopTemplateInstanceData ));
577 lti->type = LoopData;
578 lti->loopNode = node;
580 tmpl->templateInstanceSize += sizeof( LoopTemplateInstanceData );
582 if ( loopParentNode ) {
583 loopParentNode->nodeData.loop.childrenLoop =
584 GListPush( loopParentNode->nodeData.loop.childrenLoop, node );
586 if ( loopParentNode->nodeData.loop.selfNode )
587 loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf =
588 GListPush( loopParentNode->nodeData.loop.selfNode->nodeData.nest.childrenLoopAfterSelf, node );
595 findFunction(Template tmpl, TemplateNode node) {
596 executeFunctionDesc ptr = tmpl->functions;
598 tassert(ptr != NULL);
600 while(ptr && ptr->name) {
601 if ( node->nodeData.expression.nargs < 0 || node->nodeData.expression.nargs == ptr->nargs ) {
602 if ( strcmp( node->nodeData.expression.functionName, ptr->name ) == 0 ) {
603 node->nodeData.expression.function = ptr;
610 tlog(TL_CRIT|TL_EXIT, "Can not find function named '%s' with %d arguments",
611 node->nodeData.expression.functionName,
612 node->nodeData.expression.nargs);
616 compileTree( Template tmpl, TemplateNode node, TemplateNode loopParentNode ) {
624 node->nodeData.loop.varName = qualifyVarname(tmpl, loopParentNode,
625 node->nodeData.loop.varName,
626 &node->nodeData.loop.varNameLength);
627 if ( compileTree(tmpl, node->nodeData.loop.bodyNode, node) )
630 if ( addLoop( tmpl, node, loopParentNode ) )
634 node->nodeData.nest.loop = loopParentNode;
635 if ( loopParentNode ) {
636 if ( loopParentNode->nodeData.loop.selfNode )
637 tlog(TL_WARN,"Loop '%s' has duplicated nested call", node->nodeData.loop.varName);
639 loopParentNode->nodeData.loop.selfNode = node;
641 tlog(TL_WARN,"SELF tag without loop");
644 if ( compileTree(tmpl, node->nodeData.condition.expressionNode, loopParentNode) )
646 if ( compileTree(tmpl, node->nodeData.condition.ifNode, loopParentNode) )
648 if ( compileTree(tmpl, node->nodeData.condition.elseNode, loopParentNode) )
652 GListForeach(cell, node->nodeData.children) {
653 TemplateNode chld = (TemplateNode)GLCELL_DATA(cell);
655 if ( compileTree(tmpl, chld, loopParentNode) )
660 node->nodeData.variable.flags = checkSpecialVariable(
661 node->nodeData.variable.flags,
662 node->nodeData.variable.varName );
664 if ( (node->nodeData.variable.flags & TND_GLOBAL) == 0 )
665 node->nodeData.variable.varName = qualifyVarname(tmpl, loopParentNode,
666 node->nodeData.variable.varName,
667 &node->nodeData.variable.varNameLength);
669 node->nodeData.variable.varValueOffset = findVariable( tmpl, loopParentNode,
670 node->nodeData.variable.flags,
671 node->nodeData.variable.varName,
672 node->nodeData.variable.varNameLength );
675 if ( compileTree(tmpl, node->nodeData.print.expressionNode, loopParentNode) )
679 node->nodeData.expression.nargs = GLIST_LENGTH(node->nodeData.expression.argsNode);
680 findFunction(tmpl, node);
682 node->nodeData.expression.argsValue = mcalloc(tmpl->templateContext, sizeof(VariableValue) *
683 node->nodeData.expression.nargs );
685 GListForeach(cell, node->nodeData.expression.argsNode)
686 if ( compileTree(tmpl, (TemplateNode)GLCELL_DATA(cell), loopParentNode) )
690 tlog(TL_CRIT|TL_EXIT, "unexpected IncludeNode");
696 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
703 initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename ) {
709 state.basename = basedir;
711 memset(tmpl, 0, sizeof(TemplateData));
712 tmpl->templateContext = mc;
713 SFSInit_dp(&tmpl->variables, sizeof(Offset), NULL);
716 executeFunctionDesc ptr = functions;
723 tmpl->functions = mcalloc(tmpl->templateContext,
724 sizeof(executeFunctionDescData) * n + sizeof(Functions));
726 memcpy( tmpl->functions, functions, sizeof(executeFunctionDescData) * n );
727 memcpy( tmpl->functions + n, Functions, sizeof(Functions));
729 tmpl->functions = Functions;
731 if ( (err=recursiveReadTemplate(&state, NULL, filename))!=0 )
734 tmpl->templateInstance = mcalloc( tmpl->templateContext, tmpl->templateInstanceSize );
735 tmpl->templateInstanceSize = 0;
736 if ( (err=compileTree( tmpl, tmpl->tree, NULL ))!=0 )
747 freeNode( TemplateNode node ) {
753 switch (node->type) {
755 freeNode( node->nodeData.loop.bodyNode ); /* selfNode is somewhere inside bodyNode */
756 GListFree( node->nodeData.loop.childrenLoop );
757 GListFree( node->nodeData.loop.listVarValues );
760 GListForeach( cell, node->nodeData.children )
761 freeNode( (TemplateNode)GLCELL_DATA(cell) );
762 GListFree( node->nodeData.children );
765 freeNode( node->nodeData.condition.expressionNode );
766 freeNode( node->nodeData.condition.ifNode );
767 freeNode( node->nodeData.condition.elseNode );
770 freeNode( node->nodeData.print.expressionNode);
773 GListForeach(cell, node->nodeData.expression.argsNode)
774 freeNode( GLCELL_DATA(cell) );
775 GListFree( node->nodeData.expression.argsNode );
778 GListFree( node->nodeData.nest.childrenLoopAfterSelf );
790 freeTemplate( Template tmpl ) {
791 SFSFree( &tmpl->variables, NULL );
792 freeNode( tmpl->tree );
800 newTemplateInstance(Template tmpl, MemoryContext *mc) {
804 mc = tmpl->templateContext;
806 ti = mcalloc(mc, sizeof(TemplateInstanceData) + tmpl->templateInstanceSize);
808 ti->templateContext = mc;
809 memcpy( ti->instanceData, tmpl->templateInstance, tmpl->templateInstanceSize);
815 newLoopInstance( TemplateInstance tmpl, TemplateNode node ) {
816 LoopInstance upper = NULL;
817 LoopTemplateInstance loopData = (LoopTemplateInstance)
818 (tmpl->instanceData + node->nodeData.loop.loopDataOffset);
820 if ( loopData->currentInstance )
821 upper = loopData->currentInstance->upperInstance;
823 loopData->currentInstance =
824 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
825 loopData->currentInstance->upperInstance = upper;
827 TListPush( loopData, loopData->currentInstance );
829 loopData->lastRow = NULL;
833 addTemplateRow( TemplateInstance tmpl, char * key) {
836 LoopTemplateInstance loopData;
837 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
842 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
845 if ( pOffset == NULL )
846 return TVAR_NOTFOUND;
848 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
850 if ( loopData->type != LoopData )
851 return TVAR_FORBIDDEN;
852 node = loopData->loopNode;
854 tassert( *pOffset == node->nodeData.loop.loopDataOffset );
856 nvar = GLIST_LENGTH( node->nodeData.loop.listVarValues );
858 /* loop without vars can not be looped */
861 if ( TListIsEmpty(loopData) )
862 newLoopInstance(tmpl, node);
864 GListForeach( cell, node->nodeData.loop.childrenLoop )
865 newLoopInstance( tmpl, GLCELL_DATA(cell) );
867 loopData->lastRow = rowData = mcalloc( tmpl->templateContext, LRDHDRSZ + sizeof(VariableValueData) * nvar );
868 rowData->loop = node;
869 rowData->nestedInstance = NULL;
871 GListForeach( cell, node->nodeData.loop.listVarValues ) {
872 VariableValue vv = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
874 vv->value.ptrValue = rowData->varvals + i;
875 rowData->varvals[i].flags = 0;
879 loopData->currentInstance->nrow++;
880 TListPush( loopData->currentInstance, rowData );
886 addTemplateNestedLoop( TemplateInstance tmpl, char * key) {
889 LoopTemplateInstance loopData;
890 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
893 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
896 if ( pOffset == NULL )
897 return TVAR_NOTFOUND;
899 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
901 if ( loopData->type != LoopData )
902 return TVAR_FORBIDDEN;
903 node = loopData->loopNode;
905 if ( node->nodeData.loop.selfNode == NULL )
906 return TVAR_FORBIDDEN;
908 if ( TListIsEmpty(loopData) || loopData->lastRow == NULL )
911 GListForeach( cell, node->nodeData.loop.childrenLoop ) {
912 LoopTemplateInstance childData = (LoopTemplateInstance)
913 (tmpl->instanceData + ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.loopDataOffset);
915 childData->lastRow = NULL;
918 loopData->lastRow->nestedInstance =
919 mc0alloc(tmpl->templateContext, sizeof(LoopInstanceData) );
920 loopData->lastRow->nestedInstance->upperInstance =
921 loopData->currentInstance;
922 loopData->currentInstance =
923 loopData->lastRow->nestedInstance;
924 loopData->lastRow = NULL;
930 returnTemplateNestedLoop( TemplateInstance tmpl, char * key) {
933 LoopTemplateInstance loopData;
934 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
937 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
940 if ( pOffset == NULL )
941 return TVAR_NOTFOUND;
943 loopData = (LoopTemplateInstance)(tmpl->instanceData + *pOffset);
945 if ( loopData->type != LoopData )
946 return TVAR_FORBIDDEN;
947 node = loopData->loopNode;
949 if ( node->nodeData.loop.selfNode == NULL )
950 return TVAR_FORBIDDEN;
952 if ( TListIsEmpty(loopData) )
955 if ( loopData->currentInstance == NULL )
958 GListForeach( cell, node->nodeData.loop.childrenLoop ) {
959 LoopTemplateInstance childData = (LoopTemplateInstance)
960 (tmpl->instanceData + ((TemplateNode)GLCELL_DATA(cell))->nodeData.loop.loopDataOffset);
962 childData->lastRow = NULL;
965 loopData->currentInstance = loopData->currentInstance->upperInstance;
966 loopData->lastRow = NULL;
972 static VariableValueData storage;
975 setTemplateValue( TemplateInstance tmpl, char *key) {
977 VariableValue varval;
978 char *lkey = strlower(mcstrdup(tmpl->templateContext, key));
980 pOffset = SFSFindData(&tmpl->tmpl->variables, lkey, 0);
983 if ( pOffset == NULL )
984 return TVAR_NOTFOUND;
986 varval = (VariableValue)(tmpl->instanceData + *pOffset);
988 if ( varval->type != 0 && varval->type < valueInt ) {
989 return TVAR_LOOPMARK;
990 } else if ( varval->type == valuePointer ) {
991 /* looped variable */
992 varval = varval->value.ptrValue;
994 if ( varval == NULL )
997 tassert( (varval->flags & TND_GLOBAL) == 0 );
1000 if ( varval->flags & TND__SPECIALMASK )
1001 return TVAR_FORBIDDEN;
1003 if ( storage.flags & TND_DEFINED ) {
1004 varval->flags |= TND_DEFINED;
1005 varval->type = storage.type;
1006 varval->value = storage.value;
1008 varval->flags &= ~TND_DEFINED;
1016 setTemplateValueInt( TemplateInstance tmpl, char * key, int val ) {
1017 storage.flags = TND_DEFINED;
1018 storage.type = valueInt;
1019 storage.value.intValue = val;
1020 return setTemplateValue( tmpl, key );
1024 setTemplateValueString( TemplateInstance tmpl, char * key, char * val ) {
1025 storage.flags = TND_DEFINED;
1026 storage.type = valueString;
1027 storage.value.stringValue = val;
1028 return setTemplateValue( tmpl, key );
1032 setTemplateValueTime( TemplateInstance tmpl, char * key, time_t val ) {
1033 storage.flags = TND_DEFINED;
1034 storage.type = valueTime;
1035 storage.value.timeValue = val;
1036 return setTemplateValue( tmpl, key );
1040 setTemplateValueBool( TemplateInstance tmpl, char * key, int val ) {
1041 storage.flags = TND_DEFINED;
1042 storage.type = valueBool;
1043 storage.value.boolValue = val;
1044 return setTemplateValue( tmpl, key );
1048 setTemplateValueDouble( TemplateInstance tmpl, char * key, double val ) {
1049 storage.flags = TND_DEFINED;
1050 storage.type = valueDouble;
1051 storage.value.boolValue = val;
1052 return setTemplateValue( tmpl, key );
1056 setTemplateValueUndefined( TemplateInstance tmpl, char * key ) {
1058 return setTemplateValue( tmpl, key );
1066 printVal( TemplateInstance tmpl, VariableValue value, int *len, char *format ) {
1072 if ( value->type == valueTime ) {
1074 res = mcalloc( tmpl->templateContext, printedlen+1 );
1076 while ( (printedlen = strftime(NULL, 0, (format) ? format : "%Y-%m-%d %H:%M:%S",
1077 localtime(&value->value.timeValue))) == 0 ) {
1079 res=mcrealloc(res, printedlen);
1086 switch (value->type) {
1088 printedlen = snprintf(NULL, 0, (format) ? format : "%d", value->value.intValue);
1091 if ( value->value.stringValue == NULL || *value->value.stringValue == '\0' )
1093 printedlen = snprintf(NULL, 0, (format) ? format : "%s", value->value.stringValue);
1096 printedlen = snprintf(NULL, 0, "%s", (value->value.boolValue) ? "true" : "false" );
1099 printedlen = snprintf(NULL, 0, (format) ? format : "%f", value->value.doubleValue);
1107 res = mcalloc( tmpl->templateContext, printedlen+1 );
1109 switch (value->type) {
1111 printedlen = snprintf(res, printedlen+1, (format) ? format : "%d", value->value.intValue);
1114 printedlen = snprintf(res, printedlen+1, (format) ? format : "%s", value->value.stringValue);
1117 printedlen = snprintf(res, printedlen+1, "%s", (value->value.boolValue) ? "true" : "false" );
1120 printedlen = snprintf(res, printedlen+1, (format) ? format : "%f", value->value.doubleValue);
1134 static VariableValue
1135 executeExpression( TemplateInstance tmpl, TemplateNode node ) {
1136 VariableValue outvalue = NULL;
1141 switch (node->type) {
1143 outvalue = &node->nodeData.value;
1146 outvalue = (VariableValue)(tmpl->instanceData + node->nodeData.variable.varValueOffset);
1148 tassert( (outvalue->flags & TND_DEFINED) == 0 || (outvalue->type >= valueInt && outvalue->type <= valuePointer) );
1150 if ( outvalue->type == valuePointer )
1151 outvalue = outvalue->value.ptrValue;
1153 case ExpressionNode:
1154 GListForeach(cell, node->nodeData.expression.argsNode)
1155 node->nodeData.expression.argsValue[i++] =
1156 executeExpression( tmpl, (TemplateNode)GLCELL_DATA(cell) );
1158 outvalue = node->nodeData.expression.function->execFn(tmpl,
1159 node->nodeData.expression.nargs,
1160 node->nodeData.expression.argsValue);
1166 case CollectionNode:
1169 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1172 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1176 tassert( outvalue!=NULL );
1182 printNode( TemplateInstance tmpl, TemplateNode node, LoopInstance loopInstance ) {
1184 VariableValue value;
1190 switch (node->type) {
1193 LoopTemplateInstance loopData = (LoopTemplateInstance)
1194 (tmpl->instanceData + node->nodeData.loop.loopDataOffset);
1196 LoopInstance instance;
1198 if ( loopInstance ) {
1199 instance = loopInstance;
1201 TListShift( loopData, instance );
1202 if ( instance == NULL )
1206 for(i=0; i<instance->nrow;i++) {
1209 VariableValue realValue;
1211 TListShift( instance, rowData );
1213 GListForeach( cell, node->nodeData.loop.listVarValues ) {
1214 value = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
1216 tassert( value->type == valuePointer );
1217 realValue = value->value.ptrValue = rowData->varvals+j;
1219 if ( value->flags & TND___FIRST ) {
1220 realValue->type = valueInt;
1222 realValue->flags |= TND_DEFINED;
1223 realValue->value.intValue = 1;
1225 realValue->flags &= ~TND_DEFINED;
1226 realValue->value.intValue = 0;
1228 } else if ( value->flags & TND___LAST ) {
1229 realValue->type = valueInt;
1230 if ( i==instance->nrow - 1 ) {
1231 realValue->flags |= TND_DEFINED;
1232 realValue->value.intValue = 1;
1234 realValue->flags &= ~TND_DEFINED;
1235 realValue->value.intValue = 0;
1237 } else if ( value->flags & TND___COUNTER ) {
1238 realValue->type = valueInt;
1239 realValue->flags |= TND_DEFINED;
1240 realValue->value.intValue = i+1;
1241 } else if ( value->flags & TND___SIZE ) {
1242 realValue->type = valueInt;
1243 realValue->flags |= TND_DEFINED;
1244 realValue->value.intValue = instance->nrow;
1245 } else if ( value->flags & TND___ODD ) {
1246 realValue->type = valueBool;
1247 realValue->flags |= TND_DEFINED;
1248 realValue->value.boolValue = (i%2) ? 0 : 1 ;
1249 } else if ( value->flags & TND___EVEN ) {
1250 realValue->type = valueBool;
1251 realValue->flags |= TND_DEFINED;
1252 realValue->value.boolValue = (i%2) ? 1 : 0 ;
1258 if ( node->nodeData.loop.selfNode )
1259 node->nodeData.loop.selfNode->nodeData.nest.savedRowData = rowData;
1261 printNode( tmpl, node->nodeData.loop.bodyNode, NULL );
1266 if ( node->nodeData.nest.loop && node->nodeData.nest.savedRowData ) {
1267 LoopRow savedRowData = node->nodeData.nest.savedRowData; /* save current row */
1268 LoopInstance *savedChildrenInstance = NULL;
1271 * Save child's instances for current loop
1273 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1274 savedChildrenInstance = mcalloc(tmpl->templateContext, sizeof(LoopInstance) *
1275 GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf));
1278 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1279 TemplateNode chld = GLCELL_DATA(cell);
1280 LoopTemplateInstance loopData = (LoopTemplateInstance)
1281 (tmpl->instanceData + chld->nodeData.loop.loopDataOffset);
1282 LoopInstance cellInstance;
1284 TListShift( loopData, cellInstance );
1286 savedChildrenInstance[i++] = cellInstance;
1290 printNode( tmpl, node->nodeData.nest.loop, savedRowData->nestedInstance );
1293 * Restore saved datas
1296 GListForeach( cell, node->nodeData.nest.loop->nodeData.loop.listVarValues ) {
1297 value = (VariableValue) (tmpl->instanceData + ((Offset)GLCELL_DATA(cell)));
1298 value->value.ptrValue = savedRowData->varvals + i;
1302 if ( GLIST_LENGTH(node->nodeData.nest.childrenLoopAfterSelf) ) {
1304 GListForeach( cell, node->nodeData.nest.childrenLoopAfterSelf) {
1305 TemplateNode chld = GLCELL_DATA(cell);
1306 LoopTemplateInstance loopData = (LoopTemplateInstance)
1307 (tmpl->instanceData + chld->nodeData.loop.loopDataOffset);
1309 if ( savedChildrenInstance[i] )
1310 TListUnShift( loopData, savedChildrenInstance[i] );
1317 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1319 if ( isVariable(value) )
1320 printNode( tmpl, node->nodeData.condition.ifNode, loopInstance );
1322 printNode( tmpl, node->nodeData.condition.elseNode, loopInstance );
1324 case CollectionNode:
1325 GListForeach( cell, node->nodeData.children )
1326 printNode( tmpl, (TemplateNode)GLCELL_DATA(cell), loopInstance );
1329 value = executeExpression( tmpl, node->nodeData.condition.expressionNode );
1331 if ( value && (value->flags & TND_DEFINED) != 0 ) {
1335 res = printVal(tmpl, value, &len, node->nodeData.print.formatValue);
1337 if ( (node->nodeData.variable.flags & TND_HTMLESCAPE) && tmpl->tmpl->htmlEscape )
1338 res = tmpl->tmpl->htmlEscape(res, &len);
1339 if ( (node->nodeData.variable.flags & TND_URLESCAPE) && tmpl->tmpl->urlEscape )
1340 res = tmpl->tmpl->urlEscape(res, &len);
1342 if ( res && len>0 ) {
1343 tmpl->tmpl->printString( res, len );
1346 } else if ( node->nodeData.print.defaultValue ) {
1347 tmpl->tmpl->printString( node->nodeData.print.defaultValue,
1348 strlen( node->nodeData.print.defaultValue ) );
1352 tmpl->tmpl->printString( node->nodeData.text.value, node->nodeData.text.valueLength );
1357 case ExpressionNode:
1358 tlog(TL_CRIT|TL_EXIT, "Unexpected node type: %d", node->type);
1361 tlog(TL_CRIT|TL_EXIT, "Unknown node type: %d", node->type);
1367 printTemplate( TemplateInstance tmpl ) {
1368 if (!tmpl->tmpl->printString)
1371 printNode(tmpl, tmpl->tmpl->tree, NULL);
1377 void printLevel(int level) {
1382 recursiveDump(Template tmpl, TemplateNode node, int level) {
1386 if (node == NULL ) {
1391 switch(node->type) {
1393 printf("IncludeNode\n");
1396 printf("LoopNode '%s'\n", node->nodeData.loop.varName);
1397 recursiveDump(tmpl, node->nodeData.loop.bodyNode, level+1);
1400 printf("ConditionNode\n");
1401 recursiveDump(tmpl, node->nodeData.condition.expressionNode, level+1);
1402 recursiveDump(tmpl, node->nodeData.condition.ifNode, level+1);
1403 recursiveDump(tmpl, node->nodeData.condition.elseNode, level+1);
1405 case CollectionNode:
1406 printf("CollectionNode\n");
1407 GListForeach(cell, node->nodeData.children)
1408 recursiveDump(tmpl, (TemplateNode)GLCELL_DATA(cell), level+1);
1411 printf("TextNode len:%d\n", node->nodeData.text.valueLength);
1414 printf("VariableNode '%s'\n", node->nodeData.variable.varName);
1416 case ExpressionNode:
1417 printf("ExpressionNode '%s'\n", node->nodeData.expression.functionName);
1418 GListForeach(cell, node->nodeData.expression.argsNode)
1419 recursiveDump( tmpl, GLCELL_DATA(cell) ,level + 1);
1422 printf("PrintNode\n");
1423 recursiveDump( tmpl, node->nodeData.print.expressionNode, level + 1 );
1426 printf("ConstNode\n");
1429 printf("NestNode\n");
1432 tlog(TL_CRIT|TL_EXIT, "unknown node type: %d", node->type);
1437 dumpTemplate( Template tmpl ) {
1438 recursiveDump(tmpl, tmpl->tree, 0);