Version 1.7.6.
[libguestfs.git] / generator / generator_fish.ml
index 749c661..0c81dfc 100644 (file)
@@ -58,34 +58,29 @@ let generate_fish_cmds () =
   pr "#include \"full-write.h\"\n";
   pr "#include \"xstrtol.h\"\n";
   pr "#include \"fish.h\"\n";
   pr "#include \"full-write.h\"\n";
   pr "#include \"xstrtol.h\"\n";
   pr "#include \"fish.h\"\n";
+  pr "#include \"options.h\"\n";
+  pr "#include \"cmds_gperf.h\"\n";
   pr "\n";
   pr "/* Valid suffixes allowed for numbers.  See Gnulib xstrtol function. */\n";
   pr "static const char *xstrtol_suffixes = \"0kKMGTPEZY\";\n";
   pr "\n";
 
   pr "\n";
   pr "/* Valid suffixes allowed for numbers.  See Gnulib xstrtol function. */\n";
   pr "static const char *xstrtol_suffixes = \"0kKMGTPEZY\";\n";
   pr "\n";
 
-  (* list_commands function, which implements guestfish -h *)
-  pr "void list_commands (void)\n";
-  pr "{\n";
-  pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
-  pr "  list_builtin_commands ();\n";
   List.iter (
   List.iter (
-    fun (name, _, _, flags, _, shortdesc, _) ->
-      let name = replace_char name '_' '-' in
-      pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
-        name shortdesc
-  ) all_functions_and_fish_commands_sorted;
-  pr "  printf (\"    %%s\\n\",";
-  pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
-  pr "}\n";
-  pr "\n";
+    fun (name, _, _, _, _, _, _) ->
+      pr "static int run_%s (const char *cmd, size_t argc, char *argv[]);\n"
+        name
+  ) all_functions;
 
 
-  (* display_command function, which implements guestfish -h cmd *)
-  pr "int display_command (const char *cmd)\n";
-  pr "{\n";
+  pr "\n";
 
 
+  (* List of command_entry structs. *)
   List.iter (
   List.iter (
-    fun (name, style, _, flags, _, shortdesc, longdesc) ->
+    fun (name, _, _, flags, _, shortdesc, longdesc) ->
+      pr "struct command_entry %s_cmd_entry = {\n" name;
+
       let name2 = replace_char name '_' '-' in
       let name2 = replace_char name '_' '-' in
+      pr "  .name = \"%s\",\n" name2;
+
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
       let describe_alias =
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
       let describe_alias =
@@ -94,40 +89,40 @@ let generate_fish_cmds () =
             (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
         else "" in
 
             (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
         else "" in
 
-      pr "  if (";
-      pr "STRCASEEQ (cmd, \"%s\")" name;
-      if name <> name2 then
-        pr " || STRCASEEQ (cmd, \"%s\")" name2;
-      List.iter (
-        fun alias ->
-          pr " || STRCASEEQ (cmd, \"%s\")" alias
-      ) aliases;
-      pr ") {\n";
-      pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
-        name2 shortdesc
-        ("=head1 DESCRIPTION\n\n" ^
-         longdesc ^ describe_alias);
-      pr "    return 0;\n";
-      pr "  }\n";
-      pr "  else\n"
+      pr "  .shortdesc = \"%s\",\n" shortdesc;
+      pr "  .podbody = %S,\n"
+        ("=head1 DESCRIPTION\n\n" ^ longdesc ^ describe_alias);
+
+      pr "  .run = run_%s\n" name;
+      pr "};\n";
+      pr "\n";
   ) fish_commands;
 
   List.iter (
   ) fish_commands;
 
   List.iter (
-    fun (name, style, _, flags, _, shortdesc, longdesc) ->
+    fun (name, (_, args, optargs), _, flags, _, shortdesc, longdesc) ->
+      pr "struct command_entry %s_cmd_entry = {\n" name;
+
       let name2 = replace_char name '_' '-' in
       let name2 = replace_char name '_' '-' in
+      pr "  .name = \"%s\",\n" name2;
+
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
+
       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
       let synopsis =
       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
       let synopsis =
-        match snd style with
+        match args with
         | [] -> name2
         | args ->
             let args = List.filter (function Key _ -> false | _ -> true) args in
         | [] -> name2
         | args ->
             let args = List.filter (function Key _ -> false | _ -> true) args in
-            sprintf "%s %s"
-              name2 (String.concat " " (List.map name_of_argt args)) in
+            sprintf "%s%s%s"
+              name2
+              (String.concat ""
+                 (List.map (fun arg -> " " ^ name_of_argt arg) args))
+              (String.concat ""
+                 (List.map (fun arg -> sprintf " [%s:..]" (name_of_argt arg)) optargs)) in
 
       let warnings =
 
       let warnings =
-        if List.exists (function Key _ -> true | _ -> false) (snd style) then
+        if List.exists (function Key _ -> true | _ -> false) args then
           "\n\nThis command has one or more key or passphrase parameters.
 Guestfish will prompt for these separately."
         else "" in
           "\n\nThis command has one or more key or passphrase parameters.
 Guestfish will prompt for these separately."
         else "" in
@@ -160,25 +155,44 @@ Guestfish will prompt for these separately."
             (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
         else "" in
 
             (String.concat " or " (List.map (fun s -> "'" ^ s ^ "'") aliases))
         else "" in
 
-      pr "  if (";
-      pr "STRCASEEQ (cmd, \"%s\")" name;
-      if name <> name2 then
-        pr " || STRCASEEQ (cmd, \"%s\")" name2;
-      List.iter (
-        fun alias ->
-          pr " || STRCASEEQ (cmd, \"%s\")" alias
-      ) aliases;
-      pr ") {\n";
-      pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
-        name2 shortdesc
+      pr "  .shortdesc = \"%s\",\n" shortdesc;
+      pr "  .podbody = %S,\n"
         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
          "=head1 DESCRIPTION\n\n" ^
          longdesc ^ warnings ^ describe_alias);
         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
          "=head1 DESCRIPTION\n\n" ^
          longdesc ^ warnings ^ describe_alias);
-      pr "    return 0;\n";
-      pr "  }\n";
-      pr "  else\n"
+
+      pr "  .run = run_%s\n" name;
+      pr "};\n";
+      pr "\n";
   ) all_functions;
 
   ) all_functions;
 
+  (* list_commands function, which implements guestfish -h *)
+  pr "void list_commands (void)\n";
+  pr "{\n";
+  pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
+  pr "  list_builtin_commands ();\n";
+  List.iter (
+    fun (name, _, _, flags, _, shortdesc, _) ->
+      let name = replace_char name '_' '-' in
+      pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
+        name shortdesc
+  ) all_functions_and_fish_commands_sorted;
+  pr "  printf (\"    %%s\\n\",";
+  pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
+  pr "}\n";
+  pr "\n";
+
+  (* display_command function, which implements guestfish -h cmd *)
+  pr "int display_command (const char *cmd)\n";
+  pr "{\n";
+  pr "  const struct command_table *ct;\n";
+  pr "\n";
+  pr "  ct = lookup_fish_command (cmd, strlen (cmd));\n";
+  pr "  if (ct) {\n";
+  pr "    pod2text (ct->entry->name, ct->entry->shortdesc, ct->entry->podbody);\n";
+  pr "    return 0;\n";
+  pr "  }\n";
+  pr "  else\n";
   pr "    return display_builtin_command (cmd);\n";
   pr "}\n";
   pr "\n";
   pr "    return display_builtin_command (cmd);\n";
   pr "}\n";
   pr "\n";
@@ -274,10 +288,11 @@ Guestfish will prompt for these separately."
 
   (* run_<action> actions *)
   List.iter (
 
   (* run_<action> actions *)
   List.iter (
-    fun (name, style, _, flags, _, _, _) ->
-      pr "static int run_%s (const char *cmd, size_t argc, char *argv[])\n" name;
+    fun (name, (ret, args, optargs as style), _, flags, _, _, _) ->
+      pr "static int\n";
+      pr "run_%s (const char *cmd, size_t argc, char *argv[])\n" name;
       pr "{\n";
       pr "{\n";
-      (match fst style with
+      (match ret with
        | RErr
        | RInt _
        | RBool _ -> pr "  int r;\n"
        | RErr
        | RInt _
        | RBool _ -> pr "  int r;\n"
@@ -308,26 +323,46 @@ Guestfish will prompt for these separately."
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
         | Int64 n -> pr "  int64_t %s;\n" n
         | Bool n -> pr "  int %s;\n" n
         | Int n -> pr "  int %s;\n" n
         | Int64 n -> pr "  int64_t %s;\n" n
-      ) (snd style);
+        | Pointer _ -> assert false
+      ) args;
+
+      if optargs <> [] then (
+        pr "  struct guestfs_%s_argv optargs_s = { .bitmask = 0 };\n" name;
+        pr "  struct guestfs_%s_argv *optargs = &optargs_s;\n" name
+      );
+
+      if args <> [] || optargs <> [] then
+        pr "  size_t i = 0;\n";
+
+      pr "\n";
 
       (* Check and convert parameters. *)
 
       (* Check and convert parameters. *)
-      let argc_expected =
+      let argc_minimum, argc_maximum =
         let args_no_keys =
         let args_no_keys =
-          List.filter (function Key _ -> false | _ -> true) (snd style) in
-        List.length args_no_keys in
-      pr "  if (argc != %d) {\n" argc_expected;
-      pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
-        argc_expected;
+          List.filter (function Key _ -> false | _ -> true) args in
+        let argc_minimum = List.length args_no_keys in
+        let argc_maximum = argc_minimum + List.length optargs in
+        argc_minimum, argc_maximum in
+
+      if argc_minimum = argc_maximum then (
+        pr "  if (argc != %d) {\n" argc_minimum;
+        pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
+          argc_minimum;
+      ) else (
+        pr "  if (argc < %d || argc > %d) {\n" argc_minimum argc_maximum;
+        pr "    fprintf (stderr, _(\"%%s should have %%d-%%d parameter(s)\\n\"), cmd, %d, %d);\n"
+          argc_minimum argc_maximum;
+      );
       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
       pr "    return -1;\n";
       pr "  }\n";
 
       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
       pr "    return -1;\n";
       pr "  }\n";
 
-      let parse_integer fn fntyp rtyp range name =
+      let parse_integer expr fn fntyp rtyp range name =
         pr "  {\n";
         pr "    strtol_error xerr;\n";
         pr "    %s r;\n" fntyp;
         pr "\n";
         pr "  {\n";
         pr "    strtol_error xerr;\n";
         pr "    %s r;\n" fntyp;
         pr "\n";
-        pr "    xerr = %s (argv[i++], NULL, 0, &r, xstrtol_suffixes);\n" fn;
+        pr "    xerr = %s (%s, NULL, 0, &r, xstrtol_suffixes);\n" fn expr;
         pr "    if (xerr != LONGINT_OK) {\n";
         pr "      fprintf (stderr,\n";
         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
         pr "    if (xerr != LONGINT_OK) {\n";
         pr "      fprintf (stderr,\n";
         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
@@ -349,9 +384,6 @@ Guestfish will prompt for these separately."
         pr "  }\n";
       in
 
         pr "  }\n";
       in
 
-      if snd style <> [] then
-        pr "  size_t i = 0;\n";
-
       List.iter (
         function
         | Device name
       List.iter (
         function
         | Device name
@@ -389,13 +421,77 @@ Guestfish will prompt for these separately."
               and comment =
                 "The Int type in the generator is a signed 31 bit int." in
               Some (min, max, comment) in
               and comment =
                 "The Int type in the generator is a signed 31 bit int." in
               Some (min, max, comment) in
-            parse_integer "xstrtoll" "long long" "int" range name
+            parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
         | Int64 name ->
         | Int64 name ->
-            parse_integer "xstrtoll" "long long" "int64_t" None name
-      ) (snd style);
+            parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
+        | Pointer _ -> assert false
+      ) args;
+
+      (* Optional arguments are prefixed with <argname>:<value> and
+       * may be missing, so we need to parse those until the end of
+       * the argument list.
+       *)
+      if optargs <> [] then (
+        let uc_name = String.uppercase name in
+        pr "\n";
+        pr "  for (; i < argc; ++i) {\n";
+        pr "    uint64_t this_mask;\n";
+        pr "    const char *this_arg;\n";
+        pr "\n";
+        pr "    ";
+        List.iter (
+          fun argt ->
+            let n = name_of_argt argt in
+            let uc_n = String.uppercase n in
+            let len = String.length n in
+            pr "if (STRPREFIX (argv[i], \"%s:\")) {\n" n;
+            (match argt with
+             | Bool n ->
+                 pr "      optargs_s.%s = is_true (&argv[i][%d]) ? 1 : 0;\n"
+                   n (len+1);
+             | Int n ->
+                 let range =
+                   let min = "(-(2LL<<30))"
+                   and max = "((2LL<<30)-1)"
+                   and comment =
+                     "The Int type in the generator is a signed 31 bit int." in
+                   Some (min, max, comment) in
+                 let expr = sprintf "&argv[i][%d]" (len+1) in
+                 parse_integer expr "xstrtoll" "long long" "int" range name
+             | Int64 n ->
+                 let expr = sprintf "&argv[i][%d]" (len+1) in
+                 parse_integer expr "xstrtoll" "long long" "int64_t" None name
+             | String n ->
+                 pr "      optargs_s.%s = &argv[i][%d];\n" n (len+1);
+             | _ -> assert false
+            );
+            pr "      this_mask = GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n;
+            pr "      this_arg = \"%s\";\n" n;
+            pr "    }\n";
+            pr "    else ";
+        ) optargs;
+
+        pr "{\n";
+        pr "      fprintf (stderr, _(\"%%s: unknown optional argument \\\"%%s\\\"\\n\"),\n";
+        pr "               cmd, argv[i]);\n";
+        pr "      return -1;\n";
+        pr "    }\n";
+        pr "\n";
+        pr "    if (optargs_s.bitmask & this_mask) {\n";
+        pr "      fprintf (stderr, _(\"%%s: optional argument \\\"%%s\\\" given twice\\n\"),\n";
+        pr "               cmd, this_arg);\n";
+        pr "      return -1;\n";
+        pr "    }\n";
+        pr "    optargs_s.bitmask |= this_mask;\n";
+        pr "  }\n";
+        pr "\n";
+      );
 
       (* Call C API function. *)
 
       (* Call C API function. *)
-      pr "  r = guestfs_%s " name;
+      if optargs = [] then
+        pr "  r = guestfs_%s " name
+      else
+        pr "  r = guestfs_%s_argv " name;
       generate_c_call_args ~handle:"g" style;
       pr ";\n";
 
       generate_c_call_args ~handle:"g" style;
       pr ";\n";
 
@@ -412,7 +508,8 @@ Guestfish will prompt for these separately."
             pr "  free_file_in (%s);\n" name
         | StringList name | DeviceList name ->
             pr "  free_strings (%s);\n" name
             pr "  free_file_in (%s);\n" name
         | StringList name | DeviceList name ->
             pr "  free_strings (%s);\n" name
-      ) (snd style);
+        | Pointer _ -> assert false
+      ) args;
 
       (* Any output flags? *)
       let fish_output =
 
       (* Any output flags? *)
       let fish_output =
@@ -426,7 +523,7 @@ Guestfish will prompt for these separately."
             failwithf "%s: more than one FishOutput flag is not allowed" name in
 
       (* Check return value for errors and display command results. *)
             failwithf "%s: more than one FishOutput flag is not allowed" name in
 
       (* Check return value for errors and display command results. *)
-      (match fst style with
+      (match ret with
        | RErr -> pr "  return r;\n"
        | RInt _ ->
            pr "  if (r == -1) return -1;\n";
        | RErr -> pr "  return r;\n"
        | RInt _ ->
            pr "  if (r == -1) return -1;\n";
@@ -499,36 +596,84 @@ Guestfish will prompt for these separately."
   ) all_functions;
 
   (* run_action function *)
   ) all_functions;
 
   (* run_action function *)
-  pr "int run_action (const char *cmd, size_t argc, char *argv[])\n";
+  pr "int\n";
+  pr "run_action (const char *cmd, size_t argc, char *argv[])\n";
   pr "{\n";
   pr "{\n";
+  pr "  const struct command_table *ct;\n";
+  pr "\n";
+  pr "  ct = lookup_fish_command (cmd, strlen (cmd));\n";
+  pr "  if (ct)\n";
+  pr "    return ct->entry->run (cmd, argc, argv);\n";
+  pr "  else {\n";
+  pr "    fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
+  pr "    if (command_num == 1)\n";
+  pr "      extended_help_message ();\n";
+  pr "    return -1;\n";
+  pr "  }\n";
+  pr "}\n"
+
+(* gperf code to do fast lookups of commands. *)
+and generate_fish_cmds_gperf () =
+  generate_header CStyle GPLv2plus;
+
+  let all_functions_sorted =
+    List.filter (
+      fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
+    ) all_functions_sorted in
+
+  let all_functions_and_fish_commands_sorted =
+    List.sort action_compare (all_functions_sorted @ fish_commands) in
+
+  pr "\
+%%language=ANSI-C
+%%define lookup-function-name lookup_fish_command
+%%ignore-case
+%%readonly-tables
+%%null-strings
+
+%%{
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include \"cmds_gperf.h\"
+
+";
+
+  List.iter (
+    fun (name, _, _, _, _, _, _) ->
+      pr "extern struct command_entry %s_cmd_entry;\n" name
+  ) all_functions_and_fish_commands_sorted;
+
+  pr "\
+%%}
+
+struct command_table;
+
+%%%%
+";
 
   List.iter (
     fun (name, _, _, flags, _, _, _) ->
       let name2 = replace_char name '_' '-' in
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
 
   List.iter (
     fun (name, _, _, flags, _, _, _) ->
       let name2 = replace_char name '_' '-' in
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
-      pr "  if (";
-      pr "STRCASEEQ (cmd, \"%s\")" name;
+
+      (* The basic command. *)
+      pr "%s, &%s_cmd_entry\n" name name;
+
+      (* Command with dashes instead of underscores. *)
       if name <> name2 then
       if name <> name2 then
-        pr " || STRCASEEQ (cmd, \"%s\")" name2;
+        pr "%s, &%s_cmd_entry\n" name2 name;
+
+      (* Aliases for the command. *)
       List.iter (
         fun alias ->
       List.iter (
         fun alias ->
-          pr " || STRCASEEQ (cmd, \"%s\")" alias;
+          pr "%s, &%s_cmd_entry\n" alias name;
       ) aliases;
       ) aliases;
-      pr ")\n";
-      pr "    return run_%s (cmd, argc, argv);\n" name;
-      pr "  else\n";
-  ) all_functions_and_fish_commands_sorted;
-
-  pr "    {\n";
-  pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
-  pr "      if (command_num == 1)\n";
-  pr "        extended_help_message ();\n";
-  pr "      return -1;\n";
-  pr "    }\n";
-  pr "  return 0;\n";
-  pr "}\n";
-  pr "\n"
+  ) all_functions_and_fish_commands_sorted
 
 (* Readline completion for guestfish. *)
 and generate_fish_completion () =
 
 (* Readline completion for guestfish. *)
 and generate_fish_completion () =
@@ -637,7 +782,7 @@ and generate_fish_actions_pod () =
   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
 
   List.iter (
   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
 
   List.iter (
-    fun (name, style, _, flags, _, _, longdesc) ->
+    fun (name, (_, args, optargs), _, flags, _, _, longdesc) ->
       let longdesc =
         Str.global_substitute rex (
           fun s ->
       let longdesc =
         Str.global_substitute rex (
           fun s ->
@@ -668,19 +813,28 @@ and generate_fish_actions_pod () =
         | FileIn n | FileOut n -> pr " (%s|-)" n
         | BufferIn n -> pr " %s" n
         | Key _ -> () (* keys are entered at a prompt *)
         | FileIn n | FileOut n -> pr " (%s|-)" n
         | BufferIn n -> pr " %s" n
         | Key _ -> () (* keys are entered at a prompt *)
-      ) (snd style);
+        | Pointer _ -> assert false
+      ) args;
+      List.iter (
+        function
+        | Bool n | Int n | Int64 n | String n -> pr " [%s:..]" n
+        | _ -> assert false
+      ) optargs;
       pr "\n";
       pr "\n";
       pr "%s\n\n" longdesc;
 
       if List.exists (function FileIn _ | FileOut _ -> true
       pr "\n";
       pr "\n";
       pr "%s\n\n" longdesc;
 
       if List.exists (function FileIn _ | FileOut _ -> true
-                      | _ -> false) (snd style) then
+                      | _ -> false) args then
         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
 
         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
 
-      if List.exists (function Key _ -> true | _ -> false) (snd style) then
+      if List.exists (function Key _ -> true | _ -> false) args then
         pr "This command has one or more key or passphrase parameters.
 Guestfish will prompt for these separately.\n\n";
 
         pr "This command has one or more key or passphrase parameters.
 Guestfish will prompt for these separately.\n\n";
 
+      if optargs <> [] then
+        pr "This command has one or more optional arguments.  See L</OPTIONAL ARGUMENTS>.\n\n";
+
       if List.mem ProtocolLimitWarning flags then
         pr "%s\n\n" protocol_limit_warning;
 
       if List.mem ProtocolLimitWarning flags then
         pr "%s\n\n" protocol_limit_warning;
 
@@ -695,7 +849,7 @@ Guestfish will prompt for these separately.\n\n";
 (* Generate documentation for guestfish-only commands. *)
 and generate_fish_commands_pod () =
   List.iter (
 (* Generate documentation for guestfish-only commands. *)
 and generate_fish_commands_pod () =
   List.iter (
-    fun (name, style, _, flags, _, _, longdesc) ->
+    fun (name, _, _, flags, _, _, longdesc) ->
       let name = replace_char name '_' '-' in
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
       let name = replace_char name '_' '-' in
       let aliases =
         filter_map (function FishAlias n -> Some n | _ -> None) flags in
@@ -755,6 +909,8 @@ and generate_fish_prep_options_c () =
   generate_header CStyle GPLv2plus;
 
   pr "\
   generate_header CStyle GPLv2plus;
 
   pr "\
+#include <stdio.h>
+
 #include \"fish.h\"
 #include \"prepopts.h\"
 
 #include \"fish.h\"
 #include \"prepopts.h\"