Don't rely on implicit promotion of float to double in printf args.
[libguestfs.git] / generator / generator_fish.ml
index 76b4c7a..3d52421 100644 (file)
@@ -30,6 +30,13 @@ open Generator_structs
 open Generator_prepopts
 open Generator_c
 
 open Generator_prepopts
 open Generator_c
 
+let doc_opttype_of = function
+  | Bool n -> "true|false"
+  | Int n
+  | Int64 n -> "N"
+  | String n -> ".."
+  | _ -> assert false
+
 (* Generate a lot of different functions for guestfish. *)
 let generate_fish_cmds () =
   generate_header CStyle GPLv2plus;
 (* Generate a lot of different functions for guestfish. *)
 let generate_fish_cmds () =
   generate_header CStyle GPLv2plus;
@@ -48,16 +55,21 @@ let generate_fish_cmds () =
 
   pr "#include <config.h>\n";
   pr "\n";
 
   pr "#include <config.h>\n";
   pr "\n";
+  pr "/* It is safe to call deprecated functions from this file. */\n";
+  pr "#undef GUESTFS_WARN_DEPRECATED\n";
+  pr "\n";
   pr "#include <stdio.h>\n";
   pr "#include <stdlib.h>\n";
   pr "#include <string.h>\n";
   pr "#include <inttypes.h>\n";
   pr "\n";
   pr "#include <stdio.h>\n";
   pr "#include <stdlib.h>\n";
   pr "#include <string.h>\n";
   pr "#include <inttypes.h>\n";
   pr "\n";
-  pr "#include <guestfs.h>\n";
   pr "#include \"c-ctype.h\"\n";
   pr "#include \"full-write.h\"\n";
   pr "#include \"xstrtol.h\"\n";
   pr "#include \"c-ctype.h\"\n";
   pr "#include \"full-write.h\"\n";
   pr "#include \"xstrtol.h\"\n";
+  pr "\n";
+  pr "#include <guestfs.h>\n";
   pr "#include \"fish.h\"\n";
   pr "#include \"fish.h\"\n";
+  pr "#include \"fish-cmds.h\"\n";
   pr "#include \"options.h\"\n";
   pr "#include \"cmds_gperf.h\"\n";
   pr "\n";
   pr "#include \"options.h\"\n";
   pr "#include \"cmds_gperf.h\"\n";
   pr "\n";
