OSSP CVS Repository

ossp - Check-in [1938]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1938
Date: 2002-Mar-04 12:53:27 (local)
2002-Mar-04 11:53:27 (UTC)
User:rse
Branch:
Comment: Add new important feature: user-supplied post-operation functions. This allows one to configure a var_cb_operation_t callback in the var_t context and allow it to implement functions triggered by ${name:%func[(arg)]}. This is especially intended for application-specific encoding and post-adjustment functions.
Tickets:
Inspections:
Files:
ossp-pkg/var/TODO      1.19 -> 1.20     0 inserted, 5 deleted
ossp-pkg/var/var.c      1.75 -> 1.76     143 inserted, 8 deleted
ossp-pkg/var/var.h      1.26 -> 1.27     12 inserted, 1 deleted
ossp-pkg/var/var.pod      1.24 -> 1.25     99 inserted, 2 deleted
ossp-pkg/var/var_test.c      1.38 -> 1.39     54 inserted, 0 deleted

ossp-pkg/var/TODO 1.19 -> 1.20

--- TODO 2002/02/28 12:10:33     1.19
+++ TODO 2002/03/04 11:53:27     1.20
@@ -19,8 +19,3 @@
 
  o document exception handling
 
- o additional feature: functions via callback.
-   ${foo:F<bar>:F<quux>} calls callback for bar with result of foo
-   expansion and then callback for quux with the result returned from
-   bar.
-


ossp-pkg/var/var.c 1.75 -> 1.76

--- var.c        2002/03/04 11:37:34     1.75
+++ var.c        2002/03/04 11:53:27     1.76
@@ -72,19 +72,21 @@
 
 /* the external context structure */
 struct var_st {
-    var_syntax_t   syntax;
-    char_class_t   syntax_nameclass;
-    var_cb_value_t cb_value_fct;
-    void          *cb_value_ctx;
+    var_syntax_t         syntax;
+    char_class_t         syntax_nameclass;
+    var_cb_value_t       cb_value_fct;
+    void                *cb_value_ctx;
+    var_cb_operation_t   cb_operation_fct;
+    void                *cb_operation_ctx;
 };
 
 /* the internal expansion context structure */
 struct var_parse_st {
     struct var_parse_st *lower;
-    int force_expand;
-    int rel_lookup_flag;
-    int rel_lookup_cnt;
-    int index_this;
+    int                  force_expand;
+    int                  rel_lookup_flag;
+    int                  rel_lookup_cnt;
+    int                  index_this;
 };
 typedef struct var_parse_st var_parse_t;
 
@@ -443,6 +445,7 @@
 /* forward declarations */
 static int parse_variable(var_t *var, var_parse_t *ctx, const char *begin, const char *end, tokenbuf_t *result);
 static int parse_numexp (var_t *var, var_parse_t *ctx, const char *begin, const char *end, int *result, int *failed);
+static int parse_name   (var_t *var, var_parse_t *ctx, const char *begin, const char *end);
 
 /* parse substitution text */
 static int 
@@ -485,6 +488,71 @@
     return (p - begin);
 }
 
+/* parse opertion argument text */
+static int 
+parse_opargtext(
+    var_t *var, var_parse_t *ctx,
+    const char *begin, const char *end)
+{
+    const char *p;
+
+    /* parse until delim_init or ')' */
+    for (p = begin; p != end && *p != var->syntax.delim_init && *p != ')'; p++) {
+        if (*p == var->syntax.escape) {
+            if (p + 1 == end)
+                return VAR_ERR_INCOMPLETE_QUOTED_PAIR;
+            p++;
+        }
+    }
+    return (p - begin);
+}
+
+static int 
+parse_opargtext_or_variable(
+    var_t *var, var_parse_t *ctx,
+    const char *begin, const char *end,
+    tokenbuf_t *result)
+{
+    const char *p;
+    tokenbuf_t tmp;
+    int rc;
+
+    tokenbuf_init(result);
+    tokenbuf_init(&tmp);
+    p = begin;
+    if (p == end)
+        return 0;
+    do {
+        rc = parse_opargtext(var, ctx, p, end);
+        if (rc < 0)
+            goto error_return;
+        if (rc > 0) {
+            if (!tokenbuf_append(result, p, rc)) {
+                rc = VAR_ERR_OUT_OF_MEMORY;
+                goto error_return;
+            }
+            p += rc;
+        }
+        rc = parse_variable(var, ctx, p, end, &tmp);
+        if (rc < 0)
+            goto error_return;
+        if (rc > 0) {
+            p += rc;
+            if (!tokenbuf_merge(result, &tmp)) {
+                rc = VAR_ERR_OUT_OF_MEMORY;
+                goto error_return;
+            }
+        }
+    } while (rc > 0);
+    tokenbuf_free(&tmp);
+    return (p - begin);
+
+    error_return:
+    tokenbuf_free(&tmp);
+    tokenbuf_free(result);
+    return rc;
+}
+
 /* parse expression or variable */
 static int 
 parse_exptext_or_variable(
@@ -1314,6 +1382,62 @@
             }
             break;
         }
