widl: Implement support for pointers to base types.
[wine] / tools / widl / proxy.c
1 /*
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  * Copyright 2004 Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <signal.h>
34
35 #include "widl.h"
36 #include "utils.h"
37 #include "parser.h"
38 #include "header.h"
39
40 #define END_OF_LIST(list)       \
41   do {                          \
42     if (list) {                 \
43       while (NEXT_LINK(list))   \
44         list = NEXT_LINK(list); \
45     }                           \
46   } while(0)
47
48 static FILE* proxy;
49 static int indent = 0;
50
51 /* FIXME: support generation of stubless proxies */
52
53 static int print_proxy( const char *format, ... )
54 {
55   va_list va;
56   int i, r;
57
58   va_start( va, format );
59   for( i=0; i<indent; i++ )
60     fprintf( proxy, "    " );
61   r = vfprintf( proxy, format, va );
62   va_end( va );
63   return r;
64 }
65
66
67 static type_t *get_base_type( var_t *arg )
68 {
69   type_t *t = arg->type;
70   while( (t->type == 0) && t->ref )
71     t = t->ref;
72   return t;
73 }
74
75 static void write_stubdescproto(void)
76 {
77   print_proxy( "extern const MIDL_STUB_DESC Object_StubDesc;\n");
78   print_proxy( "\n");
79 }
80
81 static void write_stubdesc(void)
82 {
83   print_proxy( "const MIDL_STUB_DESC Object_StubDesc = {\n");
84   print_proxy( "    0,\n");
85   print_proxy( "    NdrOleAllocate,\n");
86   print_proxy( "    NdrOleFree,\n");
87   print_proxy( "    {0}, 0, 0, 0, 0,\n");
88   print_proxy( "    0 /* __MIDL_TypeFormatString.Format */\n");
89   print_proxy( "};\n");
90   print_proxy( "\n");
91 }
92
93 static void write_formatdesc( const char *str )
94 {
95   print_proxy( "typedef struct _MIDL_%s_FORMAT_STRING\n", str );
96   indent++;
97   print_proxy( "{\n");
98   print_proxy( "short Pad;\n");
99   print_proxy( "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
100   indent--;
101   print_proxy( "} MIDL_%s_FORMAT_STRING;\n", str);
102   print_proxy( "\n");
103 }
104
105 static void write_formatstringsdecl(void)
106 {
107   print_proxy( "#define TYPE_FORMAT_STRING_SIZE %d\n",1); /* FIXME */
108   print_proxy( "#define PROC_FORMAT_STRING_SIZE %d\n",1); /* FIXME */
109   fprintf(proxy, "\n");
110   write_formatdesc( "TYPE" );
111   write_formatdesc( "PROC" );
112   fprintf(proxy, "\n");
113   print_proxy( "extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
114   print_proxy( "extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
115   print_proxy( "\n");
116 }
117
118 static void write_formatstring( int proc )
119 {
120   const char *t, *n;
121   if( !proc )
122   {
123     t = "TYPE";
124     n = "Type";
125   }
126   else
127   {
128     t = "PROC";
129     n = "Proc";
130   }
131   print_proxy( "static const MIDL_%s_FORMAT_STRING __MIDL_%sFormatString =\n", t, n);
132   print_proxy( "{\n");
133   indent++;
134   print_proxy( "0,\n");
135   print_proxy( "{\n");
136   indent++;
137   print_proxy( "0\n");
138   indent--;
139   print_proxy( "}\n");
140   indent--;
141   print_proxy( "};\n");
142   print_proxy( "\n");
143 }
144
145 static void init_proxy(void)
146 {
147   if (proxy) return;
148   if(!(proxy = fopen(proxy_name, "w")))
149     error("Could not open %s for output\n", proxy_name);
150   print_proxy( "/*** Autogenerated by WIDL %s - Do not edit ***/\n", WIDL_FULLVERSION);
151   print_proxy( "\n");
152   print_proxy( "#ifndef __REDQ_RPCPROXY_H_VERSION__\n");
153   print_proxy( "#define __REQUIRED_RPCPROXY_H_VERSION__ 440\n");
154   print_proxy( "#endif /* __REDQ_RPCPROXY_H_VERSION__ */\n");
155   print_proxy( "\n");
156   print_proxy( "#include \"rpcproxy.h\"\n");
157   print_proxy( "#ifndef __RPCPROXY_H_VERSION__\n");
158   print_proxy( "#error This code needs a newer version of rpcproxy.h\n");
159   print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n");
160   print_proxy( "\n");
161   print_proxy( "#include \"%s\"\n", header_name);
162   print_proxy( "\n");
163   write_formatstringsdecl();
164   write_stubdescproto();
165 }
166
167 static void clear_output_vars( var_t *arg )
168 {
169   END_OF_LIST(arg);
170   while (arg) {
171     if (is_attr(arg->attrs, ATTR_OUT) && !is_attr(arg->attrs, ATTR_IN)) {
172       print_proxy( "if(%s)\n", arg->name );
173       indent++;
174       print_proxy( "MIDL_memset( %s, 0, sizeof( ", arg->name );
175       indent--;
176       write_type(proxy, arg->type, arg, arg->tname);
177       fprintf( proxy, " ));\n" );
178     }
179     arg = PREV_LINK(arg);
180   }
181 }
182
183 static int is_pointer(var_t *arg)
184 {
185   if (arg->ptr_level)
186     return 1;
187   if (arg->type->type == RPC_FC_FP )
188     return 1;
189   return 0;
190 }
191
192 static void proxy_check_pointers( var_t *arg )
193 {
194   END_OF_LIST(arg);
195   while (arg) {
196     if (is_pointer(arg)) {
197         print_proxy( "if(!%s)\n", arg->name );
198         indent++;
199         print_proxy( "RpcRaiseException(RPC_X_NULL_REF_POINTER);\n");
200         indent--;
201     }
202     arg = PREV_LINK(arg);
203   }
204 }
205
206 static void marshall_size_arg( var_t *arg )
207 {
208   int index = 0;
209   const type_t *type = get_base_type(arg);
210   expr_t *expr;
211
212   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
213   if (expr)
214   {
215     print_proxy( "_StubMsg.MaxCount = ", arg->name );
216     write_expr(proxy, expr, 0);
217     fprintf(proxy, ";\n\n");
218     print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name );
219     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
220     return;
221   }
222
223   switch( type->type )
224   {
225   case RPC_FC_BYTE:
226   case RPC_FC_CHAR:
227     print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 1, arg->name );
228     break;
229
230   case RPC_FC_WCHAR:
231   case RPC_FC_SHORT:
232   case RPC_FC_USHORT:
233   case RPC_FC_ENUM16:
234     print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 2, arg->name );
235     break;
236
237   case RPC_FC_LONG:
238   case RPC_FC_ULONG:
239   case RPC_FC_ENUM32:
240     print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 4, arg->name );
241     break;
242       
243   case RPC_FC_STRUCT:
244     print_proxy( "NdrSimpleStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name );
245     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index );
246     break;
247
248   case RPC_FC_C_CSTRING:
249   case RPC_FC_C_WSTRING:
250   case RPC_FC_CARRAY:
251     print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name );
252     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
253     break;
254
255   case RPC_FC_BOGUS_STRUCT:
256     print_proxy( "NdrComplexStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name );
257     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index );
258     break;
259
260   case RPC_FC_FP:
261     {
262       var_t temp;
263       memset( &temp, 0, sizeof temp );
264       temp.type = type->ref;
265       temp.name = arg->name; /* FIXME */
266 #if 0
267       print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name );
268 #endif
269       marshall_size_arg( &temp );
270     }
271     break;
272
273   case RPC_FC_IP:
274     print_proxy( "NdrPointerBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name );
275     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
276     break;
277
278   default:
279     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
280   }
281 }
282
283 static void proxy_gen_marshall_size( var_t *arg )
284 {
285   print_proxy( "_StubMsg.BufferLength = 0U;\n" );
286
287   END_OF_LIST(arg);
288   while (arg) {
289     if (is_attr(arg->attrs, ATTR_IN)) 
290     {
291       marshall_size_arg( arg );
292       fprintf(proxy, "\n");
293     }
294     arg = PREV_LINK(arg);
295   }
296 }
297
298 static void marshall_copy_arg( var_t *arg )
299 {
300   int index = 0;
301   type_t *type = get_base_type(arg);
302   expr_t *expr;
303
304   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
305   if (expr)
306   {
307     print_proxy( "_StubMsg.MaxCount = ", arg->name );
308     write_expr(proxy, expr, 0);
309     fprintf(proxy, ";\n\n");
310     print_proxy( "NdrConformantArrayMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
311     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
312     return;
313   }
314
315   switch( type->type )
316   {
317   case RPC_FC_BYTE:
318   case RPC_FC_CHAR:
319   case RPC_FC_WCHAR:
320   case RPC_FC_SHORT:
321   case RPC_FC_USHORT:
322   case RPC_FC_ENUM16:
323   case RPC_FC_LONG:
324   case RPC_FC_ULONG:
325   case RPC_FC_ENUM32:
326     print_proxy( "*(");
327     write_type(proxy, arg->type, arg, arg->tname);
328     fprintf(proxy, " *)_StubMsg.Buffer = %s;\n", arg->name );
329     print_proxy("_StubMsg.Buffer += sizeof(");
330     write_type(proxy, arg->type, arg, arg->tname);
331     fprintf(proxy, ");\n");
332     break;
333       
334   case RPC_FC_STRUCT:
335     /* FIXME: add the format string, and set the index below */
336     print_proxy( "NdrSimpleStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
337     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
338     break;
339
340   case RPC_FC_C_CSTRING:
341   case RPC_FC_C_WSTRING:
342   case RPC_FC_CARRAY:
343     break;
344
345   case RPC_FC_BOGUS_STRUCT:
346     print_proxy( "NdrComplexStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
347     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index );
348     break;
349
350   case RPC_FC_FP:
351     {
352       var_t temp;
353       memset( &temp, 0, sizeof temp );
354       temp.type = type->ref;
355       temp.name = arg->name; /* FIXME */
356 #if 0
357       print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name );
358 #endif
359       marshall_copy_arg( &temp );
360     }
361     break;
362
363   case RPC_FC_IP:
364     print_proxy( "NdrPointerMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
365     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
366     break;
367
368   default:
369     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
370   }
371 }
372
373 static void gen_marshall_copydata( var_t *arg )
374 {
375   END_OF_LIST(arg);
376   while (arg) {
377     if (is_attr(arg->attrs, ATTR_IN)) 
378     {
379       marshall_copy_arg( arg );
380       fprintf(proxy, "\n");
381     }
382     arg = PREV_LINK(arg);
383   }
384 }
385
386 static void gen_marshall( var_t *arg )
387 {
388   /* generated code to determine the size of the buffer required */
389   proxy_gen_marshall_size( arg );
390
391   /* generated code to allocate the buffer */
392   print_proxy( "NdrProxyGetBuffer(This, &_StubMsg);\n" );
393
394   /* generated code to copy the args into the buffer */
395   gen_marshall_copydata( arg );
396
397   print_proxy( "\n");
398 }
399
400 static void unmarshall_copy_arg( var_t *arg )
401 {
402   int index = 0;
403   type_t *type = get_base_type(arg);
404   expr_t *expr;
405
406   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
407   if (expr)
408   {
409     print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
410     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
411     return;
412   }
413
414   switch( type->type )
415   {
416   case RPC_FC_BYTE:
417   case RPC_FC_CHAR:
418   case RPC_FC_WCHAR:
419   case RPC_FC_SHORT:
420   case RPC_FC_USHORT:
421   case RPC_FC_ENUM16:
422   case RPC_FC_LONG:
423   case RPC_FC_ULONG:
424   case RPC_FC_ENUM32:
425     print_proxy( "%s = *(", arg->name );
426     write_type(proxy, arg->type, arg, arg->tname);
427     fprintf(proxy," *)_StubMsg.Buffer;\n");
428     print_proxy("_StubMsg.Buffer += sizeof(");
429     write_type(proxy, arg->type, arg, arg->tname);
430     fprintf(proxy, ");\n");
431     break;
432       
433   case RPC_FC_STRUCT:
434     print_proxy( "NdrSimpleStructUnmarshall(&_StubMsg, (unsigned char**)%s, ", arg->name );
435     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index );
436     break;
437
438   case RPC_FC_C_CSTRING:
439   case RPC_FC_C_WSTRING:
440   case RPC_FC_CARRAY:
441     print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
442     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
443     break;
444
445   case RPC_FC_BOGUS_STRUCT:
446     print_proxy( "NdrComplexStructUnmarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
447     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index );
448     break;
449
450   case RPC_FC_FP:
451     {
452       var_t temp;
453       memset( &temp, 0, sizeof temp );
454       temp.type = type->ref;
455       temp.name = arg->name; /* FIXME */
456 #if 1
457       print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name );
458 #endif
459       unmarshall_copy_arg( &temp );
460     }
461     break;
462
463   case RPC_FC_IP:
464     print_proxy( "NdrPointerUnmarshall(&_StubMsg, (unsigned char**)&%s, ", arg->name );
465     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index );
466     break;
467
468   default:
469     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
470   }
471 }
472
473 static void gen_unmarshall( var_t *arg )
474 {
475   END_OF_LIST(arg);
476   while (arg) {
477     if (is_attr(arg->attrs, ATTR_OUT)) 
478     {
479       unmarshall_copy_arg( arg );
480       fprintf(proxy, "\n");
481     }
482     arg = PREV_LINK(arg);
483   }
484 }
485
486 static void free_variable( var_t *arg )
487 {
488   var_t *constraint;
489   int index = 0; /* FIXME */
490   type_t *type;
491   expr_t *expr;
492
493   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
494   if (expr)
495   {
496     print_proxy( "_StubMsg.MaxCount = ", arg->name );
497     write_expr(proxy, expr, 0);
498     fprintf(proxy, ";\n\n");
499     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
500     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index );
501     fprintf(proxy, "(void*)%s );\n", arg->name );
502     return;
503   }
504
505   type = get_base_type(arg);
506   switch( type->type )
507   {
508   case RPC_FC_BYTE:
509   case RPC_FC_CHAR:
510   case RPC_FC_WCHAR:
511   case RPC_FC_SHORT:
512   case RPC_FC_USHORT:
513   case RPC_FC_ENUM16:
514   case RPC_FC_LONG:
515   case RPC_FC_ULONG:
516   case RPC_FC_ENUM32:
517   case RPC_FC_STRUCT:
518     break;
519
520   case RPC_FC_FP:
521   case RPC_FC_IP:
522     constraint = get_attrp( arg->attrs, ATTR_IIDIS );
523     if( constraint )
524       print_proxy( "_StubMsg.MaxCount = (unsigned long) ( %s );\n",constraint->name);
525     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
526     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index );
527     fprintf(proxy, "(void*)%s );\n", arg->name );
528     break;
529
530   default:
531     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
532   }
533 }
534
535 static void proxy_free_variables( var_t *arg )
536 {
537   END_OF_LIST(arg);
538   while (arg) {
539     if (is_attr(arg->attrs, ATTR_OUT)) 
540     {
541       free_variable( arg );
542       fprintf(proxy, "\n");
543     }
544     arg = PREV_LINK(arg);
545   }
546 }
547
548 static void gen_proxy(type_t *iface, func_t *cur, int idx)
549 {
550   var_t *def = cur->def;
551   int has_ret = !is_void(def->type, def);
552
553   indent = 0;
554   write_type(proxy, def->type, def, def->tname);
555   print_proxy( " STDMETHODCALLTYPE %s_", iface->name);
556   write_name(proxy, def);
557   print_proxy( "_Proxy(\n");
558   write_args(proxy, cur->args, iface->name, 1, TRUE);
559   print_proxy( ")\n");
560   print_proxy( "{\n");
561   indent ++;
562   /* local variables */
563   if (has_ret) {
564     print_proxy( "" );
565     write_type(proxy, def->type, def, def->tname);
566     print_proxy( " _RetVal;\n");
567   }
568   print_proxy( "RPC_MESSAGE _Msg;\n" );
569   print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" );
570   print_proxy( "\n");
571
572   /* FIXME: trace */
573   clear_output_vars( cur->args );
574
575   print_proxy( "RpcTryExcept\n" );
576   print_proxy( "{\n" );
577   indent++;
578   print_proxy( "NdrProxyInitialize(This, &_Msg, &_StubMsg, &Object_StubDesc, %d);\n", idx);
579   proxy_check_pointers( cur->args );
580
581   print_proxy( "RpcTryFinally\n" );
582   print_proxy( "{\n" );
583   indent++;
584
585   gen_marshall( cur->args );
586
587   print_proxy( "NdrProxySendReceive(This, &_StubMsg);\n" );
588   fprintf(proxy, "\n");
589   print_proxy("if ((_Msg.DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
590   indent++;
591   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" );
592   indent--;
593   fprintf(proxy, "\n");
594
595   gen_unmarshall( cur->args );
596   if (has_ret) {
597     /* 
598      * FIXME: We only need to round the buffer up if it could be unaligned...
599      *    We should calculate how much buffer we used and output the following
600      *    line only if necessary.
601      */
602     print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n");
603
604     print_proxy( "_RetVal = *(" );
605     write_type(proxy, def->type, def, def->tname);
606     fprintf(proxy, " *)_StubMsg.Buffer;\n");
607     print_proxy("_StubMsg.Buffer += sizeof(");
608     write_type(proxy, def->type, def, def->tname);
609     fprintf(proxy, ");\n");
610   }
611
612   indent--;
613   print_proxy( "}\n");
614   print_proxy( "RpcFinally\n" );
615   print_proxy( "{\n" );
616   indent++;
617   print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" );
618   indent--;
619   print_proxy( "}\n");
620   print_proxy( "RpcEndFinally\n" );
621   indent--;
622   print_proxy( "}\n" );
623   print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
624   print_proxy( "{\n" );
625   if (has_ret) {
626     indent++;
627     proxy_free_variables( cur->args );
628     print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
629     indent--;
630   }
631   print_proxy( "}\n" );
632   print_proxy( "RpcEndExcept\n" );
633
634   if (has_ret) {
635     print_proxy( "return _RetVal;\n" );
636   }
637   indent--;
638   print_proxy( "}\n");
639   print_proxy( "\n");
640 }
641
642 static void stub_write_locals( var_t *arg )
643 {
644   int n = 0;
645   while (arg) {
646     int outptr = is_attr(arg->attrs, ATTR_OUT);
647
648     /* create a temporary variable to store the output */
649     if (outptr) {
650       var_t temp;
651       memset( &temp, 0, sizeof temp );
652       temp.ptr_level = arg->ptr_level - 1; /* dereference once */
653       print_proxy("");
654       write_type(proxy, arg->type, &temp, arg->tname);
655       fprintf(proxy, " _M%d;\n",n++);
656     }
657     print_proxy("");
658     write_type(proxy, arg->type, arg, arg->tname);
659     fprintf(proxy, " ");
660     write_name(proxy, arg);
661     fprintf(proxy, ";\n");
662     arg = NEXT_LINK(arg);
663   }
664 }
665
666 static void stub_unmarshall( var_t *arg )
667 {
668   int n = 0;
669   END_OF_LIST(arg);
670   while (arg) {
671     if (is_attr(arg->attrs, ATTR_IN))
672     {
673       unmarshall_copy_arg( arg );
674       fprintf(proxy,"\n");
675     }
676     else if (is_attr(arg->attrs, ATTR_OUT)) {
677       type_t *type = get_base_type(arg);
678       switch( type->type )
679       {
680       case RPC_FC_STRUCT:
681         print_proxy("MIDL_memset(");
682         write_name(proxy, arg);
683         fprintf(proxy,", 0, sizeof(");
684         write_type(proxy, arg->type, arg, arg->tname);
685         fprintf(proxy,"));\n");
686         break;
687       default:
688         print_proxy("");
689         write_name(proxy, arg);
690         fprintf(proxy," = &_M%d;\n", n);
691         print_proxy("_M%d = 0;\n", n++);
692         break;
693       }
694     }
695     arg = PREV_LINK(arg);
696   }
697 }
698
699 static void stub_gen_marshall_size( var_t *arg )
700 {
701   print_proxy( "_StubMsg.BufferLength = 0U;\n" );
702
703   END_OF_LIST(arg);
704   while (arg) {
705     if (is_attr(arg->attrs, ATTR_OUT))
706       marshall_size_arg( arg );
707     arg = PREV_LINK(arg);
708   }
709 }
710
711 static void stub_gen_marshall_copydata( var_t *arg )
712 {
713   END_OF_LIST(arg);
714   while (arg) {
715     if (is_attr(arg->attrs, ATTR_OUT))
716       marshall_copy_arg( arg );
717     arg = PREV_LINK(arg);
718   }
719 }
720
721 static void stub_genmarshall( var_t *args )
722 {
723   /* FIXME: size buffer */
724   stub_gen_marshall_size( args );
725
726   print_proxy("NdrStubGetBuffer(This, pRpcChannelBuffer, &_StubMsg);\n");
727
728   stub_gen_marshall_copydata( args );
729 }
730
731 static void gen_stub(type_t *iface, func_t *cur, const char *cas)
732 {
733   var_t *def = cur->def;
734   var_t *arg;
735   int has_ret = !is_void(def->type, def);
736
737   indent = 0;
738   print_proxy( "void __RPC_STUB %s_", iface->name);
739   write_name(proxy, def);
740   print_proxy( "_Stub(\n");
741   indent++;
742   print_proxy( "IRpcStubBuffer* This,\n");
743   print_proxy( "IRpcChannelBuffer* pRpcChannelBuffer,\n");
744   print_proxy( "PRPC_MESSAGE _Msg,\n");
745   print_proxy( "DWORD* _pdwStubPhase)\n");
746   indent--;
747   print_proxy( "{\n");
748   indent++;
749   /* local variables */
750   if (has_ret) {
751     print_proxy("");
752     write_type(proxy, def->type, def, def->tname);
753     fprintf(proxy, " _RetVal;\n");
754   }
755   print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name);
756   print_proxy("MIDL_STUB_MESSAGE _StubMsg;\n");
757   stub_write_locals( cur->args );
758   fprintf(proxy, "\n");
759
760   /* FIXME: trace */
761
762   print_proxy("NdrStubInitialize(_Msg, &_StubMsg, &Object_StubDesc, pRpcChannelBuffer);\n");
763   fprintf(proxy, "\n");
764
765   print_proxy("RpcTryFinally\n");
766   print_proxy("{\n");
767   indent++;
768   print_proxy("if ((_Msg->DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
769   indent++;
770   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" );
771   indent--;
772   fprintf(proxy, "\n");
773
774   stub_unmarshall( cur->args );
775   fprintf(proxy, "\n");
776
777   print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
778   fprintf(proxy, "\n");
779   print_proxy("");
780   if (has_ret) fprintf(proxy, "_RetVal = ");
781   fprintf(proxy, "%s_", iface->name);
782   if (cas) fprintf(proxy, "%s_Stub", cas);
783   else write_name(proxy, def);
784   fprintf(proxy, "(_This");
785   arg = cur->args;
786   if (arg) {
787     END_OF_LIST(arg);
788     while (arg) {
789       fprintf(proxy, ", ");
790       write_name(proxy, arg);
791       arg = PREV_LINK(arg);
792     }
793   }
794   fprintf(proxy, ");\n");
795   fprintf(proxy, "\n");
796   print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
797   fprintf(proxy, "\n");
798
799   stub_genmarshall( cur->args );
800   fprintf(proxy, "\n");
801
802   if (has_ret) {
803     /* 
804      * FIXME: We only need to round the buffer up if it could be unaligned...
805      *    We should calculate how much buffer we used and output the following
806      *    line only if necessary.
807      */
808     print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n");
809
810     print_proxy( "*(" );
811     write_type(proxy, def->type, def, def->tname);
812     fprintf(proxy, " *)_StubMsg.Buffer = _RetVal;\n");
813     print_proxy("_StubMsg.Buffer += sizeof(");
814     write_type(proxy, def->type, def, def->tname);
815     fprintf(proxy, ");\n");
816   }
817
818   indent--;
819   print_proxy("}\n");
820   print_proxy("RpcFinally\n");
821   print_proxy("{\n");
822   print_proxy("}\n");
823   print_proxy("RpcEndFinally\n");
824
825   print_proxy("_Msg->BufferLength = _StubMsg.Buffer - (unsigned char *)_Msg->Buffer;\n");
826   indent--;
827
828   print_proxy("}\n");
829   print_proxy("\n");
830 }
831
832 static int write_proxy_methods(type_t *iface)
833 {
834   func_t *cur = iface->funcs;
835   int i = 0;
836
837   END_OF_LIST(cur);
838
839   if (iface->ref) i = write_proxy_methods(iface->ref);
840   while (cur) {
841     var_t *def = cur->def;
842     if (!is_callas(def->attrs)) {
843       if (i) fprintf(proxy, ",\n");
844       print_proxy( "%s_", iface->name);
845       write_name(proxy, def);
846       fprintf(proxy, "_Proxy");
847       i++;
848     }
849     cur = PREV_LINK(cur);
850   }
851   return i;
852 }
853
854 static int write_stub_methods(type_t *iface)
855 {
856   func_t *cur = iface->funcs;
857   int i = 0;
858
859   END_OF_LIST(cur);
860
861   if (iface->ref) i = write_stub_methods(iface->ref);
862   else return i; /* skip IUnknown */
863   while (cur) {
864     var_t *def = cur->def;
865     if (!is_local(def->attrs)) {
866       if (i) fprintf(proxy,",\n");
867       print_proxy( "%s_", iface->name);
868       write_name(proxy, def);
869       fprintf(proxy, "_Stub");
870       i++;
871     }
872     cur = PREV_LINK(cur);
873   }
874   return i;
875 }
876
877 static void write_proxy(type_t *iface)
878 {
879   int midx = -1, stubs;
880   func_t *cur = iface->funcs;
881
882   if (!cur) return;
883
884   END_OF_LIST(cur);
885
886   /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */
887
888   fprintf(proxy, "/*****************************************************************************\n");
889   fprintf(proxy, " * %s interface\n", iface->name);
890   fprintf(proxy, " */\n");
891   while (cur) {
892     const var_t *def = cur->def;
893     if (!is_local(def->attrs)) {
894       const var_t *cas = is_callas(def->attrs);
895       const char *cname = cas ? cas->name : NULL;
896       int idx = cur->idx;
897       if (cname) {
898         const func_t *m = iface->funcs;
899         while (m && strcmp(get_name(m->def), cname))
900           m = NEXT_LINK(m);
901         idx = m->idx;
902       }
903       gen_proxy(iface, cur, idx);
904       gen_stub(iface, cur, cname);
905       if (midx == -1) midx = idx;
906       else if (midx != idx) yyerror("method index mismatch in write_proxy");
907       midx++;
908     }
909     cur = PREV_LINK(cur);
910   }
911
912   /* proxy vtable */
913   print_proxy( "const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name);
914   print_proxy( "{\n");
915   indent++;
916   print_proxy( "{\n", iface->name);
917   indent++;
918   print_proxy( "&IID_%s,\n", iface->name);
919   indent--;
920   print_proxy( "},\n");
921   print_proxy( "{\n");
922   indent++;
923   write_proxy_methods(iface);
924   fprintf(proxy, "\n");
925   indent--;
926   print_proxy( "}\n");
927   indent--;
928   print_proxy( "};\n");
929   fprintf(proxy, "\n\n");
930
931   /* stub vtable */
932   print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name);
933   print_proxy( "{\n");
934   indent++;
935   stubs = write_stub_methods(iface);
936   fprintf(proxy, "\n");
937   indent--;
938   fprintf(proxy, "};\n");
939   print_proxy( "\n");
940   print_proxy( "const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name);
941   print_proxy( "{\n");
942   indent++;
943   print_proxy( "{\n");
944   indent++;
945   print_proxy( "&IID_%s,\n", iface->name);
946   print_proxy( "0,\n");
947   print_proxy( "%d,\n", stubs+3);
948   print_proxy( "&%s_table[-3],\n", iface->name);
949   indent--;
950   print_proxy( "},\n", iface->name);
951   print_proxy( "{\n");
952   indent++;
953   print_proxy( "CStdStubBuffer_METHODS\n");
954   indent--;
955   print_proxy( "}\n");
956   indent--;
957   print_proxy( "};\n");
958   print_proxy( "\n");
959 }
960
961 void write_proxies(ifref_t *ifaces)
962 {
963   ifref_t *lcur = ifaces;
964   ifref_t *cur;
965   char *file_id = proxy_token;
966   int c;
967
968   if (!do_proxies) return;
969   if (!lcur) return;
970   END_OF_LIST(lcur);
971
972   init_proxy();
973   if(!proxy) return;
974
975   cur = lcur;
976   while (cur) {
977     if (is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
978       write_proxy(cur->iface);
979     cur = PREV_LINK(cur);
980   }
981
982   if (!proxy) return;
983
984   write_stubdesc();
985
986   print_proxy( "#if !defined(__RPC_WIN32__)\n");
987   print_proxy( "#error Currently only Wine and WIN32 are supported.\n");
988   print_proxy( "#endif\n");
989   print_proxy( "\n");
990   write_formatstring( 1 );
991   write_formatstring( 0 );
992
993   fprintf(proxy, "const CInterfaceProxyVtbl* _%s_ProxyVtblList[] =\n", file_id);
994   fprintf(proxy, "{\n");
995   cur = lcur;
996   while (cur) {
997     if(cur->iface->ref && cur->iface->funcs &&
998        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
999       fprintf(proxy, "    (CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", cur->iface->name);
1000     cur = PREV_LINK(cur);
1001   }
1002   fprintf(proxy, "    0\n");
1003   fprintf(proxy, "};\n");
1004   fprintf(proxy, "\n");
1005
1006   fprintf(proxy, "const CInterfaceStubVtbl* _%s_StubVtblList[] =\n", file_id);
1007   fprintf(proxy, "{\n");
1008   cur = lcur;
1009   while (cur) {
1010     if(cur->iface->ref && cur->iface->funcs &&
1011        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
1012       fprintf(proxy, "    (CInterfaceStubVtbl*)&_%sStubVtbl,\n", cur->iface->name);
1013     cur = PREV_LINK(cur);
1014   }
1015   fprintf(proxy, "    0\n");
1016   fprintf(proxy, "};\n");
1017   fprintf(proxy, "\n");
1018
1019   fprintf(proxy, "PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
1020   fprintf(proxy, "{\n");
1021   cur = lcur;
1022   while (cur) {
1023     if(cur->iface->ref && cur->iface->funcs &&
1024        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
1025       fprintf(proxy, "    \"%s\",\n", cur->iface->name);
1026     cur = PREV_LINK(cur);
1027   }
1028   fprintf(proxy, "    0\n");
1029   fprintf(proxy, "};\n");
1030   fprintf(proxy, "\n");
1031
1032   fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id);
1033   fprintf(proxy, "\n");
1034   fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
1035   fprintf(proxy, "{\n");
1036   cur = lcur;
1037   c = 0;
1038   while (cur) {
1039     if(cur->iface->ref)
1040     {
1041       fprintf(proxy, "    if (!_%s_CHECK_IID(%d))\n", file_id, c);
1042       fprintf(proxy, "    {\n");
1043       fprintf(proxy, "        *pIndex = %d;\n", c);
1044       fprintf(proxy, "        return 1;\n");
1045       fprintf(proxy, "    }\n");
1046       c++;
1047     }
1048     cur = PREV_LINK(cur);
1049   }
1050   fprintf(proxy, "    return 0;\n");
1051   fprintf(proxy, "}\n");
1052   fprintf(proxy, "\n");
1053
1054   fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id);
1055   fprintf(proxy, "{\n");
1056   fprintf(proxy, "    (PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id);
1057   fprintf(proxy, "    (PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id);
1058   fprintf(proxy, "    (const PCInterfaceName*)&_%s_InterfaceNamesList,\n", file_id);
1059   fprintf(proxy, "    0,\n");
1060   fprintf(proxy, "    &_%s_IID_Lookup,\n", file_id);
1061   fprintf(proxy, "    %d,\n", c);
1062   fprintf(proxy, "    1,\n");
1063   fprintf(proxy, "    0,\n");
1064   fprintf(proxy, "    0,\n");
1065   fprintf(proxy, "    0,\n");
1066   fprintf(proxy, "    0\n");
1067   fprintf(proxy, "};\n");
1068
1069   fclose(proxy);
1070 }