client.c 16.7 KB
Newer Older
1 2 3
/*
 * IDL Compiler
 *
4
 * Copyright 2005-2006 Eric Kohl
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23 24 25
 */

#include "config.h"
#include "wine/port.h"
 
#include <stdio.h>
#include <stdlib.h>
26 27 28
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
29 30 31 32 33 34 35 36 37
#include <string.h>
#include <ctype.h>

#include "widl.h"
#include "utils.h"
#include "parser.h"
#include "header.h"

#include "widltypes.h"
38
#include "typegen.h"
39
#include "expr.h"
40 41 42 43

static FILE* client;
static int indent = 0;

44
static void print_client( const char *format, ... )
45 46 47
{
    va_list va;
    va_start(va, format);
48
    print(client, indent, format, va);
49 50 51 52
    va_end(va);
}


53
static void check_pointers(const func_t *func)
54
{
55
    const var_t *var;
56 57

    if (!func->args)
58
        return;
59

60
    LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
61
    {
62
        if (is_var_ptr(var) && cant_be_null(var))
63
        {
64 65 66 67 68 69
            print_client("if (!%s)\n", var->name);
            print_client("{\n");
            indent++;
            print_client("RpcRaiseException(RPC_X_NULL_REF_POINTER);\n");
            indent--;
            print_client("}\n\n");
70
        }
71 72 73
    }
}

