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