OSSP CVS Repository

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

ossp-pkg/var/var.c 1.61 -> 1.62

--- var.c        2002/02/27 13:44:16     1.61
+++ var.c        2002/02/28 08:08:16     1.62
@@ -31,6 +31,8 @@
 #include "config.h"
 #endif
 
+#include <stdlib.h>
+#include <stdarg.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
@@ -56,75 +58,29 @@
 #define VAR_RC(rv) (rv)
 #endif /* WITH_EX */
 
-/* The default configuration for the parser. */
-
-const var_config_t var_config_default = {
-    '$',                        /* varinit */
-    '{',                        /* startdelim */
-    '}',                        /* enddelim */
-    '[',                        /* startindex */
-    ']',                        /* endindex */
-    '#',                        /* current_index */
-    '\\',                       /* escape */
-    "a-zA-Z0-9_"                /* namechars */
+/* the external context structure */
+struct var_st {
+    var_syntax_t   syntax;
+    var_cb_value_t cb_value_fct;
+    void          *cb_value_ctx;
 };
 
-/* The var_strerror() routine will map a var_rc_t into a text message. */
-
-const char *var_strerror(var_rc_t rc)
-{
-    static char *var_errors[] = {
-        "everything ok",                                                        /* VAR_OK = 0 */
-        "incomplete named character",                                           /* VAR_ERR_INCOMPLETE_NAMED_CHARACTER */
-        "incomplete hexadecimal value",                                         /* VAR_ERR_INCOMPLETE_HEX */
-        "invalid hexadecimal value",                                            /* VAR_ERR_INVALID_HEX */
-        "octal value too large",                                                /* VAR_ERR_OCTAL_TOO_LARGE */
-        "invalid octal value",                                                  /* VAR_ERR_INVALID_OCTAL */
-        "incomplete octal value",                                               /* VAR_ERR_INCOMPLETE_OCTAL */
-        "incomplete grouped hexadecimal value",                                 /* VAR_ERR_INCOMPLETE_GROUPED_HEX */
-        "incorrect character class specification",                              /* VAR_ERR_INCORRECT_CLASS_SPEC */
-        "invalid expansion configuration",                                      /* VAR_ERR_INVALID_CONFIGURATION */
-        "out of memory",                                                        /* VAR_ERR_OUT_OF_MEMORY */
-        "incomplete variable specification",                                    /* VAR_ERR_INCOMPLETE_VARIABLE_SPEC */
-        "undefined variable",                                                   /* VAR_ERR_UNDEFINED_VARIABLE */
-        "input is neither text nor variable",                                   /* VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE */
-        "unknown command character in variable",                                /* VAR_ERR_UNKNOWN_COMMAND_CHAR */
-        "malformated search and replace operation",                             /* VAR_ERR_MALFORMATTED_REPLACE */
-        "unknown flag in search and replace operation",                         /* VAR_ERR_UNKNOWN_REPLACE_FLAG */
-        "invalid regular expression in search and replace operation",           /* VAR_ERR_INVALID_REGEX_IN_REPLACE */
-        "missing parameter in command",                                         /* VAR_ERR_MISSING_PARAMETER_IN_COMMAND */
-        "empty search string in search and replace operation",                  /* VAR_ERR_EMPTY_SEARCH_STRING */
-        "start offset missing in cut operation",                                /* VAR_ERR_MISSING_START_OFFSET */
-        "offsets in cut operation delimited by unknown character",              /* VAR_ERR_INVALID_OFFSET_DELIMITER */
-        "range out of bounds in cut operation",                                 /* VAR_ERR_RANGE_OUT_OF_BOUNDS */
-        "offset out of bounds in cut operation",                                /* VAR_ERR_OFFSET_OUT_OF_BOUNDS */
-        "logic error in cut operation",                                         /* VAR_ERR_OFFSET_LOGIC */
-        "malformatted transpose operation",                                     /* VAR_ERR_MALFORMATTED_TRANSPOSE */
-        "source and destination classes do not match in transpose operation",   /* VAR_ERR_TRANSPOSE_CLASSES_MISMATCH */
-        "empty character class in transpose operation",                         /* VAR_ERR_EMPTY_TRANSPOSE_CLASS */
-        "incorrect character class in transpose operation",                     /* VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC */
-        "malformatted padding operation",                                       /* VAR_ERR_MALFORMATTED_PADDING */
-        "width parameter missing in padding operation",                         /* VAR_ERR_MISSING_PADDING_WIDTH */
-        "fill string missing in padding operation",                             /* VAR_ERR_EMPTY_PADDING_FILL_STRING */
-        "unknown quoted pair in search and replace operation",                  /* VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE */
-        "sub-matching reference out of range",                                  /* VAR_ERR_SUBMATCH_OUT_OF_RANGE */
-        "invalid argument",                                                     /* VAR_ERR_INVALID_ARGUMENT */
-        "incomplete quoted pair",                                               /* VAR_ERR_INCOMPLETE_QUOTED_PAIR */
-        "lookup function does not support variable arrays",                     /* VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED */
-        "index specification of array variable contains an invalid character",  /* VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC */
-        "index specification of array variable is incomplete",                  /* VAR_ERR_INCOMPLETE_INDEX_SPEC */
-        "bracket expression in array variable's index is not closed",           /* VAR_ERR_UNCLOSED_BRACKET_IN_INDEX */
-        "division by zero error in index specification",                        /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX */
-        "unterminated loop construct",                                          /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT */
-        "invalid character in loop limits"                                      /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS */
-    };
-
-    rc = 0 - rc;
-    if (rc < 0 || rc >= sizeof(var_errors) / sizeof(char *))
-        return "unknown error";
+/* the internal expansion context structure */
+typedef struct {
+    int            force_expand;
+} var_expand_t;
 
-    return var_errors[rc];
-}
+/* the default syntax configuration */
+static const var_syntax_t var_syntax_default = {
+    '\\',         /* escape */
+    '$',          /* delim_init */
+    '{',          /* delim_open */
+    '}',          /* delim_close */
+    '[',          /* index_open */
+    ']',          /* index_close */
+    '#',          /* index_mark */
+    "a-zA-Z0-9_"  /* name_chars */
+};
 
 /* Routines for manipulation of token buffers. */
 
@@ -384,85 +340,25 @@
         return expand_simple_hex(src, dst, end);
 }
 
