1 /* 2 * IDL Compiler 3 * 4 * Copyright 2005-2006 Eric Kohl 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "wine/port.h" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #ifdef HAVE_UNISTD_H 27 # include <unistd.h> 28 #endif 29 #include <string.h> 30 #include <ctype.h> 31 32 #include "widl.h" 33 #include "utils.h" 34 #include "parser.h" 35 #include "header.h" 36 37 #include "widltypes.h" 38 #include "typegen.h" 39 #include "expr.h" 40 41 static FILE* client; 42 static int indent = 0; 43 44 static void print_client( const char *format, ... ) __attribute__((format (printf, 1, 2))); 45 static void print_client( const char *format, ... ) 46 { 47 va_list va; 48 va_start(va, format); 49 print(client, indent, format, va); 50 va_end(va); 51 } 52 53 static void write_client_func_decl( const type_t *iface, const var_t *func ) 54 { 55 const char *callconv = get_attrp(func->type->attrs, ATTR_CALLCONV); 56 const var_list_t *args = type_get_function_args(func->type); 57 type_t *rettype = type_function_get_rettype(func->type); 58 59 if (!callconv) callconv = "__cdecl"; 60 write_type_decl_left(client, rettype); 61 fprintf(client, " %s ", callconv); 62 fprintf(client, "%s%s(\n", prefix_client, get_name(func)); 63 indent++; 64 if (args) 65 write_args(client, args, iface->name, 0, TRUE); 66 else 67 print_client("void"); 68 fprintf(client, ")\n"); 69 indent--; 70 } 71 72 static void write_function_stub( const type_t *iface, const var_t *func, 73 int method_count, unsigned int proc_offset ) 74 { 75 unsigned char explicit_fc, implicit_fc; 76 int has_full_pointer = is_full_pointer_function(func); 77 var_t *retval = type_function_get_retval(func->type); 78 const var_t *handle_var = get_func_handle_var( iface, func, &explicit_fc, &implicit_fc ); 79 int has_ret = !is_void(retval->type); 80 81 if (is_interpreted_func( iface, func )) 82 { 83 write_client_func_decl( iface, func ); 84 write_client_call_routine( client, iface, func, iface->name, proc_offset ); 85 return; 86 } 87 88 print_client( "struct __frame_%s%s\n{\n", prefix_client, get_name(func) ); 89 indent++; 90 print_client( "__DECL_EXCEPTION_FRAME\n" ); 91 print_client("MIDL_STUB_MESSAGE _StubMsg;\n"); 92 if (handle_var) 93 { 94 if (explicit_fc == RPC_FC_BIND_GENERIC) 95 print_client("%s %s;\n", 96 get_explicit_generic_handle_type(handle_var)->name, handle_var->name ); 97 print_client("RPC_BINDING_HANDLE _Handle;\n"); 98 } 99 100 if (has_ret && decl_indirect(retval->type)) 101 { 102 print_client("void *_p_%s;\n", retval->name); 103 } 104 indent--; 105 print_client( "};\n\n" ); 106 107 print_client( "static void __finally_%s%s(", prefix_client, get_name(func) ); 108 print_client( " struct __frame_%s%s *__frame )\n{\n", prefix_client, get_name(func) ); 109 indent++; 110 111 if (has_full_pointer) 112 write_full_pointer_free(client, indent, func); 113 114 print_client("NdrFreeBuffer(&__frame->_StubMsg);\n"); 115 116 if (explicit_fc == RPC_FC_BIND_GENERIC) 117 { 118 fprintf(client, "\n"); 119 print_client("if (__frame->_Handle)\n"); 120 indent++; 121 print_client("%s_unbind(__frame->%s, __frame->_Handle);\n", 122 get_explicit_generic_handle_type(handle_var)->name, handle_var->name); 123 indent--; 124 } 125 indent--; 126 print_client( "}\n\n" ); 127 128 write_client_func_decl( iface, func ); 129 130 /* write the functions body */ 131 fprintf(client, "{\n"); 132 indent++; 133 print_client( "struct __frame_%s%s __f, * const __frame = &__f;\n", prefix_client, get_name(func) ); 134 135 /* declare return value */ 136 if (has_ret) 137 { 138 print_client("%s", ""); 139 write_type_decl(client, retval->type, retval->name); 140 fprintf(client, ";\n"); 141 } 142 print_client("RPC_MESSAGE _RpcMessage;\n"); 143 144 if (handle_var) 145 { 146 print_client( "__frame->_Handle = 0;\n" ); 147 if (explicit_fc == RPC_FC_BIND_GENERIC) 148 print_client("__frame->%s = %s;\n", handle_var->name, handle_var->name ); 149 } 150 if (has_ret && decl_indirect(retval->type)) 151 { 152 print_client("__frame->_p_%s = &%s;\n", retval->name, retval->name); 153 } 154 fprintf(client, "\n"); 155 156 print_client( "RpcExceptionInit( 0, __finally_%s%s );\n", prefix_client, get_name(func) ); 157 158 if (has_full_pointer) 159 write_full_pointer_init(client, indent, func, FALSE); 160 161 /* check pointers */ 162 write_pointer_checks( client, indent, func ); 163 164 print_client("RpcTryFinally\n"); 165 print_client("{\n"); 166 indent++; 167 168 print_client("NdrClientInitializeNew(&_RpcMessage, &__frame->_StubMsg, &%s_StubDesc, %d);\n", 169 iface->name, method_count); 170 171 if (is_attr(func->attrs, ATTR_IDEMPOTENT) || is_attr(func->attrs, ATTR_BROADCAST)) 172 { 173 print_client("_RpcMessage.RpcFlags = ( RPC_NCA_FLAGS_DEFAULT "); 174 if (is_attr(func->attrs, ATTR_IDEMPOTENT)) 175 fprintf(client, "| RPC_NCA_FLAGS_IDEMPOTENT "); 176 if (is_attr(func->attrs, ATTR_BROADCAST)) 177 fprintf(client, "| RPC_NCA_FLAGS_BROADCAST "); 178 fprintf(client, ");\n\n"); 179 } 180 181 switch (explicit_fc) 182 { 183 case RPC_FC_BIND_PRIMITIVE: 184 print_client("__frame->_Handle = %s;\n", handle_var->name); 185 fprintf(client, "\n"); 186 break; 187 case RPC_FC_BIND_GENERIC: 188 print_client("__frame->_Handle = %s_bind(%s);\n", 189 get_explicit_generic_handle_type(handle_var)->name, handle_var->name); 190 fprintf(client, "\n"); 191 break; 192 case RPC_FC_BIND_CONTEXT: 193 { 194 /* if the context_handle attribute appears in the chain of types 195 * without pointers being followed, then the context handle must 196 * be direct, otherwise it is a pointer */ 197 int is_ch_ptr = !is_aliaschain_attr(handle_var->type, ATTR_CONTEXTHANDLE); 198 print_client("if (%s%s != 0)\n", is_ch_ptr ? "*" : "", handle_var->name); 199 indent++; 200 print_client("__frame->_Handle = NDRCContextBinding(%s%s);\n", 201 is_ch_ptr ? "*" : "", handle_var->name); 202 indent--; 203 if (is_attr(handle_var->attrs, ATTR_IN) && !is_attr(handle_var->attrs, ATTR_OUT)) 204 { 205 print_client("else\n"); 206 indent++; 207 print_client("RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);\n"); 208 indent--; 209 } 210 fprintf(client, "\n"); 211 break; 212 } 213 case 0: /* implicit handle */ 214 if (handle_var) 215 { 216 print_client("__frame->_Handle = %s;\n", handle_var->name); 217 fprintf(client, "\n"); 218 } 219 break; 220 } 221 222 write_remoting_arguments(client, indent, func, "", PASS_IN, PHASE_BUFFERSIZE); 223 224 print_client("NdrGetBuffer(&__frame->_StubMsg, __frame->_StubMsg.BufferLength, "); 225 if (handle_var) 226 fprintf(client, "__frame->_Handle);\n\n"); 227 else 228 fprintf(client,"%s__MIDL_AutoBindHandle);\n\n", iface->name); 229 230 /* marshal arguments */ 231 write_remoting_arguments(client, indent, func, "", PASS_IN, PHASE_MARSHAL); 232 233 /* send/receive message */ 234 /* print_client("NdrNsSendReceive(\n"); */ 235 /* print_client("(unsigned char *)__frame->_StubMsg.Buffer,\n"); */ 236 /* print_client("(RPC_BINDING_HANDLE *) &%s__MIDL_AutoBindHandle);\n", iface->name); */ 237 print_client("NdrSendReceive(&__frame->_StubMsg, __frame->_StubMsg.Buffer);\n\n"); 238 239 print_client("__frame->_StubMsg.BufferStart = _RpcMessage.Buffer;\n"); 240 print_client("__frame->_StubMsg.BufferEnd = __frame->_StubMsg.BufferStart + _RpcMessage.BufferLength;\n"); 241 242 if (has_out_arg_or_return(func)) 243 { 244 fprintf(client, "\n"); 245 246 print_client("if ((_RpcMessage.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n"); 247 indent++; 248 print_client("NdrConvert(&__frame->_StubMsg, (PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", 249 proc_offset); 250 indent--; 251 } 252 253 /* unmarshall arguments */ 254 fprintf(client, "\n"); 255 write_remoting_arguments(client, indent, func, "", PASS_OUT, PHASE_UNMARSHAL); 256 257 /* unmarshal return value */ 258 if (has_ret) 259 { 260 if (decl_indirect(retval->type)) 261 print_client("MIDL_memset(&%s, 0, sizeof(%s));\n", retval->name, retval->name); 262 else if (is_ptr(retval->type) || is_array(retval->type)) 263 print_client("%s = 0;\n", retval->name); 264 write_remoting_arguments(client, indent, func, "", PASS_RETURN, PHASE_UNMARSHAL); 265 } 266 267 indent--; 268 print_client("}\n"); 269 print_client("RpcFinally\n"); 270 print_client("{\n"); 271 indent++; 272 print_client( "__finally_%s%s( __frame );\n", prefix_client, get_name(func) ); 273 indent--; 274 print_client("}\n"); 275 print_client("RpcEndFinally\n"); 276 277 278 /* emit return code */ 279 if (has_ret) 280 { 281 fprintf(client, "\n"); 282 print_client("return %s;\n", retval->name); 283 } 284 285 indent--; 286 fprintf(client, "}\n"); 287 fprintf(client, "\n"); 288 } 289 290 static void write_function_stubs(type_t *iface, unsigned int *proc_offset) 291 { 292 const statement_t *stmt; 293 const var_t *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); 294 int method_count = 0; 295 296 if (!implicit_handle) 297 print_client("static RPC_BINDING_HANDLE %s__MIDL_AutoBindHandle;\n\n", iface->name); 298 299 STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) ) 300 { 301 const var_t *func = stmt->u.var; 302 write_function_stub( iface, func, method_count++, *proc_offset ); 303 *proc_offset += get_size_procformatstring_func( iface, func ); 304 } 305 } 306 307 308 static void write_stubdescdecl(type_t *iface) 309 { 310 print_client("static const MIDL_STUB_DESC %s_StubDesc;\n", iface->name); 311 fprintf(client, "\n"); 312 } 313 314 315 static void write_stubdescriptor(type_t *iface, int expr_eval_routines) 316 { 317 const var_t *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); 318 319 print_client("static const MIDL_STUB_DESC %s_StubDesc =\n", iface->name); 320 print_client("{\n"); 321 indent++; 322 print_client("(void *)& %s___RpcClientInterface,\n", iface->name); 323 print_client("MIDL_user_allocate,\n"); 324 print_client("MIDL_user_free,\n"); 325 print_client("{\n"); 326 indent++; 327 if (implicit_handle) 328 print_client("&%s,\n", implicit_handle->name); 329 else 330 print_client("&%s__MIDL_AutoBindHandle,\n", iface->name); 331 indent--; 332 print_client("},\n"); 333 print_client("0,\n"); 334 if (!list_empty( &generic_handle_list )) 335 print_client("BindingRoutines,\n"); 336 else 337 print_client("0,\n"); 338 if (expr_eval_routines) 339 print_client("ExprEvalRoutines,\n"); 340 else 341 print_client("0,\n"); 342 print_client("0,\n"); 343 print_client("__MIDL_TypeFormatString.Format,\n"); 344 print_client("1, /* -error bounds_check flag */\n"); 345 print_client("0x%x, /* Ndr library version */\n", get_stub_mode() == MODE_Oif ? 0x50002 : 0x10001); 346 print_client("0,\n"); 347 print_client("0x50100a4, /* MIDL Version 5.1.164 */\n"); 348 print_client("0,\n"); 349 print_client("%s,\n", list_empty(&user_type_list) ? "0" : "UserMarshalRoutines"); 350 print_client("0, /* notify & notify_flag routine table */\n"); 351 print_client("1, /* Flags */\n"); 352 print_client("0, /* Reserved3 */\n"); 353 print_client("0, /* Reserved4 */\n"); 354 print_client("0 /* Reserved5 */\n"); 355 indent--; 356 print_client("};\n"); 357 fprintf(client, "\n"); 358 } 359 360 361 static void write_clientinterfacedecl(type_t *iface) 362 { 363 unsigned int ver = get_attrv(iface->attrs, ATTR_VERSION); 364 const UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); 365 const str_list_t *endpoints = get_attrp(iface->attrs, ATTR_ENDPOINT); 366 367 if (endpoints) write_endpoints( client, iface->name, endpoints ); 368 369 print_client("static const RPC_CLIENT_INTERFACE %s___RpcClientInterface =\n", iface->name ); 370 print_client("{\n"); 371 indent++; 372 print_client("sizeof(RPC_CLIENT_INTERFACE),\n"); 373 print_client("{{0x%08x,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n", 374 uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], 375 uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], 376 uuid->Data4[7], MAJORVERSION(ver), MINORVERSION(ver)); 377 print_client("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */ 378 print_client("0,\n"); 379 if (endpoints) 380 { 381 print_client("%u,\n", list_count(endpoints)); 382 print_client("(PRPC_PROTSEQ_ENDPOINT)%s__RpcProtseqEndpoint,\n", iface->name); 383 } 384 else 385 { 386 print_client("0,\n"); 387 print_client("0,\n"); 388 } 389 print_client("0,\n"); 390 print_client("0,\n"); 391 print_client("0,\n"); 392 indent--; 393 print_client("};\n"); 394 if (old_names) 395 print_client("RPC_IF_HANDLE %s_ClientIfHandle DECLSPEC_HIDDEN = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", 396 iface->name, iface->name); 397 else 398 print_client("RPC_IF_HANDLE %s%s_v%d_%d_c_ifspec DECLSPEC_HIDDEN = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", 399 prefix_client, iface->name, MAJORVERSION(ver), MINORVERSION(ver), iface->name); 400 fprintf(client, "\n"); 401 } 402 403 404 static void write_implicithandledecl(type_t *iface) 405 { 406 const var_t *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); 407 408 if (implicit_handle) 409 { 410 write_type_decl( client, implicit_handle->type, implicit_handle->name ); 411 fprintf(client, ";\n\n"); 412 } 413 } 414 415 416 static void init_client(void) 417 { 418 if (client) return; 419 if (!(client = fopen(client_name, "w"))) 420 error("Could not open %s for output\n", client_name); 421 422 print_client("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", PACKAGE_VERSION, input_name); 423 print_client("#include <string.h>\n"); 424 print_client( "\n"); 425 print_client("#include \"%s\"\n", header_name); 426 print_client( "\n"); 427 print_client( "#ifndef DECLSPEC_HIDDEN\n"); 428 print_client( "#define DECLSPEC_HIDDEN\n"); 429 print_client( "#endif\n"); 430 print_client( "\n"); 431 } 432 433 434 static void write_client_ifaces(const statement_list_t *stmts, int expr_eval_routines, unsigned int *proc_offset) 435 { 436 const statement_t *stmt; 437 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry ) 438 { 439 if (stmt->type == STMT_TYPE && type_get_type(stmt->u.type) == TYPE_INTERFACE) 440 { 441 int has_func = 0; 442 const statement_t *stmt2; 443 type_t *iface = stmt->u.type; 444 if (!need_stub(iface)) 445 return; 446 447 fprintf(client, "/*****************************************************************************\n"); 448 fprintf(client, " * %s interface\n", iface->name); 449 fprintf(client, " */\n"); 450 fprintf(client, "\n"); 451 452 STATEMENTS_FOR_EACH_FUNC(stmt2, type_iface_get_stmts(iface)) 453 { 454 has_func = 1; 455 break; 456 } 457 458 if (has_func) 459 { 460 write_implicithandledecl(iface); 461 462 write_clientinterfacedecl(iface); 463 write_stubdescdecl(iface); 464 write_function_stubs(iface, proc_offset); 465 466 print_client("#if !defined(__RPC_WIN%u__)\n", pointer_size == 8 ? 64 : 32); 467 print_client("#error Invalid build platform for this stub.\n"); 468 print_client("#endif\n"); 469 470 fprintf(client, "\n"); 471 write_stubdescriptor(iface, expr_eval_routines); 472 } 473 } 474 } 475 } 476 477 static void write_generic_handle_routine_list(void) 478 { 479 generic_handle_t *gh; 480 481 if (list_empty( &generic_handle_list )) return; 482 print_client( "static const GENERIC_BINDING_ROUTINE_PAIR BindingRoutines[] =\n" ); 483 print_client( "{\n" ); 484 indent++; 485 LIST_FOR_EACH_ENTRY( gh, &generic_handle_list, generic_handle_t, entry ) 486 { 487 print_client( "{ (GENERIC_BINDING_ROUTINE)%s_bind, (GENERIC_UNBIND_ROUTINE)%s_unbind },\n", 488 gh->name, gh->name ); 489 } 490 indent--; 491 print_client( "};\n\n" ); 492 } 493 494 static void write_client_routines(const statement_list_t *stmts) 495 { 496 unsigned int proc_offset = 0; 497 int expr_eval_routines; 498 499 if (need_inline_stubs_file( stmts )) 500 { 501 write_exceptions( client ); 502 print_client( "\n"); 503 } 504 505 write_formatstringsdecl(client, indent, stmts, need_stub); 506 expr_eval_routines = write_expr_eval_routines(client, client_token); 507 if (expr_eval_routines) 508 write_expr_eval_routine_list(client, client_token); 509 write_generic_handle_routine_list(); 510 write_user_quad_list(client); 511 512 write_client_ifaces(stmts, expr_eval_routines, &proc_offset); 513 514 fprintf(client, "\n"); 515 516 write_procformatstring(client, stmts, need_stub); 517 write_typeformatstring(client, stmts, need_stub); 518 } 519 520 void write_client(const statement_list_t *stmts) 521 { 522 if (!do_client) 523 return; 524 if (do_everything && !need_stub_files(stmts)) 525 return; 526 527 init_client(); 528 if (!client) 529 return; 530 531 if (do_win32 && do_win64) 532 { 533 fprintf(client, "#ifndef _WIN64\n\n"); 534 pointer_size = 4; 535 write_client_routines( stmts ); 536 fprintf(client, "\n#else /* _WIN64 */\n\n"); 537 pointer_size = 8; 538 write_client_routines( stmts ); 539 fprintf(client, "\n#endif /* _WIN64 */\n"); 540 } 541 else if (do_win32) 542 { 543 pointer_size = 4; 544 write_client_routines( stmts ); 545 } 546 else if (do_win64) 547 { 548 pointer_size = 8; 549 write_client_routines( stmts ); 550 } 551 552 fclose(client); 553 } 554