Home | History | Annotate | Download | only in cs
      1 /*
      2  * Copyright 2001-2004 Brandon Long
      3  * All Rights Reserved.
      4  *
      5  * ClearSilver Templating System
      6  *
      7  * This code is made available under the terms of the ClearSilver License.
      8  * http://www.clearsilver.net/license.hdf
      9  *
     10  */
     11 
     12 /*
     13  * CS Syntax (pseudo BNF, pseudo accurate)
     14  * ------------------------------------------------------------------
     15  * CS          := (ANYTHING COMMAND)*
     16  * CS_OPEN     := <?cs
     17  * CS_CLOSE    := ?>
     18  * COMMAND     := (CMD_IF | CMD_VAR | CMD_EVAR | CMD_INCLUDE | CMD_EACH
     19  *                 | CMD_DEF | CMD_CALL | CMD_SET | CMD_LOOP )
     20  * CMD_IF      := CS_OPEN IF CS_CLOSE CS CMD_ENDIF
     21  * CMD_ENDIF   := CS_OPEN ENDIF CS_CLOSE
     22  * CMD_INCLUDE := CS_OPEN INCLUDE CS_CLOSE
     23  * CMD_DEF     := CS_OPEN DEF CS_CLOSE
     24  * CMD_CALL    := CS_OPEN CALL CS_CLOSE
     25  * CMD_SET     := CS_OPEN SET CS_CLOSE
     26  * CMD_LOOP    := CS_OPEN LOOP CS_CLOSE
     27  * LOOP        := loop:VAR = EXPR, EXPR, EXPR
     28  * SET         := set:VAR = EXPR
     29  * EXPR        := (ARG | ARG OP EXPR)
     30  * CALL        := call:VAR LPAREN ARG (,ARG)* RPAREN
     31  * DEF         := def:VAR LPAREN ARG (,ARG)* RPAREN
     32  * INCLUDE     := include:(VAR|STRING)
     33  * IF          := (if:ARG OP ARG|if:ARG|if:!ARG)
     34  * ENDIF       := /if
     35  * OP          := ( == | != | < | <= | > | >= | || | && | + | - | * | / | % )
     36  * ARG         := (STRING|VAR|NUM)
     37  * STRING      := "[^"]"
     38  * VAR         := [^"<> ]+
     39  * NUM         := #[0-9]+
     40  */
     41 
     42 #ifndef __CSHDF_H_
     43 #define __CSHDF_H_ 1
     44 
     45 #include "util/neo_misc.h"
     46 #include "util/neo_err.h"
     47 #include "util/ulist.h"
     48 #include "util/neo_hdf.h"
     49 #include "util/neo_str.h"
     50 
     51 __BEGIN_DECLS
     52 
     53 typedef enum
     54 {
     55   /* Unary operators */
     56   CS_OP_NONE = (1<<0),
     57   CS_OP_EXISTS = (1<<1),
     58   CS_OP_NOT = (1<<2),
     59   CS_OP_NUM = (1<<3),
     60 
     61   /* Binary Operators */
     62   CS_OP_EQUAL = (1<<4),
     63   CS_OP_NEQUAL = (1<<5),
     64   CS_OP_LT = (1<<6),
     65   CS_OP_LTE = (1<<7),
     66   CS_OP_GT = (1<<8),
     67   CS_OP_GTE = (1<<9),
     68   CS_OP_AND = (1<<10),
     69   CS_OP_OR = (1<<11),
     70   CS_OP_ADD = (1<<12),
     71   CS_OP_SUB = (1<<13),
     72   CS_OP_MULT = (1<<14),
     73   CS_OP_DIV = (1<<15),
     74   CS_OP_MOD = (1<<16),
     75 
     76   /* Associative Operators */
     77   CS_OP_LPAREN = (1<<17),
     78   CS_OP_RPAREN = (1<<18),
     79   CS_OP_LBRACKET = (1<<19),
     80   CS_OP_RBRACKET = (1<<20),
     81 
     82   CS_OP_DOT = (1<<21),
     83   CS_OP_COMMA = (1<<22),
     84 
     85   /* Types */
     86   CS_TYPE_STRING = (1<<25),
     87   CS_TYPE_NUM = (1<<26),
     88   CS_TYPE_VAR = (1<<27),
     89   CS_TYPE_VAR_NUM = (1<<28),
     90 
     91   /* Not real types... */
     92   CS_TYPE_MACRO = (1<<29),
     93   CS_TYPE_FUNCTION = (1<<30)
     94 } CSTOKEN_TYPE;
     95 
     96 #define CS_OPS_UNARY (CS_OP_EXISTS | CS_OP_NOT | CS_OP_NUM | CS_OP_LPAREN)
     97 #define CS_TYPES (CS_TYPE_STRING | CS_TYPE_NUM | CS_TYPE_VAR | CS_TYPE_VAR_NUM)
     98 #define CS_OPS_LVALUE (CS_OP_DOT | CS_OP_LBRACKET | CS_TYPES)
     99 #define CS_TYPES_VAR (CS_TYPE_VAR | CS_TYPE_VAR_NUM)
    100 #define CS_TYPES_CONST (CS_TYPE_STRING | CS_TYPE_NUM)
    101 #define CS_ASSOC (CS_OP_RPAREN | CS_OP_RBRACKET)
    102 
    103 typedef struct _parse CSPARSE;
    104 typedef struct _funct CS_FUNCTION;
    105 typedef struct _escape_context CS_ECONTEXT;
    106 typedef struct _position CS_POSITION;
    107 typedef struct _error CS_ERROR;
    108 
    109 typedef struct _arg
    110 {
    111   CSTOKEN_TYPE op_type;
    112   char *argexpr;
    113   char *s;
    114   long int n;
    115   int alloc;
    116   struct _funct *function;
    117   struct _macro *macro;
    118   struct _arg *expr1;
    119   struct _arg *expr2;
    120   struct _arg *next;
    121 } CSARG;
    122 
    123 #define CSF_REQUIRED (1<<0)
    124 
    125 typedef struct _tree
    126 {
    127   int node_num;
    128   int cmd;
    129   int flags;
    130   NEOS_ESCAPE escape;
    131   CSARG arg1;
    132   CSARG arg2;
    133   CSARG *vargs;
    134 
    135   char *fname;
    136   int linenum;
    137   int colnum;
    138 
    139   struct _tree *case_0;
    140   struct _tree *case_1;
    141   struct _tree *next;
    142 } CSTREE;
    143 
    144 typedef struct _local_map
    145 {
    146   CSTOKEN_TYPE type;
    147   char *name;
    148   int map_alloc;
    149   /* These three (s,n,h) used to be a union, but now we sometimes allocate
    150    * a buffer in s with the "string" value of n, so its separate */
    151   char *s;
    152   long int n;
    153   HDF *h;
    154   int first;  /* This local is the "first" item in an each/loop */
    155   int last;   /* This local is the "last" item in an loop, each is calculated
    156                explicitly based on hdf_obj_next() in _builtin_last() */
    157   struct _local_map *next;
    158 } CS_LOCAL_MAP;
    159 
    160 typedef struct _macro
    161 {
    162   char *name;
    163   int n_args;
    164   CSARG *args;
    165 
    166   CSTREE *tree;
    167 
    168   struct _macro *next;
    169 } CS_MACRO;
    170 
    171 
    172 /* CSOUTFUNC is a callback function for where cs_render will render the
    173  * template to.
    174  * Technically, the char * for this func should be const char *, but that
    175  * would break existing code. */
    176 typedef NEOERR* (*CSOUTFUNC)(void *, char *);
    177 
    178 /* CSFUNCTION is a callback function used for handling a function made
    179  * available inside the template.  Used by cs_register_function.  Exposed
    180  * here as part of the experimental extension framework, this may change
    181  * in future versions. */
    182 typedef NEOERR* (*CSFUNCTION)(CSPARSE *parse, CS_FUNCTION *csf, CSARG *args,
    183                               CSARG *result);
    184 
    185 /* CSSTRFUNC is a callback function for the more limited "string filter"
    186  * function handling.  String filters only take a string and return a
    187  * string and have no "data" that is passed back, attempting to make them
    188  * "safe" from extensions that might try to do silly things like SQL queries.
    189  * */
    190 typedef NEOERR* (*CSSTRFUNC)(const char *str, char **ret);
    191 
    192 /* CSFILELOAD is a callback function to intercept file load requests and
    193  * provide templates via another mechanism.  This way you can load templates
    194  * that you compiled-into your binary, from in-memory caches, or from a
    195  * zip file, etc.  The HDF is provided so you can choose to use the
    196  * hdf_search_path function to find the file.  contents should return
    197  * a full malloc copy of the contents of the file, which the parser will modify
    198  * and own and free.  Use cs_register_fileload to set this function for
    199  * your CSPARSE context. */
    200 typedef NEOERR* (*CSFILELOAD)(void *ctx, HDF *hdf, const char *filename,
    201                               char **contents);
    202 
    203 struct _funct
    204 {
    205   char *name;
    206   int name_len;
    207   int n_args;
    208   NEOS_ESCAPE escape; /* States escaping exemptions. default: NONE. */
    209 
    210   CSFUNCTION function;
    211   CSSTRFUNC str_func;
    212 
    213   struct _funct *next;
    214 };
    215 
    216 /* This structure maintains the necessary running state to manage
    217  * automatic escaping in tandem with the 'escape' directive. It is passed
    218  * around inside _parse.
    219  */
    220 struct _escape_context
    221 {
    222   NEOS_ESCAPE global_ctx; /* Contains global default escaping mode:
    223 			     none,html,js,url */
    224   NEOS_ESCAPE current;    /* Used to pass around parse and evaluation specific
    225                              data from subfunctions upward. */
    226   NEOS_ESCAPE next_stack; /* This is a big fat workaround. Since STACK_ENTRYs
    227                              are only added to the stack after the
    228                              command[].parse_handler() is called for the call
    229                              it is being setup for, this is used to pass state
    230                              forward.  E.g. This is used for 'def' to set UNDEF
    231                              escaping state to delay escaping status to
    232                              evaluation time. */
    233   NEOS_ESCAPE when_undef; /* Contains the escaping context to be used when a
    234                              UNDEF is being replaced at evaluation time.  E.g.
    235                              this is set in call_eval to force the macro code
    236                              to get call's parsing context at eval time. */
    237 };
    238 
    239 /* This structure is used to track current location within the CS file being
    240  * parsed. This information is used to find the filename and line number for
    241  * each node.
    242  */
    243 struct _position {
    244   int line;        /* Line number for current position */
    245   int col;         /* Column number for current position */
    246   int cur_offset;  /* The current position - commence reading from here */
    247 };
    248 
    249 struct _error {
    250   NEOERR *err;
    251   struct _error *next;
    252 };
    253 
    254 struct _parse
    255 {
    256   const char *context;   /* A string identifying where the parser is parsing */
    257   int in_file;           /* Indicates if current context is a file */
    258   int offset;
    259 
    260   int audit_mode;        /* If in audit_mode, gather some extra information */
    261   CS_POSITION pos;       /* Container for current position in CS file */
    262   CS_ERROR *err_list;    /* List of non-fatal errors encountered */
    263 
    264   char *context_string;
    265   CS_ECONTEXT escaping; /* Context container for escape data */
    266 
    267   char *tag;		/* Usually cs, but can be set via HDF Config.TagStart */
    268   int taglen;
    269 
    270   ULIST *stack;
    271   ULIST *alloc;         /* list of strings owned by CSPARSE and free'd when
    272                            its destroyed */
    273   CSTREE *tree;
    274   CSTREE *current;
    275   CSTREE **next;
    276 
    277   HDF *hdf;
    278 
    279   struct _parse *parent;  /* set on internally created parse instances to point
    280                              at the parent.  This can be used for hierarchical
    281                              scope in the future. */
    282 
    283   CS_LOCAL_MAP *locals;
    284   CS_MACRO *macros;
    285   CS_FUNCTION *functions;
    286 
    287   /* Output */
    288   void *output_ctx;
    289   CSOUTFUNC output_cb;
    290 
    291   void *fileload_ctx;
    292   CSFILELOAD fileload;
    293 
    294   /* Global hdf struct */
    295   /* smarti:  Added for support for global hdf under local hdf */
    296   HDF *global_hdf;
    297 };
    298 
    299 /*
    300  * Function: cs_init - create and initialize a CS context
    301  * Description: cs_init will create a CSPARSE structure and initialize
    302  *       it.  This structure maintains the state and information
    303  *       necessary for parsing and rendering a CS template.
    304  * Input: parse - a pointer to a pointer to a CSPARSE structure that
    305  *        will be created
    306  *        hdf - the HDF dataset to be used during parsing and rendering
    307  * Output: parse will contain a pointer to the allocated CSPARSE
    308  *         structure.  This structure will be deallocated with
    309  *         cs_destroy()
    310  * Return: NERR_NOMEM
    311  * MT-Level: cs routines perform no locking, and neither do hdf
    312  *           routines.  They should be safe in an MT environment as long
    313  *           as they are confined to a single thread.
    314  */
    315 NEOERR *cs_init (CSPARSE **parse, HDF *hdf);
    316 
    317 /*
    318  * Function: cs_parse_file - parse a CS template file
    319  * Description: cs_parse_file will parse the CS template located at
    320  *              path.  It will use hdf_search_path() if path does not
    321  *              begin with a '/'.  The parsed CS template will be
    322  *              appended to the current parse tree stored in the CSPARSE
    323  *              structure.  The entire file is loaded into memory and
    324  *              parsed in place.
    325  * Input: parse - a CSPARSE structure created with cs_init
    326  *        path - the path to the file to parse
    327  * Output: None
    328  * Return: NERR_ASSERT - if path == NULL
    329  *         NERR_NOT_FOUND - if path isn't found
    330  *         NERR_SYSTEM - if path can't be accessed
    331  *         NERR_NOMEM - unable to allocate memory to load file into memory
    332  *         NERR_PARSE - error in CS template
    333  */
    334 NEOERR *cs_parse_file (CSPARSE *parse, const char *path);
    335 
    336 /*
    337  * Function: cs_parse_string - parse a CS template string
    338  * Description: cs_parse_string parses a string.  The string is
    339  *              modified, and internal references are kept by the parse
    340  *              tree.  For this reason, ownership of the string is
    341  *              transfered to the CS system, and the string will be
    342  *              free'd when cs_destroy() is called.
    343  *              The parse information will be appended to the current
    344  *              parse tree.  During parse, the only HDF variables which
    345  *              are evaluated are those used in evar or include
    346  *              statements.
    347  * Input: parse - a CSPARSE structure created with cs_init
    348  *        buf - the string to parse.  Embedded NULLs are not currently
    349  *              supported
    350  *        blen - the length of the string
    351  * Output: None
    352  * Return: NERR_PARSE - error in CS template
    353  *         NERR_NOMEM - unable to allocate memory for parse structures
    354  *         NERR_NOT_FOUND - missing required variable
    355  */
    356 NEOERR *cs_parse_string (CSPARSE *parse, char *buf, size_t blen);
    357 
    358 /*
    359  * Function: cs_render - render a CS parse tree
    360  * Description: cs_render will evaluate a CS parse tree, calling the
    361  *              CSOUTFUNC passed to it for output.  Note that calling
    362  *              cs_render multiple times on the same parse tree may or
    363  *              may not render the same output as the set statement has
    364  *              side-effects, it updates the HDF data used by the
    365  *              render.  Typically, you will call one of the cs_parse
    366  *              functions before calling this function.
    367  * Input: parse - the CSPARSE structure containing the CS parse tree
    368  *                that will be evaluated
    369  *        ctx - user data that will be passed as the first variable to
    370  *              the CSOUTFUNC.
    371  *        cb - a CSOUTFUNC called to render the output.  A CSOUTFUNC is
    372  *             defined as:
    373  *                 typedef NEOERR* (*CSOUTFUNC)(void *, char *);
    374  * Output: None
    375  * Return: NERR_NOMEM - Unable to allocate memory for CALL or SET
    376  *                      functions
    377  *         any error your callback functions returns
    378  */
    379 NEOERR *cs_render (CSPARSE *parse, void *ctx, CSOUTFUNC cb);
    380 
    381 /*
    382  * Function: cs_dump - dump the cs parse tree
    383  * Description: cs_dump will dump the CS parse tree in the parse struct.
    384  *              This can be useful for debugging your templates.
    385  *              This function also uses the CSOUTFUNC callback to
    386  *              display the parse tree.
    387  * Input: parse - the CSPARSE structure created with cs_init
    388  *        ctx - user data to be passed to the CSOUTFUNC
    389  *        cb - a CSOUTFUNC callback
    390  * Output: None
    391  * Return: NERR_ASSERT if there is no parse tree
    392  *         anything your CSOUTFUNC may return
    393  */
    394 NEOERR *cs_dump (CSPARSE *parse, void *ctx, CSOUTFUNC cb);
    395 
    396 /*
    397  * Function: cs_destroy - clean up and dealloc a parse tree
    398  * Description: cs_destroy will clean up all the memory associated with
    399  *              a CSPARSE structure, including strings passed to
    400  *              cs_parse_string.  This does not clean up any memory
    401  *              allocated by your own CSOUTFUNC or the HDF data
    402  *              structure passed to cs_init.  It is safe to call this
    403  *              with a NULL pointer, and it will leave parse NULL as
    404  *              well (ie, it can be called more than once on the same
    405  *              var)
    406  * Input: parse - a pointer to a parse structure.
    407  * Output: parse - will be NULL
    408  * Return: None
    409  */
    410 void cs_destroy (CSPARSE **parse);
    411 
    412 /*
    413  * Function: cs_register_fileload - register a fileload function
    414  * Description: cs_register_fileload registers a fileload function that
    415  *              overrides the built-in function.  The built-in function
    416  *              uses hdf_search_path and ne_file_load (based on stat/open/read)
    417  *              to find and load the file on every template render.
    418  *              You can override this function if you wish to provide
    419  *              other template search functions, or load the template
    420  *              from an in-memory cache, etc.
    421  *              This fileload function will be used by cs_parse, including
    422  *              any include: commands in the template.
    423  * Input: parse - a pointer to an initialized CSPARSE structure
    424  *        ctx - pointer that is passed to the CSFILELOAD function when called
    425  *        fileload - a CSFILELOAD function
    426  * Output: None
    427  * Return: None
    428  *
    429  */
    430 
    431 void cs_register_fileload(CSPARSE *parse, void *ctx, CSFILELOAD fileload);
    432 
    433 /*
    434  * Function: cs_register_strfunc - register a string handling function
    435  * Description: cs_register_strfunc will register a string function that
    436  *              can be called during CS render.  This not-callback is
    437  *              designed to allow for string formating/escaping
    438  *              functions that are not built-in to CS (since CS is not
    439  *              HTML specific, for instance, but it is very useful to
    440  *              have CS have functions for javascript/html/url
    441  *              escaping).  Note that we explicitly don't provide any
    442  *              associated data or anything to attempt to keep you from
    443  *              using this as a generic callback...
    444  *              The format of a CSSTRFUNC is:
    445  *                 NEOERR * str_func(char *in, char **out);
    446  *              This function should not modify the input string, and
    447  *              should allocate the output string with a libc function.
    448  *              (as we will call free on it)
    449  * Input: parse - a pointer to a CSPARSE structure initialized with cs_init()
    450  *        funcname - the name for the CS function call
    451  *                   Note that registering a duplicate funcname will
    452  *                   raise a NERR_DUPLICATE error
    453  *        str_func - a CSSTRFUNC not-callback
    454  * Return: NERR_NOMEM - failure to allocate any memory for data structures
    455  *         NERR_DUPLICATE - funcname already registered
    456  *
    457  */
    458 NEOERR *cs_register_strfunc(CSPARSE *parse, char *funcname, CSSTRFUNC str_func);
    459 
    460 /*
    461  * Function: cs_register_esc_strfunc - cs_register_strfunc with escaping context
    462  * Description: cs_register_esc_strfunc functions exactly as cs_register_strfunc
    463  *              except that it changes the evaluation escaping context to disable
    464  *              default escaping.
    465  * Input: parse - a pointer to a CSPARSE structure initialized with cs_init()
    466  *        funcname - the name for the CS function call
    467  *                   Note that registering a duplicate funcname will
    468  *                   raise a NERR_DUPLICATE error
    469  *        str_func - a CSSTRFUNC not-callback
    470  * Return: NERR_NOMEM - failure to allocate any memory for data structures
    471  *         NERR_DUPLICATE - funcname already registered
    472  *
    473  */
    474 NEOERR *cs_register_esc_strfunc(CSPARSE *parse, char *funcname,
    475                                 CSSTRFUNC str_func);
    476 
    477 /* Testing functions for future function api.  This api may change in the
    478  * future. */
    479 NEOERR *cs_arg_parse(CSPARSE *parse, CSARG *args, const char *fmt, ...);
    480 NEOERR *cs_arg_parsev(CSPARSE *parse, CSARG *args, const char *fmt, va_list ap);
    481 NEOERR *cs_register_function(CSPARSE *parse, const char *funcname,
    482                                   int n_args, CSFUNCTION function);
    483 
    484 __END_DECLS
    485 
    486 #endif /* __CSHDF_H_ */
    487