OSSP CVS Repository

ossp - Difference in ossp-pkg/var/var.c versions 1.70 and 1.71
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/var/var.c 1.70 -> 1.71

--- var.c        2002/02/28 20:28:14     1.70
+++ var.c        2002/03/01 20:28:33     1.71
@@ -79,9 +79,14 @@
 };
 
 /* the internal expansion context structure */
-typedef struct {
-    int            force_expand;
-} var_parse_t;
+struct var_parse_st {
+    struct var_parse_st *lower;
+    int force_expand;
+    int rel_lookup_flag;
+    int rel_lookup_cnt;
+    int index_this;
+};
+typedef struct var_parse_st var_parse_t;
 
 /* the default syntax configuration */
 static const var_syntax_t var_syntax_default = {
@@ -97,6 +102,32 @@
 
 /*
 **
+**  ==== PARSE CONTEXT FUNCTIONS ====
+**
+*/
+
+static var_parse_t *
+var_parse_push(
+    var_parse_t *lower, var_parse_t *upper)
+{
+    if (upper == NULL)
+        return NULL;
+    memcpy(upper, lower, sizeof(var_parse_t));
+    upper->lower = lower;
+    return upper;
+}
+
+static var_parse_t *
+var_parse_pop(
+    var_parse_t *upper)
+{
+    if (upper == NULL)
+        return NULL;
+    return upper->lower;
+}
+
+/*
+**
 **  ==== TOKEN BUFFER FUNCTIONS ====
 **
 */
@@ -228,6 +259,7 @@
         class[(int)a] = 1;
     }
     while (++a <= b);
+    return;
 }
 
 static var_rc_t expand_character_class(const char *desc, char_class_t class)
@@ -366,9 +398,9 @@
 */
 
 /* forward declarations */
-static int parse_variable(var_t *var, var_parse_t *ctx, const char *begin, const char *end, int force_expand, tokenbuf_t *result, int index_this, int* rel_lookup_flag);
-static int parse_command (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int force_expand, tokenbuf_t *data, int index_this, int* rel_lookup_flag);
-static int parse_num_exp (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int index_this, int* result, int* failed, int* rel_lookup_flag);
+static int parse_variable(var_t *var, var_parse_t *ctx, const char *begin, const char *end, tokenbuf_t *result);
+static int parse_command (var_t *var, var_parse_t *ctx, const char *begin, const char *end, tokenbuf_t *data);
+static int parse_num_exp (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int *result, int *failed);
 
 /* parse plain text */
 static int 
