.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.3 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "var 3" .TH var 3 "VAR 1.1.3" "02-Oct-2005" "Variable Expansion Library" .SH "NAME" \&\fBOSSP var\fR \-\- Variable Expansion .SH "SYNOPSIS" .IX Header "SYNOPSIS" .IP "Types:" 2 .IX Item "Types:" \&\fBvar_rc_t\fR, \&\fBvar_t\fR, \&\fBvar_config_t\fR, \&\fBvar_syntax_t\fR, \&\fBvar_cb_value_t\fR, \&\fBvar_cb_operation_t\fR. .IP "Functions:" 2 .IX Item "Functions:" \&\fBvar_create\fR, \&\fBvar_destroy\fR, \&\fBvar_config\fR, \&\fBvar_unescape\fR, \&\fBvar_expand\fR, \&\fBvar_formatv\fR, \&\fBvar_format\fR, \&\fBvar_strerror\fR. .IP "Variables:" 2 .IX Item "Variables:" \&\fBvar_id\fR. .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fB\s-1OSSP\s0 var\fR is a flexible, full-featured and fast variable construct expansion library. .PP It supports a configurable variable construct syntax very similar to the style found in many scripting languages (like \f(CW\*(C`@\*(C'\fR\fIname\fR, \&\f(CW${\fR\fIname\fR\f(CW\*(C`}\*(C'\fR, \f(CW$(\fR\fIname\fR\f(CW\*(C`)\*(C'\fR, etc.) and provides both simple scalar (\f(CW${\fR\fIname\fR\f(CW\*(C`}\*(C'\fR) and array (\f(CW${\fR\fIname\fR\f(CW\*(C`[\*(C'\fR\fIindex\fR\f(CW\*(C`]}\*(C'\fR) expansion, plus optionally one or more post-operations on the expanded value (\f(CW${\fR\fIname\fR\f(CW\*(C`:\*(C'\fR\fIop\fR[\f(CW\*(C`:\*(C'\fR\fIop\fR...]]\f(CW\*(C`}\*(C'\fR). .PP 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 (..\f(CW\*(C`[\*(C'\fR..\f(CW${\fR\fIname\fR\f(CW\*(C`[#+1]}\*(C'\fR..\f(CW\*(C`]\*(C'\fR..). .PP The actual variable value lookup is performed through a callback function, so \fB\s-1OSSP\s0 var\fR can expand arbitrary values. .SH "SYNTAX CONSTRUCTS" .IX Header "SYNTAX CONSTRUCTS" A string expanded through \fB\s-1OSSP\s0 var\fR can consist of arbitrary text characters plus one or more of the following special syntax constructs which are expanded by \fB\s-1OSSP\s0 var\fR. .ie n .IP """\e""\fR\fI\s-1NNN\s0" 4 .el .IP "\f(CW\e\fR\fI\s-1NNN\s0\fR" 4 .IX Item "NNN" Character with the octal value \fI\s-1NNN\s0\fR (\fIN\fR: \f(CW0\fR,...,\f(CW7\fR). .ie n .IP """\ex""\fR\fI\s-1NN\s0\fR, \f(CW""\ex{""\fR\fI\s-1NNMM\s0..\fR\f(CW""}""" 4 .el .IP "\f(CW\ex\fR\fI\s-1NN\s0\fR, \f(CW\ex{\fR\fI\s-1NNMM\s0..\fR\f(CW}\fR" 4 .IX Item "xNN, x{NNMM..}" Character with the hexadecimal value \fI\s-1NN\s0\fR or the characters denoted by grouped hexadecimal numbers \fI\s-1NNMM\s0..\fR. (\fIN\fR, \fIM\fR: \&\f(CW0\fR,...,\f(CW9\fR,[\f(CW\*(C`aA\*(C'\fR],...,[\f(CW\*(C`fF\*(C'\fR]). .ie n .IP """\et""\fR, \f(CW""\er""\fR, \f(CW""\en""" 4 .el .IP "\f(CW\et\fR, \f(CW\er\fR, \f(CW\en\fR" 4 .IX Item "t, r, n" Tabulator (\s-1TAB\s0), Carriage Return (\s-1CR\s0) and Newline (\s-1NL\s0) character. .ie n .IP """\e\e""\fR, \f(CW""\e""\fR\fIx" 4 .el .IP "\f(CW\e\e\fR, \f(CW\e\fR\fIx\fR" 4 .IX Item ", x" Ordinary character \f(CW\*(C`\e\*(C'\fR and \fIx\fR. .ie n .IP """$""\fR\fIname\fR, \f(CW${\fR\fIname\fR\f(CW""}""" 4 .el .IP "\f(CW$\fR\fIname\fR, \f(CW${\fR\fIname\fR\f(CW}\fR" 4 .IX Item "$name, ${name}" Contents of scalar variable \fIname\fR. .ie n .IP "${\fR\fIname\fR\f(CW""[""\fR\fIindex\fR\f(CW""]""\fR\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW[\fR\fIindex\fR\f(CW]\fR\f(CW}\fR" 4 .IX Item "${name[index]}" Contents of array variable \fIname\fR at position \fIindex\fR. For \fIindex\fR full arithmetic expressions are allowed. .ie n .IP "${\fR\fIname\fR\f(CW"":#}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:#}\fR" 4 .IX Item "${name:#}" Length of \f(CW\*(C`$\*(C'\fR\fIname\fR. .ie n .IP "${\fR\fIname\fR\f(CW"":l}""\fR, \f(CW${\fR\fIname\fR\f(CW"":u}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:l}\fR, \f(CW${\fR\fIname\fR\f(CW:u}\fR" 4 .IX Item "${name:l}, ${name:u}" \&\f(CW\*(C`$\*(C'\fR\fIname\fR, converted to all lower-case or all upper\-case. .ie n .IP "${\fR\fIname\fR\f(CW"":\-""\fR\fIword\fR\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:\-\fR\fIword\fR\f(CW}\fR" 4 .IX Item "${name:-word}" If \f(CW\*(C`$\*(C'\fR\fIname\fR is not empty string and not undefined, then \f(CW\*(C`$\*(C'\fR\fIname\fR, else \fIword\fR (Default Value). .ie n .IP "${\fR\fIname\fR\f(CW"":+""\fR\fIword\fR\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:+\fR\fIword\fR\f(CW}\fR" 4 .IX Item "${name:+word}" If \f(CW\*(C`$\*(C'\fR\fIname\fR is empty string, then empty string, else \fIword\fR (Positive Alternative). .ie n .IP "${\fR\fIname\fR\f(CW"":*""\fR\fIword\fR\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:*\fR\fIword\fR\f(CW}\fR" 4 .IX Item "${name:*word}" If \f(CW\*(C`$\*(C'\fR\fIname\fR is not empty string, then empty string, else \fIword\fR (Negative Alternative). .ie n .IP "${\fR\fIname\fR\f(CW"":o""\fR\fIstart\fR\f(CW"",""\fR[\fIlength\fR]\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:o\fR\fIstart\fR\f(CW,\fR[\fIlength\fR]\f(CW}\fR" 4 .IX Item "${name:ostart,[length]}" Substring of \f(CW\*(C`$\*(C'\fR\fIname\fR starting at position \fIstart\fR with \fIlength\fR characters. .ie n .IP "${\fR\fIname\fR\f(CW"":o""\fR\fIstart\fR\f(CW""\-""\fR[\fIend\fR]\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:o\fR\fIstart\fR\f(CW\-\fR[\fIend\fR]\f(CW}\fR" 4 .IX Item "${name:ostart-[end]}" Substring of \f(CW\*(C`$\*(C'\fR\fIname\fR starting at position \fIstart\fR and ending at position \fIend\fR (inclusive). .ie n .IP "${\fR\fIname\fR\f(CW"":s/""\fR\fIpattern\fR\f(CW""/""\fR\fIstring\fR\f(CW""/""\fR[\f(CW""itg""\fR]\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:s/\fR\fIpattern\fR\f(CW/\fR\fIstring\fR\f(CW/\fR[\f(CWitg\fR]\f(CW}\fR" 4 .IX Item "${name:s/pattern/string/[itg]}" \&\f(CW\*(C`$\*(C'\fR\fIname\fR after replacing characters matching \fIpattern\fR with \&\fIstring\fR. By default, case-sensitive regular expression matching is performed and only the first occurrence of \fIpattern\fR is replaced. Flag "\f(CW\*(C`i\*(C'\fR\*(L" switches to case insensitive matching; flag \*(R"\f(CW\*(C`t\*(C'\fR\*(L" switches to plain text pattern; flag \*(R"\f(CW\*(C`g\*(C'\fR\*(L" switches to replacements of all occurrences; flag \*(R"\f(CW\*(C`m\*(C'\fR\*(L" switches to multi-line matching (That is, change \&\*(R"\f(CW\*(C`^\*(C'\fR\*(L" and \*(R"\f(CW\*(C`$\*(C'\fR" from matching the start or end of the string to matching the start or end of any line). .ie n .IP "${\fR\fIname\fR\f(CW"":y/""\fR\fIochars\fR\f(CW""/""\fR\fInchars\fR\f(CW""/}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:y/\fR\fIochars\fR\f(CW/\fR\fInchars\fR\f(CW/}\fR" 4 .IX Item "${name:y/ochars/nchars/}" \&\f(CW\*(C`$\*(C'\fR\fIname\fR after replacing all characters found in the \fIochars\fR character class by the corresponding character in the \fInchars\fR character class. .ie n .IP "${\fR\fIname\fR\f(CW"":p/""\fR\fIwidth\fR\f(CW""/""\fR\fIstring\fR\f(CW""/""\fR{\f(CW""l""\fR,\f(CW""c""\fR,\f(CW""r""\fR}\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:p/\fR\fIwidth\fR\f(CW/\fR\fIstring\fR\f(CW/\fR{\f(CWl\fR,\f(CWc\fR,\f(CWr\fR}\f(CW}\fR" 4 .IX Item "${name:p/width/string/{l,c,r}}" \&\f(CW\*(C`$\*(C'\fR\fIname\fR after padding to \fIwidth\fR with \fIstring\fR. Original contents of \fIname\fR is either left justified (flag "\f(CW\*(C`l\*(C'\fR\*(L"), centered (flag \&\*(R"\f(CW\*(C`c\*(C'\fR\*(L"), or right justified (flag \*(R"\f(CW\*(C`r\*(C'\fR"). .ie n .IP "${\fR\fIname\fR\f(CW"":%""\fR\fIfunc\fR[\f(CW""(""\fR\fIarg\fR\f(CW"")""\fR]\f(CW""}""" 4 .el .IP "\f(CW${\fR\fIname\fR\f(CW:%\fR\fIfunc\fR[\f(CW(\fR\fIarg\fR\f(CW)\fR]\f(CW}\fR" 4 .IX Item "${name:%func[(arg)]}" \&\f(CW\*(C`$\*(C'\fR\fIname\fR after passing it to an application-supplied function \fIfunc\fR. The optional argument \fIarg\fR is passed to the function, too. By default no such functions are defined. .ie n .IP """[""\fR\fIbody\fR\f(CW""]""\fR, \f(CW""[""\fR\fIbody\fR\f(CW""]""\fR\f(CW""{""\fR\fIstart\fR\f(CW"",""\fR\fIstep\fR\f(CW"",""\fR\fIend\fR\f(CW""}""" 4 .el .IP "\f(CW[\fR\fIbody\fR\f(CW]\fR, \f(CW[\fR\fIbody\fR\f(CW]\fR\f(CW{\fR\fIstart\fR\f(CW,\fR\fIstep\fR\f(CW,\fR\fIend\fR\f(CW}\fR" 4 .IX Item "[body], [body]{start,step,end}" Repeat expansion of \fIbody\fR as long as at least one array variable does not expand to the empty string (first variant) or exactly (\fIend\fR\-\fIstart\fR)/\fIstep\fR times (second variant). In both cases the character "\f(CW\*(C`#\*(C'\fR" is expanded in \fIbody\fR as the current loop index (\f(CW0\fR,... for first variant and \fIstart\fR,...,\fIend\fR with stepping \&\fIstep\fR for second variant). The "\f(CW\*(C`#\*(C'\fR" is usually used in the \fIindex\fR of array variable lookups. For \fIstart\fR, \fIstep\fR and \fIend\fR, 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 \fIstart\fR, \fIstep\fR, \fIend\fR and \fIindex\fR parts of variable constructs in \fIbody\fR. .SH "SYNTAX CONSTRUCTS (GRAMMAR)" .IX Header "SYNTAX CONSTRUCTS (GRAMMAR)" All the variable syntax constructs supported by \fB\s-1OSSP\s0 var\fR follow the same grammatical form. For completeness and reference reasons, the corresponding grammar is given in an extended \s-1BNF:\s0 .PP .Vb 4 \& input ::= ( TEXT \& | variable \& | INDEX_OPEN input INDEX_CLOSE (loop_limits)? \& )* .Ve .PP .Vb 1 \& variable ::= DELIM_INIT (name|expression) .Ve .PP .Vb 1 \& name ::= (NAME_CHARS)+ .Ve .PP .Vb 5 \& expression ::= DELIM_OPEN \& (name|variable)+ \& (INDEX_OPEN num_exp INDEX_CLOSE)? \& (':' command)* \& DELIM_CLOSE .Ve .PP .Vb 18 \& 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' .Ve .PP .Vb 2 \& num_exp ::= operand \& | operand ('+'|'-'|'*'|'/'|'%') num_exp .Ve .PP .Vb 4 \& operand ::= ('+'|'-')? NUMBER \& | INDEX_MARK \& | '(' num_exp ')' \& | variable .Ve .PP .Vb 3 \& loop_limits ::= DELIM_OPEN \& (num_exp)? ',' (num_exp)? (',' (num_exp)?)? \& DELIM_CLOSE .Ve .PP .Vb 1 \& NUMBER ::= ('0'|...|'9')+ .Ve .PP .Vb 5 \& TEXT_PATTERN::= (^('/'))+ \& TEXT_SUBST ::= (^(DELIM_INIT|'/'))+ \& TEXT_ARGS ::= (^(DELIM_INIT|')'))+ \& TEXT_EXP ::= (^(DELIM_INIT|DELIM_CLOSE|':'))+ \& TEXT ::= (^(DELIM_INIT|INDEX_OPEN|INDEX_CLOSE))+ .Ve .PP .Vb 7 \& DELIM_INIT ::= '$' \& DELIM_OPEN ::= '{' \& DELIM_CLOSE ::= '}' \& INDEX_OPEN ::= '[' \& INDEX_CLOSE ::= ']' \& INDEX_MARK ::= '#' \& NAME_CHARS ::= 'a'|...|'z'|'A'|...|'Z'|'0'|...|'9' .Ve .PP Notice that the grammar definitions of \s-1DELIM_INIT\s0, \s-1DELIM_OPEN\s0, \&\s-1DELIM_CLOSE\s0, \s-1INDEX_OPEN\s0, \s-1INDEX_CLOSE\s0, \s-1INDEX_MARK\s0 and \s-1NAME_CHARS\s0 correspond to the default syntax configuration only. They can be changed through the \s-1API\s0 (see \fBvar_syntax_t\fR). .SH "APPLICATION PROGRAMMING INTERFACE (API)" .IX Header "APPLICATION PROGRAMMING INTERFACE (API)" The following is a detailed description of the \fB\s-1OSSP\s0 var\fR \fBISO-C\fR language Application Programming Interface (\s-1API\s0): .Sh "\s-1TYPES\s0" .IX Subsection "TYPES" The \fB\s-1OSSP\s0 var\fR \s-1API\s0 consists of the following \fBISO-C\fR data types: .IP "\fBvar_rc_t\fR" 4 .IX Item "var_rc_t" This is an exported enumerated integer type describing the return code of all \s-1API\s0 functions. On success, every \s-1API\s0 function returns \&\f(CW\*(C`VAR_OK\*(C'\fR. On error, it returns \f(CW\*(C`VAR_ERR_XXX\*(C'\fR. For a list of all possible return codes see \fIvar.h\fR. Their corresponding describing text can be determined with function \fBvar_strerror\fR. .IP "\fBvar_t\fR" 4 .IX Item "var_t" This is an opaque data type representing a variable expansion context. Only pointers to this abstract data type are used in the \s-1API\s0. .IP "\fBvar_config_t\fR" 4 .IX Item "var_config_t" This is an exported enumerated integer type describing configuration parameters for function \fBvar_config\fR. Currently \f(CW\*(C`VAR_CONFIG_SYNTAX\*(C'\fR for configuring the syntax via \fBvar_syntax_t\fR, \f(CW\*(C`VAR_CONFIG_CB_VALUE\*(C'\fR for configuring the callback for value lookups via \fBvar_cb_value_t\fR, and \f(CW\*(C`VAR_CONFIG_CB_OPERATION\*(C'\fR for configuring the callback for custom value operation functions via \fBvar_cb_operation_t\fR are defined. .IP "\fBvar_syntax_t\fR" 4 .IX Item "var_syntax_t" This is an exported structural data type describing the variable construct syntax. It is passed to \fBvar_config\fR on \f(CW\*(C`VAR_CONFIG_SYNTAX\*(C'\fR and consists of the following members (directly corresponding to the upper-case non-terminals in the grammar above): .Sp .Vb 8 \& char escape; /* default: '\e\e' */ \& 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_" */ .Ve .Sp All members are single character constants, except for \fIname_chars\fR which is a character class listing all valid characters. As an abbreviation the construct "\fIx\fR\f(CW\*(C`\-\*(C'\fR\fIy\fR" is supported which means all characters from \fIx\fR to \fIy\fR (both included) in the underlying character set. .IP "\fBvar_cb_value_t\fR" 4 .IX Item "var_cb_value_t" This is an exported function pointer type for variable value lookup functions. Such a callback function \fBcb\fR has to be of the following prototype: .Sp var_rc_t *\fBcb\fR(var_t *\fIvar\fR, void *\fIctx\fR, const char *\fIvar_ptr\fR, size_t \fIvar_len\fR, int \fIvar_idx\fR, const char **\fIval_ptr\fR, size_t *\fIval_len\fR, size_t *\fIval_size\fR); .Sp This function will be called by \fBvar_expand\fR internally whenever it has to resolve the contents of a variable. Its parameters are: .RS 4 .IP "var_t *\fIvar\fR" 4 .IX Item "var_t *var" This is the passed-through argument as passed to \fBvar_expand\fR as the first argument. This can be used in the callback function to distinguish the expansion context or to resolve return codes, etc. .IP "void *\fIctx\fR" 4 .IX Item "void *ctx" This is the passed-through argument as passed to \fBvar_config\fR on \&\f(CW\*(C`VAR_CONFIG_CB_VALUE\*(C'\fR as the forth argument. This can be used to provide an internal context to the callback function through \&\fBvar_expand\fR. .IP "const char *\fIvar_ptr\fR" 4 .IX Item "const char *var_ptr" This is a pointer to the name of the variable whose contents \&\fBvar_expand\fR wishes to resolve. Please note that the string is \s-1NOT\s0 necessarily terminated by a \f(CW\*(C`NUL\*(C'\fR ('\f(CW\*(C`\e0\*(C'\fR') character. If the callback function needs it \f(CW\*(C`NUL\*(C'\fR\-terminated, it has to copy the string into an a temporary buffer of its own and \f(CW\*(C`NUL\*(C'\fR\-terminate it there. .IP "size_t \fIvar_len\fR" 4 .IX Item "size_t var_len" This is the length of the variable name at \fIvar_ptr\fR. .IP "int \fIvar_idx\fR" 4 .IX Item "int 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 (\f(CW0\fR) is provided by default as \&\fIvar_idx\fR. If \fIvar_idx\fR is less than zero, the callback should return the number of entries in the array variable. If \fIvar_idx\fR 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. .IP "const char **\fIval_ptr\fR" 4 .IX Item "const char **val_ptr" This is a pointer to the location where the callback function should store the pointer to the resolved value of the variable. .IP "size_t *\fIval_len\fR" 4 .IX Item "size_t *val_len" This is a pointer to the location where the callback function should store the length of the resolved value of the variable. .IP "size_t *\fIval_size\fR" 4 .IX Item "size_t *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. .Sp 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 \fIgetenv\fR\|(3), where the system provides the buffer for the string \-\-, this should be set to zero (\f(CW0\fR). .Sp In case a buffer size greater than zero is returned by the callback, \&\fBvar_expand\fR will make use of that buffer internally if possible. It will also \fIfree\fR\|(3) the buffer when it is not needed anymore, so it is important that it was previously allocated with \fImalloc\fR\|(3) by the callback. .RE .RS 4 .Sp The return code of the lookup function \fBcb\fR is interpreted by \&\fBvar_expand\fR according to the following convention: \f(CW\*(C`VAR_OK\*(C'\fR means success, that is, the contents of the variable has been resolved successfully and the \fIval_ptr\fR, \fIval_len\fR, and \fIval_size\fR variables have been filled with appropriate values. A return code \f(CW\*(C`VAR_ERR_XXX\*(C'\fR means that the resolving failed, such as a system error or lack of resources. In the latter two cases, the contents of \fIval_ptr\fR, \&\fIval_len\fR and \fIval_size\fR is assumed to be undefined. Hence, \&\fBvar_expand\fR will not \fIfree\fR\|(3) any possibly allocated buffers, the callback must take care of this itself. .Sp If a callback returns the special \f(CW\*(C`VAR_ERR_UNDEFINED_VARIABLE\*(C'\fR return code, the behavior of \fBvar_expand\fR depends on the setting of its \&\fIforce_expand\fR parameter. If \fIforce_expand\fR has been set, \fBvar_expand\fR will pass-through this error to the caller. If \fIforce_expand\fR has not been set, \fBvar_expand\fR 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. .Sp If the callback returns an \f(CW\*(C`VAR_ERR_XXX\*(C'\fR, \fBvar_expand\fR will fail with this return code. If the cause for the error can not be denoted by an error code defined in \fIvar.h\fR, callback implementors should use the error code \f(CW\*(C`VAR_ERR_CALLBACK\*(C'\fR (which is currently defined to \-64). It is guaranteed that no error code smaller than \f(CW\*(C`VAR_ERR_CALLBACK\*(C'\fR is ever used by any \fB\s-1OSSP\s0 var\fR \s-1API\s0 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 (\f(CW\*(C`VAR_ERR_CALLBACK\*(C'\fR \- \fIn\fR) (\fIn\fR >= 0) from the callback function. .RE .IP "\fBvar_cb_operation_t\fR" 4 .IX Item "var_cb_operation_t" This is an exported function pointer type for variable value operation functions. Such a callback function \fBcb\fR has to be of the following prototype: .Sp var_rc_t *\fBcb\fR(var_t *\fIvar\fR, void *\fIctx\fR, const char *\fIop_ptr\fR, size_t \fIop_len\fR, const char *\fIarg_ptr\fR, size_t \fIarg_len\fR, const char *\fIval_ptr\fR, size_t \fIval_len\fR, const char **\fIout_ptr\fR, size_t *\fIout_len\fR, size_t *\fIout_size\fR); .Sp This function will be called by \fBvar_expand\fR internally whenever a custom operation is used. Its parameters are: .RS 4 .IP "var_t *\fIvar\fR" 4 .IX Item "var_t *var" This is the passed-through argument as passed to \fBvar_expand\fR as the first argument. This can be used in the callback function to distinguish the expansion context or to resolve return codes, etc. .IP "void *\fIctx\fR" 4 .IX Item "void *ctx" This is the passed-through argument as passed to \fBvar_config\fR on \&\f(CW\*(C`VAR_CONFIG_CB_OPERATION\*(C'\fR as the forth argument. This can be used to provide an internal context to the callback function through \&\fBvar_expand\fR. .IP "const char *\fIop_ptr\fR" 4 .IX Item "const char *op_ptr" This is a pointer to the name of the operation which \fBvar_expand\fR wishes to perform. Please note that the string is \s-1NOT\s0 necessarily terminated by a \f(CW\*(C`NUL\*(C'\fR ('\f(CW\*(C`\e0\*(C'\fR') character. If the callback function needs it \&\f(CW\*(C`NUL\*(C'\fR\-terminated, it has to copy the string into an a temporary buffer of its own and \f(CW\*(C`NUL\*(C'\fR\-terminate it there. .IP "size_t \fIop_len\fR" 4 .IX Item "size_t op_len" This is the length of the variable name at \fIop_ptr\fR. .IP "const char *\fIarg_ptr\fR" 4 .IX Item "const char *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 \&\f(CW\*(C`NULL\*(C'\fR. .IP "size_t \fIarg_len\fR" 4 .IX Item "size_t arg_len" This is the length of the \fIarg_ptr\fR. .IP "const char *\fIval_ptr\fR" 4 .IX Item "const char *val_ptr" This is a pointer to the value of the variable which the operation wants to adjust. .IP "size_t \fIval_len\fR" 4 .IX Item "size_t val_len" This is the length of the \fIval_ptr\fR. .IP "const char **\fIout_ptr\fR" 4 .IX Item "const char **out_ptr" This is a pointer to the location where the callback function should store the pointer to the adjusted value. .IP "size_t *\fIout_len\fR" 4 .IX Item "size_t *out_len" This is a pointer to the location where the callback function should store the length of the adjusted value of the variable. .IP "size_t *\fIout_size\fR" 4 .IX Item "size_t *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. .Sp 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 (\f(CW0\fR). .Sp In case a buffer size greater than zero is returned by the callback, \&\fBvar_expand\fR will make use of that buffer internally if possible. It will also \fIfree\fR\|(3) the buffer when it is not needed anymore, so it is important that it was previously allocated with \fImalloc\fR\|(3) by the callback. .RE .RS 4 .RE .Sh "\s-1FUNCTIONS\s0" .IX Subsection "FUNCTIONS" The \fB\s-1OSSP\s0 var\fR \s-1API\s0 consists of the following \fBISO-C\fR functions: .IP "var_rc_t \fBvar_create\fR(var_t **\fIvar\fR);" 4 .IX Item "var_rc_t var_create(var_t **var);" Create a new variable expansion context and store it into \fIvar\fR. .IP "var_rc_t \fBvar_destroy\fR(var_t *\fIvar\fR);" 4 .IX Item "var_rc_t var_destroy(var_t *var);" Destroy the variable expansion context \fIvar\fR. .IP "var_rc_t \fBvar_config\fR(var_t *\fIvar\fR, var_config_t \fImode\fR, ...);" 4 .IX Item "var_rc_t var_config(var_t *var, var_config_t mode, ...);" Configure the variable expansion context \fIvar\fR. The variable argument list depends on the \fImode\fR identifier: .RS 4 .ie n .IP """VAR_CONFIG_SYNTAX""\fR, var_syntax_t *\fIsyntax" 4 .el .IP "\f(CWVAR_CONFIG_SYNTAX\fR, var_syntax_t *\fIsyntax\fR" 4 .IX Item "VAR_CONFIG_SYNTAX, var_syntax_t *syntax" This overrides the syntax configuration in \fIvar\fR with the one provided in \fIsyntax\fR. The complete structure contents is copied, so the caller is allowed to immediately destroy \fIsyntax\fR after the \fBvar_config\fR call. The default is the contents as shown above under the type description of \&\fBvar_syntax_t\fR. .ie n .IP """VAR_CONFIG_CB_VALUE""\fR, var_cb_value_t \fIcb\fR, void *\fIctx" 4 .el .IP "\f(CWVAR_CONFIG_CB_VALUE\fR, var_cb_value_t \fIcb\fR, void *\fIctx\fR" 4 .IX Item "VAR_CONFIG_CB_VALUE, var_cb_value_t cb, void *ctx" This overrides the value expansion in \fIvar\fR. The default is \f(CW\*(C`NULL\*(C'\fR for \&\fIcb\fR and \fIctx\fR. At least \f(CW\*(C`NULL\*(C'\fR for \fIcb\fR is not valid for proper operation of \fBvar_expand\fR, so the caller has to configure the callback before variable expansions can be successfully performed. .ie n .IP """VAR_CONFIG_CB_OPERATION""\fR, var_cb_operation_t \fIcb\fR, void *\fIctx" 4 .el .IP "\f(CWVAR_CONFIG_CB_OPERATION\fR, var_cb_operation_t \fIcb\fR, void *\fIctx\fR" 4 .IX Item "VAR_CONFIG_CB_OPERATION, var_cb_operation_t cb, void *ctx" This provides a custom value operation function for \fIvar\fR. The default is \f(CW\*(C`NULL\*(C'\fR for \fIcb\fR and \fIctx\fR which means no custom operation is available. .RE .RS 4 .RE .IP "var_rc_t \fBvar_unescape\fR(var_t *\fIvar\fR, const char *\fIsrc_ptr\fR, size_t \fIsrc_len\fR, char *\fIdst_ptr\fR, size_t \fIdst_len\fR, int \fIall\fR);" 4 .IX Item "var_rc_t var_unescape(var_t *var, const char *src_ptr, size_t src_len, char *dst_ptr, size_t dst_len, int all);" This expands escape sequences found in the input buffer \&\fIsrc_ptr\fR/\fIsrc_len\fR. The \fIdst_ptr\fR/\fIdst_len\fR 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 \fIsrc_len\fR+1 characters. The reason is that \fBvar_unescape\fR always adds a terminating \&\f(CW\*(C`NUL\*(C'\fR ('\f(CW\*(C`\e0\*(C'\fR') character at the end of the output buffer, so that you can use the result comfortably with other C library routines. The supplied \fIdst_ptr\fR either has to point to a pre-allocated buffer or is allowed to point to \fIsrc_ptr\fR (because the unescaping operation is guaranteed to either keep the size or reduce the size of the input). .Sp The parameter \fIall\fR is a boolean flag that modifies the behavior of \fBvar_unescape\fR. If is set to true (any value except zero), \&\fBvar_unescape\fR will expand \fBany\fR escape sequences it sees, even those that it does not know about. This means that "\f(CW\*(C`\e1\*(C'\fR\*(L" will become \*(R"\f(CW1\fR\*(L", even though \*(R"\f(CW\*(C`\e1\*(C'\fR" has no special meaning to \fBvar_unescape\fR. If \fIall\fR is set to false (the value zero), such escape sequences will be copied verbatim to the output buffer. .Sp The quoted pairs supported by \fBvar_unescape\fR are "\f(CW\*(C`\et\*(C'\fR\*(L" (tabulator), \&\*(R"\f(CW\*(C`\er\*(C'\fR\*(L" (carriage return), \*(R"\f(CW\*(C`\en\*(C'\fR\*(L" (line feed), \*(R"\f(CW\*(C`\eNNN\*(C'\fR\*(L" (octal value), \&\*(R"\f(CW\*(C`\exNN\*(C'\fR\*(L" (hexadecimal value), and \*(R"\f(CW\*(C`\ex{NNMM..}\*(C'\fR" (grouped hexadecimal values). .IP "var_rc_t \fBvar_expand\fR(var_t *\fIvar\fR, const char *\fIsrc_ptr\fR, size_t \fIsrc_len\fR, char **\fIdst_ptr\fR, size_t *\fIdst_len\fR, int \fIforce_expand\fR);" 4 .IX Item "var_rc_t var_expand(var_t *var, const char *src_ptr, size_t src_len, char **dst_ptr, size_t *dst_len, int force_expand);" This is the heart of \fB\s-1OSSP\s0 var\fR. It expands all syntax constructs in \&\fIsrc_ptr\fR/\fIsrc_len\fR and stores them in an allocated buffer returned in \fIdst_ptr\fR/\fIdst_len\fR. .Sp The output buffer \fIdst_ptr\fR/\fIdst_len\fR is allocated by \fBvar_expand\fR using the system call \fImalloc\fR\|(3), thus it is the caller's responsibility to \fIfree\fR\|(3) that buffer once it is no longer used anymore. The output buffer for convenience reasons is always \f(CW\*(C`NUL\*(C'\fR\-terminated by \&\fBvar_expand\fR, but this \f(CW\*(C`NUL\*(C'\fR character is not counted for \fIdst_len\fR. The \fIdst_len\fR pointer can be specified as \f(CW\*(C`NULL\*(C'\fR if you are not interested in the output buffer length. .Sp The \fIforce_expand\fR flag determines how \fBvar_expand\fR deals with undefined variables (indicated by the callback function through the return code \f(CW\*(C`VAR_ERR_UNDEFINED_VARIABLE\*(C'\fR). If it is set to true (any value except zero), \fBvar_expand\fR will fail with error code \&\f(CW\*(C`VAR_ERR_UNDEFINED_VARIABLE\*(C'\fR 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), \fBvar_expand\fR 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 \&\fIforce_expand\fR to true in order to make sure no unexpanded variable constructs are left over in the buffer. .Sp If \fBvar_expand\fR fails with an error, \fIdst_ptr\fR will point to \fIsrc_ptr\fR and \fIdst_len\fR will contain the number of characters that have been consumed from \fIsrc_ptr\fR before the error occurred. In other words, if an error occurs, \fIdst_ptr\fR/\fIdst_len\fR point to the last parsing location in \fIsrc_ptr\fR/\fIsrc_len\fR before the error occurred. The only exceptions for this error semantics are: on \f(CW\*(C`VAR_ERR_INVALID_ARGUMENT\*(C'\fR and \f(CW\*(C`VAR_ERR_OUT_OF_MEMORY\*(C'\fR errors, \fIdst_ptr\fR and \fIdst_len\fR are undefined. .IP "var_rc_t \fBvar_formatv\fR(var_t *\fIvar\fR, char **\fIdst_ptr\fR, int \fIforce_expand\fR, const char *\fIfmt\fR, va_list \fIap\fR);" 4 .IX Item "var_rc_t var_formatv(var_t *var, char **dst_ptr, int force_expand, const char *fmt, va_list ap);" This is a high-level function on top of \fBvar_expand\fR which expands simple \fIprintf\fR\|(3)\-style constructs before expanding the complex variable constructs. So, this is something of a combination between \fIsprintf\fR\|(3) and \fBvar_expand\fR. .Sp It expands simple "\f(CW%s\fR\*(L" (string, type \*(R"\f(CW\*(C`char *\*(C'\fR\*(L"), \*(R"\f(CW%d\fR\*(L" (integer number, type \*(R"\f(CW\*(C`int\*(C'\fR\*(L") and \*(R"\f(CW%c\fR\*(L" (character, type \*(R"\f(CW\*(C`int\*(C'\fR") constructs in \fIfmt\fR. The values are taken from the variable argument vector \fIap\fR. After this expansion the result is passed through \fBvar_expand\fR by passing through the \fIvar\fR, \fIdst_ptr\fR and \fIforce_expand\fR arguments. The final result is a \fImalloc\fR\|(3)'ed buffer provided in \fIdst_ptr\fR which the caller has to \fIfree\fR\|(3) later. .IP "var_rc_t \fBvar_format\fR(var_t *\fIvar\fR, char **\fIdst_ptr\fR, int \fIforce_expand\fR, const char *\fIfmt\fR, ...);" 4 .IX Item "var_rc_t var_format(var_t *var, char **dst_ptr, int force_expand, const char *fmt, ...);" This is just a wrapper around \fBvar_formatv\fR which translates the variable argument list into \f(CW\*(C`va_list\*(C'\fR. .IP "var_rc_t \fBvar_strerror\fR(var_t *\fIvar\fR, var_rc_t \fIrc\fR, char **\fIstr\fR);" 4 .IX Item "var_rc_t var_strerror(var_t *var, var_rc_t rc, char **str);" This can be used to map any \fBvar_rc_t\fR return codes (as returned by all the \fB\s-1OSSP\s0 var\fR \s-1API\s0 functions) into a clear-text message describing the reason for failure in prose. Please note that errors coming from the callback, such as \f(CW\*(C`VAR_ERR_CALLBACK\*(C'\fR and those based on it, cannot be mapped and will yield the message "\f(CW\*(C`unknown error\*(C'\fR". .Sh "\s-1VARIABLES\s0" .IX Subsection "VARIABLES" The \fB\s-1OSSP\s0 var\fR \s-1API\s0 consists of the following \fBISO-C\fR exported variables: .IP "\fBvar_id\fR" 4 .IX Item "var_id" This is just a pointer to the constant string "\f(CW\*(C`OSSP var\*(C'\fR". It is used as the first argument in \fBex_trow\fR calls if \fB\s-1OSSP\s0 var\fR is built with \&\fB\s-1OSSP\s0 ex\fR support. It then allows the application to determine whether a caught exception was thrown by \fB\s-1OSSP\s0 var\fR. See \fB\s-1EXCEPTION\s0 \s-1HANDLING\s0\fR below for more details. .SH "COMBINING UNESCAPING AND EXPANSION" .IX Header "COMBINING UNESCAPING AND EXPANSION" For maximum power and flexibility, you usually want to combine \&\fBvar_unescape\fR and \fBvar_expand\fR. That is, you will want to use \&\fBvar_unescape\fR to turn all escape sequences into their real representation before you call \fBvar_expand\fR for expanding variable constructs. This way the user can safely use specials like "\f(CW\*(C`\en\*(C'\fR\*(L" or \&\*(R"\f(CW\*(C`\et\*(C'\fR" 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 \fBvar_unescape\fR pass with the \fIall\fR flag set to false, or the routine will also expand escape sequences like "\f(CW\*(C`\e1\*(C'\fR", which might have a special meaning (regular expression back\-references) in the \fBvar_expand\fR pass to follow. .PP Once all known escape sequences are expanded, expand the variables with \fBvar_expand\fR. After that, you will want to have a second pass with \fBvar_unescape\fR and the flag \fIall\fR set to true, to make sure all remaining escape sequences are expanded. Also, the \fBvar_expand\fR pass might have introduced now quoted pairs into the output text, which you need to expand to get the desired effect. .SH "EXCEPTION HANDLING" .IX Header "EXCEPTION HANDLING" \&\fB\s-1OSSP\s0 var\fR can be optionally built with support for exception handling via \fB\s-1OSSP\s0 ex\fR (see http://www.ossp.org/pkg/lib/ex/). For this it has to be configured with the \s-1GNU\s0 Autoconf option \f(CW\*(C`\-\-with\-ex\*(C'\fR. The difference then is that the \fB\s-1OSSP\s0 var\fR \s-1API\s0 functions throw exceptions instead of returning \f(CW\*(C`VAR_ERR_XXX\*(C'\fR return codes. .PP The thrown exceptions can be identified as \fB\s-1OSSP\s0 var\fR exceptions by checking the exception attribute \fBex_class\fR. It is the \fB\s-1OSSP\s0 var\fR \&\s-1API\s0 symbol \fBvar_id\fR for all \fB\s-1OSSP\s0 var\fR exceptions. The \fBex_object\fR attribute is always \f(CW\*(C`NULL\*(C'\fR. The \fBex_value\fR attribute is the \&\fBvar_rc_t\fR which forced the throwing of the exception. .PP Exception throwing can be suppressed with \fBex_shield\fR only. .SH "EXAMPLE (DEVELOPER)" .IX Header "EXAMPLE (DEVELOPER)" The following simple but complete program illustrates the full usage of \fB\s-1OSSP\s0 var\fR. 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. .PP .Vb 3 \& #include \& #include \& #include .Ve .PP .Vb 1 \& #include "var.h" .Ve .PP .Vb 6 \& 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]; .Ve .PP .Vb 12 \& 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] = '\e0'; \& if ((*val_ptr = getenv(tmp)) == NULL) \& return VAR_ERR_UNDEFINED_VARIABLE; \& *val_len = strlen(*val_ptr); \& *val_size = 0; \& return VAR_OK; \& } .Ve .PP .Vb 3 \& static void die(const char *context, var_t *var, var_rc_t rc) \& { \& char *error; .Ve .PP .Vb 4 \& var_strerror(var, rc, &error); \& fprintf(stderr, "ERROR: %s: %s (%d)\en", context, error, rc); \& exit(1); \& } .Ve .PP .Vb 9 \& 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 = { '\e\e', '$', '{', '}', '[', ']', '#', "a-zA-Z0-9_" }; .Ve .PP .Vb 6 \& /* 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: \e"%s\e"\en", src_ptr); .Ve .PP .Vb 7 \& /* 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); .Ve .PP .Vb 5 \& /* 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: \e"%s\e"\en", src_ptr); .Ve .PP .Vb 9 \& /* 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: \e"%s\e"\en", dst_ptr); \& fprintf(stdout, " %*s\en", dst_len, "^"); \& } \& die("variable expansion", var, rc); \& } \& fprintf(stdout, "expanded: \e"%s\e"\en", dst_ptr); .Ve .PP .Vb 5 \& /* 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: \e"%s\e"\en", dst_ptr); \& free(dst_ptr); .Ve .PP .Vb 3 \& /* destroy variable expansion context */ \& if ((rc = var_destroy(var)) != VAR_OK) \& die("destroy context", var, rc); .Ve .PP .Vb 2 \& return 0; \& } .Ve .PP Copy & paste the source code into a file \fIvar_play.c\fR (or use the version already shipped with the \fB\s-1OSSP\s0 var\fR source distribution), compile it with .PP .Vb 3 \& $ cc `var-config --cflags` \e \& -o var_play var_play.c \e \& `var-config --ldflags --libs` .Ve .PP and use it to play with the various \fB\s-1OSSP\s0 var\fR variable expansion possibilities. .SH "EXAMPLE (USER)" .IX Header "EXAMPLE (USER)" The following are a few sample use cases of \fB\s-1OSSP\s0 var\fR variable expansions. They all assume the default syntax configuration and the following variable definitions: \f(CW\*(C`$foo=foo\*(C'\fR (a scalar), \f(CW\*(C`$bar=\*(C'\fR (an array), \&\f(CW\*(C`$baz=\*(C'\fR (another array), \f(CW\*(C`$quux=quux\*(C'\fR (another scalar), \f(CW\*(C`$name=\*(C'\fR (another scalar) and \f(CW\*(C`$empty=""\*(C'\fR (another scalar). .PP .Vb 18 \& Input Output \& ----------------------------- -------------- \& $foo foo \& ${foo} foo \& ${bar[0]} bar1 \& ${${name[1]}[0]} bar1 \& ${foo:u:y/O/U/:s/(.*)/<\e1>/} \& ${foo:u:y/O/U/:s/(.*)/<\e1>/} \& ${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 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIpcre\fR\|(3), \fIregex\fR\|(7), \fB\s-1OSSP\s0 val\fR (Value Access), \fB\s-1OSSP\s0 ex\fR (Exception Handling). .SH "HISTORY" .IX Header "HISTORY" \&\fB\s-1OSSP\s0 var\fR was initially written by Peter Simons in November 2001 under contract with the \&\fB\s-1OSSP\s0\fR sponsor \fBCable & Wireless\fR. Its \s-1API\s0 and internal code structure was revamped in February 2002 by Ralf S. Engelschall to fully conform to the \fB\s-1OSSP\s0\fR 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.