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