PageRenderTime 85ms CodeModel.GetById 22ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/rel-1.3.35/Source/Swig/typemap.c

#
C | 1900 lines | 1387 code | 206 blank | 307 comment | 351 complexity | 9d280ab9c0f442829cd831a7eecfd7b1 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
   1/* -----------------------------------------------------------------------------
   2 * See the LICENSE file for information on copyright, usage and redistribution
   3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
   4 *
   5 * typemap.c
   6 *
   7 * A somewhat generalized implementation of SWIG1.1 typemaps.
   8 * ----------------------------------------------------------------------------- */
   9
  10char cvsroot_typemap_c[] = "$Id: typemap.c 9889 2007-08-10 02:55:27Z wuzzeb $";
  11
  12#include "swig.h"
  13#include "cparse.h"
  14#include <ctype.h>
  15
  16#if 0
  17#define SWIG_DEBUG
  18#endif
  19
  20static void replace_embedded_typemap(String *s);
  21
  22/* -----------------------------------------------------------------------------
  23 * Typemaps are stored in a collection of nested hash tables.  Something like
  24 * this:
  25 *
  26 * [ type ]
  27 *    +-------- [ name ]
  28 *    +-------- [ name ]
  29 *    
  30 * Each hash table [ type ] or [ name ] then contains references to the
  31 * different typemap methods.    These are referenced by names such as
  32 * "tmap:in", "tmap:out", "tmap:argout", and so forth.
  33 *
  34 * The object corresponding to a specific method has the following
  35 * attributes:
  36 *
  37 *    "type"    -  Typemap type
  38 *    "pname"   -  Parameter name
  39 *    "code"    -  Typemap code
  40 *    "typemap" -  Descriptive text describing the actual map
  41 *    "locals"  -  Local variables (if any)
  42 * 
  43 * ----------------------------------------------------------------------------- */
  44
  45#define MAX_SCOPE  32
  46
  47
  48static Hash *typemaps[MAX_SCOPE];
  49static int tm_scope = 0;
  50
  51static Hash *get_typemap(int tm_scope, SwigType *type) {
  52  Hash *tm = 0;
  53  SwigType *dtype = 0;
  54  if (SwigType_istemplate(type)) {
  55    String *ty = Swig_symbol_template_deftype(type, 0);
  56    dtype = Swig_symbol_type_qualify(ty, 0);
  57    /* Printf(stderr,"gettm %s %s\n", type, dtype); */
  58    type = dtype;
  59    Delete(ty);
  60  }
  61  tm = Getattr(typemaps[tm_scope], type);
  62
  63
  64  if (dtype) {
  65    if (!tm) {
  66      String *t_name = SwigType_templateprefix(type);
  67      if (!Equal(t_name, type)) {
  68	tm = Getattr(typemaps[tm_scope], t_name);
  69      }
  70      Delete(t_name);
  71    }
  72    Delete(dtype);
  73  }
  74
  75  return tm;
  76}
  77
  78static void set_typemap(int tm_scope, SwigType *type, Hash *tm) {
  79  SwigType *dtype = 0;
  80  if (SwigType_istemplate(type)) {
  81    String *ty = Swig_symbol_template_deftype(type, 0);
  82    dtype = Swig_symbol_type_qualify(ty, 0);
  83    /* Printf(stderr,"settm %s %s\n", type, dtype); */
  84    type = dtype;
  85    Delete(ty);
  86  } else {
  87    dtype = Copy(type);
  88    type = dtype;
  89  }
  90  Setattr(typemaps[tm_scope], type, tm);
  91  Delete(dtype);
  92}
  93
  94
  95/* -----------------------------------------------------------------------------
  96 * Swig_typemap_init()
  97 *
  98 * Initialize the typemap system
  99 * ----------------------------------------------------------------------------- */
 100
 101void Swig_typemap_init() {
 102  int i;
 103  for (i = 0; i < MAX_SCOPE; i++) {
 104    typemaps[i] = 0;
 105  }
 106  typemaps[0] = NewHash();
 107  tm_scope = 0;
 108}
 109
 110static String *tmop_name(const String_or_char *op) {
 111  static Hash *names = 0;
 112  String *s;
 113  /* Due to "interesting" object-identity semantics of DOH,
 114     we have to make sure that we only intern strings without object
 115     identity into the hash table.
 116
 117     (Swig_typemap_attach_kwargs calls tmop_name several times with
 118     the "same" String *op (i.e., same object identity) but differing
 119     string values.)
 120
 121     Most other callers work around this by using char* rather than
 122     String *.
 123     -- mkoeppe, Jun 17, 2003
 124   */
 125  const char *op_without_object_identity = Char(op);
 126  if (!names)
 127    names = NewHash();
 128  s = Getattr(names, op_without_object_identity);
 129  if (s)
 130    return s;
 131  s = NewStringf("tmap:%s", op);
 132  Setattr(names, op_without_object_identity, s);
 133  Delete(s);
 134  return s;
 135}
 136
 137/* -----------------------------------------------------------------------------
 138 * Swig_typemap_new_scope()
 139 * 
 140 * Create a new typemap scope
 141 * ----------------------------------------------------------------------------- */
 142
 143void Swig_typemap_new_scope() {
 144  tm_scope++;
 145  typemaps[tm_scope] = NewHash();
 146}
 147
 148/* -----------------------------------------------------------------------------
 149 * Swig_typemap_pop_scope()
 150 *
 151 * Pop the last typemap scope off
 152 * ----------------------------------------------------------------------------- */
 153
 154Hash *Swig_typemap_pop_scope() {
 155  if (tm_scope > 0) {
 156    return typemaps[tm_scope--];
 157  }
 158  return 0;
 159}
 160
 161/* ----------------------------------------------------------------------------- 
 162 * Swig_typemap_register()
 163 *
 164 * Add a new multi-valued typemap
 165 * ----------------------------------------------------------------------------- */
 166
 167void Swig_typemap_register(const String_or_char *op, ParmList *parms, String_or_char *code, ParmList *locals, ParmList *kwargs) {
 168  Hash *tm;
 169  Hash *tm1;
 170  Hash *tm2;
 171  Parm *np;
 172  String *tmop;
 173  SwigType *type;
 174  String *pname;
 175
 176  if (!parms)
 177    return;
 178  tmop = tmop_name(op);
 179
 180  /* Register the first type in the parameter list */
 181
 182  type = Getattr(parms, "type");
 183  pname = Getattr(parms, "name");
 184
 185  /* See if this type has been seen before */
 186  tm = get_typemap(tm_scope, type);
 187  if (!tm) {
 188    tm = NewHash();
 189    set_typemap(tm_scope, type, tm);
 190    Delete(tm);
 191  }
 192  if (pname) {
 193    /* See if parameter has been seen before */
 194    tm1 = Getattr(tm, pname);
 195    if (!tm1) {
 196      tm1 = NewHash();
 197      Setattr(tm, pname, tm1);
 198      Delete(tm1);
 199    }
 200    tm = tm1;
 201  }
 202
 203  /* Now see if this typemap op has been seen before */
 204  tm2 = Getattr(tm, tmop);
 205  if (!tm2) {
 206    tm2 = NewHash();
 207    Setattr(tm, tmop, tm2);
 208    Delete(tm2);
 209  }
 210
 211  /* For a multi-valued typemap, the typemap code and information
 212     is really only stored in the last argument.  However, to
 213     make this work, we perform a really neat trick using
 214     the typemap operator name.
 215
 216     For example, consider this typemap
 217
 218     %typemap(in) (int foo, int *bar, char *blah[]) {
 219     ...
 220     }
 221
 222     To store it, we look at typemaps for the following:
 223
 224     operator                  type-name
 225     ----------------------------------------------
 226     "in"                      int foo
 227     "in-int+foo:"             int *bar
 228     "in-int+foo:-p.int+bar:   char *blah[]
 229
 230     Notice how the operator expands to encode information about
 231     previous arguments.        
 232
 233   */
 234
 235  np = nextSibling(parms);
 236  if (np) {
 237    /* Make an entirely new operator key */
 238    String *newop = NewStringf("%s-%s+%s:", op, type, pname);
 239    /* Now reregister on the remaining arguments */
 240    Swig_typemap_register(newop, np, code, locals, kwargs);
 241
 242    /*    Setattr(tm2,newop,newop); */
 243    Delete(newop);
 244  } else {
 245    String *str = SwigType_str(type, pname);
 246    String *typemap = NewStringf("typemap(%s) %s", op, str);
 247    ParmList *clocals = CopyParmList(locals);
 248    ParmList *ckwargs = CopyParmList(kwargs);
 249
 250    Setattr(tm2, "code", code);
 251    Setattr(tm2, "type", type);
 252    Setattr(tm2, "typemap", typemap);
 253    if (pname) {
 254      Setattr(tm2, "pname", pname);
 255    }
 256    Setattr(tm2, "locals", clocals);
 257    Setattr(tm2, "kwargs", ckwargs);
 258
 259    Delete(clocals);
 260    Delete(ckwargs);
 261
 262    Delete(str);
 263    Delete(typemap);
 264  }
 265}
 266
 267/* -----------------------------------------------------------------------------
 268 * Swig_typemap_get()
 269 *
 270 * Retrieve typemap information from current scope.
 271 * ----------------------------------------------------------------------------- */
 272
 273static Hash *Swig_typemap_get(SwigType *type, String_or_char *name, int scope) {
 274  Hash *tm, *tm1;
 275  /* See if this type has been seen before */
 276  if ((scope < 0) || (scope > tm_scope))
 277    return 0;
 278  tm = get_typemap(scope, type);
 279  if (!tm) {
 280    return 0;
 281  }
 282  if ((name) && Len(name)) {
 283    tm1 = Getattr(tm, name);
 284    return tm1;
 285  }
 286  return tm;
 287}
 288
 289/* -----------------------------------------------------------------------------
 290 * Swig_typemap_copy()
 291 *
 292 * Copy a typemap
 293 * ----------------------------------------------------------------------------- */
 294
 295int Swig_typemap_copy(const String_or_char *op, ParmList *srcparms, ParmList *parms) {
 296  Hash *tm = 0;
 297  String *tmop;
 298  Parm *p;
 299  String *pname;
 300  SwigType *ptype;
 301  int ts = tm_scope;
 302  String *tmops, *newop;
 303  if (ParmList_len(parms) != ParmList_len(srcparms))
 304    return -1;
 305
 306  tmop = tmop_name(op);
 307  while (ts >= 0) {
 308    p = srcparms;
 309    tmops = NewString(tmop);
 310    while (p) {
 311      ptype = Getattr(p, "type");
 312      pname = Getattr(p, "name");
 313
 314      /* Lookup the type */
 315      tm = Swig_typemap_get(ptype, pname, ts);
 316      if (!tm)
 317	break;
 318
 319      tm = Getattr(tm, tmops);
 320      if (!tm)
 321	break;
 322
 323      /* Got a match.  Look for next typemap */
 324      newop = NewStringf("%s-%s+%s:", tmops, ptype, pname);
 325      Delete(tmops);
 326      tmops = newop;
 327      p = nextSibling(p);
 328    }
 329    Delete(tmops);
 330
 331    if (!p && tm) {
 332
 333      /* Got some kind of match */
 334      Swig_typemap_register(op, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs"));
 335      return 0;
 336    }
 337    ts--;
 338  }
 339  /* Not found */
 340  return -1;
 341
 342}
 343
 344/* -----------------------------------------------------------------------------
 345 * Swig_typemap_clear()
 346 *
 347 * Delete a multi-valued typemap
 348 * ----------------------------------------------------------------------------- */
 349
 350void Swig_typemap_clear(const String_or_char *op, ParmList *parms) {
 351  SwigType *type;
 352  String *name;
 353  Parm *p;
 354  String *newop;
 355  Hash *tm = 0;
 356
 357  /* This might not work */
 358  newop = NewString(op);
 359  p = parms;
 360  while (p) {
 361    type = Getattr(p, "type");
 362    name = Getattr(p, "name");
 363    tm = Swig_typemap_get(type, name, tm_scope);
 364    if (!tm)
 365      return;
 366    p = nextSibling(p);
 367    if (p)
 368      Printf(newop, "-%s+%s:", type, name);
 369  }
 370  if (tm) {
 371    tm = Getattr(tm, tmop_name(newop));
 372    if (tm) {
 373      Delattr(tm, "code");
 374      Delattr(tm, "locals");
 375      Delattr(tm, "kwargs");
 376    }
 377  }
 378  Delete(newop);
 379}
 380
 381/* -----------------------------------------------------------------------------
 382 * Swig_typemap_apply()
 383 *
 384 * Multi-argument %apply directive.  This is pretty horrible so I sure hope
 385 * it works.
 386 * ----------------------------------------------------------------------------- */
 387
 388static
 389int count_args(String *s) {
 390  /* Count up number of arguments */
 391  int na = 0;
 392  char *c = Char(s);
 393  while (*c) {
 394    if (*c == '+')
 395      na++;
 396    c++;
 397  }
 398  return na;
 399}
 400
 401int Swig_typemap_apply(ParmList *src, ParmList *dest) {
 402  String *ssig, *dsig;
 403  Parm *p, *np, *lastp, *dp, *lastdp = 0;
 404  int narg = 0;
 405  int ts = tm_scope;
 406  SwigType *type = 0, *name;
 407  Hash *tm, *sm;
 408  int match = 0;
 409
 410  /*  Printf(stdout,"apply : %s --> %s\n", ParmList_str(src), ParmList_str(dest)); */
 411
 412  /* Create type signature of source */
 413  ssig = NewStringEmpty();
 414  dsig = NewStringEmpty();
 415  p = src;
 416  dp = dest;
 417  lastp = 0;
 418  while (p) {
 419    lastp = p;
 420    lastdp = dp;
 421    np = nextSibling(p);
 422    if (np) {
 423      Printf(ssig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name"));
 424      Printf(dsig, "-%s+%s:", Getattr(dp, "type"), Getattr(dp, "name"));
 425      narg++;
 426    }
 427    p = np;
 428    dp = nextSibling(dp);
 429  }
 430
 431  /* make sure a typemap node exists for the last destination node */
 432  type = Getattr(lastdp, "type");
 433  tm = get_typemap(tm_scope, type);
 434  if (!tm) {
 435    tm = NewHash();
 436    set_typemap(tm_scope, type, tm);
 437    Delete(tm);
 438  }
 439  name = Getattr(lastdp, "name");
 440  if (name) {
 441    Hash *tm1 = Getattr(tm, name);
 442    if (!tm1) {
 443      tm1 = NewHash();
 444      Setattr(tm, NewString(name), tm1);
 445      Delete(tm1);
 446    }
 447    tm = tm1;
 448  }
 449
 450  /* This is a little nasty.  We need to go searching for all possible typemaps in the
 451     source and apply them to the target */
 452
 453  type = Getattr(lastp, "type");
 454  name = Getattr(lastp, "name");
 455
 456  while (ts >= 0) {
 457
 458    /* See if there is a matching typemap in this scope */
 459    sm = Swig_typemap_get(type, name, ts);
 460
 461    /* if there is not matching, look for a typemap in the
 462       original typedef, if any, like in:
 463
 464       typedef unsigned long size_t;
 465       ...
 466       %apply(size_t) {my_size};  ==>  %apply(unsigned long) {my_size};
 467     */
 468    if (!sm) {
 469      SwigType *ntype = SwigType_typedef_resolve(type);
 470      if (ntype && (Cmp(ntype, type) != 0)) {
 471	sm = Swig_typemap_get(ntype, name, ts);
 472      }
 473      Delete(ntype);
 474    }
 475
 476    if (sm) {
 477      /* Got a typemap.  Need to only merge attributes for methods that match our signature */
 478      Iterator ki;
 479      match = 1;
 480      for (ki = First(sm); ki.key; ki = Next(ki)) {
 481	/* Check for a signature match with the source signature */
 482	if ((count_args(ki.key) == narg) && (Strstr(ki.key, ssig))) {
 483	  String *oldm;
 484	  /* A typemap we have to copy */
 485	  String *nkey = Copy(ki.key);
 486	  Replace(nkey, ssig, dsig, DOH_REPLACE_ANY);
 487
 488	  /* Make sure the typemap doesn't already exist in the target map */
 489
 490	  oldm = Getattr(tm, nkey);
 491	  if (!oldm || (!Getattr(tm, "code"))) {
 492	    String *code;
 493	    ParmList *locals;
 494	    ParmList *kwargs;
 495	    Hash *sm1 = ki.item;
 496
 497	    code = Getattr(sm1, "code");
 498	    locals = Getattr(sm1, "locals");
 499	    kwargs = Getattr(sm1, "kwargs");
 500	    if (code) {
 501	      Replace(nkey, dsig, "", DOH_REPLACE_ANY);
 502	      Replace(nkey, "tmap:", "", DOH_REPLACE_ANY);
 503	      Swig_typemap_register(nkey, dest, code, locals, kwargs);
 504	    }
 505	  }
 506	  Delete(nkey);
 507	}
 508      }
 509    }
 510    ts--;
 511  }
 512  Delete(ssig);
 513  Delete(dsig);
 514  return match;
 515}
 516
 517/* -----------------------------------------------------------------------------
 518 * Swig_typemap_clear_apply()
 519 *
 520 * %clear directive.   Clears all typemaps for a type (in the current scope only).    
 521 * ----------------------------------------------------------------------------- */
 522
 523/* Multi-argument %clear directive */
 524void Swig_typemap_clear_apply(Parm *parms) {
 525  String *tsig;
 526  Parm *p, *np, *lastp;
 527  int narg = 0;
 528  Hash *tm;
 529  String *name;
 530
 531  /* Create a type signature of the parameters */
 532  tsig = NewStringEmpty();
 533  p = parms;
 534  lastp = 0;
 535  while (p) {
 536    lastp = p;
 537    np = nextSibling(p);
 538    if (np) {
 539      Printf(tsig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name"));
 540      narg++;
 541    }
 542    p = np;
 543  }
 544  tm = get_typemap(tm_scope, Getattr(lastp, "type"));
 545  if (!tm) {
 546    Delete(tsig);
 547    return;
 548  }
 549  name = Getattr(lastp, "name");
 550  if (name) {
 551    tm = Getattr(tm, name);
 552  }
 553  if (tm) {
 554    /* Clear typemaps that match our signature */
 555    Iterator ki, ki2;
 556    char *ctsig = Char(tsig);
 557    for (ki = First(tm); ki.key; ki = Next(ki)) {
 558      char *ckey = Char(ki.key);
 559      if (strncmp(ckey, "tmap:", 5) == 0) {
 560	int na = count_args(ki.key);
 561	if ((na == narg) && strstr(ckey, ctsig)) {
 562	  Hash *h = ki.item;
 563	  for (ki2 = First(h); ki2.key; ki2 = Next(ki2)) {
 564	    Delattr(h, ki2.key);
 565	  }
 566	}
 567      }
 568    }
 569  }
 570  Delete(tsig);
 571}
 572
 573/* Internal function to strip array dimensions. */
 574static SwigType *strip_arrays(SwigType *type) {
 575  SwigType *t;
 576  int ndim;
 577  int i;
 578  t = Copy(type);
 579  ndim = SwigType_array_ndim(t);
 580  for (i = 0; i < ndim; i++) {
 581    SwigType_array_setdim(t, i, "ANY");
 582  }
 583  return t;
 584}
 585
 586/* -----------------------------------------------------------------------------
 587 * Swig_typemap_search()
 588 *
 589 * Search for a typemap match.    Tries to find the most specific typemap
 590 * that includes a 'code' attribute.
 591 * ----------------------------------------------------------------------------- */
 592
 593Hash *Swig_typemap_search(const String_or_char *op, SwigType *type, const String_or_char *name, SwigType **matchtype) {
 594  Hash *result = 0, *tm, *tm1, *tma;
 595  Hash *backup = 0;
 596  SwigType *noarrays = 0;
 597  SwigType *primitive = 0;
 598  SwigType *ctype = 0;
 599  int ts;
 600  int isarray;
 601  const String *cname = 0;
 602  SwigType *unstripped = 0;
 603  String *tmop = tmop_name(op);
 604
 605  if ((name) && Len(name))
 606    cname = name;
 607  ts = tm_scope;
 608
 609  while (ts >= 0) {
 610    ctype = type;
 611    while (ctype) {
 612      /* Try to get an exact type-match */
 613      tm = get_typemap(ts, ctype);
 614      if (tm && cname) {
 615	tm1 = Getattr(tm, cname);
 616	if (tm1) {
 617	  result = Getattr(tm1, tmop);	/* See if there is a type-name match */
 618	  if (result && Getattr(result, "code"))
 619	    goto ret_result;
 620	  if (result)
 621	    backup = result;
 622	}
 623      }
 624      if (tm) {
 625	result = Getattr(tm, tmop);	/* See if there is simply a type match */
 626	if (result && Getattr(result, "code"))
 627	  goto ret_result;
 628	if (result)
 629	  backup = result;
 630      }
 631      isarray = SwigType_isarray(ctype);
 632      if (isarray) {
 633	/* If working with arrays, strip away all of the dimensions and replace with "ANY".
 634	   See if that generates a match */
 635	if (!noarrays) {
 636	  noarrays = strip_arrays(ctype);
 637	}
 638	tma = get_typemap(ts, noarrays);
 639	if (tma && cname) {
 640	  tm1 = Getattr(tma, cname);
 641	  if (tm1) {
 642	    result = Getattr(tm1, tmop);	/* type-name match */
 643	    if (result && Getattr(result, "code"))
 644	      goto ret_result;
 645	    if (result)
 646	      backup = result;
 647	  }
 648	}
 649	if (tma) {
 650	  result = Getattr(tma, tmop);	/* type match */
 651	  if (result && Getattr(result, "code"))
 652	    goto ret_result;
 653	  if (result)
 654	    backup = result;
 655	}
 656	Delete(noarrays);
 657	noarrays = 0;
 658      }
 659
 660      /* No match so far.   If the type is unstripped, we'll strip its
 661         qualifiers and check.   Otherwise, we'll try to resolve a typedef */
 662
 663      if (!unstripped) {
 664	unstripped = ctype;
 665	ctype = SwigType_strip_qualifiers(ctype);
 666	if (!Equal(ctype, unstripped))
 667	  continue;		/* Types are different */
 668	Delete(ctype);
 669	ctype = unstripped;
 670	unstripped = 0;
 671      }
 672      {
 673	String *octype;
 674	if (unstripped) {
 675	  Delete(ctype);
 676	  ctype = unstripped;
 677	  unstripped = 0;
 678	}
 679	octype = ctype;
 680	ctype = SwigType_typedef_resolve(ctype);
 681	if (octype != type)
 682	  Delete(octype);
 683      }
 684    }
 685
 686    /* Hmmm. Well, no match seems to be found at all. See if there is some kind of default mapping */
 687
 688    primitive = SwigType_default(type);
 689    while (primitive) {
 690      tm = get_typemap(ts, primitive);
 691      if (tm && cname) {
 692	tm1 = Getattr(tm, cname);
 693	if (tm1) {
 694	  result = Getattr(tm1, tmop);	/* See if there is a type-name match */
 695	  if (result)
 696	    goto ret_result;
 697	}
 698      }
 699      if (tm) {			/* See if there is simply a type match */
 700	result = Getattr(tm, tmop);
 701	if (result)
 702	  goto ret_result;
 703      }
 704      {
 705	SwigType *nprim = SwigType_default(primitive);
 706	Delete(primitive);
 707	primitive = nprim;
 708      }
 709    }
 710    if (ctype != type) {
 711      Delete(ctype);
 712      ctype = 0;
 713    }
 714    ts--;			/* Hmmm. Nothing found in this scope.  Guess we'll go try another scope */
 715  }
 716  result = backup;
 717
 718ret_result:
 719  if (noarrays)
 720    Delete(noarrays);
 721  if (primitive)
 722    Delete(primitive);
 723  if ((unstripped) && (unstripped != type))
 724    Delete(unstripped);
 725  if (matchtype) {
 726    *matchtype = Copy(ctype);
 727  }
 728  if (type != ctype)
 729    Delete(ctype);
 730  return result;
 731}
 732
 733
 734/* -----------------------------------------------------------------------------
 735 * Swig_typemap_search_multi()
 736 *
 737 * Search for a multi-valued typemap.
 738 * ----------------------------------------------------------------------------- */
 739
 740Hash *Swig_typemap_search_multi(const String_or_char *op, ParmList *parms, int *nmatch) {
 741  SwigType *type;
 742  SwigType *mtype = 0;
 743  String *name;
 744  String *newop;
 745  Hash *tm, *tm1;
 746
 747  if (!parms) {
 748    *nmatch = 0;
 749    return 0;
 750  }
 751  type = Getattr(parms, "type");
 752  name = Getattr(parms, "name");
 753
 754  /* Try to find a match on the first type */
 755  tm = Swig_typemap_search(op, type, name, &mtype);
 756  if (tm) {
 757    if (mtype && SwigType_isarray(mtype)) {
 758      Setattr(parms, "tmap:match", mtype);
 759    }
 760    Delete(mtype);
 761    newop = NewStringf("%s-%s+%s:", op, type, name);
 762    tm1 = Swig_typemap_search_multi(newop, nextSibling(parms), nmatch);
 763    if (tm1)
 764      tm = tm1;
 765    if (Getattr(tm, "code")) {
 766      *(nmatch) = *nmatch + 1;
 767    } else {
 768      tm = 0;
 769    }
 770    Delete(newop);
 771  }
 772  return tm;
 773}
 774
 775
 776/* -----------------------------------------------------------------------------
 777 * typemap_replace_vars()
 778 *
 779 * Replaces typemap variables on a string.  index is the $n variable.
 780 * type and pname are the type and parameter name.
 781 * ----------------------------------------------------------------------------- */
 782
 783static
 784void replace_local_types(ParmList *p, const String *name, const String *rep) {
 785  SwigType *t;
 786  while (p) {
 787    t = Getattr(p, "type");
 788    Replace(t, name, rep, DOH_REPLACE_ANY);
 789    p = nextSibling(p);
 790  }
 791}
 792
 793static
 794int check_locals(ParmList *p, const char *s) {
 795  while (p) {
 796    char *c = GetChar(p, "type");
 797    if (strstr(c, s))
 798      return 1;
 799    p = nextSibling(p);
 800  }
 801  return 0;
 802}
 803
 804static
 805void typemap_replace_vars(String *s, ParmList *locals, SwigType *type, SwigType *rtype, String *pname, String *lname, int index) {
 806  char var[512];
 807  char *varname;
 808  SwigType *ftype;
 809
 810  Replaceall(s, "$typemap", "$TYPEMAP");
 811
 812  ftype = SwigType_typedef_resolve_all(type);
 813
 814  if (!pname)
 815    pname = lname;
 816  {
 817    Parm *p;
 818    int rep = 0;
 819    p = locals;
 820    while (p) {
 821      if (Strchr(Getattr(p, "type"), '$'))
 822	rep = 1;
 823      p = nextSibling(p);
 824    }
 825    if (!rep)
 826      locals = 0;
 827  }
 828
 829  sprintf(var, "$%d_", index);
 830  varname = &var[strlen(var)];
 831
 832  /* If the original datatype was an array. We're going to go through and substitute
 833     its array dimensions */
 834
 835  if (SwigType_isarray(type) || SwigType_isarray(ftype)) {
 836    String *size;
 837    int ndim;
 838    int i;
 839    if (SwigType_array_ndim(type) != SwigType_array_ndim(ftype))
 840      type = ftype;
 841    ndim = SwigType_array_ndim(type);
 842    size = NewStringEmpty();
 843    for (i = 0; i < ndim; i++) {
 844      String *dim = SwigType_array_getdim(type, i);
 845      if (index == 1) {
 846	char t[32];
 847	sprintf(t, "$dim%d", i);
 848	Replace(s, t, dim, DOH_REPLACE_ANY);
 849	replace_local_types(locals, t, dim);
 850      }
 851      sprintf(varname, "dim%d", i);
 852      Replace(s, var, dim, DOH_REPLACE_ANY);
 853      replace_local_types(locals, var, dim);
 854      if (Len(size))
 855	Putc('*', size);
 856      Append(size, dim);
 857      Delete(dim);
 858    }
 859    sprintf(varname, "size");
 860    Replace(s, var, size, DOH_REPLACE_ANY);
 861    replace_local_types(locals, var, size);
 862    Delete(size);
 863  }
 864
 865  /* Parameter name substitution */
 866  if (index == 1) {
 867    Replace(s, "$parmname", pname, DOH_REPLACE_ANY);
 868  }
 869  strcpy(varname, "name");
 870  Replace(s, var, pname, DOH_REPLACE_ANY);
 871
 872  /* Type-related stuff */
 873  {
 874    SwigType *star_type, *amp_type, *base_type, *lex_type;
 875    SwigType *ltype, *star_ltype, *amp_ltype;
 876    String *mangle, *star_mangle, *amp_mangle, *base_mangle, *base_name;
 877    String *descriptor, *star_descriptor, *amp_descriptor;
 878    String *ts;
 879    char *sc;
 880
 881    sc = Char(s);
 882
 883    if (strstr(sc, "type") || check_locals(locals, "type")) {
 884      /* Given type : $type */
 885      ts = SwigType_str(type, 0);
 886      if (index == 1) {
 887	Replace(s, "$type", ts, DOH_REPLACE_ANY);
 888	replace_local_types(locals, "$type", type);
 889      }
 890      strcpy(varname, "type");
 891      Replace(s, var, ts, DOH_REPLACE_ANY);
 892      replace_local_types(locals, var, type);
 893      Delete(ts);
 894      sc = Char(s);
 895    }
 896    if (strstr(sc, "ltype") || check_locals(locals, "ltype")) {
 897      /* Local type:  $ltype */
 898      ltype = SwigType_ltype(type);
 899      ts = SwigType_str(ltype, 0);
 900      if (index == 1) {
 901	Replace(s, "$ltype", ts, DOH_REPLACE_ANY);
 902	replace_local_types(locals, "$ltype", ltype);
 903      }
 904      strcpy(varname, "ltype");
 905      Replace(s, var, ts, DOH_REPLACE_ANY);
 906      replace_local_types(locals, var, ltype);
 907      Delete(ts);
 908      Delete(ltype);
 909      sc = Char(s);
 910    }
 911    if (strstr(sc, "mangle") || strstr(sc, "descriptor")) {
 912      /* Mangled type */
 913
 914      mangle = SwigType_manglestr(type);
 915      if (index == 1)
 916	Replace(s, "$mangle", mangle, DOH_REPLACE_ANY);
 917      strcpy(varname, "mangle");
 918      Replace(s, var, mangle, DOH_REPLACE_ANY);
 919
 920      descriptor = NewStringf("SWIGTYPE%s", mangle);
 921
 922      if (index == 1)
 923	if (Replace(s, "$descriptor", descriptor, DOH_REPLACE_ANY))
 924	  SwigType_remember(type);
 925
 926      strcpy(varname, "descriptor");
 927      if (Replace(s, var, descriptor, DOH_REPLACE_ANY))
 928	SwigType_remember(type);
 929
 930      Delete(descriptor);
 931      Delete(mangle);
 932    }
 933
 934    /* One pointer level removed */
 935    /* This creates variables of the form
 936       $*n_type
 937       $*n_ltype
 938     */
 939
 940    if (SwigType_ispointer(ftype) || (SwigType_isarray(ftype)) || (SwigType_isreference(ftype))) {
 941      if (!(SwigType_isarray(type) || SwigType_ispointer(type) || SwigType_isreference(type))) {
 942	star_type = Copy(ftype);
 943      } else {
 944	star_type = Copy(type);
 945      }
 946      if (!SwigType_isreference(star_type)) {
 947	if (SwigType_isarray(star_type)) {
 948	  SwigType_del_element(star_type);
 949	} else {
 950	  SwigType_del_pointer(star_type);
 951	}
 952	ts = SwigType_str(star_type, 0);
 953	if (index == 1) {
 954	  Replace(s, "$*type", ts, DOH_REPLACE_ANY);
 955	  replace_local_types(locals, "$*type", star_type);
 956	}
 957	sprintf(varname, "$*%d_type", index);
 958	Replace(s, varname, ts, DOH_REPLACE_ANY);
 959	replace_local_types(locals, varname, star_type);
 960	Delete(ts);
 961      } else {
 962	SwigType_del_element(star_type);
 963      }
 964      star_ltype = SwigType_ltype(star_type);
 965      ts = SwigType_str(star_ltype, 0);
 966      if (index == 1) {
 967	Replace(s, "$*ltype", ts, DOH_REPLACE_ANY);
 968	replace_local_types(locals, "$*ltype", star_ltype);
 969      }
 970      sprintf(varname, "$*%d_ltype", index);
 971      Replace(s, varname, ts, DOH_REPLACE_ANY);
 972      replace_local_types(locals, varname, star_ltype);
 973      Delete(ts);
 974      Delete(star_ltype);
 975
 976      star_mangle = SwigType_manglestr(star_type);
 977      if (index == 1)
 978	Replace(s, "$*mangle", star_mangle, DOH_REPLACE_ANY);
 979
 980      sprintf(varname, "$*%d_mangle", index);
 981      Replace(s, varname, star_mangle, DOH_REPLACE_ANY);
 982
 983      star_descriptor = NewStringf("SWIGTYPE%s", star_mangle);
 984      if (index == 1)
 985	if (Replace(s, "$*descriptor", star_descriptor, DOH_REPLACE_ANY))
 986	  SwigType_remember(star_type);
 987      sprintf(varname, "$*%d_descriptor", index);
 988      if (Replace(s, varname, star_descriptor, DOH_REPLACE_ANY))
 989	SwigType_remember(star_type);
 990
 991      Delete(star_descriptor);
 992      Delete(star_mangle);
 993      Delete(star_type);
 994    } else {
 995      /* TODO: Signal error if one of the $* substitutions is
 996         requested */
 997    }
 998    /* One pointer level added */
 999    amp_type = Copy(type);
1000    SwigType_add_pointer(amp_type);
1001    ts = SwigType_str(amp_type, 0);
1002    if (index == 1) {
1003      Replace(s, "$&type", ts, DOH_REPLACE_ANY);
1004      replace_local_types(locals, "$&type", amp_type);
1005    }
1006    sprintf(varname, "$&%d_type", index);
1007    Replace(s, varname, ts, DOH_REPLACE_ANY);
1008    replace_local_types(locals, varname, amp_type);
1009    Delete(ts);
1010
1011    amp_ltype = SwigType_ltype(type);
1012    SwigType_add_pointer(amp_ltype);
1013    ts = SwigType_str(amp_ltype, 0);
1014
1015    if (index == 1) {
1016      Replace(s, "$&ltype", ts, DOH_REPLACE_ANY);
1017      replace_local_types(locals, "$&ltype", amp_ltype);
1018    }
1019    sprintf(varname, "$&%d_ltype", index);
1020    Replace(s, varname, ts, DOH_REPLACE_ANY);
1021    replace_local_types(locals, varname, amp_ltype);
1022    Delete(ts);
1023    Delete(amp_ltype);
1024
1025    amp_mangle = SwigType_manglestr(amp_type);
1026    if (index == 1)
1027      Replace(s, "$&mangle", amp_mangle, DOH_REPLACE_ANY);
1028    sprintf(varname, "$&%d_mangle", index);
1029    Replace(s, varname, amp_mangle, DOH_REPLACE_ANY);
1030
1031    amp_descriptor = NewStringf("SWIGTYPE%s", amp_mangle);
1032    if (index == 1)
1033      if (Replace(s, "$&descriptor", amp_descriptor, DOH_REPLACE_ANY))
1034	SwigType_remember(amp_type);
1035    sprintf(varname, "$&%d_descriptor", index);
1036    if (Replace(s, varname, amp_descriptor, DOH_REPLACE_ANY))
1037      SwigType_remember(amp_type);
1038
1039    Delete(amp_descriptor);
1040    Delete(amp_mangle);
1041    Delete(amp_type);
1042
1043    /* Base type */
1044    if (SwigType_isarray(type)) {
1045      SwigType *bt = Copy(type);
1046      Delete(SwigType_pop_arrays(bt));
1047      base_type = SwigType_str(bt, 0);
1048      Delete(bt);
1049    } else {
1050      base_type = SwigType_base(type);
1051    }
1052
1053    base_name = SwigType_namestr(base_type);
1054    if (index == 1) {
1055      Replace(s, "$basetype", base_name, DOH_REPLACE_ANY);
1056      replace_local_types(locals, "$basetype", base_name);
1057    }
1058    strcpy(varname, "basetype");
1059    Replace(s, var, base_type, DOH_REPLACE_ANY);
1060    replace_local_types(locals, var, base_name);
1061
1062    base_mangle = SwigType_manglestr(base_type);
1063    if (index == 1)
1064      Replace(s, "$basemangle", base_mangle, DOH_REPLACE_ANY);
1065    strcpy(varname, "basemangle");
1066    Replace(s, var, base_mangle, DOH_REPLACE_ANY);
1067    Delete(base_mangle);
1068    Delete(base_type);
1069    Delete(base_name);
1070
1071    lex_type = SwigType_base(rtype);
1072    if (index == 1)
1073      Replace(s, "$lextype", lex_type, DOH_REPLACE_ANY);
1074    strcpy(varname, "lextype");
1075    Replace(s, var, lex_type, DOH_REPLACE_ANY);
1076    Delete(lex_type);
1077  }
1078
1079  /* Replace any $n. with (&n)-> */
1080  {
1081    char temp[64];
1082    sprintf(var, "$%d.", index);
1083    sprintf(temp, "(&$%d)->", index);
1084    Replace(s, var, temp, DOH_REPLACE_ANY);
1085  }
1086
1087  /* Replace the bare $n variable */
1088  sprintf(var, "$%d", index);
1089  Replace(s, var, lname, DOH_REPLACE_ANY);
1090  Delete(ftype);
1091}
1092
1093/* ------------------------------------------------------------------------
1094 * static typemap_locals()
1095 *
1096 * Takes a string, a parameter list and a wrapper function argument and
1097 * creates the local variables.
1098 * ------------------------------------------------------------------------ */
1099
1100static void typemap_locals(DOHString * s, ParmList *l, Wrapper *f, int argnum) {
1101  Parm *p;
1102  char *new_name;
1103
1104  p = l;
1105  while (p) {
1106    SwigType *pt = Getattr(p, "type");
1107    SwigType *at = SwigType_alttype(pt, 1);
1108    String *pn = Getattr(p, "name");
1109    String *value = Getattr(p, "value");
1110    if (at)
1111      pt = at;
1112    if (pn) {
1113      if (Len(pn) > 0) {
1114	String *str;
1115	int isglobal = 0;
1116
1117	str = NewStringEmpty();
1118
1119	if (strncmp(Char(pn), "_global_", 8) == 0) {
1120	  isglobal = 1;
1121	}
1122
1123	/* If the user gave us $type as the name of the local variable, we'll use
1124	   the passed datatype instead */
1125
1126	if ((argnum >= 0) && (!isglobal)) {
1127	  Printf(str, "%s%d", pn, argnum);
1128	} else {
1129	  Append(str, pn);
1130	}
1131	if (isglobal && Wrapper_check_local(f, str)) {
1132	  p = nextSibling(p);
1133	  Delete(str);
1134	  if (at)
1135	    Delete(at);
1136	  continue;
1137	}
1138	if (value) {
1139	  String *pstr = SwigType_str(pt, str);
1140	  new_name = Wrapper_new_localv(f, str, pstr, "=", value, NIL);
1141	  Delete(pstr);
1142	} else {
1143	  String *pstr = SwigType_str(pt, str);
1144	  new_name = Wrapper_new_localv(f, str, pstr, NIL);
1145	  Delete(pstr);
1146	}
1147	if (!isglobal) {
1148	  /* Substitute  */
1149	  Replace(s, pn, new_name, DOH_REPLACE_ID | DOH_REPLACE_NOQUOTE);
1150	}
1151	Delete(str);
1152      }
1153    }
1154    p = nextSibling(p);
1155    if (at)
1156      Delete(at);
1157  }
1158}
1159
1160/* -----------------------------------------------------------------------------
1161 * Swig_typemap_lookup()
1162 *
1163 * Perform a typemap lookup (ala SWIG1.1)
1164 * ----------------------------------------------------------------------------- */
1165
1166String *Swig_typemap_lookup(const String_or_char *op, SwigType *type, String_or_char *pname,
1167			    String_or_char *lname, String_or_char *source, String_or_char *target, Wrapper *f) {
1168  Hash *tm;
1169  String *s = 0;
1170  SwigType *mtype = 0;
1171  ParmList *locals;
1172  tm = Swig_typemap_search(op, type, pname, &mtype);
1173  if (!tm)
1174    return 0;
1175
1176  s = Getattr(tm, "code");
1177  if (!s) {
1178    if (mtype)
1179      Delete(mtype);
1180    return 0;
1181  }
1182
1183
1184  /* Blocked */
1185  if (Cmp(s, "pass") == 0) {
1186    Delete(mtype);
1187    return 0;
1188  }
1189
1190  s = Copy(s);			/* Make a local copy of the typemap code */
1191
1192  locals = Getattr(tm, "locals");
1193  if (locals)
1194    locals = CopyParmList(locals);
1195
1196  /* This is wrong.  It replaces locals in place.   Need to fix this */
1197  if (mtype && SwigType_isarray(mtype)) {
1198    typemap_replace_vars(s, locals, mtype, type, pname, lname, 1);
1199  } else {
1200    typemap_replace_vars(s, locals, type, type, pname, lname, 1);
1201  }
1202
1203  if (locals && f) {
1204    typemap_locals(s, locals, f, -1);
1205  }
1206
1207  replace_embedded_typemap(s);
1208
1209  /* Now perform character replacements */
1210  Replace(s, "$source", source, DOH_REPLACE_ANY);
1211  Replace(s, "$target", target, DOH_REPLACE_ANY);
1212
1213  /*  {
1214     String *tmname = Getattr(tm,"typemap");
1215     if (tmname) Replace(s,"$typemap",tmname, DOH_REPLACE_ANY);
1216     }
1217   */
1218
1219  Replace(s, "$parmname", pname, DOH_REPLACE_ANY);
1220  /*  Replace(s,"$name",pname,DOH_REPLACE_ANY); */
1221
1222  Delete(locals);
1223  Delete(mtype);
1224  return s;
1225}
1226
1227/* -----------------------------------------------------------------------------
1228 * Swig_typemap_lookup_new()
1229 *
1230 * Attach one or more typemaps to a node
1231 * op    - typemap name, eg "out", "newfree"
1232 * node  - the node to attach the typemaps to
1233 * lname -
1234 * f     -
1235 * ----------------------------------------------------------------------------- */
1236
1237String *Swig_typemap_lookup_new(const String_or_char *op, Node *node, const String_or_char *lname, Wrapper *f) {
1238  SwigType *type;
1239  SwigType *mtype = 0;
1240  String *pname;
1241  Hash *tm = 0;
1242  String *s = 0;
1243  String *sdef = 0;
1244  ParmList *locals;
1245  ParmList *kw;
1246  char temp[256];
1247  String *symname;
1248  String *cname = 0;
1249  String *clname = 0;
1250  char *cop = Char(op);
1251  /* special case, we need to check for 'ref' call 
1252     and set the default code 'sdef' */
1253  if (node && Cmp(op, "newfree") == 0) {
1254    sdef = Swig_ref_call(node, lname);
1255  }
1256
1257  type = Getattr(node, "type");
1258  if (!type)
1259    return sdef;
1260
1261  pname = Getattr(node, "name");
1262
1263#if 1
1264  if (pname && node && checkAttribute(node, "kind", "function")) {
1265    /* 
1266       For functions, look qualified names first, such as
1267
1268       struct Foo {
1269       int *foo(int bar)   ->  Foo::foo
1270       };
1271     */
1272    Symtab *st = Getattr(node, "sym:symtab");
1273    String *qsn = st ? Swig_symbol_string_qualify(pname, st) : 0;
1274    if (qsn) {
1275      if (Len(qsn) && !Equal(qsn, pname)) {
1276	tm = Swig_typemap_search(op, type, qsn, &mtype);
1277	if (tm && (!Getattr(tm, "pname") || strstr(Char(Getattr(tm, "type")), "SWIGTYPE"))) {
1278	  tm = 0;
1279	}
1280      }
1281      Delete(qsn);
1282    }
1283  }
1284  if (!tm)
1285#endif
1286    tm = Swig_typemap_search(op, type, pname, &mtype);
1287  if (!tm)
1288    return sdef;
1289
1290  s = Getattr(tm, "code");
1291  if (!s)
1292    return sdef;
1293
1294  /* Empty typemap. No match */
1295  if (Cmp(s, "pass") == 0)
1296    return sdef;
1297
1298  s = Copy(s);			/* Make a local copy of the typemap code */
1299
1300  locals = Getattr(tm, "locals");
1301  if (locals)
1302    locals = CopyParmList(locals);
1303
1304  if (pname) {
1305    if (SwigType_istemplate(pname)) {
1306      cname = SwigType_namestr(pname);
1307      pname = cname;
1308    }
1309  }
1310  if (SwigType_istemplate((char *) lname)) {
1311    clname = SwigType_namestr((char *) lname);
1312    lname = clname;
1313  }
1314
1315  if (mtype && SwigType_isarray(mtype)) {
1316    typemap_replace_vars(s, locals, mtype, type, pname, (char *) lname, 1);
1317  } else {
1318    typemap_replace_vars(s, locals, type, type, pname, (char *) lname, 1);
1319  }
1320
1321  if (locals && f) {
1322    typemap_locals(s, locals, f, -1);
1323  }
1324  replace_embedded_typemap(s);
1325  /*  {
1326     String *tmname = Getattr(tm,"typemap");
1327     if (tmname) Replace(s,"$typemap",tmname, DOH_REPLACE_ANY);
1328     } */
1329
1330  Replace(s, "$name", pname, DOH_REPLACE_ANY);
1331
1332  symname = Getattr(node, "sym:name");
1333  if (symname) {
1334    Replace(s, "$symname", symname, DOH_REPLACE_ANY);
1335  }
1336
1337  Setattr(node, tmop_name(op), s);
1338  if (locals) {
1339    sprintf(temp, "%s:locals", cop);
1340    Setattr(node, tmop_name(temp), locals);
1341    Delete(locals);
1342  }
1343
1344  if (Checkattr(tm, "type", "SWIGTYPE")) {
1345    sprintf(temp, "%s:SWIGTYPE", cop);
1346    Setattr(node, tmop_name(temp), "1");
1347  }
1348
1349  /* Attach kwargs */
1350  kw = Getattr(tm, "kwargs");
1351  while (kw) {
1352    String *value = Copy(Getattr(kw, "value"));
1353    String *type = Getattr(kw, "type");
1354    char *ckwname = Char(Getattr(kw, "name"));
1355    if (type) {
1356      String *mangle = Swig_string_mangle(type);
1357      Append(value, mangle);
1358      Delete(mangle);
1359    }
1360    sprintf(temp, "%s:%s", cop, ckwname);
1361    Setattr(node, tmop_name(temp), value);
1362    Delete(value);
1363    kw = nextSibling(kw);
1364  }
1365
1366  /* Look for warnings */
1367  {
1368    String *w;
1369    sprintf(temp, "%s:warning", cop);
1370    w = Getattr(node, tmop_name(temp));
1371    if (w) {
1372      Swig_warning(0, Getfile(node), Getline(node), "%s\n", w);
1373    }
1374  }
1375
1376  /* Look for code fragments */
1377  {
1378    String *f;
1379    sprintf(temp, "%s:fragment", cop);
1380    f = Getattr(node, tmop_name(temp));
1381    if (f) {
1382      String *fname = Copy(f);
1383      Setfile(fname, Getfile(node));
1384      Setline(fname, Getline(node));
1385      Swig_fragment_emit(fname);
1386      Delete(fname);
1387    }
1388  }
1389
1390  if (cname)
1391    Delete(cname);
1392  if (clname)
1393    Delete(clname);
1394  if (mtype)
1395    Delete(mtype);
1396  if (sdef) {			/* put 'ref' and 'newfree' codes together */
1397    String *p = NewStringf("%s\n%s", sdef, s);
1398    Delete(s);
1399    Delete(sdef);
1400    s = p;
1401  }
1402  return s;
1403}
1404
1405/* -----------------------------------------------------------------------------
1406 * Swig_typemap_attach_kwargs()
1407 *
1408 * If this hash (tm) contains a linked list of parameters under its "kwargs"
1409 * attribute, add keys for each of those named keyword arguments to this
1410 * parameter for later use.
1411 * For example, attach the typemap attributes to p:
1412 * %typemap(in, foo="xyz") ...
1413 * A new attribute called "tmap:in:foo" with value "xyz" is attached to p.
1414 * ----------------------------------------------------------------------------- */
1415
1416void Swig_typemap_attach_kwargs(Hash *tm, const String_or_char *op, Parm *p) {
1417  String *temp = NewStringEmpty();
1418  Parm *kw = Getattr(tm, "kwargs");
1419  while (kw) {
1420    String *value = Copy(Getattr(kw, "value"));
1421    String *type = Getattr(kw, "type");
1422    if (type) {
1423      Hash *v = NewHash();
1424      Setattr(v, "type", type);
1425      Setattr(v, "value", value);
1426      Delete(value);
1427      value = v;
1428    }
1429    Clear(temp);
1430    Printf(temp, "%s:%s", op, Getattr(kw, "name"));
1431    Setattr(p, tmop_name(temp), value);
1432    Delete(value);
1433    kw = nextSibling(kw);
1434  }
1435  Clear(temp);
1436  Printf(temp, "%s:match_type", op);
1437  Setattr(p, tmop_name(temp), Getattr(tm, "type"));
1438  Delete(temp);
1439}
1440
1441/* -----------------------------------------------------------------------------
1442 * Swig_typemap_warn()
1443 *
1444 * If any warning message is attached to this parameter's "tmap:op:warning"
1445 * attribute, print that warning message.
1446 * ----------------------------------------------------------------------------- */
1447
1448static void Swig_typemap_warn(const String_or_char *op, Parm *p) {
1449  String *temp = NewStringf("%s:warning", op);
1450  String *w = Getattr(p, tmop_name(temp));
1451  Delete(temp);
1452  if (w) {
1453    Swig_warning(0, Getfile(p), Getline(p), "%s\n", w);
1454  }
1455}
1456
1457static void Swig_typemap_emit_code_fragments(const String_or_char *op, Parm *p) {
1458  String *temp = NewStringf("%s:fragment", op);
1459  String *f = Getattr(p, tmop_name(temp));
1460  if (f) {
1461    String *fname = Copy(f);
1462    Setfile(fname, Getfile(p));
1463    Setline(fname, Getline(p));
1464    Swig_fragment_emit(fname);
1465    Delete(fname);
1466  }
1467  Delete(temp);
1468}
1469
1470/* -----------------------------------------------------------------------------
1471 * Swig_typemap_attach_parms()
1472 *
1473 * Given a parameter list, this function attaches all of the typemaps for a
1474 * given typemap type
1475 * ----------------------------------------------------------------------------- */
1476
1477String *Swig_typemap_get_option(Hash *tm, String *name) {
1478  Parm *kw = Getattr(tm, "kwargs");
1479  while (kw) {
1480    String *kname = Getattr(kw, "name");
1481    if (Equal(kname, name)) {
1482      return Getattr(kw, "value");
1483    }
1484    kw = nextSibling(kw);
1485  }
1486  return 0;
1487}
1488
1489void Swig_typemap_attach_parms(const String_or_char *op, ParmList *parms, Wrapper *f) {
1490  Parm *p, *firstp;
1491  Hash *tm;
1492  int nmatch = 0;
1493  int i;
1494  String *s;
1495  ParmList *locals;
1496  int argnum = 0;
1497  char temp[256];
1498  char *cop = Char(op);
1499  String *kwmatch = 0;
1500  p = parms;
1501
1502#ifdef SWIG_DEBUG
1503  Printf(stdout, "Swig_typemap_attach_parms:  %s\n", op);
1504#endif
1505
1506  while (p) {
1507    argnum++;
1508    nmatch = 0;
1509#ifdef SWIG_DEBUG
1510    Printf(stdout, "parms:  %s %s %s\n", op, Getattr(p, "name"), Getattr(p, "type"));
1511#endif
1512    tm = Swig_typemap_search_multi(op, p, &nmatch);
1513#ifdef SWIG_DEBUG
1514    if (tm)
1515      Printf(stdout, "found:  %s\n", tm);
1516#endif
1517    if (!tm) {
1518      p = nextSibling(p);
1519      continue;
1520    }
1521    /*
1522       Check if the typemap requires to match the type of another
1523       typemap, for example:
1524
1525       %typemap(in) SWIGTYPE * (int var) {...}
1526       %typemap(freearg,match="in") SWIGTYPE * {if (var$argnum) ...}
1527
1528       here, the freearg typemap requires the "in" typemap to match,
1529       or the 'var$argnum' variable will not exist.
1530     */
1531    kwmatch = Swig_typemap_get_option(tm, "match");
1532    if (kwmatch) {
1533      String *tmname = NewStringf("tmap:%s", kwmatch);
1534      String *tmin = Getattr(p, tmname);
1535      Delete(tmname);
1536#ifdef SWIG_DEBUG
1537      if (tm)
1538	Printf(stdout, "matching:  %s\n", kwmatch);
1539#endif
1540      if (tmin) {
1541	String *tmninp = NewStringf("tmap:%s:numinputs", kwmatch);
1542	String *ninp = Getattr(p, tmninp);
1543	Delete(tmninp);
1544	if (ninp && Equal(ninp, "0")) {
1545	  p = nextSibling(p);
1546	  continue;
1547	} else {
1548	  SwigType *typetm = Getattr(tm, "type");
1549	  String *temp = NewStringf("tmap:%s:match_type", kwmatch);
1550	  SwigType *typein = Getattr(p, temp);
1551	  Delete(temp);
1552	  if (!Equal(typein, typetm)) {
1553	    p = nextSibling(p);
1554	    continue;
1555	  } else {
1556	    int nnmatch;
1557	    Hash *tmapin = Swig_typemap_search_multi(kwmatch, p, &nnmatch);
1558	    String *tmname = Getattr(tm, "pname");
1559	    String *tnname = Getattr(tmapin, "pname");
1560	    if (!(tmname && tnname && Equal(tmname, tnname)) && !(!tmname && !tnname)) {
1561	      p = nextSibling(p);
1562	      continue;
1563	    }
1564	  }
1565
1566	}
1567      } else {
1568	p = nextSibling(p);
1569	continue;
1570      }
1571    }
1572
1573    s = Getattr(tm, "code");
1574    if (!s) {
1575      p = nextSibling(p);
1576      continue;
1577    }
1578#ifdef SWIG_DEBUG
1579    if (s)
1580      Printf(stdout, "code:  %s\n", s);
1581#endif
1582
1583    /* Empty typemap. No match */
1584    if (Cmp(s, "pass") == 0) {
1585      p = nextSibling(p);
1586      continue;
1587    }
1588
1589    s = Copy(s);
1590    locals = Getattr(tm, "locals");
1591    if (locals)
1592      locals = CopyParmList(locals);
1593    firstp = p;
1594#ifdef SWIG_DEBUG
1595    Printf(stdout, "nmatch:  %d\n", nmatch);
1596#endif
1597    for (i = 0; i < nmatch; i++) {
1598      SwigType *type;
1599      String *pname;
1600      String *lname;
1601      SwigType *mtype;
1602
1603
1604      type = Getattr(p, "type");
1605      pname = Getattr(p, "name");
1606      lname = Getattr(p, "lname");
1607      mtype = Getattr(p, "tmap:match");
1608
1609      if (mtype) {
1610	typemap_replace_vars(s, locals, mtype, type, pname, lname, i + 1);
1611	Delattr(p, "tmap:match");
1612      } else {
1613	typemap_replace_vars(s, locals, type, type, pname, lname, i + 1);
1614      }
1615
1616      if (Checkattr(tm, "type", "SWIGTYPE")) {
1617	sprintf(temp, "%s:SWIGTYPE", cop);
1618	Setattr(p, tmop_name(temp), "1");
1619      }
1620      p = nextSibling(p);
1621    }
1622
1623    if (locals && f) {
1624      typemap_locals(s, locals, f, argnum);
1625    }
1626
1627    replace_embedded_typemap(s);
1628
1629    /* Replace the argument number */
1630    sprintf(temp, "%d", argnum);
1631    Replace(s, "$argnum", temp, DOH_REPLACE_ANY);
1632
1633    /* Attach attributes to object */
1634#ifdef SWIG_DEBUG
1635    Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), tmop_name(op), s);
1636#endif
1637    Setattr(firstp, tmop_name(op), s);	/* Code object */
1638
1639    if (locals) {
1640      sprintf(temp, "%s:locals", cop);
1641      Setattr(firstp, tmop_name(temp), locals);
1642      Delete(locals);
1643    }
1644
1645    /* Attach a link to the next parameter.  Needed for multimaps */
1646    sprintf(temp, "%s:next", cop);
1647    Setattr(firstp, tmop_name(temp), p);
1648
1649    /* Attach kwargs */
1650    Swig_typemap_attach_kwargs(tm, op, firstp);
1651
1652    /* Print warnings, if any */
1653    Swig_typemap_warn(op, firstp);
1654
1655    /* Look for code fragments */
1656    Swig_typemap_emit_code_fragments(op, firstp);
1657
1658    /* increase argnum to consider numinputs */
1659    argnum += nmatch - 1;
1660    Delete(s);
1661#ifdef SWIG_DEBUG
1662    Printf(stdout, "res: %s %s %s\n", Getattr(firstp, "name"), tmop_name(op), Getattr(firstp, tmop_name(op)));
1663#endif
1664
1665  }
1666#ifdef SWIG_DEBUG
1667  Printf(stdout, "Swig_typemap_attach_parms: end\n");
1668#endif
1669
1670}
1671
1672/* -----------------------------------------------------------------------------
1673 * split_embedded()
1674 *
1675 * This function replaces the special variable $typemap(....) with typemap
1676 * code.  The general form of $typemap is as follows:
1677 *
1678 *   $TYPEMAP(method, $var1=value, $var2=value, $var3=value,...)
1679 *
1680 * For example:
1681 *
1682 *   $TYPEMAP(in, $1=int x, $input=y, ...)
1683 *
1684 * Note: this was added as an experiment and could be removed
1685 * ----------------------------------------------------------------------------- */
1686
1687/* Splits the arguments of an embedded typemap */
1688static List *split_embedded(String *s) {
1689  List *args = 0;
1690  char *c, *start;
1691  int level = 0;
1692  int leading = 1;
1693  args = NewList();
1694
1695  c = strchr(Char(s), '(');
1696  c++;
1697
1698  start = c;
1699  while (*c) {
1700    if (*c == '\"') {
1701      c++;
1702      while (*c) {
1703	if (*c == '\\') {
1704	  c++;
1705	} else {
1706	  if (*c == '\"')
1707	    break;
1708	}
1709	c++;
1710      }
1711    }
1712    if ((level == 0) && ((*c == ',') || (*c == ')'))) {
1713      String *tmp = NewStringWithSize(start, c - start);
1714      Append(args, tmp);
1715      Delete(tmp);
1716      start = c + 1;
1717      leading = 1;
1718      if (*c == ')')
1719	break;
1720      c++;
1721      continue;
1722    }
1723    if (*c == '(')
1724      level++;
1725    if (*c == ')')
1726      level--;
1727    if (isspace((int) *c) && leading)
1728      start++;
1729    if (!isspace((int) *c))
1730      leading = 0;
1731    c++;
1732  }
1733  return args;
1734}
1735
1736static void split_var(String *s, String **name, String **value) {
1737  char *eq;
1738  char *c;
1739
1740  eq = strchr(Char(s), '=');
1741  if (!eq) {
1742    *name = 0;
1743    *value = 0;
1744    return;
1745  }
1746  c = Char(s);
1747  *name = NewStringWithSize(c, eq - c);
1748
1749  /* Look for $n variables */
1750  if (isdigit((int) *(c))) {
1751    /* Parse the value as a type */
1752    String *v;
1753    Parm *p;
1754    v = NewString(eq + 1);
1755    p = Swig_cparse_parm(v);
1756    Delete(v);
1757    *value = p;
1758  } else {
1759    *value = NewString(eq + 1);
1760  }
1761}
1762
1763static void replace_embedded_typemap(String *s) {
1764  char *start = 0;
1765  while ((start = strstr(Char(s), "$TYPEMAP("))) {
1766
1767    /* Gather the argument */
1768    char *end = 0, *c;
1769    int level = 0;
1770    String *tmp;
1771    c = start;
1772    while (*c) {
1773      if (*c == '(')
1774	level++;
1775      if (*c == ')') {
1776	level--;
1777	if (level == 0) {
1778	  end = c + 1;
1779	  break;
1780	}
1781      }
1782      c++;
1783    }
1784    if (end) {
1785      tmp = NewStringWithSize(start, (end - start));
1786    } else {
1787      tmp = 0;
1788    }
1789
1790    /* Got a substitution. Split it apart into pieces */
1791    if (tmp) {
1792      List *l;
1793      Hash *vars;
1794      String *method;
1795      int i, ilen;
1796
1797      l = split_embedded(tmp);
1798      vars = NewHash();
1799      ilen = Len(l);
1800      for (i = 1; i < ilen; i++) {
1801	String *n, *v;
1802	split_var(Getitem(l, i), &n, &v);
1803	if (n && v) {
1804	  Insert(n, 0, "$");
1805	  Setattr(vars, n, v);
1806	}
1807	Delete(n);
1808	Delete(v);
1809      }
1810
1811      method = Getitem(l, 0);
1812      /* Generate the parameter list for matching typemaps */
1813
1814      {
1815	Parm *p = 0;
1816	Parm *first = 0;
1817	char temp[32];
1818	int n = 1;
1819	while (1) {
1820	  Hash *v;
1821	  sprintf(temp, "$%d", n);
1822	  v = Getattr(vars, temp);
1823	  if (v) {
1824	    if (p) {
1825	      set_nextSibling(p, v);
1826	      set_previousSibling(v, p);
1827	    }
1828	    p = v;
1829	    Setattr(p, "lname", Getattr(p, "name"));
1830	    if (Getattr(p, "value")) {
1831	      Setattr(p, "name", Getattr(p, "value"));
1832	    }
1833	    if (!first)
1834	      first = p;
1835	    DohIncref(p);
1836	    Delattr(vars, temp);
1837	  } else {
1838	    break;
1839	  }
1840	  n++;
1841	}
1842	/* Perform a typemap search */
1843	if (first) {
1844#ifdef SWIG_DEBUG
1845	  Printf(stdout, "Swig_typemap_attach_parms:  embedded\n");
1846#endif
1847	  Swig_typemap_attach_parms(method, first, 0);
1848	  {
1849	    String *tm;
1850	    int match = 0;
1851	    char attr[64];
1852	    sprintf(attr, "tmap:%s", Char(method));
1853
1854	    /* Look for the typemap code */
1855	    tm = Getattr(first, attr);
1856	    if (tm) {
1857	      sprintf(attr, "tmap:%s:next", Char(method));
1858	      if (!Getattr(first, attr)) {
1859		/* Should be no more matches.  Hack??? */
1860		/* Replace all of the remaining variables */
1861		Iterator ki;
1862		for (ki = First(vars); ki.key; ki = Next(ki)) {
1863		  Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY);
1864		}
1865		/* Do the replacement */
1866		Replace(s, tmp, tm, DOH_REPLACE_ANY);
1867		Delete(tm);
1868		match = 1;
1869	      }
1870	    }
1871	    if (!match) {
1872	      Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", tmp);
1873	    }
1874	  }
1875	}
1876      }
1877      Replace(s, tmp, "<embedded typemap>", DOH_REPLACE_ANY);
1878      Delete(vars);
1879      Delete(tmp);
1880      Delete(l);
1881    }
1882  }
1883}
1884
1885/* -----------------------------------------------------------------------------
1886 * Swig_typemap_debug()
1887 * ----------------------------------------------------------------------------- */
1888
1889void Swig_typemap_debug() {
1890  int ts;
1891  Printf(stdout, "---[ typemaps ]--------------------------------------------------------------\n");
1892
1893  ts = tm_scope;
1894  while (ts >= 0) {
1895    Printf(stdout, "::: scope %d\n\n", ts);
1896    Printf(stdout, "%s\n", typemaps[ts]);
1897    ts--;
1898  }
1899  Printf(stdout, "-----------------------------------------------------------------------------\n");
1900}