ruby: Run tests one at a time, instead of in parallel.
[libguestfs.git] / src / generator.ml
index 116fb01..82f7e50 100755 (executable)
@@ -1424,9 +1424,9 @@ See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
       [["is_file"; "/known-1"]]);
     InitISOFS, Always, TestOutputFalse (
       [["is_file"; "/directory"]])],
-   "test if file exists",
+   "test if a regular file",
    "\
-This returns C<true> if and only if there is a file
+This returns C<true> if and only if there is a regular file
 with the given C<path> name.  Note that it returns false for
 other objects like directories.
 
@@ -1437,7 +1437,7 @@ See also C<guestfs_stat>.");
       [["is_dir"; "/known-3"]]);
     InitISOFS, Always, TestOutputTrue (
       [["is_dir"; "/directory"]])],
-   "test if file exists",
+   "test if a directory",
    "\
 This returns C<true> if and only if there is a directory
 with the given C<path> name.  Note that it returns false for
@@ -5341,7 +5341,7 @@ and generate_xdr () =
   generate_header CStyle LGPLv2plus;
 
   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
-  pr "typedef string str<>;\n";
+  pr "typedef string guestfs_str<>;\n";
   pr "\n";
 
   (* Internal structures. *)
@@ -5376,8 +5376,8 @@ and generate_xdr () =
              function
              | Pathname n | Device n | Dev_or_Path n | String n ->
                  pr "  string %s<>;\n" n
-             | OptString n -> pr "  str *%s;\n" n
-             | StringList n | DeviceList n -> pr "  str %s<>;\n" n
+             | OptString n -> pr "  guestfs_str *%s;\n" n
+             | StringList n | DeviceList n -> pr "  guestfs_str %s<>;\n" n
              | Bool n -> pr "  bool %s;\n" n
              | Int n -> pr "  int %s;\n" n
              | Int64 n -> pr "  hyper %s;\n" n
@@ -5407,7 +5407,7 @@ and generate_xdr () =
            pr "};\n\n"
        | RStringList n ->
            pr "struct %s_ret {\n" name;
-           pr "  str %s<>;\n" n;
+           pr "  guestfs_str %s<>;\n" n;
            pr "};\n\n"
        | RStruct (n, typ) ->
            pr "struct %s_ret {\n" name;
@@ -5419,7 +5419,7 @@ and generate_xdr () =
            pr "};\n\n"
        | RHashtable n ->
            pr "struct %s_ret {\n" name;
-           pr "  str %s<>;\n" n;
+           pr "  guestfs_str %s<>;\n" n;
            pr "};\n\n"
        | RBufferOut n ->
            pr "struct %s_ret {\n" name;
@@ -7375,7 +7375,7 @@ and generate_fish_cmds () =
   (* run_<action> actions *)
   List.iter (
     fun (name, style, _, flags, _, _, _) ->
-      pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
+      pr "static int run_%s (const char *cmd, size_t argc, char *argv[])\n" name;
       pr "{\n";
       (match fst style with
        | RErr
@@ -7560,7 +7560,7 @@ and generate_fish_cmds () =
   ) all_functions;
 
   (* run_action function *)
-  pr "int run_action (const char *cmd, int argc, char *argv[])\n";
+  pr "int run_action (const char *cmd, size_t argc, char *argv[])\n";
   pr "{\n";
   List.iter (
     fun (name, _, _, flags, _, _, _) ->
@@ -7705,7 +7705,7 @@ and generate_fish_actions_pod () =
               try Str.matched_group 1 s
               with Not_found ->
                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
-            "C<" ^ replace_char sub '_' '-' ^ ">"
+            "L</" ^ replace_char sub '_' '-' ^ ">"
         ) longdesc in
       let name = replace_char name '_' '-' in
       let alias =
@@ -8095,7 +8095,7 @@ copy_table (char * const * argv)
             pr "  char *%s = guestfs_safe_strdup (g, String_val (%sv));\n" n n
         | OptString n ->
             pr "  char *%s =\n" n;
-            pr "    %sv != Val_int (0) ?" n;
+            pr "    %sv != Val_int (0) ?\n" n;
             pr "      guestfs_safe_strdup (g, String_val (Field (%sv, 0))) : NULL;\n" n
         | StringList n | DeviceList n ->
             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
@@ -8393,133 +8393,136 @@ DESTROY (g)
           | Int64 n -> pr "      int64_t %s;\n" n
       ) (snd style);
 
