• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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