-var_rc_t var_unescape(const char *src, size_t len, char *dst,
-                      int unescape_all)
-{
-    const char *end = src + len;
-    var_rc_t rc;
-
-    while (src < end) {
-        if (*src == '\\') {
-            if (++src == end)
-                return VAR_RC(VAR_ERR_INCOMPLETE_NAMED_CHARACTER);
-            switch (*src) {
-            case '\\':
-                if (!unescape_all) {
-                    *dst++ = '\\';
-                }
-                *dst++ = '\\';
-                break;
-            case 'n':
-                *dst++ = '\n';
-                break;
-            case 't':
-                *dst++ = '\t';
-                break;
-            case 'r':
-                *dst++ = '\r';
-                break;
-            case 'x':
-                ++src;
-                if ((rc = expand_hex(&src, &dst, end)) != VAR_OK)
-                    return VAR_RC(rc);
-                break;
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                if (end - src >= 3 && isdigit((int)src[1]) && isdigit((int)src[2])) {
-                    if ((rc = expand_octal(&src, &dst, end)) != 0)
-                        return VAR_RC(rc);
-                    break;
-                }
-            default:
-                if (!unescape_all) {
-                    *dst++ = '\\';
-                }
-                *dst++ = *src;
-            }
-            ++src;
-        } else
-            *dst++ = *src++;
-    }
-    *dst = '\0';
-    return VAR_OK;
-}
-
 /* The recursive-descent parser for variable expressions. */
 
 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 current_index,
+                    const var_syntax_t *config, const char_class_t nameclass,
+                    var_cb_value_t lookup, void *lookup_context,
+                    int force_expand, tokenbuf_t *result, int index_mark,
                     int* rel_lookup_flag);
 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, int current_index, int* rel_lookup_flag);
-static int num_exp(const char *begin, const char *end, int current_index,
+                   const var_syntax_t *config, const char_class_t nameclass,
+                   var_cb_value_t lookup, void *lookup_context, int force_expand,
+                   tokenbuf_t *data, int index_mark, int* rel_lookup_flag);
+static int num_exp(const char *begin, const char *end, int index_mark,
                    int* result, int* failed, int* rel_lookup_flag,
-                   const var_config_t *config,
+                   const var_syntax_t *config,
                    const char_class_t nameclass,
-                   var_cb_t lookup, void* lookup_context);
+                   var_cb_value_t lookup, void* lookup_context);
 
-static int text(const char *begin, const char *end, char varinit,
-                char startindex, char endindex, char escape)
+static int text(const char *begin, const char *end, char delim_init,
+                char index_open, char index_close, char escape)
 {
     const char *p;
 
@@ -471,9 +367,9 @@
             if (++p == end)
                 return VAR_ERR_INCOMPLETE_QUOTED_PAIR;
         }