+        case '%': {
+            /* operation callback function */
+            const char *op_ptr;
+            size_t op_len;
+            const char *arg_ptr;
+            size_t arg_len;
+            const char *val_ptr;
+            size_t val_len;
+            const char *out_ptr;
+            size_t out_len; 
+            size_t out_size;
+            tokenbuf_t args;
+
+            p++;
+            rc = parse_name(var, ctx, p, end);
+            if (rc < 0)
+                goto error_return;
+            op_ptr = p;
+            op_len = rc;
+            p += rc;
+            if (*p == '(') {
+                p++;
+                tokenbuf_init(&args);
+                rc = parse_opargtext_or_variable(var, ctx, p, end, &args);
+                if (rc < 0)
+                    goto error_return;
+                p += rc;
+                arg_ptr = args.begin;
+                arg_len = args.end - args.begin;
+                if (*p != ')') {
+                    rc = VAR_ERR_MALFORMED_OPERATION_ARGUMENTS;
+                    goto error_return;
+                }
+                p++;
+            }
+            else {
+                arg_ptr = NULL;
+                arg_len = 0;
+            }
+            val_ptr = data->begin;
+            val_len = data->end - data->begin;
+
+            if (data->begin != NULL && var->cb_operation_fct != NULL) {
+                /* call operation callback function */
+                rc = (*var->cb_operation_fct)(var, var->cb_operation_ctx,
+                                              op_ptr, op_len,
+                                              arg_ptr, arg_len,
+                                              val_ptr, val_len,
+                                              &out_ptr, &out_len, &out_size);
+                if (rc < 0)
+                    goto error_return;
+                tokenbuf_free(data);
+                tokenbuf_set(data, out_ptr, out_ptr+out_len, out_size);
+            }
+            break;
+        }
         default:
             return VAR_ERR_UNKNOWN_COMMAND_CHAR;
     }
@@ -2141,6 +2265,15 @@
             var->cb_value_ctx = ctx;
             break;
         }
+        case VAR_CONFIG_CB_OPERATION: {
+            var_cb_operation_t fct;
+            void *ctx;
+            fct = (var_cb_operation_t)va_arg(ap, void *);
+            ctx = (void *)va_arg(ap, void *);
+            var->cb_operation_fct = fct;
+            var->cb_operation_ctx = ctx;
+            break;
+        }
         default:
             return VAR_RC(VAR_ERR_INVALID_ARGUMENT);
     }
