OSSP CVS Repository

ossp - Difference in ossp-pkg/var/var.pod versions 1.20 and 1.21
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/var/var.pod 1.20 -> 1.21

--- var.pod      2002/02/27 13:44:16     1.20
+++ var.pod      2002/02/28 08:08:16     1.21
@@ -35,841 +35,642 @@
 
 =head1 SYNOPSIS
 
-var_rc_t var_unescape(const char *src, size_t len, char *dst, int unescape_all);
+=over 2
 
-var_rc_t var_expand(const char *input, size_t input_len, char **result, size_t *result_len, var_cb_t lookup, void *lookup_context, const var_config_t *config, int force_expand);
+=item Types:
 
-const char *var_strerror(var_rc_t rc);
+B<var_rc_t>,
+B<var_t>,
+B<var_config_t>,
+B<var_syntax_t>,
+B<var_cb_value_t>.
 
-=head1 DESCRIPTION
-
-The routines included in this library, var_unescape() and
-var_expand(), enable application developers to make use of variable
-expansion in an arbitrary text buffer. Assume, for instance, your
-application provided the data items
-
-    HOST   = peti.example.org
-    OSTYPE = FreeBSD
-    HOME   = /home/my-application
-
-and you had obtained the following message from the user via means of
-a configuration file, the system environment, or the command line:
-
-    My-application starting up with the following configuration:
-
-        HOST   = $HOST
-        OSTYPE = $OSTYPE
-        HOME   = $HOME
-
-Then you could use var_expand() to replace the variables in that
-message by their actual contents.
-
-The good thing about this kind of approach is that you separate the
-actual information in a message from the message's layout, language,
-or content encoding. If the user doesn't like messages as long the one
-above, he'd simply provide the template
-
-    my-application: $HOST ($OSTYPE), $HOME
-
-to get the result, he's interested in. Maybe all he's interested in
-is:
-
-    my-application's home is $HOME
-
-To take things one step further, OSSP var provides the user -- the
-person providing the template file, that is -- with powerful
-mechanisms to modify the presentation of the variable's contents. For
-example, the expression ${HOME:l} would yield the contents of the
-variable HOME converted to all lower-case. Or, to show on even more
-powerful construct: The expression ${HOME:y/ \t/__/} would turn all
-blanks or tabs in the contents of HOME to underscores, before
-inserting it into the output text.
-
-Similarly, the function var_unescape() will expand "quoted pairs",
-thus allowing the user to speficy non-printable characters is a
-template, such as the carrige return ('\r'), the newline ('\n'), or --
-as seen above -- the tab ('\t').
-
-Using these two routines in combination, gives the application
-developer the power to have the user custumize the application's
-messages as he or she sees fit at virtually no extra cost;
-incorporating a template mechanism into your own applications with
-OSSP var is extremely simple.
-
-=head1 THE VAR_UNESCAPE FUNCTION
-
-The purpose of var_unescape() is to expand any quoted pairs found in
-the input buffer. Its prototype is:
-
-    var_rc_t var_unescape(const char *src, size_t len,
-                          char *dst, int unescape_all);
-
-The first parameter, "src", is a pointer to the input buffer, which
-should be processed. Unlike most C library functions, var_unescape()
-does not expect the buffer to be terminated by a null byte ('\0'),
-instead, it expects the length of the buffer's contents as parameter
-"len". The third parameter, "dst" is a pointer to a buffer, into which
-the expanded buffer is copied if processing is successful. The size of
-this buffer must be at least len+1 characters. The reason the result
-buffer has to be one byte longer than the input buffer is that
-var_unescape() always adds a terminating null byte at the end of the
-output buffer, so that you can use the result comfortably with other C
-library routines.
-
-The last parameter, "unescape_all", is flag that modifies the behavior
-of var_unescape(). If is set to TRUE (any value except zero, that is),
-var_unescape() will expand B<any> quoted pair it sees, even those that
-it does not know about. Hence, a "\1" will become a "1", even though
-"\1" has no special meaning to var_unescape(). If "unescape_all" is
-set to FALSE (zero), such quoted pairs will be copied verbatimly to
-the output buffer.
-
-The quoted pairs supported by var_unescape() are '\t', '\r', '\n',
-'\abc' (octal), '\xAB' (hexadecimal), and '\x{...}' (grouped
-hexadecimal). Please refer to section "SUPPORTED NAMED CHARACTERS" for
-a more comprehensive description of these quoted pairs.
-
-If var_unescape() encounters any syntax errors, it will return an
-error code denoting exactly what kind of error occured; please refer
-to section "CODES RETURNED BY THE LIBRARY" for a complete list of
-possible return codes. If no error occured, VAR_OK is returned.
-
-=head1 THE VAR_EXPAND FUNCTION
-
-The second function of OSSP var is var_expand(), the routine that will
-expand any variables found in a text buffer to their actual contents.
-Its prototype is:
-
-    var_rc_t var_expand(const char *input, size_t input_len,
-                        char **result, size_t *result_len,
-                        var_cb_t lookup, void *lookup_context,
-                        const var_config_t *config,
-                        int force_expand);
-
-Don't be scared, the usage is way simpler than it looks at first
-glance. The parameters of var_expand() are:
+=item Functions:
 
-=over 4
+B<var_create>,
+B<var_destroy>,
+B<var_config>,
+B<var_unescape>,
+B<var_expand>, 
+B<var_strerror>.
 
-=item const char *input
+=item Variables:
 
-A pointer to the text buffer containing the variable expressions to be
-expanded. Unlike in most other C library functions, this text buffer
-need not be terminated by a null byte.
-
-=item size_t input_len
-
-The length of the text buffer's contents.
-
-=item char **result
-
-A pointer to a character pointer in which the location of the expanded
-text buffer will be stored. The result buffer will be allocated by
-var_expand() using the system call malloc(3), thus it is the caller's
-responsibility to free(3) that buffer once it is not used anymore. The
-result buffer will be terminated by null byte, which is not included
-in the "result_len" counter.
-
-If var_expand() fails with an error, "result" will point to "input".
-The only exceptions are the VAR_ERR_INVALID_ARGUMENT
-VAR_ERR_OUT_OF_MEMORY errors, in which case "result" is undefined.
-
-=item size_t *result_len
-
-A pointer to the location in which the length of the expanded text
-buffer will be stored. If var_expand() fails with an error -- with the
-exception of VAR_ERR_INVALID_ARGUMENT and VAR_ERR_OUT_OF_MEMORY --,
-"result_len" will contain the number of characters that have been
-consumed from "input" before the error occured. This argument can be
-NULL if the application is not interested in this information.
-
-=item var_cb_t lookup
-
-A pointer to the function used to perform the actual variable lookup.
-Please refer to section "THE LOOKUP CALLBACK" for a comprehensive
-description.
-
-=item void *lookup_context
-
-An arbitrary value passed through to "lookup" every time it is called.
-Please refer to section "THE LOOKUP CALLBACK" for a comprehensive
-description.
-
-=item const var_config_t *config
-
-The configuration of var_expand(). The var_config_t structure is
-defined as follows:
-
-    typedef struct {
-        char varinit;
-        char startdelim;
-        char enddelim;
-        char startindex;
-        char endindex;
-        char current_index;
-        char escape;
-        char *namechars;
-    } var_config_t;
-
-Using this structure, you can modify the parser to use different
-tokens to find variable constructs. If "config" is NULL, the default
-configuration will be used, which you can access through the
-declaration
-
-    extern const var_config_t var_config_default;
-
-in var.h. The default configuration for var_init looks like this:
-
-    const var_config_t var_config_default = {
-        '$',              /* varinit */
-        '{',              /* startdelim */
-        '}',              /* enddelim */
-        '[',              /* startindex */
-        ']',              /* endindex */
-        '#',              /* current_index */
-        '\\',             /* escape */
-        "a-zA-Z0-9_"      /* namechars */
-    };
-
-Please note that the setting of var_config_t.escape is actually a
-single backslash; the quote above has been taken from the C source
-code, which is why the backslash had to be escaped with another
-backslash for the C pre-processor.
-
-=item int force_expand
-
-This flag determines how var_expand() deals with undefined variables.
-If it is set to TRUE (any value but zero), var_expand() will fail with
-error code VAR_ERR_UNDEFINED_VARIABLE whenever an undefined variable
-is encountered. If set to FALSE (zero), var_expand() will copy the
-expression it failed to expand verbatimly into the output buffer, in
-order to enable you to go over the buffer with an additional pass.
-
-Generally, if you do not plan to use muli-pass expansion, you should
-set "force_expand" to TRUE in order to make sure no unexpanded
-variables are left over in the buffer.
+B<var_id>.
 
 =back
 
