header.c 25.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * IDL Compiler
 *
 * Copyright 2002 Ove Kaaven
 *
 * 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
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
25 26 27
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
28 29 30 31 32
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <signal.h>

33
#include "windef.h"
34 35 36 37 38 39 40
#include "widl.h"
#include "utils.h"
#include "parser.h"
#include "header.h"

static int indentation = 0;

41
static void indent(FILE *h, int delta)
42 43 44
{
  int c;
  if (delta < 0) indentation += delta;
45
  for (c=0; c<indentation; c++) fprintf(h, "    ");
46 47 48
  if (delta > 0) indentation += delta;
}

49
int is_attr(const attr_t *a, enum attr_type t)
50 51 52 53 54 55 56 57
{
  while (a) {
    if (a->type == t) return 1;
    a = NEXT_LINK(a);
  }
  return 0;
}

58
void *get_attrp(const attr_t *a, enum attr_type t)
59 60 61 62 63 64 65 66
{
  while (a) {
    if (a->type == t) return a->u.pval;
    a = NEXT_LINK(a);
  }
  return NULL;
}

67
unsigned long get_attrv(const attr_t *a, enum attr_type t)
68 69 70 71 72 73 74 75
{
  while (a) {
    if (a->type == t) return a->u.ival;
    a = NEXT_LINK(a);
  }
  return 0;
}

76
int is_void(const type_t *t, const var_t *v)
77 78 79 80 81 82
{
  if (v && v->ptr_level) return 0;
  if (!t->type && !t->ref) return 1;
  return 0;
}

83
void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *uuid)
84 85
{
  if (!uuid) return;
86
  fprintf(f, "DEFINE_GUID(%s_%s, 0x%08x, 0x%04x, 0x%04x, 0x%02x,0x%02x, 0x%02x,"
87 88 89 90 91 92
        "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x);\n",
        guid_prefix, name, 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], uuid->Data4[7]);
}

93
static void write_pident(FILE *h, const var_t *v)
94 95 96
{
  int c;
  for (c=0; c<v->ptr_level; c++) {
97
    fprintf(h, "*");
98
  }
99
  if (v->name) fprintf(h, "%s", v->name);
100 101
}

102
void write_name(FILE *h, const var_t *v)
103
{
104 105 106 107
  if (is_attr( v->attrs, ATTR_PROPGET ))
    fprintf(h, "get_" );
  else if (is_attr( v->attrs, ATTR_PROPPUT ))
    fprintf(h, "put_" );
108 109
  else if (is_attr( v->attrs, ATTR_PROPPUTREF ))
    fprintf(h, "putref_" );
110 111 112
  fprintf(h, "%s", v->name);
}

113
const char* get_name(const var_t *v)
114 115 116 117
{
  return v->name;
}

Robert Shearman's avatar
Robert Shearman committed
118
void write_array(FILE *h, const expr_t *v, int field)
119 120 121 122 123
{
  if (!v) return;
  while (NEXT_LINK(v)) v = NEXT_LINK(v);
  fprintf(h, "[");
  while (v) {
124 125
    if (v->is_const)
      fprintf(h, "%ld", v->cval); /* statically sized array */
126
    else
127
      if (field) fprintf(h, "1"); /* dynamically sized array */
128 129 130 131 132 133 134 135 136 137 138
    if (PREV_LINK(v))
      fprintf(h, ", ");
    v = PREV_LINK(v);
  }
  fprintf(h, "]");
}

static void write_field(FILE *h, var_t *v)
{
  if (!v) return;
  if (v->type) {
139
    indent(h, 0);
140 141 142 143 144
    write_type(h, v->type, NULL, v->tname);
    if (get_name(v)) {
      fprintf(h, " ");
      write_pident(h, v);
    }
145 146 147 148
    else {
      /* not all C/C++ compilers support anonymous structs and unions */
      switch (v->type->type) {
      case RPC_FC_STRUCT:
149 150 151 152 153
      case RPC_FC_CVSTRUCT:
      case RPC_FC_CPSTRUCT:
      case RPC_FC_CSTRUCT:
      case RPC_FC_PSTRUCT:
      case RPC_FC_BOGUS_STRUCT:
154 155 156 157 158 159 160 161 162 163 164
      case RPC_FC_ENCAPSULATED_UNION:
        fprintf(h, " DUMMYSTRUCTNAME");
        break;
      case RPC_FC_NON_ENCAPSULATED_UNION:
        fprintf(h, " DUMMYUNIONNAME");
        break;
      default:
        /* ? */
        break;
      }
    }
165
    write_array(h, v->array, 1);
166 167 168 169
    fprintf(h, ";\n");
  }
}

