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