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