-var_expand() returns VAR_OK if everything went fine, and one of the
-error codes described in section "CODES RETURNED BY THE LIBRARY" if
-the function call failed.
-
-=head1 THE VAR_STRERROR FUNCTION
-
-In order to make life for application developers easier, the helper
-function var_strerror() has been provided, which can be used to map
-any of the error codes returned by the OSSP var library into a
-clear-text message describing the reason for failure. Please note that
-errors coming from the callback, such as VAR_ERR_CALLBACK and those
-based on it, cannot be mapped and will yield the message "unknown
-error".
-
-=head1 COMBINING VAR_UNESCAPE AND VAR_EXPAND
-
-For maximum power and flexibility, you will want to use both routines
-provided by this library in combination. That is, you will want to use
-var_unescape() to turn all quoted pairs into their real
-representation, before you call var_expand(), because then the user
-can safely use specials like "\n" or "\t" throughout the template and
-achieve the desired effect. These quoted pairs are particularly useful
-if search-and-replace or transpose actions are performed on variables
-before they're expanded. Be sure, though, to make the first
-var_unescape() pass with "expand_all" set to FALSE, or the routine
-will also expand quoted pairs like "\1", which might have a special
-meaning in the var_expand() pass to follow.
-
-Once, all known quoted pairs are expanded, expand the variables with
-var_expand(). After that, you will want to have a second pass with
-var_unescape() and "expand_all" set to TRUE, to make sure all
-remaining quoted pairs are expanded. Also, the var_expand() pass might
-have introduced now quoted pairs into the output text, which you need
-to expand to get the desired effect.
-
-Take a look at this code snipped, to see how to combine var_unescape()
-und var_expand() properly:
-
-    var_rc_t rc;
-    char* result;
-    size_t result_len;
-
-    if ((rc = var_unescape(input, strlen(input), output, 0)) != VAR_OK ||
-        (rc = var_expand(output, strlen(output),
-                         &result, &result_len,
-                         &lookup, NULL,
-                         NULL, 1)) != VAR_OK ||
-        (rc = var_unescape(input, strlen(input), output, 1)) != VAR_OK)
-    {
-        printf("Expanding the template failed with error %d.\n", rc);
-        exit(1);
-    }
-    [...]
-    free(result);
-
-=head1 THE LOOKUP CALLBACK
-
-The function var_expand() does not know how to look the contents of a
-variable up itself. Instead, it relies on a caller-supplied callback
-function, which adheres to the var_cb_t function interface:
-
- var_rc_t lookup(void *context,
-                 const char *varname, size_t name_len, int index,
-                 const char **data, size_t *data_len,
-                 size_t *buffer_size);
-
-This function will be called by var_expand() whenever it has to
-retrieve the contents of, say, the variable $name, using the following
-parameters:
-
-=over 4
-
-=item void *context
-
-The contents of context is passed through from the var_expand()'s
-"lookup_context" parameter to the callback. This parameter can be used
-by the programmer to provide internal data to the callback function
-through var_expand().
-
-=item const char *varname
-
-This is a pointer to the name of the variable which's contents
-var_expand() wishes to retrieve. In our example of looking up $name,
-varname would point to the string "name". Please note that the string
-is NOT necessarily terminated by a '\0' character! If the callback
-function needs to pass the string to the standard C library string
-manipulation functions during the lookup, it will have to copy the
-string into a buffer of its own to ensure it is null-terminated.
-
-=item size_t name_len
-
-The "name_len" parameter contains the length of the variable name
-"varname" points to.
-
-=item int index
-
-The contents of this interger determines which entry of a variable
-array to look-up. If the variable specification that led to the
-execution of the lookup function did not contain an index, zero is
-provided per default. If "index" is negative, the callback must return
-the number of entries of the variable array.
-
-=item const char **data
-
-This is a pointer to the location where the callback function should
-store the pointer to the contents of the variable.
-
-=item size_t *data_len
-
-This is a pointer to the location where the callback function should
-store the length of the contents of the variable.
-
-=item size_t *buffer_size
-
-This is a pointer to the location where the callback function should
-store the size of the buffer that has been allocated to hold the
-contents of the looked-up variable. If no buffer has been allocated at
-all, because the variable uses some other means of storing the
-contents -- as in the case of getenv(3), where the system provides the
-buffer for the string --, this should be zero (0).
-
-In case a buffer size greater than zero is returned by the callback
-function, var_expand() will make use of that buffer internally if
-possible. If will also free(3) the buffer when it is not needed
-anymore.
-
-=back
-
-The return code of the lookup function is interpreted by var_expand()
-according to the following convention: VAR_OK means success, that
-is, the contents of the variable has been looked-up successfully and
-the "data", "data_len", and "buffer_size" locations have been filled
-with appropriate values. A return code VAR_ERR_XXX means that the lookup
-failed, such as a system error or lack of resources. In the latter two
-cases, the contents of "data", "data_len" and "buffer_size" is assumed
-to be undefined. Hence, var_expand() will not free(3) any possibly
-allocated buffers, the callback must take care of that itself.
-
-If a callback returns the special VAR_ERR_UNDEFINED_VARIABLE return
-code, the behaviour of var_expand() depends on the setting of
-the "force_expand" parameter. If force-expand mode has been set,
-var_expand() will fail with this error. If force-expand mode has
-not been set, var_expand() will copy the expression that caused the
-lookup to fail verbatimly into the output buffer so that an additional
-expanding pass may expand it later.
-
-If the callback returns an VAR_ERR_XXX, var_expand() will fail with the return
-code it got from the callback.  If the cause for the error can not be denoted
-by an error code defined in var.h, callback implementors should use the error
-code VAR_ERR_CALLBACK, which is currently defined to -64. It is guaranteed
-that no error code smaller than VAR_ERR_CALLBACK is ever used by var_expand()
-or VAR_UNESCAPE(), so if the callback implementor wishes to distinguish
-between different reasons for failure, he can define his own set of errors
-
-    typedef enum {
-        LOOKUP_ERROR_ONE   = -3,
-        LOOKUP_ERROR_TWO   = -2,
-        LOOKUP_ERROR_THREE = -1,
-    } lookup_error_t;
-
-and return, say, "(VAR_ERR_CALLBACK - LOOKUP_ERROR_TWO)".
-
-To illustrate the implementation of a proper callback, take a look at
-the following expamle that accesses the system environment via
-getenv(3) to lookup variables and to return them to var_expand():
-
-    var_rc_t env_lookup(
-        void *context,
-        const char *varname, size_t name_len, int idx,
-        const char **data, size_t *data_len,
-        size_t *buffer_size)
-    {
-        char tmp[256];
-
-        if (idx != 0)
-            return VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED;
-        if (name_len > sizeof(tmp) - 1)
-            return VAR_ERR_CALLBACK;
-        memcpy(tmp, varname, name_len);
-        tmp[name_len] = '\0';
-        if ((*data = getenv(tmp)) == NULL)
-            return VAR_ERR_UNDEFINED_VARIABLE;
-        *data_len = strlen(*data);
-        *buffer_size = 0;
-        return VAR_OK;
-    }
-
-=head1 SUPPORTED NAMED CHARACTERS
-
-The var_unescape() function knows the following constructs:
-
-=over 4
-
-=item \t, \r, \n
-
-These expressions are replaced by the appropriate binary
-representation of a tab, a carrige return and a newline respectively.
-
-=item \abc
-
-This expression is replaced by the value of the octal number "abc".
-Valid digits of "a" are in the range of '0' to '3', for digits "b" and
-"c" in the range of '0' to '7'. Please note that an octal expression
-is recognized only if the backslash is followed by three digits! The
-expression "\1a7", for example, is interpreted as the quoted pair "\1"
-followed by the verbatim text "a7".
-
-=item \xAB
-
-This expression is replaced by the value of the hexadecimal number
-$AB. Both characters "A" and "B" must be in the range of '0' to '9',
-'a' to 'f', or 'A' to 'F'.
-
-=item \x{...}
-
-This expression denotes a set of grouped hexadecimal numbers. The
-"..." part may consist of an arbitrary number of hexadecimal pairs,
-such as in "\x{}", "\x{ff}", or "\x{55ffab04}". The empty expression
-"\x{}" is a no-op; it will not produce any output.
-
-This construct may be useful to specify multi-byte characters (as in
-Unicode). Even though "\x{0102}" is effectively equivalent to
-"\x01\x02", the grouping of values may be useful in other contexts,
-even though var_unescape() or var_expand() make no direct use of it.
-
-=back
+=head1 DESCRIPTION
 
