From 9388e0b0ef1053a05122f6d6b8bb89339bdf2998 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 1 Jan 2012 20:01:15 +0000 Subject: [PATCH] Add enums. --- APIs/handle.api | 4 +- examples/Makefile.am | 4 +- examples/remote.c | 2 +- generator-macros/pa_wrap.ml | 19 ++++++++- generator/.depend | 7 ++- generator/Makefile.am | 3 ++ generator/wrappi_boilerplate.ml | 3 +- generator/wrappi_boilerplate.mli | 2 +- generator/wrappi_c.ml | 35 ++++++++++++++- generator/wrappi_c_impl.ml | 34 +++++++++------ generator/wrappi_enums.ml | 92 ++++++++++++++++++++++++++++++++++++++++ generator/wrappi_enums.mli | 21 +++++++++ generator/wrappi_main.ml | 5 +++ lib/.gitignore | 2 + lib/connect.c | 2 +- lib/implementation_files.mk | 6 ++- 16 files changed, 213 insertions(+), 28 deletions(-) create mode 100644 generator/wrappi_enums.ml create mode 100644 generator/wrappi_enums.mli diff --git a/APIs/handle.api b/APIs/handle.api index 3f22260..6803fe6 100644 --- a/APIs/handle.api +++ b/APIs/handle.api @@ -18,6 +18,6 @@ entry_point local void connect () -(* XXX Should scheme be an enum? *) -entry_point local void set_scheme (string scheme) +enum scheme ["local"; "ssh"] ;; +entry_point local void set_scheme (enum scheme scheme) entry_point local void set_hostname (string hostname) diff --git a/examples/Makefile.am b/examples/Makefile.am index 15b68bd..fa78ec7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -18,7 +18,9 @@ noinst_PROGRAMS = remote remote_SOURCES = remote.c -remote_CFLAGS = -I../lib +remote_CFLAGS = \ + -I../lib \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) remote_LDADD = ../lib/libwrappi.la CLEANFILES = *~ diff --git a/examples/remote.c b/examples/remote.c index 5e0d722..ae1d5b6 100644 --- a/examples/remote.c +++ b/examples/remote.c @@ -31,7 +31,7 @@ main (int argc, char *argv[]) * simply comment out the next two lines, then wrappi will run the * commands on the local machine. */ - wrap_set_scheme (w, "ssh"); + wrap_set_scheme (w, WRAP_SCHEME_SSH); wrap_set_hostname (w, hostname); /* Connect the handle. Because we didn't set any error handler, diff --git a/generator-macros/pa_wrap.ml b/generator-macros/pa_wrap.ml index 5ce6d08..a31497a 100644 --- a/generator-macros/pa_wrap.ml +++ b/generator-macros/pa_wrap.ml @@ -86,6 +86,16 @@ let add_typedef _loc name t = Wrappi_accumulator.add_typedef td >> +let add_enum _loc name identifiers = + let loc = expr_of_loc _loc _loc in + + <:str_item< + let en = { Wrappi_types.en_loc = $loc$; + en_name = $str:name$; + en_identifiers = Array.of_list $identifiers$ } in + Wrappi_accumulator.add_enum en + >> + let () = (* Quotation expander for C code. *) let c_quotation_expander _loc _ code = @@ -112,7 +122,7 @@ EXTEND Gram ptype: [ [ "bool" -> <:expr< Wrappi_types.TBool >> ] | [ "buffer" -> <:expr< Wrappi_types.TBuffer >> ] - (* enum XXX *) + | [ "enum"; name = LIDENT -> <:expr< Wrappi_types.TEnum $str:name$ >> ] | [ "file" -> <:expr< Wrappi_types.TFile >> ] | [ "hash"; "("; t = ptype; ")" -> <:expr< Wrappi_types.THash $t$ >> ] | [ "int" -> <:expr< Wrappi_types.TInt >> ] @@ -124,7 +134,7 @@ EXTEND Gram | [ "struct"; name = LIDENT -> <:expr< Wrappi_types.TStruct $str:name$ >> ] | [ "uint32" -> <:expr< Wrappi_types.TUInt32 >> ] | [ "uint64" -> <:expr< Wrappi_types.TUInt64 >> ] - (* union XXX *) + | [ "union"; name = LIDENT -> <:expr< Wrappi_types.TUnion $str:name$ >> ] | [ name = LIDENT -> <:expr< Wrappi_types.TTypedef $str:name$ >> ] ]; @@ -148,6 +158,11 @@ EXTEND Gram -> add_entry_point _loc local name parameters rtype code includes ] + + | [ "enum"; name = LIDENT; identifiers = expr -> + add_enum _loc name identifiers + ] + | [ "typedef"; t = ptype; name = LIDENT -> add_typedef _loc name t ] diff --git a/generator/.depend b/generator/.depend index 033feaf..2ab30d0 100644 --- a/generator/.depend +++ b/generator/.depend @@ -7,8 +7,11 @@ wrappi_c.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c.cmi wrappi_c_impl.cmi: wrappi_c_impl.cmo: wrappi_pr.cmi wrappi_boilerplate.cmi wrappi_c_impl.cmi wrappi_c_impl.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c_impl.cmi -wrappi_main.cmo: wrappi_pr.cmi wrappi_c_impl.cmi wrappi_c.cmi -wrappi_main.cmx: wrappi_pr.cmx wrappi_c_impl.cmx wrappi_c.cmx +wrappi_enums.cmi: +wrappi_enums.cmo: wrappi_enums.cmi +wrappi_enums.cmx: wrappi_enums.cmi +wrappi_main.cmo: wrappi_pr.cmi wrappi_enums.cmi wrappi_c_impl.cmi wrappi_c.cmi +wrappi_main.cmx: wrappi_pr.cmx wrappi_enums.cmx wrappi_c_impl.cmx wrappi_c.cmx wrappi_pr.cmi: wrappi_pr.cmo: wrappi_pr.cmi wrappi_pr.cmx: wrappi_pr.cmi diff --git a/generator/Makefile.am b/generator/Makefile.am index 872d000..cecc7c2 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -30,6 +30,8 @@ SOURCES = \ wrappi_c_impl.ml \ wrappi_c.mli \ wrappi_c.ml \ + wrappi_enums.mli \ + wrappi_enums.ml \ wrappi_main.ml \ wrappi_pr.mli \ wrappi_pr.ml @@ -38,6 +40,7 @@ SOURCES = \ OBJECTS = \ wrappi_pr.cmo \ wrappi_boilerplate.cmo \ + wrappi_enums.cmo \ wrappi_c_impl.cmo \ wrappi_c.cmo \ wrappi_main.cmo diff --git a/generator/wrappi_boilerplate.ml b/generator/wrappi_boilerplate.ml index 5e39b31..1a6e18d 100644 --- a/generator/wrappi_boilerplate.ml +++ b/generator/wrappi_boilerplate.ml @@ -31,8 +31,7 @@ type comment_style = | ErlangStyle type license = GPLv2plus | LGPLv2plus -let generate_header comment license = - let inputs = [ "generator/wrappi_*.ml" ] in +let generate_header inputs comment license = let c = match comment with | CStyle -> pr "/* "; " *" | CPlusPlusStyle -> pr "// "; "//" diff --git a/generator/wrappi_boilerplate.mli b/generator/wrappi_boilerplate.mli index c2fa59e..bc1f292 100644 --- a/generator/wrappi_boilerplate.mli +++ b/generator/wrappi_boilerplate.mli @@ -21,4 +21,4 @@ type comment_style = | ErlangStyle type license = GPLv2plus | LGPLv2plus -val generate_header : comment_style -> license -> unit +val generate_header : string list -> comment_style -> license -> unit diff --git a/generator/wrappi_c.ml b/generator/wrappi_c.ml index 7f9c1b4..80b832b 100644 --- a/generator/wrappi_c.ml +++ b/generator/wrappi_c.ml @@ -23,10 +23,12 @@ open Wrappi_boilerplate open Printf +let inputs = ["wrappi_c.ml"] + let c_of_ptype ~param = function | TBool -> "int" | TBuffer -> assert false (* XXX not implemented *) - | TEnum name -> sprintf "enum wrap_%s" name + | TEnum name -> sprintf "wrap_%s_enum" name | TFile -> if param then "const char *" else "char *" | THash t -> if param then "char * const *" else "char **" | TInt -> "int" (* XXX not int, correct type depends on preconditions *) @@ -69,7 +71,7 @@ let pr_extern_decl ep = pr ");\n" let generate_lib_wrappi_h api = - generate_header CStyle LGPLv2plus; + generate_header inputs CStyle LGPLv2plus; pr "\ /* Please read the wrappi(1) man page for full documentation. If you @@ -89,6 +91,35 @@ extern \"C\" { /* The handle. */ typedef struct wrap_h wrap_h; +/* Types. */ +"; + + iter_enums api ( + fun en -> + let name = en.en_name in + + (* The C compiler may choose to declare the sizeof(enum) == + * sizeof(char), and adding fields to such an enum later could + * cause ABI breakage. (See the gcc --fshort-enums option for one + * example of this). Therefore use the enum just to declare the + * values, and typedef the enum as an int. + *) + pr "enum {\n"; + + Array.iteri ( + fun i id -> + pr " WRAP_%s_%s = %d,\n" + (String.uppercase name) (String.uppercase id) i + ) en.en_identifiers; + + pr " WRAP_%s_ENUM_MAX = %d\n" + (String.uppercase name) (Array.length en.en_identifiers); + pr "};\n"; + pr "typedef int wrap_%s_enum;\n" name; + pr "\n"; + ); + + pr "\ /* Connection management. */ extern wrap_h *wrap_create (void); extern void wrap_close (wrap_h *w); diff --git a/generator/wrappi_c_impl.ml b/generator/wrappi_c_impl.ml index c3e2ed7..2c3c143 100644 --- a/generator/wrappi_c_impl.ml +++ b/generator/wrappi_c_impl.ml @@ -25,10 +25,12 @@ open Wrappi_pr open Printf +let inputs = ["wrappi_c_impl.ml"] + let c_of_ptype ~param = function | TBool -> "int" | TBuffer -> assert false (* XXX not implemented *) - | TEnum name -> sprintf "enum wrap_%s" name + | TEnum name -> sprintf "wrap_%s_enum" name | TFile -> if param then "const char *" else "char *" | THash t -> if param then "char * const *" else "char **" | TInt -> "int" (* XXX not int, correct type depends on preconditions *) @@ -77,16 +79,18 @@ let pr_defn ?(impl = false) ep = pr ")\n" let generate_implementation ep = - generate_header CStyle LGPLv2plus; + generate_header inputs CStyle LGPLv2plus; pr "\ /* Automatically generated implementation of '%s'. - * This API was defined in '%s' at line %d. - */ +" ep.ep_name; -" ep.ep_name (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc); + if not (Loc.is_ghost ep.ep_loc) then + pr " * This API was defined in '%s' at line %d.\n" + (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc); + + pr " */ - pr "\ #include #include @@ -111,7 +115,8 @@ pr "\ (match ep.ep_code with | None -> () (* XXX implicit code *) | Some { cc_loc = loc; cc_code = code } -> - pr "#line %d \"%s\"\n" (Loc.start_line loc) (Loc.file_name loc); + if not (Loc.is_ghost loc) then + pr "#line %d \"%s\"\n" (Loc.start_line loc) (Loc.file_name loc); pr "%s" code ); @@ -126,9 +131,9 @@ pr "\ pr_defn ep; pr "{\n"; - pr " assert (w->scheme == NULL); /* XXX */;\n"; - pr "\n"; - pr " "; + pr " if (w->scheme == NULL) {\n"; + pr " /* Local connection. */\n"; + pr " "; let ret, req, opt = ep.ep_ftype in @@ -149,10 +154,15 @@ pr "\ pr ");\n"; (match ret with - | RVoid -> pr " return;\n" + | RVoid -> pr " return;\n" | _ -> () ); + pr " } else {\n"; + pr " /* Remote connection. */\n"; + pr " abort (); /* XXX */\n"; + pr " }\n"; + pr "}\n" ) @@ -167,7 +177,7 @@ let filename_of_ep ep = filename let generate_lib_implementation_files_mk api = - generate_header HashStyle GPLv2plus; + generate_header inputs HashStyle GPLv2plus; let eps = StringMap.bindings api.api_entry_points in let cmp (a, _) (b, _) = compare a b in diff --git a/generator/wrappi_enums.ml b/generator/wrappi_enums.ml new file mode 100644 index 0000000..3b33ec5 --- /dev/null +++ b/generator/wrappi_enums.ml @@ -0,0 +1,92 @@ +(* wrappi + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Camlp4.PreCast + +open Wrappi_types +open Wrappi_utils + +open Printf + +let extend_api api = + let eps = ref api.api_entry_points in + + iter_enums api ( + fun en -> + let name = en.en_name in + + (* Add an entry point wrap__enum_to_string. *) + let fname = sprintf "%s_enum_to_string" name in + let code = + let b = Buffer.create 512 in + bprintf b " switch (v) {\n"; + Array.iter ( + fun id -> + bprintf b " case WRAP_%s_%s: return \"%s\";\n" + (String.uppercase name) (String.uppercase id) id; + ) en.en_identifiers; + bprintf b " default:\n"; + bprintf b " set_error (\"unknown enum case %%d\", v);\n"; + bprintf b " return NULL;\n"; + bprintf b " }\n"; + Buffer.contents b in + let c_code = { + cc_loc = Loc.ghost; + cc_code = code; + } in + let ep = { + ep_loc = Loc.ghost; + ep_local = true; + ep_name = fname; + ep_ftype = RStaticString, ["v", TEnum name, None], []; + ep_code = Some c_code; + ep_includes = [] + } in + + eps := StringMap.add fname ep !eps; + + (* Add an entry point wrap__string_to_enum. *) + let fname = sprintf "%s_string_to_enum" name in + let code = + let b = Buffer.create 512 in + Array.iter ( + fun id -> + bprintf b " if (STREQ (v, \"%s\"))\n" id; + bprintf b " return WRAP_%s_%s;\n" + (String.uppercase name) (String.uppercase id); + ) en.en_identifiers; + bprintf b " set_error (\"unknown enum case %%s\", v);\n"; + bprintf b " return -1;\n"; + Buffer.contents b in + let c_code = { + cc_loc = Loc.ghost; + cc_code = code; + } in + let ep = { + ep_loc = Loc.ghost; + ep_local = true; + ep_name = fname; + ep_ftype = Return (TEnum name), ["v", TString, None], []; + ep_code = Some c_code; + ep_includes = [] + } in + + eps := StringMap.add fname ep !eps + ); + + { api with api_entry_points = !eps } diff --git a/generator/wrappi_enums.mli b/generator/wrappi_enums.mli new file mode 100644 index 0000000..a5d36ec --- /dev/null +++ b/generator/wrappi_enums.mli @@ -0,0 +1,21 @@ +(* wrappi + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +(** Add some functions to the API for converting enums to/from strings. *) + +val extend_api : Wrappi_types.api -> Wrappi_types.api diff --git a/generator/wrappi_main.ml b/generator/wrappi_main.ml index 8f92cb1..abe74ed 100644 --- a/generator/wrappi_main.ml +++ b/generator/wrappi_main.ml @@ -30,6 +30,11 @@ let nr_sds = StringMap.cardinal api.api_structs let nr_uns = StringMap.cardinal api.api_unions let nr_eps = StringMap.cardinal api.api_entry_points +(* Extend the API with some entry points which are purely + * generated from other things, eg. from enums. + *) +let api = Wrappi_enums.extend_api api + let dump_and_exit () = printf "typedefs (%d):\n" nr_tds; iter_typedefs api (fun td -> printf " %s\n" (string_of_typedef td)); diff --git a/lib/.gitignore b/lib/.gitignore index 76d4e3e..2f8a6ba 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -6,3 +6,5 @@ /error-get_error_func.c /mkdir-mkdir.c /mknod-mknod_char.c +/ghost-location-scheme_enum_to_string.c +/ghost-location-scheme_string_to_enum.c diff --git a/lib/connect.c b/lib/connect.c index a57fcfa..2062e08 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -33,7 +33,7 @@ wrap_connect (wrap_h *w) } void -wrap_set_scheme (wrap_h *w, const char *scheme) +wrap_set_scheme (wrap_h *w, wrap_scheme_enum scheme) { /* XXX */ } diff --git a/lib/implementation_files.mk b/lib/implementation_files.mk index 04c4a17..8290343 100644 --- a/lib/implementation_files.mk +++ b/lib/implementation_files.mk @@ -1,6 +1,6 @@ # wrappi generated file # WARNING: THIS FILE IS GENERATED FROM: -# generator/wrappi_*.ml +# wrappi_c_impl.ml # ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST. # # Copyright (C) 2011-2012 Red Hat Inc. @@ -24,7 +24,9 @@ local_implementation_files := \ error-error.c \ error-get_errno.c \ error-get_error.c \ - error-get_error_func.c + error-get_error_func.c \ + ghost-location-scheme_enum_to_string.c \ + ghost-location-scheme_string_to_enum.c remote_implementation_files := \ filesize-filesize.c \ -- 1.8.3.1