*/
/******************************************************************************
+ * 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@> ]
* <@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
+ * __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() call and provide temporary memory context for usual work.
+ * after printTemplate is called it's needed to call resetTemplate() and
+ * then resetMemoryContext() for second context.
+ *
******************************************************************************/
#ifndef __TEMPLATE_H__
LoopNode,
ConditionNode,
CollectionNode,
+ ExpressionNode,
+ PrintNode,
+ ConstNode,
+ NestNode,
/* 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_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_DEFINED (0x0200)
#define TND__SPECIALMASK (TND___FIRST | TND___LAST | TND___COUNTER | TND___SIZE | TND___ODD | TND___EVEN)
-struct TemplateNodeData;
+
+typedef struct TemplateData *Template;
+
typedef struct TemplateNodeData *TemplateNode;
typedef struct VariableValueData * VariableValue;
} value;
} VariableValueData;
+
+typedef struct executeFunctionDescData *executeFunctionDesc;
+typedef struct executeFunctionDescData {
+ char *name;
+ int nargs; /* -1 - variable number */
+ VariableValue (*execFn)(Template, int, VariableValue*);
+} executeFunctionDescData;
+
typedef struct LoopInstanceData * LoopInstance;
+
+typedef struct LoopRowData *LoopRow;
+
+typedef struct LoopRowData {
+ TemplateNode loop;
+ LoopInstance nestedInstance;
+ VariableValueData varvals[1];
+} LoopRowData;
+#define LRDHDRSZ (offsetof(LoopRowData, varvals))
+
typedef struct LoopInstanceData {
int nrow;
- GList *rowValues;
+ LoopInstance upperInstance;
+ GList *rowValues; /*list of LoopRow */
} LoopInstanceData;
typedef struct TemplateNodeData {
int varNameLength;
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;
+ /* listInstace -+
+ +->instance-+
+ +->row
+ |
+ |
+ +->row->currentInstance
+ */
+ LoopRow lastRow;
+ LoopInstance currentInstance;
} 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;
} TemplateData;
-typedef struct TemplateData *Template;
-
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 );
int setTemplateValueUndefined( Template tmpl, char * key );
int setTemplateValueDouble( Template tmpl, char * key, double val );
int addTemplateRow( Template tmpl, char * key );
-
+int addTemplateNestedLoop( Template tmpl, char * key);
+int returnTemplateNestedLoop( Template tmpl, char * key);
void dumpTemplate( Template tmpl );
#endif