add .gitignore
[tedtools.git] / template.h
index 72a57e5..97e9070 100644 (file)
  */
 
 /******************************************************************************
+ *                         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__
@@ -66,6 +143,11 @@ typedef     enum TemplateNodeType {
        LoopNode,
        ConditionNode,
        CollectionNode,
+       ExpressionNode,
+       PrintNode,
+       ConstNode,
+       NestNode,
+       LoopData,
 
        /* value's types of variables */
        valueInt = 200, /* smallest of any values type */
@@ -76,20 +158,26 @@ typedef    enum TemplateNodeType {
        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;
@@ -97,7 +185,7 @@ typedef struct VariableValueData {
        TemplateNodeType        type; /* should be first, see resetTemplate/freeTemplate */
        int                                     flags;
        union {
-               int                             intValue;
+               int64_t                 intValue;
                char                    *stringValue;
                time_t                  timeValue;
                int                             boolValue;
@@ -107,12 +195,49 @@ typedef struct VariableValueData {
        } 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 */
 
@@ -127,32 +252,55 @@ typedef struct  TemplateNodeData {
                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;
@@ -170,21 +318,29 @@ 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;
+       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)
@@ -192,13 +348,14 @@ int printTemplate( Template tmpl );
 #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