Add structs.
[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 ->
42     if param then sprintf "const struct wrap_%s *" name
43     else sprintf "struct wrap_%s *" name
44   | TTypedef name -> assert false (* should never happen *)
45   | TUInt32 -> "uint32_t"
46   | TUInt64 -> "uint64_t"
47   | TUnion name -> sprintf "union wrap_%s" name
48
49 let c_of_rtype = function
50   | RVoid -> "void"
51   | RStaticString -> "const char *"
52   | Return t -> c_of_ptype ~param:false t
53
54 let field_of_ptype = function
55   | TBool -> "int"
56   | TBuffer -> assert false (* XXX not implemented *)
57   | TEnum name -> sprintf "wrap_%s_enum" name
58   | TFile -> assert false (* cannot occur in a struct *)
59   | THash t -> "char **"
60   | TInt -> "int" (* XXX not int, correct type depends on preconditions *)
61   | TInt32 -> "int32_t"
62   | TInt64 -> "int64_t"
63   | TList t -> assert false (* XXX not implemented *)
64   | TNullable TString -> "char *"
65   | TNullable _ -> assert false (* XXX may be implemented in future *)
66   | TString -> "char *"
67   | TStruct name -> assert false (* we don't allow struct/union here *)
68   | TTypedef name -> assert false (* should never happen *)
69   | TUInt32 -> "uint32_t"
70   | TUInt64 -> "uint64_t"
71   | TUnion name ->  assert false (* we don't allow struct/union here *)
72
73 (* Print the extern... declaration of a single entry point. *)
74 let pr_extern_decl ep =
75   let ret, req, opt = ep.ep_ftype in
76   pr "extern %s wrap_%s (wrap_h *w" (c_of_rtype ret) ep.ep_name;
77
78   (* Required parameters. *)
79   List.iter (
80     fun (name, t, _) ->
81       let t = c_of_ptype ~param:true t in
82       let sep = (* "const char *" - omit space after asterisk *)
83         let len = String.length t in
84         if isalnum t.[len-1] then " " else "" in
85       pr ", %s%s%s" t sep name
86   ) req;
87
88   (* Optional parameters. *)
89   if opt <> [] then
90     pr ", ...";
91
92   pr ");\n"
93
94 let generate_lib_wrappi_h api =
95   generate_header inputs CStyle LGPLv2plus;
96
97   pr "\
98 /* Please read the wrappi(1) man page for full documentation.  If you
99  * are not familiar with man pages or don't have the documentation
100  * installed, it is also available online at http://wrappi.org/
101  */
102
103 #ifndef WRAPPI_H_
104 #define WRAPPI_H_
105
106 #ifdef __cplusplus
107 extern \"C\" {
108 #endif
109
110 #include <stdint.h>
111
112 /* The handle. */
113 typedef struct wrap_h wrap_h;
114
115 /* Types. */
116 ";
117
118   iter_enums api (
119     fun en ->
120       let name = en.en_name in
121
122       (* The C compiler may choose to declare the sizeof(enum) ==
123        * sizeof(char), and adding fields to such an enum later could
124        * cause ABI breakage.  (See the gcc --fshort-enums option for one
125        * example of this).  Therefore use the enum just to declare the
126        * values, and typedef the enum as an int.
127        *)
128       pr "enum {\n";
129
130       Array.iteri (
131         fun i id ->
132           pr "  WRAP_%s_%s = %d,\n"
133             (String.uppercase name) (String.uppercase id) i
134       ) en.en_identifiers;
135       pr "};\n";
136       pr "typedef int wrap_%s_enum;\n" name;
137       pr "\n";
138   );
139
140   iter_structs api (
141     fun sd ->
142       let name = sd.sd_name in
143
144       pr "struct wrap_%s {\n" name;
145
146       Array.iter (
147         fun (name, t) ->
148           pr "  %s %s;\n" (field_of_ptype t) name
149       ) sd.sd_fields;
150       pr "};\n";
151       pr "void wrap_free_%s (struct wrap_%s *);\n" name name;
152       pr "\n"
153   );
154
155   pr "\
156 /* Connection management. */
157 extern wrap_h *wrap_create (void);
158 extern void wrap_close (wrap_h *w);
159
160 ";
161
162   (* Separate the local and remote functions. *)
163   pr "\
164 /* Handle functions. */
165 ";
166   iter_entry_points api (fun ep -> if ep.ep_local then pr_extern_decl ep);
167
168   pr "\
169
170 /* API entry points. */
171 ";
172   iter_entry_points api (fun ep -> if not ep.ep_local then pr_extern_decl ep);
173
174   pr "\
175
176 #ifdef __cplusplus
177 }
178 #endif
179
180 #endif /* WRAPPI_H_ */
181 "
182
183 (* Functions for freeing structs are part of the C bindings.  We don't
184  * want them to be exposed in other languages, although they will be
185  * used by other bindings.
186  *)
187 let generate_lib_free_structs_c api =
188   generate_header inputs CStyle LGPLv2plus;
189
190   pr "\
191 #include <stdlib.h>
192
193 #include \"wrappi.h\"
194 ";
195
196   iter_structs api (
197     fun sd ->
198       pr "\n";
199
200       let name = sd.sd_name in
201
202       pr "void\n";
203       pr "wrap_free_%s (struct wrap_%s *v)\n" name name;
204       pr "{\n";
205
206       Array.iter (
207         fun (n, t) ->
208           match t with
209           | TBool | TEnum _ | TInt | TInt32 | TInt64 | TUInt32 | TUInt64 ->
210             () (* these don't need to be freed *)
211           | TBuffer -> assert false (* XXX not implemented *)
212           | TFile
213           | TNullable TString
214           | TString ->
215             pr "  free (v->%s);\n" n
216           | THash t -> assert false (* XXX not implemented *)
217           | TList t -> assert false (* XXX not implemented *)
218           | TNullable _ -> assert false (* XXX may be implemented in future *)
219           | TStruct name -> assert false (* cannot occur in structs *)
220           | TTypedef name -> assert false (* should never happen *)
221           | TUnion name -> assert false (* cannot occur in structs *)
222       ) sd.sd_fields;
223       pr "  free (v);\n";
224       pr "}\n"
225   )
226
227 let generate api =
228   output_to "lib/wrappi.h" generate_lib_wrappi_h api;
229   output_to "lib/free_structs.c" generate_lib_free_structs_c api