generator: Create a separate type for optional arguments
[libguestfs.git] / generator / generator_fish.ml
index cdf9171..175f8dc 100644 (file)
@@ -29,6 +29,13 @@ open Generator_actions
 open Generator_structs
 open Generator_prepopts
 open Generator_c
+open Generator_events
+
+let doc_opttype_of = function
+  | OBool n -> "true|false"
+  | OInt n
+  | OInt64 n -> "N"
+  | OString n -> ".."
 
 (* Generate a lot of different functions for guestfish. *)
 let generate_fish_cmds () =
@@ -56,11 +63,13 @@ let generate_fish_cmds () =
   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 "\n";
+  pr "#include <guestfs.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";
@@ -120,7 +129,9 @@ let generate_fish_cmds () =
               (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_optargt arg) (doc_opttype_of arg)
+                  ) optargs)) in
 
       let warnings =
         if List.exists (function Key _ -> true | _ -> false) args then
@@ -134,16 +145,6 @@ Guestfish will prompt for these separately."
             ("\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
@@ -172,7 +173,8 @@ Guestfish will prompt for these separately."
   ) 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";
@@ -188,7 +190,8 @@ Guestfish will prompt for these separately."
   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";
@@ -203,7 +206,8 @@ Guestfish will prompt for these separately."
   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";
@@ -223,7 +227,8 @@ Guestfish will prompt for these separately."
       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";
@@ -262,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 "  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";
@@ -283,7 +290,8 @@ Guestfish will prompt for these separately."
   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";
@@ -416,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 (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
@@ -446,15 +456,15 @@ Guestfish will prompt for these separately."
         pr "    ";
         List.iter (
           fun argt ->
-            let n = name_of_argt argt in
+            let n = name_of_optargt 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 ->
+             | OBool n ->
                  pr "      optargs_s.%s = is_true (&argv[i][%d]) ? 1 : 0;\n"
                    n (len+1);
-             | Int n ->
+             | OInt n ->
                  let range =
                    let min = "(-(2LL<<30))"
                    and max = "((2LL<<30)-1)"
@@ -464,13 +474,12 @@ Guestfish will prompt for these separately."
                  let expr = sprintf "&argv[i][%d]" (len+1) in
                  parse_integer expr "xstrtoll" "long long" "int" range
                    (sprintf "optargs_s.%s" n)
-             | Int64 n ->
+             | OInt64 n ->
                  let expr = sprintf "&argv[i][%d]" (len+1) in
                  parse_integer expr "xstrtoll" "long long" "int64_t" None
                    (sprintf "optargs_s.%s" n)
-             | String n ->
+             | OString 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;
@@ -619,6 +628,22 @@ Guestfish will prompt for these separately."
   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;
@@ -824,8 +849,8 @@ and generate_fish_actions_pod () =
       ) args;
       List.iter (
         function
-        | Bool n | Int n | Int64 n | String n -> pr " [%s:..]" n
-        | _ -> assert false
+        | (OBool n | OInt n | OInt64 n | OString n) as arg ->
+          pr " [%s:%s]" n (doc_opttype_of arg)
       ) optargs;
       pr "\n";
       pr "\n";
@@ -845,9 +870,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 DangerWillRobinson flags then
-        pr "%s\n\n" danger_will_robinson;
-
       match deprecation_notice flags with
       | None -> ()
       | Some txt -> pr "%s\n\n" txt
@@ -947,3 +969,93 @@ and generate_fish_prep_options_c () =
         name name;
   ) prepopts;
   pr "};\n"
+
+and generate_fish_event_names () =
+  generate_header CStyle GPLv2plus;
+
+  pr "\
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include \"fish.h\"
+
+const char *
+event_name_of_event_bitmask (uint64_t ev)
+{
+  switch (ev) {
+";
+
+  List.iter (
+    fun (name, _) ->
+      pr "  case GUESTFS_EVENT_%s:\n" (String.uppercase name);
+      pr "    return \"%s\";\n" name
+  ) events;
+
+  pr "  default:
+    abort (); /* should not happen */
+  }
+}
+
+void
+print_event_set (uint64_t event_bitmask, FILE *fp)
+{
+  int comma = 0;
+
+  if (event_bitmask == GUESTFS_EVENT_ALL) {
+    fputs (\"*\", fp);
+    return;
+  }
+
+";
+
+  List.iter (
+    fun (name, _) ->
+      pr "  if (event_bitmask & GUESTFS_EVENT_%s) {\n" (String.uppercase name);
+      pr "    if (comma) fputc (',', fp);\n";
+      pr "    comma = 1;\n";
+      pr "    fputs (\"%s\", fp);\n" name;
+      pr "  }\n"
+  ) events;
+
+  pr "\
+}
+
+int
+event_bitmask_of_event_set (const char *arg, uint64_t *eventset_r)
+{
+  size_t n;
+
+  if (STREQ (arg, \"*\")) {
+    *eventset_r = GUESTFS_EVENT_ALL;
+    return 0;
+  }
+
+  *eventset_r = 0;
+
+  while (*arg) {
+    n = strcspn (arg, \",\");
+
+    ";
+
+  List.iter (
+    fun (name, _) ->
+      pr "if (STREQLEN (arg, \"%s\", n))\n" name;
+      pr "      *eventset_r |= GUESTFS_EVENT_%s;\n" (String.uppercase name);
+      pr "    else ";
+  ) events;
+
+  pr "\
+{
+      fprintf (stderr, _(\"unknown event name: %%s\\n\"), arg);
+      return -1;
+    }
+
+    arg += n;
+    if (*arg == ',')
+      arg++;
+  }
+
+  return 0;
+}
+"