This patch adds support for functions with variable arity and implements a version of regexp() with flags. Currently, only the 'i' flag is supported and makes regexp() case-insensitive.<br><br><br><div class="gmail_quote">
On Wed, Aug 1, 2012 at 12:19 AM, Raphaël Pinson <span dir="ltr"><<a href="mailto:raphael.pinson@camptocamp.com" target="_blank">raphael.pinson@camptocamp.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
---<br>
 src/pathx.c |   54 +++++++++++++++++++++++++++++++++++++++++++-----------<br>
 1 file changed, 43 insertions(+), 11 deletions(-)<br>
<br>
diff --git a/src/pathx.c b/src/pathx.c<br>
index c6aa4c4..2908223 100644<br>
--- a/src/pathx.c<br>
+++ b/src/pathx.c<br>
@@ -199,6 +199,7 @@ struct expr {<br>
         char            *ident;        /* E_VAR */<br>
         struct {                       /* E_APP */<br>
             const struct func *func;<br>
+            unsigned int     arity;<br>
             struct expr       **args;<br>
         };<br>
     };<br>
@@ -283,6 +284,7 @@ static void func_position(struct state *state);<br>
 static void func_count(struct state *state);<br>
 static void func_label(struct state *state);<br>
 static void func_regexp(struct state *state);<br>
+static void func_regexp_flag(struct state *state);<br>
 static void func_glob(struct state *state);<br>
 static void func_int(struct state *state);<br>
<br>
@@ -290,6 +292,9 @@ static const enum type const arg_types_nodeset[] = { T_NODESET };<br>
 static const enum type const arg_types_string[] = { T_STRING };<br>
 static const enum type const arg_types_bool[] = { T_BOOLEAN };<br>