170
static void write_fields(FILE *h, var_t *v)
171 172 173 174 175 176 177 178 179 180 181 182
{
  var_t *first = v;
  if (!v) return;
  while (NEXT_LINK(v)) v = NEXT_LINK(v);
  while (v) {
    write_field(h, v);
    if (v == first) break;
    v = PREV_LINK(v);
  }
}

static void write_enums(FILE *h, var_t *v)
183 184 185 186
{
  if (!v) return;
  while (NEXT_LINK(v)) v = NEXT_LINK(v);
  while (v) {
187
    if (get_name(v)) {
188
      indent(h, 0);
189
      write_name(h, v);
190 191
      if (v->eval) {
        fprintf(h, " = ");
192
        write_expr(h, v->eval, 0);
193
      }
194
    }
195 196
    if (PREV_LINK(v))
      fprintf(h, ",\n");
197 198
    v = PREV_LINK(v);
  }
199
  fprintf(h, "\n");
200 201
}

202 203 204 205 206
int needs_space_after(type_t *t)
{
  return t->kind == TKIND_ALIAS || ! is_ptr(t);
}

207
void write_type(FILE *h, type_t *t, const var_t *v, const char *n)
208 209 210
{
  int c;

211 212
  if (t->is_const) fprintf(h, "const ");

213
  if (n) fprintf(h, "%s", n);
214
  else if (t->kind == TKIND_ALIAS) fprintf(h, "%s", t->name);
215
  else {
216 217 218
    if (t->sign > 0) fprintf(h, "signed ");
    else if (t->sign < 0) fprintf(h, "unsigned ");
    switch (t->type) {
219 220
      case RPC_FC_ENUM16:
      case RPC_FC_ENUM32:
221
        if (t->defined && !t->written && !t->ignore) {
222 223
          if (t->name) fprintf(h, "enum %s {\n", t->name);
          else fprintf(h, "enum {\n");
224
          t->written = TRUE;
225 226
          indentation++;
          write_enums(h, t->fields);
227
          indent(h, -1);
228 229 230 231
          fprintf(h, "}");
        }
        else fprintf(h, "enum %s", t->name);
        break;
232
      case RPC_FC_STRUCT:
233 234 235 236 237
      case RPC_FC_CVSTRUCT:
      case RPC_FC_CPSTRUCT:
      case RPC_FC_CSTRUCT:
      case RPC_FC_PSTRUCT:
      case RPC_FC_BOGUS_STRUCT:
238
      case RPC_FC_ENCAPSULATED_UNION:
239
        if (t->defined && !t->written && !t->ignore) {
240 241
          if (t->name) fprintf(h, "struct %s {\n", t->name);
          else fprintf(h, "struct {\n");
242
          t->written = TRUE;
243
          indentation++;
244
          write_fields(h, t->fields);
245
          indent(h, -1);
246 247 248 249
          fprintf(h, "}");
        }
        else fprintf(h, "struct %s", t->name);
        break;
250
      case RPC_FC_NON_ENCAPSULATED_UNION:
251
        if (t->defined && !t->written && !t->ignore) {
252 253
          if (t->name) fprintf(h, "union %s {\n", t->name);
          else fprintf(h, "union {\n");
254
          t->written = TRUE;
255 256
          indentation++;
          write_fields(h, t->fields);
257
          indent(h, -1);
258 259 260 261
          fprintf(h, "}");
        }
        else fprintf(h, "union %s", t->name);
        break;
262 263
      case RPC_FC_RP:
      case RPC_FC_UP:
264
      case RPC_FC_FP:
265
      case RPC_FC_OP:
266
        if (t->ref) write_type(h, t->ref, NULL, t->name);
267
        fprintf(h, "%s*", needs_space_after(t->ref) ? " " : "");
268
        break;
269
      default:
270
        fprintf(h, "%s", t->name);
271 272 273 274 275 276 277 278 279
    }
  }
  if (v) {
    for (c=0; c<v->ptr_level; c++) {
      fprintf(h, "*");
    }
  }
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297

struct user_type
{
    struct user_type *next;
    char name[1];
};

static struct user_type *user_type_list;

static int user_type_registered(const char *name)
{
  struct user_type *ut;
  for (ut = user_type_list; ut; ut = ut->next)
    if (!strcmp(name, ut->name))
        return 1;
  return 0;
}

298
static void check_for_user_types(const var_t *v)
299 300
{
  while (v) {
301 302 303
    type_t *type;
    for (type = v->type; type; type = type->kind == TKIND_ALIAS ? type->orig : type->ref) {
      const char *name = type->name;
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
      if (type->user_types_registered) continue;
      type->user_types_registered = 1;
      if (is_attr(type->attrs, ATTR_WIREMARSHAL)) {
        if (!user_type_registered(name))
        {
          struct user_type *ut = xmalloc(sizeof(struct user_type) + strlen(name));
          strcpy(ut->name, name);
          ut->next = user_type_list;
          user_type_list = ut;
        }
        /* don't carry on parsing fields within this type as we are already
         * using a wire marshaled type */
        break;
      }
      else if (type->fields)
      {
320
        const var_t *fields = type->fields;
321 322 323 324 325 326 327 328 329 330 331 332 333 334
        while (NEXT_LINK(fields)) fields = NEXT_LINK(fields);
        check_for_user_types(fields);
      }
    }
    v = PREV_LINK(v);
  }
}

void write_user_types(void)
{
  struct user_type *ut;
  for (ut = user_type_list; ut; ut = ut->next)
  {
    const char *name = ut->name;
335
    fprintf(header, "ULONG           __RPC_USER %s_UserSize     (ULONG *, ULONG, %s *);\n", name, name);
336
    fprintf(header, "unsigned char * __RPC_USER %s_UserMarshal  (ULONG *, unsigned char *, %s *);\n", name, name);
337
    fprintf(header, "unsigned char * __RPC_USER %s_UserUnmarshal(ULONG *, unsigned char *, %s *);\n", name, name);
338
    fprintf(header, "void            __RPC_USER %s_UserFree     (ULONG *, %s *);\n", name, name);
339 340 341
  }
}

342
void write_typedef(type_t *type)
343 344
{
  fprintf(header, "typedef ");
345
  write_type(header, type->orig, NULL, NULL);
346
  fprintf(header, "%s%s;\n", needs_space_after(type->orig) ? " " : "", type->name);
347 348
}

349
void write_expr(FILE *h, const expr_t *e, int brackets)
350 351 352 353 354 355 356 357 358 359
{
  switch (e->type) {
  case EXPR_VOID:
    break;
  case EXPR_NUM:
    fprintf(h, "%ld", e->u.lval);
    break;
  case EXPR_HEXNUM:
    fprintf(h, "0x%lx", e->u.lval);
    break;
360 361 362 363 364 365
  case EXPR_TRUEFALSE:
    if (e->u.lval == 0)
      fprintf(h, "FALSE");
    else
      fprintf(h, "TRUE");
    break;
366 367 368 369 370
  case EXPR_IDENTIFIER:
    fprintf(h, "%s", e->u.sval);
    break;
  case EXPR_NEG:
    fprintf(h, "-");
371
    write_expr(h, e->ref, 1);
372
    break;
373 374
  case EXPR_NOT:
    fprintf(h, "~");
375
    write_expr(h, e->ref, 1);
376
    break;
377 378
  case EXPR_PPTR:
    fprintf(h, "*");
379
    write_expr(h, e->ref, 1);
380 381 382 383 384
    break;
  case EXPR_CAST:
    fprintf(h, "(");
    write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
    fprintf(h, ")");
385
    write_expr(h, e->ref, 1);
386 387 388 389 390 391 392 393 394 395 396 397 398 399
    break;
  case EXPR_SIZEOF:
    fprintf(h, "sizeof(");
    write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
    fprintf(h, ")");
    break;
  case EXPR_SHL:
  case EXPR_SHR:
  case EXPR_MUL:
  case EXPR_DIV:
  case EXPR_ADD:
  case EXPR_SUB:
  case EXPR_AND:
  case EXPR_OR:
400 401
    if (brackets) fprintf(h, "(");
    write_expr(h, e->ref, 1);
402 403 404 405 406 407 408 409 410 411 412
    switch (e->type) {
    case EXPR_SHL: fprintf(h, " << "); break;
    case EXPR_SHR: fprintf(h, " >> "); break;
    case EXPR_MUL: fprintf(h, " * "); break;
    case EXPR_DIV: fprintf(h, " / "); break;
    case EXPR_ADD: fprintf(h, " + "); break;
    case EXPR_SUB: fprintf(h, " - "); break;
    case EXPR_AND: fprintf(h, " & "); break;
    case EXPR_OR:  fprintf(h, " | "); break;
    default: break;
    }
413 414
    write_expr(h, e->u.ext, 1);
    if (brackets) fprintf(h, ")");
415
    break;
416
  case EXPR_COND:
417 418
    if (brackets) fprintf(h, "(");
    write_expr(h, e->ref, 1);
419
    fprintf(h, " ? ");
420
    write_expr(h, e->u.ext, 1);
421
    fprintf(h, " : ");
422 423
    write_expr(h, e->ext2, 1);
    if (brackets) fprintf(h, ")");
424
    break;
425 426 427
  }
}

428
void write_constdef(const var_t *v)
429 430
{
  fprintf(header, "#define %s (", get_name(v));
431
  write_expr(header, v->eval, 0);
432 433 434
  fprintf(header, ")\n\n");
}

435
void write_externdef(const var_t *v)
436 437 438 439 440 441 442 443 444 445
{
  fprintf(header, "extern const ");
  write_type(header, v->type, NULL, v->tname);
  if (get_name(v)) {
    fprintf(header, " ");
    write_pident(header, v);
  }
  fprintf(header, ";\n\n");
}

446
void write_library(const char *name, const attr_t *attr) {
447
  const UUID *uuid = get_attrp(attr, ATTR_UUID);
448
  fprintf(header, "\n");
449
  write_guid(header, "LIBID", name, uuid);
450 451 452
  fprintf(header, "\n");
}

453

454
const var_t* get_explicit_handle_var(const func_t* func)
455
{
456
    const var_t* var;
457 458 459 460 461 462 463 464

    if (!func->args)
        return NULL;

    var = func->args;
    while (NEXT_LINK(var)) var = NEXT_LINK(var);
    while (var)
    {
465
        if (var->type->type == RPC_FC_BIND_PRIMITIVE)
466 467 468 469 470 471 472 473
            return var;

        var = PREV_LINK(var);
    }

    return NULL;
}

474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
int has_out_arg_or_return(const func_t *func)
{
    var_t *var;

    if (!is_void(func->def->type, NULL))
        return 1;

    if (!func->args)
        return 0;

    var = func->args;
    while (NEXT_LINK(var)) var = NEXT_LINK(var);
    while (var)
    {
        if (is_attr(var->attrs, ATTR_OUT))
            return 1;

        var = PREV_LINK(var);
    }
    return 0;
}

496

497 498
/********** INTERFACES **********/

499
int is_object(const attr_t *a)
500
{
501 502 503 504 505
  while (a) {
    if (a->type == ATTR_OBJECT || a->type == ATTR_ODL) return 1;
    a = NEXT_LINK(a);
  }
  return 0;
506 507
}

508
int is_local(const attr_t *a)
509 510 511 512
{
  return is_attr(a, ATTR_LOCAL);
}

513
const var_t *is_callas(const attr_t *a)
514
{
515
  return get_attrp(a, ATTR_CALLAS);
516 517
}

518
static void write_method_macro(const type_t *iface, const char *name)
519 520 521
{
  func_t *cur = iface->funcs;

522
  if (iface->ref) write_method_macro(iface->ref, name);
523

524
  if (!cur) return;
525 526
  while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
  fprintf(header, "/*** %s methods ***/\n", iface->name);
  while (cur) {
    var_t *def = cur->def;
    if (!is_callas(def->attrs)) {
      var_t *arg = cur->args;
      int argc = 0;
      int c;
      while (arg) {
	arg = NEXT_LINK(arg);
	argc++;
      }

      fprintf(header, "#define %s_", name);
      write_name(header,def);
      fprintf(header, "(p");
      for (c=0; c<argc; c++)
	fprintf(header, ",%c", c+'a');
      fprintf(header, ") ");

546 547 548
      fprintf(header, "(p)->lpVtbl->");
      write_name(header, def);
      fprintf(header, "(p");
549 550 551 552 553 554 555 556
      for (c=0; c<argc; c++)
	fprintf(header, ",%c", c+'a');
      fprintf(header, ")\n");
    }
    cur = PREV_LINK(cur);
  }
}

557
void write_args(FILE *h, var_t *arg, const char *name, int method, int do_indent)
558
{
559
  int count = 0;
560 561 562 563
  if (arg) {
    while (NEXT_LINK(arg))
      arg = NEXT_LINK(arg);
  }
564 565
  if (do_indent)
  {
566 567
      indentation++;
      indent(h, 0);
568
  }
569 570
  if (method == 1) {
    fprintf(h, "%s* This", name);
571 572
    count++;
  }
573
  while (arg) {
574
    if (count) {
575 576 577
        if (do_indent)
        {
            fprintf(h, ",\n");
578
            indent(h, 0);
579 580
        }
        else fprintf(h, ",");
581
    }
582
    write_type(h, arg->type, arg, arg->tname);
583 584 585 586 587 588 589 590 591 592
    if (arg->args)
    {
      fprintf(h, " (STDMETHODCALLTYPE *");
      write_name(h,arg);
      fprintf(h, ")(");
      write_args(h, arg->args, NULL, 0, FALSE);
      fprintf(h, ")");
    }
    else
    {
593 594
      if (needs_space_after(arg->type))
        fprintf(h, " ");
595 596
      write_name(h, arg);
    }
597
    write_array(h, arg->array, 0);
598
    arg = PREV_LINK(arg);
599
    count++;
600
  }
601
  if (do_indent) indentation--;
602 603
}

604
static void write_cpp_method_def(const type_t *iface)
605 606
{
  func_t *cur = iface->funcs;
607 608

  if (!cur) return;
609 610 611 612
  while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
  while (cur) {
    var_t *def = cur->def;
    if (!is_callas(def->attrs)) {
613
      indent(header, 0);
614 615
      fprintf(header, "virtual ");
      write_type(header, def->type, def, def->tname);
616
      fprintf(header, " STDMETHODCALLTYPE ");
617 618
      write_name(header, def);
      fprintf(header, "(\n");
619
      write_args(header, cur->args, iface->name, 2, TRUE);
620 621 622 623 624 625 626
      fprintf(header, ") = 0;\n");
      fprintf(header, "\n");
    }
    cur = PREV_LINK(cur);
  }
}

627
static void do_write_c_method_def(const type_t *iface, const char *name)
628
{
629
  const func_t *cur = iface->funcs;
630

631
  if (iface->ref) do_write_c_method_def(iface->ref, name);
632 633 634

  if (!cur) return;
  while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
635
  indent(header, 0);
636 637
  fprintf(header, "/*** %s methods ***/\n", iface->name);
  while (cur) {
638
    const var_t *def = cur->def;
639
    if (!is_callas(def->attrs)) {
640
      indent(header, 0);
641
      write_type(header, def->type, def, def->tname);
642
      fprintf(header, " (STDMETHODCALLTYPE *");
643 644
      write_name(header, def);
      fprintf(header, ")(\n");
645
      write_args(header, cur->args, name, 1, TRUE);
646 647 648 649 650
      fprintf(header, ");\n");
      fprintf(header, "\n");
    }
    cur = PREV_LINK(cur);
  }
651 652
}

653
static void write_c_method_def(const type_t *iface)
654 655 656 657
{
  do_write_c_method_def(iface, iface->name);
}

658
static void write_c_disp_method_def(const type_t *iface)
659 660 661 662
{
  do_write_c_method_def(iface->ref, iface->name);
}

663
static void write_method_proto(const type_t *iface)
664
{
665
  const func_t *cur = iface->funcs;
666 667

  if (!cur) return;
668 669
  while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
  while (cur) {
670 671 672
    const var_t *def = cur->def;
    const var_t *cas = is_callas(def->attrs);
    const var_t *args;
673 674 675 676
    if (!is_local(def->attrs)) {
      /* proxy prototype */
      write_type(header, def->type, def, def->tname);
      fprintf(header, " CALLBACK %s_", iface->name);
677
      write_name(header, def);
678
      fprintf(header, "_Proxy(\n");
679
      write_args(header, cur->args, iface->name, 1, TRUE);
680 681 682 683 684
      fprintf(header, ");\n");
      /* stub prototype */
      fprintf(header, "void __RPC_STUB %s_", iface->name);
      write_name(header,def);
      fprintf(header, "_Stub(\n");
685 686
      fprintf(header, "    IRpcStubBuffer* This,\n");
      fprintf(header, "    IRpcChannelBuffer* pRpcChannelBuffer,\n");
687 688
      fprintf(header, "    PRPC_MESSAGE pRpcMessage,\n");
      fprintf(header, "    DWORD* pdwStubPhase);\n");
689 690 691 692 693 694 695

      args = cur->args;
      if (args) {
        while (NEXT_LINK(args))
          args = NEXT_LINK(args);
      }
      check_for_user_types(args);
696 697
    }
    if (cas) {
698
      const func_t *m = iface->funcs;
699 700 701
      while (m && strcmp(get_name(m->def), cas->name))
        m = NEXT_LINK(m);
      if (m) {
702
        const var_t *mdef = m->def;
703 704 705 706 707
        /* proxy prototype - use local prototype */
        write_type(header, mdef->type, mdef, mdef->tname);
        fprintf(header, " CALLBACK %s_", iface->name);
        write_name(header, mdef);
        fprintf(header, "_Proxy(\n");
708
        write_args(header, m->args, iface->name, 1, TRUE);
709 710 711 712 713 714
        fprintf(header, ");\n");
        /* stub prototype - use remotable prototype */
        write_type(header, def->type, def, def->tname);
        fprintf(header, " __RPC_STUB %s_", iface->name);
        write_name(header, mdef);
        fprintf(header, "_Stub(\n");
715
        write_args(header, cur->args, iface->name, 1, TRUE);
716 717 718
        fprintf(header, ");\n");
      }
      else {
719
        parser_warning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name);
720 721 722 723 724 725 726
      }
    }

    cur = PREV_LINK(cur);
  }
}