-      let do_cleanups () =
-        List.iter (
-          function
-          | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
-          | Bool _ | Int _ | Int64 _
-          | FileIn _ | FileOut _ -> ()
-          | StringList n | DeviceList n -> pr "      free (%s);\n" n
-        ) (snd style)
-      in
-
-      (* Code. *)
+      (* PREINIT section (local variable declarations). *)
+      pr "PREINIT:\n";
       (match fst style with
        | RErr ->
-           pr "PREINIT:\n";
            pr "      int r;\n";
+       | RInt _
+       | RBool _ ->
+           pr "      int r;\n";
+       | RInt64 _ ->
+           pr "      int64_t r;\n";
+       | RConstString _ ->
+           pr "      const char *r;\n";
+       | RConstOptString _ ->
+           pr "      const char *r;\n";
+       | RString _ ->
+           pr "      char *r;\n";
+       | RStringList _ | RHashtable _ ->
+           pr "      char **r;\n";
+           pr "      size_t i, n;\n";
+       | RStruct (_, typ) ->
+           pr "      struct guestfs_%s *r;\n" typ;
+       | RStructList (_, typ) ->
+           pr "      struct guestfs_%s_list *r;\n" typ;
+           pr "      size_t i;\n";
+           pr "      HV *hv;\n";
+       | RBufferOut _ ->
+           pr "      char *r;\n";
+           pr "      size_t size;\n";
+      );
+
+      (* CODE or PPCODE section.  PPCODE is used where we are
+       * returning void, or where we push the return value on the stack
+       * ourselves.  Using CODE means we will manipulate RETVAL.
+       *)
+      (match fst style with
+       | RErr ->
+           pr " PPCODE:\n";
+       | RInt n
+       | RBool n ->
+           pr "   CODE:\n";
+       | RInt64 n ->
+           pr "   CODE:\n";
+       | RConstString n ->
+           pr "   CODE:\n";
+       | RConstOptString n ->
+           pr "   CODE:\n";
+       | RString n ->
+           pr "   CODE:\n";
+       | RStringList n | RHashtable n ->
+           pr " PPCODE:\n";
+       | RBufferOut n ->
+           pr "   CODE:\n";
+       | RStruct _
+       | RStructList _ ->
            pr " PPCODE:\n";
-           pr "      r = guestfs_%s " name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
+      );
+
+      (* The call to the C function. *)
+      pr "      r = guestfs_%s " name;
+      generate_c_call_args ~handle:"g" style;
+      pr ";\n";
+
+      (* Cleanup any arguments. *)
+      List.iter (
+        function
+        | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
+        | Bool _ | Int _ | Int64 _
+        | FileIn _ | FileOut _ -> ()
+        | StringList n | DeviceList n -> pr "      free (%s);\n" n
+      ) (snd style);
+
+      (* Check return value for errors and return it if necessary. *)
+      (match fst style with
+       | RErr ->
            pr "      if (r == -1)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
        | RInt n
        | RBool n ->
-           pr "PREINIT:\n";
-           pr "      int %s;\n" n;
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == -1)\n" n;
+           pr "      if (r == -1)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      RETVAL = newSViv (%s);\n" n;
+           pr "      RETVAL = newSViv (r);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
        | RInt64 n ->
-           pr "PREINIT:\n";
-           pr "      int64_t %s;\n" n;
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == -1)\n" n;
+           pr "      if (r == -1)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      RETVAL = my_newSVll (%s);\n" n;
+           pr "      RETVAL = my_newSVll (r);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
        | RConstString n ->
-           pr "PREINIT:\n";
-           pr "      const char *%s;\n" n;
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == NULL)\n" n;
+           pr "      if (r == NULL)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      RETVAL = newSVpv (%s, 0);\n" n;
+           pr "      RETVAL = newSVpv (r, 0);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
        | RConstOptString n ->
