* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
+open Wrappi_types
+open Wrappi_utils
open Wrappi_pr
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 "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 *)
+ | TInt32 -> "int32_t"
+ | TInt64 -> "int64_t"
+ | TList t -> assert false (* XXX not implemented *)
+ | 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 ->
+ 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"
+ | TUnion name -> sprintf "union wrap_%s" name
+
+let c_of_rtype = function
+ | RVoid -> "void"
+ | 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
+ pr "extern %s wrap_%s (wrap_h *w" (c_of_rtype ret) ep.ep_name;
+
+ (* Required parameters. *)
+ List.iter (
+ fun (name, t, _) ->
+ let t = c_of_ptype ~param:true t in
+ let sep = (* "const char *" - omit space after asterisk *)
+ let len = String.length t in
+ if isalnum t.[len-1] then " " else "" in
+ pr ", %s%s%s" t sep name
+ ) req;
+
+ (* Optional parameters. *)
+ if opt <> [] then
+ pr ", ...";
+
+ 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
+ * are not familiar with man pages or don't have the documentation
+ * installed, it is also available online at http://wrappi.org/
+ */
+
#ifndef WRAPPI_H_
#define WRAPPI_H_
extern \"C\" {
#endif
+#include <stdint.h>
+
+/* 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 "};\n";
+ pr "typedef int wrap_%s_enum;\n" name;
+ 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);
+extern void wrap_close (wrap_h *w);
+
+";
+
+ (* Separate the local and remote functions. *)
+ pr "\
+/* Handle functions. */
+";
+ iter_entry_points api (fun ep -> if ep.ep_local then pr_extern_decl ep);
+
+ pr "\
+
+/* API entry points. */
+";
+ iter_entry_points api (fun ep -> if not ep.ep_local then pr_extern_decl ep);
+
+ pr "\
+
+/* C API introspection. */
+";
+ iter_entry_points api (
+ fun ep ->
+ let name = ep.ep_name in
+ let ret, req, opt = ep.ep_ftype in
+
+ pr "struct wrap_%s_args {\n" name;
+ List.iter (
+ fun (n, t, _) ->
+ let t = c_of_ptype ~param:true t in
+ let sep = (* "const char *" - omit space after asterisk *)
+ let len = String.length t in
+ if isalnum t.[len-1] then " " else "" in
+ pr " %s%s%s;\n" t sep n
+ ) req;
+ pr "};\n";
+ pr "\n";
+
+ if opt <> [] then assert false; (* XXX not implemented *)
+
+ pr "struct wrap_%s_ret {\n" name;
+ (match ret with
+ | RVoid -> ()
+ | RStaticString -> pr " const char *r;\n";
+ | Return t ->
+ let t = c_of_ptype ~param:false t in
+ let sep = (* "const char *" - omit space after asterisk *)
+ let len = String.length t in
+ if isalnum t.[len-1] then " " else "" in
+ pr " %s%sr;\n" t sep
+ );
+
+ pr "};\n";
+ pr "\n";
+ );
+
+ pr "\
+extern void wrap_call (wrap_h *w, const char *name, const void *args, void *ret);
+extern size_t wrap_call_get_args_struct_size (wrap_h *w, const char *name);
+extern size_t wrap_call_get_ret_struct_size (wrap_h *w, const char *name);
+extern /* xdrproc_t */ void *wrap_call_get_args_xdrproc (wrap_h *w, const char *name);
+extern /* xdrproc_t */ void *wrap_call_get_ret_xdrproc (wrap_h *w, const char *name);
#ifdef __cplusplus
}
#endif /* WRAPPI_H_ */
"
+let generate_lib_call_c api =
+ generate_header inputs CStyle LGPLv2plus;
+
+ pr "\
+#include <config.h>
+
+#include <stdio.h>
+
+#include \"wrappi.h\"
+#include \"internal.h\"
+
+void
+wrap_call (wrap_h *w, const char *name, const void *args, void *ret)
+{
+ int proc;
+
+ proc = wrap_int_lookup_proc_entry (name);
+ if (proc == -1) {
+ set_error (\"procedure not found: %%s\", name);
+ return;
+ }
+
+ /* This ends up calling wrap_int_call_<name>. */
+ wrap_int_proc_table[proc].call (w, args, ret);
+}
+
+size_t
+wrap_call_get_args_struct_size (wrap_h *w, const char *name)
+{
+ int proc;
+
+ proc = wrap_int_lookup_proc_entry (name);
+ if (proc == -1) {
+ set_error (\"procedure not found: %%s\", name);
+ return 0;
+ }
+
+ return wrap_int_proc_table[proc].args_struct_size;
+}
+
+size_t
+wrap_call_get_ret_struct_size (wrap_h *w, const char *name)
+{
+ int proc;
+
+ proc = wrap_int_lookup_proc_entry (name);
+ if (proc == -1) {
+ set_error (\"procedure not found: %%s\", name);
+ return 0;
+ }
+
+ return wrap_int_proc_table[proc].ret_struct_size;
+}
+
+/* Really this returns xdrproc_t but we don't want to have to include
+ * XDR headers in the public API.
+ */
+void *
+wrap_call_get_args_xdrproc (wrap_h *w, const char *name)
+{
+ int proc;
+
+ proc = wrap_int_lookup_proc_entry (name);
+ if (proc == -1) {
+ set_error (\"procedure not found: %%s\", name);
+ return 0;
+ }
+
+ return wrap_int_proc_table[proc].args_xdrproc;
+}
+
+/* Really this returns xdrproc_t but we don't want to have to include
+ * XDR headers in the public API.
+ */
+void *
+wrap_call_get_ret_xdrproc (wrap_h *w, const char *name)
+{
+ int proc;
+
+ proc = wrap_int_lookup_proc_entry (name);
+ if (proc == -1) {
+ set_error (\"procedure not found: %%s\", name);
+ return 0;
+ }
+
+ return wrap_int_proc_table[proc].ret_xdrproc;
+}
+";
+
+ iter_entry_points api (
+ fun ep ->
+ pr "\n";
+
+ let name = ep.ep_name in
+ let ret, req, opt = ep.ep_ftype in
+
+ pr "void\n";
+ pr "wrap_int_call_%s (wrap_h *w, const void *argsv, void *retv)\n" name;
+ pr "{\n";
+ if req <> [] || opt <> [] then
+ pr " const struct wrap_%s_args *args = argsv;\n" name;
+ if ret <> RVoid then
+ pr " struct wrap_%s_ret *ret = retv;\n" name;
+ pr "\n";
+
+ pr " ";
+ (match ret with
+ | RVoid -> ()
+ | _ -> pr "ret->r = "
+ );
+
+ pr "wrap_%s (w" name;
+ List.iter (fun (n, _, _) -> pr ", args->%s" n) req;
+
+ if opt <> [] then assert false; (* XXX not implemented *)
+
+ pr ");\n";
+ pr "}\n";
+ )
+
+(* 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 <config.h>
+
+#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/call.c" generate_lib_call_c api;
+ output_to "lib/free_structs.c" generate_lib_free_structs_c api