widl: Create an explicit structure for the function frame of all generated functions.
[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 <ctype.h>
32
33 #include "widl.h"
34 #include "utils.h"
35 #include "parser.h"
36 #include "header.h"
37 #include "typegen.h"
38 #include "expr.h"
39
40 #define END_OF_LIST(list)       \
41   do {                          \
42     if (list) {                 \
43       while (NEXT_LINK(list))   \
44         list = NEXT_LINK(list); \
45     }                           \
46   } while(0)
47
48 static FILE* proxy;
49 static int indent = 0;
50
51 /* FIXME: support generation of stubless proxies */
52
53 static void print_proxy( const char *format, ... )
54 {
55   va_list va;
56   va_start( va, format );
57   print( proxy, indent, format, va );
58   va_end( va );
59 }
60
61 static void write_stubdescproto(void)
62 {
63   print_proxy( "static const MIDL_STUB_DESC Object_StubDesc;\n");
64   print_proxy( "\n");
65 }
66
67 static void write_stubdesc(int expr_eval_routines)
68 {
69   print_proxy( "static const MIDL_STUB_DESC Object_StubDesc =\n{\n");
70   indent++;
71   print_proxy( "0,\n");
72   print_proxy( "NdrOleAllocate,\n");
73   print_proxy( "NdrOleFree,\n");
74   print_proxy( "{0}, 0, 0, %s, 0,\n", expr_eval_routines ? "ExprEvalRoutines" : "0");
75   print_proxy( "__MIDL_TypeFormatString.Format,\n");
76   print_proxy( "1, /* -error bounds_check flag */\n");
77   print_proxy( "0x10001, /* Ndr library version */\n");
78   print_proxy( "0,\n");
79   print_proxy( "0x50100a4, /* MIDL Version 5.1.164 */\n");
80   print_proxy( "0,\n");
81   print_proxy("%s,\n", list_empty(&user_type_list) ? "0" : "UserMarshalRoutines");
82   print_proxy( "0,  /* notify & notify_flag routine table */\n");
83   print_proxy( "1,  /* Flags */\n");
84   print_proxy( "0,  /* Reserved3 */\n");
85   print_proxy( "0,  /* Reserved4 */\n");
86   print_proxy( "0   /* Reserved5 */\n");
87   indent--;
88   print_proxy( "};\n");
89   print_proxy( "\n");
90 }
91
92 static void init_proxy(const statement_list_t *stmts)
93 {
94   if (proxy) return;
95   if(!(proxy = fopen(proxy_name, "w")))
96     error("Could not open %s for output\n", proxy_name);
97   print_proxy( "/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", PACKAGE_VERSION, input_name);
98   print_proxy( "\n");
99   print_proxy( "#ifndef __REDQ_RPCPROXY_H_VERSION__\n");
100   print_proxy( "#define __REQUIRED_RPCPROXY_H_VERSION__ 440\n");
101   print_proxy( "#endif /* __REDQ_RPCPROXY_H_VERSION__ */\n");
102   print_proxy( "\n");
103   print_proxy( "#define __midl_proxy\n");
104   print_proxy( "#include \"objbase.h\"\n");
105   print_proxy( "#include \"rpcproxy.h\"\n");
106   print_proxy( "#ifndef __RPCPROXY_H_VERSION__\n");
107   print_proxy( "#error This code needs a newer version of rpcproxy.h\n");
108   print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n");
109   print_proxy( "\n");
110   print_proxy( "#include \"%s\"\n", header_name);
111   print_proxy( "\n");
112   print_proxy( "#ifndef USE_COMPILER_EXCEPTIONS\n");
113   print_proxy( "\n");
114   print_proxy( "#include \"wine/exception.h\"\n");
115   print_proxy( "#undef RpcTryExcept\n");
116   print_proxy( "#undef RpcExcept\n");
117   print_proxy( "#undef RpcEndExcept\n");
118   print_proxy( "#undef RpcTryFinally\n");
119   print_proxy( "#undef RpcFinally\n");
120   print_proxy( "#undef RpcEndFinally\n");
121   print_proxy( "#undef RpcExceptionCode\n");
122   print_proxy( "\n");
123   print_proxy( "struct __proxy_frame\n");
124   print_proxy( "{\n");
125   print_proxy( "    EXCEPTION_REGISTRATION_RECORD frame;\n");
126   print_proxy( "    sigjmp_buf                    jmp;\n");
127   print_proxy( "    DWORD                         code;\n");
128   print_proxy( "    MIDL_STUB_MESSAGE             _StubMsg;\n");
129   print_proxy( "    void                         *this;\n");
130   print_proxy( "    int                           fullptr;\n");
131   print_proxy( "};\n");
132   print_proxy( "\n");
133   print_proxy("static void __proxy_finally_handler( struct __proxy_frame *frame )\n");
134   print_proxy( "{\n");
135   print_proxy( "    if (frame->fullptr) NdrFullPointerXlatFree( frame->_StubMsg.FullPtrXlatTables );\n");
136   print_proxy( "    if (frame->this) NdrProxyFreeBuffer( frame->this, &frame->_StubMsg );\n" );
137   print_proxy( "}\n\n");
138   print_proxy( "static DWORD __proxy_exception_handler( EXCEPTION_RECORD *record,\n");
139   print_proxy( "                                        EXCEPTION_REGISTRATION_RECORD *frame,\n");
140   print_proxy( "                                        CONTEXT *context,\n");
141   print_proxy( "                                        EXCEPTION_REGISTRATION_RECORD **pdispatcher )\n");
142   print_proxy( "{\n");
143   print_proxy( "    struct __proxy_frame *proxy_frame = (struct __proxy_frame *)frame;\n");
144   print_proxy( "\n");
145   print_proxy( "    if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))\n");
146   print_proxy( "    {\n" );
147   print_proxy( "        if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))\n");
148   print_proxy( "            __proxy_finally_handler( proxy_frame );\n");
149   print_proxy( "        return ExceptionContinueSearch;\n");
150   print_proxy( "    }\n" );
151   print_proxy( "    if (proxy_frame->_StubMsg.dwStubPhase == PROXY_SENDRECEIVE)\n");
152   print_proxy( "        return ExceptionContinueSearch;\n");
153   print_proxy( "\n");
154   print_proxy( "    proxy_frame->code = record->ExceptionCode;\n");
155   print_proxy( "    __wine_rtl_unwind( frame, record );\n");
156   print_proxy( "    __proxy_finally_handler( proxy_frame );\n");
157   print_proxy( "    __wine_pop_frame( frame );\n");
158   print_proxy( "    siglongjmp( proxy_frame->jmp, 1 );\n");
159   print_proxy( "}\n");
160   print_proxy( "\n");
161   print_proxy( "#define RpcTryExcept \\\n");
162   print_proxy( "        __frame->frame.Handler = __proxy_exception_handler; \\\n");
163   print_proxy( "        if (!sigsetjmp( __frame->jmp, 0 )) \\\n");
164   print_proxy( "        { \\\n");
165   print_proxy( "            __wine_push_frame( &__frame->frame ); \\\n");
166   print_proxy( "            {\n");
167   print_proxy( "\n");
168   print_proxy( "#define RpcExcept(expr) \\\n");
169   print_proxy( "            } \\\n");
170   print_proxy( "            __wine_pop_frame( &__frame->frame ); \\\n");
171   print_proxy( "        } \\\n");
172   print_proxy( "        else\n");
173   print_proxy( "\n");
174   print_proxy( "#define RpcEndExcept\n");
175   print_proxy( "\n");
176   print_proxy( "#define RpcExceptionCode() (__frame->code)\n");
177   print_proxy( "\n");
178   print_proxy( "#define RpcTryFinallyProxy(ptr) \\\n");
179   print_proxy("    __frame->this = This; \\\n");
180   print_proxy("    __frame->fullptr = ptr;\n");
181   print_proxy( "\n");
182   print_proxy( "#define RpcFinallyProxy \\\n");
183   print_proxy("    __frame->this = 0; \\\n");
184   print_proxy("    __frame->fullptr = 0;\n");
185   print_proxy( "\n");
186   print_proxy( "#define RpcTryFinallyStub\n");
187   print_proxy( "\n");
188   print_proxy( "#define RpcFinallyStub\n");
189   print_proxy( "\n");
190   print_proxy( "#define RpcEndFinally\n");
191   print_proxy( "\n");
192   print_proxy( "#else /* USE_COMPILER_EXCEPTIONS */\n");
193   print_proxy( "\n");
194   print_proxy( "#define RpcTryFinallyProxy(ptr) RpcTryFinally\n");
195   print_proxy( "#define RpcTryFinallyStub RpcTryFinally\n");
196   print_proxy( "#define RpcFinallyProxy RpcFinally\n");
197   print_proxy( "#define RpcFinallyStub RpcFinally\n");
198   print_proxy( "\n");
199   print_proxy( "struct __proxy_frame\n");
200   print_proxy( "{\n");
201   print_proxy( "    MIDL_STUB_MESSAGE _StubMsg;\n");
202   print_proxy( "};\n");
203   print_proxy( "\n");
204   print_proxy( "#endif /* USE_COMPILER_EXCEPTIONS */\n");
205   print_proxy( "\n");
206   print_proxy( "struct __stub_frame\n");
207   print_proxy( "{\n");
208   print_proxy( "    MIDL_STUB_MESSAGE _StubMsg;\n");
209   print_proxy( "};\n");
210   print_proxy( "\n");
211   write_formatstringsdecl(proxy, indent, stmts, need_proxy);
212   write_stubdescproto();
213 }
214
215 static void clear_output_vars( const var_list_t *args )
216 {
217   const var_t *arg;
218
219   if (!args) return;
220   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
221   {
222     if (is_attr(arg->attrs, ATTR_OUT) && !is_attr(arg->attrs, ATTR_IN)) {
223       print_proxy( "if(%s)\n", arg->name );
224       indent++;
225       print_proxy( "MIDL_memset( %s, 0, sizeof( *%s ));\n", arg->name, arg->name );
226       indent--;
227     }
228   }
229 }
230
231 int is_var_ptr(const var_t *v)
232 {
233   return is_ptr(v->type);
234 }
235
236 int cant_be_null(const var_t *v)
237 {
238   /* Search backwards for the most recent pointer attribute.  */
239   const attr_list_t *attrs = v->attrs;
240   const type_t *type = v->type;
241
242   /* context handles have their own checking so they can be null for the
243    * purposes of null ref pointer checking */
244   if (is_aliaschain_attr(type, ATTR_CONTEXTHANDLE))
245       return 0;
246
247   if (! attrs && type)
248   {
249     attrs = type->attrs;
250     type = type->ref;
251   }
252
253   while (attrs)
254   {
255     int t = get_attrv(attrs, ATTR_POINTERTYPE);
256
257     if (t == RPC_FC_FP || t == RPC_FC_OP || t == RPC_FC_UP)
258       return 0;
259
260     if (t == RPC_FC_RP)
261       return 1;
262
263     if (type)
264     {
265       attrs = type->attrs;
266       type = type->ref;
267     }
268     else
269       attrs = NULL;
270   }
271
272   return 1;                             /* Default is RPC_FC_RP.  */
273 }
274
275 static void proxy_check_pointers( const var_list_t *args )
276 {
277   const var_t *arg;
278
279   if (!args) return;
280   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
281   {
282     if (is_var_ptr(arg) && cant_be_null(arg)) {
283         print_proxy( "if(!%s)\n", arg->name );
284         indent++;
285         print_proxy( "RpcRaiseException(RPC_X_NULL_REF_POINTER);\n");
286         indent--;
287     }
288   }
289 }
290
291 static void free_variable( const var_t *arg )
292 {
293   unsigned int type_offset = arg->type->typestring_offset;
294   expr_t *iid;
295   type_t *type = arg->type;
296   expr_t *size = get_size_is_expr(type, arg->name);
297
298   if (size)
299   {
300     print_proxy( "__frame->_StubMsg.MaxCount = " );
301     write_expr(proxy, size, 0, 1, NULL, NULL);
302     fprintf(proxy, ";\n\n");
303     print_proxy( "NdrClearOutParameters( &__frame->_StubMsg, ");
304     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
305     fprintf(proxy, "(void*)%s );\n", arg->name );
306     return;
307   }
308
309   switch( type->type )
310   {
311   case RPC_FC_BYTE:
312   case RPC_FC_CHAR:
313   case RPC_FC_WCHAR:
314   case RPC_FC_SHORT:
315   case RPC_FC_USHORT:
316   case RPC_FC_ENUM16:
317   case RPC_FC_LONG:
318   case RPC_FC_ULONG:
319   case RPC_FC_ENUM32:
320   case RPC_FC_STRUCT:
321     break;
322
323   case RPC_FC_FP:
324   case RPC_FC_IP:
325     iid = get_attrp( arg->attrs, ATTR_IIDIS );
326     if( iid )
327     {
328       print_proxy( "__frame->_StubMsg.MaxCount = (unsigned long) " );
329       write_expr(proxy, iid, 1, 1, NULL, NULL);
330       print_proxy( ";\n\n" );
331     }
332     print_proxy( "NdrClearOutParameters( &__frame->_StubMsg, ");
333     fprintf(proxy, "&__MIDL_TypeFormatString.Format[%u], ", type_offset );
334     fprintf(proxy, "(void*)%s );\n", arg->name );
335     break;
336
337   default:
338     print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type );
339   }
340 }
341
342 static void proxy_free_variables( var_list_t *args )
343 {
344   const var_t *arg;
345
346   if (!args) return;
347   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
348     if (is_attr(arg->attrs, ATTR_OUT))
349     {
350       free_variable( arg );
351       fprintf(proxy, "\n");
352     }
353 }
354
355 static void gen_proxy(type_t *iface, const func_t *cur, int idx,
356                       unsigned int proc_offset)
357 {
358   var_t *def = cur->def;
359   int has_ret = !is_void(get_func_return_type(cur));
360   int has_full_pointer = is_full_pointer_function(cur);
361   const char *callconv = get_attrp(def->type->attrs, ATTR_CALLCONV);
362   if (!callconv) callconv = "";
363
364   indent = 0;
365   write_type_decl_left(proxy, get_func_return_type(cur));
366   print_proxy( " %s %s_%s_Proxy(\n", callconv, iface->name, get_name(def));
367   write_args(proxy, cur->args, iface->name, 1, TRUE);
368   print_proxy( ")\n");
369   print_proxy( "{\n");
370   indent ++;
371   print_proxy( "struct __proxy_frame __f, * const __frame = &__f;\n" );
372   /* local variables */
373   if (has_ret) {
374     print_proxy( "" );
375     write_type_decl_left(proxy, get_func_return_type(cur));
376     print_proxy( " _RetVal;\n");
377   }
378   print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
379   if (has_ret) {
380     if (decl_indirect(get_func_return_type(cur)))
381       print_proxy("void *_p_%s = &%s;\n",
382                  "_RetVal", "_RetVal");
383   }
384   print_proxy( "\n");
385
386   if (has_full_pointer)
387     write_full_pointer_init(proxy, indent, cur, FALSE);
388
389   /* FIXME: trace */
390   clear_output_vars( cur->args );
391
392   print_proxy( "RpcTryExcept\n" );
393   print_proxy( "{\n" );
394   indent++;
395   print_proxy( "NdrProxyInitialize(This, &_RpcMessage, &__frame->_StubMsg, &Object_StubDesc, %d);\n", idx);
396   proxy_check_pointers( cur->args );
397
398   print_proxy( "RpcTryFinallyProxy(%d)\n", has_full_pointer );
399   print_proxy( "{\n" );
400   indent++;
401
402   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_BUFFERSIZE);
403
404   print_proxy( "NdrProxyGetBuffer(This, &__frame->_StubMsg);\n" );
405
406   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_MARSHAL);
407
408   print_proxy( "NdrProxySendReceive(This, &__frame->_StubMsg);\n" );
409   fprintf(proxy, "\n");
410   print_proxy( "__frame->_StubMsg.BufferStart = _RpcMessage.Buffer;\n" );
411   print_proxy( "__frame->_StubMsg.BufferEnd   = __frame->_StubMsg.BufferStart + _RpcMessage.BufferLength;\n\n" );
412
413   print_proxy("if ((_RpcMessage.DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
414   indent++;
415   print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
416   indent--;
417   fprintf(proxy, "\n");
418
419   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_UNMARSHAL);
420
421   if (has_ret)
422   {
423       if (decl_indirect(get_func_return_type(cur)))
424           print_proxy("MIDL_memset(&%s, 0, sizeof(%s));\n", "_RetVal", "_RetVal");
425       else if (is_ptr(get_func_return_type(cur)) || is_array(get_func_return_type(cur)))
426           print_proxy("%s = 0;\n", "_RetVal");
427       write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_UNMARSHAL);
428   }
429
430   indent--;
431   print_proxy( "}\n");
432   print_proxy( "RpcFinallyProxy\n" );
433   print_proxy( "{\n" );
434   indent++;
435   if (has_full_pointer)
436     write_full_pointer_free(proxy, indent, cur);
437   print_proxy( "NdrProxyFreeBuffer(This, &__frame->_StubMsg);\n" );
438   indent--;
439   print_proxy( "}\n");
440   print_proxy( "RpcEndFinally\n" );
441   indent--;
442   print_proxy( "}\n" );
443   print_proxy( "RpcExcept(__frame->_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" );
444   print_proxy( "{\n" );
445   if (has_ret) {
446     indent++;
447     proxy_free_variables( cur->args );
448     print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" );
449     indent--;
450   }
451   print_proxy( "}\n" );
452   print_proxy( "RpcEndExcept\n" );
453
454   if (has_ret) {
455     print_proxy( "return _RetVal;\n" );
456   }
457   indent--;
458   print_proxy( "}\n");
459   print_proxy( "\n");
460 }
461
462 static void gen_stub(type_t *iface, const func_t *cur, const char *cas,
463                      unsigned int proc_offset)
464 {
465   var_t *def = cur->def;
466   const var_t *arg;
467   int has_ret = !is_void(get_func_return_type(cur));
468   int has_full_pointer = is_full_pointer_function(cur);
469
470   indent = 0;
471   print_proxy( "void __RPC_STUB %s_%s_Stub(\n", iface->name, get_name(def));
472   indent++;
473   print_proxy( "IRpcStubBuffer* This,\n");
474   print_proxy( "IRpcChannelBuffer *_pRpcChannelBuffer,\n");
475   print_proxy( "PRPC_MESSAGE _pRpcMessage,\n");
476   print_proxy( "DWORD* _pdwStubPhase)\n");
477   indent--;
478   print_proxy( "{\n");
479   indent++;
480   print_proxy( "struct __stub_frame __f, * const __frame = &__f;\n" );
481   print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name);
482   declare_stub_args( proxy, indent, cur );
483   fprintf(proxy, "\n");
484
485   /* FIXME: trace */
486
487   print_proxy("NdrStubInitialize(_pRpcMessage, &__frame->_StubMsg, &Object_StubDesc, _pRpcChannelBuffer);\n");
488   fprintf(proxy, "\n");
489
490   write_parameters_init(proxy, indent, cur);
491
492   print_proxy("RpcTryFinallyStub\n");
493   print_proxy("{\n");
494   indent++;
495   if (has_full_pointer)
496     write_full_pointer_init(proxy, indent, cur, TRUE);
497   print_proxy("if ((_pRpcMessage->DataRepresentation & 0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n");
498   indent++;
499   print_proxy("NdrConvert( &__frame->_StubMsg, &__MIDL_ProcFormatString.Format[%u]);\n", proc_offset );
500   indent--;
501   fprintf(proxy, "\n");
502
503   write_remoting_arguments(proxy, indent, cur, PASS_IN, PHASE_UNMARSHAL);
504   fprintf(proxy, "\n");
505
506   assign_stub_out_args( proxy, indent, cur );
507
508   print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n");
509   fprintf(proxy, "\n");
510   print_proxy("");
511   if (has_ret) fprintf(proxy, "_RetVal = ");
512   if (cas) fprintf(proxy, "%s_%s_Stub", iface->name, cas);
513   else fprintf(proxy, "_This->lpVtbl->%s", get_name(def));
514   fprintf(proxy, "(_This");
515
516   if (cur->args)
517   {
518       LIST_FOR_EACH_ENTRY( arg, cur->args, const var_t, entry )
519           fprintf(proxy, ", %s%s", arg->type->declarray ? "*" : "", get_name(arg));
520   }
521   fprintf(proxy, ");\n");
522   fprintf(proxy, "\n");
523   print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n");
524   fprintf(proxy, "\n");
525
526   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_BUFFERSIZE);
527
528   if (!is_void(get_func_return_type(cur)))
529     write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_BUFFERSIZE);
530
531   print_proxy("NdrStubGetBuffer(This, _pRpcChannelBuffer, &__frame->_StubMsg);\n");
532
533   write_remoting_arguments(proxy, indent, cur, PASS_OUT, PHASE_MARSHAL);
534   fprintf(proxy, "\n");
535
536   /* marshall the return value */
537   if (!is_void(get_func_return_type(cur)))
538     write_remoting_arguments(proxy, indent, cur, PASS_RETURN, PHASE_MARSHAL);
539
540   indent--;
541   print_proxy("}\n");
542   print_proxy("RpcFinallyStub\n");
543   print_proxy("{\n");
544
545   write_remoting_arguments(proxy, indent+1, cur, PASS_OUT, PHASE_FREE);
546
547   if (has_full_pointer)
548     write_full_pointer_free(proxy, indent, cur);
549
550   print_proxy("}\n");
551   print_proxy("RpcEndFinally\n");
552
553   print_proxy("_pRpcMessage->BufferLength = __frame->_StubMsg.Buffer - (unsigned char *)_pRpcMessage->Buffer;\n");
554   indent--;
555
556   print_proxy("}\n");
557   print_proxy("\n");
558 }
559
560 static int write_proxy_methods(type_t *iface, int skip)
561 {
562   const func_t *cur;
563   int i = 0;
564
565   if (iface->ref) i = write_proxy_methods(iface->ref, iface->ref->ref != NULL);
566   if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) {
567     var_t *def = cur->def;
568     if (!is_callas(def->attrs)) {
569       if (i) fprintf(proxy, ",\n");
570       if (skip) print_proxy( "0  /* %s_%s_Proxy */", iface->name, get_name(def));
571       else print_proxy( "%s_%s_Proxy", iface->name, get_name(def));
572       i++;
573     }
574   }
575   return i;
576 }
577
578 static int write_stub_methods(type_t *iface, int skip)
579 {
580   const func_t *cur;
581   int i = 0;
582
583   if (iface->ref) i = write_stub_methods(iface->ref, TRUE);
584   else return i; /* skip IUnknown */
585
586   if (iface->funcs) LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry ) {
587     var_t *def = cur->def;
588     if (!is_local(def->attrs)) {
589       if (i) fprintf(proxy,",\n");
590       if (skip) print_proxy("STUB_FORWARDING_FUNCTION");
591       else print_proxy( "%s_%s_Stub", iface->name, get_name(def));
592       i++;
593     }
594   }
595   return i;
596 }
597
598 static void write_proxy(type_t *iface, unsigned int *proc_offset)
599 {
600   int midx = -1, stubs;
601   const func_t *cur;
602
603   if (!iface->funcs) return;
604
605   /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */
606
607   fprintf(proxy, "/*****************************************************************************\n");
608   fprintf(proxy, " * %s interface\n", iface->name);
609   fprintf(proxy, " */\n");
610   LIST_FOR_EACH_ENTRY( cur, iface->funcs, const func_t, entry )
611   {
612     const var_t *def = cur->def;
613     if (!is_local(def->attrs)) {
614       const var_t *cas = is_callas(def->attrs);
615       const char *cname = cas ? cas->name : NULL;
616       int idx = cur->idx;
617       if (cname) {
618           const func_t *m;
619           LIST_FOR_EACH_ENTRY( m, iface->funcs, const func_t, entry )
620               if (!strcmp(m->def->name, cname))
621               {
622                   idx = m->idx;
623                   break;
624               }
625       }
626       gen_proxy(iface, cur, idx, *proc_offset);
627       gen_stub(iface, cur, cname, *proc_offset);
628       *proc_offset += get_size_procformatstring_func( cur );
629       if (midx == -1) midx = idx;
630       else if (midx != idx) error("method index mismatch in write_proxy\n");
631       midx++;
632     }
633   }
634
635   /* proxy vtable */
636   print_proxy( "static const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name);
637   print_proxy( "{\n");
638   indent++;
639   print_proxy( "{\n", iface->name);
640   indent++;
641   print_proxy( "&IID_%s,\n", iface->name);
642   indent--;
643   print_proxy( "},\n");
644   print_proxy( "{\n");
645   indent++;
646   write_proxy_methods(iface, FALSE);
647   fprintf(proxy, "\n");
648   indent--;
649   print_proxy( "}\n");
650   indent--;
651   print_proxy( "};\n");
652   fprintf(proxy, "\n\n");
653
654   /* stub vtable */
655   print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name);
656   print_proxy( "{\n");
657   indent++;
658   stubs = write_stub_methods(iface, FALSE);
659   fprintf(proxy, "\n");
660   indent--;
661   fprintf(proxy, "};\n");
662   print_proxy( "\n");
663   print_proxy( "static const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name);
664   print_proxy( "{\n");
665   indent++;
666   print_proxy( "{\n");
667   indent++;
668   print_proxy( "&IID_%s,\n", iface->name);
669   print_proxy( "0,\n");
670   print_proxy( "%d,\n", stubs+3);
671   print_proxy( "&%s_table[-3],\n", iface->name);
672   indent--;
673   print_proxy( "},\n", iface->name);
674   print_proxy( "{\n");
675   indent++;
676   print_proxy( "CStdStubBuffer_METHODS\n");
677   indent--;
678   print_proxy( "}\n");
679   indent--;
680   print_proxy( "};\n");
681   print_proxy( "\n");
682 }
683
684 static int does_any_iface(const statement_list_t *stmts, type_pred_t pred)
685 {
686   const statement_t *stmt;
687
688   if (stmts)
689     LIST_FOR_EACH_ENTRY(stmt, stmts, const statement_t, entry)
690     {
691       if (stmt->type == STMT_LIBRARY)
692       {
693           if (does_any_iface(stmt->u.lib->stmts, pred))
694               return TRUE;
695       }
696       else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
697       {
698         if (pred(stmt->u.type))
699           return TRUE;
700       }
701     }
702
703   return FALSE;
704 }
705
706 int need_proxy(const type_t *iface)
707 {
708   return is_object(iface->attrs) && !is_local(iface->attrs);
709 }
710
711 int need_stub(const type_t *iface)
712 {
713   return !is_object(iface->attrs) && !is_local(iface->attrs);
714 }
715
716 int need_proxy_file(const statement_list_t *stmts)
717 {
718   return does_any_iface(stmts, need_proxy);
719 }
720
721 int need_stub_files(const statement_list_t *stmts)
722 {
723   return does_any_iface(stmts, need_stub);
724 }
725
726 static void write_proxy_stmts(const statement_list_t *stmts, unsigned int *proc_offset)
727 {
728   const statement_t *stmt;
729   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
730   {
731     if (stmt->type == STMT_LIBRARY)
732       write_proxy_stmts(stmt->u.lib->stmts, proc_offset);
733     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
734     {
735       if (need_proxy(stmt->u.type))
736         write_proxy(stmt->u.type, proc_offset);
737     }
738   }
739 }
740
741 static void write_proxy_iface_name_format(const statement_list_t *stmts, const char *format)
742 {
743   const statement_t *stmt;
744   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
745   {
746     if (stmt->type == STMT_LIBRARY)
747       write_proxy_iface_name_format(stmt->u.lib->stmts, format);
748     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
749     {
750       type_t *iface = stmt->u.type;
751       if (iface->ref && iface->funcs && need_proxy(iface))
752         fprintf(proxy, format, iface->name);
753     }
754   }
755 }
756
757 static void write_iid_lookup(const statement_list_t *stmts, const char *file_id, int *c)
758 {
759   const statement_t *stmt;
760   if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
761   {
762     if (stmt->type == STMT_LIBRARY)
763       write_iid_lookup(stmt->u.lib->stmts, file_id, c);
764     else if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
765     {
766       type_t *iface = stmt->u.type;
767       if(iface->ref && iface->funcs && need_proxy(iface))
768       {
769         fprintf(proxy, "    if (!_%s_CHECK_IID(%d))\n", file_id, *c);
770         fprintf(proxy, "    {\n");
771         fprintf(proxy, "        *pIndex = %d;\n", *c);
772         fprintf(proxy, "        return 1;\n");
773         fprintf(proxy, "    }\n");
774         (*c)++;
775       }
776     }
777   }
778 }
779
780 void write_proxies(const statement_list_t *stmts)
781 {
782   int expr_eval_routines;
783   char *file_id = proxy_token;
784   int c;
785   unsigned int proc_offset = 0;
786
787   if (!do_proxies) return;
788   if (do_everything && !need_proxy_file(stmts)) return;
789
790   init_proxy(stmts);
791   if(!proxy) return;
792
793   write_proxy_stmts(stmts, &proc_offset);
794
795   expr_eval_routines = write_expr_eval_routines(proxy, proxy_token);
796   if (expr_eval_routines)
797       write_expr_eval_routine_list(proxy, proxy_token);
798   write_user_quad_list(proxy);
799   write_stubdesc(expr_eval_routines);
800
801   print_proxy( "#if !defined(__RPC_WIN32__)\n");
802   print_proxy( "#error Currently only Wine and WIN32 are supported.\n");
803   print_proxy( "#endif\n");
804   print_proxy( "\n");
805   write_procformatstring(proxy, stmts, need_proxy);
806   write_typeformatstring(proxy, stmts, need_proxy);
807
808   fprintf(proxy, "static const CInterfaceProxyVtbl* const _%s_ProxyVtblList[] =\n", file_id);
809   fprintf(proxy, "{\n");
810   write_proxy_iface_name_format(stmts, "    (const CInterfaceProxyVtbl*)&_%sProxyVtbl,\n");
811   fprintf(proxy, "    0\n");
812   fprintf(proxy, "};\n");
813   fprintf(proxy, "\n");
814
815   fprintf(proxy, "static const CInterfaceStubVtbl* const _%s_StubVtblList[] =\n", file_id);
816   fprintf(proxy, "{\n");
817   write_proxy_iface_name_format(stmts, "    (const CInterfaceStubVtbl*)&_%sStubVtbl,\n");
818   fprintf(proxy, "    0\n");
819   fprintf(proxy, "};\n");
820   fprintf(proxy, "\n");
821
822   fprintf(proxy, "static PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id);
823   fprintf(proxy, "{\n");
824   write_proxy_iface_name_format(stmts, "    \"%s\",\n");
825   fprintf(proxy, "    0\n");
826   fprintf(proxy, "};\n");
827   fprintf(proxy, "\n");
828
829   fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id);
830   fprintf(proxy, "\n");
831   fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
832   fprintf(proxy, "{\n");
833   c = 0;
834   write_iid_lookup(stmts, file_id, &c);
835   fprintf(proxy, "    return 0;\n");
836   fprintf(proxy, "}\n");
837   fprintf(proxy, "\n");
838
839   fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id);
840   fprintf(proxy, "{\n");
841   fprintf(proxy, "    (const PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id);
842   fprintf(proxy, "    (const PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id);
843   fprintf(proxy, "    _%s_InterfaceNamesList,\n", file_id);
844   fprintf(proxy, "    0,\n");
845   fprintf(proxy, "    &_%s_IID_Lookup,\n", file_id);
846   fprintf(proxy, "    %d,\n", c);
847   fprintf(proxy, "    1,\n");
848   fprintf(proxy, "    0,\n");
849   fprintf(proxy, "    0,\n");
850   fprintf(proxy, "    0,\n");
851   fprintf(proxy, "    0\n");
852   fprintf(proxy, "};\n");
853
854   fclose(proxy);
855 }