Fixed some issues found by winapi_check.
[wine] / tools / widl / header.c
1 /*
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #include <string.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <signal.h>
32
33 #include "widl.h"
34 #include "utils.h"
35 #include "parser.h"
36 #include "header.h"
37 #include "proxy.h"
38
39 static int indentation = 0;
40
41 static void indent(int delta)
42 {
43   int c;
44   if (delta < 0) indentation += delta;
45   for (c=0; c<indentation; c++) fprintf(header, "    ");
46   if (delta > 0) indentation += delta;
47 }
48
49 int is_void(type_t *t, var_t *v)
50 {
51   if (v && v->ptr_level) return 0;
52   if (!t->type && !t->ref) return 1;
53   return 0;
54 }
55
56 static void write_pident(var_t *v)
57 {
58   int c;
59   for (c=0; c<v->ptr_level; c++) {
60     fprintf(header, "*");
61   }
62   if (v->name) fprintf(header, "%s", v->name);
63 }
64
65 void write_name(FILE *h, var_t *v)
66 {
67   fprintf(h, "%s", v->name);
68 }
69
70 char* get_name(var_t *v)
71 {
72   return v->name;
73 }
74
75 static void write_fields(FILE *h, var_t *v)
76 {
77   if (!v) return;
78   while (NEXT_LINK(v)) v = NEXT_LINK(v);
79   while (v) {
80     if (v->type) {
81       indent(0);
82       write_type(h, v->type, NULL, v->tname);
83       if (get_name(v)) {
84         fprintf(header, " ");
85         write_pident(v);
86       }
87       fprintf(header, ";\n");
88     }
89     v = PREV_LINK(v);
90   }
91 }
92
93 void write_type(FILE *h, type_t *t, var_t *v, char *n)
94 {
95   int c;
96
97   if (n) fprintf(h, "%s", n);
98   else {
99     if (t->is_const) fprintf(h, "const ");
100     if (t->type) {
101       switch (t->type) {
102       case RPC_FC_BYTE:
103         fprintf(h, "byte");
104         break;
105       case RPC_FC_CHAR:
106         fprintf(h, "char");
107         break;
108       case RPC_FC_USHORT:
109         fprintf(h, "unsigned ");
110       case RPC_FC_SHORT:
111         if (t->ref) fprintf(h, t->ref->name);
112         fprintf(h, "short");
113         break;
114       case RPC_FC_ULONG:
115         fprintf(h, "unsigned ");
116       case RPC_FC_LONG:
117         if (t->ref) fprintf(h, t->ref->name);
118         else fprintf(h, "long");
119         break;
120       case RPC_FC_STRUCT:
121         if (t->defined && !t->written) {
122           if (t->name) fprintf(h, "struct %s {\n", t->name);
123           else fprintf(h, "struct {\n");
124           indentation++;
125           write_fields(h, t->fields);
126           indent(-1);
127           fprintf(h, "}");
128         }
129         else fprintf(h, "struct %s", t->name);
130         break;
131       case RPC_FC_NON_ENCAPSULATED_UNION:
132         if (t->defined && !t->written) {
133           if (t->name) fprintf(h, "union %s {\n", t->name);
134           else fprintf(h, "union {\n");
135           indentation++;
136           write_fields(h, t->fields);
137           indent(-1);
138           fprintf(h, "}");
139         }
140         else fprintf(h, "union %s", t->name);
141         break;
142       default:
143         fprintf(h, "(unknown-type:%d)", t->type);
144       }
145     }
146     else {
147       if (t->ref) {
148         write_type(h, t->ref, NULL, t->name);
149       }
150       else fprintf(h, "void");
151     }
152   }
153   if (v) {
154     for (c=0; c<v->ptr_level; c++) {
155       fprintf(h, "*");
156     }
157   }
158 }
159
160 void write_typedef(type_t *type, var_t *names)
161 {
162   char *tname = names->tname;
163   while (NEXT_LINK(names)) names = NEXT_LINK(names);
164   fprintf(header, "typedef ");
165   write_type(header, type, NULL, tname);
166   fprintf(header, " ");
167   while (names) {
168     write_pident(names);
169     if (PREV_LINK(names))
170       fprintf(header, ", ");
171     names = PREV_LINK(names);
172   }
173   fprintf(header, ";\n");
174 }
175
176 /********** INTERFACES **********/
177
178 int is_object(attr_t *a)
179 {
180   while (a) {
181     if (a->type == ATTR_OBJECT) return 1;
182     a = NEXT_LINK(a);
183   }
184   return 0;
185 }
186
187 int is_local(attr_t *a)
188 {
189   while (a) {
190     if (a->type == ATTR_LOCAL) return 1;
191     a = NEXT_LINK(a);
192   }
193   return 0;
194 }
195
196 var_t *is_callas(attr_t *a)
197 {
198   while (a) {
199     if (a->type == ATTR_CALLAS) return a->u.pval;
200     a = NEXT_LINK(a);
201   }
202   return NULL;
203 }
204
205 static void write_method_def(type_t *iface)
206 {
207   func_t *cur = iface->funcs;
208   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
209   fprintf(header, "#define %s_METHODS", iface->name);
210   while (cur) {
211     var_t *def = cur->def;
212     if (!is_callas(def->attrs)) {
213       var_t *arg = cur->args;
214       int argc = 0;
215       if (arg) {
216         argc++;
217         while (NEXT_LINK(arg)) {
218           arg = NEXT_LINK(arg);
219           argc++;
220         }
221       }
222       fprintf(header, " \\\n");
223       if (!is_void(def->type, def)) {
224         if (argc)
225           fprintf(header, "    ICOM_METHOD%d (", argc);
226         else
227           fprintf(header, "    ICOM_METHOD  (");
228         write_type(header, def->type, def, def->tname);
229         fprintf(header, ",");
230       } else
231         if (argc)
232           fprintf(header, "    ICOM_VMETHOD%d(", argc);
233         else
234           fprintf(header, "    ICOM_VMETHOD (");
235       write_name(header, def);
236       while (arg) {
237         fprintf(header, ",");
238         write_type(header, arg->type, arg, arg->tname);
239         fprintf(header, ",");
240         write_name(header,arg);
241         arg = PREV_LINK(arg);
242       }
243       fprintf(header, ")");
244     }
245     cur = PREV_LINK(cur);
246   }
247   fprintf(header, "\n");
248 }
249
250 static int write_method_macro(type_t *iface, char *name)
251 {
252   int idx;
253   func_t *cur = iface->funcs;
254   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
255
256   if (iface->ref) idx = write_method_macro(iface->ref, name);
257   else idx = 0;
258   fprintf(header, "/*** %s methods ***/\n", iface->name);
259   while (cur) {
260     var_t *def = cur->def;
261     if (!is_callas(def->attrs)) {
262       var_t *arg = cur->args;
263       int argc = 0;
264       int c;
265       while (arg) {
266         arg = NEXT_LINK(arg);
267         argc++;
268       }
269
270       fprintf(header, "#define %s_", name);
271       write_name(header,def);
272       fprintf(header, "(p");
273       for (c=0; c<argc; c++)
274         fprintf(header, ",%c", c+'a');
275       fprintf(header, ") ");
276
277       if (argc)
278         fprintf(header, "ICOM_CALL%d(", argc);
279       else
280         fprintf(header, "ICOM_CALL(");
281       write_name(header,def);
282       fprintf(header, ",p");
283       for (c=0; c<argc; c++)
284         fprintf(header, ",%c", c+'a');
285       fprintf(header, ")\n");
286       if (cur->idx == -1) cur->idx = idx;
287       else if (cur->idx != idx) yyerror("BUG: method index mismatch in write_method_macro");
288       idx++;
289     }
290     cur = PREV_LINK(cur);
291   }
292   return idx;
293 }
294
295 void write_method_args(FILE *h, var_t *arg, char *name)
296 {
297   if (arg) {
298     while (NEXT_LINK(arg))
299       arg = NEXT_LINK(arg);
300   }
301   fprintf(h, "    %s* This", name);
302   while (arg) {
303     fprintf(h, ",\n    ");
304     write_type(h, arg->type, arg, arg->tname);
305     fprintf(h, " ");
306     write_name(h,arg);
307     arg = PREV_LINK(arg);
308   }
309 }
310
311 static void write_method_proto(type_t *iface)
312 {
313   func_t *cur = iface->funcs;
314   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
315   while (cur) {
316     var_t *def = cur->def;
317     var_t *cas = is_callas(def->attrs);
318     if (!is_local(def->attrs)) {
319       /* proxy prototype */
320       write_type(header, def->type, def, def->tname);
321       fprintf(header, " CALLBACK %s_", iface->name);
322       write_name(header,def);
323       fprintf(header, "_Proxy(\n");
324       write_method_args(header, cur->args, iface->name);
325       fprintf(header, ");\n");
326       /* stub prototype */
327       fprintf(header, "void __RPC_STUB %s_", iface->name);
328       write_name(header,def);
329       fprintf(header, "_Stub(\n");
330       fprintf(header, "    IRpcStubBuffer* This,\n");
331       fprintf(header, "    IRpcChannelBuffer* pRpcChannelBuffer,\n");
332       fprintf(header, "    PRPC_MESSAGE pRpcMessage,\n");
333       fprintf(header, "    DWORD* pdwStubPhase);\n");
334     }
335     if (cas) {
336       func_t *m = iface->funcs;
337       while (m && strcmp(get_name(m->def), cas->name))
338         m = NEXT_LINK(m);
339       if (m) {
340         var_t *mdef = m->def;
341         /* proxy prototype - use local prototype */
342         write_type(header, mdef->type, mdef, mdef->tname);
343         fprintf(header, " CALLBACK %s_", iface->name);
344         write_name(header, mdef);
345         fprintf(header, "_Proxy(\n");
346         write_method_args(header, m->args, iface->name);
347         fprintf(header, ");\n");
348         /* stub prototype - use remotable prototype */
349         write_type(header, def->type, def, def->tname);
350         fprintf(header, " __RPC_STUB %s_", iface->name);
351         write_name(header, mdef);
352         fprintf(header, "_Stub(\n");
353         write_method_args(header, cur->args, iface->name);
354         fprintf(header, ");\n");
355       }
356       else {
357         yywarning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name);
358       }
359     }
360
361     cur = PREV_LINK(cur);
362   }
363 }
364
365 void write_forward(type_t *iface)
366 {
367   if (!iface->written) {
368     fprintf(header, "typedef struct %s %s;\n", iface->name, iface->name);
369     iface->written = TRUE;
370   }
371 }
372
373 void write_interface(type_t *iface)
374 {
375   if (!is_object(iface->attrs)) {
376     if (!iface->funcs) return;
377     yywarning("RPC interfaces not supported yet\n");
378     return;
379   }
380
381   if (!iface->funcs) {
382     yywarning("%s has no methods", iface->name);
383     return;
384   }
385
386   fprintf(header, "/*****************************************************************************\n");
387   fprintf(header, " * %s interface\n", iface->name);
388   fprintf(header, " */\n");
389   write_forward(iface);
390   if (iface->ref)
391     fprintf(header, "#define ICOM_INTERFACE %s\n", iface->name);
392   write_method_def(iface);
393   fprintf(header, "#define %s_IMETHODS \\\n", iface->name);
394   if (iface->ref)
395     fprintf(header, "    %s_IMETHODS \\\n", iface->ref->name);
396   fprintf(header, "    %s_METHODS \\\n", iface->name);
397   if (iface->ref) {
398     fprintf(header, "ICOM_DEFINE(%s,%s)\n", iface->name, iface->ref->name);
399     fprintf(header, "#undef ICOM_INTERFACE\n");
400   }
401   fprintf(header, "\n");
402   write_method_macro(iface, iface->name);
403   fprintf(header, "\n");
404   write_method_proto(iface);
405   fprintf(header, "\n");
406
407   if (!is_local(iface->attrs))
408     write_proxy(iface);
409 }