]>
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 | /*********************************************************************** | |
17 | * $Header$ | |
18 | * | |
19 | * tcl.cxx | |
20 | * | |
21 | * Definitions for creating a simple, stand-alone TCL implementation. | |
22 | * | |
23 | ***********************************************************************/ | |
24 | ||
25 | #include "swig.h" | |
26 | #include "swigtcl.h" | |
27 | #include <ctype.h> | |
28 | ||
29 | static char *Tcl_config="swigtcl.swg"; | |
30 | static char *usage = "\ | |
31 | Tcl Options (available with -tcl)\n\ | |
32 | -module name - Set name of module\n\ | |
33 | -prefix name - Set a prefix to be appended to all names\n\ | |
34 | -namespace - Build module into a Tcl8 namespace. \n\ | |
35 | -noobject - Omit code for object oriented interface.\n\ | |
36 | -old - Use old SWIG interface (same as -noobject).\n\n"; | |
37 | ||
38 | ||
39 | static char *ns_name = 0; | |
40 | static String mod_init; | |
41 | static String mod_extern; | |
42 | ||
43 | // --------------------------------------------------------------------- | |
44 | // TCL::parse_args(int argc, char *argv[]) | |
45 | // | |
46 | // Parse tcl specific command line options | |
47 | // --------------------------------------------------------------------- | |
48 | ||
49 | void TCL::parse_args(int argc, char *argv[]) { | |
50 | ||
51 | int i = 1; | |
52 | sprintf(LibDir,"%s",tcl_path); | |
53 | ||
54 | // Look for certain command line options | |
55 | ||
56 | for (i = 1; i < argc; i++) { | |
57 | if (argv[i]) { | |
58 | if (strcmp(argv[i],"-prefix") == 0) { | |
59 | if (argv[i+1]) { | |
60 | prefix = new char[strlen(argv[i+1])+2]; | |
61 | strcpy(prefix, argv[i+1]); | |
62 | mark_arg(i); | |
63 | mark_arg(i+1); | |
64 | i++; | |
65 | } else { | |
66 | arg_error(); | |
67 | } | |
68 | } else if (strcmp(argv[i],"-module") == 0) { | |
69 | if (argv[i+1]) { | |
70 | set_module(argv[i+1],0); | |
71 | mark_arg(i); | |
72 | mark_arg(i+1); | |
73 | i++; | |
74 | } else { | |
75 | arg_error(); | |
76 | } | |
77 | } else if (strcmp(argv[i],"-namespace") == 0) { | |
78 | nspace = 1; | |
79 | mark_arg(i); | |
80 | } else if (strcmp(argv[i],"-old") == 0) { | |
81 | shadow = 0; | |
82 | mark_arg(i); | |
83 | } else if (strcmp(argv[i],"-noobject") == 0) { | |
84 | shadow = 0; | |
85 | mark_arg(i); | |
86 | } else if (strcmp(argv[i],"-help") == 0) { | |
87 | fputs(usage,stderr); | |
88 | } | |
89 | } | |
90 | } | |
91 | ||
92 | // If a package has been specified, make sure it ends with a '_' | |
93 | ||
94 | if (prefix) { | |
95 | ns_name = copy_string(prefix); | |
96 | if (prefix[strlen(prefix)] != '_') { | |
97 | prefix[strlen(prefix)+1] = 0; | |
98 | prefix[strlen(prefix)] = '_'; | |
99 | } | |
100 | } else | |
101 | prefix = ""; | |
102 | ||
103 | // Create a symbol SWIGTCL | |
104 | ||
105 | add_symbol("SWIGTCL",0,0); | |
106 | typemap_lang = "tcl"; | |
107 | ||
108 | // Attempt to load up the C++ configuration files | |
109 | ||
110 | get_file("delcmd.swg",delcmd); | |
111 | get_file("methodcmd.swg",methodcmd); | |
112 | get_file("objcmd.swg",objcmd); | |
113 | ||
114 | } | |
115 | ||
116 | // --------------------------------------------------------------------- | |
117 | // void TCL::parse() | |
118 | // | |
119 | // Start parsing an interface file for Tcl. | |
120 | // --------------------------------------------------------------------- | |
121 | ||
122 | void TCL::parse() { | |
123 | ||
124 | fprintf(stderr,"Making wrappers for Tcl\n"); | |
125 | ||
126 | // Print out TCL specific headers | |
127 | ||
128 | headers(); | |
129 | ||
130 | // Run the parser | |
131 | ||
132 | yyparse(); | |
133 | ||
134 | } | |
135 | ||
136 | // --------------------------------------------------------------------- | |
137 | // TCL::set_module(char *mod_name,char **mod_list) | |
138 | // | |
139 | // Sets the module name. | |
140 | // Does nothing if it's already set (so it can be overridden as a command | |
141 | // line option). | |
142 | // | |
143 | // mod_list is a NULL-terminated list of additional modules. This | |
144 | // is really only useful when building static executables and other | |
145 | // things. | |
146 | //---------------------------------------------------------------------- | |
147 | ||
148 | void TCL::set_module(char *mod_name, char **mod_list) { | |
149 | ||
150 | char temp[256], *c; | |
151 | int i; | |
152 | ||
153 | if (module) return; | |
154 | ||
155 | module = new char[strlen(mod_name)+1]; | |
156 | strcpy(module,mod_name); | |
157 | ||
158 | // Fix capitalization for Tcl | |
159 | ||
160 | c = module; | |
161 | while (*c) { | |
162 | *c = (char) tolower(*c); | |
163 | c++; | |
164 | } | |
165 | ||
166 | // Now create an initialization function | |
167 | ||
168 | sprintf(temp,"%s_Init", module); | |
169 | init_name = new char[strlen(temp) + 1]; | |
170 | strcpy(init_name, temp); | |
171 | *init_name = toupper(*init_name); | |
172 | ||
173 | if (!ns_name) ns_name = copy_string(module); | |
174 | ||
175 | // If namespaces have been specified, set the prefix to the module name | |
176 | ||
177 | if ((nspace) && (strlen(prefix) < 1)) { | |
178 | prefix = new char[strlen(module)+2]; | |
179 | strcpy(prefix,module); | |
180 | prefix[strlen(module)] = '_'; | |
181 | prefix[strlen(module)+1] = 0; | |
182 | } | |
183 | ||
184 | // If additional modules have been specified, create some code for | |
185 | // initializing them. | |
186 | ||
187 | if (mod_list) { | |
188 | i = 0; | |
189 | while (mod_list[i]) { | |
190 | c = mod_list[i]; | |
191 | while (*c) { | |
192 | *c = (char) tolower(*c); | |
193 | c++; | |
194 | } | |
195 | sprintf(temp,"%s_Init",mod_list[i]); | |
196 | temp[0] = toupper(temp[0]); | |
197 | ||
198 | // Dump out some initialization code | |
199 | ||
200 | mod_init << tab4 << "if (" << temp << "(" << interp_name << ") == TCL_ERROR) {\n" | |
201 | << tab8 << "return TCL_ERROR;\n" | |
202 | << tab4 << "}\n\n"; | |
203 | mod_extern << "extern int " << temp << "(Tcl_Interp *);\n"; | |
204 | i++; | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
209 | ||
210 | // --------------------------------------------------------------------- | |
211 | // TCL::set_init(char *iname) | |
212 | // | |
213 | // Sets the initialization function name. | |
214 | // Does nothing if it's already set | |
215 | // | |
216 | //---------------------------------------------------------------------- | |
217 | ||
218 | void TCL::set_init(char *iname) { | |
219 | ||
220 | if (init_name) return; | |
221 | ||
222 | init_name = new char[strlen(iname)+1]; | |
223 | strcpy(init_name, iname); | |
224 | ||
225 | } | |
226 | ||
227 | // --------------------------------------------------------------------- | |
228 | // TCL::headers(void) | |
229 | // | |
230 | // Generate the appropriate header files for TCL interface. | |
231 | // ---------------------------------------------------------------------- | |
232 | ||
233 | void TCL::headers(void) | |
234 | { | |
235 | ||
236 | emit_banner(f_header); | |
237 | fprintf(f_header,"/* Implementation : TCL 7.x */\n\n"); | |
238 | fprintf(f_header,"#include <tcl.h>\n"); | |
239 | fprintf(f_header,"#include <string.h>\n"); | |
240 | fprintf(f_header,"#include <stdlib.h>\n"); | |
241 | fprintf(f_header,"#define SWIGTCL\n"); | |
242 | ||
243 | if (NoInclude) { | |
244 | fprintf(f_header,"#define SWIG_NOINCLUDE\n"); | |
245 | } | |
246 | ||
247 | if (insert_file("swigtcl.swg", f_header) == -1) { | |
248 | fprintf(stderr,"Unable to find 'swigtcl.swg'. Possible installation problem.\n"); | |
249 | SWIG_exit(1); | |
250 | } | |
251 | } | |
252 | ||
253 | // -------------------------------------------------------------------- | |
254 | // TCL::initialize(void) | |
255 | // | |
256 | // Produces an initialization function. Assumes that the init function | |
257 | // name has already been specified. | |
258 | // --------------------------------------------------------------------- | |
259 | ||
260 | void TCL::initialize() | |
261 | { | |
262 | ||
263 | if ((!ns_name) && (nspace)) { | |
264 | fprintf(stderr,"Tcl error. Must specify a namespace.\n"); | |
265 | SWIG_exit(1); | |
266 | } | |
267 | ||
268 | if (!init_name) { | |
269 | init_name = "Swig_Init"; | |
270 | fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); | |
271 | } | |
272 | ||
273 | fprintf(f_header,"#define SWIG_init %s\n", init_name); | |
274 | if (!module) module = "swig"; | |
275 | fprintf(f_header,"#define SWIG_name \"%s\"\n", module); | |
276 | if (nspace) { | |
277 | fprintf(f_header,"#define SWIG_prefix \"%s::\"\n", ns_name); | |
278 | fprintf(f_header,"#define SWIG_namespace \"%s\"\n\n", ns_name); | |
279 | } else { | |
280 | fprintf(f_header,"#define SWIG_prefix \"%s\"\n", prefix); | |
281 | fprintf(f_header,"#define SWIG_namespace \"\"\n\n"); | |
282 | } | |
283 | fprintf(f_header,"#ifdef __cplusplus\n"); | |
284 | fprintf(f_header,"extern \"C\" {\n"); | |
285 | fprintf(f_header,"#endif\n"); | |
286 | fprintf(f_header,"#ifdef MAC_TCL\n"); | |
287 | fprintf(f_header,"#pragma export on\n"); | |
288 | fprintf(f_header,"#endif\n"); | |
289 | fprintf(f_header,"SWIGEXPORT(int) %s(Tcl_Interp *);\n", init_name); | |
290 | fprintf(f_header,"#ifdef MAC_TCL\n"); | |
291 | fprintf(f_header,"#pragma export off\n"); | |
292 | fprintf(f_header,"#endif\n"); | |
293 | fprintf(f_header,"#ifdef __cplusplus\n"); | |
294 | fprintf(f_header,"}\n"); | |
295 | fprintf(f_header,"#endif\n"); | |
296 | ||
297 | fprintf(f_init,"SWIGEXPORT(int) %s(Tcl_Interp *%s) {\n", init_name, interp_name); | |
298 | ||
299 | fprintf(f_init,"\t if (%s == 0) \n", interp_name); | |
300 | fprintf(f_init,"\t\t return TCL_ERROR;\n"); | |
301 | ||
302 | /* Check to see if other initializations need to be performed */ | |
303 | ||
304 | if (strlen(mod_extern.get())) { | |
305 | fprintf(f_init,"%s\n",mod_init.get()); | |
306 | fprintf(f_header,"#ifdef __cplusplus\n"); | |
307 | fprintf(f_header,"extern \"C\" {\n"); | |
308 | fprintf(f_header,"#endif\n"); | |
309 | fprintf(f_header,"%s\n",mod_extern.get()); | |
310 | fprintf(f_header,"#ifdef __cplusplus\n"); | |
311 | fprintf(f_header,"}\n"); | |
312 | fprintf(f_header,"#endif\n"); | |
313 | } | |
314 | ||
315 | /* Check to see if we're adding support for Tcl8 nspaces */ | |
316 | if (nspace) { | |
317 | fprintf(f_init,"#if (TCL_MAJOR_VERSION >= 8)\n"); | |
318 | fprintf(f_init,"\t Tcl_Eval(%s,\"namespace eval %s { }\");\n", interp_name, ns_name); | |
319 | fprintf(f_init,"#endif\n"); | |
320 | } | |
321 | } | |
322 | ||
323 | // --------------------------------------------------------------------- | |
324 | // TCL::close(void) | |
325 | // | |
326 | // Wrap things up. Close initialization function. | |
327 | // --------------------------------------------------------------------- | |
328 | ||
329 | void TCL::close(void) | |
330 | { | |
331 | ||
332 | // Dump the pointer equivalency table | |
333 | ||
334 | emit_ptr_equivalence(f_init); | |
335 | ||
336 | // Close the init file and quit | |
337 | fprintf(f_init,"%s",postinit.get()); | |
338 | fprintf(f_init,"\t return TCL_OK;\n"); | |
339 | fprintf(f_init,"}\n"); | |
340 | } | |
341 | ||
342 | // ---------------------------------------------------------------------- | |
343 | // TCL::get_pointer(char *iname, char *srcname, char *src, char *dest, | |
344 | // DataType *t, String &f, char *ret) | |
345 | // | |
346 | // iname = name of function or variable | |
347 | // srcname = name of source | |
348 | // src = source variable in wrapper code | |
349 | // dest = destination variable in wrapper code | |
350 | // t = Datatype | |
351 | // f = String where output is going to go | |
352 | // ret = Return action | |
353 | // ---------------------------------------------------------------------- | |
354 | ||
355 | void TCL::get_pointer(char *iname, char *srcname, char *src, char *dest, | |
356 | DataType *t, String &f, char *ret) { | |
357 | ||
358 | // Pointers are read as hex-strings with encoded type information | |
359 | ||
360 | f << tab4 << "if (SWIG_GetPtr(" << src << ",(void **) &" << dest << ","; | |
361 | ||
362 | if (t->type == T_VOID) f << "(char *) 0)) {\n"; | |
363 | else | |
364 | f << "\"" << t->print_mangle() << "\")) {\n"; | |
365 | ||
366 | // Now emit code according to the level of strictness desired | |
367 | ||
368 | switch(TypeStrict) { | |
369 | case 0: // No type checking | |
370 | f << tab4 << "}\n"; | |
371 | break; | |
372 | case 1: // Warning message only | |
373 | f << tab8 << "fprintf(stderr,\"Warning : type mismatch in " << srcname | |
374 | << " of " << iname << ". Expected " << t->print_mangle() | |
375 | << ", received %s\\n\"," << src << ");\n" | |
376 | << tab4 << "}\n"; | |
377 | case 2: // Super strict mode. | |
378 | f << tab8 << "Tcl_SetResult(interp, \"Type error in " << srcname << " of " << iname | |
379 | << ". Expected " << t->print_mangle() << ", received \", TCL_STATIC);\n" | |
380 | << tab8 << "Tcl_AppendResult(interp, " << src << ", (char *) NULL);\n" | |
381 | << tab8 << ret << ";\n" | |
382 | << tab4 << "}\n"; | |
383 | break; | |
384 | default : | |
385 | fprintf(stderr,"Unknown strictness level\n"); | |
386 | break; | |
387 | } | |
388 | } | |
389 | ||
390 | // ---------------------------------------------------------------------- | |
391 | // TCL::create_command(char *cname, char *iname) | |
392 | // | |
393 | // Creates a Tcl command from a C function. | |
394 | // ---------------------------------------------------------------------- | |
395 | ||
396 | void TCL::create_command(char *cname, char *iname) { | |
397 | ||
398 | ||
399 | char *wname = name_wrapper(cname,prefix); | |
400 | ||
401 | fprintf(f_init,"\t Tcl_CreateCommand(%s,SWIG_prefix \"%s\",%s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n", interp_name, iname, wname); | |
402 | ||
403 | // Add interpreter name to repeatcmd hash table. This hash is used in C++ code | |
404 | // generation to try and find repeated wrapper functions. | |
405 | ||
406 | repeatcmd.add(iname,copy_string(wname)); | |
407 | } | |
408 | ||
409 | // ---------------------------------------------------------------------- | |
410 | // TCL::create_function(char *name, char *iname, DataType *d, ParmList *l) | |
411 | // | |
412 | // Create a function declaration and register it with the interpreter. | |
413 | // ---------------------------------------------------------------------- | |
414 | ||
415 | void TCL::create_function(char *name, char *iname, DataType *d, ParmList *l) | |
416 | { | |
417 | Parm *p; | |
418 | int pcount,i,j; | |
419 | char *wname; | |
420 | char *usage = 0; | |
421 | char source[256], target[256], argnum[32], *tm; | |
422 | String cleanup, outarg; | |
423 | int numopt; | |
424 | int have_build = 0; // Status indicating build typemap | |
425 | String build; | |
426 | ||
427 | WrapperFunction f; | |
428 | ||
429 | // Make a wrapper name for this function | |
430 | ||
431 | wname = name_wrapper(iname,prefix); | |
432 | ||
433 | // Now write the wrapper function itself....this is pretty ugly | |
434 | ||
435 | f.def << "static int " << wname << "(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) {\n"; | |
436 | f.code << tab4 << "clientData = clientData; argv = argv;\n"; | |
437 | ||
438 | // Print out variables for storing arguments. | |
439 | ||
440 | pcount = emit_args(d, l, f); | |
441 | ||
442 | // Get number of optional arguments | |
443 | ||
444 | numopt = l->numopt(); | |
445 | ||
446 | // Check the number of arguments | |
447 | ||
448 | usage = usage_func(iname,d,l); // Create a usage string | |
449 | f.code << tab4 << "if ((argc < " << (pcount-numopt) +1 << ") || (argc > " << l->numarg()+1 << ")) {\n" | |
450 | << tab8 << "Tcl_SetResult(interp, \"Wrong # args. " << usage << "\",TCL_STATIC);\n" | |
451 | << tab8 << "return TCL_ERROR;\n" | |
452 | << tab4 << "}\n"; | |
453 | ||
454 | // Extract parameters. This case statement should be used to extract | |
455 | // Function parameters. Add more cases if you want to do more. | |
456 | ||
457 | i = 0; | |
458 | j = 0; | |
459 | p = l->get_first(); | |
460 | while (p != 0) { | |
461 | // Produce string representations of the source and target arguments | |
462 | sprintf(source,"argv[%d]",j+1); | |
463 | sprintf(target,"_arg%d",i); | |
464 | sprintf(argnum,"%d",j+1); | |
465 | ||
466 | // See if this argument is being ignored | |
467 | ||
468 | if (!p->ignore) { | |
469 | if (j >= (pcount-numopt)) | |
470 | f.code << tab4 << "if (argc >" << j+1 << ") { \n"; | |
471 | ||
472 | // See if there is a type-mapping | |
473 | ||
474 | if ((tm = typemap_lookup("in","tcl",p->t,p->name,source,target,&f))) { | |
475 | // Yep. Use it instead of the default | |
476 | f.code << tm << "\n"; | |
477 | f.code.replace("$argnum",argnum); | |
478 | f.code.replace("$arg",source); | |
479 | } else { | |
480 | ||
481 | if (!p->t->is_pointer) { | |
482 | ||
483 | // Extract a parameter by value. | |
484 | ||
485 | switch(p->t->type) { | |
486 | ||
487 | // Signed Integers | |
488 | ||
489 | case T_BOOL: | |
490 | case T_INT: | |
491 | case T_SINT: | |
492 | case T_SHORT: | |
493 | case T_SSHORT: | |
494 | case T_LONG: | |
495 | case T_SLONG: | |
496 | case T_SCHAR: | |
497 | f.code << tab4 << "_arg" << i << " = " << p->t->print_cast() << " atol(argv[" << j+1 << "]);\n"; | |
498 | break; | |
499 | ||
500 | // Unsigned Integers | |
501 | ||
502 | case T_UINT: | |
503 | case T_USHORT: | |
504 | case T_ULONG: | |
505 | case T_UCHAR: | |
506 | f.code << tab4 << "_arg" << i << " = " << p->t->print_cast() << " strtoul(argv[" << j+1 | |
507 | << "],(char **) NULL,0);\n"; | |
508 | break; | |
509 | ||
510 | // Floating point | |
511 | ||
512 | case T_FLOAT: | |
513 | case T_DOUBLE: | |
514 | f.code << tab4 << "_arg" << i << " = " << p->t->print_cast() << " atof(argv[" << j+1 << "]);\n"; | |
515 | break; | |
516 | ||
517 | // A single character | |
518 | ||
519 | case T_CHAR : | |
520 | f.code << tab4 << "_arg" << i << " = *argv[" << j+1 << "];\n"; | |
521 | break; | |
522 | ||
523 | // Void.. Do nothing. | |
524 | ||
525 | case T_VOID : | |
526 | break; | |
527 | ||
528 | // User defined. This is an error. | |
529 | ||
530 | case T_USER: | |
531 | ||
532 | // Unsupported data type | |
533 | ||
534 | default : | |
535 | fprintf(stderr,"%s : Line %d: Unable to use type %s as a function argument.\n", | |
536 | input_file, line_number, p->t->print_type()); | |
537 | break; | |
538 | } | |
539 | } else { /* Pointer type */ | |
540 | ||
541 | // Function argument is some sort of pointer | |
542 | // Look for a string. Otherwise, just pull off a pointer. | |
543 | ||
544 | if ((p->t->type == T_CHAR) && (p->t->is_pointer == 1)) { | |
545 | f.code << tab4 << "_arg" << i << " = argv[" << j+1 << "];\n"; | |
546 | } else { | |
547 | ||
548 | // Have a generic pointer type here. Read it in as | |
549 | // a hex-string | |
550 | ||
551 | char arg_temp[256]; | |
552 | sprintf(arg_temp,"argument %d",j+1); | |
553 | get_pointer(iname,arg_temp,source,target,p->t,f.code,"return TCL_ERROR"); | |
554 | } | |
555 | } | |
556 | } | |
557 | if (j >= (pcount-numopt)) | |
558 | f.code << tab4 << "} \n"; | |
559 | j++; | |
560 | } | |
561 | ||
562 | // Check to see if there is any sort of "build" typemap (highly complicated) | |
563 | ||
564 | if ((tm = typemap_lookup("build","tcl",p->t,p->name,source,target))) { | |
565 | build << tm << "\n"; | |
566 | have_build = 1; | |
567 | } | |
568 | ||
569 | // Check to see if there was any sort of a constaint typemap | |
570 | if ((tm = typemap_lookup("check","tcl",p->t,p->name,source,target))) { | |
571 | // Yep. Use it instead of the default | |
572 | f.code << tm << "\n"; | |
573 | f.code.replace("$argnum",argnum); | |
574 | f.code.replace("$arg",source); | |
575 | } | |
576 | ||
577 | // Check if there was any cleanup code (save it for later) | |
578 | if ((tm = typemap_lookup("freearg","tcl",p->t,p->name,target,"interp->result"))) { | |
579 | // Yep. Use it instead of the default | |
580 | cleanup << tm << "\n"; | |
581 | cleanup.replace("$argnum",argnum); | |
582 | cleanup.replace("$arg",source); | |
583 | } | |
584 | if ((tm = typemap_lookup("argout","tcl",p->t,p->name,target,"interp->result"))) { | |
585 | // Yep. Use it instead of the default | |
586 | outarg << tm << "\n"; | |
587 | outarg.replace("$argnum",argnum); | |
588 | outarg.replace("$arg",source); | |
589 | } | |
590 | p = l->get_next(); // Get next parameter and continue | |
591 | i++; | |
592 | } | |
593 | ||
594 | // If there was a "build" typemap, we need to go in and perform a serious hack | |
595 | ||
596 | if (have_build) { | |
597 | char temp1[32]; | |
598 | char temp2[256]; | |
599 | l->sub_parmnames(build); // Replace all parameter names | |
600 | j = 1; | |
601 | for (i = 0; i < l->nparms; i++) { | |
602 | p = l->get(i); | |
603 | if (strlen(p->name) > 0) { | |
604 | sprintf(temp1,"_in_%s", p->name); | |
605 | } else { | |
606 | sprintf(temp1,"_in_arg%d", i); | |
607 | } | |
608 | sprintf(temp2,"argv[%d]",j); | |
609 | build.replaceid(temp1,temp2); | |
610 | if (!p->ignore) | |
611 | j++; | |
612 | } | |
613 | f.code << build; | |
614 | } | |
615 | ||
616 | // Now write code to make the function call | |
617 | ||
618 | emit_func_call(name,d,l,f); | |
619 | ||
620 | // Return value if necessary | |
621 | ||
622 | if ((tm = typemap_lookup("out","tcl",d,name,"_result","interp->result"))) { | |
623 | // Yep. Use it instead of the default | |
624 | f.code << tm << "\n"; | |
625 | } else if ((d->type != T_VOID) || (d->is_pointer)) { | |
626 | // Normal SWIG mappings | |
627 | ||
628 | if (!d->is_pointer) { | |
629 | ||
630 | // Function returns a "value" | |
631 | ||
632 | switch(d->type) { | |
633 | // Is a signed integer | |
634 | case T_BOOL: | |
635 | case T_INT: | |
636 | case T_SINT: | |
637 | case T_SHORT: | |
638 | case T_SSHORT: | |
639 | case T_LONG : | |
640 | case T_SLONG: | |
641 | case T_SCHAR: | |
642 | f.code << tab4 << "sprintf(interp->result,\"%ld\", (long) _result);\n"; | |
643 | break; | |
644 | ||
645 | // Is an unsigned integer | |
646 | case T_UINT: | |
647 | case T_USHORT: | |
648 | case T_ULONG: | |
649 | case T_UCHAR: | |
650 | f.code << tab4 << "sprintf(interp->result,\"%lu\", (unsigned long) _result);\n"; | |
651 | break; | |
652 | ||
653 | // Is a single character. Assume we return it as a string | |
654 | case T_CHAR : | |
655 | f.code << tab4 << "sprintf(interp->result,\"%c\", _result);\n"; | |
656 | break; | |
657 | ||
658 | // Floating point number | |
659 | case T_DOUBLE : | |
660 | case T_FLOAT : | |
661 | f.code << tab4 << "Tcl_PrintDouble(interp,(double) _result, interp->result);\n"; | |
662 | //sprintf(interp->result,\"%0.17f\",(double) _result);\n"; | |
663 | break; | |
664 | ||
665 | // User defined type | |
666 | case T_USER : | |
667 | ||
668 | // Okay. We're returning malloced memory at this point. | |
669 | // Probably dangerous, but what the hell | |
670 | ||
671 | d->is_pointer++; | |
672 | f.code << tab4 << "SWIG_MakePtr(interp->result, (void *) _result,\"" << d->print_mangle() | |
673 | << "\");\n"; | |
674 | d->is_pointer--; | |
675 | break; | |
676 | ||
677 | // Unknown type | |
678 | default : | |
679 | fprintf(stderr,"%s : Line %d: Unable to use return type %s in function %s.\n", | |
680 | input_file, line_number, d->print_type(), name); | |
681 | break; | |
682 | } | |
683 | } else { | |
684 | ||
685 | // Is a pointer return type | |
686 | ||
687 | if ((d->type == T_CHAR) && (d->is_pointer == 1)) { | |
688 | // Return a character string | |
689 | f.code << tab4 << "Tcl_SetResult(interp, (char *) _result, " << char_result << ");\n"; | |
690 | } else { | |
691 | f.code << tab4 << "SWIG_MakePtr(interp->result, (void *) _result,\"" << d->print_mangle() << "\");\n"; | |
692 | } | |
693 | } | |
694 | } | |
695 | ||
696 | // Dump argument output code; | |
697 | f.code << outarg; | |
698 | ||
699 | // Dump the argument cleanup code | |
700 | f.code << cleanup; | |
701 | ||
702 | // Look for any remaining cleanup | |
703 | ||
704 | if (NewObject) { | |
705 | if ((tm = typemap_lookup("newfree","tcl",d,iname,"_result",""))) { | |
706 | f.code << tm << "\n"; | |
707 | } | |
708 | } | |
709 | ||
710 | if ((tm = typemap_lookup("ret","tcl",d,name,"_result",""))) { | |
711 | // Yep. Use it instead of the default | |
712 | f.code << tm << "\n"; | |
713 | } | |
714 | ||
715 | // Wrap things up (in a manner of speaking) | |
716 | ||
717 | f.code << tab4 << "return TCL_OK;\n}"; | |
718 | ||
719 | // Substitute the cleanup code | |
720 | f.code.replace("$cleanup",cleanup); | |
721 | f.code.replace("$name",iname); | |
722 | ||
723 | // Dump out the function | |
724 | ||
725 | f.print(f_wrappers); | |
726 | ||
727 | // Add interpreter name to repeatcmd hash table. This hash is used in C++ code | |
728 | // generation to try and find repeated wrapper functions. | |
729 | ||
730 | fprintf(f_init,"\t Tcl_CreateCommand(%s, SWIG_prefix \"%s\", %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n", interp_name, iname, wname); | |
731 | ||
732 | // If there's a documentation entry, produce a usage string | |
733 | ||
734 | if (doc_entry) { | |
735 | ||
736 | static DocEntry *last_doc_entry = 0; | |
737 | ||
738 | // Use usage as description | |
739 | doc_entry->usage << usage; | |
740 | ||
741 | // Set the cinfo field to specific a return type | |
742 | ||
743 | if (last_doc_entry != doc_entry) { | |
744 | doc_entry->cinfo << "returns " << d->print_type(); | |
745 | last_doc_entry = doc_entry; | |
746 | } | |
747 | } | |
748 | } | |
749 | ||
750 | // ----------------------------------------------------------------------- | |
751 | // TCL::link_variable(char *name, char *iname, DataType *t, | |
752 | // int ex) | |
753 | // | |
754 | // Create a TCL link to a variable. | |
755 | // ----------------------------------------------------------------------- | |
756 | ||
757 | void TCL::link_variable(char *name, char *iname, DataType *t) | |
758 | { | |
759 | ||
760 | String s; | |
761 | char *tm,*tm1; | |
762 | String realname; | |
763 | ||
764 | ||
765 | // See if there were any typemaps | |
766 | ||
767 | tm = typemap_lookup("varin","tcl",t,name,"",""); | |
768 | tm1 = typemap_lookup("varout","tcl",t,name,"",""); | |
769 | if (tm || tm1) { | |
770 | fprintf(stderr,"%s : Line %d. Warning. varin/varout typemap methods not supported.", | |
771 | input_file, line_number); | |
772 | } | |
773 | ||
774 | // Check the datatype. Must be a valid Tcl type (there aren't many) | |
775 | ||
776 | if (((t->type == T_INT) && (!t->is_pointer)) || | |
777 | ((t->type == T_UINT) && (!t->is_pointer)) || | |
778 | ((t->type == T_SINT) && (!t->is_pointer)) || | |
779 | ((t->type == T_DOUBLE) && (!t->is_pointer)) || | |
780 | ((t->type == T_BOOL) && (!t->is_pointer)) || | |
781 | ((t->type == T_CHAR) && (t->is_pointer == 1))) { | |
782 | ||
783 | // This is a valid TCL type. | |
784 | ||
785 | if (t->type == T_UINT) | |
786 | fprintf(stderr,"%s : Line %d : ** Warning. Linkage of unsigned type may be unsafe.\n", | |
787 | input_file, line_number); | |
788 | ||
789 | // Now add symbol to the TCL interpreter | |
790 | ||
791 | switch(t->type) { | |
792 | case T_CHAR : | |
793 | if (t->arraystr) { | |
794 | // Is an array. We have to do something different | |
795 | fprintf(f_wrappers,"static char *tclvar%s = %s;\n",name,name); | |
796 | s << "(char *) &tclvar" << name << ", TCL_LINK_STRING"; | |
797 | } else { | |
798 | s << "(char *) &" << name << ", TCL_LINK_STRING"; | |
799 | } | |
800 | break; | |
801 | case T_BOOL: | |
802 | case T_INT : | |
803 | case T_UINT: | |
804 | case T_SINT: | |
805 | s << "(char *) &" << name << ", TCL_LINK_INT"; | |
806 | break; | |
807 | case T_DOUBLE : | |
808 | s << "(char *) &" << name << ", TCL_LINK_DOUBLE"; | |
809 | break; | |
810 | default : | |
811 | fprintf(f_init,"Fatal error. Internal error (Tcl:link_variable)\n"); | |
812 | break; | |
813 | } | |
814 | ||
815 | if (Status & STAT_READONLY) | |
816 | s << " | TCL_LINK_READ_ONLY);\n"; | |
817 | else | |
818 | s << ");\n"; | |
819 | ||
820 | fprintf(f_init,"\t Tcl_LinkVar(%s, SWIG_prefix \"%s\", %s",interp_name, iname, s.get()); | |
821 | ||
822 | // Make a usage string for it | |
823 | ||
824 | if (doc_entry) { | |
825 | doc_entry->usage << usage_var(iname,t); | |
826 | doc_entry->cinfo = ""; | |
827 | doc_entry->cinfo << "Global : " << t->print_type() << " " << name; | |
828 | } | |
829 | } else { | |
830 | ||
831 | // Have some sort of "other" type. | |
832 | // We're going to emit some functions to set/get it's value instead | |
833 | ||
834 | emit_set_get(name,iname, t); | |
835 | if (doc_entry) { | |
836 | doc_entry->cinfo = ""; | |
837 | doc_entry->cinfo << "Global : " << t->print_type() << " " << iname; | |
838 | } | |
839 | ||
840 | // If shadow classes are enabled and we have a user-defined type | |
841 | // that we know about, create a command for it. | |
842 | ||
843 | if (shadow) { | |
844 | if ((t->type == T_USER) && (t->is_pointer < 1)) { | |
845 | // See if the datatype is in our hash table | |
846 | if (hash.lookup(t->name)) { | |
847 | // Yep. Try to create a command for it | |
848 | // postinit << tab4 << "Tcl_CreateCommand(interp, SWIG_prefix \"" << iname << "\",Tcl" << (char *) hash.lookup(t->name) | |
849 | // << "MethodCmd, (ClientData)"; | |
850 | ||
851 | postinit << tab4 << "{\n" | |
852 | << tab8 << "char cmd[] = \"" | |
853 | << (char *) hash.lookup(t->name) << " " << iname << " -this [" | |
854 | << iname << "_get ]\";\n" | |
855 | << tab8 << "Tcl_GlobalEval(interp,cmd);\n" | |
856 | << tab4 << "}\n"; | |
857 | ||
858 | // postinit << tab4 << "Tcl_GlobalEval(interp,\"set " << iname << " [" << iname << "_get ];" | |
859 | // << (char *) hash.lookup(t->name) << " -this $" << iname << "\");\n"; | |
860 | ||
861 | } | |
862 | } | |
863 | } | |
864 | } | |
865 | } | |
866 | ||
867 | // ----------------------------------------------------------------------- | |
868 | // TCL::declare_const(char *name, char *iname, DataType *type, char *value) | |
869 | // | |
870 | // Makes a constant. Really just creates a variable and links to it. | |
871 | // Tcl variable linkage allows read-only variables so we'll use that | |
872 | // instead of just creating a Tcl variable. | |
873 | // ------------------------------------------------------------------------ | |
874 | ||
875 | void TCL::declare_const(char *name, char *, DataType *type, char *value) { | |
876 | ||
877 | int OldStatus = Status; // Save old status flags | |
878 | DataType *t; | |
879 | char var_name[256]; | |
880 | char *tm; | |
881 | String rvalue; | |
882 | ||
883 | Status = STAT_READONLY; // Enable readonly mode. | |
884 | ||
885 | // Make a static variable; | |
886 | ||
887 | sprintf(var_name,"_wrap_const_%s",name); | |
888 | ||
889 | // See if there's a typemap | |
890 | ||
891 | rvalue = value; | |
892 | if ((type->type == T_CHAR) && (type->is_pointer == 1)) { | |
893 | rvalue << "\""; | |
894 | "\"" >> rvalue; | |
895 | } | |
896 | if ((type->type == T_CHAR) && (type->is_pointer == 0)) { | |
897 | rvalue << "'"; | |
898 | "'" >> rvalue; | |
899 | } | |
900 | if ((tm = typemap_lookup("const","tcl",type,name,rvalue.get(),name))) { | |
901 | // Yep. Use it instead of the default | |
902 | fprintf(f_init,"%s\n",tm); | |
903 | } else { | |
904 | ||
905 | // Create variable and assign it a value | |
906 | ||
907 | if (type->is_pointer == 0) { | |
908 | switch(type->type) { | |
909 | case T_BOOL: case T_INT: case T_SINT: case T_DOUBLE: | |
910 | fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); | |
911 | link_variable(var_name,name,type); | |
912 | break; | |
913 | case T_SHORT: | |
914 | case T_LONG: | |
915 | case T_SSHORT: | |
916 | case T_SCHAR: | |
917 | case T_SLONG: | |
918 | fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); | |
919 | fprintf(f_header,"static char *%s_char;\n", var_name); | |
920 | if (CPlusPlus) | |
921 | fprintf(f_init,"\t %s_char = new char[32];\n",var_name); | |
922 | else | |
923 | fprintf(f_init,"\t %s_char = (char *) malloc(32);\n",var_name); | |
924 | ||
925 | fprintf(f_init,"\t sprintf(%s_char,\"%%ld\", (long) %s);\n", var_name, var_name); | |
926 | sprintf(var_name,"%s_char",var_name); | |
927 | t = new DataType(T_CHAR); | |
928 | t->is_pointer = 1; | |
929 | link_variable(var_name,name,t); | |
930 | delete t; | |
931 | break; | |
932 | case T_UINT: | |
933 | case T_USHORT: | |
934 | case T_ULONG: | |
935 | case T_UCHAR: | |
936 | fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); | |
937 | fprintf(f_header,"static char *%s_char;\n", var_name); | |
938 | if (CPlusPlus) | |
939 | fprintf(f_init,"\t %s_char = new char[32];\n",var_name); | |
940 | else | |
941 | fprintf(f_init,"\t %s_char = (char *) malloc(32);\n",var_name); | |
942 | ||
943 | fprintf(f_init,"\t sprintf(%s_char,\"%%lu\", (unsigned long) %s);\n", var_name, var_name); | |
944 | sprintf(var_name,"%s_char",var_name); | |
945 | t = new DataType(T_CHAR); | |
946 | t->is_pointer = 1; | |
947 | link_variable(var_name,name,t); | |
948 | delete t; | |
949 | break; | |
950 | case T_FLOAT: | |
951 | type->type = T_DOUBLE; | |
952 | strcpy(type->name,"double"); | |
953 | fprintf(f_header,"static %s %s = %s (%s);\n", type->print_type(), var_name, type->print_cast(), value); | |
954 | link_variable(var_name,name,type); | |
955 | break; | |
956 | ||
957 | case T_CHAR: | |
958 | type->is_pointer++; | |
959 | fprintf(f_header,"static %s %s = \"%s\";\n", type->print_type(), var_name, value); | |
960 | link_variable(var_name,name,type); | |
961 | type->is_pointer--; | |
962 | break; | |
963 | default: | |
964 | fprintf(stderr,"%s : Line %d. Unsupported constant value.\n", input_file, line_number); | |
965 | break; | |
966 | } | |
967 | } else { | |
968 | // Have some sort of pointer value here | |
969 | if ((type->type == T_CHAR) && (type->is_pointer == 1)) { | |
970 | // Character string | |
971 | fprintf(f_header,"static %s %s = \"%s\";\n", type->print_type(), var_name, value); | |
972 | link_variable(var_name,name,type); | |
973 | } else { | |
974 | // Something else. Some sort of pointer value | |
975 | fprintf(f_header,"static %s %s = %s;\n", type->print_type(), var_name, value); | |
976 | fprintf(f_header,"static char *%s_char;\n", var_name); | |
977 | if (CPlusPlus) | |
978 | fprintf(f_init,"\t %s_char = new char[%d];\n",var_name,(int) strlen(type->print_mangle())+ 20); | |
979 | else | |
980 | fprintf(f_init,"\t %s_char = (char *) malloc(%d);\n",var_name,(int) strlen(type->print_mangle())+ 20); | |
981 | ||
982 | t = new DataType(T_CHAR); | |
983 | t->is_pointer = 1; | |
984 | fprintf(f_init,"\t SWIG_MakePtr(%s_char, (void *) %s,\"%s\");\n", | |
985 | var_name, var_name, type->print_mangle()); | |
986 | sprintf(var_name,"%s_char",var_name); | |
987 | link_variable(var_name,name,t); | |
988 | delete t; | |
989 | } | |
990 | } | |
991 | } | |
992 | ||
993 | // Create a documentation entry for this | |
994 | ||
995 | if (doc_entry) { | |
996 | doc_entry->usage = ""; // Destroy any previous information from linking | |
997 | doc_entry->usage << usage_const(name, type, value); | |
998 | doc_entry->cinfo = ""; | |
999 | doc_entry->cinfo << "Constant : " << type->print_type(); | |
1000 | } | |
1001 | Status = OldStatus; | |
1002 | } | |
1003 | ||
1004 | // ---------------------------------------------------------------------- | |
1005 | // TCL::usage_var(char *iname, DataType *t, char **s) | |
1006 | // | |
1007 | // Produces a usage string for a tcl variable. Stores it in s | |
1008 | // ---------------------------------------------------------------------- | |
1009 | ||
1010 | char *TCL::usage_var(char *iname, DataType *t) { | |
1011 | ||
1012 | static String temp; | |
1013 | ||
1014 | temp = ""; | |
1015 | if (!nspace) { | |
1016 | temp << "$" << prefix << iname; | |
1017 | } else { | |
1018 | temp << ns_name << "::" << iname; | |
1019 | } | |
1020 | if (!(((t->type == T_INT) && (!t->is_pointer)) || | |
1021 | ((t->type == T_UINT) && (!t->is_pointer)) || | |
1022 | ((t->type == T_DOUBLE) && (!t->is_pointer)) || | |
1023 | ((t->type == T_BOOL) && (!t->is_pointer)) || | |
1024 | ((t->type == T_CHAR) && (t->is_pointer)))) { | |
1025 | /* We emitted a pair of set/get functions instead. Doc will be generated for that */ | |
1026 | return temp; | |
1027 | } | |
1028 | return temp; | |
1029 | } | |
1030 | ||
1031 | ||
1032 | // --------------------------------------------------------------------------- | |
1033 | // char *TCL::usage_string(char *iname, DataType *t, ParmList *l), | |
1034 | // | |
1035 | // Generates a generic usage string for a Tcl function. | |
1036 | // --------------------------------------------------------------------------- | |
1037 | ||
1038 | char * TCL::usage_string(char *iname, DataType *, ParmList *l) { | |
1039 | ||
1040 | static String temp; | |
1041 | Parm *p; | |
1042 | int i, numopt,pcount; | |
1043 | ||
1044 | temp = ""; | |
1045 | temp << iname << " "; | |
1046 | ||
1047 | /* Now go through and print parameters */ | |
1048 | i = 0; | |
1049 | pcount = l->nparms; | |
1050 | numopt = l->numopt(); | |
1051 | p = l->get_first(); | |
1052 | while (p != 0) { | |
1053 | ||
1054 | // Only print an argument if not ignored | |
1055 | ||
1056 | if (!typemap_check("ignore","tcl",p->t,p->name)) { | |
1057 | if (i >= (pcount-numopt)) | |
1058 | temp << "?"; | |
1059 | ||
1060 | /* If parameter has been named, use that. Otherwise, just print a type */ | |
1061 | ||
1062 | if ((p->t->type != T_VOID) || (p->t->is_pointer)) { | |
1063 | if (strlen(p->name) > 0) { | |
1064 | temp << p->name; | |
1065 | } | |
1066 | else { | |
1067 | temp << "{ " << p->t->print_type() << " }"; | |
1068 | } | |
1069 | } | |
1070 | if (i >= (pcount-numopt)) | |
1071 | temp << "?"; | |
1072 | temp << " "; | |
1073 | i++; | |
1074 | } | |
1075 | p = l->get_next(); | |
1076 | } | |
1077 | return temp; | |
1078 | } | |
1079 | ||
1080 | // --------------------------------------------------------------------------- | |
1081 | // char *TCL::usage_func(char *iname, DataType *t, ParmList *l), | |
1082 | // | |
1083 | // Produces a usage string for a function in Tcl | |
1084 | // --------------------------------------------------------------------------- | |
1085 | ||
1086 | char * TCL::usage_func(char *iname, DataType *t, ParmList *l) { | |
1087 | ||
1088 | String temp; | |
1089 | ||
1090 | if (nspace) { | |
1091 | temp << ns_name << "::" << iname; | |
1092 | } else { | |
1093 | temp << prefix << iname; | |
1094 | } | |
1095 | return usage_string(temp,t,l); | |
1096 | } | |
1097 | ||
1098 | // ----------------------------------------------------------------- | |
1099 | // TCL::usage_const(char *name, DataType *type, char *value) | |
1100 | // char **s) | |
1101 | // | |
1102 | // Makes a usage string and returns it | |
1103 | // ----------------------------------------------------------------- | |
1104 | ||
1105 | char *TCL::usage_const(char *name, DataType *, char *value) { | |
1106 | static String temp; | |
1107 | temp = ""; | |
1108 | if (nspace) { | |
1109 | temp << ns_name << "::" << name << " = " << value; | |
1110 | } else { | |
1111 | temp << "$" << prefix << name << " = " << value; | |
1112 | } | |
1113 | return temp; | |
1114 | } | |
1115 | ||
1116 | // ------------------------------------------------------------------- | |
1117 | // TCL::add_native(char *name, char *funcname) | |
1118 | // | |
1119 | // This adds an already written Tcl wrapper function to our | |
1120 | // initialization function. | |
1121 | // ------------------------------------------------------------------- | |
1122 | ||
1123 | ||
1124 | void TCL::add_native(char *name, char *funcname) { | |
1125 | ||
1126 | fprintf(f_init,"\t Tcl_CreateCommand(%s, SWIG_prefix \"%s\", %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n",interp_name, name, funcname); | |
1127 | ||
1128 | if (doc_entry) { | |
1129 | if (nspace) | |
1130 | doc_entry->usage << ns_name << "::" << name << " args"; | |
1131 | else | |
1132 | doc_entry->usage << prefix << name << " args"; | |
1133 | ||
1134 | doc_entry->cinfo << "Native method : " << funcname; | |
1135 | } | |
1136 | ||
1137 | } | |
1138 | ||
1139 | // ------------------------------------------------------------------- | |
1140 | // TCL::pragma(char *lname, char *name, char *value) | |
1141 | // | |
1142 | // This is an experimental %pragma handler. Officially unsupported | |
1143 | // in this release, but requested in e-mail. | |
1144 | // -------------------------------------------------------------------- | |
1145 | ||
1146 | void TCL::pragma(char *lname, char *name, char *) { | |
1147 | ||
1148 | if (strcmp(lname,"tcl") == 0) { | |
1149 | if (strcmp(name,"dynamic") == 0) { | |
1150 | char_result = "TCL_DYNAMIC"; | |
1151 | } else if (strcmp(name,"static") == 0) { | |
1152 | char_result = "TCL_STATIC"; | |
1153 | } else if (strcmp(name,"volatile") == 0) { | |
1154 | char_result = "TCL_VOLATILE"; | |
1155 | } | |
1156 | } | |
1157 | } | |
1158 | ||
1159 | ||
1160 | // --------------------------------------------------------------------- | |
1161 | // C++ Handling | |
1162 | // | |
1163 | // The following functions provide some support for C++ classes and | |
1164 | // C structs. | |
1165 | // --------------------------------------------------------------------- | |
1166 | ||
1167 | void TCL::cpp_open_class(char *classname, char *rename, char *ctype, int strip) { | |
1168 | char temp[256]; | |
1169 | this->Language::cpp_open_class(classname,rename,ctype,strip); | |
1170 | ||
1171 | if (shadow) { | |
1172 | ||
1173 | config = ""; | |
1174 | cget = ""; | |
1175 | methods = ""; | |
1176 | options = ""; | |
1177 | config_options = ""; | |
1178 | methodnames = ""; | |
1179 | ||
1180 | have_constructor = 0; | |
1181 | have_destructor = 0; | |
1182 | have_methods = 0; | |
1183 | have_config = 0; | |
1184 | have_cget = 0; | |
1185 | ||
1186 | if (rename) | |
1187 | class_name = copy_string(rename); | |
1188 | else | |
1189 | class_name = copy_string(classname); | |
1190 | ||
1191 | base_class = (char *) 0; | |
1192 | if (!strip) { | |
1193 | class_type = new char[strlen(ctype)+2]; | |
1194 | sprintf(class_type,"%s ", ctype); | |
1195 | } else | |
1196 | class_type = ""; | |
1197 | ||
1198 | real_classname = copy_string(classname); | |
1199 | ||
1200 | // Build up the hash table | |
1201 | ||
1202 | hash.add(real_classname,copy_string(class_name)); | |
1203 | sprintf(temp,"%s %s", class_type, real_classname); | |
1204 | hash.add(temp,copy_string(class_name)); | |
1205 | } | |
1206 | } | |
1207 | ||
1208 | void TCL::cpp_close_class() { | |
1209 | String code; | |
1210 | DataType *t; | |
1211 | String temp; | |
1212 | ||
1213 | this->Language::cpp_close_class(); | |
1214 | if (shadow) { | |
1215 | ||
1216 | t = new DataType; | |
1217 | sprintf(t->name,"%s%s", class_type, real_classname); | |
1218 | t->type = T_USER; | |
1219 | t->is_pointer = 1; | |
1220 | ||
1221 | // Note : The object oriented interface is defined by three files | |
1222 | // delcmd.swg - Object deletion wrapper | |
1223 | // methodcmd.swg - Method invocation command | |
1224 | // objcmd.swg - Command to create a new object | |
1225 | // | |
1226 | // These files are located in the SWIG library. This module | |
1227 | // grabs the files and performs marker replacements to | |
1228 | // build the wrapper function. | |
1229 | ||
1230 | // Generate a Tcl function for object destruction | |
1231 | ||
1232 | if (have_destructor) { | |
1233 | code << delcmd; | |
1234 | } | |
1235 | ||
1236 | // Dump out method code | |
1237 | code << methodcmd; | |
1238 | ||
1239 | // Dump out object creation command | |
1240 | code << objcmd; | |
1241 | ||
1242 | // Now perform marker replacements | |
1243 | code.replace("@CLASS@",class_name); | |
1244 | temp = ""; | |
1245 | temp << name_destroy(class_name); | |
1246 | code.replace("@DESTRUCTOR@",temp); | |
1247 | code.replace("@CLASSTYPE@",t->print_type()); | |
1248 | "configure " >> methodnames; | |
1249 | "cget " >> methodnames; | |
1250 | code.replace("@METHODLIST@", methodnames); | |
1251 | code.replace("@CLASSMANGLE@",t->print_mangle()); | |
1252 | code.replace("@METHODS@",methods); | |
1253 | code.replace("@CONFIGMETHODS@",config); | |
1254 | code.replace("@CGETMETHODS@",cget); | |
1255 | if (have_constructor) { | |
1256 | temp = ""; | |
1257 | temp << name_wrapper(name_construct(class_name),prefix); | |
1258 | } else { | |
1259 | temp = "0"; | |
1260 | } | |
1261 | code.replace("@TCLCONSTRUCTOR@",temp); | |
1262 | code.replace("@CONFIGLIST@",config_options); | |
1263 | code.replace("@CGETLIST@",options); | |
1264 | if (have_destructor) { | |
1265 | temp = "TclDelete"; | |
1266 | temp << class_name; | |
1267 | } else { | |
1268 | temp = "0"; | |
1269 | } | |
1270 | code.replace("@TCLDESTRUCTOR@",temp); | |
1271 | fprintf(f_wrappers,"%s\n", code.get()); | |
1272 | fprintf(f_init,"\t Tcl_CreateCommand(interp, SWIG_prefix \"%s\",Tcl%sCmd, (ClientData) NULL, NULL);\n", class_name, class_name); | |
1273 | } | |
1274 | } | |
1275 | ||
1276 | void TCL::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { | |
1277 | ||
1278 | char *realname; | |
1279 | String temp; | |
1280 | char *rname; | |
1281 | ||
1282 | this->Language::cpp_member_func(name,iname,t,l); | |
1283 | ||
1284 | if (shadow) { | |
1285 | if (iname) | |
1286 | realname = iname; | |
1287 | else | |
1288 | realname = name; | |
1289 | ||
1290 | // Add stubs for this member to our class handler function | |
1291 | ||
1292 | if (have_methods) | |
1293 | methods << tab4 << "else "; | |
1294 | else | |
1295 | methods << tab4; | |
1296 | ||
1297 | // Try to figure out if there is a wrapper for this function | |
1298 | ||
1299 | temp = ""; | |
1300 | temp << name_member(realname,class_name); | |
1301 | ||
1302 | rname = (char *) repeatcmd.lookup(temp); | |
1303 | ||
1304 | if (!rname) | |
1305 | rname = name_wrapper(temp.get(),prefix); | |
1306 | ||
1307 | methods << "if (strcmp(argv[1],\"" << realname << "\") == 0) {\n" | |
1308 | << tab4 << tab4 << "cmd = " << rname << ";\n" | |
1309 | << tab4 << "}"; | |
1310 | ||
1311 | have_methods = 1; | |
1312 | methodnames << realname << " "; | |
1313 | ||
1314 | if (doc_entry) { | |
1315 | doc_entry->usage = ""; | |
1316 | doc_entry->usage << usage_string(realname,t,l); | |
1317 | } | |
1318 | } | |
1319 | } | |
1320 | ||
1321 | void TCL::cpp_variable(char *name, char *iname, DataType *t) { | |
1322 | char *realname; | |
1323 | String temp, temp1; | |
1324 | char *rname; | |
1325 | ||
1326 | this->Language::cpp_variable(name, iname, t); | |
1327 | ||
1328 | if (shadow) { | |
1329 | if (iname) | |
1330 | realname = iname; | |
1331 | else | |
1332 | realname = name; | |
1333 | ||
1334 | // Write config code | |
1335 | ||
1336 | char *bc = class_name; | |
1337 | ||
1338 | if (!(Status & STAT_READONLY)) { | |
1339 | if (!have_config) { | |
1340 | config << tab8 << tab8; | |
1341 | } else { | |
1342 | config << " else "; | |
1343 | } | |
1344 | ||
1345 | temp = ""; | |
1346 | temp << name_set(name_member(realname,bc)); | |
1347 | rname = (char *) repeatcmd.lookup(temp); | |
1348 | if (!rname) | |
1349 | rname = name_wrapper(temp.get(),prefix); | |
1350 | ||
1351 | config << "if (strcmp(argv[i],\"-" << realname << "\") == 0) {\n" | |
1352 | << tab8 << tab8 << tab4 << "cmd = " << rname << ";\n" | |
1353 | << tab8 << tab8 << "} "; | |
1354 | ||
1355 | have_config = 1; | |
1356 | } | |
1357 | ||
1358 | // Write cget code | |
1359 | ||
1360 | if (!have_cget) { | |
1361 | cget << tab8 << tab8; | |
1362 | } else { | |
1363 | cget << " else "; | |
1364 | } | |
1365 | ||
1366 | // Try to figure out if there is a wrapper for this function | |
1367 | temp = ""; | |
1368 | temp << name_get(name_member(realname,bc)); | |
1369 | rname = (char *) repeatcmd.lookup(temp); | |
1370 | if (!rname) | |
1371 | rname = name_wrapper(temp.get(),prefix); | |
1372 | ||
1373 | cget << "if (strcmp(argv[2],\"-" << realname << "\") == 0) {\n" | |
1374 | << tab8 << tab8 << tab4 << "cmd = " << rname << ";\n" | |
1375 | << tab8 << tab8 << "} "; | |
1376 | have_cget = 1; | |
1377 | ||
1378 | options << "-" << realname << " "; | |
1379 | if (!(Status & STAT_READONLY)) { | |
1380 | config_options << "-" << realname << " "; | |
1381 | } | |
1382 | if (doc_entry){ | |
1383 | doc_entry->usage = ""; | |
1384 | doc_entry->usage << "-" << realname << "\n"; | |
1385 | } | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | void TCL::cpp_constructor(char *name, char *iname, ParmList *l) { | |
1390 | this->Language::cpp_constructor(name,iname,l); | |
1391 | ||
1392 | if (shadow) { | |
1393 | if ((!have_constructor) && (doc_entry)) { | |
1394 | doc_entry->usage = ""; | |
1395 | doc_entry->usage << class_name << usage_string(" name",0,l); | |
1396 | } | |
1397 | have_constructor = 1; | |
1398 | } | |
1399 | } | |
1400 | void TCL::cpp_destructor(char *name, char *newname) { | |
1401 | this->Language::cpp_destructor(name,newname); | |
1402 | if (shadow) { | |
1403 | if (!have_destructor) { | |
1404 | if (doc_entry) { | |
1405 | doc_entry->usage = "rename obj {}"; | |
1406 | } | |
1407 | } | |
1408 | have_destructor = 1; | |
1409 | } | |
1410 | } | |
1411 | ||
1412 | void TCL::cpp_inherit(char **baseclass, int) { | |
1413 | this->Language::cpp_inherit(baseclass); | |
1414 | } | |
1415 | ||
1416 | void TCL::cpp_declare_const(char *name, char *iname, DataType *type, char *value) { | |
1417 | this->Language::cpp_declare_const(name,iname,type,value); | |
1418 | } | |
1419 | ||
1420 | ||
1421 | // -------------------------------------------------------------------------------- | |
1422 | // TCL::add_typedef(DataType *t, char *name) | |
1423 | // | |
1424 | // This is called whenever a typedef is encountered. When shadow classes are | |
1425 | // used, this function lets us discovered hidden uses of a class. For example : | |
1426 | // | |
1427 | // struct FooBar { | |
1428 | // ... | |
1429 | // } | |
1430 | // | |
1431 | // typedef FooBar *FooBarPtr; | |
1432 | // | |
1433 | // -------------------------------------------------------------------------------- | |
1434 | ||
1435 | void TCL::add_typedef(DataType *t, char *name) { | |
1436 | ||
1437 | if (!shadow) return; | |
1438 | ||
1439 | // First check to see if there aren't too many pointers | |
1440 | ||
1441 | if (t->is_pointer > 1) return; | |
1442 | if (hash.lookup(name)) return; // Already added | |
1443 | ||
1444 | // Now look up the datatype in our shadow class hash table | |
1445 | ||
1446 | if (hash.lookup(t->name)) { | |
1447 | ||
1448 | // Yep. This datatype is in the hash | |
1449 | // Put this types 'new' name into the hash | |
1450 | hash.add(name,copy_string((char *) hash.lookup(t->name))); | |
1451 | } | |
1452 | } | |
1453 | ||
1454 | // ----------------------------------------------------------------------- | |
1455 | // TCL::cpp_class_decl(char *name, char *rename, char *type) | |
1456 | // | |
1457 | // Treatment of an empty class definition. Used to handle | |
1458 | // shadow classes across modules. | |
1459 | // ----------------------------------------------------------------------- | |
1460 | ||
1461 | void TCL::cpp_class_decl(char *name, char *rename, char *type) { | |
1462 | char temp[256]; | |
1463 | this->Language::cpp_class_decl(name,rename, type); | |
1464 | if (shadow) { | |
1465 | hash.add(name,copy_string(rename)); | |
1466 | // Add full name of datatype to the hash table | |
1467 | if (strlen(type) > 0) { | |
1468 | sprintf(temp,"%s %s", type, name); | |
1469 | hash.add(temp,copy_string(rename)); | |
1470 | } | |
1471 | } | |
1472 | } |