-        else if (*p == varinit)
+        else if (*p == delim_init)
             break;
-        else if (startindex && (*p == startindex || *p == endindex))
+        else if (index_open && (*p == index_open || *p == index_close))
             break;
     }
     return p - begin;
@@ -499,11 +395,11 @@
 }
 
 static int substext(const char *begin, const char *end,
-                    const var_config_t *config)
+                    const var_syntax_t *config)
 {
     const char *p;
 
-    for (p = begin; p != end && *p != config->varinit && *p != '/'; p++) {
+    for (p = begin; p != end && *p != config->delim_init && *p != '/'; p++) {
         if (*p == config->escape) {
             if (p + 1 == end)
                 return VAR_ERR_INCOMPLETE_QUOTED_PAIR;
@@ -514,14 +410,14 @@
 }
 
 static int exptext(const char *begin, const char *end,
-                   const var_config_t *config)
+                   const var_syntax_t *config)
 {
     const char *p;
 
     for (p = begin;
             p != end
-         && *p != config->varinit
-         && *p != config->enddelim
+         && *p != config->delim_init
+         && *p != config->delim_close
          && *p != ':'; p++) {
         if (*p == config->escape) {
             if (p + 1 == end)
@@ -544,11 +440,11 @@
     return num;
 }
 
-static int num_exp_read_operand(const char *begin, const char *end, int current_index,
+static int num_exp_read_operand(const char *begin, const char *end, int index_mark,
                                 int *result, int *failed, int *rel_lookup_flag,
-                                const var_config_t *config,
+                                const var_syntax_t *config,
                                 const char_class_t nameclass,
-                                var_cb_t lookup, void *lookup_context)
+                                var_cb_value_t lookup, void *lookup_context)
 {
     const char* p = begin;
     tokenbuf_t tmp;
@@ -560,7 +456,7 @@
         return VAR_ERR_INCOMPLETE_INDEX_SPEC;
 
     if (*p == '(') {
-        rc = num_exp(++p, end, current_index, result, failed,
+        rc = num_exp(++p, end, index_mark, result, failed,
                      rel_lookup_flag, config, nameclass, lookup, lookup_context);
         if (rc < 0)
             return rc;
@@ -571,13 +467,13 @@
             return VAR_ERR_UNCLOSED_BRACKET_IN_INDEX;
         ++p;
     }
-    else if (*p == config->varinit) {
+    else if (*p == config->delim_init) {
         rc = variable(p, end, config, nameclass, lookup,
-                      lookup_context, 1, &tmp, current_index, rel_lookup_flag);
+                      lookup_context, 1, &tmp, index_mark, rel_lookup_flag);
         if (rc == VAR_ERR_UNDEFINED_VARIABLE) {
             *failed = 1;
             rc = variable(p, end, config, nameclass, lookup,
-                          lookup_context, 0, &tmp, current_index, rel_lookup_flag);
+                          lookup_context, 0, &tmp, index_mark, rel_lookup_flag);
             if (rc < 0)
                 return rc;
             p += rc;
@@ -587,16 +483,16 @@
             if (rc < 0)
                 return rc;
             p += rc;
-            rc = num_exp(tmp.begin, tmp.end, current_index, result,
+            rc = num_exp(tmp.begin, tmp.end, index_mark, result,
                          failed, rel_lookup_flag, config, nameclass, lookup, lookup_context);
             tokenbuf_free(&tmp);
             if (rc < 0)
                 return rc;
         }
     }
-    else if (config->current_index && *p == config->current_index) {
+    else if (config->index_mark && *p == config->index_mark) {
         p++;
-        *result = current_index;
+        *result = index_mark;
         (*rel_lookup_flag)++;
     }
     else if (isdigit(*p)) {
@@ -625,11 +521,11 @@
     return p - begin;
 }
 
-static int num_exp(const char *begin, const char *end, int current_index,
+static int num_exp(const char *begin, const char *end, int index_mark,
                    int *result, int *failed, int *rel_lookup_flag,
-                   const var_config_t *config,
+                   const var_syntax_t *config,
                    const char_class_t nameclass,
-                   var_cb_t lookup, void *lookup_context)
+                   var_cb_value_t lookup, void *lookup_context)
 {
     const char *p = begin;
     char operator;
@@ -639,7 +535,7 @@
     if (begin == end)
         return VAR_ERR_INCOMPLETE_INDEX_SPEC;
 
-    rc = num_exp_read_operand(p, end, current_index, result,
+    rc = num_exp_read_operand(p, end, index_mark, result,
                               failed, rel_lookup_flag, config, nameclass,
                               lookup, lookup_context);
     if (rc < 0)
@@ -649,7 +545,7 @@
     while (p != end) {
         if (*p == '+' || *p == '-') {
             operator = *p++;
-            rc = num_exp(p, end, current_index, &right, failed,
+            rc = num_exp(p, end, index_mark, &right, failed,
                          rel_lookup_flag, config, nameclass, lookup, lookup_context);
             if (rc < 0)
                 return rc;
@@ -661,7 +557,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, index_mark, &right, failed,
                                       rel_lookup_flag, config, nameclass, lookup, lookup_context);
             if (rc < 0)
                 return rc;
@@ -697,10 +593,10 @@
 }
 
 static int expression(const char *begin, const char *end,
-                      const var_config_t *config,
-                      const char_class_t nameclass, var_cb_t lookup,
+                      const var_syntax_t *config,
+                      const char_class_t nameclass, var_cb_value_t lookup,
                       void *lookup_context, int force_expand,
-                      tokenbuf_t *result, int current_index, int *rel_lookup_flag)
+                      tokenbuf_t *result, int index_mark, int *rel_lookup_flag)
     {
     const char *p = begin;
     const char *data;
@@ -719,7 +615,7 @@
 
     /* Expect STARTDELIM. */
 
-    if (p == end || *p != config->startdelim)
+    if (p == end || *p != config->delim_open)
         return 0;
 
     if (++p == end)
@@ -741,7 +637,7 @@
         }
 
         rc = variable(p, end, config, nameclass, lookup, lookup_context,
-                      force_expand, &tmp, current_index, rel_lookup_flag);
+                      force_expand, &tmp, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -763,8 +659,8 @@
 
     /* 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,
+    if (config->index_open && *p == config->index_open) {
+        rc = num_exp(++p, end, index_mark, &idx, &failed,
                      rel_lookup_flag, config, nameclass, lookup, lookup_context);
         if (rc < 0)
             goto error_return;
@@ -778,7 +674,7 @@
             rc = VAR_ERR_INCOMPLETE_INDEX_SPEC;
             goto error_return;
         }
-        if (*p != config->endindex) {
+        if (*p != config->index_close) {
             rc = VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC;
             goto error_return;
         }
@@ -788,7 +684,7 @@
     /* Now we have the name of the variable stored in "name". The next
        token here must either be an END-DELIM or a ':'. */
 
-    if (p == end || (*p != config->enddelim && *p != ':')) {
+    if (p == end || (*p != config->delim_close && *p != ':')) {
         rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC;
         goto error_return;
     }
@@ -839,11 +735,11 @@
             if (!failed)
                 rc = command(p, end, config, nameclass, lookup,
                              lookup_context, force_expand, result,
-                             current_index, rel_lookup_flag);
+                             index_mark, rel_lookup_flag);
             else
                 rc = command(p, end, config, nameclass, lookup,
                              lookup_context, force_expand, &tmp,
-                             current_index, rel_lookup_flag);
+                             index_mark, rel_lookup_flag);
             if (rc < 0)
                 goto error_return;
             p += rc;
@@ -851,7 +747,7 @@
                 result->end += rc;
         }
 
-        if (p == end || *p != config->enddelim) {
+        if (p == end || *p != config->delim_close) {
             rc = VAR_ERR_INCOMPLETE_VARIABLE_SPEC;
             goto error_return;
         }
@@ -876,9 +772,9 @@
 }
 
 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 current_index,
+                    const var_syntax_t *config, const char_class_t nameclass,
+                    var_cb_value_t lookup, void *lookup_context,
+                    int force_expand, tokenbuf_t *result, int index_mark,
                     int *rel_lookup_flag)
 {
     const char *p = begin;
@@ -893,7 +789,7 @@
 
     /* Expect VARINIT. */
 
-    if (p == end || *p != config->varinit)
+    if (p == end || *p != config->delim_init)
         return 0;
 
     if (++p == end)
@@ -924,17 +820,17 @@
     /* OK, we're dealing with a complex expression here. */
 
     rc = expression(p, end, config, nameclass, lookup, lookup_context,
-                    force_expand, result, current_index, rel_lookup_flag);
+                    force_expand, result, index_mark, rel_lookup_flag);
     if (rc > 0)
         rc++;
     return rc;
 }
 
 static int exptext_or_variable(const char *begin, const char *end,
-                               const var_config_t *config,
-                               const char_class_t nameclass, var_cb_t lookup,
+                               const var_syntax_t *config,
+                               const char_class_t nameclass, var_cb_value_t lookup,
                                void *lookup_context, int force_expand,
-                               tokenbuf_t *result, int current_index,
+                               tokenbuf_t *result, int index_mark,
                                int *rel_lookup_flag)
 {
     const char *p = begin;
@@ -960,7 +856,7 @@
         }
 
         rc = variable(p, end, config, nameclass, lookup, lookup_context,
-                      force_expand, &tmp, current_index, rel_lookup_flag);
+                      force_expand, &tmp, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -983,10 +879,10 @@
 }
 
 static int substext_or_variable(const char *begin, const char *end,
-                                const var_config_t *config,
-                                const char_class_t nameclass, var_cb_t lookup,
+                                const var_syntax_t *config,
+                                const char_class_t nameclass, var_cb_value_t lookup,
                                 void *lookup_context, int force_expand,
-                                tokenbuf_t *result, int current_index,
+                                tokenbuf_t *result, int index_mark,
                                 int *rel_lookup_flag)
 {
     const char *p = begin;
@@ -1012,7 +908,7 @@
         }
 
         rc = variable(p, end, config, nameclass, lookup, lookup_context,
-                      force_expand, &tmp, current_index, rel_lookup_flag);
+                      force_expand, &tmp, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc > 0) {
@@ -1469,9 +1365,9 @@
 }
 
 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, int current_index, int *rel_lookup_flag)
+                   const var_syntax_t *config, const char_class_t nameclass,
+                   var_cb_value_t lookup, void *lookup_context, int force_expand,
+                   tokenbuf_t *data, int index_mark, int *rel_lookup_flag)
 {
     const char *p = begin;
     tokenbuf_t tmptokbuf;
@@ -1577,7 +1473,7 @@
         p++;
         rc = exptext_or_variable(p, end, config, nameclass, lookup,
                                  lookup_context, force_expand, &tmptokbuf,
-                                 current_index, rel_lookup_flag);
+                                 index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc == 0) {
@@ -1594,7 +1490,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, current_index, rel_lookup_flag);
+                                 lookup_context, force_expand, &tmptokbuf, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc == 0) {
@@ -1617,7 +1513,7 @@
     case '+':                   /* Substitute parameter if data is not empty. */
         p++;
         rc = exptext_or_variable(p, end, config, nameclass, lookup,
-                                 lookup_context, force_expand, &tmptokbuf, current_index, rel_lookup_flag);
+                                 lookup_context, force_expand, &tmptokbuf, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         if (rc == 0) {
@@ -1639,7 +1535,7 @@
         p++;
 
         rc = substext_or_variable(p, end, config, nameclass, lookup,
-                                  lookup_context, force_expand, &search, current_index, rel_lookup_flag);
+                                  lookup_context, force_expand, &search, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         p += rc;
@@ -1651,7 +1547,7 @@
         p++;
 
         rc = substext_or_variable(p, end, config, nameclass, lookup,
-                                  lookup_context, force_expand, &replace, current_index, rel_lookup_flag);
+                                  lookup_context, force_expand, &replace, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         p += rc;
@@ -1685,7 +1581,7 @@
         p++;
 
         rc = substext_or_variable(p, end, config, nameclass, lookup,
-                                  lookup_context, force_expand, &search, current_index, rel_lookup_flag);
+                                  lookup_context, force_expand, &search, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         p += rc;
@@ -1697,7 +1593,7 @@
         p++;
 
         rc = substext_or_variable(p, end, config, nameclass, lookup,
-                                  lookup_context, force_expand, &replace, current_index, rel_lookup_flag);
+                                  lookup_context, force_expand, &replace, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         p += rc;
@@ -1740,7 +1636,7 @@
         p++;
 
         rc = substext_or_variable(p, end, config, nameclass, lookup,
-                                  lookup_context, force_expand, &replace, current_index, rel_lookup_flag);
+                                  lookup_context, force_expand, &replace, index_mark, rel_lookup_flag);
         if (rc < 0)
             goto error_return;
         p += rc;
@@ -1790,7 +1686,7 @@
 }
 
 struct wrapper_context {
-    var_cb_t lookup;
+    var_cb_value_t lookup;
     void    *context;
     int     *rel_lookup_flag;
 };
