]> git.neil.brown.name Git - lafs-utils.git/commitdiff
Add 'choice' argument type.
authorNeilBrown <neilb@suse.de>
Sun, 13 Mar 2011 02:55:03 +0000 (13:55 +1100)
committerNeilBrown <neilb@suse.de>
Sun, 13 Mar 2011 03:03:45 +0000 (14:03 +1100)
A 'choice' must be selected from a set list of options.

Signed-off-by: NeilBrown <neilb@suse.de>
tools/lafs.c

index af8e00bde9a71ba7b5b3adbe6b6fb136401e643e..b3d83672b62666d9530f51a6b128669f61cbd966 100644 (file)
@@ -65,20 +65,21 @@ struct state {
  * types are:
  *   flag:  expect --tagname      This is either present or not.
  *   opaque:                      An uninterpreted string, often a number.
+ *   choice:                     On of a defined list of strings.
  *   external:                    An external filename - completion is possible.
  *   internal:                    An internal filename - completion might be possible.
  *   subcommand:                  one of a list of subcommands.
  * Any unique prefix of a tag is allowed to match.
  */
-enum argtype { flag, opaque, external, internal, subcommand, terminal };
+enum argtype { flag, opaque, choice, external, internal, subcommand, terminal };
 static struct args {
        char *tag;
        enum argtype type;
        int pos;
-       struct cmd *subcmd;
+       union { struct cmd *subcmd; char **options; };
        char *desc;
 } lafs_args[];
-#define TERMINAL_ARG {NULL, terminal, 0, NULL, NULL}
+#define TERMINAL_ARG {NULL, terminal, 0, {NULL}, NULL}
 
 /* When a positional parameter is identified as 'subcommand' it is associated
  * with a list of 'struct cmd' identifying the possible subcommands.
@@ -139,6 +140,17 @@ static int find_tag(struct args *args, const char *tag, int len)
        return best;
 }
 
+/* Find an option in the list, return position.
+ * No prefixing is allowed
+ */
+static int find_option(char **options, char *w)
+{
+       int i;
+       for (i = 0; options[i]; i++)
+               if (strcmp(options[i], w) == 0)
+                       return i;
+       return -1;
+}
 
 /* Return the first word on the line, modifying the line in-place and
  * updating *line to be ready to get the next word.
@@ -226,7 +238,7 @@ static void **parse_line(struct args **argsp, char *line, int *offsetp,
        rv = calloc(i+offset, sizeof(char*));
        size = i+offset;
 
-       while ((w = take_word(&line)) != NULL) {
+       while (!*error && (w = take_word(&line)) != NULL) {
                if (*w == '-') {
                        /* Find the matching tag. */
                        char *t = w, *e;
@@ -271,8 +283,17 @@ static void **parse_line(struct args **argsp, char *line, int *offsetp,
                         * parse the remaining args in the context of the
                         * given subcommand - if it exists.
                         */
-                       if (args[i].type == subcommand) {
-                               struct cmd *c = find_cmd(args[i].subcmd, w);
+                       switch(args[i].type) {
+                               struct cmd *c;
+                               int o;
+                       default: break;
+                       case choice:
+                               o = find_option(args[i].options, w);
+                               if (o < 0)
+                                       asprintf(error, "Value %s for %s is not acceptable", w, args[i].tag);
+                               break;
+                       case subcommand:
+                               c = find_cmd(args[i].subcmd, w);
                                rv[i+offset] = c;
                                if (c) {
                                        args = c->args;
@@ -289,6 +310,7 @@ static void **parse_line(struct args **argsp, char *line, int *offsetp,
                                        }
                                } else
                                        asprintf(error, "Unrecognised command: %s",w);
+                               break;
                        }
                }
        }
@@ -314,8 +336,8 @@ static int execute_line(struct state *st, char *line)
                return -1;
        }
        c = (struct cmd*)arglist[0];
-
-       c->cmd(st, arglist);
+       if (c)
+               c->cmd(st, arglist);
        free(arglist);
        return 1;
 }
@@ -466,6 +488,29 @@ static char *tag_gen(const char *prefix, int state)
        return NULL;
 }
 