-           pr "PREINIT:\n";
-           pr "      const char *%s;\n" n;
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == NULL)\n" n;
+           pr "      if (r == NULL)\n";
            pr "        RETVAL = &PL_sv_undef;\n";
            pr "      else\n";
-           pr "        RETVAL = newSVpv (%s, 0);\n" n;
+           pr "        RETVAL = newSVpv (r, 0);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
        | RString n ->
-           pr "PREINIT:\n";
-           pr "      char *%s;\n" n;
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == NULL)\n" n;
+           pr "      if (r == NULL)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      RETVAL = newSVpv (%s, 0);\n" n;
-           pr "      free (%s);\n" n;
+           pr "      RETVAL = newSVpv (r, 0);\n";
+           pr "      free (r);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
        | RStringList n | RHashtable n ->
-           pr "PREINIT:\n";
-           pr "      char **%s;\n" n;
-           pr "      size_t i, n;\n";
-           pr " PPCODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == NULL)\n" n;
+           pr "      if (r == NULL)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
+           pr "      for (n = 0; r[n] != NULL; ++n) /**/;\n";
            pr "      EXTEND (SP, n);\n";
            pr "      for (i = 0; i < n; ++i) {\n";
-           pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
-           pr "        free (%s[i]);\n" n;
+           pr "        PUSHs (sv_2mortal (newSVpv (r[i], 0)));\n";
+           pr "        free (r[i]);\n";
            pr "      }\n";
-           pr "      free (%s);\n" n;
+           pr "      free (r);\n";
        | RStruct (n, typ) ->
            let cols = cols_of_struct typ in
-           generate_perl_struct_code typ cols name style n do_cleanups
+           generate_perl_struct_code typ cols name style n
        | RStructList (n, typ) ->
            let cols = cols_of_struct typ in
-           generate_perl_struct_list_code typ cols name style n do_cleanups
+           generate_perl_struct_list_code typ cols name style n
        | RBufferOut n ->
-           pr "PREINIT:\n";
-           pr "      char *%s;\n" n;
-           pr "      size_t size;\n";
-           pr "   CODE:\n";
-           pr "      %s = guestfs_%s " n name;
-           generate_c_call_args ~handle:"g" style;
-           pr ";\n";
-           do_cleanups ();
-           pr "      if (%s == NULL)\n" n;
+           pr "      if (r == NULL)\n";
            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-           pr "      RETVAL = newSVpvn (%s, size);\n" n;
-           pr "      free (%s);\n" n;
+           pr "      RETVAL = newSVpvn (r, size);\n";
+           pr "      free (r);\n";
            pr " OUTPUT:\n";
            pr "      RETVAL\n"
       );
@@ -8527,61 +8530,45 @@ DESTROY (g)
       pr "\n"
   ) all_functions
 
-and generate_perl_struct_list_code typ cols name style n do_cleanups =
-  pr "PREINIT:\n";
-  pr "      struct guestfs_%s_list *%s;\n" typ n;
-  pr "      size_t i;\n";
-  pr "      HV *hv;\n";
-  pr " PPCODE:\n";
-  pr "      %s = guestfs_%s " n name;
-  generate_c_call_args ~handle:"g" style;
-  pr ";\n";
-  do_cleanups ();
-  pr "      if (%s == NULL)\n" n;
+and generate_perl_struct_list_code typ cols name style n =
+  pr "      if (r == NULL)\n";
   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
-  pr "      EXTEND (SP, %s->len);\n" n;
-  pr "      for (i = 0; i < %s->len; ++i) {\n" n;
+  pr "      EXTEND (SP, r->len);\n";
+  pr "      for (i = 0; i < r->len; ++i) {\n";
   pr "        hv = newHV ();\n";
   List.iter (
     function
     | name, FString ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (r->val[i].%s, 0), 0);\n"
+          name (String.length name) name
     | name, FUUID ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (r->val[i].%s, 32), 0);\n"
+          name (String.length name) name
     | name, FBuffer ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
-          name (String.length name) n name n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (r->val[i].%s, r->val[i].%s_len), 0);\n"
+          name (String.length name) name name
     | name, (FBytes|FUInt64) ->
