Added "generate headers only" command-line option. Implemented imports
[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(FILE *h, var_t *v)
57 {
58   int c;
59   for (c=0; c<v->ptr_level; c++) {
60     fprintf(h, "*");
61   }
62   if (v->name) fprintf(h, "%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_array(FILE *h, expr_t *v)
76 {
77   if (!v) return;
78   while (NEXT_LINK(v)) v = NEXT_LINK(v);
79   fprintf(h, "[");
80   while (v) {
81     if (v->type == EXPR_NUM)
82       fprintf(h, "%ld", v->u.lval); /* statically sized array */
83     else
84       fprintf(h, "1"); /* dynamically sized array */
85     if (PREV_LINK(v))
86       fprintf(h, ", ");
87     v = PREV_LINK(v);
88   }
89   fprintf(h, "]");
90 }
91
92 static void write_field(FILE *h, var_t *v)
93 {
94   if (!v) return;
95   if (v->type) {
96     indent(0);
97     write_type(h, v->type, NULL, v->tname);
98     if (get_name(v)) {
99       fprintf(h, " ");
100       write_pident(h, v);
101     }
102     write_array(h, v->array);
103     fprintf(h, ";\n");
104   }
105 }
106
107 static void write_fields(FILE *h, var_t *v)
108 {
109   var_t *first = v;
110   if (!v) return;
111   while (NEXT_LINK(v)) v = NEXT_LINK(v);
112   while (v) {
113     write_field(h, v);
114     if (v == first) break;
115     v = PREV_LINK(v);
116   }
117 }
118
119 static void write_enums(FILE *h, var_t *v)
120 {
121   if (!v) return;
122   while (NEXT_LINK(v)) v = NEXT_LINK(v);
123   while (v) {
124     if (get_name(v)) {
125       indent(0);
126       write_name(h, v);
127       if (v->has_val)
128         fprintf(h, " = %ld", v->lval);
129     }
130     if (PREV_LINK(v))
131       fprintf(h, ",\n");
132     v = PREV_LINK(v);
133   }
134   fprintf(h, "\n");
135 }
136
137 void write_type(FILE *h, type_t *t, var_t *v, char *n)
138 {
139   int c;
140
141   if (n) fprintf(h, "%s", n);
142   else {
143     if (t->is_const) fprintf(h, "const ");
144     if (t->type) {
145       if (t->sign > 0) fprintf(h, "signed ");
146       else if (t->sign < 0) fprintf(h, "unsigned ");
147       switch (t->type) {
148       case RPC_FC_BYTE:
149         if (t->ref) fprintf(h, t->ref->name);
150         else fprintf(h, "byte");
151         break;
152       case RPC_FC_CHAR:
153         if (t->ref) fprintf(h, t->ref->name);
154         else fprintf(h, "char");
155         break;
156       case RPC_FC_WCHAR:
157         fprintf(h, "wchar_t");
158         break;
159       case RPC_FC_USHORT:
160       case RPC_FC_SHORT:
161         if (t->ref) fprintf(h, t->ref->name);
162         else fprintf(h, "short");
163         break;
164       case RPC_FC_ULONG:
165       case RPC_FC_LONG:
166         if (t->ref) fprintf(h, t->ref->name);
167         else fprintf(h, "long");
168         break;
169       case RPC_FC_HYPER:
170         if (t->ref) fprintf(h, t->ref->name);
171         else fprintf(h, "__int64");
172         break;
173       case RPC_FC_FLOAT:
174         fprintf(h, "float");
175         break;
176       case RPC_FC_DOUBLE:
177         fprintf(h, "double");
178         break;
179       case RPC_FC_ENUM16:
180       case RPC_FC_ENUM32:
181         if (t->defined && !t->written) {
182           if (t->name) fprintf(h, "enum %s {\n", t->name);
183           else fprintf(h, "enum {\n");
184           indentation++;
185           write_enums(h, t->fields);
186           indent(-1);
187           fprintf(h, "}");
188         }
189         else fprintf(h, "enum %s", t->name);
190         break;
191       case RPC_FC_STRUCT:
192         if (t->defined && !t->written) {
193           if (t->name) fprintf(h, "struct %s {\n", t->name);
194           else fprintf(h, "struct {\n");
195           indentation++;
196           write_fields(h, t->fields);
197           indent(-1);
198           fprintf(h, "}");
199         }
200         else fprintf(h, "struct %s", t->name);
201         break;
202       case RPC_FC_ENCAPSULATED_UNION:
203         if (t->defined && !t->written) {
204           var_t *d = t->fields;
205           if (t->name) fprintf(h, "struct %s {\n", t->name);
206           else fprintf(h, "struct {\n");
207           indentation++;
208           write_field(h, d);
209           indent(0);
210           fprintf(h, "union {\n");
211           indentation++;
212           write_fields(h, NEXT_LINK(d));
213           indent(-1);
214           fprintf(h, "} u;\n");
215           indent(-1);
216           fprintf(h, "}");
217         }
218         else fprintf(h, "struct %s", t->name);
219         break;
220       case RPC_FC_NON_ENCAPSULATED_UNION:
221         if (t->defined && !t->written) {
222           if (t->name) fprintf(h, "union %s {\n", t->name);
223           else fprintf(h, "union {\n");
224           indentation++;
225           write_fields(h, t->fields);
226           indent(-1);
227           fprintf(h, "}");
228         }
229         else fprintf(h, "union %s", t->name);
230         break;
231       default:
232         fprintf(h, "(unknown-type:%d)", t->type);
233       }
234     }
235     else {
236       if (t->ref) {
237         write_type(h, t->ref, NULL, t->name);
238       }
239       else fprintf(h, "void");
240     }
241   }
242   if (v) {
243     for (c=0; c<v->ptr_level; c++) {
244       fprintf(h, "*");
245     }
246   }
247 }
248
249 void write_typedef(type_t *type, var_t *names)
250 {
251   char *tname = names->tname;
252   while (NEXT_LINK(names)) names = NEXT_LINK(names);
253   fprintf(header, "typedef ");
254   write_type(header, type, NULL, tname);
255   fprintf(header, " ");
256   while (names) {
257     write_pident(header, names);
258     if (PREV_LINK(names))
259       fprintf(header, ", ");
260     names = PREV_LINK(names);
261   }
262   fprintf(header, ";\n\n");
263 }
264
265 /********** INTERFACES **********/
266
267 uuid_t *get_uuid(attr_t *a)
268 {
269   while (a) {
270     if (a->type == ATTR_UUID) return a->u.pval;
271     a = NEXT_LINK(a);
272   }
273   return NULL;
274 }
275
276 int is_object(attr_t *a)
277 {
278   while (a) {
279     if (a->type == ATTR_OBJECT) return 1;
280     a = NEXT_LINK(a);
281   }
282   return 0;
283 }
284
285 int is_local(attr_t *a)
286 {
287   while (a) {
288     if (a->type == ATTR_LOCAL) return 1;
289     a = NEXT_LINK(a);
290   }
291   return 0;
292 }
293
294 var_t *is_callas(attr_t *a)
295 {
296   while (a) {
297     if (a->type == ATTR_CALLAS) return a->u.pval;
298     a = NEXT_LINK(a);
299   }
300   return NULL;
301 }
302
303 static void write_method_def(type_t *iface)
304 {
305   func_t *cur = iface->funcs;
306   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
307   fprintf(header, "#define %s_METHODS", iface->name);
308   while (cur) {
309     var_t *def = cur->def;
310     if (!is_callas(def->attrs)) {
311       var_t *arg = cur->args;
312       int argc = 0;
313       if (arg) {
314         argc++;
315         while (NEXT_LINK(arg)) {
316           arg = NEXT_LINK(arg);
317           argc++;
318         }
319       }
320       fprintf(header, " \\\n");
321       if (!is_void(def->type, def)) {
322         if (argc)
323           fprintf(header, "    ICOM_METHOD%d (", argc);
324         else
325           fprintf(header, "    ICOM_METHOD  (");
326         write_type(header, def->type, def, def->tname);
327         fprintf(header, ",");
328       } else
329         if (argc)
330           fprintf(header, "    ICOM_VMETHOD%d(", argc);
331         else
332           fprintf(header, "    ICOM_VMETHOD (");
333       write_name(header, def);
334       while (arg) {
335         fprintf(header, ",");
336         write_type(header, arg->type, arg, arg->tname);
337         fprintf(header, ",");
338         write_name(header,arg);
339         arg = PREV_LINK(arg);
340       }
341       fprintf(header, ")");
342     }
343     cur = PREV_LINK(cur);
344   }
345   fprintf(header, "\n");
346 }
347
348 static int write_method_macro(type_t *iface, char *name)
349 {
350   int idx;
351   func_t *cur = iface->funcs;
352   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
353
354   if (iface->ref) idx = write_method_macro(iface->ref, name);
355   else idx = 0;
356   fprintf(header, "/*** %s methods ***/\n", iface->name);
357   while (cur) {
358     var_t *def = cur->def;
359     if (!is_callas(def->attrs)) {
360       var_t *arg = cur->args;
361       int argc = 0;
362       int c;
363       while (arg) {
364         arg = NEXT_LINK(arg);
365         argc++;
366       }
367
368       fprintf(header, "#define %s_", name);
369       write_name(header,def);
370       fprintf(header, "(p");
371       for (c=0; c<argc; c++)
372         fprintf(header, ",%c", c+'a');
373       fprintf(header, ") ");
374
375       if (argc)
376         fprintf(header, "ICOM_CALL%d(", argc);
377       else
378         fprintf(header, "ICOM_CALL(");
379       write_name(header,def);
380       fprintf(header, ",p");
381       for (c=0; c<argc; c++)
382         fprintf(header, ",%c", c+'a');
383       fprintf(header, ")\n");
384       if (cur->idx == -1) cur->idx = idx;
385       else if (cur->idx != idx) yyerror("BUG: method index mismatch in write_method_macro");
386       idx++;
387     }
388     cur = PREV_LINK(cur);
389   }
390   return idx;
391 }
392
393 void write_method_args(FILE *h, var_t *arg, char *name)
394 {
395   if (arg) {
396     while (NEXT_LINK(arg))
397       arg = NEXT_LINK(arg);
398   }
399   fprintf(h, "    %s* This", name);
400   while (arg) {
401     fprintf(h, ",\n    ");
402     write_type(h, arg->type, arg, arg->tname);
403     fprintf(h, " ");
404     write_name(h,arg);
405     arg = PREV_LINK(arg);
406   }
407 }
408
409 static void write_method_proto(type_t *iface)
410 {
411   func_t *cur = iface->funcs;
412   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
413   while (cur) {
414     var_t *def = cur->def;
415     var_t *cas = is_callas(def->attrs);
416     if (!is_local(def->attrs)) {
417       /* proxy prototype */
418       write_type(header, def->type, def, def->tname);
419       fprintf(header, " CALLBACK %s_", iface->name);
420       write_name(header,def);
421       fprintf(header, "_Proxy(\n");
422       write_method_args(header, cur->args, iface->name);
423       fprintf(header, ");\n");
424       /* stub prototype */
425       fprintf(header, "void __RPC_STUB %s_", iface->name);
426       write_name(header,def);
427       fprintf(header, "_Stub(\n");
428       fprintf(header, "    struct IRpcStubBuffer* This,\n");
429       fprintf(header, "    struct IRpcChannelBuffer* pRpcChannelBuffer,\n");
430       fprintf(header, "    PRPC_MESSAGE pRpcMessage,\n");
431       fprintf(header, "    DWORD* pdwStubPhase);\n");
432     }
433     if (cas) {
434       func_t *m = iface->funcs;
435       while (m && strcmp(get_name(m->def), cas->name))
436         m = NEXT_LINK(m);
437       if (m) {
438         var_t *mdef = m->def;
439         /* proxy prototype - use local prototype */
440         write_type(header, mdef->type, mdef, mdef->tname);
441         fprintf(header, " CALLBACK %s_", iface->name);
442         write_name(header, mdef);
443         fprintf(header, "_Proxy(\n");
444         write_method_args(header, m->args, iface->name);
445         fprintf(header, ");\n");
446         /* stub prototype - use remotable prototype */
447         write_type(header, def->type, def, def->tname);
448         fprintf(header, " __RPC_STUB %s_", iface->name);
449         write_name(header, mdef);
450         fprintf(header, "_Stub(\n");
451         write_method_args(header, cur->args, iface->name);
452         fprintf(header, ");\n");
453       }
454       else {
455         yywarning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name);
456       }
457     }
458
459     cur = PREV_LINK(cur);
460   }
461 }
462
463 void write_forward(type_t *iface)
464 {
465   /* C/C++ forwards should only be written for object interfaces, so if we
466    * have a full definition we only write one if we find [object] among the
467    * attributes - however, if we don't have a full definition at this point
468    * (i.e. this is an IDL forward), then we also assume that it is an object
469    * interface, since non-object interfaces shouldn't need forwards */
470   if ((!iface->defined || is_object(iface->attrs)) && !iface->written) {
471     fprintf(header, "typedef struct %s %s;\n", iface->name, iface->name);
472     iface->written = TRUE;
473   }
474 }
475
476 void write_guid(type_t *iface)
477 {
478   uuid_t *uuid = get_uuid(iface->attrs);
479   if (!uuid) return;
480   fprintf(header, "DEFINE_GUID(IID_%s, 0x%08lx, 0x%04x, 0x%04x, 0x%02x,0x%02x, 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x);\n",
481           iface->name, uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1],
482           uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]);
483 }
484
485 void write_interface(type_t *iface)
486 {
487   if (!is_object(iface->attrs)) {
488     if (!iface->funcs) return;
489     yywarning("RPC interfaces not supported yet\n");
490     return;
491   }
492
493   if (!iface->funcs) {
494     yywarning("%s has no methods", iface->name);
495     return;
496   }
497
498   fprintf(header, "/*****************************************************************************\n");
499   fprintf(header, " * %s interface\n", iface->name);
500   fprintf(header, " */\n");
501   write_guid(iface);
502   write_forward(iface);
503   fprintf(header, "#define ICOM_INTERFACE %s\n", iface->name);
504   write_method_def(iface);
505   fprintf(header, "#define %s_IMETHODS \\\n", iface->name);
506   if (iface->ref)
507     fprintf(header, "    %s_IMETHODS \\\n", iface->ref->name);
508   fprintf(header, "    %s_METHODS\n", iface->name);
509   if (iface->ref)
510     fprintf(header, "ICOM_DEFINE(%s,%s)\n", iface->name, iface->ref->name);
511   else
512     fprintf(header, "ICOM_DEFINE1(%s)\n", iface->name);
513   fprintf(header, "#undef ICOM_INTERFACE\n");
514   fprintf(header, "\n");
515   write_method_macro(iface, iface->name);
516   fprintf(header, "\n");
517   write_method_proto(iface);
518   fprintf(header, "\n");
519
520   if (!is_local(iface->attrs))
521     write_proxy(iface);
522 }