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, "$<ype", ts, DOH_REPLACE_ANY); 1026 replace_local_types(locals, "$<ype", 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