-        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (r->val[i].%s), 0);\n"
+          name (String.length name) name
     | name, FInt64 ->
-        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (r->val[i].%s), 0);\n"
+          name (String.length name) name
     | name, (FInt32|FUInt32) ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (r->val[i].%s), 0);\n"
+          name (String.length name) name
     | name, FChar ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&r->val[i].%s, 1), 0);\n"
+          name (String.length name) name
     | name, FOptPercent ->
-        pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
-          name (String.length name) n name
+        pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (r->val[i].%s), 0);\n"
+          name (String.length name) name
   ) cols;
   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
   pr "      }\n";
-  pr "      guestfs_free_%s_list (%s);\n" typ n
-
-and generate_perl_struct_code typ cols name style n do_cleanups =
-  pr "PREINIT:\n";
-  pr "      struct guestfs_%s *%s;\n" typ n;
-  pr " PPCODE:\n";
-  pr "      %s = guestfs_%s " n name;
-  generate_c_call_args ~handle:"g" style;
-  pr ";\n";
-  do_cleanups ();
-  pr "      if (%s == NULL)\n" n;
+  pr "      guestfs_free_%s_list (r);\n" typ
+
+and generate_perl_struct_code typ cols name style n =
+  pr "      if (r == NULL)\n";
   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
   List.iter (
@@ -8590,31 +8577,31 @@ and generate_perl_struct_code typ cols name style n do_cleanups =
 
       match col with
       | name, FString ->
-          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (newSVpv (r->%s, 0)));\n"
+            name
       | name, FBuffer ->
-          pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
-            n name n name
+          pr "      PUSHs (sv_2mortal (newSVpvn (r->%s, r->%s_len)));\n"
+            name name
       | name, FUUID ->
-          pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (newSVpv (r->%s, 32)));\n"
+            name
       | name, (FBytes|FUInt64) ->
-          pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (my_newSVull (r->%s)));\n"
+            name
       | name, FInt64 ->
-          pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (my_newSVll (r->%s)));\n"
+            name
       | name, (FInt32|FUInt32) ->
-          pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (newSVnv (r->%s)));\n"
+            name
       | name, FChar ->
-          pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (newSVpv (&r->%s, 1)));\n"
+            name
       | name, FOptPercent ->
-          pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
-            n name
+          pr "      PUSHs (sv_2mortal (newSVnv (r->%s)));\n"
+            name
   ) cols;
-  pr "      free (%s);\n" n
+  pr "      free (r);\n"
 
 (* Generate Sys/Guestfs.pm. *)
 and generate_perl_pm () =
@@ -8729,6 +8716,37 @@ sub new {
 
 =back
 
+=head1 AVAILABILITY
+
+From time to time we add new libguestfs APIs.  Also some libguestfs
+APIs won't be available in all builds of libguestfs (the Fedora
+build is full-featured, but other builds may disable features).
+How do you test whether the APIs that your Perl program needs are
+available in the version of C<Sys::Guestfs> that you are using?
+
+To test if a particular function is available in the C<Sys::Guestfs>
+class, use the ordinary Perl UNIVERSAL method C<can(METHOD)>
+(see L<perlobj(1)>).  For example:
+
+ use Sys::Guestfs;
+ if (defined (Sys::Guestfs->can (\"set_verbose\"))) {
+   print \"\\$h->set_verbose is available\\n\";
+ }
+
+To test if particular features are supported by the current
+build, use the L</available> method like the example below.  Note
+that the appliance must be launched first.
+
+ $h->available ( [\"augeas\"] );
+
+Since the L</available> method croaks if the feature is not supported,
+you might also want to wrap this in an eval and return a boolean.
+In fact this has already been done for you: use
+L<Sys::Guestfs::Lib(3)/feature_available>.
+
+For further discussion on this topic, refer to
+L<guestfs(3)/AVAILABILITY>.
+
 =head1 COPYRIGHT
 
 Copyright (C) %s Red Hat Inc.
@@ -8784,6 +8802,12 @@ and generate_python_c () =
   pr "\
 #include <Python.h>
 
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>