Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v rcsdiff -q -kk '-r1.42' '-r1.43' -u '/v/ossp/cvs/ossp-pkg/var/var.c,v' 2>/dev/null --- var.c 2001/12/08 16:27:57 1.42 +++ var.c 2001/12/12 16:51:20 1.43 @@ -98,7 +98,8 @@ "index specification of array variable contains an invalid character", /* VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC = -38 */ "index specification of array variable is incomplete", /* VAR_ERR_INCOMPLETE_INDEX_SPEC = -39 */ "bracket expression in array variable's index is not closed", /* VAR_ERR_UNCLOSED_BRACKET_IN_INDEX = -40 */ - "division by zero error in index specification" /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX = -41 */ + "division by zero error in index specification", /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX = -41 */ + "unterterminated loop construct" /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT = -42 */ }; rc = 0 - rc; @@ -429,28 +430,36 @@ /* The recursive-descent parser for variable expressions. */ static int variable(const char *, const char *, const var_config_t *, - const char_class_t, var_cb_t, void *, int, tokenbuf_t *); + const char_class_t, var_cb_t, void *, int, tokenbuf_t *, int); static int command(const char *, const char *, const var_config_t *, - const char_class_t, var_cb_t, void *, int, tokenbuf_t *); + const char_class_t, var_cb_t, void *, int, tokenbuf_t *, int); static int num_exp(const char *begin, const char *end, int current_index, int* result, int* failed, const var_config_t *config, const char_class_t nameclass, var_cb_t lookup, void* lookup_context); static int text(const char *begin, const char *end, char varinit, - char escape) -{ + char startindex, char endindex, char escape) + { const char *p; - for (p = begin; p != end && *p != varinit; ++p) { - if (*p == escape) { - if (p + 1 == end) + for (p = begin; p != end; ++p) + { + if (*p == escape) + { + if (++p == end) return VAR_ERR_INCOMPLETE_QUOTED_PAIR; - else - ++p; + } + else if (*p == varinit) + { + break; + } + else if (startindex && (*p == startindex || *p == endindex)) + { + break; + } } - } return p - begin; -} + } static int varname(const char *begin, const char *end, const char_class_t nameclass) @@ -540,11 +549,11 @@ } else if (*p == config->varinit) { - rc = variable(p, end, config, nameclass, lookup, lookup_context, 1, &tmp); + rc = variable(p, end, config, nameclass, lookup, lookup_context, 1, &tmp, current_index); if (rc == VAR_ERR_UNDEFINED_VARIABLE) { *failed = 1; - rc = variable(p, end, config, nameclass, lookup, lookup_context, 0, &tmp); + rc = variable(p, end, config, nameclass, lookup, lookup_context, 0, &tmp, current_index); if (rc < 0) return rc; p += rc; @@ -689,14 +698,14 @@ const var_config_t *config, const char_class_t nameclass, var_cb_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result) + tokenbuf_t *result, int current_index) { const char *p = begin; const char *data; size_t len, buffer_size; int failed = 0; int rc; - int index = 0; + int index = current_index; tokenbuf_t name; tokenbuf_t tmp; @@ -733,7 +742,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp); + force_expand, &tmp, current_index); if (rc < 0) goto error_return; if (rc > 0) @@ -762,7 +771,7 @@ if (config->startindex && *p == config->startindex) { printf("Found START-INDEX: %s\n", p); - rc = num_exp(++p, end, 0, &index, &failed, config, nameclass, lookup, lookup_context); + rc = num_exp(++p, end, current_index, &index, &failed, config, nameclass, lookup, lookup_context); if (rc < 0) goto error_return; if (rc == 0) @@ -853,10 +862,10 @@ ++p; if (!failed) rc = command(p, end, config, nameclass, lookup, - lookup_context, force_expand, result); + lookup_context, force_expand, result, current_index); else rc = command(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmp); + lookup_context, force_expand, &tmp, current_index); if (rc < 0) goto error_return; p += rc; @@ -892,7 +901,7 @@ 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 force_expand, tokenbuf_t *result, int current_index) { const char *p = begin; const char *data; @@ -939,7 +948,7 @@ /* OK, we're dealing with a complex expression here. */ rc = expression(p, end, config, nameclass, lookup, lookup_context, - force_expand, result); + force_expand, result, current_index); if (rc > 0) ++rc; return rc; @@ -949,7 +958,7 @@ const var_config_t *config, const char_class_t nameclass, var_cb_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result) + tokenbuf_t *result, int current_index) { const char *p = begin; tokenbuf_t tmp; @@ -974,7 +983,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp); + force_expand, &tmp, current_index); if (rc < 0) goto error_return; if (rc > 0) { @@ -1001,7 +1010,7 @@ const var_config_t *config, const char_class_t nameclass, var_cb_t lookup, void *lookup_context, int force_expand, - tokenbuf_t *result) + tokenbuf_t *result, int current_index) { const char *p = begin; tokenbuf_t tmp; @@ -1026,7 +1035,7 @@ } rc = variable(p, end, config, nameclass, lookup, lookup_context, - force_expand, &tmp); + force_expand, &tmp, current_index); if (rc < 0) goto error_return; if (rc > 0) { @@ -1472,7 +1481,7 @@ 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) + tokenbuf_t *data, int current_index) { const char *p = begin; tokenbuf_t tmptokbuf; @@ -1578,7 +1587,7 @@ case '-': /* Substitute parameter if data is empty. */ ++p; rc = exptext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmptokbuf); + lookup_context, force_expand, &tmptokbuf, current_index); if (rc < 0) goto error_return; if (rc == 0) { @@ -1595,7 +1604,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); + lookup_context, force_expand, &tmptokbuf, current_index); if (rc < 0) goto error_return; if (rc == 0) { @@ -1618,7 +1627,7 @@ case '+': /* Substitute parameter if data is not empty. */ ++p; rc = exptext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmptokbuf); + lookup_context, force_expand, &tmptokbuf, current_index); if (rc < 0) goto error_return; if (rc == 0) { @@ -1640,7 +1649,7 @@ ++p; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &search); + lookup_context, force_expand, &search, current_index); if (rc < 0) goto error_return; p += rc; @@ -1652,7 +1661,7 @@ ++p; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace); + lookup_context, force_expand, &replace, current_index); if (rc < 0) goto error_return; p += rc; @@ -1686,7 +1695,7 @@ ++p; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &search); + lookup_context, force_expand, &search, current_index); if (rc < 0) goto error_return; p += rc; @@ -1698,7 +1707,7 @@ ++p; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace); + lookup_context, force_expand, &replace, current_index); if (rc < 0) goto error_return; p += rc; @@ -1741,7 +1750,7 @@ ++p; rc = substext_or_variable(p, end, config, nameclass, lookup, - lookup_context, force_expand, &replace); + lookup_context, force_expand, &replace, current_index); if (rc < 0) goto error_return; p += rc; @@ -1790,31 +1799,101 @@ return rc; } +struct wrapper_context + { + var_cb_t lookup; + void* context; + int* found_variables; + }; + +static int lookup_wrapper(void *context, + const char *varname, size_t name_len, int index, + const char **data, size_t *data_len, + size_t *buffer_size) + { + static char buf[1]; + struct wrapper_context* wcon = context; + int rc; + + printf("Looking up '"); + fwrite(varname, name_len, 1, stdout); + printf("[%d]' ... rc = ", index); + + rc = (*wcon->lookup)(wcon->context, varname, name_len, index, data, data_len, buffer_size); + printf("%d\n", rc); + if (rc == 0) + { + *data = buf; + *data_len = 0; + *buffer_size = 0; + return 1; + } + else + { + *(wcon->found_variables) += 1; + return rc; + } + } + 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, void *lookup_context, int force_expand, - tokenbuf_t *output) + tokenbuf_t *output, int current_index, size_t recursion_level) { const char* p = begin; int rc; tokenbuf_t result; - + int found_variables; + int i; + int output_backup; + struct wrapper_context wcon; tokenbuf_init(&result); do { - rc = text(begin, end, config->varinit, config->escape); + printf("input(): Parsing string '%s'.\n", begin); + + if (begin != end && *begin == config->startindex) + { + printf("Found loop construct.\n"); + wcon.lookup = lookup; + wcon.context = lookup_context; + wcon.found_variables = &found_variables; + ++begin; + for (i = 0; i == 0 || found_variables; ++i) + { + output_backup = output->end - output->begin; + found_variables = 0; + printf("Recursing with default index %d.\n", i); + rc = input(begin, end, config, nameclass, &lookup_wrapper, &wcon, 1, output, i, recursion_level+1); + printf("input() recursion returned %d.\n", rc); + if (rc < 0) + goto error_return; + if (begin[rc] != config->endindex) + { + rc = VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT; + goto error_return; + } + } + output->end = output->begin + output_backup; + begin += rc; + ++begin; + continue; + } + + rc = text(begin, end, config->varinit, config->startindex, config->endindex, config->escape); if (rc > 0) { if (!tokenbuf_append(output, begin, rc)) { rc = VAR_ERR_OUT_OF_MEMORY; goto error_return; } begin += rc; + continue; } else if (rc < 0) goto error_return; rc = variable(begin, end, config, nameclass, lookup, - lookup_context, force_expand, &result); + lookup_context, force_expand, &result, current_index); if (rc > 0) { if (!tokenbuf_append (output, result.begin, result.end - result.begin)) { @@ -1822,18 +1901,19 @@ goto error_return; } begin += rc; + continue; } if (rc < 0) goto error_return; } - while (rc > 0); + while (begin != end && rc > 0); - if (begin != end) { + if (recursion_level == 0 && begin != end) { rc = VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE; goto error_return; } - return VAR_OK; + return begin - p; error_return: tokenbuf_free(output); @@ -1882,8 +1962,8 @@ /* Call the parser. */ tokenbuf_init(&output); rc = input(input_buf, input_buf + input_len, config, nameclass, - lookup, lookup_context, force_expand, &output); + lookup, lookup_context, force_expand, &output, 0, 0); *result = (char *)output.begin; *result_len = output.end - output.begin; - return rc; + return (rc >= 0) ? VAR_OK : rc; } Index: ossp-pkg/var/var.h RCS File: /v/ossp/cvs/ossp-pkg/var/var.h,v rcsdiff -q -kk '-r1.16' '-r1.17' -u '/v/ossp/cvs/ossp-pkg/var/var.h,v' 2>/dev/null --- var.h 2001/12/08 16:27:57 1.16 +++ var.h 2001/12/12 16:51:20 1.17 @@ -36,6 +36,7 @@ typedef enum { VAR_ERR_CALLBACK = -64, + VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT = -42, VAR_ERR_DIVISION_BY_ZERO_IN_INDEX = -41, VAR_ERR_UNCLOSED_BRACKET_IN_INDEX = -40, VAR_ERR_INCOMPLETE_INDEX_SPEC = -39, Index: ossp-pkg/var/var.pod RCS File: /v/ossp/cvs/ossp-pkg/var/var.pod,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/var/var.pod,v' 2>/dev/null --- var.pod 2001/12/12 14:34:18 1.12 +++ var.pod 2001/12/12 16:51:20 1.13 @@ -614,7 +614,7 @@ =head1 EBNF GRAMMAR OF SUPPORTED EXPRESSIONS - input : (TEXT|variable)* + input : ( TEXT | variable | START-INDEX input END-INDEX )* variable : '$' (name|expression) @@ -659,7 +659,7 @@ EXPTEXT : '[^$}:]+' - TEXT : '[^$]+' + TEXT : '[^$[\]]+' Please note that the descriptions of START-DELIM, END-DELIM, VARNAME, SUBSTEXT, and EXPTEXT shown here assume that var_expand() has been Index: ossp-pkg/var/var_test.c RCS File: /v/ossp/cvs/ossp-pkg/var/var_test.c,v rcsdiff -q -kk '-r1.22' '-r1.23' -u '/v/ossp/cvs/ossp-pkg/var/var_test.c,v' 2>/dev/null --- var_test.c 2001/12/08 16:28:41 1.22 +++ var_test.c 2001/12/12 16:51:20 1.23 @@ -142,7 +142,8 @@ { "${ARRAY[$NUMEXP]}", "entry1" }, { "${ARRAY[$NUMEXP-1]}", "entry0" }, { "${ARRAY[${UNDEFINED}-1]}", "${ARRAY[${UNDEFINED}-1]}" }, - { "${ARRAY[5/(${UNDEFINED})]}", "${ARRAY[5/(${UNDEFINED})]}" } + { "${ARRAY[5/(${UNDEFINED})]}", "${ARRAY[5/(${UNDEFINED})]}" }, + { ":[${ARRAY}-]:", ":entry0-entry1-entry2-entry3-:" } }; char *tmp; size_t tmp_len;