--- 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);
|