727
static void write_function_proto(const type_t *iface)
728
{
729
  const char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
730
  int explicit_handle = is_attr(iface->attrs, ATTR_EXPLICIT_HANDLE);
731
  const var_t* explicit_handle_var;
732

733 734 735 736
  func_t *cur = iface->funcs;
  while (NEXT_LINK(cur)) cur = NEXT_LINK(cur);
  while (cur) {
    var_t *def = cur->def;
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751

    /* check for a defined binding handle */
    explicit_handle_var = get_explicit_handle_var(cur);
    if (explicit_handle) {
      if (!explicit_handle_var) {
        error("%s() does not define an explicit binding handle!\n", def->name);
        return;
      }
    } else if (implicit_handle) {
      if (explicit_handle_var) {
        error("%s() must not define a binding handle!\n", def->name);
        return;
      }
    }

752 753 754 755 756
    /* FIXME: do we need to handle call_as? */
    write_type(header, def->type, def, def->tname);
    fprintf(header, " ");
    write_name(header, def);
    fprintf(header, "(\n");
757 758 759 760
    if (cur->args)
      write_args(header, cur->args, iface->name, 0, TRUE);
    else
      fprintf(header, "    void");
761 762 763 764 765 766
    fprintf(header, ");\n");

    cur = PREV_LINK(cur);
  }
}

