]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxSWIG/SWIG/typemap.cxx
Since I have made several changes to SWIG over the years to accomodate
[wxWidgets.git] / wxPython / wxSWIG / SWIG / typemap.cxx
1 /*******************************************************************************
2 * Simplified Wrapper and Interface Generator (SWIG)
3 *
4 * Author : David Beazley
5 *
6 * Department of Computer Science
7 * University of Chicago
8 * 1100 E 58th Street
9 * Chicago, IL 60637
10 * beazley@cs.uchicago.edu
11 *
12 * Please read the file LICENSE for the copyright and terms by which SWIG
13 * can be used and distributed.
14 *******************************************************************************/
15
16 #include "internal.h"
17
18 #include <limits.h>
19
20 // ------------------------------------------------------------------------
21 // $Header$
22 //
23 // typemap.cxx
24 //
25 // This file provides universal support for typemaps. Typemaps are created
26 // using the following SWIG command in an interface file:
27 //
28 // %typemap(lang,operation) type { code } Make a new typemap
29 // %typemap(lang,operation) type; Clears any previous typemap
30 //
31 // lang is an identifier indicating the target language. The typemap will
32 // simply be ignored if its for a different language. The code is the
33 // corresponding C code for the mapping. An example typemap might look
34 // like this :
35 //
36 // %typemap(tcl,get) double {
37 // $target = atof($source);
38 // }
39 // %typemap(tcl,set) double {
40 // sprintf($target,"%0.17f",$source);
41 // }
42 //
43 // The variables $target and $source should be used in any type-mappings.
44 // Additional local variables can be created, but this should be done
45 // by enclosing the entire code fragment in an extra set of braces.
46 //
47 // The C++ API to the type-mapper is as follows :
48 //
49 // void typemap_register(char *op, char *lang, DataType *type, char *pname, String &getcode, ParmList *args)
50 // char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source, char *target);
51 // void typemap_clear(char *op, char *lang, DataType *type, char *pname);
52 //
53 // The lookup functions return a character string corresponding to the type-mapping
54 // code or NULL if none exists. The string return will have the source and target
55 // strings substituted for the strings "$source" and "$target" in the type-mapping code.
56 //
57 // (2/19/97) This module has been extended somewhat to provide generic mappings
58 // of other parts of the code--most notably exceptions.
59 //
60 // void fragment_register(char *op, char *lang, String &code)
61 // char fragment_lookup(char *op, char *lang, int age);
62 // char fragment_clear(char *op, char *lang);
63 //
64 // ------------------------------------------------------------------------
65
66 // Structure for holding a typemap
67
68 struct TypeMap {
69 char *lang;
70 DataType *type;
71 String code;
72 int first;
73 int last;
74 TypeMap *next;
75 TypeMap *previous; // Previously defined typemap (if any)
76 ParmList *args; // Local variables (if any)
77
78 TypeMap(char *l, DataType *t, String &c, ParmList *p = 0) {
79 lang = copy_string(l);
80 type = new DataType(t);
81 code << c;
82 first = type_id;
83 last = INT_MAX;
84 next = 0;
85 previous = 0;
86 if (p) {
87 args = new ParmList(p);
88 } else {
89 args = 0;
90 }
91 }
92 TypeMap(char *l, DataType *t, char *c, ParmList *p = 0) {
93 lang = copy_string(l);
94 type = new DataType(t);
95 code << c;
96 first = type_id;
97 last = INT_MAX;
98 next = 0;
99 previous = 0;
100 if (p) {
101 args = new ParmList(p);
102 } else {
103 args = 0;
104 }
105 }
106 TypeMap(char *l, char *c) {
107 lang = copy_string(l);
108 type = 0;
109 code << c;
110 first = type_id;
111 last = INT_MAX;
112 next = 0;
113 previous = 0;
114 args = 0;
115 }
116 TypeMap(TypeMap *t) {
117 lang = copy_string(t->lang);
118 type = new DataType(t->type);
119 code << t->code;
120 first = type_id;
121 last = INT_MAX;
122 next = 0;
123 previous = t->previous;
124 if (args) {
125 args = new ParmList(args);
126 } else {
127 args = 0;
128 }
129 }
130 };
131
132 // Hash tables for storing type-mappings
133
134 static Hash typemap_hash;
135
136 // Structure for holding "applications of a typemap"
137
138 struct TmMethod {
139 char *name; // Typemap name;
140 DataType *type; // Typemap type
141 TmMethod *next; // Next method
142 TmMethod(char *n, DataType *t, TmMethod *m = 0) {
143 if (n) name = copy_string(n);
144 else name = 0;
145 if (t) {
146 type = new DataType(t);
147 } else {
148 type = 0;
149 }
150 next = m;
151 }
152 };
153
154 // Hash table for storing applications of a datatype
155
156 static Hash application_hash;
157
158 // ------------------------------------------------------------------------
159 // void typemap_apply(DataType *tm_type, char *tm_name, DataType *type, char *pname)
160 //
161 // Attempts to apply a typemap given by (tm_type,tm_name) to (type,pname)
162 // Called by the %apply directive.
163 // ------------------------------------------------------------------------
164
165 void typemap_apply(DataType *tm_type, char *tm_name, DataType *type, char *pname) {
166 TmMethod *m,*m1;
167 char temp[512];
168
169 // Form the application name
170 if (!pname) pname = "";
171 sprintf(temp,"%s$%s",type->print_type(),pname);
172
173 // See if there is a method already defined
174
175 m = (TmMethod *) application_hash.lookup(temp);
176
177 if (!m) {
178 m = new TmMethod(temp,type,0);
179 application_hash.add(temp,m);
180 }
181
182 // Check to see if an array typemap has been applied to a non-array type
183
184 if ((tm_type->arraystr) && (!type->arraystr)) {
185 fprintf(stderr,"%s:%d: Warning. Array typemap has been applied to a non-array type.\n",
186 input_file,line_number);
187 }
188
189 // If both are arrays, make sure they have the same dimension
190
191 if ((tm_type->arraystr) && (type->arraystr)) {
192 char s[128],*t;
193 if (tm_type->array_dimensions() != type->array_dimensions()) {
194 fprintf(stderr,"%s:%d: Warning. Array types have different number of dimensions.\n",
195 input_file,line_number);
196 } else {
197 for (int i = 0; i < tm_type->array_dimensions(); i++) {
198 strcpy(s,tm_type->get_dimension(i));
199 t = type->get_dimension(i);
200 if (strcmp(s,"ANY") != 0) {
201 if (strcmp(s,t))
202 fprintf(stderr,"%s:%d: Warning. Array typemap applied to an array of different size.\n",
203 input_file, line_number);
204 }
205 }
206 }
207 }
208
209 // Add a new mapping corresponding to the typemap
210
211 m1 = new TmMethod(tm_name,tm_type,m->next);
212 m->next = m1;
213
214 }
215 // ------------------------------------------------------------------------
216 // void typemap_clear_apply(DataType *type, char *pname)
217 //
218 // Clears the application of a typemap.
219 // Called by the %clear directive.
220 // ------------------------------------------------------------------------
221
222 void typemap_clear_apply(DataType *type, char *pname) {
223 char temp[512];
224 if (!pname) pname = "";
225 sprintf(temp,"%s$%s", type->print_type(), pname);
226 application_hash.remove(temp);
227 }
228
229 // ------------------------------------------------------------------------
230 // char *typemap_string(char *lang, DataType *type, char *pname, char *ary, char *suffix)
231 //
232 // Produces a character string corresponding to a lang, datatype, and
233 // method. This string is used as the key for our typemap hash table.
234 // ------------------------------------------------------------------------
235
236 static char *typemap_string(char *lang, DataType *type, char *pname, char *ary, char *suffix) {
237 static String str;
238
239 int old_status;
240 old_status = type->status;
241 type->status = 0;
242 str = "";
243
244 if (ary)
245 str << lang << type->print_type() << pname << ary << suffix;
246 else
247 str << lang << type->print_type() << pname << suffix;
248
249 type->status = old_status;
250 return str;
251 }
252
253 // ------------------------------------------------------------------------
254 // void typemap_register(char *op, char *lang, DataType *type, char *pname,
255 // char *getcode, ParmList *args)
256 //
257 // Register a new mapping with the type-mapper.
258 // ------------------------------------------------------------------------
259
260 void typemap_register(char *op, char *lang, DataType *type, char *pname,
261 char *getcode, ParmList *args) {
262
263 char *key;
264 TypeMap *tm,*tm_old;
265 char temp[256];
266 int is_default = 0;
267
268 // printf("Registering : %s %s %s %s\n%s\n", op, lang, type->print_type(), pname, getcode);
269
270
271 tm = new TypeMap(lang,type,getcode,args);
272 // If this is a default typemap, downgrade the type!
273
274 if (strcmp(pname,"SWIG_DEFAULT_TYPE") == 0) {
275 tm->type->primitive();
276 is_default = 1;
277 }
278
279 key = typemap_string(lang,tm->type,pname,tm->type->arraystr, op);
280
281 // Get any previous setting of the typemap
282
283 tm_old = (TypeMap *) typemap_hash.lookup(key);
284
285 if (tm_old) {
286
287 // Perform a chaining operation, but only if the last typemap is
288 // active.
289
290 if (type_id < tm_old->last) {
291 sprintf(temp,"$%s",op);
292 tm->code.replace(temp,tm_old->code);
293 }
294
295 // If found, we need to attach the old version to the new one
296
297 tm->previous = tm_old;
298 tm->next = tm_old;
299 tm_old->last = type_id;
300
301 // Remove the old one from the hash
302
303 typemap_hash.remove(key);
304 }
305
306 // Add new typemap to the hash table
307 typemap_hash.add(key,(void *) tm);
308
309 // Now try to perform default chaining operation (if available)
310 // if (!is_default) {
311 // sprintf(temp,"$%s",op);
312 // if (strstr(tm->code,temp)) {
313 // tm->code.replace(temp,typemap_resolve_default(op,lang,type));
314 // }
315 // }
316
317 // Just a sanity check to make sure args look okay.
318
319 if (args) {
320 Parm *p;
321 p = tm->args->get_first();
322 while (p) {
323 if (p->name) {
324 // printf(" %s %s\n", p->t->print_type(),p->name);
325 } else {
326 fprintf(stderr,"%s:%d: Typemap error. Local variables must have a name\n",
327 input_file, line_number);
328 }
329 // If a call by reference thingy, fix that
330 if (p->call_type & CALL_REFERENCE) {
331 p->t->is_pointer--;
332 p->call_type = 0;
333 }
334 p = tm->args->get_next();
335 }
336 }
337 }
338
339 // ------------------------------------------------------------------------
340 // void typemap_register(char *op, char *lang, char *type, char *pname,
341 // char *getcode, ParmList *args)
342 //
343 // Register a new mapping with the type-mapper. Special version that uses a
344 // string instead of a datatype.
345 // ------------------------------------------------------------------------
346
347 void typemap_register(char *op, char *lang, char *type, char *pname,
348 char *getcode, ParmList *args) {
349 DataType temp;
350 strcpy(temp.name,type);
351 temp.is_pointer = 0;
352 temp.type = T_USER;
353 typemap_register(op,lang,&temp,pname,getcode,args);
354 }
355
356
357 // ------------------------------------------------------------------------
358 // void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr,
359 // char *code, ParmList *args)
360 //
361 // Registers a default typemap with the system using numerical type codes.
362 // type is the numerical code, ptr is the level of indirection.
363 // ------------------------------------------------------------------------
364
365 void typemap_register_default(char *op, char *lang, int type, int ptr, char *arraystr,
366 char *code, ParmList *args) {
367
368 DataType *t = new DataType(type);
369
370 // Create a raw datatype from the arguments
371
372 t->is_pointer = ptr;
373 t->arraystr = copy_string(arraystr);
374
375 // Now, go register this as a default type
376
377 typemap_register(op,lang,t,"SWIG_DEFAULT_TYPE",code,args);
378 delete t;
379 }
380
381
382 // ------------------------------------------------------------------------
383 // static TypeMap *typemap_search(char *key, int id)
384 //
385 // An internal function for searching for a particular typemap given
386 // a key value and datatype id.
387 //
388 // Basically this checks the hash table and then checks the id against
389 // first and last values, looking for a match. This is to properly
390 // handle scoping problems.
391 // ------------------------------------------------------------------------
392
393 TypeMap *typemap_search(char *key, int id) {
394
395 TypeMap *tm;
396
397 tm = (TypeMap *) typemap_hash.lookup(key);
398 while (tm) {
399 if ((id >= tm->first) && (id < tm->last)) return tm;
400 else tm = tm->next;
401 }
402 return tm;
403 }
404
405 // ------------------------------------------------------------------------
406 // TypeMap *typemap_search_array(char *op, char *lang, DataType *type, char *pname, String &str)
407 //
408 // Performs a typemap lookup on an array type. This is abit complicated
409 // because we need to look for ANY tags specifying that any array dimension
410 // is valid. The resulting code will be placed in str with dimension variables
411 // substituted.
412 // ------------------------------------------------------------------------
413
414 TypeMap *typemap_search_array(char *op, char *lang, DataType *type, char *pname, String &str) {
415 char *origarr = type->arraystr;
416 char *key;
417 int ndim,i,j,k,n;
418 TypeMap *tm;
419 char temp[10];
420
421 if (!type->arraystr) return 0;
422
423 // First check to see if exactly this array has been mapped
424
425 key = typemap_string(lang,type,pname,type->arraystr,op);
426 tm = typemap_search(key,type->id);
427
428 // Check for unnamed array of specific dimensions
429 if (!tm) {
430 key = typemap_string(lang,type,"",type->arraystr,op);
431 tm = typemap_search(key,type->id);
432 }
433
434 if (!tm) {
435 // We're going to go search for matches with the ANY tag
436 String tempastr;
437 ndim = type->array_dimensions(); // Get number of dimensions
438 j = (1 << ndim) - 1; // Status bits
439 for (i = 0; i < (1 << ndim); i++) {
440 // Form an array string
441 tempastr = "";
442 k = j;
443 for (n = 0; n < ndim; n++) {
444 if (k & 1) {
445 tempastr << "[" << type->get_dimension(n) << "]";
446 } else {
447 tempastr << "[ANY]";
448 }
449 k = k >> 1;
450 }
451 // printf("checking (%s) : %s\n",origarr,tempastr.get());
452 type->arraystr = tempastr.get();
453 key = typemap_string(lang,type,pname,type->arraystr,op);
454 tm = typemap_search(key,type->id);
455 if (!tm) {
456 key = typemap_string(lang,type,"",type->arraystr,op);
457 tm = typemap_search(key,type->id);
458 }
459 type->arraystr = origarr;
460 if (tm) break;
461 j--;
462 }
463 }
464
465 if (tm) {
466 str << tm->code;
467 ndim = type->array_dimensions();
468 for (i = 0; i < ndim; i++) {
469 sprintf(temp,"$dim%d",i);
470 str.replace(temp,type->get_dimension(i));
471 }
472 }
473 return tm;
474 }
475
476 // ------------------------------------------------------------------------
477 // static typemap_locals(Datatype *t, char *pname, String &s, ParmList *l, WrapperFunction &f)
478 //
479 // Takes a string, a parameter list and a wrapper function argument and
480 // starts creating local variables.
481 //
482 // Substitutes locals in the string with actual values used.
483 // ------------------------------------------------------------------------
484
485 static void typemap_locals(DataType *t, char *pname, String &s, ParmList *l, WrapperFunction &f) {
486 Parm *p;
487 char *new_name;
488
489 p = l->get_first();
490 while (p) {
491 if (p->name) {
492 if (strlen(p->name) > 0) {
493 String str;
494 DataType *tt;
495
496 // If the user gave us $type as the name of the local variable, we'll use
497 // the passed datatype instead
498
499 if (strcmp(p->t->name,"$type")==0 || strcmp(p->t->name,"$basetype")==0) {
500 tt = t;
501 } else {
502 tt = p->t;
503 }
504
505 // Have a real parameter here
506 if (tt->arraystr) {
507 tt->is_pointer--;
508 str << p->name << tt->arraystr;
509 }
510 else {
511 str << p->name;
512 }
513
514 // Substitute parameter names
515 str.replace("$arg",pname);
516 if (strcmp(p->t->name,"$basetype")==0) {
517 // use $basetype
518 char temp_ip = tt->is_pointer;
519 char temp_ip1 = tt->implicit_ptr;
520 tt->is_pointer = 0;
521 tt->implicit_ptr = 0;
522 new_name = f.new_local(tt->print_type(),str);
523 tt->is_pointer = temp_ip;
524 tt->implicit_ptr = temp_ip1;
525 }
526 else
527 new_name = f.new_local(tt->print_full(),str);
528
529 if (tt->arraystr) tt->is_pointer++;
530 // Substitute
531 s.replaceid(p->name,new_name);
532 }
533 }
534 p = l->get_next();
535 }
536 // If the original datatype was an array. We're going to go through and substitute
537 // it's array dimensions
538
539 if (t->arraystr) {
540 char temp[10];
541 for (int i = 0; i < t->array_dimensions(); i++) {
542 sprintf(temp,"$dim%d",i);
543 f.locals.replace(temp,t->get_dimension(i));
544 }
545 }
546
547 }
548
549 // ------------------------------------------------------------------------
550 // char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source,
551 // char *target, WrapperFunction *f)
552 //
553 // Looks up a "get" function in the type-map and returns a character string
554 // containing the appropriate translation code.
555 //
556 // op is string code for type of mapping
557 // lang is the target language string
558 // type is the datatype
559 // pname is an optional parameter name
560 // source is a string with the source variable
561 // target is a string containing the target value
562 // f is a wrapper function object (optional)
563 //
564 // Returns NULL if no mapping is found.
565 //
566 // Typemaps follow a few rules regarding naming and C pointers by checking
567 // declarations in this order.
568 //
569 // 1. type name [] - A named array (most specific)
570 // 2. type name - Named argument
571 // 3. type [] - Type with array
572 // 4. type - Ordinary type
573 //
574 // Array checking is only made if the datatype actally has an array specifier
575 //
576 // Array checking uses a special token "ANY" that indicates that any
577 // dimension will match. Since we are passed a real datatype here, we
578 // need to hack this a special case.
579 //
580 // Array dimensions are substituted into the variables $dim1, $dim2,...,$dim9
581 // ------------------------------------------------------------------------
582
583 static DataType *realtype; // This is a gross hack
584 static char *realname = 0; // Real parameter name
585
586 char *typemap_lookup_internal(char *op, char *lang, DataType *type, char *pname, char *source,
587 char *target, WrapperFunction *f) {
588 static String str;
589 char *key = 0;
590 TypeMap *tm = 0;
591
592 if (!lang) {
593 return 0;
594 }
595
596 // First check for named array
597 str = "";
598 tm = typemap_search_array(op,lang,type,pname,str);
599
600 // Check for named argument
601 if (!tm) {
602 key = typemap_string(lang,type,pname,0,op);
603 tm = typemap_search(key,type->id);
604 if (tm)
605 str << tm->code;
606 }
607
608 // Check for unnamed type
609 if (!tm) {
610 key = typemap_string(lang,type,"",0,op);
611 tm = typemap_search(key,type->id);
612 if (tm)
613 str << tm->code;
614 }
615 if (!tm) return 0;
616
617 // Now perform character replacements
618
619 str.replace("$source",source);
620 str.replace("$target",target);
621 str.replace("$type", realtype->print_type());
622 if (realname) {
623 str.replace("$parmname", realname);
624 } else {
625 str.replace("$parmname","");
626 }
627 // Print base type (without any pointers)
628 {
629 char temp_ip = realtype->is_pointer;
630 char temp_ip1 = realtype->implicit_ptr;
631 realtype->is_pointer = 0;
632 realtype->implicit_ptr = 0;
633 char *bt = realtype->print_type();
634 if (bt[strlen(bt)-1] == ' ')
635 bt[strlen(bt)-1] = 0;
636 str.replace("$basetype",bt);
637 str.replace("$basemangle",realtype->print_mangle());
638 realtype->is_pointer = temp_ip;
639 realtype->implicit_ptr = temp_ip1;
640 }
641
642 str.replace("$mangle",realtype->print_mangle());
643
644 // If there were locals and a wrapper function, replace
645 if ((tm->args) && f) {
646 typemap_locals(realtype, pname, str,tm->args,*f);
647 }
648
649 // If there were locals and no wrapper function, print a warning
650 if ((tm->args) && !f) {
651 if (!pname) pname = "";
652 fprintf(stderr,"%s:%d: Warning. '%%typemap(%s,%s) %s %s' being applied with ignored locals.\n",
653 input_file, line_number, lang,op, type->print_type(), pname);
654 }
655
656 // Return character string
657
658 return str;
659 }
660
661 // ----------------------------------------------------------
662 // Real function call that takes care of application mappings
663 // ----------------------------------------------------------
664
665 char *typemap_lookup(char *op, char *lang, DataType *type, char *pname, char *source,
666 char *target, WrapperFunction *f) {
667 TmMethod *m;
668 char temp[512];
669 char *result;
670 char *ppname;
671 char *tstr;
672
673 realtype = type; // The other half of the gross hack
674 realname = pname;
675
676 // Try to apply typemap right away
677
678 result = typemap_lookup_internal(op,lang,type,pname,source,target,f);
679
680 // If not found, try to pick up anything that might have been
681 // specified with %apply
682
683 if ((!result) && (pname)) {
684 int drop_pointer = 0;
685 ppname = pname;
686 if (!ppname) ppname = "";
687
688 // The idea : We're going to cycle through applications and
689 // drop pointers off until we get a match.
690
691 while (drop_pointer <= (type->is_pointer - type->implicit_ptr)) {
692 type->is_pointer -= drop_pointer;
693 tstr = type->print_type();
694 sprintf(temp,"%s$%s",tstr,ppname);
695 // No mapping was found. See if the name has been mapped with %apply
696 m = (TmMethod *) application_hash.lookup(temp);
697 if (!m) {
698 sprintf(temp,"%s$",tstr);
699 m = (TmMethod *) application_hash.lookup(temp);
700 }
701 if (m) {
702 m = m->next;
703 while (m) {
704 char *oldary = 0;
705 static String newarray;
706 if (*(m->name)) ppname = m->name;
707 else ppname = pname;
708 m->type->is_pointer += drop_pointer;
709
710 // Copy old array string (just in case)
711
712 oldary = m->type->arraystr;
713
714 // If the mapping type is an array and has the 'ANY' keyword, we
715 // have to play some magic
716
717 if ((m->type->arraystr) && (type->arraystr)) {
718 // Build up the new array string
719 newarray = "";
720 for (int n = 0; n < m->type->array_dimensions(); n++) {
721 char *d = m->type->get_dimension(n);
722 if (strcmp(d,"ANY") == 0) {
723 newarray << "[" << type->get_dimension(n) << "]";
724 } else {
725 newarray << "[" << d << "]";
726 }
727 }
728 m->type->arraystr = newarray.get();
729 } else if (type->arraystr) {
730 // If an array string is available for the current datatype,
731 // make it available.
732 m->type->arraystr = type->arraystr;
733 }
734 result = typemap_lookup_internal(op,lang,m->type,ppname,source,target,f);
735 m->type->arraystr = oldary;
736 m->type->is_pointer -= drop_pointer;
737 if (result) {
738 type->is_pointer += drop_pointer;
739 return result;
740 }
741 m = m->next;
742 }
743 }
744 type->is_pointer += drop_pointer;
745 drop_pointer++;
746 }
747 }
748 // Still no idea, try to find a default typemap
749
750 if (!result) {
751 DataType *t = new DataType(type);
752 t->primitive(); // Knock it down to its basic type
753 result = typemap_lookup_internal(op,lang,t,"SWIG_DEFAULT_TYPE",source,target,f);
754 if (result) {
755 delete t;
756 return result;
757 }
758 if ((t->type == T_USER) || (t->is_pointer)) {
759 if ((t->type == T_CHAR) && (t->is_pointer == 1)) return 0;
760
761 // Still no result, go even more primitive
762 t->type = T_USER;
763 t->is_pointer = 1;
764 if (t->arraystr) delete [] t->arraystr;
765 t->arraystr = 0;
766 t->primitive();
767 result = typemap_lookup_internal(op,lang,t,"SWIG_DEFAULT_TYPE",source,target,f);
768 }
769 delete t;
770 }
771 return result;
772 }
773
774 // ----------------------------------------------------------------------------
775 // char *typemap_check(char *op, char *lang, DataType *type, char *pname)
776 //
777 // Checks to see if there is a typemap. Returns typemap string if found, NULL
778 // if not.
779 // ----------------------------------------------------------------------------
780
781 char *typemap_check_internal(char *op, char *lang, DataType *type, char *pname) {
782 static String str;
783 char *key = 0;
784 TypeMap *tm = 0;
785
786 if (!lang) {
787 return 0;
788 }
789 // First check for named array
790 str = "";
791 tm = typemap_search_array(op,lang,type,pname,str);
792
793 // First check for named array
794 //
795 // if (type->arraystr) {
796 // key = typemap_string(lang,type,pname,type->arraystr,op);
797 // tm = typemap_search(key,type->id);
798 // }
799
800 // Check for named argument
801 if (!tm) {
802 key = typemap_string(lang,type,pname,0,op);
803 tm = typemap_search(key,type->id);
804 }
805
806 // Check for unnamed array
807 if ((!tm) && (type->arraystr)) {
808 key = typemap_string(lang,type,"",type->arraystr,op);
809 tm = typemap_search(key,type->id);
810 }
811
812 // Check for unname type
813 if (!tm) {
814 key = typemap_string(lang,type,"",0,op);
815 tm = typemap_search(key,type->id);
816 }
817 if (!tm) return 0;
818
819 str = "";
820 str << tm->code;
821
822 // Return character string
823
824 return str;
825 }
826
827 // Function for checking with applications
828
829 char *typemap_check(char *op, char *lang, DataType *type, char *pname) {
830 TmMethod *m;
831 char temp[512];
832 char *result;
833 char *ppname;
834 char *tstr;
835 // Try to apply typemap right away
836
837 result = typemap_check_internal(op,lang,type,pname);
838
839 if (!result) {
840 int drop_pointer = 0;
841 ppname = pname;
842 if (!ppname) ppname = "";
843
844 // The idea : We're going to cycle through applications and
845 // drop pointers off until we get a match.
846
847 while (drop_pointer <= (type->is_pointer - type->implicit_ptr)) {
848 type->is_pointer -= drop_pointer;
849 tstr = type->print_type();
850 sprintf(temp,"%s$%s",tstr,ppname);
851 // No mapping was found. See if the name has been mapped with %apply
852 m = (TmMethod *) application_hash.lookup(temp);
853 if (!m) {
854 sprintf(temp,"%s$",tstr);
855 m = (TmMethod *) application_hash.lookup(temp);
856 }
857 if (m) {
858 m = m->next;
859 while (m) {
860 char *oldary = 0;
861 static String newarray;
862 if (*(m->name)) ppname = m->name;
863 else ppname = pname;
864 m->type->is_pointer += drop_pointer;
865 oldary = m->type->arraystr;
866
867 // If the mapping type is an array and has the 'ANY' keyword, we
868 // have to play some magic
869
870 if ((m->type->arraystr) && (type->arraystr)) {
871 // Build up the new array string
872 newarray = "";
873 for (int n = 0; n < m->type->array_dimensions(); n++) {
874 char *d = m->type->get_dimension(n);
875 if (strcmp(d,"ANY") == 0) {
876 newarray << "[" << type->get_dimension(n) << "]";
877 } else {
878 newarray << "[" << d << "]";
879 }
880 }
881 oldary = m->type->arraystr;
882 m->type->arraystr = newarray.get();
883 } else if (type->arraystr) {
884 m->type->arraystr = type->arraystr;
885 }
886 result = typemap_check_internal(op,lang,m->type,ppname);
887 m->type->arraystr = oldary;
888 m->type->is_pointer -= drop_pointer;
889 if (result) {
890 type->is_pointer += drop_pointer;
891 return result;
892 }
893 m = m->next;
894 }
895 }
896 type->is_pointer += drop_pointer;
897 drop_pointer++;
898 }
899 }
900
901 // If still no result, might have a default typemap
902 if (!result) {
903 DataType *t = new DataType(type);
904 t->primitive(); // Knock it down to its basic type
905 result = typemap_check_internal(op,lang,t,"SWIG_DEFAULT_TYPE");
906 if (result) {
907 delete t;
908 return result;
909 }
910 if ((t->type == T_USER) || (t->is_pointer)) {
911 if ((t->type == T_CHAR) && (t->is_pointer == 1)) return 0;
912 // Still no result, go even more primitive
913 t->type = T_USER;
914 t->is_pointer = 1;
915 if (t->arraystr) delete [] t->arraystr;
916 t->arraystr = 0;
917 t->primitive();
918 result = typemap_check_internal(op,lang,t,"SWIG_DEFAULT_TYPE");
919 }
920 delete t;
921 }
922 return result;
923 }
924
925 // ------------------------------------------------------------------------
926 // void typemap_clear(char *op, char *lang, DataType *type, char *pname)
927 //
928 // Clears any previous typemap. This works like a stack. Clearing a
929 // typemap returns to any previous typemap in force. If there is no
930 // previous map, then don't worry about it.
931 // ------------------------------------------------------------------------
932
933 void typemap_clear(char *op, char *lang, DataType *type, char *pname) {
934
935 char *key;
936 TypeMap *tm;
937
938 key = typemap_string(lang,type,pname,type->arraystr,op);
939
940 // Look for any previous version, simply set the last id if
941 // applicable.
942
943 tm = (TypeMap *) typemap_hash.lookup(key);
944 if (tm) {
945 if (tm->last > type_id) tm->last = type_id;
946 }
947 }
948
949 // ------------------------------------------------------------------------
950 // void typemap_copy(char *op, char *lang, DataType *stype, char *sname,
951 // DataType *ttype, char *tname)
952 //
953 // Copies the code associate with a typemap
954 // ------------------------------------------------------------------------
955
956 void typemap_copy(char *op, char *lang, DataType *stype, char *sname,
957 DataType *ttype, char *tname) {
958
959 char *key;
960 TypeMap *tm, *tk, *tn;
961
962 // Try to locate a previous typemap
963
964 key = typemap_string(lang,stype,sname,stype->arraystr,op);
965 tm = typemap_search(key,stype->id);
966 if (!tm) return;
967 if (strcmp(ttype->name,"PREVIOUS") == 0) {
968 // Pop back up to the previous typemap (if any)
969 tk = tm->next;
970 if (tk) {
971 tn = new TypeMap(tk); // Make a copy of the previous typemap
972 tn->next = tm; // Set up symlinks
973 typemap_hash.remove(key); // Remove old hash entry
974 typemap_hash.add(key,(void *) tn);
975 }
976 } else {
977 typemap_register(op,lang,ttype,tname,tm->code,tm->args);
978 }
979 }
980
981 // ------------------------------------------------------------------------
982 // char *fragment_string(char *op, char *lang)
983 //
984 // Produces a character string corresponding to a language and method
985 // This string is used as the key for our typemap hash table.
986 // ------------------------------------------------------------------------
987
988 static char *fragment_string(char *op, char *lang) {
989 static String str;
990
991 str = "";
992
993 str << "fragment:" << lang << op;
994 return str;
995 }
996
997 // ------------------------------------------------------------------------
998 // void fragment_register(char *op, char *lang, char *code)
999 //
1000 // Register a code fragment with the type-mapper.
1001 // ------------------------------------------------------------------------
1002
1003 void fragment_register(char *op, char *lang, char *code) {
1004
1005 char *key;
1006 TypeMap *tm,*tm_old;
1007 char temp[256];
1008
1009 tm = new TypeMap(lang,code);
1010 key = fragment_string(op,lang);
1011
1012 // Get any previous setting of the typemap
1013
1014 tm_old = (TypeMap *) typemap_hash.lookup(key);
1015 if (tm_old) {
1016 // If found, we need to attach the old version to the new one
1017
1018 // Perform a chaining operation
1019
1020 sprintf(temp,"$%s",op);
1021 if (type_id < tm_old->last)
1022 tm->code.replace(temp,tm_old->code);
1023
1024 tm->next = tm_old;
1025 tm_old->last = type_id;
1026
1027 // Remove the old one from the hash
1028
1029 typemap_hash.remove(key);
1030 }
1031
1032 // Perform a default chaining operation if needed (defaults to nothing)
1033 sprintf(temp,"$%s",op);
1034 tm->code.replace(temp,"");
1035
1036 // Add new typemap to the hash table
1037 typemap_hash.add(key,(void *) tm);
1038
1039 }
1040
1041
1042 // ------------------------------------------------------------------------
1043 // char *fragment_lookup(char *op, char *lang, int age)
1044 //
1045 // op is string code for type of mapping
1046 // lang is the target language string
1047 // age is age of fragment.
1048 //
1049 // Returns NULL if no mapping is found.
1050 //
1051 // ------------------------------------------------------------------------
1052
1053 char *fragment_lookup(char *op, char *lang, int age) {
1054 static String str;
1055 char *key = 0;
1056 TypeMap *tm = 0;
1057
1058 if (!lang) {
1059 return 0;
1060 }
1061
1062 str = "";
1063 key = fragment_string(op,lang);
1064 tm = typemap_search(key,age);
1065
1066 if (!tm) return 0;
1067
1068 str << tm->code;
1069 return str;
1070 }
1071
1072 // ------------------------------------------------------------------------
1073 // void fragment_clear(char *op, char *lang)
1074 //
1075 // Clears any previous fragment definition. Is a stack operation--will
1076 // restore any previously declared typemap.
1077 // ------------------------------------------------------------------------
1078
1079 void fragment_clear(char *op, char *lang) {
1080
1081 char *key;
1082 TypeMap *tm;
1083
1084 key = fragment_string(op,lang);
1085
1086 // Look for any previous version, simply set the last id if
1087 // applicable.
1088
1089 tm = (TypeMap *) typemap_hash.lookup(key);
1090 if (tm) {
1091 if (tm->last > type_id) tm->last = type_id;
1092 }
1093 }