/*
* 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 <archie@freebsd.org>
*/
#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_ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>