]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Added support for "break"
authorAlan T. DeKok <aland@freeradius.org>
Sat, 28 May 2011 15:58:09 +0000 (17:58 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 28 May 2011 16:04:34 +0000 (18:04 +0200)
man/man5/unlang.5
src/main/modcall.c

index 93b75f5c6d618d5b2ceafae9beb97bd4177ff65d..8eb54c43ea702ad894c5898799f5dbf13e12c2f9 100644 (file)
@@ -95,8 +95,12 @@ returned false, and if the specified condition evaluates to true.
 .br
 Loops over a named variable, running the block for each copy of the
 named variable.  The return value of the block is the return value of
-the last statement executed.  There is currently no way to exit the
-loop early.
+the last statement executed.  The loop can be exited early by using
+the "break" keyword.  Unlike other languages, "break" here means "exit
+the loop at the next iteration", not "exit the loop now".  The result
+is that any statements after the "break" keyword will still be
+executed.  We recommend using "break" only when it is the last
+statement in a "foreach" block.
 
 The attribute name is just the name, e.g. reply:Reply-Message, with
 none of the usual variable referenced %{...}.  This is because it is a
index 0c5168abc1d94a0be81b755e94b8a4508afb663d..0fecc7f3cf82444d71c224a1b07a83379142f959 100644 (file)
@@ -51,7 +51,7 @@ struct modcallable {
        enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
 #ifdef WITH_UNLANG
               MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
-              MOD_FOREACH,
+              MOD_FOREACH, MOD_BREAK,
 #endif
               MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
        int method;
@@ -341,6 +341,7 @@ static const char *group_name[] = {
        "switch",
        "case",
        "foreach",
+       "break",
 #endif
        "policy",
        "reference",
@@ -494,6 +495,24 @@ int modcall(int component, modcallable *c, REQUEST *request)
                        goto handle_result;
                }
 
+               if (child->type == MOD_BREAK) {
+                       int i;
+                       VALUE_PAIR **copy_p;
+
+                       for (i = 8; i >= 0; i--) {
+                               copy_p = request_data_get(request,
+                                                         radius_get_vp, i);
+                               if (copy_p) {
+                                               RDEBUG2("%.*s #  BREAK Foreach-Variable-%d", stack.pointer + 1, modcall_spaces, i);
+                                       pairfree(copy_p);
+                                       break;
+                               }
+                       }
+
+                       myresult = RLM_MODULE_NOOP;
+                       goto handle_result;
+               }
+
                if (child->type == MOD_FOREACH) {
                        int i, depth = -1;
                        VALUE_PAIR *vp;
@@ -767,10 +786,12 @@ int modcall(int component, modcallable *c, REQUEST *request)
                
                if (0) {
                handle_result:
-                       RDEBUG2("%.*s} # %s %s = %s",
-                               stack.pointer + 1, modcall_spaces,
-                               group_name[child->type], child->name ? child->name : "",
-                               fr_int2str(rcode_table, myresult, "??"));
+                       if (child->type != MOD_BREAK) {
+                               RDEBUG2("%.*s} # %s %s = %s",
+                                       stack.pointer + 1, modcall_spaces,
+                                       group_name[child->type], child->name ? child->name : "",
+                                       fr_int2str(rcode_table, myresult, "??"));
+                       }
                }
                
                /*
@@ -1605,6 +1626,21 @@ static modcallable *do_compile_modforeach(modcallable *parent,
        csingle->type = MOD_FOREACH;
        return csingle;
 }
+
+static modcallable *do_compile_modbreak(modcallable *parent, int component)
+{
+       modcallable *csingle;
+
+       component = component;  /* -Wunused */
+
+
+       csingle= do_compile_modgroup(parent, component, NULL,
+                                    GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
+       if (!csingle) return NULL;
+       csingle->name = "";
+       csingle->type = MOD_BREAK;
+       return csingle;
+}
 #endif
 
 static modcallable *do_compile_modserver(modcallable *parent,
@@ -2003,6 +2039,10 @@ static modcallable *do_compile_modsingle(modcallable *parent,
                }
        }
 
+       if (strcmp(modrefname, "break") == 0) {
+               return do_compile_modbreak(parent, component);
+       }
+
        /*
         *      Not a virtual module.  It must be a real module.
         */
@@ -2161,6 +2201,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
        g = rad_malloc(sizeof(*g));
        memset(g, 0, sizeof(*g));
        g->grouptype = grouptype;
+       g->children = NULL;
 
        c = mod_grouptocallable(g);
        c->parent = parent;
@@ -2168,6 +2209,11 @@ static modcallable *do_compile_modgroup(modcallable *parent,
        c->next = NULL;
        memset(c->actions, 0, sizeof(c->actions));
 
+       if (!cs) {              /* only for "break" */
+               c->name = "";
+               goto set_codes;
+       }
+
        /*
         *      Remember the name for printing, etc.
         *
@@ -2183,7 +2229,6 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                        c->type = MOD_POLICY;
                }
        }
-       g->children = NULL;
 
        /*
         *      Loop over the children of this group.
@@ -2254,6 +2299,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                }
        }
 
+set_codes:
        /*
         *      Set the default actions, if they haven't already been
         *      set.