]>
Commit | Line | Data |
---|---|---|
c90f71dd RD |
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 | } |