From 00e9ee626a00324c1808ab860f00f1a07c88ade8 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 1 Jan 2012 22:20:10 +0000 Subject: [PATCH] Add structs. --- .gitignore | 1 + APIs/gettimeofday.api | 39 +++++++++++++++++ APIs/handle.api | 2 +- APIs/time_t.api | 22 ++++++++++ generator-lib/wrappi_accumulator.ml | 12 +++++- generator-lib/wrappi_types.ml | 6 +-- generator-lib/wrappi_types.mli | 6 +-- generator-macros/pa_wrap.ml | 24 +++++++++++ generator/.depend | 7 ++- generator/Makefile.am | 5 ++- generator/wrappi_c.ml | 85 ++++++++++++++++++++++++++++++++++++- generator/wrappi_c_impl.ml | 21 ++++++++- generator/wrappi_main.ml | 1 + generator/wrappi_structs.ml | 30 +++++++++++++ generator/wrappi_structs.mli | 21 +++++++++ lib/.gitignore | 1 + lib/Makefile.am | 1 + lib/implementation_files.mk | 1 + 18 files changed, 268 insertions(+), 17 deletions(-) create mode 100644 APIs/gettimeofday.api create mode 100644 APIs/time_t.api create mode 100644 generator/wrappi_structs.ml create mode 100644 generator/wrappi_structs.mli diff --git a/.gitignore b/.gitignore index ec4a33c..3d8285c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ Makefile.in /generator/generator /generator/stamp-generator /install-sh +/lib/free_structs.c /lib/wrappi.h /libtool /local* diff --git a/APIs/gettimeofday.api b/APIs/gettimeofday.api new file mode 100644 index 0000000..bdfd909 --- /dev/null +++ b/APIs/gettimeofday.api @@ -0,0 +1,39 @@ +(* wrappi -*- tuareg -*- + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +struct timeval { + time_t tv_sec; + uint32 tv_usec +} + +entry_point +struct timeval gettimeofday () +<< + int r; + struct timeval tv; + + r = gettimeofday (&tv, NULL); + if (r == -1) { + set_error_errno ("gettimeofday"); + return NULL; + } + ret->tv_sec = tv.tv_sec; + ret->tv_usec = tv.tv_usec; + return ret; +>> +includes ["sys/time.h"] diff --git a/APIs/handle.api b/APIs/handle.api index 6803fe6..6cbab8d 100644 --- a/APIs/handle.api +++ b/APIs/handle.api @@ -18,6 +18,6 @@ entry_point local void connect () -enum scheme ["local"; "ssh"] ;; +enum scheme ["local"; "ssh"] entry_point local void set_scheme (enum scheme scheme) entry_point local void set_hostname (string hostname) diff --git a/APIs/time_t.api b/APIs/time_t.api new file mode 100644 index 0000000..01fc753 --- /dev/null +++ b/APIs/time_t.api @@ -0,0 +1,22 @@ +(* wrappi -*- tuareg -*- + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +(* Signed so we can represent times before the epoch, and 64 bit so we + * don't suffer from 2K38 bugs. + *) +typedef int64 time_t diff --git a/generator-lib/wrappi_accumulator.ml b/generator-lib/wrappi_accumulator.ml index 3713d35..237bb0b 100644 --- a/generator-lib/wrappi_accumulator.ml +++ b/generator-lib/wrappi_accumulator.ml @@ -117,7 +117,11 @@ let get_api () = fun sd -> let fields = sd.sd_fields in let fields = - Array.map (resolve_typedefs "enum" sd.sd_name sd.sd_loc) fields in + Array.map ( + fun (name, t) -> + let t = resolve_typedefs "enum" sd.sd_name sd.sd_loc t in + (name, t) + ) fields in { sd with sd_fields = fields } ) sds in @@ -125,7 +129,11 @@ let get_api () = fun un -> let fields = un.un_fields in let fields = - Array.map (resolve_typedefs "union" un.un_name un.un_loc) fields in + Array.map ( + fun (name, t) -> + let t = resolve_typedefs "union" un.un_name un.un_loc t in + (name, t) + ) fields in { un with un_fields = fields } ) uns in diff --git a/generator-lib/wrappi_types.ml b/generator-lib/wrappi_types.ml index 998e911..84e008c 100644 --- a/generator-lib/wrappi_types.ml +++ b/generator-lib/wrappi_types.ml @@ -77,15 +77,13 @@ type enum = { type struct_decl = { sd_loc : Camlp4.PreCast.Loc.t; sd_name : string; - sd_identifiers : string array; - sd_fields : ptype array; + sd_fields : (string * ptype) array; } type union = { un_loc : Camlp4.PreCast.Loc.t; un_name : string; - un_identifiers : string array; - un_fields : ptype array; + un_fields : (string * ptype) array; } type api = { diff --git a/generator-lib/wrappi_types.mli b/generator-lib/wrappi_types.mli index 72840fd..fd276c4 100644 --- a/generator-lib/wrappi_types.mli +++ b/generator-lib/wrappi_types.mli @@ -82,16 +82,14 @@ type enum = { type struct_decl = { sd_loc : Camlp4.PreCast.Loc.t; sd_name : string; - sd_identifiers : string array; - sd_fields : ptype array; + sd_fields : (string * ptype) array; } (** A struct declaration. *) type union = { un_loc : Camlp4.PreCast.Loc.t; un_name : string; - un_identifiers : string array; - un_fields : ptype array; + un_fields : (string * ptype) array; } (** A qualified union declaration. *) diff --git a/generator-macros/pa_wrap.ml b/generator-macros/pa_wrap.ml index a31497a..bfe28fb 100644 --- a/generator-macros/pa_wrap.ml +++ b/generator-macros/pa_wrap.ml @@ -96,6 +96,21 @@ let add_enum _loc name identifiers = Wrappi_accumulator.add_enum en >> +let add_struct _loc name fields = + let loc = expr_of_loc _loc _loc in + + let fields = List.map ( + fun (name, t) -> <:expr< ($str:name$, $t$) >> + ) fields in + let fields = expr_of_list _loc fields in + + <:str_item< + let sd = { Wrappi_types.sd_loc = $loc$; + sd_name = $str:name$; + sd_fields = Array.of_list $fields$ } in + Wrappi_accumulator.add_struct sd + >> + let () = (* Quotation expander for C code. *) let c_quotation_expander _loc _ code = @@ -148,6 +163,9 @@ EXTEND Gram (* A single function parameter. XXX Preconditions. *) parameter: [[ t = ptype; name = LIDENT -> (name, t) ]]; + (* A single struct field. XXX Preconditions. *) + struct_field: [[ t = ptype; name = LIDENT -> (name, t) ]]; + str_item: LEVEL "top" [ [ "entry_point"; local = OPT "local"; @@ -163,6 +181,12 @@ EXTEND Gram add_enum _loc name identifiers ] + | [ "struct"; name = LIDENT; "{"; + fields = LIST0 struct_field SEP ";"; + "}" -> + add_struct _loc name fields + ] + | [ "typedef"; t = ptype; name = LIDENT -> add_typedef _loc name t ] diff --git a/generator/.depend b/generator/.depend index 2ab30d0..7d2e46e 100644 --- a/generator/.depend +++ b/generator/.depend @@ -10,8 +10,11 @@ wrappi_c_impl.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c_impl.cmi 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_main.cmo: wrappi_structs.cmi wrappi_pr.cmi wrappi_enums.cmi wrappi_c_impl.cmi wrappi_c.cmi +wrappi_main.cmx: wrappi_structs.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 +wrappi_structs.cmi: +wrappi_structs.cmo: wrappi_structs.cmi +wrappi_structs.cmx: wrappi_structs.cmi diff --git a/generator/Makefile.am b/generator/Makefile.am index cecc7c2..19c04e6 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -34,13 +34,16 @@ SOURCES = \ wrappi_enums.ml \ wrappi_main.ml \ wrappi_pr.mli \ - wrappi_pr.ml + wrappi_pr.ml \ + wrappi_structs.mli \ + wrappi_structs.ml # In dependency order. OBJECTS = \ wrappi_pr.cmo \ wrappi_boilerplate.cmo \ wrappi_enums.cmo \ + wrappi_structs.cmo \ wrappi_c_impl.cmo \ wrappi_c.cmo \ wrappi_main.cmo diff --git a/generator/wrappi_c.ml b/generator/wrappi_c.ml index bdf65c8..099a7c2 100644 --- a/generator/wrappi_c.ml +++ b/generator/wrappi_c.ml @@ -38,7 +38,9 @@ let c_of_ptype ~param = function | TNullable TString -> if param then "const char *" else "char *" | TNullable _ -> assert false (* XXX may be implemented in future *) | TString -> if param then "const char *" else "char *" - | TStruct name -> sprintf "struct wrap_%s" name + | TStruct name -> + if param then sprintf "const struct wrap_%s *" name + else sprintf "struct wrap_%s *" name | TTypedef name -> assert false (* should never happen *) | TUInt32 -> "uint32_t" | TUInt64 -> "uint64_t" @@ -49,6 +51,25 @@ let c_of_rtype = function | RStaticString -> "const char *" | Return t -> c_of_ptype ~param:false t +let field_of_ptype = function + | TBool -> "int" + | TBuffer -> assert false (* XXX not implemented *) + | TEnum name -> sprintf "wrap_%s_enum" name + | TFile -> assert false (* cannot occur in a struct *) + | THash t -> "char **" + | TInt -> "int" (* XXX not int, correct type depends on preconditions *) + | TInt32 -> "int32_t" + | TInt64 -> "int64_t" + | TList t -> assert false (* XXX not implemented *) + | TNullable TString -> "char *" + | TNullable _ -> assert false (* XXX may be implemented in future *) + | TString -> "char *" + | TStruct name -> assert false (* we don't allow struct/union here *) + | TTypedef name -> assert false (* should never happen *) + | TUInt32 -> "uint32_t" + | TUInt64 -> "uint64_t" + | TUnion name -> assert false (* we don't allow struct/union here *) + (* Print the extern... declaration of a single entry point. *) let pr_extern_decl ep = let ret, req, opt = ep.ep_ftype in @@ -116,6 +137,21 @@ typedef struct wrap_h wrap_h; pr "\n"; ); + iter_structs api ( + fun sd -> + let name = sd.sd_name in + + pr "struct wrap_%s {\n" name; + + Array.iter ( + fun (name, t) -> + pr " %s %s;\n" (field_of_ptype t) name + ) sd.sd_fields; + pr "};\n"; + pr "void wrap_free_%s (struct wrap_%s *);\n" name name; + pr "\n" + ); + pr "\ /* Connection management. */ extern wrap_h *wrap_create (void); @@ -144,5 +180,50 @@ extern void wrap_close (wrap_h *w); #endif /* WRAPPI_H_ */ " +(* Functions for freeing structs are part of the C bindings. We don't + * want them to be exposed in other languages, although they will be + * used by other bindings. + *) +let generate_lib_free_structs_c api = + generate_header inputs CStyle LGPLv2plus; + + pr "\ +#include + +#include \"wrappi.h\" +"; + + iter_structs api ( + fun sd -> + pr "\n"; + + let name = sd.sd_name in + + pr "void\n"; + pr "wrap_free_%s (struct wrap_%s *v)\n" name name; + pr "{\n"; + + Array.iter ( + fun (n, t) -> + match t with + | TBool | TEnum _ | TInt | TInt32 | TInt64 | TUInt32 | TUInt64 -> + () (* these don't need to be freed *) + | TBuffer -> assert false (* XXX not implemented *) + | TFile + | TNullable TString + | TString -> + pr " free (v->%s);\n" n + | THash t -> assert false (* XXX not implemented *) + | TList t -> assert false (* XXX not implemented *) + | TNullable _ -> assert false (* XXX may be implemented in future *) + | TStruct name -> assert false (* cannot occur in structs *) + | TTypedef name -> assert false (* should never happen *) + | TUnion name -> assert false (* cannot occur in structs *) + ) sd.sd_fields; + pr " free (v);\n"; + pr "}\n" + ) + let generate api = - output_to "lib/wrappi.h" generate_lib_wrappi_h api + output_to "lib/wrappi.h" generate_lib_wrappi_h api; + output_to "lib/free_structs.c" generate_lib_free_structs_c api diff --git a/generator/wrappi_c_impl.ml b/generator/wrappi_c_impl.ml index 2c3c143..74f4d39 100644 --- a/generator/wrappi_c_impl.ml +++ b/generator/wrappi_c_impl.ml @@ -40,7 +40,9 @@ let c_of_ptype ~param = function | TNullable TString -> if param then "const char *" else "char *" | TNullable _ -> assert false (* XXX may be implemented in future *) | TString -> if param then "const char *" else "char *" - | TStruct name -> sprintf "struct wrap_%s" name + | TStruct name -> + if param then sprintf "const struct wrap_%s *" name + else sprintf "struct wrap_%s *" name | TTypedef name -> assert false (* should never happen *) | TUInt32 -> "uint32_t" | TUInt64 -> "uint64_t" @@ -115,8 +117,25 @@ pr "\ (match ep.ep_code with | None -> () (* XXX implicit code *) | Some { cc_loc = loc; cc_code = code } -> + (* If the return is a struct/union/list then allocate the structure + * in a local variable called 'ret' which the function should + * assign to. + *) + let ret, _, _ = ep.ep_ftype in + (match ret with + | Return (TStruct name) -> + pr " struct wrap_%s *ret = malloc (sizeof *ret);\n" name; + pr " if (!ret) {\n"; + pr " set_error_errno (\"malloc: struct wrap_%%s\", \"%s\");\n" name; + pr " return NULL;\n"; + pr " }\n" + | _ -> () (* XXX union, list, etc. *) + ); + + (* Make sure included code has correct line numbers. *) if not (Loc.is_ghost loc) then pr "#line %d \"%s\"\n" (Loc.start_line loc) (Loc.file_name loc); + pr "%s" code ); diff --git a/generator/wrappi_main.ml b/generator/wrappi_main.ml index abe74ed..322fd8e 100644 --- a/generator/wrappi_main.ml +++ b/generator/wrappi_main.ml @@ -34,6 +34,7 @@ let nr_eps = StringMap.cardinal api.api_entry_points * generated from other things, eg. from enums. *) let api = Wrappi_enums.extend_api api +let api = Wrappi_structs.extend_api api let dump_and_exit () = printf "typedefs (%d):\n" nr_tds; diff --git a/generator/wrappi_structs.ml b/generator/wrappi_structs.ml new file mode 100644 index 0000000..26bef65 --- /dev/null +++ b/generator/wrappi_structs.ml @@ -0,0 +1,30 @@ +(* 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 + +(* Nothing at the moment, but for Perl it'd be useful to have a way + * to get a list of the fields in a struct. XXX + *) +let extend_api api = + api diff --git a/generator/wrappi_structs.mli b/generator/wrappi_structs.mli new file mode 100644 index 0000000..638de52 --- /dev/null +++ b/generator/wrappi_structs.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 handling structs. *) + +val extend_api : Wrappi_types.api -> Wrappi_types.api diff --git a/lib/.gitignore b/lib/.gitignore index 846aa7f..9a2bf07 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -4,6 +4,7 @@ /error-get_errno.c /error-get_error.c /error-get_error_func.c +/gettimeofday-gettimeofday.c /mkdir-mkdir.c /mknod-mknod_char.c /ghost-location-scheme_enum_nr.c diff --git a/lib/Makefile.am b/lib/Makefile.am index 41f197d..a9f74d7 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -30,6 +30,7 @@ libwrappi_la_SOURCES = \ wrappi.h \ wrappi.c \ connect.c \ + free_structs.c \ $(local_implementation_files) \ $(remote_implementation_files) libwrappi_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) diff --git a/lib/implementation_files.mk b/lib/implementation_files.mk index c0abae2..2421bfa 100644 --- a/lib/implementation_files.mk +++ b/lib/implementation_files.mk @@ -31,5 +31,6 @@ local_implementation_files := \ remote_implementation_files := \ filesize-filesize.c \ + gettimeofday-gettimeofday.c \ mkdir-mkdir.c \ mknod-mknod_char.c -- 1.8.3.1