@@ -484,11 +516,13 @@
 parse_num_exp_operand(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end, 
-    int index_this, int *result, int *failed, int *rel_lookup_flag)
+    int *result, 
+    int *failed)
 {
     const char *p;
     tokenbuf_t tmp;
     int rc;
+    var_parse_t myctx;
 
     p = begin;
     tokenbuf_init(&tmp);
@@ -497,8 +531,7 @@
         return VAR_ERR_INCOMPLETE_INDEX_SPEC;
 
     if (*p == '(') {
-        rc = parse_num_exp(var, ctx, ++p, end, index_this, result, failed,
-                     rel_lookup_flag);
+        rc = parse_num_exp(var, ctx, ++p, end, result, failed);
         if (rc < 0)
             return rc;
         p += rc;
@@ -509,12 +542,16 @@
         ++p;
     }
     else if (*p == var->syntax.delim_init) {
-        rc = parse_variable(var, ctx, p, end, 
-                            1, &tmp, index_this, rel_lookup_flag);
+        ctx = var_parse_push(ctx, &myctx);
+        ctx->force_expand = 1;
+        rc = parse_variable(var, ctx, p, end, &tmp);
+        ctx = var_parse_pop(ctx);
         if (rc == VAR_ERR_UNDEFINED_VARIABLE) {
             *failed = 1;
-            rc = parse_variable(var, ctx, p, end, 
-                                0, &tmp, index_this, rel_lookup_flag);
+            ctx = var_parse_push(ctx, &myctx);
+            ctx->force_expand = 0;
+            rc = parse_variable(var, ctx, p, end, &tmp);
+            ctx = var_parse_pop(ctx);
             if (rc < 0)
                 return rc;
             p += rc;
@@ -524,8 +561,7 @@
             if (rc < 0)
                 return rc;
             p += rc;
-            rc = parse_num_exp(var, ctx, tmp.begin, tmp.end, index_this, result,
-                         failed, rel_lookup_flag );
+            rc = parse_num_exp(var, ctx, tmp.begin, tmp.end, result, failed);
             tokenbuf_free(&tmp);
             if (rc < 0)
                 return rc;
@@ -533,8 +569,9 @@
     }
     else if (var->syntax.index_mark && *p == var->syntax.index_mark) {
         p++;
-        *result = index_this;
-        (*rel_lookup_flag)++;
+        *result = ctx->index_this;
+        if (ctx->rel_lookup_flag)
+            ctx->rel_lookup_cnt++;
     }
     else if (isdigit(*p)) {
         *result = convert_num_exp_read_int(&p, end);
@@ -566,8 +603,7 @@
 parse_num_exp(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end, 
-    int index_this,
-    int *result, int *failed, int *rel_lookup_flag)
+    int *result, int *failed)
 {
     const char *p = begin;
     char operator;
@@ -577,8 +613,7 @@
     if (begin == end)
         return VAR_ERR_INCOMPLETE_INDEX_SPEC;
 
-    rc = parse_num_exp_operand(var, ctx, p, end, index_this, result,
-                              failed, rel_lookup_flag);
+    rc = parse_num_exp_operand(var, ctx, p, end, result, failed);
     if (rc < 0)
         return rc;
     p += rc;
@@ -586,8 +621,7 @@
     while (p != end) {
         if (*p == '+' || *p == '-') {
             operator = *p++;
-            rc = parse_num_exp(var, ctx, p, end, index_this, &right, failed,
-                         rel_lookup_flag);
+            rc = parse_num_exp(var, ctx, p, end, &right, failed);
             if (rc < 0)
                 return rc;
             p += rc;
@@ -598,8 +632,7 @@
         }
         else if (*p == '*' || *p == '/' || *p == '%') {
             operator = *p++;
-            rc = parse_num_exp_operand(var, ctx, p, end, index_this, &right, failed,
-                                      rel_lookup_flag);
+            rc = parse_num_exp_operand(var, ctx, p, end, &right, failed);
             if (rc < 0)
                 return rc;
             p += rc;
@@ -633,12 +666,39 @@
     return p - begin;
 }
 
+/* callback wrapper function */
+static int 
+lookup_value(
+    var_t *var, var_parse_t *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 buf[1];
+    int rc;
+
+    /* pass through to original callback */
+    rc = (*var->cb_value_fct)(var, var->cb_value_ctx,
+                              var_ptr, var_len, var_idx, 
+                              val_ptr, val_len, val_size);
+
+    /* convert undefined variable into empty variable */
+    if (ctx->rel_lookup_flag && rc == VAR_ERR_UNDEFINED_VARIABLE) {
+        ctx->rel_lookup_cnt--;
+        buf[0] = NUL;
+        *val_ptr  = buf;
+        *val_len  = 0;
+        *val_size = 0;
+        return VAR_OK;
+    }
+
+    return rc;
+}
+
 static int 
 parse_expression(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand,
-    tokenbuf_t *result, int index_this, int *rel_lookup_flag)
+    tokenbuf_t *result)
 {
     const char *p = begin;
     const char *data;
@@ -678,8 +738,7 @@
             p += rc;
         }
 
-        rc = parse_variable(var, ctx, p, end, 
-                      force_expand, &tmp, index_this, rel_lookup_flag);
+        rc = parse_variable(var, ctx, p, end, &tmp);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -695,7 +754,7 @@
        do. */
 
     if (name.begin == name.end) {
-        if (force_expand) {
+        if (ctx->force_expand) {
             rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC;
             goto error_return;
         }
@@ -715,8 +774,7 @@
     /* If the next token is START-INDEX, read the index specification. */
 
     if (var->syntax.index_open && *p == var->syntax.index_open) {
-        rc = parse_num_exp(var, ctx, ++p, end, index_this, &idx, &failed,
-                     rel_lookup_flag);
+        rc = parse_num_exp(var, ctx, ++p, end, &idx, &failed);
         if (rc < 0)
             goto error_return;
         if (rc == 0) {
@@ -753,12 +811,12 @@
         result->buffer_size = 0;
     }
     else {
-        rc = (*var->cb_value_fct) (var, var->cb_value_ctx, name.begin, name.end - name.begin, idx,
-                        &data, &len, &buffer_size);
+        rc = lookup_value(var, ctx, name.begin, name.end - name.begin, idx,
+                          &data, &len, &buffer_size);
         if (rc == VAR_ERR_UNDEFINED_VARIABLE) {
             /* The variable is undefined. What we'll do now depends on the
                force_expand flag. */
-            if (force_expand)
+            if (ctx->force_expand)
                 goto error_return;
 
             /* Initialize result to point back to the original text in
@@ -789,13 +847,9 @@
         while (p != end && *p == ':') {
             p++;
             if (!failed)
-                rc = parse_command(var, ctx, p, end, 
-                             force_expand, result,
-                             index_this, rel_lookup_flag);
+                rc = parse_command(var, ctx, p, end, result);
             else
-                rc = parse_command(var, ctx, p, end, 
-                             force_expand, &tmp,
-                             index_this, rel_lookup_flag);
+                rc = parse_command(var, ctx, p, end, &tmp);
             if (rc < 0)
                 goto error_return;
             p += rc;
@@ -832,8 +886,7 @@
     var_t *var, 
     var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand, tokenbuf_t *result, int index_this,
-    int *rel_lookup_flag)
+    tokenbuf_t *result)
 {
     const char *p = begin;
     const char *data;
@@ -860,8 +913,8 @@
     if (rc < 0)
         return rc;
     if (rc > 0) {
-        rc2 = (*var->cb_value_fct)(var, var->cb_value_ctx, p, rc, 0, &data, &len, &buffer_size);
-        if (rc2 == VAR_ERR_UNDEFINED_VARIABLE && !force_expand) {
+        rc2 = lookup_value(var, ctx, p, rc, 0, &data, &len, &buffer_size);
+        if (rc2 == VAR_ERR_UNDEFINED_VARIABLE && !ctx->force_expand) {
             result->begin = begin;
             result->end = begin + 1 + rc;
             result->buffer_size = 0;
@@ -877,8 +930,7 @@
 
     /* OK, we're dealing with a complex expression here. */
 
-    rc = parse_expression(var, ctx, p, end, 
-                    force_expand, result, index_this, rel_lookup_flag);
+    rc = parse_expression(var, ctx, p, end, result);
     if (rc > 0)
         rc++;
     return rc;
@@ -888,9 +940,7 @@
 parse_exptext_or_variable(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand,
-    tokenbuf_t *result, int index_this,
-    int *rel_lookup_flag)
+    tokenbuf_t *result)
 {
     const char *p = begin;
     tokenbuf_t tmp;
@@ -914,8 +964,7 @@
             p += rc;
         }
 
-        rc = parse_variable(var, ctx, p, end, 
-                      force_expand, &tmp, index_this, rel_lookup_flag);
+        rc = parse_variable(var, ctx, p, end, &tmp);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -941,9 +990,7 @@
 parse_substext_or_variable(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand,
-    tokenbuf_t *result, int index_this,
-    int *rel_lookup_flag)
+    tokenbuf_t *result)
 {
     const char *p = begin;
     tokenbuf_t tmp;
@@ -967,8 +1014,7 @@
             p += rc;
         }
 
-        rc = parse_variable(var, ctx, p, end, 
-                      force_expand, &tmp, index_this, rel_lookup_flag);
+        rc = parse_variable(var, ctx, p, end, &tmp);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -990,7 +1036,8 @@
     return rc;
 }
 
-static int parse_class_description(tokenbuf_t *src, tokenbuf_t *dst)
+static int 
+parse_class_description(tokenbuf_t *src, tokenbuf_t *dst)
 {
     unsigned char c, d;
     const char *p = src->begin;
@@ -1013,8 +1060,11 @@
     return VAR_OK;
 }
 
-static int transpose(tokenbuf_t *data, tokenbuf_t *search,
-                     tokenbuf_t *replace)
+static int 
+op_transpose(
+    tokenbuf_t *data, 
+    tokenbuf_t *search,
+    tokenbuf_t *replace)
 {
     tokenbuf_t srcclass, dstclass;
     const char *p;
@@ -1050,7 +1100,7 @@
     for (p = data->begin; p != data->end; ++p) {
         for (i = 0; i <= (srcclass.end - srcclass.begin); ++i) {
             if (*p == srcclass.begin[i]) {
-                *((char *) p) = dstclass.begin[i];
+                *((char *)p) = dstclass.begin[i];
                 break;
             }
         }
@@ -1068,8 +1118,12 @@
     return rc;
 }
 
-static int cut_out_offset(tokenbuf_t *data, tokenbuf_t *number1,
-                          tokenbuf_t *number2, int isrange)
+static int 
+op_cut_out_offset(
+    tokenbuf_t *data, 
+    tokenbuf_t *number1,
+    tokenbuf_t *number2, 
+    int isrange)
 {
     tokenbuf_t res;
     const char *p;
@@ -1112,8 +1166,12 @@
     return VAR_OK;
 }
 
-static int parse_regex_replace(const char *data, tokenbuf_t *orig,
-                                regmatch_t *pmatch, tokenbuf_t *expanded)
+static int 
+parse_regex_replace(
+    const char *data, 
+    tokenbuf_t *orig,
+    regmatch_t *pmatch, 
+    tokenbuf_t *expanded)
 {
     const char *p = orig->begin;
     size_t i;
@@ -1162,8 +1220,12 @@
     return VAR_OK;
 }
 
-static int search_and_replace(tokenbuf_t *data, tokenbuf_t *search,
-                              tokenbuf_t *replace, tokenbuf_t *flags)
+static int 
+op_search_and_replace(
+    tokenbuf_t *data, 
+    tokenbuf_t *search,
+    tokenbuf_t *replace, 
+    tokenbuf_t *flags)
 {
     const char *p;
     int case_insensitive = 0;
@@ -1316,8 +1378,12 @@
     return VAR_OK;
 }
 
-static int padding(tokenbuf_t *data, tokenbuf_t *widthstr, tokenbuf_t *fill,
-                   char position)
+static int 
+op_padding(
+    tokenbuf_t *data, 
+    tokenbuf_t *widthstr, 
+    tokenbuf_t *fill,
+    char position)
 {
     tokenbuf_t result;
     size_t width = tokenbuf_toint(widthstr);
@@ -1428,8 +1494,7 @@
 parse_command(
     var_t *var, var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand,
-    tokenbuf_t *data, int index_this, int *rel_lookup_flag)
+    tokenbuf_t *data)
 {
     const char *p = begin;
     tokenbuf_t tmptokbuf;
@@ -1449,281 +1514,272 @@
         return 0;
 
     switch (tolower(*p)) {
-    case 'l':                   /* Turn data to lowercase. */
-        if (data->begin) {
-            char *ptr;
-            /* If the buffer does not live in an allocated buffer,
-               we have to copy it before modifying the contents. */
+        case 'l':                   /* Turn data to lowercase. */
+            if (data->begin) {
+                char *ptr;
+                /* If the buffer does not live in an allocated buffer,
+                   we have to copy it before modifying the contents. */
+
+                if (data->buffer_size == 0) {
+                    if (!tokenbuf_assign(data, data->begin, data->end - data->begin)) {
+                        rc = VAR_ERR_OUT_OF_MEMORY;
+                        goto error_return;
+                    }
+                }
+                for (ptr = (char *)data->begin; ptr != data->end; ++ptr)
+                    *ptr = tolower(*ptr);
+            }
+            p++;
+            break;
 
-            if (data->buffer_size == 0) {
-                if (!tokenbuf_assign(data, data->begin, data->end - data->begin)) {
-                    rc = VAR_ERR_OUT_OF_MEMORY;
-                    goto error_return;
+        case 'u':                   /* Turn data to uppercase. */
+            if (data->begin) {
+                char *ptr;
+                if (data->buffer_size == 0) {
+                    if (!tokenbuf_assign
+                        (data, data->begin, data->end - data->begin)) {
+                        rc = VAR_ERR_OUT_OF_MEMORY;
+                        goto error_return;
+                    }
                 }
+                for (ptr = (char *) data->begin; ptr != data->end; ++ptr)
+                    *ptr = toupper(*ptr);
             }
-            for (ptr = (char *)data->begin; ptr != data->end; ++ptr)
-                *ptr = tolower(*ptr);
-        }
-        p++;
-        break;
+            ++p;
+            break;
 
-    case 'u':                   /* Turn data to uppercase. */
-        if (data->begin) {
-            char *ptr;
-            if (data->buffer_size == 0) {
-                if (!tokenbuf_assign
-                    (data, data->begin, data->end - data->begin)) {
+        case 'o':                   /* Cut out substrings. */
+            ++p;
+            rc = parse_number(var, ctx, p, end);
+            if (rc == 0) {
+                rc = VAR_ERR_MISSING_START_OFFSET;
+                goto error_return;
+            }
+            number1.begin = p;
+            number1.end = p + rc;
+            number1.buffer_size = 0;
+            p += rc;
+
+            if (*p == ',') {
+                isrange = 0;
+                ++p;
+            } else if (*p == '-') {
+                isrange = 1;
+                ++p;
+            } else {
+                rc = VAR_ERR_INVALID_OFFSET_DELIMITER;
+                goto error_return;
+            }
+
+            rc = parse_number(var, ctx, p, end);
+            number2.begin = p;
+            number2.end = p + rc;
+            number2.buffer_size = 0;
+            p += rc;
+            if (data->begin) {
+                rc = op_cut_out_offset(data, &number1, &number2, isrange);
+                if (rc < 0)
+                    goto error_return;
+            }
+            break;
+
+        case '#':                   /* Substitute length of the string. */
+            if (data->begin) {
+                char buf[((sizeof(int)*8)/3)+10]; /* sufficient size: <#bits> x log_10(2) + safety */
+                sprintf(buf, "%d", (int)(data->end - data->begin));
+                tokenbuf_free(data);
+                if (!tokenbuf_assign(data, buf, strlen(buf))) {
                     rc = VAR_ERR_OUT_OF_MEMORY;
                     goto error_return;
                 }
             }
-            for (ptr = (char *) data->begin; ptr != data->end; ++ptr)
-                *ptr = toupper(*ptr);
-        }
-        ++p;
-        break;
-
-    case 'o':                   /* Cut out substrings. */
-        ++p;
-        rc = parse_number(var, ctx, p, end);
-        if (rc == 0) {
-            rc = VAR_ERR_MISSING_START_OFFSET;
-            goto error_return;
-        }
-        number1.begin = p;
-        number1.end = p + rc;
-        number1.buffer_size = 0;
-        p += rc;
-
-        if (*p == ',') {
-            isrange = 0;
-            ++p;
-        } else if (*p == '-') {
-            isrange = 1;
             ++p;
-        } else {
-            rc = VAR_ERR_INVALID_OFFSET_DELIMITER;
-            goto error_return;
-        }
+            break;
 
-        rc = parse_number(var, ctx, p, end);
-        number2.begin = p;
-        number2.end = p + rc;
-        number2.buffer_size = 0;
-        p += rc;
-        if (data->begin) {
-            rc = cut_out_offset(data, &number1, &number2, isrange);
+        case '-':                   /* Substitute parameter if data is empty. */
+            p++;
+            rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf);
             if (rc < 0)
                 goto error_return;
-        }
-        break;
-
-    case '#':                   /* Substitute length of the string. */
-        if (data->begin) {
-            char buf[((sizeof(int)*8)/3)+10]; /* sufficient size: <#bits> x log_10(2) + safety */
-            sprintf(buf, "%d", (int)(data->end - data->begin));
-            tokenbuf_free(data);
-            if (!tokenbuf_assign(data, buf, strlen(buf))) {
-                rc = VAR_ERR_OUT_OF_MEMORY;
+            if (rc == 0) {
+                rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
                 goto error_return;
             }
-        }
-        ++p;
-        break;
-
-    case '-':                   /* Substitute parameter if data is empty. */
-        p++;
-        rc = parse_exptext_or_variable(var, ctx, p, end, 
-                                 force_expand, &tmptokbuf,
-                                 index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        if (rc == 0) {
-            rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
-            goto error_return;
-        }
-        p += rc;
-        if (data->begin != NULL && data->begin == data->end) {
-            tokenbuf_free(data);
-            tokenbuf_move(&tmptokbuf, data);
-        }
-        break;
-
-    case '*':                   /* Return "" if data is not empty, parameter otherwise. */
-        p++;
-        rc = parse_exptext_or_variable(var, ctx, p, end, 
-                                 force_expand, &tmptokbuf, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        if (rc == 0) {
-            rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
-            goto error_return;
-        }
-        p += rc;
-        if (data->begin != NULL) {
-            if (data->begin == data->end) {
+            p += rc;
+            if (data->begin != NULL && data->begin == data->end) {
                 tokenbuf_free(data);
                 tokenbuf_move(&tmptokbuf, data);
-            } else {
-                tokenbuf_free(data);
-                data->begin = data->end = "";
-                data->buffer_size = 0;
             }
-        }
-        break;
+            break;
 
-    case '+':                   /* Substitute parameter if data is not empty. */
-        p++;
-        rc = parse_exptext_or_variable(var, ctx, p, end, 
-                                 force_expand, &tmptokbuf, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        if (rc == 0) {
-            rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
-            goto error_return;
-        }
-        p += rc;
-        if (data->begin != NULL && data->begin != data->end) {
-            tokenbuf_free(data);
-            tokenbuf_move(&tmptokbuf, data);
-        }
-        break;
+        case '*':                   /* Return "" if data is not empty, parameter otherwise. */
+            p++;
+            rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf);
+            if (rc < 0)
+                goto error_return;
+            if (rc == 0) {
+                rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
+                goto error_return;
+            }
+            p += rc;
+            if (data->begin != NULL) {
+                if (data->begin == data->end) {
+                    tokenbuf_free(data);
+                    tokenbuf_move(&tmptokbuf, data);
+                } else {
+                    tokenbuf_free(data);
+                    data->begin = data->end = "";
+                    data->buffer_size = 0;
+                }
+            }
+            break;
 
-    case 's':                   /* Search and replace. */
-        p++;
+        case '+':                   /* Substitute parameter if data is not empty. */
+            p++;
+            rc = parse_exptext_or_variable(var, ctx, p, end, &tmptokbuf);
+            if (rc < 0)
+                goto error_return;
+            if (rc == 0) {
+                rc = VAR_ERR_MISSING_PARAMETER_IN_COMMAND;
+                goto error_return;
+            }
+            p += rc;
+            if (data->begin != NULL && data->begin != data->end) {
+                tokenbuf_free(data);
+                tokenbuf_move(&tmptokbuf, data);
+            }
+            break;
 
-        if (*p != '/')
-            return VAR_ERR_MALFORMATTED_REPLACE;
-        p++;
+        case 's':                   /* Search and replace. */
+            p++;
 
-        rc = parse_substext_or_variable(var, ctx, p, end, 
-                                  force_expand, &search, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        p += rc;
+            if (*p != '/')
+                return VAR_ERR_MALFORMATTED_REPLACE;
+            p++;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_REPLACE;
-            goto error_return;
-        }
-        p++;
+            rc = parse_substext_or_variable(var, ctx, p, end, &search);
+            if (rc < 0)
+                goto error_return;
+            p += rc;
 
-        rc = parse_substext_or_variable(var, ctx, p, end, 
-                                  force_expand, &replace, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        p += rc;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_REPLACE;
+                goto error_return;
+            }
+            p++;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_REPLACE;
-            goto error_return;
-        }
-        p++;
+            rc = parse_substext_or_variable(var, ctx, p, end, &replace);
+            if (rc < 0)
+                goto error_return;
+            p += rc;
 
-        rc = parse_exptext(var, ctx, p, end);
-        if (rc < 0)
-            goto error_return;
-        flags.begin = p;
-        flags.end = p + rc;
-        flags.buffer_size = 0;
-        p += rc;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_REPLACE;
+                goto error_return;
+            }
+            p++;
 
-        if (data->begin) {
-            rc = search_and_replace(data, &search, &replace, &flags);
+            rc = parse_exptext(var, ctx, p, end);
             if (rc < 0)
                 goto error_return;
-        }
-        break;
-
-    case 'y':                   /* Transpose characters from class A to class B. */
-        p++;
+            flags.begin = p;
+            flags.end = p + rc;
+            flags.buffer_size = 0;
+            p += rc;
 
-        if (*p != '/')
-            return VAR_ERR_MALFORMATTED_TRANSPOSE;
-        p++;
+            if (data->begin) {
+                rc = op_search_and_replace(data, &search, &replace, &flags);
+                if (rc < 0)
+                    goto error_return;
+            }
+            break;
 
-        rc = parse_substext_or_variable(var, ctx, p, end, 
-                                  force_expand, &search, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        p += rc;
+        case 'y':                   /* Transpose characters from class A to class B. */
+            p++;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_TRANSPOSE;
-            goto error_return;
-        }
-        p++;
+            if (*p != '/')
+                return VAR_ERR_MALFORMATTED_TRANSPOSE;
+            p++;
 
-        rc = parse_substext_or_variable(var, ctx, p, end, 
-                                  force_expand, &replace, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        p += rc;
+            rc = parse_substext_or_variable(var, ctx, p, end, &search);
+            if (rc < 0)
+                goto error_return;
+            p += rc;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_TRANSPOSE;
-            goto error_return;
-        } else
-            ++p;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_TRANSPOSE;
+                goto error_return;
+            }
+            p++;
 
-        if (data->begin) {
-            rc = transpose(data, &search, &replace);
+            rc = parse_substext_or_variable(var, ctx, p, end, &replace);
             if (rc < 0)
                 goto error_return;
-        }
-        break;
-
+            p += rc;
 
-    case 'p':                   /* Padding. */
-        p++;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_TRANSPOSE;
+                goto error_return;
+            } else
+                ++p;
 
-        if (*p != '/')
-            return VAR_ERR_MALFORMATTED_PADDING;
-        p++;
+            if (data->begin) {
+                rc = op_transpose(data, &search, &replace);
+                if (rc < 0)
+                    goto error_return;
+            }
+            break;
 
-        rc = parse_number(var, ctx, p, end);
-        if (rc == 0) {
-            rc = VAR_ERR_MISSING_PADDING_WIDTH;
-            goto error_return;
-        }
-        number1.begin = p;
-        number1.end = p + rc;
-        number1.buffer_size = 0;
-        p += rc;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_PADDING;
-            goto error_return;
-        }
-        p++;
+        case 'p':                   /* Padding. */
+            p++;
 
-        rc = parse_substext_or_variable(var, ctx, p, end, 
-                                  force_expand, &replace, index_this, rel_lookup_flag);
-        if (rc < 0)
-            goto error_return;
-        p += rc;
+            if (*p != '/')
+                return VAR_ERR_MALFORMATTED_PADDING;
+            p++;
 
-        if (*p != '/') {
-            rc = VAR_ERR_MALFORMATTED_PADDING;
-            goto error_return;
-        }
-        p++;
+            rc = parse_number(var, ctx, p, end);
+            if (rc == 0) {
+                rc = VAR_ERR_MISSING_PADDING_WIDTH;
+                goto error_return;
+            }
+            number1.begin = p;
+            number1.end = p + rc;
+            number1.buffer_size = 0;
+            p += rc;
 
-        if (*p != 'l' && *p != 'c' && *p != 'r') {
-            rc = VAR_ERR_MALFORMATTED_PADDING;
-            goto error_return;
-        }
-        p++;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_PADDING;
+                goto error_return;
+            }
+            p++;
 
-        if (data->begin) {
-            rc = padding(data, &number1, &replace, p[-1]);
+            rc = parse_substext_or_variable(var, ctx, p, end, &replace);
             if (rc < 0)
                 goto error_return;
-        }
-        break;
+            p += rc;
 
-    default:
-        return VAR_ERR_UNKNOWN_COMMAND_CHAR;
+            if (*p != '/') {
+                rc = VAR_ERR_MALFORMATTED_PADDING;
+                goto error_return;
+            }
+            p++;
+
+            if (*p != 'l' && *p != 'c' && *p != 'r') {
+                rc = VAR_ERR_MALFORMATTED_PADDING;
+                goto error_return;
+            }
+            p++;
+
+            if (data->begin) {
+                rc = op_padding(data, &number1, &replace, p[-1]);
+                if (rc < 0)
+                    goto error_return;
+            }
+            break;
+
+        default:
+            return VAR_ERR_UNKNOWN_COMMAND_CHAR;
     }
 
     /* Exit gracefully. */
@@ -1753,12 +1809,12 @@
     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_end)
 {
     const char *p;
     int rc;
     int failed;
-    int dummy;
 
     p = begin;
     if (begin == end)
@@ -1770,7 +1826,7 @@
 
     /* Read start value for the loop. */
     failed = 0;
-    rc = parse_num_exp(var, ctx, p, end, 0, start, &failed, &dummy);
+    rc = parse_num_exp(var, ctx, p, end, start, &failed);
     if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC)
         *start = 0;          /* use default */
     else if (rc < 0)
@@ -1787,7 +1843,7 @@
 
     /* Read step value for the loop. */
     failed = 0;
-    rc = parse_num_exp(var, ctx, p, end, 0, step, &failed, &dummy);
+    rc = parse_num_exp(var, ctx, p, end, step, &failed);
     if (rc == VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC)
         *step = 1;          /* use default */
     else if (rc < 0)
@@ -1815,7 +1871,7 @@
 
     /* Read stop value for the loop. */
     failed = 0;
-    rc = parse_num_exp(var, ctx, p, end, 0, stop, &failed, &dummy);
+    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;
@@ -1834,51 +1890,14 @@
     return ++p - begin;
 }
 
-/* callback wrapper context */
-typedef struct {
-    var_cb_value_t cb_value_fct;
-    void          *cb_value_ctx;
-    int           *rel_lookup_flag;
-} var_wrapper_t;
-
-/* callback wrapper function */
-static int 
-lookup_wrapper(
-    var_t *var, 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 buf[1];
-    var_wrapper_t *wcon = (var_wrapper_t *)ctx;
-    int rc;
-
-    /* pass through to original callback */
-    rc = (*wcon->cb_value_fct)(var, wcon->cb_value_ctx,
-                               var_ptr, var_len, var_idx, 
-                               val_ptr, val_len, val_size);
-
-    /* convert undefined variable into empty variable */
-    if (rc == VAR_ERR_UNDEFINED_VARIABLE) {
-        (*wcon->rel_lookup_flag)--;
-        buf[0] = NUL;
-        *val_ptr  = buf;
-        *val_len  = 0;
-        *val_size = 0;
-        return VAR_OK;
-    }
-
-    return rc;
-}
-
 /* expand input in general */
 static var_rc_t 
 parse_input(
     var_t *var,
     var_parse_t *ctx,
     const char *begin, const char *end,
-    int force_expand,
-    tokenbuf_t *output, int index_this,
-    size_t recursion_level, int *rel_lookup_flag)
+    tokenbuf_t *output, 
+    int recursion_level)
 {
     const char *p = begin;
     int rc, rc2;
@@ -1886,21 +1905,18 @@
     int start, step, stop, open_end;
     int i;
     int output_backup;
-    var_wrapper_t wcon;
-    int my_rel_lookup_flag;
-    int original_rel_lookup_state;
+    int rel_lookup_cnt;
     int loop_limit_length;
+    var_parse_t myctx;
 
     tokenbuf_init(&result);
 
-    if (rel_lookup_flag == NULL) {
-        rel_lookup_flag  = &my_rel_lookup_flag;
-        *rel_lookup_flag = 0;
-    }
-
     do {
-        if (begin != end && var->syntax.index_open && *begin == var->syntax.index_open) {
-            original_rel_lookup_state = *rel_lookup_flag;
+        /* try to parse a loop construct */
+        if (   begin != end 
+            && var->syntax.index_open != NUL 
+            && *begin == var->syntax.index_open) {
+
             loop_limit_length = -1;
             begin++;
             start = 0;
@@ -1909,27 +1925,31 @@
             open_end = 1;
             rc = 0;
             output_backup = 0;
-      re_loop:
+            rel_lookup_cnt = ctx->rel_lookup_cnt;
+
+            re_loop:
             for (i = start;
-                 (open_end  && (loop_limit_length < 0 || *rel_lookup_flag > original_rel_lookup_state)) ||
-                     (!open_end && i <= stop);
+                 (   (  open_end 
+                      && (   loop_limit_length < 0 
+                          || rel_lookup_cnt > ctx->rel_lookup_cnt)) 
+                  || (   !open_end 
+                      && i <= stop)                                            );
                  i += step) {
-                *rel_lookup_flag = original_rel_lookup_state;
+                /* remember current state for backing off */
                 output_backup = output->end - output->begin;
 
-                /* activate callback wrapper */
-                wcon.cb_value_fct    = var->cb_value_fct;
-                wcon.cb_value_ctx    = var->cb_value_ctx;
-                wcon.rel_lookup_flag = rel_lookup_flag;
-                var->cb_value_fct    = lookup_wrapper;
-                var->cb_value_ctx    = &wcon;
+                /* open temporary context for recursion */ 
+                ctx = var_parse_push(ctx, &myctx);
+                ctx->force_expand    = 1;
+                ctx->rel_lookup_flag = 1;
+                ctx->index_this      = i;
 
                 rc = parse_input(var, ctx, begin, end, 
-                                 1, output, i, recursion_level+1, rel_lookup_flag);
+                                 output, recursion_level+1);
 
-                /* deactivate callback wrapper */
-                var->cb_value_fct = wcon.cb_value_fct;
-                var->cb_value_ctx = wcon.cb_value_ctx;
+                /* retrieve info and close temporary context */
+                rel_lookup_cnt = ctx->rel_lookup_cnt;
+                ctx = var_parse_pop(ctx);
 
                 if (rc < 0)
                     goto error_return;
@@ -1955,13 +1975,14 @@
             if (open_end)
                 output->end = output->begin + output_backup;
             else
-                *rel_lookup_flag = original_rel_lookup_state;
+                rel_lookup_cnt = ctx->rel_lookup_cnt;
             begin += rc;
             begin++;
             begin += loop_limit_length;
             continue;
         }
 
+        /* try to parse plain text */
         rc = parse_text(var, ctx, begin, end);
         if (rc > 0) {
             if (!tokenbuf_append(output, begin, rc)) {
@@ -1973,9 +1994,8 @@
         } else if (rc < 0)
             goto error_return;
 
-        rc = parse_variable(var, ctx, begin, end, 
-                             force_expand, &result,
-                             index_this, rel_lookup_flag);
+        /* try to parse a variable construct */
+        rc = parse_variable(var, ctx, begin, end, &result);
         if (rc > 0) {
             if (!tokenbuf_append(output, result.begin, result.end - result.begin)) {
                 rc = VAR_ERR_OUT_OF_MEMORY;
@@ -1986,6 +2006,7 @@
         }
         if (rc < 0)
             goto error_return;
+
     } while (begin != end && rc > 0);
 
     if (recursion_level == 0 && begin != end) {
@@ -2164,7 +2185,11 @@
         return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
 
     /* prepare internal expansion context */
+    ctx.lower = NULL;
     ctx.force_expand = force_expand;
+    ctx.rel_lookup_flag = 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. */
@@ -2172,9 +2197,7 @@
 
     /* call the parsing */
     tokenbuf_init(&output);
-    rc = parse_input(var, &ctx, 
-                     src_ptr, src_ptr + src_len, 
-                     ctx.force_expand, &output, 0, 0, NULL);
+    rc = parse_input(var, &ctx, src_ptr, src_ptr + src_len, &output, 0);
 
     /* post-process output */
     if (rc >= 0) {

CVSTrac 2.0.1