767 768
void write_forward(type_t *iface)
{
769 770 771 772 773
  /* C/C++ forwards should only be written for object interfaces, so if we
   * have a full definition we only write one if we find [object] among the
   * attributes - however, if we don't have a full definition at this point
   * (i.e. this is an IDL forward), then we also assume that it is an object
   * interface, since non-object interfaces shouldn't need forwards */
774 775
  if ((!iface->defined || is_object(iface->attrs) || is_attr(iface->attrs, ATTR_DISPINTERFACE))
        && !iface->written) {
776 777 778
    fprintf(header, "#ifndef __%s_FWD_DEFINED__\n", iface->name);
    fprintf(header, "#define __%s_FWD_DEFINED__\n", iface->name);
    fprintf(header, "typedef interface %s %s;\n", iface->name, iface->name);
779
    fprintf(header, "#endif\n\n" );
780 781 782 783
    iface->written = TRUE;
  }
}

784
static void write_iface_guid(const type_t *iface)
785
{
786
  const UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
787
  write_guid(header, "IID", iface->name, uuid);
788 789
} 

790
static void write_dispiface_guid(const type_t *iface)
791
{
792
  const UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
793
  write_guid(header, "DIID", iface->name, uuid);
794 795
}

796
static void write_coclass_guid(type_t *cocl)
797
{
798
  const UUID *uuid = get_attrp(cocl->attrs, ATTR_UUID);
799
  write_guid(header, "CLSID", cocl->name, uuid);
800 801
}

