Parse the NOT operator, the [idempotent] attribute, and the handle_t
[wine] / tools / widl / proxy.c
1 /*
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #include <string.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <signal.h>
32
33 #include "widl.h"
34 #include "utils.h"
35 #include "parser.h"
36 #include "header.h"
37
38 /* FIXME: support generation of stubless proxies */
39
40 static void write_stubdesc(void)
41 {
42   fprintf(proxy, "const MIDL_STUB_DESC Object_StubDesc = {\n");
43   fprintf(proxy, "    0,\n");
44   fprintf(proxy, "    NdrOleAllocate,\n");
45   fprintf(proxy, "    NdrOleFree,\n");
46   fprintf(proxy, "    {0}, 0, 0, 0, 0,\n");
47   fprintf(proxy, "    0 /* __MIDL_TypeFormatString.Format */\n");
48   fprintf(proxy, "};\n");
49   fprintf(proxy, "\n");
50 }
51
52 static void init_proxy(void)
53 {
54   if (proxy) return;
55   proxy = fopen(proxy_name, "w");
56   fprintf(proxy, "/*** Autogenerated by WIDL %s - Do not edit ***/\n", WIDL_FULLVERSION);
57   fprintf(proxy, "#include \"rpcproxy.h\"\n");
58   fprintf(proxy, "#include \"%s\"\n", header_name);
59   fprintf(proxy, "\n");
60   write_stubdesc();
61 }
62
63 static void gen_proxy(type_t *iface, func_t *cur, int idx)
64 {
65   var_t *def = cur->def;
66   int has_ret = !is_void(def->type, def);
67
68   write_type(proxy, def->type, def, def->tname);
69   fprintf(proxy, " CALLBACK %s_", iface->name);
70   write_name(proxy, def);
71   fprintf(proxy, "_Proxy(\n");
72   write_args(proxy, cur->args, iface->name, 1);
73   fprintf(proxy, ")\n");
74   fprintf(proxy, "{\n");
75   /* local variables */
76   if (has_ret) {
77     fprintf(proxy, "    ");
78     write_type(proxy, def->type, def, def->tname);
79     fprintf(proxy, " _Ret;\n");
80   }
81   fprintf(proxy, "    RPC_MESSAGE _Msg;\n");
82   fprintf(proxy, "    MIDL_STUB_MESSAGE _StubMsg;\n");
83   fprintf(proxy, "\n");
84
85   /* FIXME: trace */
86   /* FIXME: clear output vars? */
87
88   fprintf(proxy, "    NdrProxyInitialize(This, &_Msg, &_StubMsg, &Object_StubDesc, %d);\n", idx);
89
90   /* FIXME: size buffer */
91
92   fprintf(proxy, "    NdrProxyGetBuffer(This, &_StubMsg);\n");
93
94   /* FIXME: marshall */
95
96   fprintf(proxy, "    NdrProxySendReceive(This, &_StubMsg);\n");
97
98   /* FIXME: unmarshall */
99
100   fprintf(proxy, "    NdrProxyFreeBuffer(This, &_StubMsg);\n");
101
102   if (has_ret) {
103     fprintf(proxy, "    return _Ret;\n");
104   }
105   fprintf(proxy, "}\n");
106   fprintf(proxy, "\n");
107 }
108
109 static void gen_stub(type_t *iface, func_t *cur, char *cas)
110 {
111   var_t *def = cur->def;
112   var_t *arg;
113   int has_ret = !is_void(def->type, def);
114
115   fprintf(proxy, "void __RPC_STUB %s_", iface->name);
116   write_name(proxy, def);
117   fprintf(proxy, "_Stub(\n");
118   fprintf(proxy, "    IRpcStubBuffer* This,\n");
119   fprintf(proxy, "    IRpcChannelBuffer* pRpcChannelBuffer,\n");
120   fprintf(proxy, "    PRPC_MESSAGE pRpcMessage,\n");
121   fprintf(proxy, "    DWORD* pdwStubPhase)\n");
122   fprintf(proxy, "{\n");
123   /* local variables */
124   if (has_ret) {
125     fprintf(proxy, "    ");
126     write_type(proxy, def->type, def, def->tname);
127     fprintf(proxy, " _Ret;\n");
128   }
129   fprintf(proxy, "    %s* _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name);
130   fprintf(proxy, "    MIDL_STUB_MESSAGE _StubMsg;\n");
131   arg = cur->args;
132   while (arg) {
133     fprintf(proxy, "    ");
134     write_type(proxy, arg->type, arg, arg->tname);
135     fprintf(proxy, " ");
136     write_name(proxy, arg);
137     fprintf(proxy, ";\n");
138     arg = NEXT_LINK(arg);
139   }
140   fprintf(proxy, "\n");
141
142   /* FIXME: trace */
143   /* FIXME: clear output vars? */
144
145   fprintf(proxy, "    NdrStubInitialize(pRpcMessage, &_StubMsg, &Object_StubDesc, pRpcChannelBuffer);\n");
146
147   /* FIXME: unmarshall */
148
149   fprintf(proxy, "    *pdwStubPhase = STUB_CALL_SERVER;\n");
150   fprintf(proxy, "    ");
151   if (has_ret) fprintf(proxy, "_Ret = ");
152   fprintf(proxy, "%s_", iface->name);
153   if (cas) fprintf(proxy, "%s_Stub", cas);
154   else write_name(proxy, def);
155   fprintf(proxy, "(_This");
156   arg = cur->args;
157   if (arg) {
158     while (NEXT_LINK(arg)) arg = NEXT_LINK(arg);
159     while (arg) {
160       fprintf(proxy, ", ");
161       write_name(proxy, arg);
162       arg = PREV_LINK(arg);
163     }
164   }
165   fprintf(proxy, ");\n");
166   fprintf(proxy, "    *pdwStubPhase = STUB_MARSHAL;\n");
167
168   /* FIXME: size buffer */
169
170   fprintf(proxy, "    NdrStubGetBuffer(This, pRpcChannelBuffer, &_StubMsg);\n");
171
172   /* FIXME: marshall */
173
174   fprintf(proxy, "}\n");
175   fprintf(proxy, "\n");
176 }
177
178 static int write_proxy_methods(type_t *iface)
179 {
180   func_t *cur = iface->funcs;
181   int i = 0;
182   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
183
184   if (iface->ref) i = write_proxy_methods(iface->ref);
185   while (cur) {
186     var_t *def = cur->def;
187     if (!is_callas(def->attrs)) {
188       if (i) fprintf(proxy, ",\n     ");
189       fprintf(proxy, "%s_", iface->name);
190       write_name(proxy, def);
191       fprintf(proxy, "_Proxy");
192       i++;
193     }
194     cur = PREV_LINK(cur);
195   }
196   return i;
197 }
198
199 static int write_stub_methods(type_t *iface)
200 {
201   func_t *cur = iface->funcs;
202   int i = 0;
203   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
204
205   if (iface->ref) i = write_stub_methods(iface->ref);
206   else return i; /* skip IUnknown */
207   while (cur) {
208     var_t *def = cur->def;
209     if (!is_local(def->attrs)) {
210       if (i) fprintf(proxy, ",\n");
211       fprintf(proxy, "    %s_", iface->name);
212       write_name(proxy, def);
213       fprintf(proxy, "_Stub");
214       i++;
215     }
216     cur = PREV_LINK(cur);
217   }
218   return i;
219 }
220
221 typedef struct _if_list if_list;
222 struct _if_list {
223   type_t *iface;
224   DECL_LINK(if_list)
225 };
226
227 if_list *if_first;
228
229 void write_proxy(type_t *iface)
230 {
231   int midx = -1, stubs;
232   func_t *cur = iface->funcs;
233   if_list *if_cur;
234
235   if (!cur) {
236     yywarning("%s has no methods", iface->name);
237     return;
238   }
239
240   if (header_only) return;
241
242   while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
243
244   /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */
245
246   init_proxy();
247
248   if_cur = xmalloc(sizeof(if_list));
249   if_cur->iface = iface;
250   INIT_LINK(if_cur);
251   LINK(if_cur, if_first);
252   if_first = if_cur;
253
254   fprintf(proxy, "/*****************************************************************************\n");
255   fprintf(proxy, " * %s interface\n", iface->name);
256   fprintf(proxy, " */\n");
257   while (cur) {
258     var_t *def = cur->def;
259     if (!is_local(def->attrs)) {
260       var_t *cas = is_callas(def->attrs);
261       char *cname = cas ? cas->name : NULL;
262       int idx = cur->idx;
263       if (cname) {
264         func_t *m = iface->funcs;
265         while (m && strcmp(get_name(m->def), cname))
266           m = NEXT_LINK(m);
267         idx = m->idx;
268       }
269       gen_proxy(iface, cur, idx);
270       gen_stub(iface, cur, cname);
271       if (midx == -1) midx = idx;
272       else if (midx != idx) yyerror("method index mismatch in write_proxy");
273       midx++;
274     }
275     cur = PREV_LINK(cur);
276   }
277
278   /* proxy vtable */
279   fprintf(proxy, "const CINTERFACE_PROXY_VTABLE(%d) %sProxyVtbl = {\n", midx, iface->name);
280   fprintf(proxy, "    {&IID_%s},\n", iface->name);
281   fprintf(proxy, "    {");
282   write_proxy_methods(iface);
283   fprintf(proxy, "}\n");
284   fprintf(proxy, "};\n");
285   fprintf(proxy, "\n");
286
287   /* stub vtable */
288   fprintf(proxy, "static const PRPC_STUB_FUNCTION %s_table[] = {\n", iface->name);
289   stubs = write_stub_methods(iface);
290   fprintf(proxy, "\n");
291   fprintf(proxy, "};\n");
292   fprintf(proxy, "\n");
293   fprintf(proxy, "const CInterfaceStubVtbl %sStubVtbl = {\n", iface->name);
294   fprintf(proxy, "    {&IID_%s,\n", iface->name);
295   fprintf(proxy, "     0,\n");
296   fprintf(proxy, "     %d,\n", stubs+3);
297   fprintf(proxy, "     &%s_table[-3]},\n", iface->name);
298   fprintf(proxy, "    {CStdStubBuffer_METHODS}\n");
299   fprintf(proxy, "};\n");
300   fprintf(proxy, "\n");
301 }
302
303 void finish_proxy(void)
304 {
305   if_list *lcur = if_first;
306   if_list *cur;
307   char *file_id = proxy_token;
308   int c;
309
310   if (!lcur) return;
311   while (NEXT_LINK(lcur)) lcur = NEXT_LINK(lcur);
312
313   fprintf(proxy, "const CInterfaceProxyVtbl* _%s_ProxyVtblList[] = {\n", file_id);
314   cur = lcur;
315   while (cur) {
316     fprintf(proxy, "    (CInterfaceProxyVtbl*)&%sProxyVtbl,\n", cur->iface->name);
317     cur = PREV_LINK(cur);
318   }
319   fprintf(proxy, "    0\n");
320   fprintf(proxy, "};\n");
321   fprintf(proxy, "\n");
322
323   fprintf(proxy, "const CInterfaceStubVtbl* _%s_StubVtblList[] = {\n", file_id);
324   cur = lcur;
325   while (cur) {
326     fprintf(proxy, "    (CInterfaceStubVtbl*)&%sStubVtbl,\n", cur->iface->name);
327     cur = PREV_LINK(cur);
328   }
329   fprintf(proxy, "    0\n");
330   fprintf(proxy, "};\n");
331   fprintf(proxy, "\n");
332
333   fprintf(proxy, "const PCInterfaceName _%s_InterfaceNamesList[] = {\n", file_id);
334   cur = lcur;
335   while (cur) {
336     fprintf(proxy, "    \"%s\",\n", cur->iface->name);
337     cur = PREV_LINK(cur);
338   }
339   fprintf(proxy, "    0\n");
340   fprintf(proxy, "};\n");
341   fprintf(proxy, "\n");
342
343   fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_XXX, pIID, n)\n", file_id);
344   fprintf(proxy, "\n");
345   fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id);
346   fprintf(proxy, "{\n");
347   cur = lcur;
348   c = 0;
349   while (cur) {
350     fprintf(proxy, "    if (!_%s_CHECK_IID(%d)) {\n", file_id, c);
351     fprintf(proxy, "        *pIndex = %d\n", c);
352     fprintf(proxy, "        return 1;\n");
353     fprintf(proxy, "    }\n");
354     cur = PREV_LINK(cur);
355     c++;
356   }
357   fprintf(proxy, "    return 0;\n");
358   fprintf(proxy, "}\n");
359   fprintf(proxy, "\n");
360
361   fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo = {\n", file_id);
362   fprintf(proxy, "    (PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id);
363   fprintf(proxy, "    (PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id);
364   fprintf(proxy, "    (const PCInterfaceName*)&_%s_InterfaceNamesList,\n", file_id);
365   fprintf(proxy, "    0,\n");
366   fprintf(proxy, "    &_%s_IID_Lookup,\n", file_id);
367   fprintf(proxy, "    %d,\n", c);
368   fprintf(proxy, "    1\n");
369   fprintf(proxy, "};\n");
370
371   fclose(proxy);
372 }