/* * Copyright (c) 2008 Teodor Sigaev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /****************************************************************************** * Html template library * ****************************************************************************** ****************************************************************************** * SYNTAX * ****************************************************************************** * <% EXPRESSION [, "FORMAT"] [# "DEFAULTVALUE"] [|(h|u)]%> * - format value should be as in strftime for time value and printf * for all other. Currently, bool values have only "true"/"false" * string values * <@IF EXPRESSION @> * [<@ ELSE IF EXPRESSION | ELSIF EXPRESSION @>] * [ <@ELSE@> ] * <@ENDIF@> * * Expression is classical with support following: * - ['^'] VARNAME * variable defined from C-code. Mark '^' means global * variable, not local in loop. * - expression (+|-|*|/|%) expression * ariphmetic operations * - expression ( || | && ) expression * ! expression * logical OR, AND and NOT * - expression ( < | <= | == | >= | > | != | <> ) expression * compare expression * - LENGTH(expression) * computes length of string * - DEFINED(expression) * returns true if expression is defined * - expression ? expression : expression * - ( expression ) * - USERDEFINEDFUNCTION( [expression[,expression[...]]] ) * User defined function call. Function should be defined at * C-level. * * <@LOOP MARKNAME@> * [ <@ SELF @> ] * <@ENDLOOP@> * Loop has predefined variables: * __FIRST - true for first iteration * __LAST - true for last iteration * __COUNTER - iteration's number * __LEVEL - level of nested loop (root == 0) * __SIZE - number of iterations * __ODD - true for odd iteraion * __EVEN - true for even iteraion * * <& FILENAME &> * * <# comment #> * ****************************************************************************** * C-Interface * ****************************************************************************** * - setTemplateValueInt * setTemplateValueString * setTemplateValueTime * setTemplateValueBool * setTemplateValueDouble * setTemplateValueUndefined * Sets varibale's value * - addTemplateRow * Add one iteration to the pointed loop. Local variable in loop should * pointed with predecence loop's mark(s) separated by dot. Example: * HTML: * <@Loop outerLoop@> * <% var1 %> * <@Loop innerLoop@> * <% var2 %> * <@endloop@> * <@endloop@> * C: * addTemplateRow("outerLoop"); * setTemplateValueBool("outerLoop.var1"); * addTemplateRow("innerLoop"); * setTemplateValueBool("outerLoop.innerLoop.var2"); * - addTemplateNestedLoop * returnTemplateNestedLoop * Manage self-nested loops ( ie tree-like structures ). * Loop's template should contains one <@ SELF @> pointer. * * Examplaes of usage are in data/template.html used for test. * ****************************************************************************** * Memory management * ****************************************************************************** * Unfortunatly, I'm too lazy to unify memory usage by several pieces * in library. So, library uses mixed plain malloc and memory context * concepts (tmalloc.h). * To work with library it's needed to allocate persistent memory context * for initTemplate(). * To work with template it's needed to get template's instance by * newTemplateInstance() call with separated memory context. In any time * that memory context can be reseted or freeed and it will be enough * to free template's instance. * ******************************************************************************/ #ifndef __TEMPLATE_H__ #define __TEMPLATE_H__ #include #include #include "glist.h" #include "sfxstr.h" #include "tmalloc.h" typedef enum TemplateNodeType { /* node tree types */ TextNode = 100, VariableNode, IncludeNode, LoopNode, ConditionNode, CollectionNode, ExpressionNode, PrintNode, ConstNode, NestNode, LoopData, /* value's types of variables */ valueInt = 200, /* smallest of any values type */ valueString, valueTime, valueBool, valueDouble, valuePointer } TemplateNodeType; #define TND_HTMLESCAPE (0x0001) #define TND_URLESCAPE (0x0002) #define TND_GLOBAL (0x0004) #define TND___FIRST (0x0008) #define TND___LAST (0x0010) #define TND___COUNTER (0x0020) #define TND___SIZE (0x0040) #define TND___ODD (0x0080) #define TND___EVEN (0x0100) #define TND___LEVEL (0x0200) #define TND_DEFINED (0x0400) #define TND__SPECIALMASK (TND___FIRST | TND___LAST | TND___COUNTER | TND___SIZE | TND___ODD | TND___EVEN | TND___LEVEL) typedef struct TemplateData *Template; typedef struct TemplateInstanceData *TemplateInstance; typedef struct TemplateNodeData *TemplateNode; typedef struct VariableValueData * VariableValue; typedef struct VariableValueData { TemplateNodeType type; /* should be first, see resetTemplate/freeTemplate */ int flags; union { int64_t intValue; char *stringValue; time_t timeValue; int boolValue; double doubleValue; VariableValue ptrValue; /* special value to handle loop variables, points to members of loopValues */ } value; } VariableValueData; typedef struct executeFunctionDescData *executeFunctionDesc; typedef struct executeFunctionDescData { char *name; int nargs; /* -1 - variable number */ VariableValue (*execFn)(TemplateInstance, int, VariableValue*); } executeFunctionDescData; typedef struct LoopInstanceData * LoopInstance; typedef struct LoopRowData *LoopRow; typedef struct LoopRowData { TemplateNode loop; LoopInstance nestedInstance; LoopRow nextCell; VariableValueData varvals[1]; } LoopRowData; #define LRDHDRSZ (offsetof(LoopRowData, varvals)) typedef struct LoopInstanceData { int nrow; LoopInstance upperInstance; LoopInstance nextCell; LoopRow headList; LoopRow tailList; /* GList *rowValues; */ /*list of LoopRow */ } LoopInstanceData; typedef struct LoopTemplateInstanceData *LoopTemplateInstance; typedef struct LoopTemplateInstanceData { TemplateNodeType type; /* LoopData */ TemplateNode loopNode; LoopRow lastRow; LoopInstance currentInstance; LoopInstance headList; LoopInstance tailList; /*GList *listInstance;*/ } LoopTemplateInstanceData; typedef long Offset; typedef struct TemplateNodeData { TemplateNodeType type; /* should be first, see resetTemplate/freeTemplate */ union { /* TextNode */ struct { char *value; int valueLength; } text; /* VariableNode */ struct { char *varName; int varNameLength; Offset varValueOffset; /* VariableValue value; */ int flags; } variable; /* ExpressionNode */ struct { VariableValue *argsValue; int nargs; char *functionName; executeFunctionDesc function; GList *argsNode; /* list of arguments nodes */ } expression; /* ConstNode */ VariableValueData value; /* PrintNode */ struct { TemplateNode expressionNode; char *formatValue; char *defaultValue; int flags; } print; /* IncludeNode */ char *includeFile; /* NestNode */ struct { TemplateNode loop; LoopRow savedRowData; GList *childrenLoopAfterSelf; } nest; /* LoopNode */ struct { char *varName; int varNameLength; TemplateNode bodyNode; TemplateNode selfNode; /* pointer to self-nested plase to insert */ GList *childrenLoop; /* to reset loop's instance */ GList *listVarValues; /* list of loop variables */ Offset loopDataOffset; } loop; /* ConditionNode */ struct { TemplateNode expressionNode; TemplateNode ifNode; TemplateNode elseNode; } condition; /* CollectionNode */ GList *children; } nodeData; } TemplateNodeData; /* prints result */ typedef void (*outFn)(char *, int); typedef char* (*urlEscapeFn)(char *, int * /* in/out */); typedef char* (*htmlEscapeFn)(char *, int * /* in/out */); typedef struct TemplateData { TemplateNode tree; MemoryContext *templateContext; SFSTree variables; outFn printString; urlEscapeFn urlEscape; htmlEscapeFn htmlEscape; executeFunctionDesc functions; Offset templateInstanceSize; char *templateInstance; } TemplateData; typedef struct TemplateInstanceData { Template tmpl; MemoryContext *templateContext; char instanceData[1]; } TemplateInstanceData; int parseTemplateFile(Template tmpl, char* filename ); /* return non-zero if error */ int initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename ); void freeTemplate( Template tmpl ); TemplateInstance newTemplateInstance(Template tmpl, MemoryContext *mc); int printTemplate( TemplateInstance tmpl ); #define TVAR_OK (0) #define TVAR_NOTFOUND (1) #define TVAR_FORBIDDEN (2) #define TVAR_NOROW (3) #define TVAR_LOOPMARK (4) int setTemplateValueInt( TemplateInstance tmpl, char * key, int64_t val ); int setTemplateValueString( TemplateInstance tmpl, char * key, char * val ); int setTemplateValueTime( TemplateInstance tmpl, char * key, time_t val ); int setTemplateValueBool( TemplateInstance tmpl, char * key, int val ); int setTemplateValueUndefined( TemplateInstance tmpl, char * key ); int setTemplateValueDouble( TemplateInstance tmpl, char * key, double val ); int addTemplateRow( TemplateInstance tmpl, char * key ); int addTemplateNestedLoop( TemplateInstance tmpl, char * key); int returnTemplateNestedLoop( TemplateInstance tmpl, char * key); void dumpTemplate( Template tmpl ); #endif