802
static void write_com_interface(type_t *iface)
803
{
804
  if (!iface->funcs && !iface->ref) {
805
    parser_warning("%s has no methods", iface->name);
806 807 808 809 810 811
    return;
  }

  fprintf(header, "/*****************************************************************************\n");
  fprintf(header, " * %s interface\n", iface->name);
  fprintf(header, " */\n");
812 813
  fprintf(header,"#ifndef __%s_INTERFACE_DEFINED__\n", iface->name);
  fprintf(header,"#define __%s_INTERFACE_DEFINED__\n\n", iface->name);
814
  write_iface_guid(iface);
815
  write_forward(iface);
816 817 818
  /* C++ interface */
  fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n");
  if (iface->ref)
819
  {
820
      fprintf(header, "interface %s : public %s\n", iface->name, iface->ref->name);
821 822 823 824 825 826
      fprintf(header, "{\n");
      indentation++;
      write_cpp_method_def(iface);
      indentation--;
      fprintf(header, "};\n");
  }
827 828
  else
  {
829
      fprintf(header, "interface %s\n", iface->name);
830 831 832 833 834 835 836 837
      fprintf(header, "{\n");
      fprintf(header, "    BEGIN_INTERFACE\n");
      fprintf(header, "\n");
      indentation++;
      write_cpp_method_def(iface);
      indentation--;
      fprintf(header, "    END_INTERFACE\n");
      fprintf(header, "};\n");
838
  }
839 840
  fprintf(header, "#else\n");
  /* C interface */
841
  fprintf(header, "typedef struct %sVtbl {\n", iface->name);
842
  indentation++;
843
  fprintf(header, "    BEGIN_INTERFACE\n");
844 845 846
  fprintf(header, "\n");
  write_c_method_def(iface);
  indentation--;
847
  fprintf(header, "    END_INTERFACE\n");
848 849
  fprintf(header, "} %sVtbl;\n", iface->name);
  fprintf(header, "interface %s {\n", iface->name);
850
  fprintf(header, "    CONST_VTBL %sVtbl* lpVtbl;\n", iface->name);
851 852
  fprintf(header, "};\n");
  fprintf(header, "\n");
853
  fprintf(header, "#ifdef COBJMACROS\n");
854
  write_method_macro(iface, iface->name);
855
  fprintf(header, "#endif\n");
856 857
  fprintf(header, "\n");
  fprintf(header, "#endif\n");
858 859
  fprintf(header, "\n");
  write_method_proto(iface);
860
  fprintf(header,"\n#endif  /* __%s_INTERFACE_DEFINED__ */\n\n", iface->name);
861
}
862

