/* * Copyright (c) 2001-2002 Packet Design, LLC. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, * use and redistribution of this software, in source or object code * forms, with or without modifications are expressly permitted by * Packet Design; provided, however, that: * * (i) Any and all reproductions of the source or object code * must include the copyright notice above and the following * disclaimer of warranties; and * (ii) No rights are granted, in any manner or form, to use * Packet Design trademarks, including the mark "PACKET DESIGN" * on advertising, endorsements, or otherwise except as such * appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Author: Archie Cobbs */ #ifndef _PDEL_TMPL_TMPL_H_ #define _PDEL_TMPL_TMPL_H_ /* * This code supports a simple text template language. An input file * is scanned for special function tags. A function tag is an at sign * ('@') followed by a contiguous sequence of letters, digits, and * underscores, followed by parentheses containing zero or more * function arguments. * * Function arguments may be either other function tags (the argument * to the outer function is the result of the inner function invocation), * or constant literal strings in double quotes (the argument is the * value of the string). Note this means that all function arguments * begin with either an at sign or a double quote character. Function * arguments are enclosed in parentheses, separated by commas, and * may have whitespace around them. * * When processed, function tags result in a function invocation * which returns some text which is then substituted into the output * stream. Special control flow function tags control input processing * and return the empty string. * * Non-function tag text input is passed through unaltered. * * Constant literal strings (enclosed in double quotes) respect the * normal C backslash escapes. * * Built-in functions that take no arguments do not require parentheses, * but parentheses may be included for separation purposes. * * User-supplied functions may return NULL and set errno to indicate * an error, in which case the corresponding error string is substituted, * after being formatted by the caller-supplied error formatter. * * The predefined functions are: * * @while(x) ... @endwhile * The text in between is repeated as long as x is true * (x is true if it is an integer whose value is non-zero). * * @loop(numloops) ... @endloop * The text in between is repeated 'numloops' times, which * must be an integer value. * * @loopindex(i) * Returns the loop index (counting from zero) of the loop * that is 'i' loops out from the innermost loop, else -1. * If argument is omitted it is assumed to be zero. * * @if(x) ... [ @elif ... [ @elif ... ] ] [ @else ... ] @endif * Conditional execution depending on the truth value of x. * * @define(name) ... @enddef * Defines a run-time function. The text in between is executed * whenever @name(...) is subsequently invoked. During this execution, * the variables "argc" and "arg0", "arg1", ... are set to the * function argument count and arguments, respectively (the function * name itself is always the value of "arg0". * * @break * Break out of the nearest enclosing @loop or @while loop. * * @continue * Continue with the next iteration of the nearest enclosing * @loop or @while loop. * * @return * Return from within a run-time function. * * @equal(x,y) * Returns "1" if x and y are identical, else "0". * * @not(x) * Returns "1" unless x is an integer whose value is non-zero. * * @and(arg1, arg2, ...) * Returns logical "and" of the truth values of the arguments. * * @or(arg1, arg2, ...) * Returns logical "or" of the truth values of the arguments. * * @add(arg1, ...) * Returns sum of the numerical values of the arguments. * * @mul(arg1, ...) * Returns product of the numerical values of the arguments. * * @div(arg1, arg2) * Returns the first argument divided by the second. * * @mod(arg1, arg2) * Returns the first argument modulo by the second. * * @lt(arg1, arg2) * @gt(arg1, arg2) * @le(arg1, arg2) * @ge(arg1, arg2) * Returns "0" or "1" as arg1 is <, >, <=, or >= arg2. * * @sub(arg1, ...) * Returns subtraction of the numerical values of the second * and subsequent arguments from the first. * * @error(arg) * Output the argument using the caller's error formatting. * * @eval(arg) * The argument itself is processed. Embedded function tags * are processed normally, while the rest is passed unaltered. * * @funcname(arg1, arg2, ...) * Invoke the generic user-supplied function handler. * * @@ * Expands to ``@'' * * @cat(arg1, arg2, ...) * Returns concatentated arguments. * * @set(var, value) * Sets run-time variable 'var' to have value 'value'. Variables * are global and live until tmpl_process() returns. Returns the * empty string. * * @get(var) * Retrieves the value of run-time variable 'var'. * Returns the empty string if 'var' is not set. * * @urlencode(arg) * Expands and URL-encodes the argument. * * @htmlencode(arg) * Expands and HTML-encodes the first argument. * * @output(arg) * Outputs the argument directly to the output stream. That is, * if this function is invoked from within a user-defined function, * the argument goes directly to the template output rather than * being concatenated to the return value of the function. * * @flush() * Flushes the template output. * * @foobar(...) * If "foobar" is not defined as a run-time function, then this * invokes the supplied handler for user-defined functions. * Here "foobar" is any name other than the above function names, * consisting of only letters, digits, and underscores. * */ struct tmpl; struct tmpl_ctx; #define TMPL_FUNCTION_CHARACTER '@' /*********************************************************************** CALLBACK FUNCTION TYPES ***********************************************************************/ /* * Generic function handler type. Should return a malloc'd string (allocated * with the same memory type as passed to tmpl_ctx_create()), or else return * NULL and either set errno or set *errmsgp to point to a malloc'd string * (same memory type) containing an error message. *errmsgp will be NULL * initially. * * The first argument is the function name. Subsequent arguments are the * (evaluated) arguments passed to the function. Note that this means "argc" * is always >= 1. argv[argc] is NOT guaranteed to be NULL. */ typedef char *tmpl_handler_t(struct tmpl_ctx *ctx, char **errmsgp, int argc, char **argv); /* * Error formatter type. This should format the error message string * using whatever formatting is desired and return the result in a * malloc'd buffer (note: just returning 'errmsg' is wrong; use * strdup(3) instead). Return NULL and set errno if there is an error. * The "arg" parameter is the same "arg" passed to tmpl_ctx_create(). */ typedef char *tmpl_errfmtr_t(struct tmpl_ctx *ctx, const char *errmsg); /*********************************************************************** PUBLIC FUNCTIONS ***********************************************************************/ __BEGIN_DECLS /* * Create template object by parsing "input". The input stream must * be seekable, and is not used again after this function returns. * * If num_errors != NULL, it will be set to the number of parse * errors encountered while parsing the input. * * Returns NULL and sets errno on failure. */ extern struct tmpl *tmpl_create(FILE *input, int *num_errors, const char *mtype); /* * Similar to tmpl_create(), but memory map the file so that its * contents don't have to be stored in heap memory. However, the * file contents must not change or else subsequent executions will * give garbled output. */ extern struct tmpl *tmpl_create_mmap(const char *path, int *num_errors, const char *mtype); /* * Destroy and free a template file created by tmpl_create(). * * Upon return, *tmplp is set to NULL. If *tmplp is already NULL, * this does nothing. */ extern void tmpl_destroy(struct tmpl **tmplp); /* * Create a template execution context. * * For all functions that are not predefined, the function is looked up * in the 'userfuncs' array (which is not copied and so must remain * valid for the life of the exectution context). This array must be * sorted by name and terminated with an entry having a NULL name. * All userfuncs will have 'arg' passed as their first argument. * * All strings returned by "handler" MUST be dynamically allocated * using memory type 'mtype'. * * The 'errfmtr' is called to specially format any generated error * messages; if it is NULL, error messages are output as plain text. */ extern struct tmpl_ctx *tmpl_ctx_create(void *arg, const char *mtype, tmpl_handler_t *handler, tmpl_errfmtr_t *errfmtr); /* * Get context argument. */ extern void *tmpl_ctx_get_arg(struct tmpl_ctx *ctx); /* * Get context memory type. */ extern const char *tmpl_ctx_get_mtype(struct tmpl_ctx *ctx); /* * Execute a template and output the result to 'output'. * * If a system error is encountered, execution halts and -1 * is returned with 'errno' set. Otherwise, zero is returned. * * Flags: * * TMPL_SKIP_NL_WHITE Skip inter-function text consisting only of * one or more newlines followed by whitespace. */ extern int tmpl_execute(struct tmpl *tmpl, struct tmpl_ctx *ctx, FILE *output, int flags); #define TMPL_SKIP_NL_WHITE 0x0001 /* * Destroy and free a template context created by tmpl_ctx_create(). * * Upon return, *ctxp is set to NULL. If *ctxp is already NULL, * this does nothing. */ extern void tmpl_ctx_destroy(struct tmpl_ctx **ctxp); /* * Functions to get and set variables associated with a context. */ extern const char *tmpl_ctx_get_var(struct tmpl_ctx *ctx, const char *name); extern int tmpl_ctx_set_var(struct tmpl_ctx *ctx, const char *name, const char *value); /* * Invoke a template function and write the output to "output". * * Returns zero if successful, otherwise returns -1 and either * sets *errmsgp to NULL and errno to the error code, or else * sets *errmsgp to some appropriate error message. */ extern int tmpl_execute_func(struct tmpl_ctx *ctx, FILE *output, char **errmsgp, int argc, char **argv, int flags); /* * Reset a template context. * * This undoes the result of any variable assignments and run-time * function definitions from a previous execution using the context. * That is, the context is returned to original state as returned by * tmpl_ctx_create(). */ extern void tmpl_ctx_reset(struct tmpl_ctx *ctx); /* * Built-in handler for handling a fixed list of user functions. * * The 'userfuncs' array must be sorted lexicographically by name. */ /* Structure describing a user-supplied function */ struct tmpl_func { const char *name; /* function name, null to end list */ u_int min_args; /* min # args (not counting name) */ u_int max_args; /* max # args (not counting name) */ tmpl_handler_t *handler; /* handler for function */ }; extern char *tmpl_list_handler(struct tmpl_ctx *ctx, const struct tmpl_func *userfuncs, u_int uflen, char **errmsgp, int argc, char **argv); __END_DECLS #endif /* _PDEL_TMPL_TMPL_H_ */