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 *)
| 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"
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 <config.h>
#include <stdio.h>
(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 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
);
pr_defn ep;
pr "{\n";
- pr " assert (w->scheme == NULL); /* XXX */;\n";
+ pr " /* XXX Argument precondition checks here. */\n";
pr "\n";
- pr " ";
+ pr " if (w->scheme == WRAP_SCHEME_LOCAL) {\n";
+ pr " /* Local connection. */\n";
+ pr " ";
+ let name = ep.ep_name in
let ret, req, opt = ep.ep_ftype in
(match ret with
| _ -> pr "return "
);
- pr "impl_%s ((struct wrap_internal_h *)w" ep.ep_name;
+ pr "impl_%s ((struct wrap_internal_h *)w" name;
(* Required parameters. *)
- List.iter (fun (name, _, _) -> pr ", %s" name) req;
+ List.iter (fun (n, _, _) -> pr ", %s" n) req;
(* Optional parameters. *)
if opt <> [] then
pr ");\n";
(match ret with
- | RVoid -> pr " return;\n"
+ | RVoid -> pr " return;\n"
| _ -> ()
);
+ pr " } else {\n";
+ pr " /* Remote connection. */\n";
+ pr " struct wrap_%s_args args;\n" name;
+ pr " struct wrap_%s_ret ret;\n" name;
+ pr "\n";
+ List.iter (fun (n, _, _) -> pr " args.%s = %s;\n" n n) req;
+
+ if opt <> [] then assert false; (* XXX not implemented *)
+ pr "\n";
+
+ pr " memset (&ret, 0, sizeof ret);\n";
+ pr "\n";
+
+ pr " wrap_int_make_request (w, wrap_int_%s_num,\n" name;
+ pr " &args, &ret);\n";
+
+ (match ret with
+ | RVoid -> ()
+ | _ ->
+ pr "\n";
+ pr " return ret.r;\n"
+ );
+
+ pr " }\n";
+
pr "}\n"
)
+let generate_lib_internal_procs_h api =
+ generate_header inputs CStyle LGPLv2plus;
+
+ pr "\
+#ifndef WRAPPI_INTERNAL_PROCS_H_
+#define WRAPPI_INTERNAL_PROCS_H_
+
+";
+
+ pr "\
+/* NOTE: These constants can change with each run of the generator.
+ * They are only for internal use within the library, eg. for indexing
+ * arrays. The constants must not 'escape' from the library into
+ * on-the-wire formats etc.
+ */
+enum {
+";
+
+ iter_entry_points api (
+ fun ep -> pr " wrap_int_%s_num,\n" ep.ep_name
+ );
+
+ pr "};\n";
+ pr "\n";
+
+ pr "#define wrap_int_nr_procs %d\n" (StringMap.cardinal api.api_entry_points);
+
+ pr "\n";
+ pr "#endif /* WRAPPI_INTERNAL_PROCS_H_ */\n"
+
+let generate_lib_internal_procs_c api =
+ generate_header inputs CStyle LGPLv2plus;
+
+ pr "\
+#include <config.h>
+
+#include <stdlib.h>
+
+#include \"wrappi.h\"
+#include \"internal.h\"
+
+/* Defined in lib/call.c */
+";
+
+ iter_entry_points api (
+ fun ep ->
+ pr "extern void wrap_int_call_%s (wrap_h *w, const void *args, void *ret);\n" ep.ep_name
+ );
+ pr "\n";
+
+ pr "/* Defined in lib/xdr.c */\n";
+
+ iter_entry_points api (
+ fun ep ->
+ let name = ep.ep_name in
+ pr "extern bool_t wrap_int_xdr_%s_args (XDR *, struct wrap_%s_args *);\n" name name;
+ pr "extern bool_t wrap_int_xdr_%s_ret (XDR *, struct wrap_%s_ret *);\n" name name
+ );
+ pr "\n";
+
+ pr "const struct proc_table wrap_int_proc_table[] = {\n";
+
+ iter_entry_points api (
+ fun ep ->
+ let name = ep.ep_name in
+ pr " [wrap_int_%s_num] = {\n" name;
+ pr " .name = \"%s\",\n" name;
+ pr " .args_struct_size = sizeof (struct wrap_%s_args),\n" name;
+ pr " .ret_struct_size = sizeof (struct wrap_%s_ret),\n" name;
+ pr " .call = &wrap_int_call_%s,\n" name;
+ pr " .args_xdrproc = (xdrproc_t) &wrap_int_xdr_%s_args,\n" name;
+ pr " .ret_xdrproc = (xdrproc_t) &wrap_int_xdr_%s_ret,\n" name;
+ pr " },\n"
+ );
+
+ pr "};\n"
+
+let generate_lib_internal_procs_lookup_gperf api =
+ generate_header inputs CStyle LGPLv2plus;
+
+ pr "\
+%%language=ANSI-C
+%%define lookup-function-name wrap_int_gperf_lookup_proc_entry
+%%readonly-tables
+%%null-strings
+
+%%{
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include \"wrappi.h\"
+#include \"internal.h\"
+%%}
+
+struct proc_entry;
+
+%%%%
+";
+
+ iter_entry_points api (
+ fun ep ->
+ let name = ep.ep_name in
+ pr "%s, wrap_int_%s_num\n" name name
+ )
+
(* Make a unique, reproducible filename for each entry point. *)
let filename_of_ep ep =
let filename = Loc.file_name ep.ep_loc in
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
)
);
- let gitignores = List.rev !gitignores in
- output_to "lib/.gitignore"
- (fun () -> List.iter (pr "%s\n") gitignores) ();
+ output_to "lib/internal-procs.h"
+ generate_lib_internal_procs_h api;
+
+ output_to "lib/internal-procs.c"
+ generate_lib_internal_procs_c api;
+
+ output_to "lib/internal-procs-lookup.gperf"
+ generate_lib_internal_procs_lookup_gperf api;
output_to "lib/implementation_files.mk"
- generate_lib_implementation_files_mk api
+ generate_lib_implementation_files_mk api;
+
+ let gitignores = List.rev !gitignores in
+ output_to "lib/.gitignore"
+ (fun () -> List.iter (pr "%s\n") gitignores) ()