##
##  OSSP var -- Variable Expansion
##  Copyright (c) 2001-2004 Ralf S. Engelschall <rse@engelschall.com>
##  Copyright (c) 2001-2004 The OSSP Project (http://www.ossp.org/)
##  Copyright (c) 2001-2004 Cable & Wireless (http://www.cw.com/)
##
##  This file is part of OSSP var, an extensible data serialization
##  library which can be found at http://www.ossp.org/pkg/lib/var/.
##
##  Permission to use, copy, modify, and distribute this software for
##  any purpose with or without fee is hereby granted, provided that
##  the above copyright notice and this permission notice appear in all
##  copies.
##
##  THIS SOFTWARE IS PROVIDED `AS IS' AND ANY EXPRESSED OR IMPLIED
##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
##  ON 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 ADVISED OF THE POSSIBILITY OF
##  SUCH DAMAGE.
##
##  var.pod: Unix manual page source
##

=pod

=head1 NAME

B<OSSP var> -- Variable Expansion

=head1 SYNOPSIS

=over 2

=item Types:

B<var_rc_t>,
B<var_t>,
B<var_config_t>,
B<var_syntax_t>,
B<var_cb_value_t>,
B<var_cb_operation_t>.

=item Functions:

B<var_create>,
B<var_destroy>,
B<var_config>,
B<var_unescape>,
B<var_expand>, 
B<var_formatv>, 
B<var_format>, 
B<var_strerror>.

=item Variables:

B<var_id>.

=back

=head1 DESCRIPTION

B<OSSP var> is a flexible, full-featured and fast variable construct
expansion library.

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, positive 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 C<\>I<NNN>

Character with the octal value I<NNN> 
(I<N>: C<0>,...,C<7>).

=item C<\x>I<NN>, C<\x{>I<NNMM..>C<}>

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>]).

=item C<\t>, C<\r>, C<\n>

Tabulator, Carriage Return and Newline character.

=item C<\\>, C<\>I<x>

Ordinary character C<\> and I<x>.

=item C<$>I<name>, C<${>I<name>C<}>

Contents of scalar variable I<name>.

=item C<${>I<name>C<[>I<index>C<]>C<}>

Contents of array variable I<name> at position I<index>.
For I<index> full arithmetic expressions are allowed.

