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