@@ -2266,6 +2399,8 @@
 /* var_rc_t to string mapping table */
 static const char *var_errors[] = {
     "everything ok",                                           /* VAR_OK = 0 */
+    "undefined operation",                                     /* VAR_ERR_UNDEFINED_OPERATION */
+    "malformed operation argument list",                       /* VAR_ERR_MALFORMED_OPERATION_ARGUMENTS */
     "incomplete named character",                              /* VAR_ERR_INCOMPLETE_NAMED_CHARACTER */
     "incomplete hexadecimal value",                            /* VAR_ERR_INCOMPLETE_HEX */
     "invalid hexadecimal value",                               /* VAR_ERR_INVALID_HEX */


ossp-pkg/var/var.h 1.26 -> 1.27

--- var.h        2002/02/28 12:40:01     1.26
+++ var.h        2002/03/04 11:53:27     1.27
@@ -35,6 +35,8 @@
 /* Error codes */
 typedef enum {
     VAR_ERR_CALLBACK                        = -64,
+    VAR_ERR_UNDEFINED_OPERATION             = -44,
+    VAR_ERR_MALFORMED_OPERATION_ARGUMENTS   = -43,
     VAR_ERR_INVALID_CHAR_IN_LOOP_LIMITS     = -42,
     VAR_ERR_UNTERMINATED_LOOP_CONSTRUCT     = -41,
     VAR_ERR_DIVISION_BY_ZERO_IN_INDEX       = -40,
@@ -85,7 +87,8 @@
 
 typedef enum {
     VAR_CONFIG_SYNTAX,
-    VAR_CONFIG_CB_VALUE
+    VAR_CONFIG_CB_VALUE,
+    VAR_CONFIG_CB_OPERATION
 } var_config_t;
 
 typedef struct {
@@ -105,6 +108,14 @@
     const char **val_ptr, size_t *val_len, size_t *val_size
 );
 
+typedef var_rc_t (*var_cb_operation_t)(
+    var_t *var, void *ctx,
+    const char  *op_ptr, size_t op_len,
+    const char  *arg_ptr, size_t arg_len,
+    const char  *val_ptr, size_t val_len,
+    const char **out_ptr, size_t *out_len, size_t *out_size
+);
+
 extern const char var_id[];
 
 var_rc_t  var_create    (var_t **var);


ossp-pkg/var/var.pod 1.24 -> 1.25

--- var.pod      2002/02/28 14:58:07     1.24
+++ var.pod      2002/03/04 11:53:27     1.25
@@ -43,7 +43,8 @@
 B<var_t>,
 B<var_config_t>,
 B<var_syntax_t>,
-B<var_cb_value_t>.
+B<var_cb_value_t>,
+B<var_cb_operation_t>.
 
 =item Functions:
 
@@ -172,6 +173,11 @@
 of I<name> is either left justified (flag "C<l>"), centered (flag
 "C<c>"), or right justified (flag "C<r>").
 
+=item C<${>I<name>C<:%>I<func>[C<(>I<arg>C<)>]C<}>
+
+C<$>I<name> after passing it to an application-supplied function I<func>.
+The optional argument I<arg> is passed to the function, too.
+By default no such functions are defined.
 
 =item C<[>I<body>C<]>, C<[>I<body>C<]>C<{>I<start>C<,>I<step>C<,>I<end>C<}>
 
@@ -224,6 +230,8 @@
                | 'p' '/' NUMBER 
                      '/' (variable|TEXT_SUBST)* 
                      '/' ('r'|'l'|'c')
+               | '%' (name|variable)+ 
+                     ('(' (TEXT_ARGS)? ')')?
                | 'l'
                | 'u'
 
@@ -241,7 +249,8 @@
 
  NUMBER      ::= ('0'|...|'9')+
 
- TEXT_SUBST  ::= ^(DELIM_INIT|'/')
+ TEXT_SUBST  ::= (^(DELIM_INIT|'/'))+
+ TEXT_ARGS   ::= (^(DELIM_INIT|')'))+
  TEXT_EXP    ::= (^(DELIM_INIT|DELIM_CLOSE|':'))+
  TEXT        ::= (^(DELIM_INIT|INDEX_OPEN|INDEX_CLOSE))+
 
@@ -421,6 +430,94 @@
 he subtract own callback return codes from this value, i.e., return
 (C<VAR_ERR_CALLBACK> - I<n>) (I<n> E<gt>= 0) from the callback function.
 
+=item B<var_cb_operation_t>
+
+This is an exported function pointer type for variable value operation
+functions. Such a callback function B<cb> has to be of the following
+prototype:
+
+var_rc_t *B<cb>(var_t *I<var>, void *I<ctx>, const char *I<op_ptr>,
+size_t I<op_len>, const char *I<arg_ptr>, size_t I<arg_len>, const
+char *I<val_ptr>, size_t I<val_len>, const char **I<out_ptr>, size_t
+*I<out_len>, size_t *I<out_size>);
+
+This function will be called by var_expand() internally whenever a
+custom operation is used. Its parameters are:
+
+=over 4
+
+=item var_t *I<var>
+
+This is the passed-through argument as passed to var_expand() as the
+first argument. This can be used in the callback function to distinguish
+the expansion context or to resolve return codes, etc.
+
+=item void *I<ctx>
+
+This is the passed-through argument as passed to var_config() on
+C<VAR_CONFIG_CB_OPERATION> as the forth argument. This can be used
+to provide an internal context to the callback function through
+var_expand().
+
+=item const char *I<op_ptr>
+
+This is a pointer to the name of the operation which var_expand() wishes
+to perform. Please note that the string is NOT necessarily terminated
+by a C<NUL> ('C<\0>') character. If the callback function needs it
+C<NUL>-terminated, it has to copy the string into an a temporary buffer
+of its own and C<NUL>-terminate it there.
+
+=item size_t I<op_len>
+
+This is the length of the variable name at I<op_ptr>.
+
+=item const char *I<arg_ptr>
+
+This is a pointer to the optional argument string to the operation. If
+no argument string or an empty argument string was supplied this is
+C<NULL>.
+
+=item size_t I<arg_len>
+
+This is the length of the I<arg_ptr>.
+
+=item const char *I<val_ptr>
+
+This is a pointer to the value of the variable which the
+operation wants to adjust.
+
+=item size_t I<val_len>
+
+This is the length of the I<val_ptr>.
+
+=item const char **I<out_ptr>
+
+This is a pointer to the location where the callback function should
+store the pointer to the adjusted value.
+
+=item size_t *I<out_len>
+
+This is a pointer to the location where the callback function should
+store the length of the adjusted value of the variable.
+
+=item size_t *I<out_size>
+
+This is a pointer to the location where the callback function should
+store the size of the buffer that has been allocated to hold the
+adjusted value of the variable. 
+
+If no buffer has been allocated by the callback at all, because the
+variable uses some other means of storing the contents, this should be
+set to zero (C<0>).
+
+In case a buffer size greater than zero is returned by the callback,
+var_expand() will make use of that buffer internally if possible. It
+will also free(3) the buffer when it is not needed anymore, so it
+is important that it was previously allocated with malloc(3) by the
+callback.
+
+=back
+
 =back
 
 =head2 FUNCTIONS


ossp-pkg/var/var_test.c 1.38 -> 1.39

--- var_test.c   2002/02/28 20:27:05     1.38
+++ var_test.c   2002/03/04 11:53:27     1.39
@@ -30,9 +30,55 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 
 #include "var.h"
 
+static var_rc_t 
+var_operation(
+    var_t *var, void *ctx,
+    const char  *op_ptr, size_t op_len,
+    const char  *arg_ptr, size_t arg_len,
+    const char  *val_ptr, size_t val_len,
+    char **out_ptr, size_t *out_len, size_t *out_size)
+{
+    int i;
+
+    fprintf(stderr, "op=<%s>(%d) arg=<%s>(%d) val=<%s>(%d)\n", 
+            op_ptr, op_len, arg_ptr, arg_len, val_ptr, val_len);
+    if (val_ptr == NULL) {
+        *out_ptr = "";
+        *out_len = 0;
+        *out_size = 0;
+        return VAR_OK;
+    }
+    if (op_len == 6 && strncmp(op_ptr, "return", 6) == 0) {
+        *out_ptr = malloc(arg_len);
+        *out_len = arg_len;
+        *out_size = arg_len;
+        memcpy(*out_ptr, arg_ptr, arg_len);
+        return VAR_OK;
+    }
+    else if (op_len == 5 && strncmp(op_ptr, "upper", 5) == 0) {
+        *out_ptr = malloc(val_len);
+        *out_len = val_len;
+        *out_size = val_len;
+        for (i = 0; i < val_len; i++)
+            (*out_ptr)[i] = (char)toupper((int)(val_ptr[i]));
+        return VAR_OK;
+    }
+    else if (op_len == 5 && strncmp(op_ptr, "lower", 5) == 0) {
+        *out_ptr = malloc(val_len);
+        *out_len = val_len;
+        *out_size = val_len;
+        for (i = 0; i < val_len; i++)
+            (*out_ptr)[i] = (char)tolower((int)(val_ptr[i]));
+        return VAR_OK;
+    }
+    else 
+        return VAR_ERR_UNDEFINED_OPERATION;
+}
+
 struct variable {
     const char *name;
     const unsigned int idx;
@@ -177,6 +223,9 @@
         { "-[${ARRAY[#]}:]{1,$NUMBER}-",  "-entry1:entry2:-"                               },
         { "-[${ARRAY[#]}:]{1,3,5}-",      "-entry1::-"                                     },
         { "${MULTILINE:s/^/ | /g}",       " | line1\n | line2\n"                           },
+        { "${HOME:%upper}",               "/HOME/REGRESSION-TESTS"                         },
+        { "${HOME:%upper:%lower}",        "/home/regression-tests"                         },
+        { "${EMPTY:%return($HOME)}",      "/home/regression-tests"                         },
         {
         "[${ARRAY}:${ARRAY[#]}-]",
         "entry0:entry0-entry0:entry1-entry0:entry2-entry0:entry3-"
@@ -215,6 +264,11 @@
         var_strerror(NULL, rc, &err);
         printf("unable to configure variable expansion context: %s (%d)\n", err, rc);
         return 1;
+    }
+    if ((rc = var_config(var, VAR_CONFIG_CB_OPERATION, var_operation, NULL)) != VAR_OK) {
+        var_strerror(NULL, rc, &err);
+        printf("unable to configure variable expansion context: %s (%d)\n", err, rc);
+        return 1;
     }
 
     for (i = 0; i < sizeof(tests)/sizeof(struct test_case); ++i) {

CVSTrac 2.0.1