Index: ossp-pkg/var/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/var/.cvsignore,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/var/.cvsignore,v' 2>/dev/null --- .cvsignore 2001/11/20 20:02:21 1.3 +++ .cvsignore 2002/02/28 08:08:16 1.4 @@ -1,13 +1,14 @@ -var_test -var.3 -shtool +Makefile config.guess +config.h +config.h.in config.sub -ltmain.sh -libtool.m4 configure -config.h.in -config.h -Makefile +libtool.m4 +ltmain.sh +shtool var-config var-config.1 +var.3 +var_play +var_test Index: ossp-pkg/var/Makefile.in RCS File: /v/ossp/cvs/ossp-pkg/var/Makefile.in,v rcsdiff -q -kk '-r1.4' '-r1.5' -u '/v/ossp/cvs/ossp-pkg/var/Makefile.in,v' 2>/dev/null --- Makefile.in 2002/02/27 13:44:16 1.4 +++ Makefile.in 2002/02/28 08:08:16 1.5 @@ -53,6 +53,9 @@ TST_NAME = var_test TST_OBJS = var_test.o +PLY_NAME = var_play +PLY_OBJS = var_play.o + MAN_NAME = var-config.1 var.3 # helper macro for generating a Unix manual page @@ -68,7 +71,7 @@ .SUFFIXES: .SUFFIXES: .c .o .lo -all: $(LIB_NAME) $(TST_NAME) $(MAN_NAME) +all: $(LIB_NAME) $(TST_NAME) $(PLY_NAME) $(MAN_NAME) .c.o: $(CC) $(CPPFLAGS) $(CFLAGS) -c $< @@ -77,6 +80,7 @@ $(LIB_OBJS): Makefile $(TST_OBJS): Makefile +$(PLY_OBJS): Makefile $(LIB_NAME): $(LIB_OBJS) @$(LIBTOOL) --mode=link $(CC) -o $(LIB_NAME) $(LIB_OBJS) -rpath $(libdir) \ @@ -85,6 +89,9 @@ $(TST_NAME): $(TST_OBJS) $(LIB_NAME) @$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $(TST_NAME) $(TST_OBJS) $(LIB_NAME) $(LIBS) +$(PLY_NAME): $(PLY_OBJS) $(LIB_NAME) + @$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $(PLY_NAME) $(PLY_OBJS) $(LIB_NAME) $(LIBS) + var-config.1: var-config.pod VERSION BASENAME="var-config"; SEC=1; \ NAME="VAR"; ONELINE="Variable Expansion Library"; \ @@ -112,6 +119,7 @@ clean: -$(RM) $(LIB_NAME) $(LIB_OBJS) -$(RM) $(TST_NAME) $(TST_OBJS) + -$(RM) $(PLY_NAME) $(PLY_OBJS) distclean: clean -$(RM) config.log config.status config.cache Index: ossp-pkg/var/TODO RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/TODO,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/var/Attic/TODO,v' 2>/dev/null --- TODO 2002/02/27 11:56:01 1.12 +++ TODO 2002/02/28 08:08:16 1.13 @@ -1,5 +1,10 @@ OSSP var + o add README + o generate internals into context + o use internal context to carry information + o document exception handling + o document arithmetic expressions o document loop construct --------------------------------------------------------------------- @@ -116,9 +121,7 @@ ${foo[$#{foo}]} --------------------------------------------------------------------- - o manual page style cleanup and perhaps merge with var_qref.pod? - - o add library context and move initialization and configuration + o add internal library context and move initialization and configuration into this context. o bugfix?: (thl) Index: ossp-pkg/var/VERSION RCS File: /v/ossp/cvs/ossp-pkg/var/VERSION,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/var/VERSION,v' 2>/dev/null --- VERSION 2002/02/27 13:44:16 1.2 +++ VERSION 2002/02/28 08:08:16 1.3 @@ -1,6 +1,6 @@ - VERSION -- Version Information for OSSP var (syntax: Text) + VERSION -- Version Information for OSSP VAR (syntax: Text) [automatically generated and maintained by GNU shtool] - This is OSSP var, Version 0.1.0 (20-Nov-2001) + This is OSSP VAR, Version 0.9.0 (28-Feb-2002) Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v rcsdiff -q -kk '-r1.61' '-r1.62' -u '/v/ossp/cvs/ossp-pkg/var/var.c,v' 2>/dev/null --- var.c 2002/02/27 13:44:16 1.61 +++ var.c 2002/02/28 08:08:16 1.62 @@ -31,6 +31,8 @@ #include "config.h" #endif +#include +#include #include #include #include @@ -56,75 +58,29 @@ #define VAR_RC(rv) (rv) #endif /* WITH_EX */ -/* The default configuration for the parser. */ - -const var_config_t var_config_default = { - '$', /* varinit */ - '{', /* startdelim */ - '}', /* enddelim */ - '[', /* startindex */ - ']', /* endindex */ - '#', /* current_index */ - '\\', /* escape */ - "a-zA-Z0-9_" /* namechars */ +/* the external context structure */ +struct var_st { + var_syntax_t syntax; + var_cb_value_t cb_value_fct; + void *cb_value_ctx; }; -/* The var_strerror() routine will map a var_rc_t into a text message. */ - -const char *var_strerror(var_rc_t rc) -{ - static char *var_errors[] = { - "everything ok", /* VAR_OK = 0 */ - "incomplete named character", /* VAR_ERR_INCOMPLETE_NAMED_CHARACTER */ - "incomplete hexadecimal value", /* VAR_ERR_INCOMPLETE_HEX */ - "invalid hexadecimal value", /* VAR_ERR_INVALID_HEX */ - "octal value too large", /* VAR_ERR_OCTAL_TOO_LARGE */ - "invalid octal value", /* VAR_ERR_INVALID_OCTAL */ - "incomplete octal value", /* VAR_ERR_INCOMPLETE_OCTAL */ - "incomplete grouped hexadecimal value", /* VAR_ERR_INCOMPLETE_GROUPED_HEX */ - "incorrect character class specification", /* VAR_ERR_INCORRECT_CLASS_SPEC */ - "invalid expansion configuration", /* VAR_ERR_INVALID_CONFIGURATION */ - "out of memory", /* VAR_ERR_OUT_OF_MEMORY */ - "incomplete variable specification", /* VAR_ERR_INCOMPLETE_VARIABLE_SPEC */ - "undefined variable", /* VAR_ERR_UNDEFINED_VARIABLE */ - "input is neither text nor variable", /* VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE */ - "unknown command character in variable", /* VAR_ERR_UNKNOWN_COMMAND_CHAR */ - "malformated search and replace operation", /* VAR_ERR_MALFORMATTED_REPLACE */ - "unknown flag in search and replace operation", /* VAR_ERR_UNKNOWN_REPLACE_FLAG */ - "invalid regular expression in search and replace operation", /* VAR_ERR_INVALID_REGEX_IN_REPLACE */ - "missing parameter in command", /* VAR_ERR_MISSING_PARAMETER_IN_COMMAND */ - "empty search string in search and replace operation", /* VAR_ERR_EMPTY_SEARCH_STRING */ - "start offset missing in cut operation", /* VAR_ERR_MISSING_START_OFFSET */ - "offsets in cut operation delimited by unknown character", /* VAR_ERR_INVALID_OFFSET_DELIMITER */ - "range out of bounds in cut operation", /* VAR_ERR_RANGE_OUT_OF_BOUNDS */ - "offset out of bounds in cut operation", /* VAR_ERR_OFFSET_OUT_OF_BOUNDS */ - "logic error in cut operation", /* VAR_ERR_OFFSET_LOGIC */ - "malformatted transpose operation", /* VAR_ERR_MALFORMATTED_TRANSPOSE */ - "source and destination classes do not match in transpose operation", /* VAR_ERR_TRANSPOSE_CLASSES_MISMATCH */ - "empty character class in transpose operation", /* VAR_ERR_EMPTY_TRANSPOSE_CLASS */ - "incorrect character class in transpose operation", /* VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC */ - "malformatted padding operation", /* VAR_ERR_MALFORMATTED_PADDING */ - "width parameter missing in padding operation", /* VAR_ERR_MISSING_PADDING_WIDTH */ - "fill string missing in padding operation", /* VAR_ERR_EMPTY_PADDING_FILL_STRING */ - "unknown quoted pair in search and replace operation", /* VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE */ - "sub-matching reference out of range", /* VAR_ERR_SUBMATCH_OUT_OF_RANGE */ - "invalid argument", /* VAR_ERR_INVALID_ARGUMENT */ - "incomplete quoted pair", /* VAR_ERR_INCOMPLETE_QUOTED_PAIR */ - "lookup function does not support variable arrays", /* VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED */ - "index specification of array variable contains an invalid character", /* VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC */ - "index specification of array variable is incomplete", /* VAR_ERR_INCOMPLETE_INDEX_SPEC */ - "bracket expression in array variable's index is not closed", /* VAR_ERR_UNCLOSED_BRACKET_IN_INDEX */ - "division by zero error in index specification", /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX */ - "unterminated loop construct", /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT */ - "invalid character in loop limits" /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS */ - }; - - rc = 0 - rc; - if (rc < 0 || rc >= sizeof(var_errors) / sizeof(char *)) - return "unknown error"; +/* the internal expansion context structure */ +typedef struct { + int force_expand; +} var_expand_t; - return var_errors[rc]; -} +/* the default syntax configuration */ +static const var_syntax_t var_syntax_default = { + '\\', /* escape */ + '$', /* delim_init */ + '{', /* delim_open */ + '}', /* delim_close */ + '[', /* index_open */ + ']', /* index_close */ + '#', /* index_mark */ + "a-zA-Z0-9_" /* name_chars */ +}; /* Routines for manipulation of token buffers. */ @@ -384,85 +340,25 @@ return expand_simple_hex(src, dst, end); } -var_rc_t var_unescape(const char *src, size_t len, char *dst, - int unescape_all) -{ - const char *end = src + len; - var_rc_t rc; - - while (src < end) { - if (*src == '\\') { - if (++src == end) - return VAR_RC(VAR_ERR_INCOMPLETE_NAMED_CHARACTER); - switch (*src) { - case '\\': - if (!unescape_all) { - *dst++ = '\\'; - } - *dst++ = '\\'; - break; - case 'n': - *dst++ = '\n'; - break; - case 't': - *dst++ = '\t'; - break; - case 'r': - *dst++ = '\r'; - break; - case 'x': - ++src; - if ((rc = expand_hex(&src, &dst, end)) != VAR_OK) - return VAR_RC(rc); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (end - src >= 3 && isdigit((int)src[1]) && isdigit((int)src[2])) { - if ((rc = expand_octal(&src, &dst, end)) != 0) - return VAR_RC(rc); - break; - } - default: - if (!unescape_all) { - *dst++ = '\\'; - } - *dst++ = *src; - } - ++src; - } else - *dst++ = *src++; - } - *dst = '\0'; - return VAR_OK; -} - /* The recursive-descent parser for variable expressions. */ static int variable(const char *begin, const char *end, - const var_config_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context, - int force_expand, tokenbuf_t *result, int current_index, + const var_syntax_t *config, const char_class_t nameclass, + var_cb_value_t lookup, void *lookup_context, + int force_expand, tokenbuf_t *result, int index_mark, int* rel_lookup_flag); static int command(const char *begin, const char *end, - const var_config_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *data, int current_index, int* rel_lookup_flag); -static int num_exp(const char *begin, const char *end, int current_index, + const var_syntax_t *config, const char_class_t nameclass, + var_cb_value_t lookup, void *lookup_context, int force_expand, + tokenbuf_t *data, int index_mark, int* rel_lookup_flag); +static int num_exp(const char *begin, const char *end, int index_mark, int* result, int* failed, int* rel_lookup_flag, - const var_config_t *config, + const var_syntax_t *config, const char_class_t nameclass, - var_cb_t lookup, void* lookup_context); + var_cb_value_t lookup, void* lookup_context); -static int text(const char *begin, const char *end, char varinit, - char startindex, char endindex, char escape) +static int text(const char *begin, const char *end, char delim_init, + char index_open, char index_close, char escape) { const char *p; @@ -471,9 +367,9 @@ if (++p == end) return VAR_ERR_INCOMPLETE_QUOTED_PAIR; } - else if (*p == varinit) + else if (*p == delim_init) break; - else if (startindex && (*p == startindex || *p == endindex)) + else if (index_open && (*p == index_open || *p == index_close)) break; } return p - begin; @@ -499,11 +395,11 @@ } static int substext(const char *begin, const char *end, - const var_config_t *config) + const var_syntax_t *config) { const char *p; - for (p = begin; p != end && *p != config->varinit && *p != '/'; p++) { + for (p = begin; p != end && *p != config->delim_init && *p != '/'; p++) { if (*p == config->escape) { if (p + 1 == end) return VAR_ERR_INCOMPLETE_QUOTED_PAIR; @@ -514,14 +410,14 @@ } static int exptext(const char *begin, const char *end, - const var_config_t *config) + const var_syntax_t *config) { const char *p; for (p = begin; p != end - && *p != config->varinit - && *p != config->enddelim + && *p != config->delim_init + && *p != config->delim_close && *p != ':'; p++) { if (*p == config->escape) { if (p + 1 == end) @@ -544,11 +440,11 @@ return num; } -static int num_exp_read_operand(const char *begin, const char *end, int current_index, +static int num_exp_read_operand(const char *begin, const char *end, int index_mark, int *result, int *failed, int *rel_lookup_flag, - const var_config_t *config, + const var_syntax_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context) + var_cb_value_t lookup, void *lookup_context) { const char* p = begin; tokenbuf_t tmp; @@ -560,7 +456,7 @@ return VAR_ERR_INCOMPLETE_INDEX_SPEC; if (*p == '(') { - rc = num_exp(++p, end, current_index, result, failed, + rc = num_exp(++p, end, index_mark, result, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -571,13 +467,13 @@ return VAR_ERR_UNCLOSED_BRACKET_IN_INDEX; ++p; } - else if (*p == config->varinit) { + else if (*p == config->delim_init) { rc = variable(p, end, config, nameclass, lookup, - lookup_context, 1, &tmp, current_index, rel_lookup_flag); + lookup_context, 1, &tmp, index_mark, rel_lookup_flag); if (rc == VAR_ERR_UNDEFINED_VARIABLE) { *failed = 1; rc = variable(p, end, config, nameclass, lookup, - lookup_context, 0, &tmp, current_index, rel_lookup_flag); + lookup_context, 0, &tmp, index_mark, rel_lookup_flag); if (rc < 0) return rc; p += rc; @@ -587,16 +483,16 @@ if (rc < 0) return rc; p += rc; - rc = num_exp(tmp.begin, tmp.end, current_index, result, + rc = num_exp(tmp.begin, tmp.end, index_mark, result, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); tokenbuf_free(&tmp); if (rc < 0) return rc; } } - else if (config->current_index && *p == config->current_index) { + else if (config->index_mark && *p == config->index_mark) { p++; - *result = current_index; + *result = index_mark; (*rel_lookup_flag)++; } else if (isdigit(*p)) { @@ -625,11 +521,11 @@ return p - begin; } -static int num_exp(const char *begin, const char *end, int current_index, +static int num_exp(const char *begin, const char *end, int index_mark, int *result, int *failed, int *rel_lookup_flag, - const var_config_t *config, + const var_syntax_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context) + var_cb_value_t lookup, void *lookup_context) { const char *p = begin; char operator; @@ -639,7 +535,7 @@ if (begin == end) return VAR_ERR_INCOMPLETE_INDEX_SPEC; - rc = num_exp_read_operand(p, end, current_index, result, + rc = num_exp_read_operand(p, end, index_mark, result, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) @@ -649,7 +545,7 @@ while (p != end) { if (*p == '+' || *p == '-') { operator = *p++; - rc = num_exp(p, end, current_index, &right, failed, + rc = num_exp(p, end, index_mark, &right, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -661,7 +557,7 @@ } else if (*p == '*' || *p == '/' || *p == '%') { operator = *p++; - rc = num_exp_read_operand(p, end, current_index, &right, failed, + rc = num_exp_read_operand(p, end, index_mark, &right, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -697,10 +593,10 @@ } static int expression(const char *begin, const char *end, - const var_config_t *config, - const char_class_t nameclass, var_cb_t lookup, + const var_syntax_t *config, + const char_class_t nameclass, var_cb_value_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result, int current_index, int *rel_lookup_flag) + tokenbuf_t *result, int index_mark, int *rel_lookup_flag) { const char *p = begin; const char *data; @@ -719,7 +615,7 @@ /* Expect STARTDELIM. */ - if (p == end || *p != config->startdelim) + if (p == end || *p != config->delim_open) return 0; if (++p == end) @@ -741,7 +637,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp, current_index, rel_lookup_flag); + force_expand, &tmp, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc > 0) { @@ -763,8 +659,8 @@ /* If the next token is START-INDEX, read the index specification. */ - if (config->startindex && *p == config->startindex) { - rc = num_exp(++p, end, current_index, &idx, &failed, + if (config->index_open && *p == config->index_open) { + rc = num_exp(++p, end, index_mark, &idx, &failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) goto error_return; @@ -778,7 +674,7 @@ rc = VAR_ERR_INCOMPLETE_INDEX_SPEC; goto error_return; } - if (*p != config->endindex) { + if (*p != config->index_close) { rc = VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC; goto error_return; } @@ -788,7 +684,7 @@ /* Now we have the name of the variable stored in "name". The next token here must either be an END-DELIM or a ':'. */ - if (p == end || (*p != config->enddelim && *p != ':')) { + if (p == end || (*p != config->delim_close && *p != ':')) { rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC; goto error_return; } @@ -839,11 +735,11 @@ if (!failed) rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, result, - current_index, rel_lookup_flag); + index_mark, rel_lookup_flag); else rc = command(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmp, - current_index, rel_lookup_flag); + index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -851,7 +747,7 @@ result->end += rc; } - if (p == end || *p != config->enddelim) { + if (p == end || *p != config->delim_close) { rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC; goto error_return; } @@ -876,9 +772,9 @@ } static int variable(const char *begin, const char *end, - const var_config_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context, - int force_expand, tokenbuf_t *result, int current_index, + const var_syntax_t *config, const char_class_t nameclass, + var_cb_value_t lookup, void *lookup_context, + int force_expand, tokenbuf_t *result, int index_mark, int *rel_lookup_flag) { const char *p = begin; @@ -893,7 +789,7 @@ /* Expect VARINIT. */ - if (p == end || *p != config->varinit) + if (p == end || *p != config->delim_init) return 0; if (++p == end) @@ -924,17 +820,17 @@ /* OK, we're dealing with a complex expression here. */ rc = expression(p, end, config, nameclass, lookup, lookup_context, - force_expand, result, current_index, rel_lookup_flag); + force_expand, result, index_mark, rel_lookup_flag); if (rc > 0) rc++; return rc; } static int exptext_or_variable(const char *begin, const char *end, - const var_config_t *config, - const char_class_t nameclass, var_cb_t lookup, + const var_syntax_t *config, + const char_class_t nameclass, var_cb_value_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result, int current_index, + tokenbuf_t *result, int index_mark, int *rel_lookup_flag) { const char *p = begin; @@ -960,7 +856,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp, current_index, rel_lookup_flag); + force_expand, &tmp, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc > 0) { @@ -983,10 +879,10 @@ } static int substext_or_variable(const char *begin, const char *end, - const var_config_t *config, - const char_class_t nameclass, var_cb_t lookup, + const var_syntax_t *config, + const char_class_t nameclass, var_cb_value_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result, int current_index, + tokenbuf_t *result, int index_mark, int *rel_lookup_flag) { const char *p = begin; @@ -1012,7 +908,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp, current_index, rel_lookup_flag); + force_expand, &tmp, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc > 0) { @@ -1469,9 +1365,9 @@ } static int command(const char *begin, const char *end, - const var_config_t *config, const char_class_t nameclass, - var_cb_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *data, int current_index, int *rel_lookup_flag) + const var_syntax_t *config, const char_class_t nameclass, + var_cb_value_t lookup, void *lookup_context, int force_expand, + tokenbuf_t *data, int index_mark, int *rel_lookup_flag) { const char *p = begin; tokenbuf_t tmptokbuf; @@ -1577,7 +1473,7 @@ p++; rc = exptext_or_variable(p, end, config, nameclass, lookup, lookup_context, force_expand, &tmptokbuf, - current_index, rel_lookup_flag); + index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc == 0) { @@ -1594,7 +1490,7 @@ case '*': /* Return "" if data is not empty, parameter otherwise. */ p++; rc = exptext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmptokbuf, current_index, rel_lookup_flag); + lookup_context, force_expand, &tmptokbuf, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc == 0) { @@ -1617,7 +1513,7 @@ case '+': /* Substitute parameter if data is not empty. */ p++; rc = exptext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmptokbuf, current_index, rel_lookup_flag); + lookup_context, force_expand, &tmptokbuf, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; if (rc == 0) { @@ -1639,7 +1535,7 @@ p++; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &search, current_index, rel_lookup_flag); + lookup_context, force_expand, &search, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -1651,7 +1547,7 @@ p++; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace, current_index, rel_lookup_flag); + lookup_context, force_expand, &replace, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -1685,7 +1581,7 @@ p++; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &search, current_index, rel_lookup_flag); + lookup_context, force_expand, &search, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -1697,7 +1593,7 @@ p++; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace, current_index, rel_lookup_flag); + lookup_context, force_expand, &replace, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -1740,7 +1636,7 @@ p++; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace, current_index, rel_lookup_flag); + lookup_context, force_expand, &replace, index_mark, rel_lookup_flag); if (rc < 0) goto error_return; p += rc; @@ -1790,7 +1686,7 @@ } struct wrapper_context { - var_cb_t lookup; + var_cb_value_t lookup; void *context; int *rel_lookup_flag; }; @@ -1817,9 +1713,9 @@ } static var_rc_t loop_limits(const char *begin, const char *end, - const var_config_t *config, + const var_syntax_t *config, const char_class_t nameclass, - var_cb_t lookup, void* lookup_context, + var_cb_value_t lookup, void* lookup_context, int* start, int* step, int* stop, int* open_end) { const char* p = begin; @@ -1830,7 +1726,7 @@ if (begin == end) return 0; - if (*p != config->startdelim) + if (*p != config->delim_open) return 0; else ++p; @@ -1870,7 +1766,7 @@ if (*p != ',') { - if (*p != config->enddelim) + if (*p != config->delim_close) return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; else { @@ -1907,17 +1803,17 @@ if (failed) return VAR_ERR_UNDEFINED_VARIABLE; - if (*p != config->enddelim) + if (*p != config->delim_close) return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; return ++p - begin; } static var_rc_t input(const char *begin, const char *end, - const var_config_t *config, - const char_class_t nameclass, var_cb_t lookup, + const var_syntax_t *config, + const char_class_t nameclass, var_cb_value_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *output, int current_index, + tokenbuf_t *output, int index_mark, size_t recursion_level, int *rel_lookup_flag) { const char *p = begin; @@ -1939,7 +1835,7 @@ } do { - if (begin != end && config->startindex && *begin == config->startindex) { + if (begin != end && config->index_open && *begin == config->index_open) { original_rel_lookup_state = *rel_lookup_flag; loop_limit_length = -1; wcon.lookup = lookup; @@ -1963,7 +1859,7 @@ &wcon, 1, output, i, recursion_level+1, rel_lookup_flag); if (rc < 0) goto error_return; - if (begin[rc] != config->endindex) { + if (begin[rc] != config->index_close) { rc = VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT; goto error_return; } @@ -1998,8 +1894,8 @@ continue; } - rc = text(begin, end, config->varinit, config->startindex, - config->endindex, config->escape); + rc = text(begin, end, config->delim_init, config->index_open, + config->index_close, config->escape); if (rc > 0) { if (!tokenbuf_append(output, begin, rc)) { rc = VAR_ERR_OUT_OF_MEMORY; @@ -2012,7 +1908,7 @@ rc = variable(begin, end, config, nameclass, lookup, lookup_context, force_expand, &result, - current_index, rel_lookup_flag); + index_mark, rel_lookup_flag); if (rc > 0) { if (!tokenbuf_append(output, result.begin, result.end - result.begin)) { rc = VAR_ERR_OUT_OF_MEMORY; @@ -2041,10 +1937,11 @@ return rc; } -var_rc_t var_expand(const char *input_buf, 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) +static var_rc_t internal_expand( + const char *input_buf, size_t input_len, + char **result, size_t *result_len, + var_cb_value_t lookup, void *lookup_context, + const var_syntax_t *config, int force_expand) { char_class_t nameclass; var_rc_t rc; @@ -2058,21 +1955,21 @@ /* Optionally use default configuration */ if (config == NULL) - config = &var_config_default; + config = &var_syntax_default; /* Set the result pointer to the begining of the input buffer so that it is correctly initialized in case we fail with an error. */ *result = (char *)input_buf; /* Expand the class description for valid variable names. */ - if ((rc = expand_character_class(config->namechars, nameclass)) != VAR_OK) + if ((rc = expand_character_class(config->name_chars, nameclass)) != VAR_OK) return VAR_RC(rc); /* Make sure that the specials defined in the configuration do not appear in the character name class. */ - if (nameclass[(int)config->varinit] || - nameclass[(int)config->startdelim] || - nameclass[(int)config->enddelim] || + if (nameclass[(int)config->delim_init] || + nameclass[(int)config->delim_open] || + nameclass[(int)config->delim_close] || nameclass[(int)config->escape]) return VAR_RC(VAR_ERR_INVALID_CONFIGURATION); @@ -2108,3 +2005,212 @@ return VAR_RC(rc); } +/* ------------------------------------------------------------------ */ + +var_rc_t +var_create( + var_t **pvar) +{ + var_t *var; + + if (pvar == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + if ((var = (var_t *)malloc(sizeof(var_t))) == NULL) + return VAR_RC(VAR_ERR_OUT_OF_MEMORY); + memset(var, 0, sizeof(var)); + var_config(var, VAR_CONFIG_SYNTAX, &var_syntax_default); + *pvar = var; + return VAR_OK; +} + +var_rc_t +var_destroy( + var_t *var) +{ + if (var == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + free(var); + return VAR_OK; +} + +var_rc_t +var_config( + var_t *var, + var_config_t mode, + ...) +{ + va_list ap; + + if (var == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + va_start(ap, mode); + switch (mode) { + case VAR_CONFIG_SYNTAX: { + var_syntax_t *s; + s = (var_syntax_t *)va_arg(ap, void *); + if (s == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + var->syntax.escape = s->escape; + var->syntax.delim_init = s->delim_init; + var->syntax.delim_open = s->delim_open; + var->syntax.delim_close = s->delim_close; + var->syntax.index_open = s->index_open; + var->syntax.index_close = s->index_close; + var->syntax.index_mark = s->index_mark; + if (var->syntax.name_chars != NULL) + free(var->syntax.name_chars); + var->syntax.name_chars = strdup(s->name_chars); + break; + } + case VAR_CONFIG_CB_VALUE: { + var_cb_value_t fct; + void *ctx; + fct = (var_cb_value_t)va_arg(ap, void *); + ctx = (void *)va_arg(ap, void *); + var->cb_value_fct = fct; + var->cb_value_ctx = ctx; + break; + } + default: + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + } + va_end(ap); + return VAR_OK; +} + +var_rc_t +var_unescape( + var_t *var, + const char *src, size_t srclen, + char *dst, size_t dstlen, + int all) +{ + const char *end; + var_rc_t rc; + + if (var == NULL || src == NULL || dst == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + end = src + srclen; + while (src < end) { + if (*src == '\\') { + if (++src == end) + return VAR_RC(VAR_ERR_INCOMPLETE_NAMED_CHARACTER); + switch (*src) { + case '\\': + if (!all) { + *dst++ = '\\'; + } + *dst++ = '\\'; + break; + case 'n': + *dst++ = '\n'; + break; + case 't': + *dst++ = '\t'; + break; + case 'r': + *dst++ = '\r'; + break; + case 'x': + ++src; + if ((rc = expand_hex(&src, &dst, end)) != VAR_OK) + return VAR_RC(rc); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if ( end - src >= 3 + && isdigit((int)src[1]) + && isdigit((int)src[2])) { + if ((rc = expand_octal(&src, &dst, end)) != 0) + return VAR_RC(rc); + break; + } + default: + if (!all) { + *dst++ = '\\'; + } + *dst++ = *src; + } + ++src; + } else + *dst++ = *src++; + } + *dst = '\0'; + return VAR_OK; +} + +var_rc_t +var_expand( + var_t *var, + const char *src, size_t srclen, + char **dst, size_t *dstlen, + int force_expand) +{ + /* var_expand_t ctx; */ + var_rc_t rc; + + /* ctx.force_expand = force_expand; */ + rc = internal_expand(src, srclen, dst, dstlen, + var->cb_value_fct, var->cb_value_ctx, + &var->syntax, force_expand); + return rc; +} + +var_rc_t var_strerror(var_t *var, var_rc_t rc, char **str) +{ + static char *errors[] = { + "everything ok", /* VAR_OK = 0 */ + "incomplete named character", /* VAR_ERR_INCOMPLETE_NAMED_CHARACTER */ + "incomplete hexadecimal value", /* VAR_ERR_INCOMPLETE_HEX */ + "invalid hexadecimal value", /* VAR_ERR_INVALID_HEX */ + "octal value too large", /* VAR_ERR_OCTAL_TOO_LARGE */ + "invalid octal value", /* VAR_ERR_INVALID_OCTAL */ + "incomplete octal value", /* VAR_ERR_INCOMPLETE_OCTAL */ + "incomplete grouped hexadecimal value", /* VAR_ERR_INCOMPLETE_GROUPED_HEX */ + "incorrect character class specification", /* VAR_ERR_INCORRECT_CLASS_SPEC */ + "invalid expansion configuration", /* VAR_ERR_INVALID_CONFIGURATION */ + "out of memory", /* VAR_ERR_OUT_OF_MEMORY */ + "incomplete variable specification", /* VAR_ERR_INCOMPLETE_VARIABLE_SPEC */ + "undefined variable", /* VAR_ERR_UNDEFINED_VARIABLE */ + "input is neither text nor variable", /* VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE */ + "unknown command character in variable", /* VAR_ERR_UNKNOWN_COMMAND_CHAR */ + "malformated search and replace operation", /* VAR_ERR_MALFORMATTED_REPLACE */ + "unknown flag in search and replace operation", /* VAR_ERR_UNKNOWN_REPLACE_FLAG */ + "invalid regular expression in search and replace operation", /* VAR_ERR_INVALID_REGEX_IN_REPLACE */ + "missing parameter in command", /* VAR_ERR_MISSING_PARAMETER_IN_COMMAND */ + "empty search string in search and replace operation", /* VAR_ERR_EMPTY_SEARCH_STRING */ + "start offset missing in cut operation", /* VAR_ERR_MISSING_START_OFFSET */ + "offsets in cut operation delimited by unknown character", /* VAR_ERR_INVALID_OFFSET_DELIMITER */ + "range out of bounds in cut operation", /* VAR_ERR_RANGE_OUT_OF_BOUNDS */ + "offset out of bounds in cut operation", /* VAR_ERR_OFFSET_OUT_OF_BOUNDS */ + "logic error in cut operation", /* VAR_ERR_OFFSET_LOGIC */ + "malformatted transpose operation", /* VAR_ERR_MALFORMATTED_TRANSPOSE */ + "source and destination classes do not match in transpose operation", /* VAR_ERR_TRANSPOSE_CLASSES_MISMATCH */ + "empty character class in transpose operation", /* VAR_ERR_EMPTY_TRANSPOSE_CLASS */ + "incorrect character class in transpose operation", /* VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC */ + "malformatted padding operation", /* VAR_ERR_MALFORMATTED_PADDING */ + "width parameter missing in padding operation", /* VAR_ERR_MISSING_PADDING_WIDTH */ + "fill string missing in padding operation", /* VAR_ERR_EMPTY_PADDING_FILL_STRING */ + "unknown quoted pair in search and replace operation", /* VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE */ + "sub-matching reference out of range", /* VAR_ERR_SUBMATCH_OUT_OF_RANGE */ + "invalid argument", /* VAR_ERR_INVALID_ARGUMENT */ + "incomplete quoted pair", /* VAR_ERR_INCOMPLETE_QUOTED_PAIR */ + "lookup function does not support variable arrays", /* VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED */ + "index specification of array variable contains an invalid character", /* VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC */ + "index specification of array variable is incomplete", /* VAR_ERR_INCOMPLETE_INDEX_SPEC */ + "bracket expression in array variable's index is not closed", /* VAR_ERR_UNCLOSED_BRACKET_IN_INDEX */ + "division by zero error in index specification", /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX */ + "unterminated loop construct", /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT */ + "invalid character in loop limits" /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS */ + }; + + if (str == NULL) + return VAR_RC(VAR_ERR_INVALID_ARGUMENT); + rc = 0 - rc; + if (rc < 0 || rc >= sizeof(errors) / sizeof(char *)) + *str = "unknown error"; + else + *str = errors[rc]; + return VAR_OK; +} + Index: ossp-pkg/var/var.h RCS File: /v/ossp/cvs/ossp-pkg/var/var.h,v rcsdiff -q -kk '-r1.23' '-r1.24' -u '/v/ossp/cvs/ossp-pkg/var/var.h,v' 2>/dev/null --- var.h 2002/02/27 13:44:16 1.23 +++ var.h 2002/02/28 08:08:16 1.24 @@ -77,46 +77,42 @@ VAR_ERR_INVALID_HEX = -3, VAR_ERR_INCOMPLETE_HEX = -2, VAR_ERR_INCOMPLETE_NAMED_CHARACTER = -1, - VAR_OK = 0 + VAR_OK = 0 } var_rc_t; -/* Expand quoted pairs to their binary representation. */ -var_rc_t var_unescape(const char *src, size_t len, char *dst, int unescape_all); +struct var_st; +typedef struct var_st var_t; -/* Prototype for the lookup callback used in var_expand(). */ -typedef var_rc_t (*var_cb_t)( - void *context, - const char *varname, size_t name_len, int idx, - const char **data, size_t *data_len, - size_t *buffer_size -); - -/* Configure the var_expand() parser's tokens. */ -typedef struct { - char varinit; /* '$' */ - char startdelim; /* '{' */ - char enddelim; /* '}' */ - char startindex; /* '[' */ - char endindex; /* ']' */ - char current_index; /* '#' */ - char escape; /* '\' */ - char *namechars; /* 'a-zA-Z0-9_' */ +typedef enum { + VAR_CONFIG_SYNTAX, + VAR_CONFIG_CB_VALUE } var_config_t; -/* The default configuration */ -extern const var_config_t var_config_default; - -/* Expand variable expressions in a text buffer. */ -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); - -/* Map an error code to a text message. */ -const char *var_strerror(var_rc_t rc); +typedef struct { + 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_" */ +} var_syntax_t; + +typedef var_rc_t (*var_cb_value_t)( + 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 +); -/* Unique library identifier. */ extern const char var_id[]; +var_rc_t var_create (var_t **var); +var_rc_t var_destroy (var_t *var); +var_rc_t var_config (var_t *var, var_config_t mode, ...); +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); +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); +var_rc_t var_strerror (var_t *var, var_rc_t rc, char **str); + #endif /* __VAR_H__ */ Index: ossp-pkg/var/var.pod RCS File: /v/ossp/cvs/ossp-pkg/var/var.pod,v rcsdiff -q -kk '-r1.20' '-r1.21' -u '/v/ossp/cvs/ossp-pkg/var/var.pod,v' 2>/dev/null --- 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, +B, +B, +B, +B. -=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 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, +B, +B, +B, +B, +B. -=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. =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 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, +C<${>IC<}>, C<$(>IC<)>, etc.) and provides both simple +scalar (C<${>IC<}>) and array (C<${>IC<[>IC<]}>) +expansion, plus optionally one or more post-operations on the expanded +value (C<${>IC<:>I[C<:>I...]]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<${>IC<[#+1]}>..C<]>..). + +The actual variable value lookup is performed through a callback +function, so B can expand arbitrary values. + +=head1 SYNTAX CONSTRUCTS + +A string expanded through B can consist of arbitrary text +characters plus one or more of the following special syntax constructs +which are expanded by B. =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:*} - -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:-} - -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:+} - -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-} - -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,} - -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///[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///} - -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///} - -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 - NUMBER : '[0-9]+' +Character with the octal value I +(I: C<0>,...,C<7>). - SUBSTTEXT : '[^$/]' +=item C<\x>I, C<\x{>IC<}> - EXPTEXT : '[^$}:]+' +Character with the hexadecimal value I or the characters +denoted by grouped hexadecimal numbers I. (I, I: +C<0>,...,C<9>,[C],...,[C]). - 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 -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. -=over 4 - -=item VAR_OK +=item C<$>I, C<${>IC<}> -No errors; everything went fine. +Contents of scalar variable I. -=item VAR_ERR_INCOMPLETE_QUOTED_PAIR +=item C<${>IC<[>IC<]>C<}> -The configured escape character as the last character in the input -buffer. +Contents of array variable I at position I. +For I full arithmetic expressions are allowed. -=item VAR_ERR_INVALID_ARGUMENT +=item C<${>IC<:#}> -Any of the provided arguments is invalid, for expample: the pointer to -the input buffer is NULL. +Length of C<$>I. -=item VAR_ERR_SUBMATCH_OUT_OF_RANGE +=item C<${>IC<:l}>, C<${>IC<: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, converted to all lower-case or all upper-case. -=item VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE +=item C<${>IC<:->IC<}> -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 is not empty string, then C<$>I, else I +(default value). -=item VAR_ERR_EMPTY_PADDING_FILL_STRING +=item C<${>IC<:+>IC<}> -The "fill" part in an ${name:p/width/fill/pos/} expression was found -to be empty. +If C<$>I is empty string, then empty string, else I +(positive alternative). -=item VAR_ERR_MISSING_PADDING_WIDTH +=item C<${>IC<:*>IC<}> -The "width" part in an ${name:p/width/fill/pos/} expression was found -to be empty. +If C<$>I is not empty string, then empty string, else I +(negative alternative). -=item VAR_ERR_MALFORMATTED_PADDING +=item C<${>IC<:o>IC<,>[I]C<}> -Any of the "/" delimiters was missing while parsing a -${name:p/width/fill/pos/} expression. +Substring of C<$>I starting at position I with I +characters. -=item VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC +=item C<${>IC<:o>IC<->[I]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 starting at position I and ending at +position I (inclusive). -=item VAR_ERR_EMPTY_TRANSPOSE_CLASS +=item C<${>IC<:s/>ICIC[C]C<}> -While parsing a ${name:y/old-class/new-class/} expression, any of the -character class specifications was found to be empty. +C<$>I after replacing characters matching I with +I. By default, case-sensitive regular expression matching is +performed and only the first occurance of I is replaced. Flag +"C" switches to case insensitive matching; flag "C" switches +to plain text pattern; flag "C" switches to replacements of all +occurances. -=item VAR_ERR_TRANSPOSE_CLASSES_MISMATCH +=item C<${>IC<:y/>ICIC -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 after replacing all characters found in the I +character class by the corresponding character in the I +character class. -=item VAR_ERR_MALFORMATTED_TRANSPOSE +=item C<${>IC<:p/>ICIC{C,C,C}C<}> -Any of the "/" delimiters was missing while parsing a -${name:y/old-class/new-class/} expression. +C<$>I after padding to I with I. Original contents +of I is either left justified (flag "C"), centered (flag +"C"), or right justified (flag "C"). -=item VAR_ERR_OFFSET_LOGIC -The "end" offset in a ${name:o,} expression is smaller -than the "start" offset. +=item C<[>IC<]>, C<[>IC<]>C<{>IC<,>IC<,>IC<}> -=item VAR_ERR_OFFSET_OUT_OF_BOUNDS +Repeat expansion of I as long as at least one array variable +does not expand to the empty string (first variant) or exactly +(I-I)/I times (second variant). In both cases the +character "C<#>" is expanded in C as the current loop index +(C<0>,... for first variant and I,...,I with stepping +I for second variant). I of array variable lookups. For +I, I and I, full arithmetic expressions are allowed. -The "start" offset in a ${name:o,} 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,} or ${name:o-} -expression would be greater than the number of characters found in -$name. +All the variable syntax constructs supported by B 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). -=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 B +language Application Programming Interface (API): -=item VAR_ERR_MISSING_START_OFFSET +=head2 TYPES -The "start" offset in a ${name:o,} or -${name:o-} expression was found to be empty. +The B API consists of the following B 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 -=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. On error, they return C. For a list of all +possible return codes see F. Their corresponding describing text +can be determined with var_strerror(). + +=item B + +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 + +This is an exported enumerated integer type describing configuration +parameters for var_config(). Currently C (for +configuring the syntax via B) and C +(for configuring the callback for value lookups via B) +are defined. + +=item B + +This is an exported structural data type describing the variable +construct syntax. It is passed to var_config() on C +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 +which is a character class listing all valid characters. As an +abbreviation the construct "IC<->I" is supported which means all +characters from I to I (both included) in the underlying character +set. + +=item B + +This is an exported function pointer type for variable value lookup +functions. Such a callback function B has to be of the following +prototype: + +var_rc_t *B(void *I, const char *I, size_t +I, int I, const char **I, size_t *I, +size_t *I); -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 -=item VAR_ERR_UNKNOWN_REPLACE_FLAG +This is the passed-through argument as passed to var_config() on +C 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 -=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 ('C<\0>') character. If the callback +function needs it C-terminated, it has to copy the string into an a +temporary buffer of its own and C-terminate it there. + +=item size_t I + +This is the length of the variable name at I. + +=item int I + +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. If I is less than zero, the callback should return +the number of entries in the array variable. If I 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 -=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:} expression, "char" did not specify any of the -supported operations. +=item size_t *I -=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 -=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 is interpreted by +var_expand() according to the following convention: C means +success, that is, the contents of the variable has been resolved +successfully and the I, I, and I variables +have been filled with appropriate values. A return code C +means that the resolving failed, such as a system error or lack of +resources. In the latter two cases, the contents of I, +I and I 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 return +code, the behaviour of var_expand() depends on the setting of its +I parameter. If I has been set, var_expand() +will pass-through this error to the caller. If I 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_expand() will fail with +this return code. If the cause for the error can not be denoted by an +error code defined in F, callback implementors should use the +error code C (which is currently defined to -64). +It is guaranteed that no error code smaller than C +is ever used by any B 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 - I) (I E= 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 API consists of the following B 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_t **I); -=item VAR_ERR_INCOMPLETE_GROUPED_HEX +Create a new variable expansion context and store it into I. -var_unescape() encountered the end of the input buffer in the middle -of a grouped-hex "\x{...}" expression. +=item var_rc_t B(var_t *I); -=item VAR_ERR_INCOMPLETE_OCTAL +Destroy the variable expansion context I. -var_unescape() encountered the end of the input buffer in the middle -of an octal "\000" expression. +=item var_rc_t B(var_t *I, var_config_t I, ...); -=item VAR_ERR_INVALID_OCTAL +Configure the variable expansion context I. The variable argument +list depends on the I 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_syntax_t *I -The value specified via an octal "\000" expression was larger than -0377. +This overrides the syntax configuration in I with the one provided +in I. The complete structure contents is copied, so the caller +is allowed to immediately destroy I after the var_config() call. +The default is the contents as shown above under the type description of +B. + +=item C, var_cb_value_t I, void *I + +This overrides the syntax configuration in I with the one provided +The default is C for I and I. At least C for I +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_t *I, const char *I, size_t I, char *I, size_t I, int I); -=item VAR_ERR_INCOMPLETE_HEX +This expands escape sequences found in the input buffer +I/I. The I/I 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+1 +characters. The reason is that var_unescape() always adds a terminating +C ('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 either has to be point to a pre-allocated buffer or +is allowed to point to I (because the unescaping operation is +guarrantied to either keep the size or reduce the size of the input). + +The parameter I 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 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 +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_t *I, const char *I, size_t I, char **I, size_t *I, int I); + +This is the heart of B. It expands all syntax constructs in +I/I and stores them in an allocated buffer returned +in I/I. + +The output buffer I/I 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-terminated by +var_expand(), but this C character is not counted for I. +The I pointer can be specified as C if you are not +interested in the output buffer length. + +The I flag determines how var_expand() deals with +undefined variables (indicated by the callback function through the +return code C). If it is set to true +(any value except zero), var_expand() will fail with error code +C 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 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 will point to I +and I will contain the number of characters that have been +consumed from I before the error occured. In other words, +if an error occurs, I/I point to the last parsing +location in I/I before the error occured. The only +exceptions for this error semantics are: on C +and C errors, I and I are +undefined. + +=item var_rc_t B(var_t *I, var_rc_t I, char **I); + +This can be used to map any B return codes (as returned by all +the B 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 and those based on it, cannot be +mapped and will yield the message "C". -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 =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 +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 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. 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 + #include + #include + + #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 (or use the version +already shipped with the B 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 variable expansion +possibilities. + +=head1 SEE ALSO + +pcre(3), regex(7), B (Value Access). + +=head1 HISTORY + +B was written by Peter Simons Esimons@crypt.toE in +November 2001. Its API and internal code structure was revamped in +February 2002 by Ralf S. Engelschall Erse@engelschall.comE to +fully conform to the B library standards. =cut + Index: ossp-pkg/var/var_play.c RCS File: /v/ossp/cvs/ossp-pkg/var/var_play.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/var/var_play.c,v' | diff -u /dev/null - -L'ossp-pkg/var/var_play.c' 2>/dev/null --- ossp-pkg/var/var_play.c +++ - 2024-05-02 02:52:05.518355092 +0200 @@ -0,0 +1,90 @@ + +#include +#include +#include + +#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; +} + Index: ossp-pkg/var/var_qref.pod RCS File: /v/ossp/cvs/ossp-pkg/var/Attic/var_qref.pod,v co -q -kk -p'1.3' '/v/ossp/cvs/ossp-pkg/var/Attic/var_qref.pod,v' | diff -u - /dev/null -L'ossp-pkg/var/var_qref.pod' 2>/dev/null --- ossp-pkg/var/var_qref.pod +++ /dev/null 2024-05-02 02:52:01.000000000 +0200 @@ -1,145 +0,0 @@ -## -## OSSP var -- Variable Expansion -## Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/) -## Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) -## -## This file is part of OSSP var, a variable expansion -## library which can be found at http://www.ossp.org/pkg/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_qref.pod: Quick Reference manual page source -## - -=pod - -=head1 NAME - -var_qref -- OSSP var Quick Reference - -=head1 DESCRIPTION - -A string expanded through B can consist of arbitrary text -characters plus one or more of the following special syntax constructs -which are expanded by B. This is just a very brief summary. -For more details see var(3). - -=over 4 - -=item C<\>I - -Character with the octal value I -(I: C<0>,...,C<7>). - -=item C<\x>I, C<\x{>IC<}> - -Character with the hexadecimal value I or the characters -denoted by grouped hexadecimal numbers I. (I, I: -C<0>,...,C<9>,[C],...,[C]). - -=item C<\t>, C<\r>, C<\n> - -Tabulator, Carriage Return and Newline character. - -=item C<\\>, C<\>I - -Ordinary character C<\> and I. - -=item C<$>I, C<${>IC<}> - -Contents of scalar variable I. - -=item C<${>IC<[>IC<]>C<}> - -Contents of array variable I at position I. -For I full arithmetic expressions are allowed. - -=item C<${>IC<:#}> - -Length of C<$>I. - -=item C<${>IC<:l}>, C<${>IC<:u}> - -C<$>I, converted to all lower-case or all upper-case. - -=item C<${>IC<:->IC<}> - -If C<$>I is not empty string, then C<$>I, else I -(default value). - -=item C<${>IC<:+>IC<}> - -If C<$>I is empty string, then empty string, else I -(positive alternative). - -=item C<${>IC<:*>IC<}> - -If C<$>I is not empty string, then empty string, else I -(negative alternative). - -=item C<${>IC<:o>IC<,>[I]C<}> - -Substring of C<$>I starting at position I with I -characters. - -=item C<${>IC<:o>IC<->[I]C<}> - -Substring of C<$>I starting at position I and ending at -position I (inclusive). - -=item C<${>IC<:s/>ICIC[C]C<}> - -C<$>I after replacing characters matching I with -I. By default, case-sensitive regular expression matching is -performed and only the first occurance of I is replaced. Flag -"C" switches to case insensitive matching; flag "C" switches -to plain text pattern; flag "C" switches to replacements of all -occurances. - -=item C<${>IC<:y/>ICIC - -C<$>I after replacing all characters found in the I -character class by the corresponding character in the I -character class. - -=item C<${>IC<:p/>ICIC{C,C,C}C<}> - -C<$>I after padding to I with I. Original contents -of I is either left justified (flag "C"), centered (flag -"C"), or right justified (flag "C"). - - -=item C<[>IC<]>, C<[>IC<]>C<{>IC<,>IC<,>IC<}> - -Repeat expansion of I as long as at least one array variable -does not expand to the empty string (first variant) or exactly -(I-I)/I times (second variant). In both cases the -character "C<#>" is expanded in C as the current loop index -(C<0>,... for first variant and I,...,I with stepping -I for second variant). I of array variable lookups. For -I, I and I, full arithmetic expressions are allowed. - -=back - -=head1 SEE ALSO - -var(3). - -=cut - Index: ossp-pkg/var/var_test.c RCS File: /v/ossp/cvs/ossp-pkg/var/var_test.c,v rcsdiff -q -kk '-r1.33' '-r1.34' -u '/v/ossp/cvs/ossp-pkg/var/var_test.c,v' 2>/dev/null --- var_test.c 2002/02/27 13:44:16 1.33 +++ var_test.c 2002/02/28 08:08:16 1.34 @@ -205,26 +205,38 @@ var_rc_t rc; size_t i; char buffer[1024]; + var_t *var; + char *err; - for (i = 0; i < sizeof(tests) / sizeof(struct test_case); ++i) { + if ((rc = var_create(&var)) != VAR_OK) { + var_strerror(NULL, rc, &err); + printf("unable to create variable expansion context: %s (%d)\n", err, rc); + return 1; + } + if ((rc = var_config(var, VAR_CONFIG_CB_VALUE, var_lookup, vars)) != VAR_OK) { + var_strerror(NULL, rc, &err); + printf("unable to configure variable expansion context: %s (%d)\n", err, rc); + return 1; + } + + for (i = 0; i < sizeof(tests)/sizeof(struct test_case); ++i) { #ifdef DEBUG printf("Test case #%02d: Original input is '%s'.\n", i, tests[i].input); #endif - rc = var_unescape(tests[i].input, strlen(tests[i].input), buffer, 0); + rc = var_unescape(var, tests[i].input, strlen(tests[i].input), buffer, sizeof(buffer), 0); if (rc != VAR_OK) { - printf ("Test case #%d: First var_unescape() failed with return code %d ('%s').\n", - i, rc, var_strerror(rc)); + var_strerror(var, rc, &err); + printf("Test case #%d: var_unescape() failed: %s (%d)\n", i, err, rc); return 1; } #ifdef DEBUG printf("Test case #%02d: Unescaped input is '%s'.\n", i, buffer); #endif - rc = var_expand(buffer, strlen(buffer), &tmp, &tmp_len, - &var_lookup, (void *)vars, NULL, 0); + rc = var_expand(var, buffer, strlen(buffer), &tmp, &tmp_len, 0); if (rc != VAR_OK) { - printf ("Test case #%d: var_expand() failed with return code %d ('%s').\n", - i, rc, var_strerror(rc)); + var_strerror(var, rc, &err); + printf("Test case #%d: var_expand() failed: %s (%d).\n", i, err, rc); return 1; } #ifdef DEBUG @@ -234,11 +246,12 @@ || tmp == NULL || memcmp(tests[i].expected, tmp, tmp_len) != 0) { printf("Test case #%d: Expected result '%s' but got '%s'.\n", - i, tests[i].expected, tmp); + i, tests[i].expected, tmp); return 1; } free(tmp); } + var_destroy(var); return 0; }