diff --git a/.gitignore b/.gitignore index 394e20af8..8b88abdb6 100644 --- a/.gitignore +++ b/.gitignore @@ -371,6 +371,7 @@ Makefile.in /src/guestfs-availability.pod /src/guestfs.h /src/guestfs-internal-actions.h +/src/guestfs-internal-frontend-cleanups.h /src/guestfs_protocol.c /src/guestfs_protocol.h /src/guestfs_protocol.x diff --git a/generator/c.ml b/generator/c.ml index 81f7a7635..72d8ceb40 100644 --- a/generator/c.ml +++ b/generator/c.ml @@ -779,6 +779,60 @@ and generate_internal_actions_h () = pr "\n"; pr "#endif /* GUESTFS_INTERNAL_ACTIONS_H_ */\n" +(* Generate guestfs-internal-frontend-cleanups.h file. *) +and generate_internal_frontend_cleanups_h () = + generate_header CStyle LGPLv2plus; + + pr "\ +/* These CLEANUP_* macros automatically free the struct or struct list + * pointed to by the local variable at the end of the current scope. + * + * Don't include this file directly! To use these cleanups in library + * bindings and tools, include \"guestfs-internal-frontend.h\" only. + */ + +#ifndef GUESTFS_INTERNAL_FRONTEND_CLEANUPS_H_ +#define GUESTFS_INTERNAL_FRONTEND_CLEANUPS_H_ + +#ifdef HAVE_ATTRIBUTE_CLEANUP +"; + + List.iter ( + fun { s_name = name } -> + pr "#define CLEANUP_FREE_%s \\\n" (String.uppercase name); + pr " __attribute__((cleanup(guestfs___cleanup_free_%s)))\n" name; + pr "#define CLEANUP_FREE_%s_LIST \\\n" (String.uppercase name); + pr " __attribute__((cleanup(guestfs___cleanup_free_%s_list)))\n" name + ) structs; + + pr "#else /* !HAVE_ATTRIBUTE_CLEANUP */\n"; + + List.iter ( + fun { s_name = name } -> + pr "#define CLEANUP_FREE_%s\n" (String.uppercase name); + pr "#define CLEANUP_FREE_%s_LIST\n" (String.uppercase name) + ) structs; + + pr "\ +#endif /* !HAVE_ATTRIBUTE_CLEANUP */ + +/* These functions are used internally by the CLEANUP_* macros. + * Don't call them directly. + */ + +"; + + List.iter ( + fun { s_name = name } -> + pr "extern GUESTFS_DLL_PUBLIC void guestfs___cleanup_free_%s (void *ptr);\n" + name; + pr "extern GUESTFS_DLL_PUBLIC void guestfs___cleanup_free_%s_list (void *ptr);\n" + name + ) structs; + + pr "\n"; + pr "#endif /* GUESTFS_INTERNAL_FRONTEND_CLEANUPS_H_ */\n" + (* Functions to free structures. *) and generate_client_free_structs () = generate_header CStyle LGPLv2plus; @@ -824,6 +878,28 @@ and generate_client_free_structs () = pr "}\n"; pr "\n"; + ) structs; + + pr "/* Cleanup functions used by CLEANUP_* macros. */\n"; + pr "\n"; + + List.iter ( + fun { s_name = typ } -> + pr "GUESTFS_DLL_PUBLIC void\n"; + pr "guestfs___cleanup_free_%s (void *ptr)\n" typ; + pr "{\n"; + pr " guestfs_free_%s (* (struct guestfs_%s **) ptr);\n" typ typ; + pr "}\n"; + pr "\n"; + + pr "GUESTFS_DLL_PUBLIC void\n"; + pr "guestfs___cleanup_free_%s_list (void *ptr)\n" typ; + pr "{\n"; + pr " guestfs_free_%s_list (* (struct guestfs_%s_list **) ptr);\n" + typ typ; + pr "}\n"; + pr "\n"; + ) structs (* Generate the client-side dispatch stubs. *) @@ -1707,13 +1783,24 @@ and generate_linker_script () = "guestfs_" ^ c_name ^ "_argv"] ) all_functions ) in - let structs = + let struct_frees = List.concat ( List.map (fun { s_name = typ } -> - ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"]) + ["guestfs_free_" ^ typ; + "guestfs_free_" ^ typ ^ "_list"]) structs ) in - let globals = List.sort compare (globals @ functions @ structs) in + let struct_cleanups = + List.concat ( + List.map (fun { s_name = typ } -> + ["guestfs___cleanup_free_" ^ typ; + "guestfs___cleanup_free_" ^ typ ^ "_list"]) + structs + ) in + let globals = List.sort compare (globals @ + functions @ + struct_frees @ + struct_cleanups) in pr "{\n"; pr " global:\n"; diff --git a/generator/main.ml b/generator/main.ml index f4f05fb74..0e182362b 100644 --- a/generator/main.ml +++ b/generator/main.ml @@ -84,6 +84,8 @@ Run it from the top source directory using the command output_to "src/guestfs_protocol.x" generate_xdr; output_to "src/guestfs.h" generate_guestfs_h; output_to "src/guestfs-internal-actions.h" generate_internal_actions_h; + output_to "src/guestfs-internal-frontend-cleanups.h" + generate_internal_frontend_cleanups_h; output_to "src/bindtests.c" generate_bindtests; output_to "src/guestfs-structs.pod" generate_structs_pod; output_to "src/guestfs-actions.pod" generate_actions_pod; diff --git a/src/Makefile.am b/src/Makefile.am index e344190a3..1b6dbace4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,6 +23,7 @@ generator_built = \ guestfs_protocol.x \ guestfs.h \ guestfs-internal-actions.h \ + guestfs-internal-frontend-cleanups.h \ actions-0.c \ actions-1.c \ actions-2.c \ diff --git a/src/guestfs-internal-frontend.h b/src/guestfs-internal-frontend.h index 7d418069a..c80bb3bcd 100644 --- a/src/guestfs-internal-frontend.h +++ b/src/guestfs-internal-frontend.h @@ -108,4 +108,9 @@ extern void guestfs___cleanup_xmlXPathFreeContext (void *ptr); extern void guestfs___cleanup_xmlXPathFreeObject (void *ptr); #endif +/* These are in a separate header so the header can be generated. + * Don't include the following file directly: + */ +#include "guestfs-internal-frontend-cleanups.h" + #endif /* GUESTFS_INTERNAL_FRONTEND_H_ */