entry_point local void connect ()
-(* XXX Should scheme be an enum? *)
-entry_point local void set_scheme (string scheme)
+enum scheme ["local"; "ssh"] ;;
+entry_point local void set_scheme (enum scheme scheme)
entry_point local void set_hostname (string hostname)
noinst_PROGRAMS = remote
remote_SOURCES = remote.c
-remote_CFLAGS = -I../lib
+remote_CFLAGS = \
+ -I../lib \
+ $(WARN_CFLAGS) $(WERROR_CFLAGS)
remote_LDADD = ../lib/libwrappi.la
CLEANFILES = *~
* simply comment out the next two lines, then wrappi will run the
* commands on the local machine.
*/
- wrap_set_scheme (w, "ssh");
+ wrap_set_scheme (w, WRAP_SCHEME_SSH);
wrap_set_hostname (w, hostname);
/* Connect the handle. Because we didn't set any error handler,
Wrappi_accumulator.add_typedef td
>>
+let add_enum _loc name identifiers =
+ let loc = expr_of_loc _loc _loc in
+
+ <:str_item<
+ let en = { Wrappi_types.en_loc = $loc$;
+ en_name = $str:name$;
+ en_identifiers = Array.of_list $identifiers$ } in
+ Wrappi_accumulator.add_enum en
+ >>
+
let () =
(* Quotation expander for C code. *)
let c_quotation_expander _loc _ code =
ptype: [
[ "bool" -> <:expr< Wrappi_types.TBool >> ]
| [ "buffer" -> <:expr< Wrappi_types.TBuffer >> ]
- (* enum XXX *)
+ | [ "enum"; name = LIDENT -> <:expr< Wrappi_types.TEnum $str:name$ >> ]
| [ "file" -> <:expr< Wrappi_types.TFile >> ]
| [ "hash"; "("; t = ptype; ")" -> <:expr< Wrappi_types.THash $t$ >> ]
| [ "int" -> <:expr< Wrappi_types.TInt >> ]
| [ "struct"; name = LIDENT -> <:expr< Wrappi_types.TStruct $str:name$ >> ]
| [ "uint32" -> <:expr< Wrappi_types.TUInt32 >> ]
| [ "uint64" -> <:expr< Wrappi_types.TUInt64 >> ]
- (* union XXX *)
+ | [ "union"; name = LIDENT -> <:expr< Wrappi_types.TUnion $str:name$ >> ]
| [ name = LIDENT -> <:expr< Wrappi_types.TTypedef $str:name$ >> ]
];
->
add_entry_point _loc local name parameters rtype code includes
]
+
+ | [ "enum"; name = LIDENT; identifiers = expr ->
+ add_enum _loc name identifiers
+ ]
+
| [ "typedef"; t = ptype; name = LIDENT ->
add_typedef _loc name t
]
wrappi_c_impl.cmi:
wrappi_c_impl.cmo: wrappi_pr.cmi wrappi_boilerplate.cmi wrappi_c_impl.cmi
wrappi_c_impl.cmx: wrappi_pr.cmx wrappi_boilerplate.cmx wrappi_c_impl.cmi
-wrappi_main.cmo: wrappi_pr.cmi wrappi_c_impl.cmi wrappi_c.cmi
-wrappi_main.cmx: wrappi_pr.cmx wrappi_c_impl.cmx wrappi_c.cmx
+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_pr.cmi:
wrappi_pr.cmo: wrappi_pr.cmi
wrappi_pr.cmx: wrappi_pr.cmi
wrappi_c_impl.ml \
wrappi_c.mli \
wrappi_c.ml \
+ wrappi_enums.mli \
+ wrappi_enums.ml \
wrappi_main.ml \
wrappi_pr.mli \
wrappi_pr.ml
OBJECTS = \
wrappi_pr.cmo \
wrappi_boilerplate.cmo \
+ wrappi_enums.cmo \
wrappi_c_impl.cmo \
wrappi_c.cmo \
wrappi_main.cmo
| ErlangStyle
type license = GPLv2plus | LGPLv2plus
-let generate_header comment license =
- let inputs = [ "generator/wrappi_*.ml" ] in
+let generate_header inputs comment license =
let c = match comment with
| CStyle -> pr "/* "; " *"
| CPlusPlusStyle -> pr "// "; "//"
| ErlangStyle
type license = GPLv2plus | LGPLv2plus
-val generate_header : comment_style -> license -> unit
+val generate_header : string list -> comment_style -> license -> unit
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 *)
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
/* 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 " WRAP_%s_ENUM_MAX = %d\n"
+ (String.uppercase name) (Array.length en.en_identifiers);
+ pr "};\n";
+ pr "typedef int wrap_%s_enum;\n" name;
+ pr "\n";
+ );
+
+ pr "\
/* Connection management. */
extern wrap_h *wrap_create (void);
extern void wrap_close (wrap_h *w);
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 *)
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 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 "\n";
- pr " ";
+ pr " if (w->scheme == NULL) {\n";
+ pr " /* Local connection. */\n";
+ pr " ";
let ret, req, opt = ep.ep_ftype in
pr ");\n";
(match ret with
- | RVoid -> pr " return;\n"
+ | RVoid -> pr " return;\n"
| _ -> ()
);
+ pr " } else {\n";
+ pr " /* Remote connection. */\n";
+ pr " abort (); /* XXX */\n";
+ pr " }\n";
+
pr "}\n"
)
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
--- /dev/null
+(* 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
+
+let extend_api api =
+ let eps = ref api.api_entry_points in
+
+ iter_enums api (
+ fun en ->
+ let name = en.en_name in
+
+ (* Add an entry point wrap_<name>_enum_to_string. *)
+ let fname = sprintf "%s_enum_to_string" name in
+ let code =
+ let b = Buffer.create 512 in
+ bprintf b " switch (v) {\n";
+ Array.iter (
+ fun id ->
+ bprintf b " case WRAP_%s_%s: return \"%s\";\n"
+ (String.uppercase name) (String.uppercase id) id;
+ ) en.en_identifiers;
+ bprintf b " default:\n";
+ bprintf b " set_error (\"unknown enum case %%d\", v);\n";
+ bprintf b " return NULL;\n";
+ bprintf b " }\n";
+ Buffer.contents b in
+ let c_code = {
+ cc_loc = Loc.ghost;
+ cc_code = code;
+ } in
+ let ep = {
+ ep_loc = Loc.ghost;
+ ep_local = true;
+ ep_name = fname;
+ ep_ftype = RStaticString, ["v", TEnum name, None], [];
+ ep_code = Some c_code;
+ ep_includes = []
+ } in
+
+ eps := StringMap.add fname ep !eps;
+
+ (* Add an entry point wrap_<name>_string_to_enum. *)
+ let fname = sprintf "%s_string_to_enum" name in
+ let code =
+ let b = Buffer.create 512 in
+ Array.iter (
+ fun id ->
+ bprintf b " if (STREQ (v, \"%s\"))\n" id;
+ bprintf b " return WRAP_%s_%s;\n"
+ (String.uppercase name) (String.uppercase id);
+ ) en.en_identifiers;
+ bprintf b " set_error (\"unknown enum case %%s\", v);\n";
+ bprintf b " return -1;\n";
+ Buffer.contents b in
+ let c_code = {
+ cc_loc = Loc.ghost;
+ cc_code = code;
+ } in
+ let ep = {
+ ep_loc = Loc.ghost;
+ ep_local = true;
+ ep_name = fname;
+ ep_ftype = Return (TEnum name), ["v", TString, None], [];
+ ep_code = Some c_code;
+ ep_includes = []
+ } in
+
+ eps := StringMap.add fname ep !eps
+ );
+
+ { api with api_entry_points = !eps }
--- /dev/null
+(* 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 converting enums to/from strings. *)
+
+val extend_api : Wrappi_types.api -> Wrappi_types.api
let nr_uns = StringMap.cardinal api.api_unions
let nr_eps = StringMap.cardinal api.api_entry_points
+(* Extend the API with some entry points which are purely
+ * generated from other things, eg. from enums.
+ *)
+let api = Wrappi_enums.extend_api api
+
let dump_and_exit () =
printf "typedefs (%d):\n" nr_tds;
iter_typedefs api (fun td -> printf " %s\n" (string_of_typedef td));
/error-get_error_func.c
/mkdir-mkdir.c
/mknod-mknod_char.c
+/ghost-location-scheme_enum_to_string.c
+/ghost-location-scheme_string_to_enum.c
}
void
-wrap_set_scheme (wrap_h *w, const char *scheme)
+wrap_set_scheme (wrap_h *w, wrap_scheme_enum scheme)
{
/* XXX */
}
# wrappi generated file
# WARNING: THIS FILE IS GENERATED FROM:
-# generator/wrappi_*.ml
+# wrappi_c_impl.ml
# ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.
#
# Copyright (C) 2011-2012 Red Hat Inc.
error-error.c \
error-get_errno.c \
error-get_error.c \
- error-get_error_func.c
+ error-get_error_func.c \
+ ghost-location-scheme_enum_to_string.c \
+ ghost-location-scheme_string_to_enum.c
remote_implementation_files := \
filesize-filesize.c \