+/* choice_gen is used to generate a list of possible values
+ * for a 'choice' field.
+ * 'gen_options' is the options that can go here.
+ */
+static char **gen_options;
+static char *choice_gen(const char *prefix, int state)
+{
+       static int next;
+       int len;
+
+       if (state == 0)
+               next = 0;
+
+       len = strlen(prefix);
+       for (; gen_options[next] ; next++) {
+               if (strncmp(prefix, gen_options[next], len) != 0)
+                       continue;
+               next++;
+               return strdup(gen_options[next-1]);
+       }
+       return NULL;
+}
+
 /*
  * This is the brains of the completion handler.
  * We parse the line-so-far to determine way options have already
@@ -528,6 +573,11 @@ static char **complete_in_context(const char *prefix, int start, int end)
                        matches = rl_completion_matches(
                                prefix, rl_filename_completion_function);
                        break;
+               case choice:
+                       gen_options = args[p].options;
+                       matches = rl_completion_matches(
+                               prefix, choice_gen);
+                       break;
                default:
                        break;
                }
@@ -580,8 +630,8 @@ static void c_exit(struct state *st, void **args)
 /****** HELP ******/
 static char help_help[] = "Print help for a command or all commands";
 static struct args args_help[] = {
-       { "COMMAND", subcommand, -1, lafs_cmds, "Command to display help for"},
-       { "-all", flag,      -1, NULL, "List brief help for all commands"},
+       { "COMMAND", subcommand, -1, {lafs_cmds}, "Command to display help for"},
+       { "-all", flag,      -1, {NULL}, "List brief help for all commands"},
        TERMINAL_ARG
 };
 
@@ -632,12 +682,15 @@ static void c_help(struct state *st, void **args)
 
 /****** NEWFS ******/
 static char help_newfs[] = "Create a new LaFS filesystem, which can then be stored on one or more devices.";
+static char *block_sizes[] = { "512", "1024", "2048", "4096", NULL };
 static struct args args_newfs[] = {
-       { "BLOCK-SIZE",  opaque, -1, NULL, "Block size, 512..4096, defaults to 1024"},
-       { "-block-size", opaque,  0, NULL, "Block size, 512..4096, defaults to 1024"},
-       { "-state-size", opaque, -1, NULL, "Size of state block, defaults to 1024"},
-       { "-uuid",       opaque, -1, NULL, "UUID - normally randomly generated"},
-       { "-black", opaque, -1, NULL, "nothing (just testing)"},
+       { "BLOCK-SIZE",  choice, -1, {.options=block_sizes},
+         "Block size, 512..4096, defaults to 1024"},
+       { "-block-size", choice,  0, {.options=block_sizes},
+         "Block size, 512..4096, defaults to 1024"},
+       { "-state-size", opaque, -1, {NULL}, "Size of state block, defaults to 1024"},
+       { "-uuid",       opaque, -1, {NULL}, "UUID - normally randomly generated"},
+       { "-black", opaque, -1, {NULL}, "nothing (just testing)"},
        TERMINAL_ARG
 };
 static void c_newfs(struct state *st, void **args)
@@ -649,9 +702,9 @@ static void c_newfs(struct state *st, void **args)
 /****** STORE ******/
 static char help_store[] = "Create a file in the LaFS from an external file";
 static struct args args_store[] = {
-       { "FROM", external, -1, NULL, "File to copy into LaFS"},
-       { "TO",   internal, -1, NULL, "Where to store file in LaFS"},
-       { "-from", external, 0, NULL, "File to copy into LaFS"},
+       { "FROM", external, -1, {NULL}, "File to copy into LaFS"},
+       { "TO",   internal, -1, {NULL}, "Where to store file in LaFS"},
+       { "-from", external, 0, {NULL}, "File to copy into LaFS"},
        TERMINAL_ARG
 };
 static void c_store(struct state *st, void **args)
@@ -679,6 +732,6 @@ static struct cmd lafs_cmds[] = {
 };
 
 static struct args lafs_args[] = {
-       { "COMMAND",    subcommand, -1, lafs_cmds, "Command for lafs to execute"},
+       { "COMMAND",    subcommand, -1, {lafs_cmds}, "Command for lafs to execute"},
        TERMINAL_ARG
 };