Added partial support for function pointers.
[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   if (iface->ref) write_icom_method_def( iface->ref );
429   if (!cur) return;
430   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
431   if (cur) fprintf( header, " \\\n    /*** %s methods ***/", iface->name );
432   while (cur) {
433     var_t *def = cur->def;
434     if (!is_callas(def->attrs)) {
435       var_t *arg = cur->args;
436
437       if (arg) {
438         while (NEXT_LINK(arg)) {
439           arg = NEXT_LINK(arg);
440         }
441       }
442       fprintf(header, " \\\n    STDMETHOD_(");
443       write_type(header, def->type, def, def->tname);
444       fprintf(header, ",");
445       write_name(header, def);
446       fprintf(header, ")(%s", arg ? "THIS_ " : "THIS" );
447       while (arg) {
448         write_type(header, arg->type, arg, arg->tname);
449         if (arg->args)
450         {
451           fprintf(header, " (STDMETHODCALLTYPE *");
452           write_name(header,arg);
453           fprintf( header,")(");
454           write_args(header, arg->args, NULL, 0, FALSE);
455           fprintf(header,")");
456         }
457         else
458         {
459           fprintf(header, " ");
460           write_name(header,arg);
461         }
462         write_array(header, arg->array, 0);
463         arg = PREV_LINK(arg);
464         if (arg) fprintf(header, ", ");
465       }
466       fprintf(header, ") PURE;");
467     }
468     cur = PREV_LINK(cur);
469   }
470 }
471
472 static int write_method_macro(type_t *iface, char *name)
473 {
474   int idx;
475   func_t *cur = iface->funcs;
476
477   if (iface->ref) idx = write_method_macro(iface->ref, name);
478   else idx = 0;
479
480   if (!cur) return idx;
481   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
482
483   fprintf(header, "/*** %s methods ***/\n", iface->name);
484   while (cur) {
485     var_t *def = cur->def;
486     if (!is_callas(def->attrs)) {
487       var_t *arg = cur->args;
488       int argc = 0;
489       int c;
490       while (arg) {
491         arg = NEXT_LINK(arg);
492         argc++;
493       }
494
495       fprintf(header, "#define %s_", name);
496       write_name(header,def);
497       fprintf(header, "(p");
498       for (c=0; c<argc; c++)
499         fprintf(header, ",%c", c+'a');
500       fprintf(header, ") ");
501
502       fprintf(header, "(p)->lpVtbl->");
503       write_name(header, def);
504       fprintf(header, "(p");
505       for (c=0; c<argc; c++)
506         fprintf(header, ",%c", c+'a');
507       fprintf(header, ")\n");
508       if (cur->idx == -1) cur->idx = idx;
509       else if (cur->idx != idx) yyerror("BUG: method index mismatch in write_method_macro");
510       idx++;
511     }
512     cur = PREV_LINK(cur);
513   }
514   return idx;
515 }
516
517 void write_args(FILE *h, var_t *arg, char *name, int method, int do_indent)
518 {
519   int count = 0;
520   if (arg) {
521     while (NEXT_LINK(arg))
522       arg = NEXT_LINK(arg);
523   }
524   if (do_indent)
525   {
526       if (h == header) {
527           indentation++;
528           indent(0);
529       } else fprintf(h, "    ");
530   }
531   if (method == 1) {
532     fprintf(h, "%s* This", name);
533     count++;
534   }
535   while (arg) {
536     if (count) {
537         if (do_indent)
538         {
539             fprintf(h, ",\n");
540             if (h == header) indent(0);
541             else fprintf(h, "    ");
542         }
543         else fprintf(h, ",");
544     }
545     write_type(h, arg->type, arg, arg->tname);
546     if (arg->args)
547     {
548       fprintf(h, " (STDMETHODCALLTYPE *");
549       write_name(h,arg);
550       fprintf(h, ")(");
551       write_args(h, arg->args, NULL, 0, FALSE);
552       fprintf(h, ")");
553     }
554     else
555     {
556       fprintf(h, " ");
557       write_name(h, arg);
558     }
559     write_array(h, arg->array, 0);
560     arg = PREV_LINK(arg);
561     count++;
562   }
563   if (do_indent && h == header) indentation--;
564 }
565
566 static void write_cpp_method_def(type_t *iface)
567 {
568   func_t *cur = iface->funcs;
569
570   if (!cur) return;
571   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
572   while (cur) {
573     var_t *def = cur->def;
574     if (!is_callas(def->attrs)) {
575       indent(0);
576       fprintf(header, "virtual ");
577       write_type(header, def->type, def, def->tname);
578       fprintf(header, " STDMETHODCALLTYPE ");
579       write_name(header, def);
580       fprintf(header, "(\n");
581       write_args(header, cur->args, iface->name, 2, TRUE);
582       fprintf(header, ") = 0;\n");
583       fprintf(header, "\n");
584     }
585     cur = PREV_LINK(cur);
586   }
587 }
588
589 static void do_write_c_method_def(type_t *iface, char *name)
590 {
591   func_t *cur = iface->funcs;
592
593   if (iface->ref) do_write_c_method_def(iface->ref, name);
594
595   if (!cur) return;
596   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
597   indent(0);
598   fprintf(header, "/*** %s methods ***/\n", iface->name);
599   while (cur) {
600     var_t *def = cur->def;
601     if (!is_callas(def->attrs)) {
602       indent(0);
603       write_type(header, def->type, def, def->tname);
604       fprintf(header, " (STDMETHODCALLTYPE *");
605       write_name(header, def);
606       fprintf(header, ")(\n");
607       write_args(header, cur->args, name, 1, TRUE);
608       fprintf(header, ");\n");
609       fprintf(header, "\n");
610     }
611     cur = PREV_LINK(cur);
612   }
613 }
614
615 static void write_c_method_def(type_t *iface)
616 {
617   do_write_c_method_def(iface, iface->name);
618 }
619
620 static void write_method_proto(type_t *iface)
621 {
622   func_t *cur = iface->funcs;
623
624   if (!cur) return;
625   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
626   while (cur) {
627     var_t *def = cur->def;
628     var_t *cas = is_callas(def->attrs);
629     if (!is_local(def->attrs)) {
630       /* proxy prototype */
631       write_type(header, def->type, def, def->tname);
632       fprintf(header, " CALLBACK %s_", iface->name);
633       write_name(header, def);
634       fprintf(header, "_Proxy(\n");
635       write_args(header, cur->args, iface->name, 1, TRUE);
636       fprintf(header, ");\n");
637       /* stub prototype */
638       fprintf(header, "void __RPC_STUB %s_", iface->name);
639       write_name(header,def);
640       fprintf(header, "_Stub(\n");
641       fprintf(header, "    struct IRpcStubBuffer* This,\n");
642       fprintf(header, "    struct IRpcChannelBuffer* pRpcChannelBuffer,\n");
643       fprintf(header, "    PRPC_MESSAGE pRpcMessage,\n");
644       fprintf(header, "    DWORD* pdwStubPhase);\n");
645     }
646     if (cas) {
647       func_t *m = iface->funcs;
648       while (m && strcmp(get_name(m->def), cas->name))
649         m = NEXT_LINK(m);
650       if (m) {
651         var_t *mdef = m->def;
652         /* proxy prototype - use local prototype */
653         write_type(header, mdef->type, mdef, mdef->tname);
654         fprintf(header, " CALLBACK %s_", iface->name);
655         write_name(header, mdef);
656         fprintf(header, "_Proxy(\n");
657         write_args(header, m->args, iface->name, 1, TRUE);
658         fprintf(header, ");\n");
659         /* stub prototype - use remotable prototype */
660         write_type(header, def->type, def, def->tname);
661         fprintf(header, " __RPC_STUB %s_", iface->name);
662         write_name(header, mdef);
663         fprintf(header, "_Stub(\n");
664         write_args(header, cur->args, iface->name, 1, TRUE);
665         fprintf(header, ");\n");
666       }
667       else {
668         yywarning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name);
669       }
670     }
671
672     cur = PREV_LINK(cur);
673   }
674 }
675
676 static void write_function_proto(type_t *iface)
677 {
678   func_t *cur = iface->funcs;
679   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
680   while (cur) {
681     var_t *def = cur->def;
682     /* FIXME: do we need to handle call_as? */
683     write_type(header, def->type, def, def->tname);
684     fprintf(header, " ");
685     write_name(header, def);
686     fprintf(header, "(\n");
687     write_args(header, cur->args, iface->name, 0, TRUE);
688     fprintf(header, ");\n");
689
690     cur = PREV_LINK(cur);
691   }
692 }
693
694 void write_forward(type_t *iface)
695 {
696   /* C/C++ forwards should only be written for object interfaces, so if we
697    * have a full definition we only write one if we find [object] among the
698    * attributes - however, if we don't have a full definition at this point
699    * (i.e. this is an IDL forward), then we also assume that it is an object
700    * interface, since non-object interfaces shouldn't need forwards */
701   if ((!iface->defined || is_object(iface->attrs)) && !iface->written) {
702     fprintf(header,"#ifndef __%s_FWD_DEFINED__\n", iface->name);
703     fprintf(header,"#define __%s_FWD_DEFINED__\n", iface->name);
704     fprintf(header, "typedef struct %s %s;\n", iface->name, iface->name);
705     fprintf(header, "#endif\n\n" );
706     iface->written = TRUE;
707   }
708 }
709
710 void write_guid(type_t *iface)
711 {
712   UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
713   if (!uuid) return;
714   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",
715           iface->name, uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1],
716           uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]);
717 }
718
719 void write_com_interface(type_t *iface)
720 {
721   if (!iface->funcs && !iface->ref) {
722     yywarning("%s has no methods", iface->name);
723     return;
724   }
725
726   fprintf(header, "/*****************************************************************************\n");
727   fprintf(header, " * %s interface\n", iface->name);
728   fprintf(header, " */\n");
729   fprintf(header,"#ifndef __%s_INTERFACE_DEFINED__\n", iface->name);
730   fprintf(header,"#define __%s_INTERFACE_DEFINED__\n\n", iface->name);
731   write_guid(iface);
732   write_forward(iface);
733   /* C++ interface */
734   fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n");
735   if (iface->ref)
736       fprintf(header, "struct %s : public %s\n", iface->name, iface->ref->name);
737   else
738   {
739       fprintf(header, "#ifdef ICOM_USE_COM_INTERFACE_ATTRIBUTE\n");
740       fprintf(header, "struct __attribute__((com_interface)) %s\n", iface->name);
741       fprintf(header, "#else\n");
742       fprintf(header, "struct %s\n", iface->name);
743       fprintf(header, "#endif\n");
744   }
745   fprintf(header, "{\n");
746   indentation++;
747   write_cpp_method_def(iface);
748   indentation--;
749   fprintf(header, "};\n");
750   fprintf(header, "#else\n");
751   /* C interface */
752   fprintf(header, "typedef struct %sVtbl %sVtbl;\n", iface->name, iface->name);
753   fprintf(header, "struct %s {\n", iface->name);
754   fprintf(header, "    const %sVtbl* lpVtbl;\n", iface->name);
755   fprintf(header, "};\n");
756   fprintf(header, "struct %sVtbl {\n", iface->name);
757   indentation++;
758   fprintf(header, "    ICOM_MSVTABLE_COMPAT_FIELDS\n");
759   fprintf(header, "\n");
760   write_c_method_def(iface);
761   indentation--;
762   fprintf(header, "};\n");
763   fprintf(header, "\n");
764   write_method_macro(iface, iface->name);
765   fprintf(header, "\n");
766   fprintf(header, "#endif\n");
767   fprintf(header, "\n");
768   if (compat_icom) {
769       fprintf(header, "#define %s_METHODS \\\n", iface->name);
770       fprintf(header, "    ICOM_MSVTABLE_COMPAT_FIELDS");
771       write_icom_method_def(iface);
772       fprintf(header, "\n\n");
773   }
774   write_method_proto(iface);
775   fprintf(header, "\n");
776
777   if (!is_local(iface->attrs))
778     write_proxy(iface);
779   fprintf(header,"#endif  /* __%s_INTERFACE_DEFINED__ */\n\n", iface->name);
780 }
781
782 void write_rpc_interface(type_t *iface)
783 {
784   DWORD ver = get_attrv(iface->attrs, ATTR_VERSION);
785
786   if (!iface->funcs) return;
787
788   fprintf(header, "/*****************************************************************************\n");
789   fprintf(header, " * %s interface (v%d.%d)\n", iface->name, LOWORD(ver), HIWORD(ver));
790   fprintf(header, " */\n");
791   write_guid(iface);
792   fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_c_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
793   fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_s_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
794   write_function_proto(iface);
795   fprintf(header, "\n");
796
797   /* FIXME: server/client code */
798 }
799
800 void write_interface(type_t *iface)
801 {
802   if (is_object(iface->attrs))
803     write_com_interface(iface);
804   else
805     write_rpc_interface(iface);
806 }