863
static void write_rpc_interface(const type_t *iface)
864
{
865
  unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION);
866
  const char *var = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
867 868 869 870 871 872 873 874
  static int allocate_written = 0;

  if (!allocate_written)
  {
    allocate_written = 1;
    fprintf(header, "void * __RPC_USER MIDL_user_allocate(size_t);\n");
    fprintf(header, "void __RPC_USER MIDL_user_free(void *);\n\n");
  }
875 876 877 878

  fprintf(header, "/*****************************************************************************\n");
  fprintf(header, " * %s interface (v%d.%d)\n", iface->name, LOWORD(ver), HIWORD(ver));
  fprintf(header, " */\n");
879 880
  fprintf(header,"#ifndef __%s_INTERFACE_DEFINED__\n", iface->name);
  fprintf(header,"#define __%s_INTERFACE_DEFINED__\n\n", iface->name);
881 882 883 884
  if (iface->funcs)
  {
    write_iface_guid(iface);
    if (var) fprintf(header, "extern handle_t %s;\n", var);
885 886 887 888 889 890 891 892 893 894
    if (old_names)
    {
        fprintf(header, "extern RPC_IF_HANDLE %s_ClientIfHandle;\n", iface->name);
        fprintf(header, "extern RPC_IF_HANDLE %s_ServerIfHandle;\n", iface->name);
    }
    else
    {
        fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_c_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
        fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_s_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver));
    }