@@ -76,11 +88,7 @@ let generate_fish_cmds () =
   (* List of command_entry structs. *)
   List.iter (
     fun (name, _, _, flags, _, shortdesc, longdesc) ->
   (* List of command_entry structs. *)
   List.iter (
     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 =
@@ -89,10 +97,16 @@ 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 "  .shortdesc = \"%s\",\n" shortdesc;
-      pr "  .podbody = %S,\n"
-        ("=head1 DESCRIPTION\n\n" ^ longdesc ^ describe_alias);
+      let pod =
+        sprintf "%s - %s\n\n=head1 DESCRIPTION\n\n%s\n\n%s"
+          name2 shortdesc longdesc describe_alias in
+      let text =
+        String.concat "\n" (pod2text ~trim:false ~discard:false "NAME" pod)
+        ^ "\n" in
 
 
+      pr "struct command_entry %s_cmd_entry = {\n" name;
+      pr "  .name = \"%s\",\n" name2;
+      pr "  .help = \"%s\",\n" (c_quote text);
       pr "  .run = run_%s\n" name;
       pr "};\n";
       pr "\n";
       pr "  .run = run_%s\n" name;
       pr "};\n";
       pr "\n";
@@ -100,11 +114,7 @@ let generate_fish_cmds () =
 
   List.iter (
     fun (name, (_, args, optargs), _, flags, _, shortdesc, longdesc) ->
 
   List.iter (
     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
 
@@ -119,7 +129,9 @@ let generate_fish_cmds () =
               (String.concat ""
                  (List.map (fun arg -> " " ^ name_of_argt arg) args))
               (String.concat ""
               (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
+                 (List.map (fun arg ->
+                   sprintf " [%s:%s]" (name_of_argt arg) (doc_opttype_of arg)
+                  ) optargs)) in
 
       let warnings =
         if List.exists (function Key _ -> true | _ -> false) args then
 
       let warnings =
         if List.exists (function Key _ -> true | _ -> false) args then
@@ -133,16 +145,6 @@ Guestfish will prompt for these separately."
             ("\n\n" ^ protocol_limit_warning)
           else "" in
 
             ("\n\n" ^ protocol_limit_warning)
           else "" in
 
-      (* For DangerWillRobinson commands, we should probably have
-       * guestfish prompt before allowing you to use them (especially
-       * in interactive mode). XXX
-       *)
-      let warnings =
-        warnings ^
-          if List.mem DangerWillRobinson flags then
-            ("\n\n" ^ danger_will_robinson)
-          else "" in
-
       let warnings =
         warnings ^
           match deprecation_notice flags with
       let warnings =
         warnings ^
           match deprecation_notice flags with
@@ -155,19 +157,24 @@ 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 "  .shortdesc = \"%s\",\n" shortdesc;
-      pr "  .podbody = %S,\n"
-        ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
-         "=head1 DESCRIPTION\n\n" ^
-         longdesc ^ warnings ^ describe_alias);
+      let pod =
+        sprintf "%s - %s\n\n=head1 SYNOPSIS\n\n %s\n\n=head1 DESCRIPTION\n\n%s%s%s"
+          name2 shortdesc synopsis longdesc warnings describe_alias in
+      let text =
+        String.concat "\n" (pod2text ~trim:false ~discard:false "NAME" pod)
+        ^ "\n" in
 
 
+      pr "struct command_entry %s_cmd_entry = {\n" name;
+      pr "  .name = \"%s\",\n" name2;
+      pr "  .help = \"%s\",\n" (c_quote text);
       pr "  .run = run_%s\n" name;
       pr "};\n";
       pr "\n";
   ) all_functions;
 
   (* list_commands function, which implements guestfish -h *)
       pr "  .run = run_%s\n" name;
       pr "};\n";
       pr "\n";
   ) all_functions;
 
   (* list_commands function, which implements guestfish -h *)
-  pr "void list_commands (void)\n";
+  pr "void\n";
+  pr "list_commands (void)\n";
   pr "{\n";
   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
   pr "  list_builtin_commands ();\n";
   pr "{\n";
   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
   pr "  list_builtin_commands ();\n";
@@ -183,13 +190,14 @@ Guestfish will prompt for these separately."
   pr "\n";
 
   (* display_command function, which implements guestfish -h cmd *)
   pr "\n";
 
   (* display_command function, which implements guestfish -h cmd *)
-  pr "int display_command (const char *cmd)\n";
+  pr "int\n";
+  pr "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 "{\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 "    fputs (ct->entry->help, stdout);\n";
   pr "    return 0;\n";
   pr "  }\n";
   pr "  else\n";
   pr "    return 0;\n";
   pr "  }\n";
   pr "  else\n";
@@ -198,7 +206,8 @@ Guestfish will prompt for these separately."
   pr "\n";
 
   let emit_print_list_function typ =
   pr "\n";
 
   let emit_print_list_function typ =
-    pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
+    pr "static void\n";
+    pr "print_%s_list (struct guestfs_%s_list *%ss)\n"
       typ typ typ;
     pr "{\n";
     pr "  unsigned int i;\n";
       typ typ typ;
     pr "{\n";
     pr "  unsigned int i;\n";
@@ -218,7 +227,8 @@ Guestfish will prompt for these separately."
       let needs_i =
         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
 
       let needs_i =
         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
 
-      pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
+      pr "static void\n";
+      pr "print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
       pr "{\n";
       if needs_i then (
         pr "  unsigned int i;\n";
       pr "{\n";
       if needs_i then (
         pr "  unsigned int i;\n";
@@ -257,9 +267,11 @@ Guestfish will prompt for these separately."
             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
               name typ name
         | name, FOptPercent ->
             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
               name typ name
         | name, FOptPercent ->
-            pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
-              typ name name typ name;
-            pr "  else printf (\"%%s%s: \\n\", indent);\n" name
+            pr "  if (%s->%s >= 0)\n" typ name;
+            pr "    printf (\"%%s%s: %%g %%%%\\n\", indent, (double) %s->%s);\n"
+              name typ name;
+            pr "  else\n";
+            pr "    printf (\"%%s%s: \\n\", indent);\n" name
       ) cols;
       pr "}\n";
       pr "\n";
       ) cols;
       pr "}\n";
       pr "\n";
@@ -278,7 +290,8 @@ Guestfish will prompt for these separately."
   List.iter (
     function
     | typ, (RStructOnly | RStructAndList) ->
   List.iter (
     function
     | typ, (RStructOnly | RStructAndList) ->
-        pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
+        pr "static void\n";
+        pr "print_%s (struct guestfs_%s *%s)\n" typ typ typ;
         pr "{\n";
         pr "  print_%s_indent (%s, \"\");\n" typ typ;
         pr "}\n";
         pr "{\n";
         pr "  print_%s_indent (%s, \"\");\n" typ typ;
         pr "}\n";
@@ -323,6 +336,7 @@ 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
+        | Pointer _ -> assert false
       ) args;
 
       if optargs <> [] then (
       ) args;
 
       if optargs <> [] then (
@@ -390,7 +404,7 @@ Guestfish will prompt for these separately."
             pr "  %s = argv[i++];\n" name
         | Pathname name
         | Dev_or_Path name ->
             pr "  %s = argv[i++];\n" name
         | Pathname name
         | Dev_or_Path name ->
-            pr "  %s = resolve_win_path (argv[i++]);\n" name;
+            pr "  %s = win_prefix (argv[i++]); /* process \"win:\" prefix */\n" name;
             pr "  if (%s == NULL) return -1;\n" name
         | OptString name ->
             pr "  %s = STRNEQ (argv[i], \"\") ? argv[i] : NULL;\n" name;
             pr "  if (%s == NULL) return -1;\n" name
         | OptString name ->
             pr "  %s = STRNEQ (argv[i], \"\") ? argv[i] : NULL;\n" name;
@@ -410,6 +424,8 @@ Guestfish will prompt for these separately."
             pr "  if (%s == NULL) return -1;\n" name
         | Key name ->
             pr "  %s = read_key (\"%s\");\n" name name;
             pr "  if (%s == NULL) return -1;\n" name
         | Key name ->
             pr "  %s = read_key (\"%s\");\n" name name;
+            pr "  if (keys_from_stdin)\n";
+            pr "    input_lineno++;\n";
             pr "  if (%s == NULL) return -1;\n" name
         | Bool name ->
             pr "  %s = is_true (argv[i++]) ? 1 : 0;\n" name
             pr "  if (%s == NULL) return -1;\n" name
         | Bool name ->
             pr "  %s = is_true (argv[i++]) ? 1 : 0;\n" name
@@ -423,6 +439,7 @@ Guestfish will prompt for these separately."
             parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
         | Int64 name ->
             parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
             parse_integer "argv[i++]" "xstrtoll" "long long" "int" range name
         | Int64 name ->
             parse_integer "argv[i++]" "xstrtoll" "long long" "int64_t" None name
+        | Pointer _ -> assert false
       ) args;
 
       (* Optional arguments are prefixed with <argname>:<value> and
       ) args;
 
       (* Optional arguments are prefixed with <argname>:<value> and
@@ -455,10 +472,12 @@ Guestfish will prompt for these separately."
                      "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
                      "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
+                 parse_integer expr "xstrtoll" "long long" "int" range
+                   (sprintf "optargs_s.%s" n)
              | Int64 n ->
                  let expr = sprintf "&argv[i][%d]" (len+1) in
              | Int64 n ->
                  let expr = sprintf "&argv[i][%d]" (len+1) in
-                 parse_integer expr "xstrtoll" "long long" "int64_t" None name
+                 parse_integer expr "xstrtoll" "long long" "int64_t" None
+                   (sprintf "optargs_s.%s" n)
              | String n ->
                  pr "      optargs_s.%s = &argv[i][%d];\n" n (len+1);
              | _ -> assert false
              | String n ->
                  pr "      optargs_s.%s = &argv[i][%d];\n" n (len+1);
              | _ -> assert false
@@ -506,6 +525,7 @@ 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
+        | Pointer _ -> assert false
       ) args;
 
       (* Any output flags? *)
       ) args;
 
       (* Any output flags? *)
@@ -609,6 +629,22 @@ Guestfish will prompt for these separately."
   pr "  }\n";
   pr "}\n"
 
   pr "  }\n";
   pr "}\n"
 
+and generate_fish_cmds_h () =
+  generate_header CStyle GPLv2plus;
+
+  pr "#ifndef FISH_CMDS_H\n";
+  pr "#define FISH_CMDS_H\n";
+  pr "\n";
+
+  List.iter (
+    fun (shortname, _, _, _, _, _, _) ->
+      pr "extern int run_%s (const char *cmd, size_t argc, char *argv[]);\n"
+        shortname
+  ) fish_commands;
+
+  pr "\n";
+  pr "#endif /* FISH_CMDS_H */\n"
+
 (* gperf code to do fast lookups of commands. *)
 and generate_fish_cmds_gperf () =
   generate_header CStyle GPLv2plus;
 (* gperf code to do fast lookups of commands. *)
 and generate_fish_cmds_gperf () =
   generate_header CStyle GPLv2plus;
@@ -810,10 +846,12 @@ 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 *)
+        | Pointer _ -> assert false
       ) args;
       List.iter (
         function
       ) args;
       List.iter (
         function
-        | Bool n | Int n | Int64 n | String n -> pr " [%s:..]" n
+        | (Bool n | Int n | Int64 n | String n) as arg ->
+          pr " [%s:%s]" n (doc_opttype_of arg)
         | _ -> assert false
       ) optargs;
       pr "\n";
         | _ -> assert false
       ) optargs;
       pr "\n";
@@ -834,9 +872,6 @@ Guestfish will prompt for these separately.\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;
 
-      if List.mem DangerWillRobinson flags then
-        pr "%s\n\n" danger_will_robinson;
-
       match deprecation_notice flags with
       | None -> ()
       | Some txt -> pr "%s\n\n" txt
       match deprecation_notice flags with
       | None -> ()
       | Some txt -> pr "%s\n\n" txt
@@ -905,6 +940,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\"