Do not define __WINESRC__ when building tools and miscemu.
[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_attr(attr_t *a, enum attr_type t)
50 {
51   while (a) {
52     if (a->type == t) return 1;
53     a = NEXT_LINK(a);
54   }
55   return 0;
56 }
57
58 void *get_attrp(attr_t *a, enum attr_type t)
59 {
60   while (a) {
61     if (a->type == t) return a->u.pval;
62     a = NEXT_LINK(a);
63   }
64   return NULL;
65 }
66
67 DWORD get_attrv(attr_t *a, enum attr_type t)
68 {
69   while (a) {
70     if (a->type == t) return a->u.ival;
71     a = NEXT_LINK(a);
72   }
73   return 0;
74 }
75
76 int is_void(type_t *t, var_t *v)
77 {
78   if (v && v->ptr_level) return 0;
79   if (!t->type && !t->ref) return 1;
80   return 0;
81 }
82
83 static void write_pident(FILE *h, var_t *v)
84 {
85   int c;
86   for (c=0; c<v->ptr_level; c++) {
87     fprintf(h, "*");
88   }
89   if (v->name) fprintf(h, "%s", v->name);
90 }
91
92 void write_name(FILE *h, var_t *v)
93 {
94   fprintf(h, "%s", v->name);
95 }
96
97 char* get_name(var_t *v)
98 {
99   return v->name;
100 }
101
102 static void write_array(FILE *h, expr_t *v, int field)
103 {
104   if (!v) return;
105   while (NEXT_LINK(v)) v = NEXT_LINK(v);
106   fprintf(h, "[");
107   while (v) {
108     if (v->is_const)
109       fprintf(h, "%ld", v->cval); /* statically sized array */
110     else
111       if (field) fprintf(h, "1"); /* dynamically sized array */
112     if (PREV_LINK(v))
113       fprintf(h, ", ");
114     v = PREV_LINK(v);
115   }
116   fprintf(h, "]");
117 }
118
119 static void write_field(FILE *h, var_t *v)
120 {
121   if (!v) return;
122   if (v->type) {
123     indent(0);
124     write_type(h, v->type, NULL, v->tname);
125     if (get_name(v)) {
126       fprintf(h, " ");
127       write_pident(h, v);
128     }
129     else {
130       /* not all C/C++ compilers support anonymous structs and unions */
131       switch (v->type->type) {
132       case RPC_FC_STRUCT:
133       case RPC_FC_ENCAPSULATED_UNION:
134         fprintf(h, " DUMMYSTRUCTNAME");
135         break;
136       case RPC_FC_NON_ENCAPSULATED_UNION:
137         fprintf(h, " DUMMYUNIONNAME");
138         break;
139       default:
140         /* ? */
141         break;
142       }
143     }
144     write_array(h, v->array, 1);
145     fprintf(h, ";\n");
146   }
147 }
148
149 static void write_fields(FILE *h, var_t *v)
150 {
151   var_t *first = v;
152   if (!v) return;
153   while (NEXT_LINK(v)) v = NEXT_LINK(v);
154   while (v) {
155     write_field(h, v);
156     if (v == first) break;
157     v = PREV_LINK(v);
158   }
159 }
160
161 static void write_enums(FILE *h, var_t *v)
162 {
163   if (!v) return;
164   while (NEXT_LINK(v)) v = NEXT_LINK(v);
165   while (v) {
166     if (get_name(v)) {
167       indent(0);
168       write_name(h, v);
169       if (v->eval) {
170         fprintf(h, " = ");
171         write_expr(h, v->eval);
172       }
173     }
174     if (PREV_LINK(v))
175       fprintf(h, ",\n");
176     v = PREV_LINK(v);
177   }
178   fprintf(h, "\n");
179 }
180
181 void write_type(FILE *h, type_t *t, var_t *v, char *n)
182 {
183   int c;
184
185   if (n) fprintf(h, "%s", n);
186   else {
187     if (t->is_const) fprintf(h, "const ");
188     if (t->type) {
189       if (t->sign > 0) fprintf(h, "signed ");
190       else if (t->sign < 0) fprintf(h, "unsigned ");
191       switch (t->type) {
192       case RPC_FC_BYTE:
193         if (t->ref) fprintf(h, t->ref->name);
194         else fprintf(h, "byte");
195         break;
196       case RPC_FC_CHAR:
197         if (t->ref) fprintf(h, t->ref->name);
198         else fprintf(h, "char");
199         break;
200       case RPC_FC_WCHAR:
201         fprintf(h, "wchar_t");
202         break;
203       case RPC_FC_USHORT:
204       case RPC_FC_SHORT:
205         if (t->ref) fprintf(h, t->ref->name);
206         else fprintf(h, "short");
207         break;
208       case RPC_FC_ULONG:
209       case RPC_FC_LONG:
210         if (t->ref) fprintf(h, t->ref->name);
211         else fprintf(h, "long");
212         break;
213       case RPC_FC_HYPER:
214         if (t->ref) fprintf(h, t->ref->name);
215         else fprintf(h, "hyper");
216         break;
217       case RPC_FC_FLOAT:
218         fprintf(h, "float");
219         break;
220       case RPC_FC_DOUBLE:
221         fprintf(h, "double");
222         break;
223       case RPC_FC_ENUM16:
224       case RPC_FC_ENUM32:
225         if (t->defined && !t->written) {
226           if (t->name) fprintf(h, "enum %s {\n", t->name);
227           else fprintf(h, "enum {\n");
228           t->written = TRUE;
229           indentation++;
230           write_enums(h, t->fields);
231           indent(-1);
232           fprintf(h, "}");
233         }
234         else fprintf(h, "enum %s", t->name);
235         break;
236       case RPC_FC_ERROR_STATUS_T:
237         if (t->ref) fprintf(h, t->ref->name);
238         else fprintf(h, "error_status_t");
239         break;
240       case RPC_FC_BIND_PRIMITIVE:
241         if (t->ref) fprintf(h, t->ref->name);
242         else fprintf(h, "handle_t");
243         break;
244       case RPC_FC_STRUCT:
245       case RPC_FC_ENCAPSULATED_UNION:
246         if (t->defined && !t->written) {
247           if (t->name) fprintf(h, "struct %s {\n", t->name);
248           else fprintf(h, "struct {\n");
249           t->written = TRUE;
250           indentation++;
251           write_fields(h, t->fields);
252           indent(-1);
253           fprintf(h, "}");
254         }
255         else fprintf(h, "struct %s", t->name);
256         break;
257       case RPC_FC_NON_ENCAPSULATED_UNION:
258         if (t->defined && !t->written) {
259           if (t->name) fprintf(h, "union %s {\n", t->name);
260           else fprintf(h, "union {\n");
261           t->written = TRUE;
262           indentation++;
263           write_fields(h, t->fields);
264           indent(-1);
265           fprintf(h, "}");
266         }
267         else fprintf(h, "union %s", t->name);
268         break;
269       default:
270         fprintf(h, "(unknown-type:%d)", t->type);
271       }
272     }
273     else {
274       if (t->ref) {
275         write_type(h, t->ref, NULL, t->name);
276       }
277       else fprintf(h, "void");
278     }
279   }
280   if (v) {
281     for (c=0; c<v->ptr_level; c++) {
282       fprintf(h, "*");
283     }
284   }
285 }
286
287 void write_typedef(type_t *type, var_t *names)
288 {
289   char *tname = names->tname;
290   var_t *lname;
291   while (NEXT_LINK(names)) names = NEXT_LINK(names);
292   lname = names;
293   fprintf(header, "typedef ");
294   write_type(header, type, NULL, tname);
295   fprintf(header, " ");
296   while (names) {
297     write_pident(header, names);
298     if (PREV_LINK(names))
299       fprintf(header, ", ");
300     names = PREV_LINK(names);
301   }
302   fprintf(header, ";\n");
303
304   if (get_attrp(type->attrs, ATTR_WIREMARSHAL)) {
305     names = lname;
306     while (names) {
307       char *name = get_name(names);
308       fprintf(header, "unsigned long   __RPC_USER %s_UserSize     (unsigned long *, unsigned long,   %s *);\n", name, name);
309       fprintf(header, "unsigned char * __RPC_USER %s_UserMarshal  (unsigned long *, unsigned char *, %s *);\n", name, name);
310       fprintf(header, "unsigned char * __RPC_USER %s_UserUnmarshal(unsigned long *, unsigned char *, %s *);\n", name, name);
311       fprintf(header, "void            __RPC_USER %s_UserFree     (unsigned long *, %s *);\n", name, name);
312       if (PREV_LINK(names))
313         fprintf(header, ", ");
314       names = PREV_LINK(names);
315     }
316   }
317
318   fprintf(header, "\n");
319 }
320
321 static void do_write_expr(FILE *h, expr_t *e, int p)
322 {
323   switch (e->type) {
324   case EXPR_VOID:
325     break;
326   case EXPR_NUM:
327     fprintf(h, "%ld", e->u.lval);
328     break;
329   case EXPR_HEXNUM:
330     fprintf(h, "0x%lx", e->u.lval);
331     break;
332   case EXPR_IDENTIFIER:
333     fprintf(h, "%s", e->u.sval);
334     break;
335   case EXPR_NEG:
336     fprintf(h, "-");
337     do_write_expr(h, e->ref, 1);
338     break;
339   case EXPR_NOT:
340     fprintf(h, "~");
341     do_write_expr(h, e->ref, 1);
342     break;
343   case EXPR_PPTR:
344     fprintf(h, "*");
345     do_write_expr(h, e->ref, 1);
346     break;
347   case EXPR_CAST:
348     fprintf(h, "(");
349     write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
350     fprintf(h, ")");
351     do_write_expr(h, e->ref, 1);
352     break;
353   case EXPR_SIZEOF:
354     fprintf(h, "sizeof(");
355     write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
356     fprintf(h, ")");
357     break;
358   case EXPR_SHL:
359   case EXPR_SHR:
360   case EXPR_MUL:
361   case EXPR_DIV:
362   case EXPR_ADD:
363   case EXPR_SUB:
364   case EXPR_AND:
365   case EXPR_OR:
366     if (p) fprintf(h, "(");
367     do_write_expr(h, e->ref, 1);
368     switch (e->type) {
369     case EXPR_SHL: fprintf(h, " << "); break;
370     case EXPR_SHR: fprintf(h, " >> "); break;
371     case EXPR_MUL: fprintf(h, " * "); break;
372     case EXPR_DIV: fprintf(h, " / "); break;
373     case EXPR_ADD: fprintf(h, " + "); break;
374     case EXPR_SUB: fprintf(h, " - "); break;
375     case EXPR_AND: fprintf(h, " & "); break;
376     case EXPR_OR:  fprintf(h, " | "); break;
377     default: break;
378     }
379     do_write_expr(h, e->u.ext, 1);
380     if (p) fprintf(h, ")");
381     break;
382   }
383 }
384
385 void write_expr(FILE *h, expr_t *e)
386 {
387   do_write_expr(h, e, 0);
388 }
389
390 void write_constdef(var_t *v)
391 {
392   fprintf(header, "#define %s (", get_name(v));
393   write_expr(header, v->eval);
394   fprintf(header, ")\n\n");
395 }
396
397 void write_externdef(var_t *v)
398 {
399   fprintf(header, "extern const ");
400   write_type(header, v->type, NULL, v->tname);
401   if (get_name(v)) {
402     fprintf(header, " ");
403     write_pident(header, v);
404   }
405   fprintf(header, ";\n\n");
406 }
407
408 /********** INTERFACES **********/
409
410 int is_object(attr_t *a)
411 {
412   return is_attr(a, ATTR_OBJECT);
413 }
414
415 int is_local(attr_t *a)
416 {
417   return is_attr(a, ATTR_LOCAL);
418 }
419
420 var_t *is_callas(attr_t *a)
421 {
422   return get_attrp(a, ATTR_CALLAS);
423 }
424
425 static void write_icom_method_def(type_t *iface)
426 {
427   func_t *cur = iface->funcs;
428   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
429   while (cur) {
430     var_t *def = cur->def;
431     if (!is_callas(def->attrs)) {
432       var_t *arg = cur->args;
433       int argc = 0;
434       if (arg) {
435         argc++;
436         while (NEXT_LINK(arg)) {
437           arg = NEXT_LINK(arg);
438           argc++;
439         }
440       }
441       fprintf(header, " \\\n");
442       if (!is_void(def->type, def)) {
443         if (argc)
444           fprintf(header, "    ICOM_METHOD%d (", argc);
445         else
446           fprintf(header, "    ICOM_METHOD  (");
447         write_type(header, def->type, def, def->tname);
448         fprintf(header, ",");
449       } else
450         if (argc)
451           fprintf(header, "    ICOM_VMETHOD%d(", argc);
452         else
453           fprintf(header, "    ICOM_VMETHOD (");
454       write_name(header, def);
455       while (arg) {
456         fprintf(header, ",");
457         write_type(header, arg->type, arg, arg->tname);
458         /* since the ICOM macros can't express arrays,
459          * we have to pretend they're pointers instead */
460         if (arg->array) fprintf(header, "*");
461         fprintf(header, ",");
462         write_name(header,arg);
463         arg = PREV_LINK(arg);
464       }
465       fprintf(header, ")");
466     }
467     cur = PREV_LINK(cur);
468   }
469   fprintf(header, "\n");
470 }
471
472 static int write_method_macro(type_t *iface, char *name)
473 {
474   int idx;
475   func_t *cur = iface->funcs;
476   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
477
478   if (iface->ref) idx = write_method_macro(iface->ref, name);
479   else idx = 0;
480   fprintf(header, "/*** %s methods ***/\n", iface->name);
481   while (cur) {
482     var_t *def = cur->def;
483     if (!is_callas(def->attrs)) {
484       var_t *arg = cur->args;
485       int argc = 0;
486       int c;
487       while (arg) {
488         arg = NEXT_LINK(arg);
489         argc++;
490       }
491
492       fprintf(header, "#define %s_", name);
493       write_name(header,def);
494       fprintf(header, "(p");
495       for (c=0; c<argc; c++)
496         fprintf(header, ",%c", c+'a');
497       fprintf(header, ") ");
498
499       if (use_icom) {
500         if (argc)
501           fprintf(header, "ICOM_CALL%d(", argc);
502         else
503           fprintf(header, "ICOM_CALL(");
504         write_name(header, def);
505         fprintf(header, ",p");
506       }
507       else {
508         fprintf(header, "(p)->lpVtbl->");
509         write_name(header, def);
510         fprintf(header, "(p");
511       }
512       for (c=0; c<argc; c++)
513         fprintf(header, ",%c", c+'a');
514       fprintf(header, ")\n");
515       if (cur->idx == -1) cur->idx = idx;
516       else if (cur->idx != idx) yyerror("BUG: method index mismatch in write_method_macro");
517       idx++;
518     }
519     cur = PREV_LINK(cur);
520   }
521   return idx;
522 }
523
524 void write_args(FILE *h, var_t *arg, char *name, int method)
525 {
526   int count = 0;
527   if (arg) {
528     while (NEXT_LINK(arg))
529       arg = NEXT_LINK(arg);
530   }
531   if (h == header) {
532     indentation++;
533     indent(0);
534   } else fprintf(h, "    ");
535   if (method == 1) {
536     fprintf(h, "%s* This", name);
537     count++;
538   }
539   while (arg) {
540     if (count) {
541       fprintf(h, ",\n");
542       if (h == header) indent(0);
543       else fprintf(h, "    ");
544     }
545     write_type(h, arg->type, arg, arg->tname);
546     if (method && use_icom && arg->array) fprintf(h, "*"); /* as write_icom_method_def */
547     fprintf(h, " ");
548     write_name(h, arg);
549     if (!(method && use_icom)) write_array(h, arg->array, 0);
550     arg = PREV_LINK(arg);
551     count++;
552   }
553   if (h == header) indentation--;
554 }
555
556 static void write_cpp_method_def(type_t *iface)
557 {
558   func_t *cur = iface->funcs;
559   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
560   while (cur) {
561     var_t *def = cur->def;
562     if (!is_callas(def->attrs)) {
563       indent(0);
564       fprintf(header, "virtual ");
565       write_type(header, def->type, def, def->tname);
566       fprintf(header, " CALLBACK ");
567       write_name(header, def);
568       fprintf(header, "(\n");
569       write_args(header, cur->args, iface->name, 2);
570       fprintf(header, ") = 0;\n");
571       fprintf(header, "\n");
572     }
573     cur = PREV_LINK(cur);
574   }
575 }
576
577 static void do_write_c_method_def(type_t *iface, char *name)
578 {
579   func_t *cur = iface->funcs;
580   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
581
582   if (iface->ref) do_write_c_method_def(iface->ref, name);
583   indent(0);
584   fprintf(header, "/*** %s methods ***/\n", iface->name);
585   while (cur) {
586     var_t *def = cur->def;
587     if (!is_callas(def->attrs)) {
588       indent(0);
589       write_type(header, def->type, def, def->tname);
590       fprintf(header, " (CALLBACK *");
591       write_name(header, def);
592       fprintf(header, ")(\n");
593       write_args(header, cur->args, name, 1);
594       fprintf(header, ");\n");
595       fprintf(header, "\n");
596     }
597     cur = PREV_LINK(cur);
598   }
599 }
600
601 static void write_c_method_def(type_t *iface)
602 {
603   do_write_c_method_def(iface, iface->name);
604 }
605
606 static void write_method_proto(type_t *iface)
607 {
608   func_t *cur = iface->funcs;
609   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
610   while (cur) {
611     var_t *def = cur->def;
612     var_t *cas = is_callas(def->attrs);
613     if (!is_local(def->attrs)) {
614       /* proxy prototype */
615       write_type(header, def->type, def, def->tname);
616       fprintf(header, " CALLBACK %s_", iface->name);
617       write_name(header, def);
618       fprintf(header, "_Proxy(\n");
619       write_args(header, cur->args, iface->name, 1);
620       fprintf(header, ");\n");
621       /* stub prototype */
622       fprintf(header, "void __RPC_STUB %s_", iface->name);
623       write_name(header,def);
624       fprintf(header, "_Stub(\n");
625       fprintf(header, "    struct IRpcStubBuffer* This,\n");
626       fprintf(header, "    struct IRpcChannelBuffer* pRpcChannelBuffer,\n");
627       fprintf(header, "    PRPC_MESSAGE pRpcMessage,\n");
628       fprintf(header, "    DWORD* pdwStubPhase);\n");
629     }
630     if (cas) {
631       func_t *m = iface->funcs;
632       while (m && strcmp(get_name(m->def), cas->name))
633         m = NEXT_LINK(m);
634       if (m) {
635         var_t *mdef = m->def;
636         /* proxy prototype - use local prototype */
637         write_type(header, mdef->type, mdef, mdef->tname);
638         fprintf(header, " CALLBACK %s_", iface->name);
639         write_name(header, mdef);
640         fprintf(header, "_Proxy(\n");
641         write_args(header, m->args, iface->name, 1);
642         fprintf(header, ");\n");
643         /* stub prototype - use remotable prototype */
644         write_type(header, def->type, def, def->tname);
645         fprintf(header, " __RPC_STUB %s_", iface->name);
646         write_name(header, mdef);
647         fprintf(header, "_Stub(\n");
648         write_args(header, cur->args, iface->name, 1);
649         fprintf(header, ");\n");
650       }
651       else {
652         yywarning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name);
653       }
654     }
655
656     cur = PREV_LINK(cur);
657   }
658 }
659
660 static void write_function_proto(type_t *iface)
661 {
662   func_t *cur = iface->funcs;
663   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
664   while (cur) {
665     var_t *def = cur->def;
666     /* FIXME: do we need to handle call_as? */
667     write_type(header, def->type, def, def->tname);
668     fprintf(header, " ");
669     write_name(header, def);
670     fprintf(header, "(\n");
671     write_args(header, cur->args, iface->name, 0);
672     fprintf(header, ");\n");
673
674     cur = PREV_LINK(cur);
675   }
676 }
677
678 void write_forward(type_t *iface)
679 {
680   /* C/C++ forwards should only be written for object interfaces, so if we
681    * have a full definition we only write one if we find [object] among the
682    * attributes - however, if we don't have a full definition at this point
683    * (i.e. this is an IDL forward), then we also assume that it is an object
684    * interface, since non-object interfaces shouldn't need forwards */
685   if ((!iface->defined || is_object(iface->attrs)) && !iface->written) {
686     fprintf(header, "typedef struct %s %s;\n", iface->name, iface->name);
687     iface->written = TRUE;
688   }
689 }
690
691 void write_guid(type_t *iface)
692 {
693   UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
694   if (!uuid) return;
695   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",
696           iface->name, uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1],
697           uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]);
698 }
699
700 void write_com_interface(type_t *iface)
701 {
702   if (!iface->funcs) {
703     yywarning("%s has no methods", iface->name);
704     return;
705   }
706
707   fprintf(header, "/*****************************************************************************\n");
708   fprintf(header, " * %s interface\n", iface->name);
709   fprintf(header, " */\n");
710   write_guid(iface);
711   write_forward(iface);
712   if (use_icom) {
713     fprintf(header, "#define ICOM_INTERFACE %s\n", iface->name);
714     fprintf(header, "#define %s_METHODS", iface->name);
715     write_icom_method_def(iface);
716     fprintf(header, "#define %s_IMETHODS \\\n", iface->name);
717     if (iface->ref)
718       fprintf(header, "    %s_IMETHODS \\\n", iface->ref->name);
719     fprintf(header, "    %s_METHODS\n", iface->name);
720     if (iface->ref)
721       fprintf(header, "ICOM_DEFINE(%s,%s)\n", iface->name, iface->ref->name);
722     else
723       fprintf(header, "ICOM_DEFINE1(%s)\n", iface->name);
724     fprintf(header, "#undef ICOM_INTERFACE\n");
725     fprintf(header, "\n");
726     write_method_macro(iface, iface->name);
727   }
728   else {
729     /* C++ interface */
730     fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n");
731     fprintf(header, "struct %s", iface->name);
732     if (iface->ref)
733       fprintf(header, ": %s", iface->ref->name);
734     fprintf(header, " {\n");
735     indentation++;
736     fprintf(header, "\n");
737     write_cpp_method_def(iface);
738     indentation--;
739     fprintf(header, "} ICOM_COM_INTERFACE_ATTRIBUTE;\n");
740     fprintf(header, "#else\n");
741     /* C interface */
742     fprintf(header, "typedef struct %sVtbl %sVtbl;\n", iface->name, iface->name);
743     fprintf(header, "struct %s {\n", iface->name);
744     fprintf(header, "    const %sVtbl* lpVtbl;\n", iface->name);
745     fprintf(header, "};\n");
746     fprintf(header, "struct %sVtbl {\n", iface->name);
747     indentation++;
748     fprintf(header, "    ICOM_MSVTABLE_COMPAT_FIELDS\n");
749     fprintf(header, "\n");
750     write_c_method_def(iface);
751     indentation--;
752     fprintf(header, "};\n");
753     fprintf(header, "\n");
754     if (compat_icom) {
755       fprintf(header, "#define %s_IMETHODS", iface->name);
756       if (iface->ref)
757         fprintf(header, " \\\n    %s_IMETHODS", iface->ref->name);
758       write_icom_method_def(iface);
759       fprintf(header, "\n");
760     }
761     write_method_macro(iface, iface->name);
762     fprintf(header, "\n");
763     fprintf(header, "#endif\n");
764   }
765   fprintf(header, "\n");
766   write_method_proto(iface);
767   fprintf(header, "\n");
768
769   if (!is_local(iface->attrs))
770     write_proxy(iface);
771 }
772
773 void write_rpc_interface(type_t *iface)
774 {
775   DWORD ver = get_attrv(iface->attrs, ATTR_VERSION);
776
777   if (!iface->funcs) return;
778
779   fprintf(header, "/*****************************************************************************\n");
780   fprintf(header, " * %s interface (v%d.%d)\n", iface->name, LOWORD(ver), HIWORD(ver));
781   fprintf(header, " */\n");
782   write_guid(iface);
783   fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_c_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
784   fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_s_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
785   write_function_proto(iface);
786   fprintf(header, "\n");
787
788   /* FIXME: server/client code */
789 }
790
791 void write_interface(type_t *iface)
792 {
793   if (is_object(iface->attrs))
794     write_com_interface(iface);
795   else
796     write_rpc_interface(iface);
797 }