Test the behaviour of HttpSendRequestEx when putting data into the
[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   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);
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);
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     break;
330       
331   case RPC_FC_STRUCT:
332     /* FIXME: add the format string, and set the index below */
333     print_proxy( "NdrSimpleStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
334     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
335     break;
336
337   case RPC_FC_C_CSTRING:
338   case RPC_FC_C_WSTRING:
339   case RPC_FC_CARRAY:
340     break;
341
342   case RPC_FC_BOGUS_STRUCT:
343     print_proxy( "NdrComplexStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
344     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index );
345     break;
346
347   case RPC_FC_FP:
348     {
349       var_t temp;
350       memset( &temp, 0, sizeof temp );
351       temp.type = type->ref;
352       temp.name = arg->name; /* FIXME */
353 #if 0
354       print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name );
355 #endif
356       marshall_copy_arg( &temp );
357     }
358     break;
359
360   case RPC_FC_IP:
361     print_proxy( "NdrPointerMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
362     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
363     break;
364
365   default:
366     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
367   }
368 }
369
370 static void gen_marshall_copydata( var_t *arg )
371 {
372   END_OF_LIST(arg);
373   while (arg) {
374     if (is_attr(arg->attrs, ATTR_IN)) 
375     {
376       marshall_copy_arg( arg );
377       fprintf(proxy, "\n");
378     }
379     arg = PREV_LINK(arg);
380   }
381 }
382
383 static void gen_marshall( var_t *arg )
384 {
385   /* generated code to determine the size of the buffer required */
386   proxy_gen_marshall_size( arg );
387
388   /* generated code to allocate the buffer */
389   print_proxy( "NdrProxyGetBuffer(This, &_StubMsg);\n" );
390
391   /* generated code to copy the args into the buffer */
392   gen_marshall_copydata( arg );
393
394   print_proxy( "\n");
395 }
396
397 static void unmarshall_copy_arg( var_t *arg )
398 {
399   int index = 0;
400   type_t *type = get_base_type(arg);
401   expr_t *expr;
402
403   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
404   if (expr)
405   {
406     print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
407     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
408     return;
409   }
410
411   switch( type->type )
412   {
413   case RPC_FC_BYTE:
414   case RPC_FC_CHAR:
415   case RPC_FC_WCHAR:
416   case RPC_FC_SHORT:
417   case RPC_FC_USHORT:
418   case RPC_FC_ENUM16:
419   case RPC_FC_LONG:
420   case RPC_FC_ULONG:
421   case RPC_FC_ENUM32:
422     print_proxy( "%s = *((", arg->name );
423     write_type(proxy, arg->type, arg, arg->tname);
424     fprintf(proxy,"*)_StubMsg.Buffer)++;\n");
425     break;
426       
427   case RPC_FC_STRUCT:
428     print_proxy( "NdrSimpleStructUnmarshall(&_StubMsg, (unsigned char**)%s, ", arg->name );
429     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index );
430     break;
431
432   case RPC_FC_C_CSTRING:
433   case RPC_FC_C_WSTRING:
434   case RPC_FC_CARRAY:
435     print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name );
436     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index );
437     break;
438
439   case RPC_FC_BOGUS_STRUCT:
440     print_proxy( "NdrComplexStructUnmarshall(&_StubMsg, (unsigned char*)%s, ", arg->name );
441     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index );
442     break;
443
444   case RPC_FC_FP:
445     {
446       var_t temp;
447       memset( &temp, 0, sizeof temp );
448       temp.type = type->ref;
449       temp.name = arg->name; /* FIXME */
450 #if 1
451       print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name );
452 #endif
453       unmarshall_copy_arg( &temp );
454     }
455     break;
456
457   case RPC_FC_IP:
458     print_proxy( "NdrPointerUnmarshall(&_StubMsg, (unsigned char**)&%s, ", arg->name );
459     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index );
460     break;
461
462   default:
463     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
464   }
465 }
466
467 static void gen_unmarshall( var_t *arg )
468 {
469   END_OF_LIST(arg);
470   while (arg) {
471     if (is_attr(arg->attrs, ATTR_OUT)) 
472     {
473       unmarshall_copy_arg( arg );
474       fprintf(proxy, "\n");
475     }
476     arg = PREV_LINK(arg);
477   }
478 }
479
480 static void free_variable( var_t *arg )
481 {
482   var_t *constraint;
483   int index = 0; /* FIXME */
484   type_t *type;
485   expr_t *expr;
486
487   expr = get_attrp( arg->attrs, ATTR_SIZEIS );
488   if (expr)
489   {
490     print_proxy( "_StubMsg.MaxCount = ", arg->name );
491     write_expr(proxy, expr);
492     fprintf(proxy, ";\n\n");
493     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
494     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index );
495     fprintf(proxy, "(void*)%s );\n", arg->name );
496     return;
497   }
498
499   type = get_base_type(arg);
500   switch( type->type )
501   {
502   case RPC_FC_BYTE:
503   case RPC_FC_CHAR:
504   case RPC_FC_WCHAR:
505   case RPC_FC_SHORT:
506   case RPC_FC_USHORT:
507   case RPC_FC_ENUM16:
508   case RPC_FC_LONG:
509   case RPC_FC_ULONG:
510   case RPC_FC_ENUM32:
511   case RPC_FC_STRUCT:
512     break;
513
514   case RPC_FC_FP:
515   case RPC_FC_IP:
516     constraint = get_attrp( arg->attrs, ATTR_IIDIS );
517     if( constraint )
518       print_proxy( "_StubMsg.MaxCount = (unsigned long) ( %s );\n",constraint->name);
519     print_proxy( "NdrClearOutParameters( &_StubMsg, ");
520     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index );
521     fprintf(proxy, "(void*)%s );\n", arg->name );
522     break;
523
524   default:
525     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
526   }
527 }
528
529 static void proxy_free_variables( var_t *arg )
530 {
531   END_OF_LIST(arg);
532   while (arg) {
533     if (is_attr(arg->attrs, ATTR_OUT)) 
534     {
535       free_variable( arg );
536       fprintf(proxy, "\n");
537     }
538     arg = PREV_LINK(arg);
539   }
540 }
541
542 static void gen_proxy(type_t *iface, func_t *cur, int idx)
543 {
544   var_t *def = cur->def;
545   int has_ret = !is_void(def->type, def);
546
547   indent = 0;
548   write_type(proxy, def->type, def, def->tname);
549   print_proxy( " STDMETHODCALLTYPE %s_", iface->name);
550   write_name(proxy, def);
551   print_proxy( "_Proxy(\n");
552   write_args(proxy, cur->args, iface->name, 1, TRUE);
553   print_proxy( ")\n");
554   print_proxy( "{\n");
555   indent ++;
556   /* local variables */
557   if (has_ret) {
558     print_proxy( "" );
559     write_type(proxy, def->type, def, def->tname);
560     print_proxy( " _RetVal;\n");
561   }
562   print_proxy( "RPC_MESSAGE _Msg;\n" );
563   print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" );
564   print_proxy( "\n");
565
566   /* FIXME: trace */
567   clear_output_vars( cur->args );
568
569   print_proxy( "RpcTryExcept\n" );
570   print_proxy( "{\n" );
571   indent++;
572   print_proxy( "NdrProxyInitialize(This, &_Msg, &_StubMsg, &Object_StubDesc, %d);\n", idx);
573   proxy_check_pointers( cur->args );
574
575   print_proxy( "RpcTryFinally\n" );
576   print_proxy( "{\n" );
577   indent++;
578
579   gen_marshall( cur->args );
580
581   print_proxy( "NdrProxySendReceive(This, &_StubMsg);\n" );
582   fprintf(proxy, "\n");
583   print_proxy("if ((_Msg.DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
584   indent++;
585   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" );
586   indent--;
587   fprintf(proxy, "\n");
588
589   gen_unmarshall( cur->args );
590   if (has_ret) {
591     /* 
592      * FIXME: We only need to round the buffer up if it could be unaligned...
593      *    We should calculate how much buffer we used and output the following
594      *    line only if necessary.
595      */
596     print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n");
597
598     print_proxy( "_RetVal = *((" );
599     write_type(proxy, def->type, def, def->tname);
600     fprintf(proxy, "*)_StubMsg.Buffer)++;\n");
601   }
602
603   indent--;
604   print_proxy( "}\n");
605   print_proxy( "RpcFinally\n" );
606   print_proxy( "{\n" );
607   indent++;
608   print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" );
609   indent--;
610   print_proxy( "}\n");
611   print_proxy( "RpcEndFinally\n" );
612   indent--;
613   print_proxy( "}\n" );
614   print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
615   print_proxy( "{\n" );
616   if (has_ret) {
617     indent++;
618     proxy_free_variables( cur->args );
619     print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
620     indent--;
621   }
622   print_proxy( "}\n" );
623   print_proxy( "RpcEndExcept\n" );
624
625   if (has_ret) {
626     print_proxy( "return _RetVal;\n" );
627   }
628   indent--;
629   print_proxy( "}\n");
630   print_proxy( "\n");
631 }
632
633 static void stub_write_locals( var_t *arg )
634 {
635   int n = 0;
636   while (arg) {
637     int outptr = is_attr(arg->attrs, ATTR_OUT);
638
639     /* create a temporary variable to store the output */
640     if (outptr) {
641       var_t temp;
642       memset( &temp, 0, sizeof temp );
643       temp.ptr_level = arg->ptr_level - 1; /* dereference once */
644       print_proxy("");
645       write_type(proxy, arg->type, &temp, arg->tname);
646       fprintf(proxy, " _M%d;\n",n++);
647     }
648     print_proxy("");
649     write_type(proxy, arg->type, arg, arg->tname);
650     fprintf(proxy, " ");
651     write_name(proxy, arg);
652     fprintf(proxy, ";\n");
653     arg = NEXT_LINK(arg);
654   }
655 }
656
657 static void stub_unmarshall( var_t *arg )
658 {
659   int n = 0;
660   END_OF_LIST(arg);
661   while (arg) {
662     if (is_attr(arg->attrs, ATTR_IN))
663     {
664       unmarshall_copy_arg( arg );
665       fprintf(proxy,"\n");
666     }
667     else if (is_attr(arg->attrs, ATTR_OUT)) {
668       type_t *type = get_base_type(arg);
669       switch( type->type )
670       {
671       case RPC_FC_STRUCT:
672         print_proxy("MIDL_memset(");
673         write_name(proxy, arg);
674         fprintf(proxy,", 0, sizeof(");
675         write_type(proxy, arg->type, arg, arg->tname);
676         fprintf(proxy,"));\n");
677         break;
678       default:
679         print_proxy("");
680         write_name(proxy, arg);
681         fprintf(proxy," = &_M%d;\n", n);
682         print_proxy("_M%d = 0;\n", n++);
683         break;
684       }
685     }
686     arg = PREV_LINK(arg);
687   }
688 }
689
690 static void stub_gen_marshall_size( var_t *arg )
691 {
692   print_proxy( "_StubMsg.BufferLength = 0U;\n" );
693
694   END_OF_LIST(arg);
695   while (arg) {
696     if (is_attr(arg->attrs, ATTR_OUT))
697       marshall_size_arg( arg );
698     arg = PREV_LINK(arg);
699   }
700 }
701
702 static void stub_gen_marshall_copydata( var_t *arg )
703 {
704   END_OF_LIST(arg);
705   while (arg) {
706     if (is_attr(arg->attrs, ATTR_OUT))
707       marshall_copy_arg( arg );
708     arg = PREV_LINK(arg);
709   }
710 }
711
712 static void stub_genmarshall( var_t *args )
713 {
714   /* FIXME: size buffer */
715   stub_gen_marshall_size( args );
716
717   print_proxy("NdrStubGetBuffer(This, pRpcChannelBuffer, &_StubMsg);\n");
718
719   stub_gen_marshall_copydata( args );
720 }
721
722 static void gen_stub(type_t *iface, func_t *cur, char *cas)
723 {
724   var_t *def = cur->def;
725   var_t *arg;
726   int has_ret = !is_void(def->type, def);
727
728   indent = 0;
729   print_proxy( "void __RPC_STUB %s_", iface->name);
730   write_name(proxy, def);
731   print_proxy( "_Stub(\n");
732   indent++;
733   print_proxy( "IRpcStubBuffer* This,\n");
734   print_proxy( "IRpcChannelBuffer* pRpcChannelBuffer,\n");
735   print_proxy( "PRPC_MESSAGE _Msg,\n");
736   print_proxy( "DWORD* _pdwStubPhase)\n");
737   indent--;
738   print_proxy( "{\n");
739   indent++;
740   /* local variables */
741   if (has_ret) {
742     print_proxy("");
743     write_type(proxy, def->type, def, def->tname);
744     fprintf(proxy, " _RetVal;\n");
745   }
746   print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name);
747   print_proxy("MIDL_STUB_MESSAGE _StubMsg;\n");
748   stub_write_locals( cur->args );
749   fprintf(proxy, "\n");
750
751   /* FIXME: trace */
752
753   print_proxy("NdrStubInitialize(_Msg, &_StubMsg, &Object_StubDesc, pRpcChannelBuffer);\n");
754   fprintf(proxy, "\n");
755
756   print_proxy("RpcTryFinally\n");
757   print_proxy("{\n");
758   indent++;
759   print_proxy("if ((_Msg->DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
760   indent++;
761   print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" );
762   indent--;
763   fprintf(proxy, "\n");
764
765   stub_unmarshall( cur->args );
766   fprintf(proxy, "\n");
767
768   print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
769   fprintf(proxy, "\n");
770   print_proxy("");
771   if (has_ret) fprintf(proxy, "_RetVal = ");
772   fprintf(proxy, "%s_", iface->name);
773   if (cas) fprintf(proxy, "%s_Stub", cas);
774   else write_name(proxy, def);
775   fprintf(proxy, "(_This");
776   arg = cur->args;
777   if (arg) {
778     END_OF_LIST(arg);
779     while (arg) {
780       fprintf(proxy, ", ");
781       write_name(proxy, arg);
782       arg = PREV_LINK(arg);
783     }
784   }
785   fprintf(proxy, ");\n");
786   fprintf(proxy, "\n");
787   print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
788   fprintf(proxy, "\n");
789
790   stub_genmarshall( cur->args );
791   fprintf(proxy, "\n");
792
793   if (has_ret) {
794     /* 
795      * FIXME: We only need to round the buffer up if it could be unaligned...
796      *    We should calculate how much buffer we used and output the following
797      *    line only if necessary.
798      */
799     print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n");
800
801     print_proxy( "*((" );
802     write_type(proxy, def->type, def, def->tname);
803     fprintf(proxy, "*)_StubMsg.Buffer)++ = _RetVal;\n");
804   }
805
806   indent--;
807   print_proxy("}\n");
808   print_proxy("RpcFinally\n");
809   print_proxy("{\n");
810   print_proxy("}\n");
811   print_proxy("RpcEndFinally\n");
812
813   print_proxy("_Msg->BufferLength = ((long)_StubMsg.Buffer - (long)_Msg->Buffer);\n");
814   indent--;
815
816   print_proxy("}\n");
817   print_proxy("\n");
818 }
819
820 static int write_proxy_methods(type_t *iface)
821 {
822   func_t *cur = iface->funcs;
823   int i = 0;
824
825   END_OF_LIST(cur);
826
827   if (iface->ref) i = write_proxy_methods(iface->ref);
828   while (cur) {
829     var_t *def = cur->def;
830     if (!is_callas(def->attrs)) {
831       if (i) fprintf(proxy, ",\n");
832       print_proxy( "%s_", iface->name);
833       write_name(proxy, def);
834       fprintf(proxy, "_Proxy");
835       i++;
836     }
837     cur = PREV_LINK(cur);
838   }
839   return i;
840 }
841
842 static int write_stub_methods(type_t *iface)
843 {
844   func_t *cur = iface->funcs;
845   int i = 0;
846
847   END_OF_LIST(cur);
848
849   if (iface->ref) i = write_stub_methods(iface->ref);
850   else return i; /* skip IUnknown */
851   while (cur) {
852     var_t *def = cur->def;
853     if (!is_local(def->attrs)) {
854       if (i) fprintf(proxy,",\n");
855       print_proxy( "%s_", iface->name);
856       write_name(proxy, def);
857       fprintf(proxy, "_Stub");
858       i++;
859     }
860     cur = PREV_LINK(cur);
861   }
862   return i;
863 }
864
865 static void write_proxy(type_t *iface)
866 {
867   int midx = -1, stubs;
868   func_t *cur = iface->funcs;
869
870   if (!cur) return;
871
872   END_OF_LIST(cur);
873
874   /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */
875
876   fprintf(proxy, "/*****************************************************************************\n");
877   fprintf(proxy, " * %s interface\n", iface->name);
878   fprintf(proxy, " */\n");
879   while (cur) {
880     var_t *def = cur->def;
881     if (!is_local(def->attrs)) {
882       var_t *cas = is_callas(def->attrs);
883       char *cname = cas ? cas->name : NULL;
884       int idx = cur->idx;
885       if (cname) {
886         func_t *m = iface->funcs;
887         while (m && strcmp(get_name(m->def), cname))
888           m = NEXT_LINK(m);
889         idx = m->idx;
890       }
891       gen_proxy(iface, cur, idx);
892       gen_stub(iface, cur, cname);
893       if (midx == -1) midx = idx;
894       else if (midx != idx) yyerror("method index mismatch in write_proxy");
895       midx++;
896     }
897     cur = PREV_LINK(cur);
898   }
899
900   /* proxy vtable */
901   print_proxy( "const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name);
902   print_proxy( "{\n");
903   indent++;
904   print_proxy( "{\n", iface->name);
905   indent++;
906   print_proxy( "&IID_%s,\n", iface->name);
907   indent--;
908   print_proxy( "},\n");
909   print_proxy( "{\n");
910   indent++;
911   write_proxy_methods(iface);
912   fprintf(proxy, "\n");
913   indent--;
914   print_proxy( "}\n");
915   indent--;
916   print_proxy( "};\n");
917   fprintf(proxy, "\n\n");
918
919   /* stub vtable */
920   print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name);
921   print_proxy( "{\n");
922   indent++;
923   stubs = write_stub_methods(iface);
924   fprintf(proxy, "\n");
925   indent--;
926   fprintf(proxy, "};\n");
927   print_proxy( "\n");
928   print_proxy( "const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name);
929   print_proxy( "{\n");
930   indent++;
931   print_proxy( "{\n");
932   indent++;
933   print_proxy( "&IID_%s,\n", iface->name);
934   print_proxy( "0,\n");
935   print_proxy( "%d,\n", stubs+3);
936   print_proxy( "&%s_table[-3],\n", iface->name);
937   indent--;
938   print_proxy( "},\n", iface->name);
939   print_proxy( "{\n");
940   indent++;
941   print_proxy( "CStdStubBuffer_METHODS\n");
942   indent--;
943   print_proxy( "}\n");
944   indent--;
945   print_proxy( "};\n");
946   print_proxy( "\n");
947 }
948
949 void write_proxies(ifref_t *ifaces)
950 {
951   ifref_t *lcur = ifaces;
952   ifref_t *cur;
953   char *file_id = proxy_token;
954   int c;
955
956   if (!do_proxies) return;
957   if (!lcur) return;
958   END_OF_LIST(lcur);
959
960   init_proxy();
961   if(!proxy) return;
962
963   cur = lcur;
964   while (cur) {
965     if (is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
966       write_proxy(cur->iface);
967     cur = PREV_LINK(cur);
968   }
969
970   if (!proxy) return;
971
972   write_stubdesc();
973
974   print_proxy( "#if !defined(__RPC_WIN32__)\n");
975   print_proxy( "#error Currently only Wine and WIN32 are supported.\n");
976   print_proxy( "#endif\n");
977   print_proxy( "\n");
978   write_formatstring( 1 );
979   write_formatstring( 0 );
980
981   fprintf(proxy, "const CInterfaceProxyVtbl* _%s_ProxyVtblList[] =\n", file_id);
982   fprintf(proxy, "{\n");
983   cur = lcur;
984   while (cur) {
985     if(cur->iface->ref && cur->iface->funcs &&
986        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
987       fprintf(proxy, "    (CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", cur->iface->name);
988     cur = PREV_LINK(cur);
989   }
990   fprintf(proxy, "    0\n");
991   fprintf(proxy, "};\n");
992   fprintf(proxy, "\n");
993
994   fprintf(proxy, "const CInterfaceStubVtbl* _%s_StubVtblList[] =\n", file_id);
995   fprintf(proxy, "{\n");
996   cur = lcur;
997   while (cur) {
998     if(cur->iface->ref && cur->iface->funcs &&
999        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
1000       fprintf(proxy, "    (CInterfaceStubVtbl*)&_%sStubVtbl,\n", cur->iface->name);
1001     cur = PREV_LINK(cur);
1002   }
1003   fprintf(proxy, "    0\n");
1004   fprintf(proxy, "};\n");
1005   fprintf(proxy, "\n");
1006
1007   fprintf(proxy, "PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
1008   fprintf(proxy, "{\n");
1009   cur = lcur;
1010   while (cur) {
1011     if(cur->iface->ref && cur->iface->funcs &&
1012        is_object(cur->iface->attrs) && !is_local(cur->iface->attrs))
1013       fprintf(proxy, "    \"%s\",\n", cur->iface->name);
1014     cur = PREV_LINK(cur);
1015   }
1016   fprintf(proxy, "    0\n");
1017   fprintf(proxy, "};\n");
1018   fprintf(proxy, "\n");
1019
1020   fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id);
1021   fprintf(proxy, "\n");
1022   fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
1023   fprintf(proxy, "{\n");
1024   cur = lcur;
1025   c = 0;
1026   while (cur) {
1027     if(cur->iface->ref)
1028     {
1029       fprintf(proxy, "    if (!_%s_CHECK_IID(%d))\n", file_id, c);
1030       fprintf(proxy, "    {\n");
1031       fprintf(proxy, "        *pIndex = %d;\n", c);
1032       fprintf(proxy, "        return 1;\n");
1033       fprintf(proxy, "    }\n");
1034       c++;
1035     }
1036     cur = PREV_LINK(cur);
1037   }
1038   fprintf(proxy, "    return 0;\n");
1039   fprintf(proxy, "}\n");
1040   fprintf(proxy, "\n");
1041
1042   fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id);
1043   fprintf(proxy, "{\n");
1044   fprintf(proxy, "    (PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id);
1045   fprintf(proxy, "    (PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id);
1046   fprintf(proxy, "    (const PCInterfaceName*)&_%s_InterfaceNamesList,\n", file_id);
1047   fprintf(proxy, "    0,\n");
1048   fprintf(proxy, "    &_%s_IID_Lookup,\n", file_id);
1049   fprintf(proxy, "    %d,\n", c);
1050   fprintf(proxy, "    1,\n");
1051   fprintf(proxy, "    0,\n");
1052   fprintf(proxy, "    0,\n");
1053   fprintf(proxy, "    0,\n");
1054   fprintf(proxy, "    0\n");
1055   fprintf(proxy, "};\n");
1056
1057   fclose(proxy);
1058 }