74
static void write_function_stubs(type_t *iface, unsigned int *proc_offset)
75
{
76
    const func_t *func;
77
    const char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
78
    const var_t *var;
79 80
    int method_count = 0;

81 82 83
    if (!implicit_handle)
        print_client("static RPC_BINDING_HANDLE %s__MIDL_AutoBindHandle;\n\n", iface->name);

84
    if (iface->funcs) LIST_FOR_EACH_ENTRY( func, iface->funcs, const func_t, entry )
85
    {
86 87
        const var_t *def = func->def;
        const var_t* explicit_handle_var;
88
        const var_t* explicit_generic_handle_var = NULL;
89
        const var_t* context_handle_var = NULL;
90
        int has_full_pointer = is_full_pointer_function(func);
91
        const char *callconv = get_attrp(def->type->attrs, ATTR_CALLCONV);
92 93 94

        /* check for a defined binding handle */
        explicit_handle_var = get_explicit_handle_var(func);
95
        if (!explicit_handle_var)
96 97 98
        {
            explicit_generic_handle_var = get_explicit_generic_handle_var(func);
            if (!explicit_generic_handle_var)
99
                context_handle_var = get_context_handle_var(func);
100
        }
101

102 103
        write_type_decl_left(client, get_func_return_type(func));
        if (needs_space_after(get_func_return_type(func)))
104
          fprintf(client, " ");
105
        if (callconv) fprintf(client, "%s ", callconv);
106
        write_prefix_name(client, prefix_client, def);
107 108
        fprintf(client, "(\n");
        indent++;
Eric Kohl's avatar
Eric Kohl committed
109 110
        if (func->args)
            write_args(client, func->args, iface->name, 0, TRUE);
111 112 113 114 115 116 117 118 119 120
        else
            print_client("void");
        fprintf(client, ")\n");
        indent--;

        /* write the functions body */
        fprintf(client, "{\n");
        indent++;

        /* declare return value '_RetVal' */
121
        if (!is_void(get_func_return_type(func)))
122 123
        {
            print_client("");
124
            write_type_decl_left(client, get_func_return_type(func));
125 126 127
            fprintf(client, " _RetVal;\n");
        }

128
        if (implicit_handle || explicit_handle_var || explicit_generic_handle_var || context_handle_var)
129 130 131 132
            print_client("RPC_BINDING_HANDLE _Handle = 0;\n");

        print_client("RPC_MESSAGE _RpcMessage;\n");
        print_client("MIDL_STUB_MESSAGE _StubMsg;\n");
133
        if (!is_void(get_func_return_type(func)) && decl_indirect(get_func_return_type(func)))
134 135 136 137
        {
            print_client("void *_p_%s = &%s;\n",
                         "_RetVal", "_RetVal");
        }
138
        fprintf(client, "\n");
139

140 141 142
        if (has_full_pointer)
            write_full_pointer_init(client, indent, func, FALSE);

143 144 145
        /* check pointers */
        check_pointers(func);

146 147 148 149 150 151 152 153 154 155 156 157 158
        print_client("RpcTryFinally\n");
        print_client("{\n");
        indent++;

        print_client("NdrClientInitializeNew(\n");
        indent++;
        print_client("(PRPC_MESSAGE)&_RpcMessage,\n");
        print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
        print_client("(PMIDL_STUB_DESC)&%s_StubDesc,\n", iface->name);
        print_client("%d);\n", method_count);
        indent--;
        fprintf(client, "\n");

159 160 161 162 163 164 165 166 167 168
        if (is_attr(def->attrs, ATTR_IDEMPOTENT) || is_attr(def->attrs, ATTR_BROADCAST))
        {
            print_client("_RpcMessage.RpcFlags = ( RPC_NCA_FLAGS_DEFAULT ");
            if (is_attr(def->attrs, ATTR_IDEMPOTENT))
                fprintf(client, "| RPC_NCA_FLAGS_IDEMPOTENT ");
            if (is_attr(def->attrs, ATTR_BROADCAST))
                fprintf(client, "| RPC_NCA_FLAGS_BROADCAST ");
            fprintf(client, ");\n\n");
        }

169
        if (explicit_handle_var)
170 171 172 173
        {
            print_client("_Handle = %s;\n", explicit_handle_var->name);
            fprintf(client, "\n");
        }
174 175 176 177 178 179 180
        else if (explicit_generic_handle_var)
        {
            print_client("_Handle = %s_bind(%s);\n",
                get_explicit_generic_handle_type(explicit_generic_handle_var)->name,
                explicit_generic_handle_var->name);
            fprintf(client, "\n");
        }
181 182
        else if (context_handle_var)
        {
183 184 185 186 187
            /* if the context_handle attribute appears in the chain of types
             * without pointers being followed, then the context handle must
             * be direct, otherwise it is a pointer */
            int is_ch_ptr = is_aliaschain_attr(context_handle_var->type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
            print_client("if (%s%s != 0)\n", is_ch_ptr ? "*" : "", context_handle_var->name);
188
            indent++;
189
            print_client("_Handle = NDRCContextBinding(%s%s);\n", is_ch_ptr ? "*" : "", context_handle_var->name);
190
            indent--;
191
            fprintf(client, "\n");
192
        }
193 194 195 196 197
        else if (implicit_handle)
        {
            print_client("_Handle = %s;\n", implicit_handle);
            fprintf(client, "\n");
        }
198

199
        write_remoting_arguments(client, indent, func, PASS_IN, PHASE_BUFFERSIZE);
200

201 202 203 204
        print_client("NdrGetBuffer(\n");
        indent++;
        print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
        print_client("_StubMsg.BufferLength,\n");
205
        if (implicit_handle || explicit_handle_var || explicit_generic_handle_var || context_handle_var)
206
            print_client("_Handle);\n");
207 208 209 210 211
        else
            print_client("%s__MIDL_AutoBindHandle);\n", iface->name);
        indent--;
        fprintf(client, "\n");

212
        /* marshal arguments */
213
        write_remoting_arguments(client, indent, func, PASS_IN, PHASE_MARSHAL);
214

215
        /* send/receive message */
216
        /* print_client("NdrNsSendReceive(\n"); */
217 218
        /* print_client("(unsigned char *)_StubMsg.Buffer,\n"); */
        /* print_client("(RPC_BINDING_HANDLE *) &%s__MIDL_AutoBindHandle);\n", iface->name); */
219 220 221
        print_client("NdrSendReceive(\n");
        indent++;
        print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
222
        print_client("(unsigned char *)_StubMsg.Buffer);\n\n");
223 224
        indent--;

225
        print_client("_StubMsg.BufferStart = (unsigned char *)_RpcMessage.Buffer;\n");
226
        print_client("_StubMsg.BufferEnd = _StubMsg.BufferStart + _RpcMessage.BufferLength;\n");
Robert Shearman's avatar
Robert Shearman committed
227

228
        if (has_out_arg_or_return(func))
229 230 231 232 233 234 235 236
        {
            fprintf(client, "\n");

            print_client("if ((_RpcMessage.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n");
            indent++;
            print_client("NdrConvert(\n");
            indent++;
            print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n");
237
            print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", *proc_offset);
238
            indent -= 2;
239
        }
240

241 242
        /* unmarshall arguments */
        fprintf(client, "\n");
243
        write_remoting_arguments(client, indent, func, PASS_OUT, PHASE_UNMARSHAL);
244 245

        /* unmarshal return value */
246
        if (!is_void(get_func_return_type(func)))
247
        {
248
            if (decl_indirect(get_func_return_type(func)))
249
                print_client("MIDL_memset(&%s, 0, sizeof(%s));\n", "_RetVal", "_RetVal");
250
            else if (is_ptr(get_func_return_type(func)) || is_array(get_func_return_type(func)))
251 252 253
                print_client("%s = 0;\n", "_RetVal");
            write_remoting_arguments(client, indent, func, PASS_RETURN, PHASE_UNMARSHAL);
        }
254

255 256 257
        /* update proc_offset */
        if (func->args)
        {
258
            LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
259
                *proc_offset += get_size_procformatstring_type(var->name, var->type, var->attrs);
260
        }
261 262
        if (!is_void(get_func_return_type(func)))
            *proc_offset += get_size_procformatstring_type("return value", get_func_return_type(func), NULL);
263
        else
264
            *proc_offset += 2; /* FC_END and FC_PAD */
265 266 267 268 269 270 271 272 273 274

        indent--;
        print_client("}\n");
        print_client("RpcFinally\n");
        print_client("{\n");
        indent++;


        /* FIXME: emit client finally code */

275 276 277
        if (has_full_pointer)
            write_full_pointer_free(client, indent, func);

278 279
        print_client("NdrFreeBuffer((PMIDL_STUB_MESSAGE)&_StubMsg);\n");

280 281 282 283 284 285 286 287 288 289 290
        if (!implicit_handle && explicit_generic_handle_var)
        {
            fprintf(client, "\n");
            print_client("if (_Handle)\n");
            indent++;
            print_client("%s_unbind(%s, _Handle);\n",
                get_explicit_generic_handle_type(explicit_generic_handle_var)->name,
                explicit_generic_handle_var->name);
            indent--;
        }

291 292 293 294 295 296
        indent--;
        print_client("}\n");
        print_client("RpcEndFinally\n");


        /* emit return code */
297
        if (!is_void(get_func_return_type(func)))
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
        {
            fprintf(client, "\n");
            print_client("return _RetVal;\n");
        }

        indent--;
        fprintf(client, "}\n");
        fprintf(client, "\n");

        method_count++;
    }
}


static void write_stubdescdecl(type_t *iface)
{
314
    print_client("static const MIDL_STUB_DESC %s_StubDesc;\n", iface->name);
315 316 317 318
    fprintf(client, "\n");
}


319
static void write_stubdescriptor(type_t *iface, int expr_eval_routines)
320
{
321
    const char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
322 323 324 325

    print_client("static const MIDL_STUB_DESC %s_StubDesc =\n", iface->name);
    print_client("{\n");
    indent++;
326
    print_client("(void *)& %s___RpcClientInterface,\n", iface->name);
327 328
    print_client("MIDL_user_allocate,\n");
    print_client("MIDL_user_free,\n");
329 330
    print_client("{\n");
    indent++;
Eric Kohl's avatar
Eric Kohl committed
331 332
    if (implicit_handle)
        print_client("&%s,\n", implicit_handle);
333 334
    else
        print_client("&%s__MIDL_AutoBindHandle,\n", iface->name);
335 336
    indent--;
    print_client("},\n");
337 338
    print_client("0,\n");
    print_client("0,\n");
339 340 341 342
    if (expr_eval_routines)
        print_client("ExprEvalRoutines,\n");
    else
        print_client("0,\n");
343 344 345 346 347 348 349
    print_client("0,\n");
    print_client("__MIDL_TypeFormatString.Format,\n");
    print_client("1, /* -error bounds_check flag */\n");
    print_client("0x10001, /* Ndr library version */\n");
    print_client("0,\n");
    print_client("0x50100a4, /* MIDL Version 5.1.164 */\n");
    print_client("0,\n");
350
    print_client("%s,\n", list_empty(&user_type_list) ? "0" : "UserMarshalRoutines");
351 352 353 354 355 356 357 358 359 360 361 362 363 364
    print_client("0,  /* notify & notify_flag routine table */\n");
    print_client("1,  /* Flags */\n");
    print_client("0,  /* Reserved3 */\n");
    print_client("0,  /* Reserved4 */\n");
    print_client("0   /* Reserved5 */\n");
    indent--;
    print_client("};\n");
    fprintf(client, "\n");
}


static void write_clientinterfacedecl(type_t *iface)
{
    unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION);
365
    const UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
366 367 368
    const str_list_t *endpoints = get_attrp(iface->attrs, ATTR_ENDPOINT);

    if (endpoints) write_endpoints( client, iface->name, endpoints );
369 370 371 372 373 374 375 376

    print_client("static const RPC_CLIENT_INTERFACE %s___RpcClientInterface =\n", iface->name );
    print_client("{\n");
    indent++;
    print_client("sizeof(RPC_CLIENT_INTERFACE),\n");
    print_client("{{0x%08lx,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n",
                 uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1],
                 uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6],