<br>
+static const enum type const arg_types_string_string[] = { T_STRING, T_STRING };<br>
+static const enum type const arg_types_nodeset_string[] = { T_STRING, T_STRING };<br>
+<br>
 static const struct func builtin_funcs[] = {<br>
     { .name = "last", .arity = 0, .type = T_NUMBER, .arg_types = NULL,<br>
       .impl = func_last },<br>
@@ -306,6 +311,12 @@ static const struct func builtin_funcs[] = {<br>
     { .name = "regexp", .arity = 1, .type = T_REGEXP,<br>
       .arg_types = arg_types_nodeset,<br>
       .impl = func_regexp },<br>
+    { .name = "regexp", .arity = 2, .type = T_REGEXP,<br>
+      .arg_types = arg_types_string_string,<br>
+      .impl = func_regexp_flag },<br>
+    { .name = "regexp", .arity = 2, .type = T_REGEXP,<br>
+      .arg_types = arg_types_nodeset_string,<br>
+      .impl = func_regexp_flag },<br>
     { .name = "glob", .arity = 1, .type = T_REGEXP,<br>
       .arg_types = arg_types_string,<br>
       .impl = func_glob },<br>
@@ -689,7 +700,7 @@ static void func_int(struct state *state) {<br>
 }<br>
<br>
 static struct regexp *<br>
-nodeset_as_regexp(struct info *info, struct nodeset *ns, int glob) {<br>
+nodeset_as_regexp(struct info *info, struct nodeset *ns, int glob, int nocase) {<br>
     struct regexp *result = NULL;<br>
     struct regexp **rx = NULL;<br>
     int used = 0;<br>
@@ -702,7 +713,7 @@ nodeset_as_regexp(struct info *info, struct nodeset *ns, int glob) {<br>
     if (used == 0) {<br>
         /* If the nodeset is empty, make sure we produce a regexp<br>
          * that never matches anything */<br>
-        result = make_regexp_unescape(info, "[^\001-\7ff]", 0);<br>
+        result = make_regexp_unescape(info, "[^\001-\7ff]", nocase);<br>
     } else {<br>
         if (ALLOC_N(rx, ns->used) < 0)<br>
             goto error;<br>
@@ -729,7 +740,7 @@ nodeset_as_regexp(struct info *info, struct nodeset *ns, int glob) {<br>
     return result;<br>
 }<br>
<br>
-static void func_regexp_or_glob(struct state *state, int glob) {<br>
+static void func_regexp_or_glob(struct state *state, int glob, int nocase) {<br>
     value_ind_t vind = make_value(T_REGEXP, state);<br>
     int r;<br>
<br>
@@ -742,9 +753,9 @@ static void func_regexp_or_glob(struct state *state, int glob) {<br>
         if (glob)<br>
             rx = make_regexp_from_glob(state->error->info, v->string);<br>
         else<br>
-            rx = make_regexp_unescape(state->error->info, v->string, 0);<br>
+            rx = make_regexp_unescape(state->error->info, v->string, nocase);<br>
     } else if (v->tag == T_NODESET) {<br>
-        rx = nodeset_as_regexp(state->error->info, v->nodeset, glob);<br>
+        rx = nodeset_as_regexp(state->error->info, v->nodeset, glob, nocase);<br>
     } else {<br>
         assert(0);<br>
     }<br>
@@ -767,11 +778,21 @@ static void func_regexp_or_glob(struct state *state, int glob) {<br>
 }<br>
<br>
 static void func_regexp(struct state *state) {<br>
-    func_regexp_or_glob(state, 0);<br>
+    func_regexp_or_glob(state, 0, 0);<br>
+}<br>
+<br>
+static void func_regexp_flag(struct state *state) {<br>
+    int nocase = 0;<br>
+    struct value *f = pop_value(state);<br>
+<br>
+    if (STREQ("i", f->string))<br>
+        nocase = 1;<br>
+<br>
+    func_regexp_or_glob(state, 0, nocase);<br>
 }<br>
<br>
 static void func_glob(struct state *state) {<br>
-    func_regexp_or_glob(state, 1);<br>
+    func_regexp_or_glob(state, 1, 0);<br>
 }<br>
<br>
 static bool coerce_to_bool(struct value *v) {<br>
@@ -1345,7 +1366,8 @@ static void check_app(struct expr *expr, struct state *state) {<br>
     int f;<br>
     for (f=0; f < ARRAY_CARDINALITY(builtin_funcs); f++) {<br>
         const struct func *fn = builtin_funcs + f;<br>
-        if (STRNEQ(expr->func->name, fn->name))<br>
+        if (STRNEQ(expr->func->name, fn->name) ||<br>
+           expr->arity != fn->arity)<br>
             continue;<br>
<br>
         int match = 1;<br>
@@ -1921,12 +1943,14 @@ static void parse_function_call(struct state *state) {<br>
     const struct func *func = NULL;<br>
     struct expr *expr = NULL;<br>
     int nargs = 0;<br>
+    const char *func_name = NULL;<br>
<br>
     for (int i=0; i < ARRAY_CARDINALITY(builtin_funcs); i++) {<br>
         if (looking_at(state, builtin_funcs[i].name, "("))<br>
-            func = builtin_funcs + i;<br>
+            func_name = builtin_funcs[i].name;<br>
     }<br>
-    if (func == NULL) {<br>
+<br>
+    if (func_name == NULL) {<br>
         STATE_ERROR(state, PATHX_ENAME);<br>
         return;<br>
     }<br>
@@ -1944,7 +1968,14 @@ static void parse_function_call(struct state *state) {<br>
         }<br>
     }<br>
<br>
-    if (nargs != func->arity) {<br>
+    for (int i=0; i < ARRAY_CARDINALITY(builtin_funcs); i++) {<br>
+        if (STREQ(func_name, builtin_funcs[i].name)<br>
+            && nargs == builtin_funcs[i].arity) {<br>
+            func = builtin_funcs + i;<br>
+        }<br>
+    }<br>
+<br>
+    if (func == NULL) {<br>
         STATE_ERROR(state, PATHX_EARITY);<br>
         return;<br>
     }<br>
@@ -1960,6 +1991,7 @@ static void parse_function_call(struct state *state) {<br>
         return;<br>
     }<br>
     expr->func = func;<br>
+    expr->arity = nargs;<br>
     for (int i = nargs - 1; i >= 0; i--)<br>
         expr->args[i] = pop_expr(state);<br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
1.7.9.5<br>
<br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>Raphaël Pinson<br>Administrateur Systèmes & Réseaux<br>
Camptocamp France<br>
Savoie Technolac<br>
BP 352<br>
48, avenue du Lac du Bourget<br>
73372 Le Bourget du Lac, Cedex<br>
<a href="http://www.camptocamp.com" target="_blank">www.camptocamp.com</a><br>
<br>