Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v rcsdiff -q -kk '-r1.52' '-r1.53' -u '/v/ossp/cvs/ossp-pkg/var/var.c,v' 2>/dev/null --- var.c 2001/12/14 14:40:28 1.52 +++ var.c 2001/12/16 23:40:16 1.53 @@ -99,7 +99,8 @@ "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 */ - "unterterminated loop construct" /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT = -42 */ + "unterminated loop construct", /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT = -42 */ + "invalid character in loop limits" /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS = -43 */ }; rc = 0 - rc; @@ -502,8 +503,8 @@ const char *p; for (p = begin; - p != end - && *p != config->varinit + p != end + && *p != config->varinit && *p != config->enddelim && *p != ':'; p++) { if (*p == config->escape) { @@ -543,7 +544,7 @@ return VAR_ERR_INCOMPLETE_INDEX_SPEC; if (*p == '(') { - rc = num_exp(++p, end, current_index, result, failed, + rc = num_exp(++p, end, current_index, result, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -555,11 +556,11 @@ ++p; } else if (*p == config->varinit) { - rc = variable(p, end, config, nameclass, lookup, + rc = variable(p, end, config, nameclass, lookup, lookup_context, 1, &tmp, current_index, rel_lookup_flag); if (rc == VAR_ERR_UNDEFINED_VARIABLE) { *failed = 1; - rc = variable(p, end, config, nameclass, lookup, + rc = variable(p, end, config, nameclass, lookup, lookup_context, 0, &tmp, current_index, rel_lookup_flag); if (rc < 0) return rc; @@ -570,7 +571,7 @@ if (rc < 0) return rc; p += rc; - rc = num_exp(tmp.begin, tmp.end, current_index, result, + rc = num_exp(tmp.begin, tmp.end, current_index, result, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); tokenbuf_free(&tmp); if (rc < 0) @@ -622,8 +623,8 @@ if (begin == end) return VAR_ERR_INCOMPLETE_INDEX_SPEC; - rc = num_exp_read_operand(p, end, current_index, result, - failed, rel_lookup_flag, config, nameclass, + rc = num_exp_read_operand(p, end, current_index, result, + failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -632,7 +633,7 @@ while (p != end) { if (*p == '+' || *p == '-') { operator = *p++; - rc = num_exp(p, end, current_index, &right, failed, + rc = num_exp(p, end, current_index, &right, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -644,7 +645,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, current_index, &right, failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) return rc; @@ -747,7 +748,7 @@ /* 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, + rc = num_exp(++p, end, current_index, &idx, &failed, rel_lookup_flag, config, nameclass, lookup, lookup_context); if (rc < 0) goto error_return; @@ -822,11 +823,11 @@ p++; if (!failed) rc = command(p, end, config, nameclass, lookup, - lookup_context, force_expand, result, + lookup_context, force_expand, result, current_index, rel_lookup_flag); else rc = command(p, end, config, nameclass, lookup, - lookup_context, force_expand, &tmp, + lookup_context, force_expand, &tmp, current_index, rel_lookup_flag); if (rc < 0) goto error_return; @@ -1231,7 +1232,7 @@ else rc = strncmp(p, search->begin, search->end - search->begin); - if (rc != 0) { + if (rc != 0) { /* no match, copy character */ if (!tokenbuf_append(&tmp, p, 1)) { tokenbuf_free(&tmp); @@ -1352,7 +1353,7 @@ return VAR_ERR_OUT_OF_MEMORY; i--; } - i = (width - (data->end - data->begin)) + i = (width - (data->end - data->begin)) % (fill->end - fill->begin); if (!tokenbuf_append(data, fill->begin, i)) return VAR_ERR_OUT_OF_MEMORY; @@ -1369,7 +1370,7 @@ } i--; } - i = (width - (data->end - data->begin)) + i = (width - (data->end - data->begin)) % (fill->end - fill->begin); if (!tokenbuf_append(&result, fill->begin, i)) { tokenbuf_free(&result); @@ -1396,7 +1397,7 @@ } i--; } - i = ((width - (data->end - data->begin)) / 2) + i = ((width - (data->end - data->begin)) / 2) % (fill->end - fill->begin); if (!tokenbuf_append(&result, fill->begin, i)) { tokenbuf_free(&result); @@ -1774,7 +1775,7 @@ struct wrapper_context *wcon = context; int rc; - rc = (*wcon->lookup)(wcon->context, name, name_len, + rc = (*wcon->lookup)(wcon->context, name, name_len, idx, data, data_len, buffer_size); if (rc == 0) { (*wcon->rel_lookup_flag)--; @@ -1787,6 +1788,105 @@ return rc; } +static var_rc_t loop_limits(const char *begin, const char *end, + const var_config_t *config, + const char_class_t nameclass, + var_cb_t lookup, void* lookup_context, + int* start, int* step, int* stop, int* open_end) + { + const char* p = begin; + int rc; + int failed; + int dummy; + + printf("loop_limits() called: '%s'.\n", begin); + + if (begin == end) + return 0; + + if (*p != config->startdelim) + return 0; + else + ++p; + + /* Read start value for the loop. */ + + failed = 0; + rc = num_exp(p, end, 0, start, &failed, &dummy, + config, nameclass, lookup, lookup_context); + if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) + *start = 0; /* use default */ + else if (rc < 0) + return rc; + else + p += rc; + if (failed) + return VAR_ERR_UNDEFINED_VARIABLE; + + if (*p != ',') + return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; + else + ++p; + + /* Read step value for the loop. */ + + failed = 0; + rc = num_exp(p, end, 0, step, &failed, &dummy, + config, nameclass, lookup, lookup_context); + if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) + *step = 1; /* use default */ + else if (rc < 0) + return rc; + else + p += rc; + if (failed) + return VAR_ERR_UNDEFINED_VARIABLE; + + if (*p != ',') + { + if (*p != config->enddelim) + return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; + else + { + ++p; + *stop = *step; + *step = 1; + if (rc > 0) + *open_end = 0; + else + *open_end = 1; + return p - begin; + } + } + else + ++p; + + /* Read stop value for the loop. */ + + failed = 0; + rc = num_exp(p, end, 0, stop, &failed, &dummy, + config, nameclass, lookup, lookup_context); + if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) + { + *stop = 0; /* use default */ + *open_end = 1; + } + else if (rc < 0) + return rc; + else + { + *open_end = 0; + p += rc; + } + if (failed) + return VAR_ERR_UNDEFINED_VARIABLE; + + if (*p != config->enddelim) + 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, @@ -1795,13 +1895,15 @@ size_t recursion_level, int *rel_lookup_flag) { const char *p = begin; - int rc; + int rc, rc2; tokenbuf_t result; + int start, step, stop, open_end; int i; int output_backup; struct wrapper_context wcon; int my_rel_lookup_flag; int original_rel_lookup_state; + int loop_limit_length; tokenbuf_init(&result); @@ -1813,14 +1915,23 @@ do { if (begin != end && config->startindex && *begin == config->startindex) { original_rel_lookup_state = *rel_lookup_flag; + loop_limit_length = -1; wcon.lookup = lookup; wcon.context = lookup_context; wcon.rel_lookup_flag = rel_lookup_flag; begin++; - for (i = 0; i == 0 || *rel_lookup_flag > original_rel_lookup_state; i++) { + start = 0; + step = 1; + stop = 0; + open_end = 1; + re_loop: + for (i = start; + (open_end && (loop_limit_length < 0 || *rel_lookup_flag > original_rel_lookup_state)) || + (!open_end && i <= stop); + i += step) { *rel_lookup_flag = original_rel_lookup_state; output_backup = output->end - output->begin; - rc = input(begin, end, config, nameclass, &lookup_wrapper, + rc = input(begin, end, config, nameclass, &lookup_wrapper, &wcon, 1, output, i, recursion_level+1, rel_lookup_flag); if (rc < 0) goto error_return; @@ -1828,14 +1939,41 @@ rc = VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT; goto error_return; } + if (loop_limit_length < 0) + { + rc2 = loop_limits(begin + rc + 1, end, config, nameclass, + lookup, lookup_context, &start, &step, + &stop, &open_end); + if (rc2 < 0) + { + printf("loop_limits() failed: %d ('%s').\n", rc2, var_strerror(rc2)); + goto error_return; + } + else if (rc2 == 0) + { + loop_limit_length = 0; + } + else if (rc2 > 0) + { + printf("Found loop limits: start = %d, step = %d, stop = %d, open_end = %s\n", + start, step, stop, (open_end) ? "true" : "false"); + loop_limit_length = rc2; + output->end = output->begin + output_backup; + goto re_loop; + } + } } - output->end = output->begin + output_backup; + if (open_end) + output->end = output->begin + output_backup; + else + *rel_lookup_flag = original_rel_lookup_state; begin += rc; begin++; + begin += loop_limit_length; continue; } - rc = text(begin, end, config->varinit, config->startindex, + rc = text(begin, end, config->varinit, config->startindex, config->endindex, config->escape); if (rc > 0) { if (!tokenbuf_append(output, begin, rc)) { @@ -1848,7 +1986,7 @@ goto error_return; rc = variable(begin, end, config, nameclass, lookup, - lookup_context, force_expand, &result, + lookup_context, force_expand, &result, current_index, rel_lookup_flag); if (rc > 0) { if (!tokenbuf_append(output, result.begin, result.end - result.begin)) { @@ -1942,4 +2080,3 @@ return rc; } - Index: ossp-pkg/var/var.h RCS File: /v/ossp/cvs/ossp-pkg/var/var.h,v rcsdiff -q -kk '-r1.18' '-r1.19' -u '/v/ossp/cvs/ossp-pkg/var/var.h,v' 2>/dev/null --- var.h 2001/12/14 13:47:01 1.18 +++ var.h 2001/12/16 23:40:16 1.19 @@ -36,6 +36,7 @@ typedef enum { VAR_ERR_CALLBACK = -64, + VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS = -43, VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT = -42, VAR_ERR_DIVISION_BY_ZERO_IN_INDEX = -41, VAR_ERR_UNCLOSED_BRACKET_IN_INDEX = -40, Index: ossp-pkg/var/var.pod RCS File: /v/ossp/cvs/ossp-pkg/var/var.pod,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/var/var.pod,v' 2>/dev/null --- var.pod 2001/12/12 17:18:55 1.14 +++ var.pod 2001/12/16 23:40:16 1.15 @@ -616,7 +616,9 @@ =head1 EBNF GRAMMAR OF SUPPORTED EXPRESSIONS - input : ( TEXT | variable | START-INDEX input END-INDEX )* + input : ( TEXT | variable | START-INDEX input END-INDEX ( loop-limits )? )* + + loop-limits: START-DELIM (numexp)? ',' (numexp)? ( ',' (numexp)? )? END-DELIM variable : '$' (name|expression) Index: ossp-pkg/var/var_test.c RCS File: /v/ossp/cvs/ossp-pkg/var/var_test.c,v rcsdiff -q -kk '-r1.27' '-r1.28' -u '/v/ossp/cvs/ossp-pkg/var/var_test.c,v' 2>/dev/null --- var_test.c 2001/12/14 13:49:40 1.27 +++ var_test.c 2001/12/16 23:40:16 1.28 @@ -65,7 +65,7 @@ printf("Found variable at index %d.\n", i); counter = 1; length = strlen(vars[i].data); - while ( vars[i + counter].data + while ( vars[i + counter].data && strncmp(varname, vars[i + counter].name, name_len) == 0) counter++; if (counter == 1) @@ -134,7 +134,7 @@ { "${HOME:s/[esO]/_/gi}", "/h_m_/r_gr___i_n-t__t_" }, { "${OSTYPE:s/^[re]/_/g}", "_egression-os" }, { "${EMPTY:s/^[re]/_/g}", "" }, - { "${HOME:s/.*/heinz/}", "heinz" }, + { "${HOME:s/.*\\x{}/heinz/}", "heinz" }, { "${HOME:s/e/bla/t}", "/hombla/regression-tests" }, { "${HOME:s/E/bla/t}", "/home/regression-tests" }, { "${HOME:s/E/bla/ti}", "/hombla/regression-tests" }, @@ -173,6 +173,8 @@ { "${ARRAY[5/(${UNDEFINED})]}", "${ARRAY[5/(${UNDEFINED})]}" }, { "[${ARRAY[#]}-]", "entry0-entry1-entry2-entry3-" }, { "[${ARRAY[#+1]}-]", "entry1-entry2-entry3-" }, + { "-[${ARRAY[#]}:]{1,$NUMBER}-", "-entry1:entry2:-" }, + { "-[${ARRAY[#]}:]{1,3,5}-", "-entry1::-" }, { "[${ARRAY}:${ARRAY[#]}-]", "entry0:entry0-entry0:entry1-entry0:entry2-entry0:entry3-" @@ -188,7 +190,11 @@ { "[${HEINZ[#]}: [${ARRAY[#]}${ARRAY[#+1]:+, }]${HEINZ[#+1]:+; }]", "heinz0: entry0, entry1, entry2, entry3; heinz1: entry0, entry1, entry2, entry3" - } + }, + { + "[${ARRAY[#]}:[${ARRAY[#]},]{1,2,} ]{0,2,}", + "entry0:entry1,entry3, entry2:entry1,entry3, " + }, }; char *tmp; size_t tmp_len; @@ -220,7 +226,7 @@ #ifdef DEBUG printf("Test case #%02d: Expanded output is '%s'.\n", i, tmp); #endif - if ( tmp_len != strlen(tests[i].expected) + if ( tmp_len != strlen(tests[i].expected) || tmp == NULL || memcmp(tests[i].expected, tmp, tmp_len) != 0) { printf("Test case #%d: Expected result '%s' but got '%s'.\n",