895 896
    write_function_proto(iface);
  }
897
  fprintf(header,"\n#endif  /* __%s_INTERFACE_DEFINED__ */\n\n", iface->name);
898 899 900 901 902 903 904 905 906 907 908

  /* FIXME: server/client code */
}

void write_interface(type_t *iface)
{
  if (is_object(iface->attrs))
    write_com_interface(iface);
  else
    write_rpc_interface(iface);
}
909 910 911 912 913 914 915 916 917 918 919 920

void write_dispinterface(type_t *iface)
{
  fprintf(header, "/*****************************************************************************\n");
  fprintf(header, " * %s dispinterface\n", iface->name);
  fprintf(header, " */\n");
  fprintf(header,"#ifndef __%s_DISPINTERFACE_DEFINED__\n", iface->name);
  fprintf(header,"#define __%s_DISPINTERFACE_DEFINED__\n\n", iface->name);
  write_dispiface_guid(iface);
  write_forward(iface);
  /* C++ interface */
  fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n");
921
  fprintf(header, "interface %s : public %s\n", iface->name, iface->ref->name);
922 923 924 925
  fprintf(header, "{\n");
  fprintf(header, "};\n");
  fprintf(header, "#else\n");
  /* C interface */
926
  fprintf(header, "typedef struct %sVtbl {\n", iface->name);
927 928 929 930 931 932
  indentation++;
  fprintf(header, "    BEGIN_INTERFACE\n");
  fprintf(header, "\n");
  write_c_disp_method_def(iface);
  indentation--;
  fprintf(header, "    END_INTERFACE\n");
933 934
  fprintf(header, "} %sVtbl;\n", iface->name);
  fprintf(header, "interface %s {\n", iface->name);
935
  fprintf(header, "    CONST_VTBL %sVtbl* lpVtbl;\n", iface->name);
936 937 938 939 940 941 942 943 944 945 946
  fprintf(header, "};\n");
  fprintf(header, "\n");
  fprintf(header, "#ifdef COBJMACROS\n");
  write_method_macro(iface->ref, iface->name);
  fprintf(header, "#endif\n");
  fprintf(header, "\n");
  fprintf(header, "#endif\n");
  fprintf(header, "\n");
  fprintf(header,"#endif  /* __%s_DISPINTERFACE_DEFINED__ */\n\n", iface->name);
}

947
void write_coclass(type_t *cocl)
948 949 950 951 952 953 954
{
  fprintf(header, "/*****************************************************************************\n");
  fprintf(header, " * %s coclass\n", cocl->name);
  fprintf(header, " */\n\n");
  write_coclass_guid(cocl);
  fprintf(header, "\n");
}
955

956
void write_coclass_forward(type_t *cocl)
957 958 959 960
{
  fprintf(header, "#ifndef __%s_FWD_DEFINED__\n", cocl->name);
  fprintf(header, "#define __%s_FWD_DEFINED__\n", cocl->name);
  fprintf(header, "typedef struct %s %s;\n", cocl->name, cocl->name);
961
  fprintf(header, "#endif /* defined __%s_FWD_DEFINED__ */\n\n", cocl->name );
962
}