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