Add structs.
authorRichard W.M. Jones <rjones@redhat.com>
Sun, 1 Jan 2012 22:20:10 +0000 (22:20 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Sun, 1 Jan 2012 22:20:10 +0000 (22:20 +0000)
18 files changed:
.gitignore
APIs/gettimeofday.api [new file with mode: 0644]
APIs/handle.api
APIs/time_t.api [new file with mode: 0644]
generator-lib/wrappi_accumulator.ml
generator-lib/wrappi_types.ml
generator-lib/wrappi_types.mli
generator-macros/pa_wrap.ml
generator/.depend
generator/Makefile.am
generator/wrappi_c.ml
generator/wrappi_c_impl.ml
generator/wrappi_main.ml
generator/wrappi_structs.ml [new file with mode: 0644]
generator/wrappi_structs.mli [new file with mode: 0644]
lib/.gitignore
lib/Makefile.am
lib/implementation_files.mk

index ec4a33c..3d8285c 100644 (file)
@@ -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 (file)
index 0000000..bdfd909
--- /dev/null
@@ -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"]
index 6803fe6..6cbab8d 100644 (file)
@@ -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 (file)
index 0000000..01fc753
--- /dev/null
@@ -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
index 3713d35..237bb0b 100644 (file)
@@ -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
 
index 998e911..84e008c 100644 (file)
@@ -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 = {
index 72840fd..fd276c4 100644 (file)
@@ -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. *)
 
index a31497a..bfe28fb 100644 (file)
@@ -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
     ]
index 2ab30d0..7d2e46e 100644 (file)
@@ -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
index cecc7c2..19c04e6 100644 (file)
@@ -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
index bdf65c8..099a7c2 100644 (file)
@@ -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 <stdlib.h>
+
+#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
index 2c3c143..74f4d39 100644 (file)
@@ -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
   );
 
index abe74ed..322fd8e 100644 (file)
@@ -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 (file)
index 0000000..26bef65
--- /dev/null
@@ -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 (file)
index 0000000..638de52
--- /dev/null
@@ -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
index 846aa7f..9a2bf07 100644 (file)
@@ -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
index 41f197d..a9f74d7 100644 (file)
@@ -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)
index c0abae2..2421bfa 100644 (file)
@@ -31,5 +31,6 @@ local_implementation_files := \
 
 remote_implementation_files := \
        filesize-filesize.c \
+       gettimeofday-gettimeofday.c \
        mkdir-mkdir.c \
        mknod-mknod_char.c