@@ -1817,9 +1713,9 @@
 }
 
 static var_rc_t loop_limits(const char *begin, const char *end,
-                            const var_config_t *config,
+                            const var_syntax_t *config,
                             const char_class_t nameclass,
-                            var_cb_t lookup, void* lookup_context,
+                            var_cb_value_t lookup, void* lookup_context,
                             int* start, int* step, int* stop, int* open_end)
     {
     const char* p = begin;
@@ -1830,7 +1726,7 @@
     if (begin == end)
         return 0;
 
-    if (*p != config->startdelim)
+    if (*p != config->delim_open)
         return 0;
     else
         ++p;
@@ -1870,7 +1766,7 @@
 
     if (*p != ',')
         {
-        if (*p != config->enddelim)
+        if (*p != config->delim_close)
             return VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS;
         else
             {
@@ -1907,17 +1803,17 @@
     if (failed)
         return VAR_ERR_UNDEFINED_VARIABLE;
 
-    if (*p != config->enddelim)
+    if (*p != config->delim_close)
         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,
+                      const var_syntax_t *config,
+                      const char_class_t nameclass, var_cb_value_t lookup,
                       void *lookup_context, int force_expand,
-                      tokenbuf_t *output, int current_index,
+                      tokenbuf_t *output, int index_mark,
                       size_t recursion_level, int *rel_lookup_flag)
 {
     const char *p = begin;
@@ -1939,7 +1835,7 @@
     }
 
     do {
-        if (begin != end && config->startindex && *begin == config->startindex) {
+        if (begin != end && config->index_open && *begin == config->index_open) {
             original_rel_lookup_state = *rel_lookup_flag;
             loop_limit_length = -1;
             wcon.lookup = lookup;
@@ -1963,7 +1859,7 @@
                            &wcon, 1, output, i, recursion_level+1, rel_lookup_flag);
                 if (rc < 0)
                     goto error_return;
-                if (begin[rc] != config->endindex) {
+                if (begin[rc] != config->index_close) {
                     rc = VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT;
                     goto error_return;
                 }
@@ -1998,8 +1894,8 @@
             continue;
         }
 
-        rc = text(begin, end, config->varinit, config->startindex,
-                  config->endindex, config->escape);
+        rc = text(begin, end, config->delim_init, config->index_open,
+                  config->index_close, config->escape);
         if (rc > 0) {
             if (!tokenbuf_append(output, begin, rc)) {
                 rc = VAR_ERR_OUT_OF_MEMORY;
@@ -2012,7 +1908,7 @@
 
         rc = variable(begin, end, config, nameclass, lookup,
                       lookup_context, force_expand, &result,
-                      current_index, rel_lookup_flag);
+                      index_mark, rel_lookup_flag);
         if (rc > 0) {
             if (!tokenbuf_append(output, result.begin, result.end - result.begin)) {
                 rc = VAR_ERR_OUT_OF_MEMORY;
@@ -2041,10 +1937,11 @@
     return rc;
 }
 
-var_rc_t var_expand(const char *input_buf, size_t input_len,
-                    char **result, size_t *result_len,
-                    var_cb_t lookup, void *lookup_context,
-                    const var_config_t *config, int force_expand)
+static var_rc_t internal_expand(
+    const char *input_buf, size_t input_len,
+    char **result, size_t *result_len,
+    var_cb_value_t lookup, void *lookup_context,
+    const var_syntax_t *config, int force_expand)
 {
     char_class_t nameclass;
     var_rc_t rc;
@@ -2058,21 +1955,21 @@
 
     /* Optionally use default configuration */
     if (config == NULL)
-        config = &var_config_default;
+        config = &var_syntax_default;
 
     /* Set the result pointer to the begining of the input buffer so
        that it is correctly initialized in case we fail with an error. */
     *result = (char *)input_buf;
 
     /* Expand the class description for valid variable names. */
-    if ((rc = expand_character_class(config->namechars, nameclass)) != VAR_OK)
+    if ((rc = expand_character_class(config->name_chars, nameclass)) != VAR_OK)
         return VAR_RC(rc);
 
     /* Make sure that the specials defined in the configuration do not
        appear in the character name class. */
-    if (nameclass[(int)config->varinit] ||
-        nameclass[(int)config->startdelim] ||
-        nameclass[(int)config->enddelim] ||
+    if (nameclass[(int)config->delim_init] ||
+        nameclass[(int)config->delim_open] ||
+        nameclass[(int)config->delim_close] ||
         nameclass[(int)config->escape])
         return VAR_RC(VAR_ERR_INVALID_CONFIGURATION);
 
@@ -2108,3 +2005,212 @@
     return VAR_RC(rc);
 }
 
+/* ------------------------------------------------------------------ */
+
+var_rc_t 
+var_create(
+    var_t **pvar)
+{
+    var_t *var;
+
+    if (pvar == NULL)
+        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    if ((var = (var_t *)malloc(sizeof(var_t))) == NULL)
+        return VAR_RC(VAR_ERR_OUT_OF_MEMORY);
+    memset(var, 0, sizeof(var));
+    var_config(var, VAR_CONFIG_SYNTAX, &var_syntax_default);
+    *pvar = var;
+    return VAR_OK;
+}
+
+var_rc_t 
+var_destroy(
+    var_t *var)
+{
+    if (var == NULL)
+        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    free(var);
+    return VAR_OK;
+}
+
+var_rc_t 
+var_config(
+    var_t *var, 
+    var_config_t mode, 
+    ...)
+{
+    va_list ap;
+
+    if (var == NULL)
+        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    va_start(ap, mode);
+    switch (mode) {
+        case VAR_CONFIG_SYNTAX: {
+            var_syntax_t *s;
+            s = (var_syntax_t *)va_arg(ap, void *);
+            if (s == NULL)
+                return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+            var->syntax.escape      = s->escape;
+            var->syntax.delim_init  = s->delim_init;
+            var->syntax.delim_open  = s->delim_open;
+            var->syntax.delim_close = s->delim_close;
+            var->syntax.index_open  = s->index_open;
+            var->syntax.index_close = s->index_close;
+            var->syntax.index_mark  = s->index_mark;
+            if (var->syntax.name_chars != NULL)
+                free(var->syntax.name_chars);
+            var->syntax.name_chars = strdup(s->name_chars);
+            break;
+        }
+        case VAR_CONFIG_CB_VALUE: {
+            var_cb_value_t fct;
+            void *ctx;
+            fct = (var_cb_value_t)va_arg(ap, void *);
+            ctx = (void *)va_arg(ap, void *);
+            var->cb_value_fct = fct;
+            var->cb_value_ctx = ctx;
+            break;
+        }
+        default:
+            return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    }
+    va_end(ap);
+    return VAR_OK;
+}
+
+var_rc_t 
+var_unescape(
+    var_t *var, 
+    const char *src, size_t srclen, 
+    char *dst, size_t dstlen, 
+    int all)
+{
+    const char *end;
+    var_rc_t rc;
+
+    if (var == NULL || src == NULL || dst == NULL)
+        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    end = src + srclen;
+    while (src < end) {
+        if (*src == '\\') {
+            if (++src == end)
+                return VAR_RC(VAR_ERR_INCOMPLETE_NAMED_CHARACTER);
+            switch (*src) {
+                case '\\':
+                    if (!all) {
+                        *dst++ = '\\';
+                    }
+                    *dst++ = '\\';
+                    break;
+                case 'n':
+                    *dst++ = '\n';
+                    break;
+                case 't':
+                    *dst++ = '\t';
+                    break;
+                case 'r':
+                    *dst++ = '\r';
+                    break;
+                case 'x':
+                    ++src;
+                    if ((rc = expand_hex(&src, &dst, end)) != VAR_OK)
+                        return VAR_RC(rc);
+                    break;
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                    if (   end - src >= 3 
+                        && isdigit((int)src[1]) 
+                        && isdigit((int)src[2])) {
+                        if ((rc = expand_octal(&src, &dst, end)) != 0)
+                            return VAR_RC(rc);
+                        break;
+                    }
+                default:
+                    if (!all) {
+                        *dst++ = '\\';
+                    }
+                    *dst++ = *src;
+            }
+            ++src;
+        } else
+            *dst++ = *src++;
+    }
+    *dst = '\0';
+    return VAR_OK;
+}
+
+var_rc_t 
+var_expand(
+    var_t *var, 
+    const char *src, size_t srclen, 
+    char **dst, size_t *dstlen, 
+    int force_expand)
+{
+    /* var_expand_t ctx; */
+    var_rc_t rc;
+
+    /* ctx.force_expand = force_expand; */
+    rc = internal_expand(src, srclen, dst, dstlen, 
+                         var->cb_value_fct, var->cb_value_ctx,
+                         &var->syntax, force_expand);
+    return rc;
+}
+
+var_rc_t var_strerror(var_t *var, var_rc_t rc, char **str)
+{
+    static char *errors[] = {
+        "everything ok",                                                        /* VAR_OK = 0 */
+        "incomplete named character",                                           /* VAR_ERR_INCOMPLETE_NAMED_CHARACTER */
+        "incomplete hexadecimal value",                                         /* VAR_ERR_INCOMPLETE_HEX */
+        "invalid hexadecimal value",                                            /* VAR_ERR_INVALID_HEX */
+        "octal value too large",                                                /* VAR_ERR_OCTAL_TOO_LARGE */
+        "invalid octal value",                                                  /* VAR_ERR_INVALID_OCTAL */
+        "incomplete octal value",                                               /* VAR_ERR_INCOMPLETE_OCTAL */
+        "incomplete grouped hexadecimal value",                                 /* VAR_ERR_INCOMPLETE_GROUPED_HEX */
+        "incorrect character class specification",                              /* VAR_ERR_INCORRECT_CLASS_SPEC */
+        "invalid expansion configuration",                                      /* VAR_ERR_INVALID_CONFIGURATION */
+        "out of memory",                                                        /* VAR_ERR_OUT_OF_MEMORY */
+        "incomplete variable specification",                                    /* VAR_ERR_INCOMPLETE_VARIABLE_SPEC */
+        "undefined variable",                                                   /* VAR_ERR_UNDEFINED_VARIABLE */
+        "input is neither text nor variable",                                   /* VAR_ERR_INPUT_ISNT_TEXT_NOR_VARIABLE */
+        "unknown command character in variable",                                /* VAR_ERR_UNKNOWN_COMMAND_CHAR */
+        "malformated search and replace operation",                             /* VAR_ERR_MALFORMATTED_REPLACE */
+        "unknown flag in search and replace operation",                         /* VAR_ERR_UNKNOWN_REPLACE_FLAG */
+        "invalid regular expression in search and replace operation",           /* VAR_ERR_INVALID_REGEX_IN_REPLACE */
+        "missing parameter in command",                                         /* VAR_ERR_MISSING_PARAMETER_IN_COMMAND */
+        "empty search string in search and replace operation",                  /* VAR_ERR_EMPTY_SEARCH_STRING */
+        "start offset missing in cut operation",                                /* VAR_ERR_MISSING_START_OFFSET */
+        "offsets in cut operation delimited by unknown character",              /* VAR_ERR_INVALID_OFFSET_DELIMITER */
+        "range out of bounds in cut operation",                                 /* VAR_ERR_RANGE_OUT_OF_BOUNDS */
+        "offset out of bounds in cut operation",                                /* VAR_ERR_OFFSET_OUT_OF_BOUNDS */
+        "logic error in cut operation",                                         /* VAR_ERR_OFFSET_LOGIC */
+        "malformatted transpose operation",                                     /* VAR_ERR_MALFORMATTED_TRANSPOSE */
+        "source and destination classes do not match in transpose operation",   /* VAR_ERR_TRANSPOSE_CLASSES_MISMATCH */
+        "empty character class in transpose operation",                         /* VAR_ERR_EMPTY_TRANSPOSE_CLASS */
+        "incorrect character class in transpose operation",                     /* VAR_ERR_INCORRECT_TRANSPOSE_CLASS_SPEC */
+        "malformatted padding operation",                                       /* VAR_ERR_MALFORMATTED_PADDING */
+        "width parameter missing in padding operation",                         /* VAR_ERR_MISSING_PADDING_WIDTH */
+        "fill string missing in padding operation",                             /* VAR_ERR_EMPTY_PADDING_FILL_STRING */
+        "unknown quoted pair in search and replace operation",                  /* VAR_ERR_UNKNOWN_QUOTED_PAIR_IN_REPLACE */
+        "sub-matching reference out of range",                                  /* VAR_ERR_SUBMATCH_OUT_OF_RANGE */
+        "invalid argument",                                                     /* VAR_ERR_INVALID_ARGUMENT */
+        "incomplete quoted pair",                                               /* VAR_ERR_INCOMPLETE_QUOTED_PAIR */
+        "lookup function does not support variable arrays",                     /* VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED */
+        "index specification of array variable contains an invalid character",  /* VAR_ERR_INVALID_CHAR_IN_INDEX_SPEC */
+        "index specification of array variable is incomplete",                  /* VAR_ERR_INCOMPLETE_INDEX_SPEC */
+        "bracket expression in array variable's index is not closed",           /* VAR_ERR_UNCLOSED_BRACKET_IN_INDEX */
+        "division by zero error in index specification",                        /* VAR_ERR_DIVISION_BY_ZERO_IN_INDEX */
+        "unterminated loop construct",                                          /* VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT */
+        "invalid character in loop limits"                                      /* VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS */
+    };
+
+    if (str == NULL)
+        return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
+    rc = 0 - rc;
+    if (rc < 0 || rc >= sizeof(errors) / sizeof(char *))
+        *str = "unknown error";
+    else
+        *str = errors[rc];
+    return VAR_OK;
+}
+

CVSTrac 2.0.1