377
                 uuid->Data4[7], MAJORVERSION(ver), MINORVERSION(ver));
378 379
    print_client("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */
    print_client("0,\n");
380 381 382 383 384 385 386 387 388 389
    if (endpoints)
    {
        print_client("%u,\n", list_count(endpoints));
        print_client("(PRPC_PROTSEQ_ENDPOINT)%s__RpcProtseqEndpoint,\n", iface->name);
    }
    else
    {
        print_client("0,\n");
        print_client("0,\n");
    }
390 391 392 393 394
    print_client("0,\n");
    print_client("0,\n");
    print_client("0,\n");
    indent--;
    print_client("};\n");
395 396 397 398
    if (old_names)
        print_client("RPC_IF_HANDLE %s_ClientIfHandle = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n",
                     iface->name, iface->name);
    else
399
        print_client("RPC_IF_HANDLE %s%s_v%d_%d_c_ifspec = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n",
400
                     prefix_client, iface->name, MAJORVERSION(ver), MINORVERSION(ver), iface->name);
401 402 403 404 405 406
    fprintf(client, "\n");
}


static void write_implicithandledecl(type_t *iface)
{
407
    const char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
408

409
    if (implicit_handle)
410
    {
411
        fprintf(client, "handle_t %s;\n", implicit_handle);
412 413 414 415 416 417 418 419 420 421 422
        fprintf(client, "\n");
    }
}


