*/
/******************************************************************************
+ * Html template library *
+ ******************************************************************************
+ ******************************************************************************
* SYNTAX *
******************************************************************************
- * <% [^]VARNAME[, "FORMAT"] [||"DEFAULTVALUE"] [|(h|u)]%>
- * - '^' mark means global variable.
+ * <% 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 [NOT] [DEFINED] [^]VARNAME@>
- * <@ELSE@>
+ * <@IF EXPRESSION @>
+ * [<@ ELSE IF EXPRESSION | ELSIF EXPRESSION @>]
+ * [ <@ELSE@> ]
* <@ENDIF@>
*
- * <@LOOP MARKNAME@>
+ * 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__
LoopNode,
ConditionNode,
CollectionNode,
+ ExpressionNode,
+ PrintNode,
+ ConstNode,
+ NestNode,
+ LoopData,
/* value's types of variables */
valueInt = 200, /* smallest of any values type */
valuePointer
} TemplateNodeType;
-#define TND_DEFINED (0x0001)
-#define TND_NOT (0x0002)
-#define TND_HTMLESCAPE (0x0004)
-#define TND_URLESCAPE (0x0008)
-#define TND_GLOBAL (0x0010)
-#define TND___FIRST (0x0020)
-#define TND___LAST (0x0040)
-#define TND___COUNTER (0x0080)
-#define TND___SIZE (0x0100)
-#define TND___ODD (0x0200)
-#define TND___EVEN (0x0400)
-
-#define TND__SPECIALMASK (TND___FIRST | TND___LAST | TND___COUNTER | TND___SIZE | TND___ODD | TND___EVEN)
-struct TemplateNodeData;
+#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;
TemplateNodeType type; /* should be first, see resetTemplate/freeTemplate */
int flags;
union {
- int intValue;
+ int64_t intValue;
char *stringValue;
time_t timeValue;
int boolValue;
} 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;
- GList *rowValues;
+ 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 */
struct {
char *varName;
int varNameLength;
- VariableValue value;
+ Offset varValueOffset;
+ /* VariableValue value; */
int flags;
- char *formatValue;
- char *defaultValue;
} 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;
- int counter;
- GList *childrenLoop; /* to reset instance */
+ TemplateNode selfNode; /* pointer to self-nested plase to insert */
+ GList *childrenLoop; /* to reset loop's instance */
GList *listVarValues; /* list of loop variables */
- GList *listInstance;
+ Offset loopDataOffset;
} loop;
/* ConditionNode */
struct {
- int flags;
- char *varName;
- int varNameLength;
- VariableValue value;
+ TemplateNode expressionNode;
TemplateNode ifNode;
TemplateNode elseNode;
} condition;
typedef char* (*htmlEscapeFn)(char *, int * /* in/out */);
typedef struct TemplateData {
- TemplateNode tree;
- MemoryContext *templateContext;
- SFSTree variables;
- outFn printString;
- urlEscapeFn urlEscape;
- htmlEscapeFn htmlEscape;
+ TemplateNode tree;
+ MemoryContext *templateContext;
+ SFSTree variables;
+ outFn printString;
+ urlEscapeFn urlEscape;
+ htmlEscapeFn htmlEscape;
+ executeFunctionDesc functions;
+
+ Offset templateInstanceSize;
+ char *templateInstance;
} TemplateData;
-typedef struct TemplateData *Template;
+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, char *basedir, char *filename );
+int initTemplate( Template tmpl, MemoryContext *mc, executeFunctionDesc functions, char *basedir, char *filename );
void freeTemplate( Template tmpl );
-void resetTemplate( Template tmpl );
-int printTemplate( Template tmpl );
+TemplateInstance newTemplateInstance(Template tmpl, MemoryContext *mc);
+int printTemplate( TemplateInstance tmpl );
#define TVAR_OK (0)
#define TVAR_NOTFOUND (1)
#define TVAR_NOROW (3)
#define TVAR_LOOPMARK (4)
-int setTemplateValueInt( Template tmpl, char * key, int val );
-int setTemplateValueString( Template tmpl, char * key, char * val );
-int setTemplateValueTime( Template tmpl, char * key, time_t val );
-int setTemplateValueBool( Template tmpl, char * key, int val );
-int setTemplateValueUndefined( Template tmpl, char * key );
-int setTemplateValueDouble( Template tmpl, char * key, double val );
-int addTemplateRow( Template tmpl, char * key );
-
+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