diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 7db88ceac..f370b7957 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -83,7 +83,8 @@ This is an internal test function which is used to test whether the automatically generated bindings can handle every possible parameter type correctly. -It echos the contents of each parameter to stdout. +It echos the contents of each parameter to stdout (by default) +or to a file (if C was called). You probably don't want to call this function." } ] @ List.flatten ( @@ -125,6 +126,35 @@ You probably don't want to call this function." } *) let non_daemon_functions = test_functions @ [ + { defaults with + name = "internal_test_set_output"; + style = RErr, [String "filename"], []; + in_fish = false; in_docs = false; + shortdesc = "internal test function - do not use"; + longdesc = "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +parameter type correctly. + +It sets the output file used by C. + +You probably don't want to call this function." }; + + { defaults with + name = "internal_test_close_output"; + style = RErr, [], []; + in_fish = false; in_docs = false; + shortdesc = "internal test function - do not use"; + longdesc = "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +parameter type correctly. + +It closes the output file previously opened by +C. + +You probably don't want to call this function." }; + { defaults with name = "launch"; style = RErr, [], []; diff --git a/generator/generator_bindtests.ml b/generator/generator_bindtests.ml index 67a5bbac4..aaadd370b 100644 --- a/generator/generator_bindtests.ml +++ b/generator/generator_bindtests.ml @@ -45,20 +45,68 @@ let rec generate_bindtests () = #include \"guestfs-internal-actions.h\" #include \"guestfs_protocol.h\" -static void -print_strings (char *const *argv) +int +guestfs__internal_test_set_output (guestfs_h *g, const char *filename) { - size_t argc; + FILE *fp; - printf (\"[\"); - for (argc = 0; argv[argc] != NULL; ++argc) { - if (argc > 0) printf (\", \"); - printf (\"\\\"%%s\\\"\", argv[argc]); + fp = fopen (filename, \"w\"); + if (fp == NULL) { + perrorf (g, \"cannot open output file %%s\\n\", filename); + return -1; } - printf (\"]\\n\"); + + if (guestfs_internal_test_close_output (g) == -1) { + fclose (fp); + return -1; + } + + g->test_fp = fp; + + return 0; } -/* The internal_test function prints its parameters to stdout. */ +int +guestfs__internal_test_close_output (guestfs_h *g) +{ + if (g->test_fp != NULL) { + if (fclose (g->test_fp) == EOF) { + perrorf (g, \"fclose\"); + g->test_fp = NULL; + return -1; + } + g->test_fp = NULL; + } + + return 0; +} + +static inline FILE * +get_fp (guestfs_h *g) +{ + if (g->test_fp) + return g->test_fp; + else + return stdout; +} + +static void +print_strings (guestfs_h *g, char *const *argv) +{ + FILE *fp = get_fp (g); + size_t argc; + + fprintf (fp, \"[\"); + for (argc = 0; argv[argc] != NULL; ++argc) { + if (argc > 0) fprintf (fp, \", \"); + fprintf (fp, \"\\\"%%s\\\"\", argv[argc]); + } + fprintf (fp, \"]\\n\"); +} + +/* The internal_test function prints its parameters to stdout or the + * file set by internal_test_set_output. + */ "; let test, tests = @@ -71,6 +119,9 @@ print_strings (char *const *argv) generate_prototype ~extern:false ~semicolon:false ~newline:true ~handle:"g" ~prefix:"guestfs__" ~optarg_proto:Argv name style; pr "{\n"; + pr " FILE *fp = get_fp (g);\n"; + pr "\n"; + List.iter ( function | Pathname n @@ -78,28 +129,29 @@ print_strings (char *const *argv) | String n | FileIn n | FileOut n - | Key n -> pr " printf (\"%%s\\n\", %s);\n" n + | Key n -> pr " fprintf (fp, \"%%s\\n\", %s);\n" n | BufferIn n -> pr " {\n"; pr " size_t i;\n"; pr " for (i = 0; i < %s_size; ++i)\n" n; - pr " printf (\"<%%02x>\", %s[i]);\n" n; - pr " printf (\"\\n\");\n"; + pr " fprintf (fp, \"<%%02x>\", %s[i]);\n" n; + pr " fprintf (fp, \"\\n\");\n"; pr " }\n"; - | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n - | StringList n | DeviceList n -> pr " print_strings (%s);\n" n - | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n - | Int n -> pr " printf (\"%%d\\n\", %s);\n" n - | Int64 n -> pr " printf (\"%%\" PRIi64 \"\\n\", %s);\n" n + | OptString n -> pr " fprintf (fp, \"%%s\\n\", %s ? %s : \"null\");\n" n n + | StringList n | DeviceList n -> pr " print_strings (g, %s);\n" n + | Bool n -> pr " fprintf (fp, \"%%s\\n\", %s ? \"true\" : \"false\");\n" n + | Int n -> pr " fprintf (fp, \"%%d\\n\", %s);\n" n + | Int64 n -> pr " fprintf (fp, \"%%\" PRIi64 \"\\n\", %s);\n" n | Pointer _ -> assert false ) args; + let check_optarg n printf_args = - pr " printf (\"%s: \");\n" n; + pr " fprintf (fp, \"%s: \");\n" n; pr " if (optargs->bitmask & GUESTFS_INTERNAL_TEST_%s_BITMASK) {\n" (String.uppercase n); - pr " printf (%s);\n" printf_args; + pr " fprintf (fp, %s);\n" printf_args; pr " } else {\n"; - pr " printf (\"unset\\n\");\n"; + pr " fprintf (fp, \"unset\\n\");\n"; pr " }\n"; in List.iter ( @@ -118,16 +170,16 @@ print_strings (char *const *argv) let printf_args = sprintf "\"%%s\\n\", optargs->%s" n in check_optarg n printf_args; | OStringList n -> - pr " printf (\"%s: \");\n" n; + pr " fprintf (fp, \"%s: \");\n" n; pr " if (optargs->bitmask & GUESTFS_INTERNAL_TEST_%s_BITMASK) {\n" (String.uppercase n); - pr " print_strings (optargs->%s);\n" n; + pr " print_strings (g, optargs->%s);\n" n; pr " } else {\n"; - pr " printf (\"unset\\n\");\n"; + pr " fprintf (fp, \"unset\\n\");\n"; pr " }\n"; ) optargs; pr " /* Java changes stdout line buffering so we need this: */\n"; - pr " fflush (stdout);\n"; + pr " fflush (fp);\n"; pr " return 0;\n"; pr "}\n"; pr "\n" in diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 37526063e..dc6f01a2f 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -245,6 +245,9 @@ struct guestfs_h struct timeval launch_t; /* The time that we called guestfs_launch. */ + /* Used by bindtests. */ + FILE *test_fp; + /*** Protocol. ***/ int fd[2]; /* Stdin/stdout of qemu. */ int sock; /* Daemon communications socket. */ diff --git a/src/guestfs.c b/src/guestfs.c index b5874a883..c50625755 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -270,6 +270,10 @@ guestfs_close (guestfs_h *g) /* Remove whole temporary directory. */ guestfs___remove_tmpdir (g->tmpdir); + /* Test output file used by bindtests. */ + if (g->test_fp != NULL) + fclose (g->test_fp); + /* Mark the handle as dead and then free up all memory. */ g->state = NO_HANDLE;