=item C<${>I<name>C<:#}>

Length of C<$>I<name>.

=item C<${>I<name>C<:l}>, C<${>I<name>C<:u}>

C<$>I<name>, converted to all lower-case or all upper-case.

=item C<${>I<name>C<:->I<word>C<}>

If C<$>I<name> is not empty string and not undefined, then C<$>I<name>,
else I<word> (default value).

=item C<${>I<name>C<:+>I<word>C<}>

If C<$>I<name> is empty string, then empty string, else I<word>
(positive alternative).

=item C<${>I<name>C<:*>I<word>C<}>

If C<$>I<name> is not empty string, then empty string, else I<word>
(negative alternative).

=item C<${>I<name>C<:o>I<start>C<,>[I<length>]C<}>

Substring of C<$>I<name> starting at position I<start> with I<length>
characters.

=item C<${>I<name>C<:o>I<start>C<->[I<end>]C<}>

Substring of C<$>I<name> starting at position I<start> and ending at
position I<end> (inclusive).

=item C<${>I<name>C<:s/>I<pattern>C</>I<string>C</>[C<itg>]C<}>

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; flag "C<m>" switches to multi-line matching (That is, change
"C<^>" and "C<$>" from matching the start or end of the string to
matching the start or end of any line).

=item C<${>I<name>C<:y/>I<ochars>C</>I<nchars>C</}>

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 C<${>I<name>C<:p/>I<width>C</>I<string>C</>{C<l>,C<c>,C<r>}C<}>

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 C<${>I<name>C<:%>I<func>[C<(>I<arg>C<)>]C<}>

C<$>I<name> after passing it to an application-supplied function I<func>.
The optional argument I<arg> is passed to the function, too.
By default no such functions are defined.

=item C<[>I<body>C<]>, C<[>I<body>C<]>C<{>I<start>C<,>I<step>C<,>I<end>C<}>

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.
This loop construct can be nested, too. In this case an inner loop is
fully repeated for each iteration of the outer loop. Additionally,
arithmetic expressions are supported in both I<start>, I<step>, I<end>
and I<index> parts of variable constructs in I<body>.

=back

=head1 SYNTAX CONSTRUCTS (GRAMMAR)

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' '/' (TEXT_PATTERN)+ 
                     '/' (variable|TEXT_SUBST)* 
                     '/' ('m'|'g'|'i'|'t')*
               | 'y' '/' (variable|TEXT_SUBST)+ 
                     '/' (variable|TEXT_SUBST)* 
                     '/'
               | 'p' '/' NUMBER 
                     '/' (variable|TEXT_SUBST)* 
                     '/' ('r'|'l'|'c')
               | '%' (name|variable)+ 
                     ('(' (TEXT_ARGS)? ')')?
               | '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_PATTERN::= (^('/'))+
 TEXT_SUBST  ::= (^(DELIM_INIT|'/'))+
 TEXT_ARGS   ::= (^(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>).

=head1 APPLICATION PROGRAMMING INTERFACE (API)

The following is a detailed description of the B<OSSP var> B<ISO-C>
language Application Programming Interface (API):

=head2 TYPES

The B<OSSP var> API consists of the following B<ISO-C> data types:

=over 4

=item B<var_rc_t>

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 B<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 B<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 B<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>(var_t *I<var>, 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>);

This function will be called by B<var_expand> internally whenever it has
to resolve the contents of a variable. Its parameters are:

=over 4

=item var_t *I<var>

This is the passed-through argument as passed to B<var_expand> as the
first argument. This can be used in the callback function to distinguish
the expansion context or to resolve return codes, etc.

=item void *I<ctx>

This is the passed-through argument as passed to B<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
B<var_expand>.

=item const char *I<var_ptr>

This is a pointer to the name of the variable whose contents
B<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.

=item const char **I<val_ptr>

This is a pointer to the location where the callback function should
store the pointer to the resolved value of the variable.

=item size_t *I<val_len>

This is a pointer to the location where the callback function should
store the length of the resolved value of the variable.

=item size_t *I<val_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
value of the resolved variable. 

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,
B<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.

=back

The return code of the lookup function B<cb> is interpreted by
B<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,
B<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 behavior of B<var_expand> depends on the setting of its
I<force_expand> parameter. If I<force_expand> has been set, B<var_expand>
will pass-through this error to the caller. If I<force_expand> has
not been set, B<var_expand> will copy the expression that caused the
lookup to fail verbatim into the output buffer so that an additional
expanding pass may expand it later.

If the callback returns an C<VAR_ERR_XXX>, B<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.

=item B<var_cb_operation_t>

This is an exported function pointer type for variable value operation
functions. Such a callback function B<cb> has to be of the following
prototype:

var_rc_t *B<cb>(var_t *I<var>, void *I<ctx>, const char *I<op_ptr>,
size_t I<op_len>, const char *I<arg_ptr>, size_t I<arg_len>, const
char *I<val_ptr>, size_t I<val_len>, const char **I<out_ptr>, size_t
*I<out_len>, size_t *I<out_size>);

This function will be called by B<var_expand> internally whenever a
custom operation is used. Its parameters are:

=over 4

=item var_t *I<var>

This is the passed-through argument as passed to B<var_expand> as the
first argument. This can be used in the callback function to distinguish
the expansion context or to resolve return codes, etc.

=item void *I<ctx>

This is the passed-through argument as passed to B<var_config> on
C<VAR_CONFIG_CB_OPERATION> as the forth argument. This can be used
to provide an internal context to the callback function through
B<var_expand>.

=item const char *I<op_ptr>

This is a pointer to the name of the operation which B<var_expand> wishes
to perform. 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<op_len>

This is the length of the variable name at I<op_ptr>.

=item const char *I<arg_ptr>

This is a pointer to the optional argument string to the operation. If
no argument string or an empty argument string was supplied this is
C<NULL>.

=item size_t I<arg_len>

This is the length of the I<arg_ptr>.

=item const char *I<val_ptr>

This is a pointer to the value of the variable which the
operation wants to adjust.

=item size_t I<val_len>

This is the length of the I<val_ptr>.

=item const char **I<out_ptr>

This is a pointer to the location where the callback function should
store the pointer to the adjusted value.

=item size_t *I<out_len>

This is a pointer to the location where the callback function should
store the length of the adjusted value of the variable.

=item size_t *I<out_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
adjusted value of the variable. 

If no buffer has been allocated by the callback at all, because the
variable uses some other means of storing the contents, this should be
set to zero (C<0>).

In case a buffer size greater than zero is returned by the callback,
B<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.

=back

=back

=head2 FUNCTIONS

The B<OSSP var> API consists of the following B<ISO-C> functions:

=over 4

=item var_rc_t B<var_create>(var_t **I<var>);

Create a new variable expansion context and store it into I<var>.

=item var_rc_t B<var_destroy>(var_t *I<var>);

Destroy the variable expansion context I<var>.

=item var_rc_t B<var_config>(var_t *I<var>, var_config_t I<mode>, ...);

Configure the variable expansion context I<var>. The variable argument
list depends on the I<mode> identifier:

=over 4

=item C<VAR_CONFIG_SYNTAX>, var_syntax_t *I<syntax>

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 B<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 B<var_expand>, so the caller has to
configure the callback before variable expansions can be successfully
performed.

=back

=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>);

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 B<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 B<var_unescape>. If is set to true (any value except zero),
B<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 B<var_unescape>. If I<all>
is set to false (the value zero), such escape sequences will be copied
verbatim to the output buffer.

The quoted pairs supported by B<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 B<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 convenience reasons is always C<NUL>-terminated by
B<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 B<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), B<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), B<var_expand> will copy
the expression it failed to expand verbatim 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 multi-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 B<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 occurred. 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 occurred. 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_formatv>(var_t *I<var>, char **I<dst_ptr>, int I<force_expand>, const char *I<fmt>, va_list I<ap>);