static void init_client(void)
{
    if (client) return;
    if (!(client = fopen(client_name, "w")))
        error("Could not open %s for output\n", client_name);

423
    print_client("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", PACKAGE_VERSION, input_name);
424
    print_client("#include <string.h>\n");
425
    print_client("#ifdef _ALPHA_\n");
426
    print_client("#include <stdarg.h>\n");
427 428
    print_client("#endif\n");
    fprintf(client, "\n");
429
    print_client("#include \"%s\"\n", header_name);
430 431 432 433
    fprintf(client, "\n");
}


434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
static void write_client_ifaces(const statement_list_t *stmts, int expr_eval_routines, unsigned int *proc_offset)
{
    const statement_t *stmt;
    if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
    {
        if (stmt->type == STMT_TYPE && stmt->u.type->type == RPC_FC_IP)
        {
            type_t *iface = stmt->u.type;
            if (!need_stub(iface))
                return;

            fprintf(client, "/*****************************************************************************\n");
            fprintf(client, " * %s interface\n", iface->name);
            fprintf(client, " */\n");
            fprintf(client, "\n");

            if (iface->funcs)
            {
                write_implicithandledecl(iface);

                write_clientinterfacedecl(iface);
                write_stubdescdecl(iface);
                write_function_stubs(iface, proc_offset);

                print_client("#if !defined(__RPC_WIN32__)\n");
                print_client("#error  Invalid build platform for this stub.\n");
                print_client("#endif\n");

                fprintf(client, "\n");
                write_stubdescriptor(iface, expr_eval_routines);
            }
        }
        else if (stmt->type == STMT_LIBRARY)
            write_client_ifaces(stmt->u.lib->stmts, expr_eval_routines, proc_offset);
    }
}

void write_client(const statement_list_t *stmts)
472
{
473
    unsigned int proc_offset = 0;
474
    int expr_eval_routines;
475 476 477

    if (!do_client)
        return;
478
    if (do_everything && !need_stub_files(stmts))
479 480 481 482 483 484
        return;

    init_client();
    if (!client)
        return;

485
    write_formatstringsdecl(client, indent, stmts, need_stub);
486 487 488 489
    expr_eval_routines = write_expr_eval_routines(client, client_token);
    if (expr_eval_routines)
        write_expr_eval_routine_list(client, client_token);
    write_user_quad_list(client);
490

491
    write_client_ifaces(stmts, expr_eval_routines, &proc_offset);
492

493 494
    fprintf(client, "\n");

495 496
    write_procformatstring(client, stmts, need_stub);
    write_typeformatstring(client, stmts, need_stub);
497

498 499
    fclose(client);
}