Index: ossp-pkg/var/var.c RCS File: /v/ossp/cvs/ossp-pkg/var/var.c,v rcsdiff -q -kk '-r1.71' '-r1.72' -u '/v/ossp/cvs/ossp-pkg/var/var.c,v' 2>/dev/null --- var.c 2002/03/01 20:28:33 1.71 +++ var.c 2002/03/01 21:59:37 1.72 @@ -148,6 +148,22 @@ return; } +static void tokenbuf_set(tokenbuf_t *buf, const char *begin, const char *end, size_t buffer_size) +{ + buf->begin = begin; + buf->end = end; + buf->buffer_size = buffer_size; + return; +} + +static void tokenbuf_copy(tokenbuf_t *src, tokenbuf_t *dst) +{ + dst->begin = src->begin; + dst->end = src->end; + dst->buffer_size = src->buffer_size; + return; +} + static void tokenbuf_move(tokenbuf_t *src, tokenbuf_t *dst) { dst->begin = src->begin; @@ -225,6 +241,11 @@ return 1; } +static int tokenbuf_merge(tokenbuf_t *output, tokenbuf_t *input) +{ + return tokenbuf_append(output, input->begin, input->end - input->begin); +} + static void tokenbuf_free(tokenbuf_t *buf) { if (buf->begin != NULL && buf->buffer_size > 0) @@ -511,7 +532,7 @@ return num; } -/* parse number expression operand */ +/* parse numerical expression operand */ static int parse_num_exp_operand( var_t *var, var_parse_t *ctx, @@ -599,18 +620,20 @@ return (p - begin); } +/* parse numerical expression */ static int parse_num_exp( var_t *var, var_parse_t *ctx, const char *begin, const char *end, int *result, int *failed) { - const char *p = begin; + const char *p; char operator; int right; int rc; - if (begin == end) + p = begin; + if (p == end) return VAR_ERR_INCOMPLETE_INDEX_SPEC; rc = parse_num_exp_operand(var, ctx, p, end, result, failed); @@ -666,7 +689,7 @@ return p - begin; } -/* callback wrapper function */ +/* lookup a variable value by callin the callback function */ static int lookup_value( var_t *var, var_parse_t *ctx, @@ -681,7 +704,11 @@ var_ptr, var_len, var_idx, val_ptr, val_len, val_size); - /* convert undefined variable into empty variable */ + /* convert undefined variable into empty variable if relative + lookups are counted. This is the case inside an active loop + construct if no limits are given. There the parse_input() + has to proceed until all variables have undefined values. + This trick here allows it to determine this case. */ if (ctx->rel_lookup_flag && rc == VAR_ERR_UNDEFINED_VARIABLE) { ctx->rel_lookup_cnt--; buf[0] = NUL; @@ -1803,32 +1830,35 @@ return rc; } -/* expand the loop limits */ +/* parse loop construct limits ("[...]{b,s,e}") */ static var_rc_t parse_looplimits( var_t *var, var_parse_t *ctx, const char *begin, const char *end, - int *start, int *step, int *stop, - int *open_end) + int *start, int *step, int *stop, int *open_stop) { const char *p; int rc; int failed; + /* initialization */ p = begin; - if (begin == end) + + /* we are happy if nothing is to left to parse */ + if (p == end) return 0; + + /* parse start delimiter */ if (*p != var->syntax.delim_open) return 0; - else - p++; + p++; - /* Read start value for the loop. */ + /* parse loop start value */ failed = 0; rc = parse_num_exp(var, ctx, p, end, start, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) - *start = 0; /* use default */ + *start = 0; /* use default */ else if (rc < 0) return rc; else @@ -1836,107 +1866,120 @@ if (failed) return VAR_ERR_UNDEFINED_VARIABLE; + /* parse separator */ if (*p != ',') return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; - else - p++; + p++; - /* Read step value for the loop. */ + /* parse loop step value */ failed = 0; rc = parse_num_exp(var, ctx, p, end, step, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) - *step = 1; /* use default */ + *step = 1; /* use default */ else if (rc < 0) return rc; else p += rc; if (failed) return VAR_ERR_UNDEFINED_VARIABLE; + + /* parse separator */ if (*p != ',') { + /* if not found, parse end delimiter */ if (*p != var->syntax.delim_close) 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. */ + /* shift step value to stop value */ + *stop = *step; + *step = 1; + + /* determine whether loop end is open */ + if (rc > 0) + *open_stop = 0; + else + *open_stop = 1; + return (p - begin); + } + p++; + + /* parse loop stop value */ failed = 0; rc = parse_num_exp(var, ctx, p, end, stop, &failed); if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC) { - *stop = 0; /* use default */ - *open_end = 1; + *stop = 0; /* use default */ + *open_stop = 1; } else if (rc < 0) return rc; else { - *open_end = 0; + *open_stop = 0; p += rc; } if (failed) return VAR_ERR_UNDEFINED_VARIABLE; + + /* parse end delimiter */ if (*p != var->syntax.delim_close) return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS; + p++; - return ++p - begin; + /* return amount of parsed input */ + return (p - begin); } /* expand input in general */ static var_rc_t parse_input( - var_t *var, - var_parse_t *ctx, + var_t *var, var_parse_t *ctx, const char *begin, const char *end, - tokenbuf_t *output, - int recursion_level) + tokenbuf_t *output, int recursion_level) { - const char *p = begin; + const char *p; int rc, rc2; tokenbuf_t result; - int start, step, stop, open_end; + int start, step, stop, open_stop; int i; - int output_backup; + tokenbuf_t output_backup; int rel_lookup_cnt; int loop_limit_length; var_parse_t myctx; - tokenbuf_init(&result); + /* initialization */ + p = begin; do { /* try to parse a loop construct */ - if ( begin != end + if ( p != end && var->syntax.index_open != NUL - && *begin == var->syntax.index_open) { + && *p == var->syntax.index_open) { + p++; + /* loop preparation */ loop_limit_length = -1; - begin++; + rel_lookup_cnt = ctx->rel_lookup_cnt; + open_stop = 1; + rc = 0; start = 0; step = 1; stop = 0; - open_end = 1; - rc = 0; - output_backup = 0; - rel_lookup_cnt = ctx->rel_lookup_cnt; + tokenbuf_copy(output, &output_backup); + /* iterate over loop construct, either as long as there is + (still) nothing known about the limit, or there is an open + (=unknown) limit stop and there are still defined variables + or there is a stop limit known and it is still not reached */ re_loop: for (i = start; - ( ( open_end + ( ( open_stop && ( loop_limit_length < 0 || rel_lookup_cnt > ctx->rel_lookup_cnt)) - || ( !open_end - && i <= stop) ); + || ( !open_stop + && i <= stop) ); i += step) { - /* remember current state for backing off */ - output_backup = output->end - output->begin; + + /* remember current output end for restoring */ + tokenbuf_copy(output, &output_backup); /* open temporary context for recursion */ ctx = var_parse_push(ctx, &myctx); @@ -1944,84 +1987,106 @@ ctx->rel_lookup_flag = 1; ctx->index_this = i; - rc = parse_input(var, ctx, begin, end, + /* recursive parse input through ourself */ + rc = parse_input(var, ctx, p, end, output, recursion_level+1); /* retrieve info and close temporary context */ rel_lookup_cnt = ctx->rel_lookup_cnt; ctx = var_parse_pop(ctx); + /* error handling */ if (rc < 0) goto error_return; - if (begin[rc] != var->syntax.index_close) { + + /* make sure the loop construct is closed */ + if (p[rc] != var->syntax.index_close) { rc = VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT; goto error_return; } + + /* try to parse loop construct limit specification */ if (loop_limit_length < 0) { - rc2 = parse_looplimits(var, ctx, begin + rc + 1, end, - &start, &step, - &stop, &open_end); + rc2 = parse_looplimits(var, ctx, p+rc+1, end, + &start, &step, &stop, &open_stop); if (rc2 < 0) goto error_return; else if (rc2 == 0) loop_limit_length = 0; else if (rc2 > 0) { loop_limit_length = rc2; - output->end = output->begin + output_backup; + /* restart loop from scratch */ + tokenbuf_copy(&output_backup, output); goto re_loop; } } } - if (open_end) - output->end = output->begin + output_backup; - else - rel_lookup_cnt = ctx->rel_lookup_cnt; - begin += rc; - begin++; - begin += loop_limit_length; + + /* if stop value is open, restore to the output end + because the last iteration was just to determine the loop + termination and its result has to be discarded */ + if (open_stop) + tokenbuf_copy(&output_backup, output); + + /* skip parsed loop construct */ + p += rc; + p++; + p += loop_limit_length; + continue; } /* try to parse plain text */ - rc = parse_text(var, ctx, begin, end); + rc = parse_text(var, ctx, p, end); if (rc > 0) { - if (!tokenbuf_append(output, begin, rc)) { + if (!tokenbuf_append(output, p, rc)) { rc = VAR_ERR_OUT_OF_MEMORY; goto error_return; } - begin += rc; + p += rc; continue; } else if (rc < 0) goto error_return; /* try to parse a variable construct */ - rc = parse_variable(var, ctx, begin, end, &result); + tokenbuf_init(&result); + rc = parse_variable(var, ctx, p, end, &result); if (rc > 0) { - if (!tokenbuf_append(output, result.begin, result.end - result.begin)) { + if (!tokenbuf_merge(output, &result)) { + tokenbuf_free(&result); rc = VAR_ERR_OUT_OF_MEMORY; goto error_return; } - begin += rc; + tokenbuf_free(&result); + p += rc; continue; - } + } + tokenbuf_free(&result); if (rc < 0) goto error_return; - } while (begin != end && rc > 0); + } while (p != end && rc > 0); - if (recursion_level == 0 && begin != end) { + /* We do not know whether this really could happen, but because we + are paranoid, report an error at the outer most parsing level if + there is still any input. Because this would mean that we are no + longer able to parse the remaining input as a loop construct, a + text or a variable construct. This would be very strange, but + could perhaps happen in case of configuration errors!?... */ + if (recursion_level == 0 && p != end) { rc = VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE; goto error_return; } - return begin - p; + /* return amount of parsed text */ + return (p - begin); - error_return: + /* return with an error where as a special case the output begin is + set to the input begin and the output end to the last input parsing + position. */ + error_return: tokenbuf_free(output); - tokenbuf_free(&result); - output->begin = p; - output->end = begin; - output->buffer_size = 0; + tokenbuf_set(output, begin, p, 0); return rc; } @@ -2185,42 +2250,37 @@ return VAR_RC(VAR_ERR_INVALID_ARGUMENT); /* prepare internal expansion context */ - ctx.lower = NULL; - ctx.force_expand = force_expand; + ctx.lower = NULL; + ctx.force_expand = force_expand; ctx.rel_lookup_flag = 0; - ctx.rel_lookup_cnt = 0; - ctx.index_this = 0; + ctx.rel_lookup_cnt = 0; + ctx.index_this = 0; - /* set the dst_ptr pointer to the src_ptr so that it is correctly - initialized in case we fail with an error later. */ - *dst_ptr = (char *)src_ptr; - - /* call the parsing */ + /* start the parsing */ tokenbuf_init(&output); - rc = parse_input(var, &ctx, src_ptr, src_ptr + src_len, &output, 0); + rc = parse_input(var, &ctx, src_ptr, src_ptr+src_len, &output, 0); - /* post-process output */ + /* post-processing */ if (rc >= 0) { - /* always NUL-terminate output for convinience reasons */ + /* always NUL-terminate output for convinience reasons + but do not count the NUL-terminator in the length */ if (!tokenbuf_append(&output, "\0", 1)) { tokenbuf_free(&output); return VAR_RC(VAR_ERR_OUT_OF_MEMORY); } output.end--; - /* provide dst_ptrs */ + /* provide result */ *dst_ptr = (char *)output.begin; if (dst_len != NULL) - *dst_len = output.end - output.begin; - - /* canonify all positive answers */ + *dst_len = (output.end - output.begin); rc = VAR_OK; } else { - /* provide error dst_ptr */ + /* provide result */ *dst_ptr = (char *)src_ptr; if (dst_len != NULL) - *dst_len = output.end - output.begin; + *dst_len = (output.end - output.begin); } return VAR_RC(rc);