X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;ds=sidebyside;f=generator%2Fwrappi_c.ml;h=5a7366058b44a467db602a813ca756afa2892d76;hb=cf654cde5cfc9337e254934b23274e4a7b3432ba;hp=3011ab10bc70c83a122b08196cc8eb270054afbe;hpb=b5d8f76790194561f08fb500b3cc2cb10504199e;p=wrappi.git diff --git a/generator/wrappi_c.ml b/generator/wrappi_c.ml index 3011ab1..5a73660 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 *) @@ -36,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" @@ -44,8 +48,28 @@ let c_of_ptype ~param = function 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 @@ -68,7 +92,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 @@ -88,6 +112,47 @@ 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 "};\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); @@ -108,6 +173,50 @@ extern void wrap_close (wrap_h *w); 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 @@ -115,5 +224,173 @@ extern void wrap_close (wrap_h *w); #endif /* WRAPPI_H_ */ " +let generate_lib_call_c api = + generate_header inputs CStyle LGPLv2plus; + + pr "\ +#include + +#include + +#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_. */ + 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 + +#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/call.c" generate_lib_call_c api; + output_to "lib/free_structs.c" generate_lib_free_structs_c api