More enums.
[wrappi.git] / generator / wrappi_c.ml
1 (* wrappi
2  * Copyright (C) 2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *)
18
19 open Wrappi_types
20 open Wrappi_utils
21 open Wrappi_pr
22 open Wrappi_boilerplate
23
24 open Printf
25
26 let inputs = ["wrappi_c.ml"]
27
28 let c_of_ptype ~param = function
29   | TBool -> "int"
30   | TBuffer -> assert false (* XXX not implemented *)
31   | TEnum name -> sprintf "wrap_%s_enum" name
32   | TFile -> if param then "const char *" else "char *"
33   | THash t -> if param then "char * const *" else "char **"
34   | TInt -> "int" (* XXX not int, correct type depends on preconditions *)
35   | TInt32 -> "int32_t"
36   | TInt64 -> "int64_t"
37   | TList t -> assert false (* XXX not implemented *)
38   | TNullable TString -> if param then "const char *" else "char *"
39   | TNullable _ -> assert false (* XXX may be implemented in future *)
40   | TString -> if param then "const char *" else "char *"
41   | TStruct name -> sprintf "struct wrap_%s" name
42   | TTypedef name -> assert false (* should never happen *)
43   | TUInt32 -> "uint32_t"
44   | TUInt64 -> "uint64_t"
45   | TUnion name -> sprintf "union wrap_%s" name
46
47 let c_of_rtype = function
48   | RVoid -> "void"
49   | RStaticString -> "const char *"
50   | Return t -> c_of_ptype ~param:false t
51
52 (* Print the extern... declaration of a single entry point. *)
53 let pr_extern_decl ep =
54   let ret, req, opt = ep.ep_ftype in
55   pr "extern %s wrap_%s (wrap_h *w" (c_of_rtype ret) ep.ep_name;
56
57   (* Required parameters. *)
58   List.iter (
59     fun (name, t, _) ->
60       let t = c_of_ptype ~param:true t in
61       let sep = (* "const char *" - omit space after asterisk *)
62         let len = String.length t in
63         if isalnum t.[len-1] then " " else "" in
64       pr ", %s%s%s" t sep name
65   ) req;
66
67   (* Optional parameters. *)
68   if opt <> [] then
69     pr ", ...";
70
71   pr ");\n"
72
73 let generate_lib_wrappi_h api =
74   generate_header inputs CStyle LGPLv2plus;
75
76   pr "\
77 /* Please read the wrappi(1) man page for full documentation.  If you
78  * are not familiar with man pages or don't have the documentation
79  * installed, it is also available online at http://wrappi.org/
80  */
81
82 #ifndef WRAPPI_H_
83 #define WRAPPI_H_
84
85 #ifdef __cplusplus
86 extern \"C\" {
87 #endif
88
89 #include <stdint.h>
90
91 /* The handle. */
92 typedef struct wrap_h wrap_h;
93
94 /* Types. */
95 ";
96
97   iter_enums api (
98     fun en ->
99       let name = en.en_name in
100
101       (* The C compiler may choose to declare the sizeof(enum) ==
102        * sizeof(char), and adding fields to such an enum later could
103        * cause ABI breakage.  (See the gcc --fshort-enums option for one
104        * example of this).  Therefore use the enum just to declare the
105        * values, and typedef the enum as an int.
106        *)
107       pr "enum {\n";
108
109       Array.iteri (
110         fun i id ->
111           pr "  WRAP_%s_%s = %d,\n"
112             (String.uppercase name) (String.uppercase id) i
113       ) en.en_identifiers;
114       pr "};\n";
115       pr "typedef int wrap_%s_enum;\n" name;
116       pr "\n";
117   );
118
119   pr "\
120 /* Connection management. */
121 extern wrap_h *wrap_create (void);
122 extern void wrap_close (wrap_h *w);
123
124 ";
125
126   (* Separate the local and remote functions. *)
127   pr "\
128 /* Handle functions. */
129 ";
130   iter_entry_points api (fun ep -> if ep.ep_local then pr_extern_decl ep);
131
132   pr "\
133
134 /* API entry points. */
135 ";
136   iter_entry_points api (fun ep -> if not ep.ep_local then pr_extern_decl ep);
137
138   pr "\
139
140 #ifdef __cplusplus
141 }
142 #endif
143
144 #endif /* WRAPPI_H_ */
145 "
146
147 let generate api =
148   output_to "lib/wrappi.h" generate_lib_wrappi_h api