-=head1 SUPPORTED VARIABLE EXPRESSIONS
+B<OSSP var> is a flexible, full-featured and fast variable construct
+expansion library.
 
-Additionally to the ordinary variable expansion of $name or ${name},
-var_expand() supports a number of operations that can be performed on
-the contents of "name" before it is copied to the output buffer. Such
-operations are always denoted by appending the a colon and a command
-character to the variable name, for expample: ${name:l} or
-${name:s/foo/bar/}. You can specify multiple operations, which are
-executed from the left to the right, for expample:
-${name:l:s/foo/bar/:u}.
-
-Also, you can nest variable expansion and command execution pretty
-much anywhere in the construct, for example: ${name:s/$foo/$bar/g}. In
-that context is probably useful to have a look at the formal
-expression grammar provided in section "EBNF GRAMMAR OF SUPPORTED
-EXPRESSIONS".
-
-Generally, all operations described below do not modify the contents
-of any variable -- var_expand() generally can't set variables, it will
-only read them. If the description says that an operation "replaces
-the contents of variable $foo", it is meant that rather than expanding
-the expression the the contents of $foo, it will expand to the
-modified string instead. The contents of $foo is left untouched in any
-case.
+It supports a configurable variable construct syntax very similar
+to the style found in many scripting languages (like C<@>I<name>,
+C<${>I<name>C<}>, C<$(>I<name>C<)>, etc.) and provides both simple
+scalar (C<${>I<name>C<}>) and array (C<${>I<name>C<[>I<index>C<]}>)
+expansion, plus optionally one or more post-operations on the expanded
+value (C<${>I<name>C<:>I<op>[C<:>I<op>...]]C<}>).
+
+The supported post-operations are length determination, case
+conversion, defaults, postive and negative alternatives, sub-strings,
+regular expression based substitutions, character translations, and
+padding. Additionally, a meta-construct plus arithmetic expressions for
+index and range calculations allow (even nested) iterations over array
+variable expansions (..C<[>..C<${>I<name>C<[#+1]}>..C<]>..).
+
+The actual variable value lookup is performed through a callback
+function, so B<OSSP var> can expand arbitrary values.
+
+=head1 SYNTAX CONSTRUCTS
+
+A string expanded through B<OSSP var> can consist of arbitrary text
+characters plus one or more of the following special syntax constructs
+which are expanded by B<OSSP var>.
 
 =over 4
 
-=item ${name:#}
-
-This operation will expand to the length of the contents of $name. If,
-for example, "$FOO" is "foobar", then "${FOO:#}" will result in "6".
-
-=item ${name:l}
-
-This operation will turn the contents of $name to all lower-case,
-using the system routine tolower(3), thereby possibly using the
-system's localization settings.
-
-=item ${name:u}
-
-This operation will turn the contents of $name to all upper-case,
-using the system routine toupper(3), thereby possibly using the
-system's localization settings.
-
-=item ${name:*<word>}
-
-This operation will replace the contents of $name with the empty
-string ("") if $name is not empty. Otherwise, it will replace it by
-"word".
-
-=item ${name:-<word>}
-
-This operation will replace the contents of $name with "word" if $name
-is empty. Otherwise, it will expand to the contents of $name.
-
-=item ${name:+<word>}
-
-This operation will replace the contents of $name with "word" if $name
-is not empty. Otherwise, it will expand to the contents of $name.
-
-=item ${name:o<start>-<end>}
-
-This operation will cut the string starting at position "start" to
-ending position "end" out of the contents of $name and return that.
-Please note that the character at position "end" is included in the
-result; ${name:o3-4} for instance, will return a two-character string.
-Also, please note that start positions begin at zero (0)! If the "end"
-parameter is left out, as in ${name:o3-}, the operation will return the
-string starting at position 3 until the end.
-
-=item ${name:o<start>,<length>}
-
-This operation will cut the string starting at position "start"
-of length "length" out of the contents of $name and return that.
-${name:o3,4} means, for instance, to return the next 4 characters
-starting at position 3 in the string. Please note that start positions
-begin at zero (0)! If "length" is left out, as in ${name:o3,}, the
-operation will return the string starting at position 3 until the end.
-
-=item ${name:s/<pattern>/<string>/[gti]}
-
-This operation will perform a search-and-replace operation on the
-contents of $name and return the result. The behavior of the
-search-and-replace is modified by the following flags parameter: If a
-'t' flag has been provided, a plain text search-and-replace is
-performed, otherwise, the default is to a regular expression
-search-and-replace as in the system utility sed(1). If the 'g' flag
-has been provided, the search-and-replace will replace all instances
-of "pattern" by "replace", otherwise, the default is to replace only
-the first instance. If the 'i' flag has been provided, the
-search-and-replace will take place case-insensitively, otherwise, the
-default is to distinguish character case.
-
-=item ${name:y/<ochars>/<nchars>/}
-
-This operation will translate all characters in the contents of $name
-that are found in the "ochars" class to the corresponding character in
-the "nchars" class, just like the system utility tr(1) does. Both
-"ochars" and "nchars" may contain character range specifications, for
-example "a-z0-9". A hyphon as the first or last character of the class
-specification is interpreted literally. Both the "ochars" and the
-"nchars" class must contain the same number of characters after all
-ranges are expanded, or var_expand() will abort with an error.
-
-If, for example, "$FOO" would contain "foobar", then
-"${FOO:y/a-z/A-Z/} would yield "FOOBAR". Another goodie is to use that
-operation to ROT13-encrypt or decrypt a string with the expression
-"${FOO:y/a-z/n-za-m/}".
-
-=item ${name:p/<width>/<string>/<align>}
-
-This operation will pad the contents of $name with "string" according
-to the "align" parameter, so that the result is at least "width"
-characters long. Valid parameters for align are 'l' (left), 'r'
-(right), or 'c' (center). The "string" parameter may contain multiple
-characters, if you see any use for that.
-
-If, for example, "$FOO" is "foobar", then "${FOO:p/20/./c}" would
-yield ".......foobar......."; "${FOO:p/20/./l}" would yield
-"foobar.............."; and "${FOO:p/20/./r}" would yield
-"..............foobar";
-
-=back
-
-=head1 EBNF GRAMMAR OF SUPPORTED EXPRESSIONS
-
- input      : ( TEXT | variable | START-INDEX input END-INDEX ( loop-limits )? )*
-
- loop-limits: START-DELIM (numexp)? ',' (numexp)? ( ',' (numexp)? )? END-DELIM
-
- variable   : '$' (name|expression)
-
- expression : START-DELIM (name|variable)+ (START-INDEX num-exp END-INDEX)? (':' command)* END-DELIM
-
- name       : (VARNAME)+
-
- command    : '-' (EXPTEXT|variable)+
-            | '+' (EXPTEXT|variable)+
-            | 'o' (NUMBER ('-'|',') (NUMBER)?)
-            | '#'
-            | '*' (EXPTEXT|variable)+
-            | 's' '/' (variable|SUBSTTEXT)+ '/' (variable|SUBSTTEXT)* '/' ('g'|'i'|'t')*
-            | 'y' '/' (variable|SUBSTTEXT)+ '/' (variable|SUBSTTEXT)* '/'
-            | 'p' '/' NUMBER '/' (variable|SUBSTTEXT)* '/' ('r'|'l'|'c')
-            | 'l'
-            | 'u'
-
- num-exp    : operand
-            | operand ('+'|'-'|'*'|'/'|'%') num-exp
-
- operand    : ('+'|'-')? NUMBER
-            | CURR-INDEX
-            | '(' num-exp ')'
-            | variable
-
- START-DELIM: '{'
-
- END-DELIM  : '}'
-
- START-INDEX: '['
-
- END-INDEX  : ']'
-
- CURR-INDEX : '#'
-
- VARNAME    : '[a-zA-Z0-9_]+'
+=item C<\>I<NNN>
 
- NUMBER     : '[0-9]+'
+Character with the octal value I<NNN> 
+(I<N>: C<0>,...,C<7>).
 
- SUBSTTEXT  : '[^$/]'
+=item C<\x>I<NN>, C<\x{>I<NNMM..>C<}>
 
- EXPTEXT    : '[^$}:]+'
+Character with the hexadecimal value I<NN> or the characters
+denoted by grouped hexadecimal numbers I<NNMM..>. (I<N>, I<M>:
+C<0>,...,C<9>,[C<aA>],...,[C<fF>]).
 
- TEXT       : '[^$[\]]+'
+=item C<\t>, C<\r>, C<\n>
 
-Please note that the descriptions of START-DELIM, END-DELIM, VARNAME,
-SUBSTEXT, and EXPTEXT shown here assume that var_expand() has been
-called in the default configuration. In thruth, the contents of
-VARNAME corresponds directly to the setting of "namechars" in the
-var_config_t structure. Similarly, the dollar ('$') corresponds
-directly to the setting of "varinit", and the '{' and '}' characters
-to "startdelim" and "enddelim" respectively.
+Tabulator, Carriage Return and Newline character.
 
-=head1 CODES RETURNED BY THE LIBRARY
+=item C<\\>, C<\>I<x>
 
-Generally, all routines part of that library follow the convention
-that a return code of zero or greater denotes success and a return
-code of less than zero denotes failure. (This is slightly different
-for the callbacks, please see section "THE LOOKUP CALLBACK" for
-further details.) In order to distinguish the various causes of
-failure, the following set of defines is provided in var.h:
+Ordinary character C<\> and I<x>.
 
-=over 4
-
-=item VAR_OK
+=item C<$>I<name>, C<${>I<name>C<}>
 
-No errors; everything went fine.
+Contents of scalar variable I<name>.
 
-=item VAR_ERR_INCOMPLETE_QUOTED_PAIR
+=item C<${>I<name>C<[>I<index>C<]>C<}>
 
-The configured escape character as the last character in the input
-buffer.
+Contents of array variable I<name> at position I<index>.
+For I<index> full arithmetic expressions are allowed.
 
-=item VAR_ERR_INVALID_ARGUMENT
+=item C<${>I<name>C<:#}>
 
-Any of the provided arguments is invalid, for expample: the pointer to
-the input buffer is NULL.
+Length of C<$>I<name>.
 
-=item VAR_ERR_SUBMATCH_OUT_OF_RANGE
+=item C<${>I<name>C<:l}>, C<${>I<name>C<:u}>
 
-During execution of a ${name:s/pattern/replace/flags} operation, a
-submatch has been referenced in the "replace" part, which's number is
-greater than the number of submatches encountered in the "pattern"
-part, for expample: ${name:s/foo(bar)/\2/}.
+C<$>I<name>, converted to all lower-case or all upper-case.
 
-=item VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE
+=item C<${>I<name>C<:->I<word>C<}>
 
-During execution of a ${name:s/pattern/replace/flags} operation, the
-parser encountered an unknown quoted pair in the "replace" part. Valid
-quoted pairs are "\\", "\0", "\1", ... , "\9" only.
+If C<$>I<name> is not empty string, then C<$>I<name>, else I<word>
+(default value).
 
-=item VAR_ERR_EMPTY_PADDING_FILL_STRING
+=item C<${>I<name>C<:+>I<word>C<}>
 
-The "fill" part in an ${name:p/width/fill/pos/} expression was found
-to be empty.
+If C<$>I<name> is empty string, then empty string, else I<word>
+(positive alternative).
 
-=item VAR_ERR_MISSING_PADDING_WIDTH
+=item C<${>I<name>C<:*>I<word>C<}>
 
-The "width" part in an ${name:p/width/fill/pos/} expression was found
-to be empty.
+If C<$>I<name> is not empty string, then empty string, else I<word>
+(negative alternative).
 
-=item VAR_ERR_MALFORMATTED_PADDING
+=item C<${>I<name>C<:o>I<start>C<,>[I<length>]C<}>
 
-Any of the "/" delimiters was missing while parsing a
-${name:p/width/fill/pos/} expression.
+Substring of C<$>I<name> starting at position I<start> with I<length>
+characters.
 
-=item VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC
+=item C<${>I<name>C<:o>I<start>C<->[I<end>]C<}>
 
-While parsing a ${name:y/old-class/new-class/} expression, any of the
-character class specifications had a start-of-range character that was
-greater (in terms of ASCII encoding) than the end-of-range character,
-for expample: "[z-a]".
+Substring of C<$>I<name> starting at position I<start> and ending at
+position I<end> (inclusive).
 
-=item VAR_ERR_EMPTY_TRANSPOSE_CLASS
+=item C<${>I<name>C<:s/>I<pattern>C</>I<string>C</>[C<itg>]C<}>
 
-While parsing a ${name:y/old-class/new-class/} expression, any of the
-character class specifications was found to be empty.
+C<$>I<name> after replacing characters matching I<pattern> with
+I<string>. By default, case-sensitive regular expression matching is
+performed and only the first occurance of I<pattern> is replaced. Flag
+"C<i>" switches to case insensitive matching; flag "C<t>" switches
+to plain text pattern; flag "C<g>" switches to replacements of all
+occurances.
 
-=item VAR_ERR_TRANSPOSE_CLASSES_MISMATCH
+=item C<${>I<name>C<:y/>I<ochars>C</>I<nchars>C</}>
 
-While parsing a ${name:y/old-class/new-class/} expression, the number
-of characters found in the expanded "old-class" was different than the
-number of characters in new-class".
+C<$>I<name> after replacing all characters found in the I<ochars>
+character class by the corresponding character in the I<nchars>
+character class.
 
-=item VAR_ERR_MALFORMATTED_TRANSPOSE
+=item C<${>I<name>C<:p/>I<width>C</>I<string>C</>{C<l>,C<c>,C<r>}C<}>
 
-Any of the "/" delimiters was missing while parsing a
-${name:y/old-class/new-class/} expression.
+C<$>I<name> after padding to I<width> with I<string>. Original contents
+of I<name> is either left justified (flag "C<l>"), centered (flag
+"C<c>"), or right justified (flag "C<r>").
 
-=item VAR_ERR_OFFSET_LOGIC
 
-The "end" offset in a ${name:o<start>,<end>} expression is smaller
-than the "start" offset.
+=item C<[>I<body>C<]>, C<[>I<body>C<]>C<{>I<start>C<,>I<step>C<,>I<end>C<}>
 
-=item VAR_ERR_OFFSET_OUT_OF_BOUNDS
+Repeat expansion of I<body> as long as at least one array variable
+does not expand to the empty string (first variant) or exactly
+(I<end>-I<start>)/I<step> times (second variant). In both cases the
+character "C<#>" is expanded in C<body> as the current loop index
+(C<0>,... for first variant and I<start>,...,I<end> with stepping
+I<step> for second variant). I<index> of array variable lookups. For
+I<start>, I<step> and I<end>, full arithmetic expressions are allowed.
 
-The "start" offset in a ${name:o<start>,<end>} expression is greater
-than the number of characters found in $name.
+=back
 
-=item VAR_ERR_RANGE_OUT_OF_BOUNDS
+=head1 SYNTAX CONSTRUCTS (GRAMMAR)
 
-The end-of-range in a ${name:o<start>,<end>} or ${name:o<start>-<end>}
-expression would be greater than the number of characters found in
-$name.
+All the variable syntax constructs supported by B<OSSP var> follow the
+same grammatical form. For completeness and reference reasons, the
+corresponding grammar is given in an extended BNF:
+
+ input       ::= ( TEXT
+                 | variable 
+                 | INDEX_OPEN input INDEX_CLOSE (loop_limits)?
+                 )*
+
+ variable    ::= DELIM_INIT (name|expression)
+
+ name        ::= (NAME_CHARS)+
+
+ expression  ::= DELIM_OPEN 
+                 (name|variable)+
+                 (INDEX_OPEN num_exp INDEX_CLOSE)? 
+                 (':' command)*
+                 DELIM_CLOSE
+
+ command     ::= '-' (TEXT_EXP|variable)+
+               | '+' (TEXT_EXP|variable)+
+               | 'o' NUMBER ('-'|',') (NUMBER)?
+               | '#'
+               | '*' (TEXT_EXP|variable)+
+               | 's' '/' (variable|TEXT_SUBST)+ 
+                     '/' (variable|TEXT_SUBST)* 
+                     '/' ('g'|'i'|'t')*
+               | 'y' '/' (variable|TEXT_SUBST)+ 
+                     '/' (variable|TEXT_SUBST)* 
+                     '/'
+               | 'p' '/' NUMBER 
+                     '/' (variable|TEXT_SUBST)* 
+                     '/' ('r'|'l'|'c')
+               | 'l'
+               | 'u'
+
+ num_exp     ::= operand
+               | operand ('+'|'-'|'*'|'/'|'%') num_exp
+
+ operand     ::= ('+'|'-')? NUMBER
+               | INDEX_MARK
+               | '(' num_exp ')'
+               | variable
+
+ loop_limits ::= DELIM_OPEN 
+                 (num_exp)? ',' (num_exp)? (',' (num_exp)?)? 
+                 DELIM_CLOSE
+
+ NUMBER      ::= ('0'|...|'9')+
+
+ TEXT_SUBST  ::= ^(DELIM_INIT|'/')
+ TEXT_EXP    ::= (^(DELIM_INIT|DELIM_CLOSE|':'))+
+ TEXT        ::= (^(DELIM_INIT|INDEX_OPEN|INDEX_CLOSE))+
+
+ DELIM_INIT  ::= '$'                    
+ DELIM_OPEN  ::= '{'   
+ DELIM_CLOSE ::= '}' 
+ INDEX_OPEN  ::= '['    
+ INDEX_CLOSE ::= ']'
+ INDEX_MARK  ::= '#'
+ NAME_CHARS  ::= 'a'|...|'z'|'A'|...|'Z'|'0'|...|'9'
+
+Notice that the grammar definitions of DELIM_INIT, DELIM_OPEN,
+DELIM_CLOSE, INDEX_OPEN, INDEX_CLOSE, INDEX_MARK and NAME_CHARS
+correspond to the default syntax configuration only. They can be changed
+through the API (see B<var_syntax_t>).
 
-=item VAR_ERR_INVALID_OFFSET_DELIMITER
+=head1 APPLICATION PROGRAMMING INTERFACE (API)
 
-The two numbers in an offset operation are delimited by a character
-different from "," or "-".
+The following is a detailed description of the B<OSSP var> B<ISO-C>
+language Application Programming Interface (API):
 
-=item VAR_ERR_MISSING_START_OFFSET
+=head2 TYPES
 
-The "start" offset in a ${name:o<start>,<end>} or
-${name:o<start>-<end>} expression was found to be empty.
+The B<OSSP var> API consists of the following B<ISO-C> data types:
 
-=item VAR_ERR_EMPTY_SEARCH_STRING
+=over 4
 
-The "pattern" part of a ${name:s/pattern/replace/flags} expression was
-found to be empty.
+=item B<var_rc_t>
 
-=item VAR_ERR_MISSING_PARAMETER_IN_COMMAND
+This is an exported enumerated integer type describing the return
+code of all API functions. On success, every API functions returns
+C<VAR_OK>. On error, they return C<VAR_ERR_XXX>. For a list of all
+possible return codes see F<var.h>. Their corresponding describing text
+can be determined with var_strerror().
+
+=item B<var_t>
+
+This is an opaque data type representing a variable expansion context.
+Only pointers to this abstract data type are used in the API.
+
+=item B<var_config_t>
+
+This is an exported enumerated integer type describing configuration
+parameters for var_config(). Currently C<VAR_CONFIG_SYNTAX> (for
+configuring the syntax via B<var_syntax_t>) and C<VAR_CONFIG_CB_VALUE>
+(for configuring the callback for value lookups via B<var_cb_value_t>)
+are defined.
+
+=item B<var_syntax_t>
+
+This is an exported structural data type describing the variable
+construct syntax. It is passed to var_config() on C<VAR_CONFIG_SYNTAX>
+and consists of the following members (directly corresponding to the
+upper-case non-terminals in the grammar above):
+
+ char  escape;       /* default: '\\' */
+ char  delim_init;   /* default: '$' */
+ char  delim_open;   /* default: '{' */
+ char  delim_close;  /* default: '}' */
+ char  index_open;   /* default: '[' */
+ char  index_close;  /* default: ']' */
+ char  index_mark;   /* default: '#' */
+ char *name_chars;   /* default: "a-zA-Z0-9_" */
+
+All members are single character constants, except for I<name_chars>
+which is a character class listing all valid characters. As an
+abbreviation the construct "I<x>C<->I<y>" is supported which means all
+characters from I<x> to I<y> (both included) in the underlying character
+set.
+
+=item B<var_cb_value_t>
+
+This is an exported function pointer type for variable value lookup
+functions. Such a callback function B<cb> has to be of the following
+prototype:
+
+var_rc_t *B<cb>(void *I<ctx>, const char *I<var_ptr>, size_t
+I<var_len>, int I<var_idx>, const char **I<val_ptr>, size_t *I<val_len>,
+size_t *I<val_size>);
 
-In a ${name:+word}, ${name:-word}, or ${name:*word} expression, the
-"word" part was missing -- that means empty.
+This function will be called by var_expand() internally whenever it has
+to resolve the contents of a variable. Its parameters are:
 
-=item VAR_ERR_INVALID_REGEX_IN_REPLACE
+=over 4
 
-While compiling the "pattern" part of a
-${name:s/pattern/replace/flags} expression, regcomp(3) failed with an
-error.
+=item void *I<ctx>
 
-=item VAR_ERR_UNKNOWN_REPLACE_FLAG
+This is the passed-through argument as passed to var_config() on
+C<VAR_CONFIG_CB_VALUE> as the forth argument. This can be used
+to provide an internal context to the callback function through
+var_expand().
 
-In a ${name:s/pattern/replace/flags} expression, a flag other that
-"t", "i", or "g" was found.
+=item const char *I<var_ptr>
 
-=item VAR_ERR_MALFORMATTED_REPLACE
+This is a pointer to the name of the variable which's contents
+var_expand() wishes to resolve. Please note that the string is NOT
+necessarily terminated by a C<NUL> ('C<\0>') character. If the callback
+function needs it C<NUL>-terminated, it has to copy the string into an a
+temporary buffer of its own and C<NUL>-terminate it there.
+
+=item size_t I<var_len>
+
+This is the length of the variable name at I<var_ptr>.
+
+=item int I<var_idx>
+
+This determines which entry of an array variable to lookup. If the
+variable specification that led to the execution of the lookup function
+did not contain an index, zero (C<0>) is provided by default as
+I<var_idx>. If I<var_idx> is less than zero, the callback should return
+the number of entries in the array variable. If I<var_idx> is greater or
+equal zero, it should return the specified particular entry. It is up to
+the callback to decide what to return for an index not equal to zero if
+the underlying variable is a scalar.
 
-Any of the "/" delimiters was missing while parsing a
-${name:s/pattern/replace/flags} expression.
+=item const char **I<val_ptr>
 
-=item VAR_ERR_UNKNOWN_COMMAND_CHAR
+This is a pointer to the location where the callback function should
+store the pointer to the resolved value of the variable.
 
-In a ${name:<char>} expression, "char" did not specify any of the
-supported operations.
+=item size_t *I<val_len>
 
-=item VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE
+This is a pointer to the location where the callback function should
+store the length of the resolved value of the variable.
 
-At one point during parsing of the input buffer, an expression was
-found that was neither verbatim text nor a variable expression. This
-usually is the result of a inconsistent configuration of var_expand()
-via the var_config_t paramater.
+=item size_t *I<val_size>
 
-=item VAR_ERR_UNDEFINED_VARIABLE
+This is a pointer to the location where the callback function should
+store the size of the buffer that has been allocated to hold the
+value of the resolved variable. 
 
-Looking up a variable's contents failed and var_expand() was running
-in "force expand" mode.
+If no buffer has been allocated by the callback at all, because the
+variable uses some other means of storing the contents -- as in the case
+of getenv(3), where the system provides the buffer for the string --,
+this should be set to zero (C<0>).
+
+In case a buffer size greater than zero is returned by the callback,
+var_expand() will make use of that buffer internally if possible. It
+will also free(3) the buffer when it is not needed anymore, so it
+is important that it was previously allocated with malloc(3) by the
+callback.
 
-=item VAR_ERR_INCOMPLETE_VARIABLE_SPEC
+=back
 
-The input buffer ended in the middle of a ${name} expression, or the
-configured variable initializer character was found to be the last
-character of the input buffer.
+The return code of the lookup function B<cb> is interpreted by
+var_expand() according to the following convention: C<VAR_OK> means
+success, that is, the contents of the variable has been resolved
+successfully and the I<val_ptr>, I<val_len>, and I<val_size> variables
+have been filled with appropriate values. A return code C<VAR_ERR_XXX>
+means that the resolving failed, such as a system error or lack of
+resources. In the latter two cases, the contents of I<val_ptr>,
+I<val_len> and I<val_size> is assumed to be undefined. Hence,
+var_expand() will not free(3) any possibly allocated buffers, the
+callback must take care of this itself.
+
+If a callback returns the special C<VAR_ERR_UNDEFINED_VARIABLE> return
+code, the behaviour of var_expand() depends on the setting of its
+I<force_expand> parameter. If I<force_expand> has been set, var_expand()
+will pass-through this error to the caller. If I<force_expand> has
+not been set, var_expand() will copy the expression that caused the
+lookup to fail verbatimly into the output buffer so that an additional
+expanding pass may expand it later.
 
-=item VAR_ERR_OUT_OF_MEMORY
+If the callback returns an C<VAR_ERR_XXX>, var_expand() will fail with
+this return code. If the cause for the error can not be denoted by an
+error code defined in F<var.h>, callback implementors should use the
+error code C<VAR_ERR_CALLBACK> (which is currently defined to -64).
+It is guaranteed that no error code smaller than C<VAR_ERR_CALLBACK>
+is ever used by any B<OSSP var> API function, so if the callback
+implementor wishes to distinguish between different reasons for failure,
+he subtract own callback return codes from this value, i.e., return
+(C<VAR_ERR_CALLBACK> - I<n>) (I<n> E<gt>= 0) from the callback function.
 
-var_expand() failed while malloc(3)ing internally needed buffers.
+=back
 
-=item VAR_ERR_INVALID_CONFIGURATION
+=head2 FUNCTIONS
 
-Any of the characters configured in the var_config_t structure as a
-special ("varinit", "startdelim", "enddelim", and "escape") was found
-to be a member of the "namechars" class.
+The B<OSSP var> API consists of the following B<ISO-C> functions:
 
-=item VAR_ERR_INCORRECT_CLASS_SPEC
+=over 4
 
-The character class specification "namechars" of the var_config_t
-structure provided to var_expand was syntactically incorrect, that is,
-the start-of-range was greater than end-of-range. (See also
-VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC.)
+=item var_rc_t B<var_create>(var_t **I<var>);
 
-=item VAR_ERR_INCOMPLETE_GROUPED_HEX
+Create a new variable expansion context and store it into I<var>.
 
-var_unescape() encountered the end of the input buffer in the middle
-of a grouped-hex "\x{...}" expression.
+=item var_rc_t B<var_destroy>(var_t *I<var>);
 
-=item VAR_ERR_INCOMPLETE_OCTAL
+Destroy the variable expansion context I<var>.
 
-var_unescape() encountered the end of the input buffer in the middle
-of an octal "\000" expression.
+=item var_rc_t B<var_config>(var_t *I<var>, var_config_t I<mode>, ...);
 
-=item VAR_ERR_INVALID_OCTAL
+Configure the variable expansion context I<var>. The variable argument
+list depends on the I<mode> identifier:
 
-The second of third digit of an octal "\000" expression was found not
-be in the range of '0' to '7'.
+=over 4
 
-=item VAR_ERR_OCTAL_TOO_LARGE
+=item C<VAR_CONFIG_SYNTAX>, var_syntax_t *I<syntax>
 
-The value specified via an octal "\000" expression was larger than
-0377.
+This overrides the syntax configuration in I<var> with the one provided
+in I<syntax>. The complete structure contents is copied, so the caller
+is allowed to immediately destroy I<syntax> after the var_config() call.
+The default is the contents as shown above under the type description of
+B<var_syntax_t>.
+
+=item C<VAR_CONFIG_CB_VALUE>, var_cb_value_t I<cb>, void *I<ctx>
+
+This overrides the syntax configuration in I<var> with the one provided
+The default is C<NULL> for I<cb> and I<ctx>. At least C<NULL> for I<cb>
+is not valid for proper operation of var_expand(), so the caller has to
+configure the callback before variable expansions can be successfully
+performed.
 
-=item VAR_ERR_INVALID_HEX
+=back
 
-Any of the digits of a hex "\x00" expression was found not be in the
-range of '0' to '9' or 'a' to 'b'.
+=item var_rc_t B<var_unescape>(var_t *I<var>, const char *I<src_ptr>, size_t I<src_len>, char *I<dst_ptr>, size_t  I<dst_len>, int I<all>);
 
-=item VAR_ERR_INCOMPLETE_HEX
+This expands escape sequences found in the input buffer
+I<src_ptr>/I<src_len>. The I<dst_ptr>/I<dst_len> point to a output
+buffer, into which the expanded data is copied if processing is
+successful. The size of this buffer must be at least I<src_len>+1
+characters. The reason is that var_unescape() always adds a terminating
+C<NUL> ('C<\0>') character at the end of the output buffer, so that
+you can use the result comfortably with other C library routines. The
+supplied I<dst_ptr> either has to be point to a pre-allocated buffer or
+is allowed to point to I<src_ptr> (because the unescaping operation is
+guarrantied to either keep the size or reduce the size of the input).
+
+The parameter I<all> is a boolean flag that modifies the behavior
+of var_unescape(). If is set to true (any value except zero),
+var_unescape() will expand B<any> escape sequences it sees, even those that
+it does not know about. This means that "C<\1>" will become "C<1>",
+even though "C<\1>" has no special meaning to var_unescape(). If I<all>
+is set to false (the value zero), such escape sequences will be copied
+verbatimly to the output buffer.
+
+The quoted pairs supported by var_unescape() are "C<\t>" (tabulator),
+"C<\r>" (carriage return), "C<\n>" (line feed), "C<\NNN>" (octal value),
+"C<\xNN>" (hexadecimal value), and "C<\x{NNMM..}>" (grouped hexadecimal
+values).
+
+=item var_rc_t B<var_expand>(var_t *I<var>, const char *I<src_ptr>, size_t I<src_len>, char **I<dst_ptr>, size_t *I<dst_len>, int I<force_expand>);
+
+This is the heart of B<OSSP var>. It expands all syntax constructs in
+I<src_ptr>/I<src_len> and stores them in an allocated buffer returned
+in I<dst_ptr>/I<dst_len>.
+
+The output buffer I<dst_ptr>/I<dst_len> is allocated by var_expand()
+using the system call malloc(3), thus it is the caller's responsibility
+to free(3) that buffer once it is no longer used anymore. The output
+buffer for convinience reasons is always C<NUL>-terminated by
+var_expand(), but this C<NUL> character is not counted for I<dst_len>.
+The I<dst_len> pointer can be specified as C<NULL> if you are not
+interested in the output buffer length.
+
+The I<force_expand> flag determines how var_expand() deals with
+undefined variables (indicated by the callback function through the
+return code C<VAR_ERR_UNDEFINED_VARIABLE>). If it is set to true
+(any value except zero), var_expand() will fail with error code
+C<VAR_ERR_UNDEFINED_VARIABLE> whenever an undefined variable is
+encountered. That is, it just passes-through the return code of the
+callback function. If set to false (value zero), var_expand() will copy
+the expression it failed to expand verbatimly into the output buffer,
+in order to enable you to go over the buffer with an additional pass.
+Generally, if you do not plan to use muli-pass expansion, you should set
+I<force_expand> to true in order to make sure no unexpanded variable
+constructs are left over in the buffer.
+
+If var_expand() fails with an error, I<dst_ptr> will point to I<src_ptr>
+and I<dst_len> will contain the number of characters that have been
+consumed from I<src_ptr> before the error occured. In other words,
+if an error occurs, I<dst_ptr>/I<dst_len> point to the last parsing
+location in I<src_ptr>/I<src_len> before the error occured. The only
+exceptions for this error semantics are: on C<VAR_ERR_INVALID_ARGUMENT>
+and C<VAR_ERR_OUT_OF_MEMORY> errors, I<dst_ptr> and I<dst_len> are
+undefined.
+
+=item var_rc_t B<var_strerror>(var_t *I<var>, var_rc_t I<rc>, char **I<str>);
+
+This can be used to map any B<var_rc_t> return codes (as returned by all
+the B<OSSP var> API functions) into a clear-text message describing the
+reason for failure in prose. Please note that errors coming from the
+callback, such as C<VAR_ERR_CALLBACK> and those based on it, cannot be
+mapped and will yield the message "C<unknown error>".
 
-var_unescape() encountered the end of the input buffer in the middle
-of a hex "\x00" expression.
+=back
 
-=item VAR_ERR_INCOMPLETE_NAMED_CHARACTER
+=head2 VARIABLES
 
-var_unescape() encountered the backslash ('\') as the last character
-of the input buffer.
+=over 4
 
-=item VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED
+=item B<var_id>
 
 =back
 
-=head1 SO ALSO
+=head1 COMBINING UNESCAPING AND EXPANSION
 
-regex(7)
+For maximum power and flexibility, you usually want to combine
+var_unescape() and var_expand(). That is, you will want to use
+var_unescape() to turn all escape sequences into their real
+representation before you call var_expand() for expanding variable
+constructs. This way the user can safely use specials like "C<\n>" or
+"C<\t>" throughout the template and achieve the desired effect. These
+escape sequences are particularly useful if search-and-replace or
+transpose actions are performed on variables before they are expanded.
+Be sure, though, to make the first var_unescape() pass with the I<all>
+flag set to false, or the routine will also expand escape sequences like
+"C<\1>", which might have a special meaning (regular expression
+back-references) in the var_expand() pass to follow.
+
+Once, all known escape sequences are expanded, expand the variables
+with var_expand(). After that, you will want to have a second pass
+with var_unescape() and the flag I<all> set to true, to make sure all
+remaining escape sequences are expanded. Also, the var_expand() pass
+might have introduced now quoted pairs into the output text, which you
+need to expand to get the desired effect.
+
+=head1 EXAMPLE
+
+The following simple but complete program illustrates the full usage
+of B<OSSP var>. It accepts a single argument on the command line
+and expands this in three steps (unescaping known escape sequences,
+expanding variable constructs, unescaping new and unknown escape
+sequences). The value lookup callback uses the process environment to
+resolve variables.
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ 
+ #include "var.h"
+ 
+ static var_rc_t lookup(
+     void *ctx,
+     const char  *var_ptr, size_t  var_len, int     var_idx,
+     const char **val_ptr, size_t *val_len, size_t *val_size)
+ {
+     char tmp[256];
+ 
+     if (var_idx != 0)
+         return VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED;
+     if (var_len > sizeof(tmp) - 1)
+         return VAR_ERR_OUT_OF_MEMORY;
+     memcpy(tmp, var_ptr, var_len);
+     tmp[var_len] = '\0';
+     if ((*val_ptr = getenv(tmp)) == NULL)
+         return VAR_ERR_UNDEFINED_VARIABLE;
+     *val_len = strlen(*val_ptr);
+     *val_size = 0;
+     return VAR_OK;
+ }
+ 
+ static void die(const char *context, var_t *var, var_rc_t rc)
+ {
+     char *error;
+ 
+     var_strerror(var, rc, &error);
+     fprintf(stderr, "ERROR: %s: %s (%d)\n", context, error, rc);
+     exit(1);
+ }
+ 
+ int main(int argc, char *argv[])
+ {
+     var_t *var;
+     var_rc_t rc;
+     char *src_ptr;
+     char *dst_ptr;
+     size_t src_len;
+     size_t dst_len;
+     var_syntax_t syntax = { '\\', '$', '{', '}', '[', ']', '#', "a-zA-Z0-9_" };
+ 
+     /* command line handling */
+     if (argc != 2)
+         die("command line", NULL, VAR_ERR_INVALID_ARGUMENT);
+     src_ptr = argv[1];
+     src_len = strlen(src_ptr);
+     fprintf(stdout, "input:     \"%s\"\n", src_ptr);
+ 
+     /* establish variable expansion context */
+     if ((rc = var_create(&var)) != VAR_OK)
+         die("create context", NULL, rc);
+     if ((rc = var_config(var, VAR_CONFIG_SYNTAX, &syntax)) != VAR_OK)
+         die("configure syntax", var, rc);
+     if ((rc = var_config(var, VAR_CONFIG_CB_VALUE, lookup, NULL)) != VAR_OK)
+         die("configure callback", var, rc);
+ 
+     /* unescape known escape sequences (in place) */
+     if ((rc = var_unescape(var, src_ptr, src_len, src_ptr, src_len+1, 0)) != VAR_OK)
+         die("unescape known escape sequences", var, rc);
+     src_len = strlen(src_ptr);
+     fprintf(stdout, "unescaped: \"%s\"\n", src_ptr);
+ 
+     /* expand variable constructs (force expansion) */
+     if ((rc = var_expand(var, src_ptr, src_len, &dst_ptr, &dst_len, 1)) != VAR_OK) {
+         if (rc != VAR_ERR_INVALID_ARGUMENT && rc != VAR_ERR_OUT_OF_MEMORY) {
+             fprintf(stdout, "parsing:   \"%s\"\n", dst_ptr); 
+             fprintf(stdout, "             %*s\n", dst_len, "^"); 
+         }
+         die("variable expansion", var, rc);
+     }
+     fprintf(stdout, "expanded:  \"%s\"\n", dst_ptr);
+ 
+     /* unescape new and unknown escape sequences (in place) */
+     if ((rc = var_unescape(var, dst_ptr, dst_len, dst_ptr, dst_len+1, 1)) != VAR_OK)
+         die("unescape new and unknown escape sequences", var, rc);
+     fprintf(stdout, "output:    \"%s\"\n", dst_ptr);
+     free(dst_ptr);
+ 
+     /* destroy variable expansion context */
+     if ((rc = var_destroy(var)) != VAR_OK)
+         die("destroy context", var, rc);
+ 
+     return 0;
+ }
+
+Copy & paste the source code it into F<var_play.c> (or use the version
+already shipped with the B<OSSP var> source distribution), compile it
+with
+
+ $ cc `var-config --cflags` -o var_play var_play.c `var-config --ldflags --libs`
+
+and use it to play with the various B<OSSP var> variable expansion
+possibilities.
+
+=head1 SEE ALSO
+
+pcre(3), regex(7), B<OSSP val> (Value Access).
+
+=head1 HISTORY
+
+B<OSSP var> was written by Peter Simons E<lt>simons@crypt.toE<gt> in
+November 2001. Its API and internal code structure was revamped in
+February 2002 by Ralf S. Engelschall E<lt>rse@engelschall.comE<gt> to
+fully conform to the B<OSSP> library standards.
 
 =cut
+

CVSTrac 2.0.1