]> granicus.if.org Git - ipset/commitdiff
ipset: improve command argument parsing
authorHolger Eitzenberger <holger@eitzenberger.org>
Tue, 1 Feb 2011 17:13:10 +0000 (18:13 +0100)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Tue, 1 Feb 2011 17:13:10 +0000 (18:13 +0100)
The number of comparisons for a matching a command name can be
made smaller by just checking on argv[1].

As an example consider the following 'create' arguments 'hashsize',
'family' and 'timeout'.  When having the command

 create foo hash:ip timeout 60 family inet hashsize 64

it compares without this patch:

 strcmp("timeout", "hashsize")
 strcmp("64", "hashsize")
 strcmp("family", "hashsize")
 strcmp("inet", "hashsize")
 strcmp("hashsize", "hashsize")

It is worse in practice, as 'create' has more arguments than this.

Signed-off-by: Holger Eitzenberger <holger@eitzenberger.org>
src/ipset.c

index 7dbb3033ba528a172f8ded9acc8b9c682f4ddb85..634ad9024d0a79a19a455f4a28bc16731b73b7ec 100644 (file)
@@ -206,40 +206,37 @@ restore(char *argv0)
 static int
 call_parser(int *argc, char *argv[], const struct ipset_arg *args)
 {
-       int i = 1, ret = 0;
+       int ret = 0;
        const struct ipset_arg *arg;
        const char *optstr;
        
        /* Currently CREATE and ADT may have got additional arguments */
-       if (!args)
-               goto done;
-       for (arg = args; arg->opt; arg++) {
-               for (i = 1; i < *argc; ) {
-                       D("argc: %u, i: %u: %s vs %s",
-                         *argc, i, argv[i], arg->name[0]);
-                       if (!(ipset_match_option(argv[i], arg->name))) {
-                               i++;
+       if (!args && *argc > 1)
+               goto err_unknown;
+       while (*argc > 1) {
+               for (arg = args; arg->opt; arg++) {
+                       D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
+                       if (!(ipset_match_option(argv[1], arg->name)))
                                continue;
-                       }
-                       optstr = argv[i];
+
+                       optstr = argv[1];
                        /* Shift off matched option */
                        D("match %s", arg->name[0]);
-                       ipset_shift_argv(argc, argv, i);
-                       D("argc: %u, i: %u", *argc, i);
+                       ipset_shift_argv(argc, argv, 1);
                        switch (arg->has_arg) {
                        case IPSET_MANDATORY_ARG:
-                               if (i + 1 > *argc)
+                               if (*argc < 2)
                                        return exit_error(PARAMETER_PROBLEM,
                                                "Missing mandatory argument "
                                                "of option `%s'",
                                                arg->name[0]);
                                /* Fall through */
                        case IPSET_OPTIONAL_ARG:
-                               if (i + 1 <= *argc) {
-                                       ret = ipset_call_parser(session, arg, argv[i]);
+                               if (*argc >= 2) {
+                                       ret = ipset_call_parser(session, arg, argv[1]);
                                        if (ret < 0)
                                                return ret;
-                                       ipset_shift_argv(argc, argv, i);
+                                       ipset_shift_argv(argc, argv, 1);
                                        break;
                                }
                                /* Fall through */
@@ -248,14 +245,15 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args)
                                if (ret < 0)
                                        return ret;
                        }
+                       break;
                }
+               if (!arg->opt)
+                       goto err_unknown;
        }
-done:
-       if (i < *argc)
-               return exit_error(PARAMETER_PROBLEM,
-                                 "Unknown argument: `%s'",
-                                 argv[i]);
        return ret;
+
+err_unknown:
+       return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
 }
 
 static enum ipset_adt