This is a high-level function on top of B<var_expand> which expands
simple printf(3)-style constructs before expanding the complex variable
constructs. So, this is something of a combination between sprintf(3)
and B<var_expand>.

It expands simple "C<%s>" (string, type "C<char *>"), "C<%d>" (integer
number, type "C<int>") and "C<%c>" (character, type "C<int>") constructs
in I<fmt>. The values are taken from the variable argument vector I<ap>.
After this expansion the result is passed through B<var_expand> by
passing through the I<var>, I<dst_ptr> and I<force_expand> arguments.
The final result is a malloc(3)'ed buffer provided in I<dst_ptr> which
the caller has to free(3) later.

=item var_rc_t B<var_format>(var_t *I<var>, char **I<dst_ptr>, int I<force_expand>, const char *I<fmt>, ...);

This is just a wrapper around B<var_formatv> which translates the
variable argument list into C<va_list>.

=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>".

=back

=head2 VARIABLES

=over 4

=item B<var_id>

=back

=head1 COMBINING UNESCAPING AND EXPANSION

For maximum power and flexibility, you usually want to combine
B<var_unescape> and B<var_expand>. That is, you will want to use
B<var_unescape> to turn all escape sequences into their real
representation before you call B<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 B<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 B<var_expand> pass to follow.

Once, all known escape sequences are expanded, expand the variables
with B<var_expand>. After that, you will want to have a second pass
with B<var_unescape> and the flag I<all> set to true, to make sure all
remaining escape sequences are expanded. Also, the B<var_expand> pass
might have introduced now quoted pairs into the output text, which you
need to expand to get the desired effect.

=head1 EXCEPTION HANDLING

B<OSSP var> can be optionally built with support for exception handling
via B<OSSP ex> (see http://www.ossp.org/pkg/lib/ex/). For this it has to
be configured with the GNU Autoconf option C<--with-ex>. The difference
then is that the B<OSSP var> API functions throw exceptions instead of
returning C<VAR_ERR_XXX> return codes. 

The thrown exceptions can be identified as B<OSSP var> exceptions by
checking the exception attribute C<ex_class>. It is the B<OSSP var>
API symbol C<var_id> for all B<OSSP var> exceptions. The C<ex_object>
attribute is always C<NULL>. The C<ex_value> attribute is the
C<var_rc_t> which forced the throwing of the exception. 

Exception throwing can be suppressed with C<ex_shield> only.

=head1 EXAMPLE (DEVELOPER)

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(
     var_t *var, 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 EXAMPLE (USER)

The following are a few sample use cases of B<OSSP var>
variable expansions. They all assume the default syntax
configuration and the following variable definitions: C<$foo=foo>
(a scalar), C<$bar=E<lt>bar1,bar2,bar3,E<gt>> (an array),
C<$baz=E<lt>baz1,baz2,baz3,E<gt>> (another array), C<$quux=quux>
(another scalar), C<$name=E<lt>foo,bar,baz,quuxE<gt>> (another scalar)
and C<$empty=""> (another scalar).

 Input                         Output
 ----------------------------- --------------
 $foo                          foo
 ${foo}                        foo
 ${bar[0]}                     bar1
 ${${name[1]}[0]}              bar1
 ${foo:u:y/O/U/:s/(.*)/<\1>/}  <FUU>
 ${foo:u:y/O/U/:s/(.*)/<\1>/}  <FUU>
 ${empty:-foo}                 foo
 ${foo:+yes}${foo:*no}         yes
 ${empty:+yes}${empty:*no}     no
 ${foo:p/6/./l}                foo...
 ${foo:p/6/./r}                ...foo
 [${bar[#]}${bar[#+1]:+,}]     bar1,bar2,bar3
 [${bar[#-1]:+,}${bar[#]}]     bar1,bar2,bar3
 [${bar[#]}]{2,1,3}            bar2bar3
 [${bar[#]}]{1,2,3}            bar1bar3
 [${foo[#]}[${bar[#]}]]{1,,2}  foo1bar1bar2bar3foo2bar1bar2bar3

=head1 SEE ALSO

pcre(3), regex(7), B<OSSP val> (Value Access).

=head1 HISTORY

B<OSSP var> was initially written by Peter Simons
E<lt>simons@crypt.toE<gt> in November 2001 under contract with the
B<OSSP> sponsor B<Cable & Wireless>. 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. Before its initial public release, Ralf S. Engelschall in
March 2002 finally added support for custom operations, the formatting
functionality, optional multi-line matching, etc. 

=cut

