PageRenderTime 210ms CodeModel.GetById 22ms app.highlight 171ms RepoModel.GetById 2ms app.codeStats 0ms

/tags/rel-1-3-25/SWIG/Source/Swig/typemap.c

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