1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkTclUtil.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkObject.h"
17 #include "vtkTclUtil.h"
18 #include "vtkSetGet.h"
19 #include "vtkCallbackCommand.h"
20
21 #include <string>
22 #include <vtksys/SystemTools.hxx>
23
24 #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 6)
25 #define vtkTclGetErrorLine(m) (m->errorLine)
26 #else
27 #define vtkTclGetErrorLine(m) (Tcl_GetErrorLine(m))
28 #endif
29
30 extern "C"
31 {
32 #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)
33 typedef int (*vtkTclCommandType)(ClientData, Tcl_Interp *,int, CONST84 char *[]);
34 #else
35 typedef int (*vtkTclCommandType)(ClientData, Tcl_Interp *,int, char *[]);
36 #endif
37 }
38
vtkGetInterpStruct(Tcl_Interp * interp)39 vtkTclInterpStruct *vtkGetInterpStruct(Tcl_Interp *interp)
40 {
41 vtkTclInterpStruct *is = static_cast<vtkTclInterpStruct *>(Tcl_GetAssocData(interp,(char *)("vtk"),NULL));
42 if (!is)
43 {
44 vtkGenericWarningMacro("unable to find interp struct");
45 }
46 return is;
47 }
48
vtkTclInDelete(Tcl_Interp * interp)49 VTKTCL_EXPORT int vtkTclInDelete(Tcl_Interp *interp)
50 {
51 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
52 if (is)
53 {
54 return is->InDelete;
55 }
56 return 0;
57 }
58
59
60 // just another way into DeleteCommand
vtkTclDeleteObjectFromHash(vtkObject * obj,unsigned long vtkNotUsed (eventId),void * cd,void *)61 VTKTCL_EXPORT void vtkTclDeleteObjectFromHash(vtkObject *obj,
62 unsigned long vtkNotUsed(eventId),
63 void *cd, void *)
64 {
65 vtkTclCommandArgStruct *as = static_cast<vtkTclCommandArgStruct *>(cd);
66 char temps[80];
67 Tcl_HashEntry *entry;
68 char *temp;
69 vtkTclInterpStruct *is = vtkGetInterpStruct(as->Interp);
70
71 // lookup the objects name
72 sprintf(temps,"%p",obj);
73 entry = Tcl_FindHashEntry(&is->PointerLookup,temps);
74 if (entry)
75 {
76 temp = static_cast<char *>(Tcl_GetHashValue(entry));
77 if (temp)
78 {
79 Tcl_DeleteCommand(as->Interp,temp);
80 }
81 }
82 }
83
84 // we do no error checking in this. We assume that if we were called
85 // then tcl must have been able to find the command function and object.
vtkTclGenericDeleteObject(ClientData cd)86 VTKTCL_EXPORT void vtkTclGenericDeleteObject(ClientData cd)
87 {
88 char temps[80];
89 Tcl_HashEntry *entry;
90 int (*command)(ClientData, Tcl_Interp *,int, char *[]);
91 char *args[2];
92 char *temp;
93 vtkObject *tobject;
94 int error;
95 vtkTclCommandArgStruct *as = static_cast<vtkTclCommandArgStruct *>(cd);
96 Tcl_Interp *interp = as->Interp;
97 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
98
99 /* set up the args */
100 args[1] = (char *)("Delete");
101
102 // lookup the objects name
103 sprintf(temps,"%p",as->Pointer);
104 entry = Tcl_FindHashEntry(&is->PointerLookup,temps);
105 if (!entry)
106 {
107 return;
108 }
109
110 temp = static_cast<char *>(Tcl_GetHashValue(entry));
111 args[0] = temp;
112
113 // first we clear the delete callback since we will
114 // always remove this object from the hash regardless
115 // of if it has really been freed.
116 tobject = static_cast<vtkObject *>(
117 vtkTclGetPointerFromObject(temp,"vtkObject",
118 interp, error));
119 tobject->RemoveObserver(as->Tag);
120 as->Tag = 0;
121
122 // get the command function and invoke the delete operation
123 entry = Tcl_FindHashEntry(&is->CommandLookup,temp);
124 command = (int (*)(ClientData,Tcl_Interp *,int,char *[]))(
125 Tcl_GetHashValue(entry));
126
127 // do we need to delete the c++ obj
128 if (strncmp(temp,"vtkTemp",7))
129 {
130 is->InDelete = 1;
131 command(cd,interp,2,args);
132 is->InDelete = 0;
133 }
134
135 // the actual C++ object may not be freed yet. So we
136 // force it to be free from the hash table.
137 Tcl_DeleteHashEntry(entry);
138 entry = Tcl_FindHashEntry(&is->PointerLookup,temps);
139 Tcl_DeleteHashEntry(entry);
140 entry = Tcl_FindHashEntry(&is->InstanceLookup,temp);
141 Tcl_DeleteHashEntry(entry);
142 delete as;
143
144 if (is->DebugOn)
145 {
146 vtkGenericWarningMacro("vtkTcl Attempting to free object named " << temp);
147 }
148 if (temp)
149 {
150 free(temp);
151 }
152 }
153
vtkCreateCommand(ClientData vtkNotUsed (cd),Tcl_Interp * interp,int argc,char * argv[])154 int vtkCreateCommand(ClientData vtkNotUsed(cd), Tcl_Interp *interp, int argc, char *argv[])
155 {
156 Tcl_HashEntry *entry;
157 Tcl_HashSearch search;
158 char * tmp;
159 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
160
161 if (argc < 2)
162 {
163 return TCL_OK;
164 }
165
166 if (!strcmp(argv[1],"DeleteAllObjects"))
167 {
168 for (entry = Tcl_FirstHashEntry(&is->PointerLookup,&search);
169 entry != NULL;
170 entry = Tcl_FirstHashEntry(&is->PointerLookup,&search))
171 {
172 tmp = strdup(static_cast<char *>(Tcl_GetHashValue(entry)));
173 if (tmp)
174 {
175 Tcl_DeleteCommand(interp,tmp);
176 }
177 if (tmp)
178 {
179 free(tmp);
180 }
181 }
182 return TCL_OK;
183 }
184 if (!strcmp(argv[1],"ListAllInstances"))
185 {
186 for (entry = Tcl_FirstHashEntry(&is->InstanceLookup,&search);
187 entry != NULL; entry = Tcl_NextHashEntry(&search))
188 {
189 Tcl_AppendResult(interp,
190 static_cast<char *>(Tcl_GetHashKey(&is->InstanceLookup,entry)),NULL);
191 Tcl_AppendResult(interp,"\n",NULL);
192 }
193 return TCL_OK;
194 }
195 if (!strcmp(argv[1],"DebugOn"))
196 {
197 is->DebugOn = 1;
198 return TCL_OK;
199 }
200 if (!strcmp(argv[1],"DebugOff"))
201 {
202 is->DebugOn = 0;
203 return TCL_OK;
204 }
205 if (!strcmp(argv[1],"DeleteExistingObjectOnNewOn"))
206 {
207 is->DeleteExistingObjectOnNew = 1;
208 return TCL_OK;
209 }
210 if (!strcmp(argv[1],"DeleteExistingObjectOnNewOff"))
211 {
212 is->DeleteExistingObjectOnNew = 0;
213 return TCL_OK;
214 }
215 if (!strcmp("ListMethods",argv[1]))
216 {
217 Tcl_AppendResult(interp,"Methods for vtkCommand:\n",NULL);
218 Tcl_AppendResult(interp," DebugOn\n",NULL);
219 Tcl_AppendResult(interp," DebugOff\n",NULL);
220 Tcl_AppendResult(interp," DeleteAllObjects\n",NULL);
221 Tcl_AppendResult(interp," ListAllInstances\n",NULL);
222 Tcl_AppendResult(interp," DeleteExistingObjectOnNewOn\n",NULL);
223 Tcl_AppendResult(interp," DeleteExistingObjectOnNewOff\n",NULL);
224 return TCL_OK;
225 }
226
227 Tcl_AppendResult(interp,"invalid method for vtkCommand\n",NULL);
228 return TCL_ERROR;
229 }
230
231 VTKTCL_EXPORT void
vtkTclUpdateCommand(Tcl_Interp * interp,char * name,vtkObject * temp)232 vtkTclUpdateCommand(Tcl_Interp *interp, char *name, vtkObject *temp)
233 {
234 Tcl_CmdProc *command = NULL;
235
236 // check to see if we can find the command function based on class name
237 Tcl_CmdInfo cinf;
238 char *tstr = strdup(temp->GetClassName());
239 if (Tcl_GetCommandInfo(interp,tstr,&cinf))
240 {
241 if (cinf.clientData)
242 {
243 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cinf.clientData);
244 command = reinterpret_cast<Tcl_CmdProc *>(cs->CommandFunction);
245 }
246 }
247 if (tstr)
248 {
249 free(tstr);
250 }
251
252 // if not found then just return
253 if (!command)
254 {
255 return;
256 }
257
258 // is the current command the same
259 Tcl_CmdInfo cinfo;
260 Tcl_GetCommandInfo(interp, name, &cinfo);
261 cinfo.proc = command;
262 Tcl_SetCommandInfo(interp, name, &cinfo);
263
264 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
265 Tcl_HashEntry *entry = Tcl_FindHashEntry(&is->CommandLookup,name);
266 Tcl_SetHashValue(entry,(ClientData)(command));
267 }
268
269
270 VTKTCL_EXPORT void
vtkTclGetObjectFromPointer(Tcl_Interp * interp,void * temp1,const char * targetType)271 vtkTclGetObjectFromPointer(Tcl_Interp *interp, void *temp1,
272 const char *targetType)
273 {
274 int (*command)(ClientData, Tcl_Interp *,int, char *[]) = 0;
275 int is_new;
276 vtkObject *temp = static_cast<vtkObject *>(temp1);
277 char temps[80];
278 char name[80];
279 Tcl_HashEntry *entry;
280 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
281
282 /* if it is NULL then return empty string */
283 if (!temp)
284 {
285 Tcl_ResetResult(interp);
286 return;
287 }
288
289 /* return a pointer to a vtk Object */
290 if (is->DebugOn)
291 {
292 vtkGenericWarningMacro("Looking up name for vtk pointer: " << temp);
293 }
294
295 /* first we must look up the pointer to see if it already exists */
296 sprintf(temps,"%p",temp);
297 if ((entry = Tcl_FindHashEntry(&is->PointerLookup,temps)))
298 {
299 if (is->DebugOn)
300 {
301 vtkGenericWarningMacro("Found name: "
302 << static_cast<char *>(Tcl_GetHashValue(entry))
303 << " for vtk pointer: " << temp);
304 }
305
306 /* while we are at it store the name since it is required anyhow */
307 Tcl_SetResult(interp, static_cast<char *>(Tcl_GetHashValue(entry)), TCL_VOLATILE);
308 return;
309 }
310
311 /* we must create a new name if it isn't NULL */
312 sprintf(name,"vtkTemp%i",is->Number);
313 is->Number++;
314
315 if (is->DebugOn)
316 {
317 vtkGenericWarningMacro("Created name: " << name
318 << " for vtk pointer: " << temp);
319 }
320
321 // check to see if we can find the command function based on class name
322 Tcl_CmdInfo cinf;
323 char *tstr = strdup(temp->GetClassName());
324 if (Tcl_GetCommandInfo(interp,tstr,&cinf))
325 {
326 if (cinf.clientData)
327 {
328 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cinf.clientData);
329 command = cs->CommandFunction;
330 }
331 }
332 // if the class command wasn;t found try the target return type command
333 if (!command && targetType)
334 {
335 if (tstr)
336 {
337 free(tstr);
338 }
339 tstr = strdup(targetType);
340 if (Tcl_GetCommandInfo(interp,tstr,&cinf))
341 {
342 if (cinf.clientData)
343 {
344 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cinf.clientData);
345 command = cs->CommandFunction;
346 }
347 }
348 }
349 // if we still do not havbe a match then try vtkObject
350 if (!command)
351 {
352 if (tstr)
353 {
354 free(tstr);
355 }
356 tstr = strdup("vtkObject");
357 if (Tcl_GetCommandInfo(interp,tstr,&cinf))
358 {
359 if (cinf.clientData)
360 {
361 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cinf.clientData);
362 command = cs->CommandFunction;
363 }
364 }
365 }
366 if (tstr)
367 {
368 free(tstr);
369 }
370
371 entry = Tcl_CreateHashEntry(&is->InstanceLookup,name,&is_new);
372 Tcl_SetHashValue(entry,static_cast<ClientData>(temp));
373 entry = Tcl_CreateHashEntry(&is->PointerLookup,temps,&is_new);
374 Tcl_SetHashValue(entry,static_cast<ClientData>(strdup(name)));
375 vtkTclCommandArgStruct *as = new vtkTclCommandArgStruct;
376 as->Pointer = static_cast<void *>(temp);
377 as->Interp = interp;
378 Tcl_CreateCommand(interp,name,
379 reinterpret_cast<vtkTclCommandType>(command),
380 static_cast<ClientData>(as),
381 reinterpret_cast<Tcl_CmdDeleteProc *>(vtkTclGenericDeleteObject));
382 entry = Tcl_CreateHashEntry(&is->CommandLookup,name,&is_new);
383 Tcl_SetHashValue(entry,(ClientData)(command));
384
385 // setup the delete callback
386 vtkCallbackCommand *cbc = vtkCallbackCommand::New();
387 cbc->SetCallback(vtkTclDeleteObjectFromHash);
388 cbc->SetClientData(static_cast<void *>(as));
389 as->Tag = temp->AddObserver(vtkCommand::DeleteEvent, cbc);
390 cbc->Delete();
391
392 Tcl_SetResult(interp, static_cast<char *>(name), TCL_VOLATILE);
393 }
394
vtkTclGetPointerFromObject(const char * name,const char * result_type,Tcl_Interp * interp,int & error)395 VTKTCL_EXPORT void *vtkTclGetPointerFromObject(const char *name,
396 const char *result_type,
397 Tcl_Interp *interp,
398 int &error)
399 {
400 Tcl_HashEntry *entry;
401 ClientData temp;
402 int (*command)(ClientData, Tcl_Interp *,int, char *[]);
403 char *args[3];
404 char temps[256];
405 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
406
407 /* check for empty string, empty string is the same as passing NULL */
408 if (name[0] == '\0')
409 {
410 return NULL;
411 }
412
413 // object names cannot start with a number
414 if ((name[0] >= '0')&&(name[0] <= '9'))
415 {
416 error = 1;
417 return NULL;
418 }
419
420 if ((entry = Tcl_FindHashEntry(&is->InstanceLookup,name)))
421 {
422 temp = static_cast<ClientData>(Tcl_GetHashValue(entry));
423 }
424 else
425 {
426 sprintf(temps,"vtk bad argument, could not find object named %s\n", name);
427 Tcl_AppendResult(interp,temps,NULL);
428 error = 1;
429 return NULL;
430 }
431
432 /* now handle the typecasting, get the command proc */
433 if ((entry = Tcl_FindHashEntry(&is->CommandLookup,name)))
434 {
435 command = (int (*)(ClientData,Tcl_Interp *,int,char *[]))(
436 Tcl_GetHashValue(entry));
437 }
438 else
439 {
440 sprintf(temps,"vtk bad argument, could not find command process for %s.\n", name);
441 Tcl_AppendResult(interp,temps,NULL);
442 error = 1;
443 return NULL;
444 }
445
446 /* set up the args */
447 args[0] = (char *)("DoTypecasting");
448 args[1] = strdup(result_type);
449 args[2] = NULL;
450 vtkTclCommandArgStruct foo;
451 foo.Pointer = temp;
452 foo.Interp = interp;
453 if (command(static_cast<ClientData>(&foo),static_cast<Tcl_Interp *>(NULL),3,args) == TCL_OK)
454 {
455 free (args[1]);
456 return static_cast<void *>(args[2]);
457 }
458 else
459 {
460 Tcl_Interp *i;
461 i = Tcl_CreateInterp();
462 // provide more diagnostic info
463 args[0] = (char *)("Dummy");
464 free (args[1]);
465 args[1] = (char *)("GetClassName");
466 args[2] = NULL;
467 command(static_cast<ClientData>(&foo),i,2,args);
468
469 sprintf(temps,"vtk bad argument, type conversion failed for object %s.\nCould not type convert %s which is of type %s, to type %s.\n", name, name, Tcl_GetStringResult(i), result_type);
470 Tcl_AppendResult(interp,temps,NULL);
471 error = 1;
472 Tcl_DeleteInterp(i);
473 return NULL;
474 }
475
476 }
477
vtkTclVoidFunc(void * arg)478 VTKTCL_EXPORT void vtkTclVoidFunc(void *arg)
479 {
480 int res;
481
482 vtkTclVoidFuncArg *arg2;
483
484 arg2 = static_cast<vtkTclVoidFuncArg *>(arg);
485
486 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 2
487 res = Tcl_GlobalEval(arg2->interp, arg2->command);
488 #else
489 res = Tcl_EvalEx(arg2->interp, arg2->command, -1, TCL_EVAL_GLOBAL);
490 #endif
491
492 if (res == TCL_ERROR)
493 {
494 if (Tcl_GetVar(arg2->interp,(char *)("errorInfo"),0))
495 {
496 vtkGenericWarningMacro("Error returned from vtk/tcl callback:\n" <<
497 arg2->command << endl <<
498 Tcl_GetVar(arg2->interp,(char *)("errorInfo"),0) <<
499 " at line number " <<
500 vtkTclGetErrorLine(arg2->interp));
501 }
502 else
503 {
504 vtkGenericWarningMacro("Error returned from vtk/tcl callback:\n" <<
505 arg2->command << endl <<
506 " at line number " <<
507 vtkTclGetErrorLine(arg2->interp));
508 }
509 }
510 }
511
vtkTclVoidFuncArgDelete(void * arg)512 VTKTCL_EXPORT void vtkTclVoidFuncArgDelete(void *arg)
513 {
514 vtkTclVoidFuncArg *arg2;
515
516 arg2 = static_cast<vtkTclVoidFuncArg *>(arg);
517
518 // free the string and then structure
519 delete [] arg2->command;
520 delete arg2;
521 }
522
vtkTclListInstances(Tcl_Interp * interp,ClientData arg)523 VTKTCL_EXPORT void vtkTclListInstances(Tcl_Interp *interp, ClientData arg)
524 {
525 Tcl_HashSearch srch;
526 Tcl_HashEntry *entry;
527 int first = 1;
528 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
529
530 // iteratively search hash table for command function
531 entry = Tcl_FirstHashEntry(&is->CommandLookup, &srch);
532 if (!entry)
533 {
534 Tcl_ResetResult(interp);
535 return;
536 }
537 while (entry)
538 {
539 if (Tcl_GetHashValue(entry) == arg)
540 {
541 if (first)
542 {
543 first = 0;
544 Tcl_AppendResult(interp,Tcl_GetHashKey(&is->CommandLookup,entry),NULL);
545 }
546 else
547 {
548 Tcl_AppendResult(interp, " ", Tcl_GetHashKey(&is->CommandLookup,entry),
549 NULL);
550 }
551 }
552 entry = Tcl_NextHashEntry(&srch);
553 }
554 }
555
556
vtkTclNewInstanceCommand(ClientData cd,Tcl_Interp * interp,int argc,char * argv[])557 int vtkTclNewInstanceCommand(ClientData cd, Tcl_Interp *interp,
558 int argc, char *argv[])
559 {
560 int (*command)(ClientData, Tcl_Interp *,int, char *[]);
561 Tcl_HashEntry *entry;
562 int is_new;
563 char temps[80];
564 char name[80];
565 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cd);
566 Tcl_CmdInfo cinf;
567 vtkTclInterpStruct *is = vtkGetInterpStruct(interp);
568
569 if (argc != 2)
570 {
571 Tcl_SetResult(interp, (char *)("vtk object creation requires one argument, a name, or the special New keyword to instantiate a new name."), TCL_VOLATILE);
572 return TCL_ERROR;
573 }
574
575 if ((argv[1][0] >= '0')&&(argv[1][0] <= '9'))
576 {
577 Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
578 Tcl_AppendResult(interp, ": vtk object cannot start with a numeric.", NULL);
579 return TCL_ERROR;
580 }
581
582 if (Tcl_FindHashEntry(&is->InstanceLookup,argv[1]))
583 {
584 if (is->DeleteExistingObjectOnNew)
585 {
586 Tcl_DeleteCommand(interp, argv[1]);
587 }
588 else
589 {
590 Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
591 Tcl_AppendResult(interp,
592 ": a vtk object with that name already exists.",
593 NULL);
594 return TCL_ERROR;
595 }
596 }
597
598 // Make sure we are not clobbering a built in command
599 if (Tcl_GetCommandInfo(interp,argv[1],&cinf))
600 {
601 Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
602 Tcl_AppendResult(interp,
603 ": a tcl/tk command with that name already exists.",
604 NULL);
605 return TCL_ERROR;
606 }
607
608 ClientData temp;
609 if (!strcmp("ListInstances",argv[1]))
610 {
611 vtkTclListInstances(interp,(ClientData)(cs->CommandFunction));
612 return TCL_OK;
613 }
614
615 if (!strcmp("New",argv[1]))
616 {
617 sprintf(name,"vtkObj%i",is->Number);
618 is->Number++;
619 argv[1] = name;
620 }
621
622 temp = cs->NewCommand();
623
624 if (!temp)
625 {
626 Tcl_SetResult(interp, argv[0], TCL_VOLATILE);
627 Tcl_AppendResult(interp,
628 ": no implementation exists for this class.",
629 NULL);
630 return TCL_ERROR;
631 }
632
633 entry = Tcl_CreateHashEntry(&is->InstanceLookup,argv[1],&is_new);
634 Tcl_SetHashValue(entry,temp);
635 sprintf(temps,"%p",static_cast<void *>(temp));
636 entry = Tcl_CreateHashEntry(&is->PointerLookup,temps,&is_new);
637 Tcl_SetHashValue(entry,static_cast<ClientData>(strdup(argv[1])));
638
639 // check to see if we can find the command function based on class name
640 char *tstr = strdup(static_cast<vtkObject *>(temp)->GetClassName());
641 if (Tcl_GetCommandInfo(interp,tstr,&cinf))
642 {
643 if (cinf.clientData)
644 {
645 vtkTclCommandStruct *cs2 =
646 static_cast<vtkTclCommandStruct *>(cinf.clientData);
647 command = cs2->CommandFunction;
648 }
649 else
650 {
651 command = cs->CommandFunction;
652 }
653 }
654 else
655 {
656 command = cs->CommandFunction;
657 }
658 if (tstr)
659 {
660 free(tstr);
661 }
662
663 vtkTclCommandArgStruct *as = new vtkTclCommandArgStruct;
664 as->Pointer = static_cast<void *>(temp);
665 as->Interp = interp;
666 Tcl_CreateCommand(interp,argv[1],
667 reinterpret_cast<vtkTclCommandType>(command),
668 static_cast<ClientData>(as),
669 reinterpret_cast<Tcl_CmdDeleteProc *>(vtkTclGenericDeleteObject));
670 entry = Tcl_CreateHashEntry(&is->CommandLookup,argv[1],&is_new);
671 Tcl_SetHashValue(entry,(ClientData)(cs->CommandFunction));
672
673 // setup the delete callback
674 vtkCallbackCommand *cbc = vtkCallbackCommand::New();
675 cbc->SetCallback(vtkTclDeleteObjectFromHash);
676 cbc->SetClientData(static_cast<void *>(as));
677 as->Tag =
678 static_cast<vtkObject *>(temp)->AddObserver(vtkCommand::DeleteEvent, cbc);
679 cbc->Delete();
680
681 Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
682 return TCL_OK;
683 }
684
vtkTclDeleteCommandStruct(ClientData cd)685 void vtkTclDeleteCommandStruct(ClientData cd)
686 {
687 vtkTclCommandStruct *cs = static_cast<vtkTclCommandStruct *>(cd);
688 delete cs;
689 }
690
vtkTclCreateNew(Tcl_Interp * interp,const char * cname,ClientData (* NewCommand)(),int (* CommandFunction)(ClientData cd,Tcl_Interp * interp,int argc,char * argv[]))691 void vtkTclCreateNew(Tcl_Interp *interp, const char *cname,
692 ClientData (*NewCommand)(),
693 int (*CommandFunction)(ClientData cd,
694 Tcl_Interp *interp,
695 int argc, char *argv[]))
696 {
697 vtkTclCommandStruct *cs = new vtkTclCommandStruct;
698 cs->NewCommand = NewCommand;
699 cs->CommandFunction = CommandFunction;
700 Tcl_CreateCommand(
701 interp,const_cast<char *>(cname),
702 reinterpret_cast<vtkTclCommandType>(
703 vtkTclNewInstanceCommand),
704 reinterpret_cast<ClientData *>(cs),
705 reinterpret_cast<Tcl_CmdDeleteProc *>(vtkTclDeleteCommandStruct));
706 }
707
708
vtkTclCommand()709 vtkTclCommand::vtkTclCommand()
710 {
711 this->Interp = NULL;
712 this->StringCommand = NULL;
713 }
714
~vtkTclCommand()715 vtkTclCommand::~vtkTclCommand()
716 {
717 if(this->StringCommand) { delete [] this->StringCommand; }
718 }
719
SetStringCommand(const char * arg)720 void vtkTclCommand::SetStringCommand(const char *arg)
721 {
722 if(this->StringCommand) { delete [] this->StringCommand; }
723 this->StringCommand = new char[strlen(arg)+1];
724 strcpy(this->StringCommand, arg);
725 }
726
Execute(vtkObject *,unsigned long,void *)727 void vtkTclCommand::Execute(vtkObject *, unsigned long, void *)
728 {
729 int res;
730 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 2
731 res = Tcl_GlobalEval(this->Interp, this->StringCommand);
732 #else
733 res = Tcl_EvalEx(this->Interp, this->StringCommand, -1, TCL_EVAL_GLOBAL);
734 #endif
735
736 if (res == TCL_ERROR)
737 {
738 if (Tcl_GetVar(this->Interp,(char *)("errorInfo"),0))
739 {
740 vtkGenericWarningMacro("Error returned from vtk/tcl callback:\n" <<
741 this->StringCommand << endl <<
742 Tcl_GetVar(this->Interp,(char *)("errorInfo"),0) <<
743 " at line number " <<
744 vtkTclGetErrorLine(this->Interp));
745 }
746 else
747 {
748 vtkGenericWarningMacro("Error returned from vtk/tcl callback:\n" <<
749 this->StringCommand << endl <<
750 " at line number " <<
751 vtkTclGetErrorLine(this->Interp));
752 }
753 }
754 else if (res == -1)
755 {
756 this->AbortFlagOn();
757 }
758 }
759
vtkTclApplicationInitExecutable(int vtkNotUsed (argc),const char * const argv[])760 void vtkTclApplicationInitExecutable(int vtkNotUsed(argc),
761 const char* const argv[])
762 {
763 std::string av0 = argv[0];
764
765 if (vtksys::SystemTools::FileIsFullPath(argv[0]))
766 {
767 av0 = vtksys::SystemTools::CollapseFullPath(argv[0]);
768 }
769 Tcl_FindExecutable(av0.c_str());
770 }
771
772 // We need two internal Tcl functions. They usually are declared in
773 // tclIntDecls.h, but UNIX builds do not have access to VTK's
774 // tkInternals include path. Since the signature has not changed for
775 // years (at least since 8.2), let's just prototype them.
776 EXTERN Tcl_Obj* TclGetLibraryPath _ANSI_ARGS_((void));
777 EXTERN void TclSetLibraryPath _ANSI_ARGS_((Tcl_Obj * pathPtr));
778
vtkTclApplicationInitTclTk(Tcl_Interp * interp,const char * const relative_dirs[])779 void vtkTclApplicationInitTclTk(Tcl_Interp* interp,
780 const char* const relative_dirs[])
781 {
782 /*
783 Tcl/Tk requires support files to work (set of tcl files).
784 When an app is linked against Tcl/Tk shared libraries, the path to
785 the libraries is used by Tcl/Tk to search for its support files.
786 For example, on Windows, if bin/tcl84.dll is the shared lib, support
787 files will be searched in bin/../lib/tcl8.4, which is where they are
788 usually installed.
789 If an app is linked against Tcl/Tk *static* libraries, there is no
790 way for Tcl/Tk to find its support files. In that case, it will
791 use the TCL_LIBRARY and TK_LIBRARY environment variable (those should
792 point to the support files dir, ex: c:/tcl/lib/tcl8.4, c:/tk/lib/tcl8.4).
793
794 The above code will also make Tcl/Tk search inside VTK's build/install
795 directory, more precisely inside a TclTk/lib sub dir.
796 ex: [path to vtk.exe]/TclTk/lib/tcl8.4, [path to vtk.exe]/TclTk/lib/tk8.4
797 Support files are copied to that location when
798 VTK_TCL_TK_COPY_SUPPORT_LIBRARY is ON.
799 */
800
801 int has_tcllibpath_env = getenv("TCL_LIBRARY") ? 1 : 0;
802 int has_tklibpath_env = getenv("TK_LIBRARY") ? 1 : 0;
803 std::string selfdir;
804 if(!has_tcllibpath_env || !has_tklibpath_env)
805 {
806 const char* nameofexec = Tcl_GetNameOfExecutable();
807 if(nameofexec && vtksys::SystemTools::FileExists(nameofexec))
808 {
809 std::string name = nameofexec;
810 vtksys::SystemTools::ConvertToUnixSlashes(name);
811 selfdir = vtksys::SystemTools::GetFilenamePath(name);
812 }
813 }
814 if(selfdir.length() > 0)
815 {
816 if(!has_tcllibpath_env)
817 {
818 std::string tdir;
819 for(const char* const* p = relative_dirs; *p; ++p)
820 {
821 tdir = selfdir;
822 tdir += "/";
823 tdir += *p;
824 tdir += "/tcl" TCL_VERSION;
825 tdir = vtksys::SystemTools::CollapseFullPath(tdir.c_str());
826 if(vtksys::SystemTools::FileExists(tdir.c_str()) &&
827 vtksys::SystemTools::FileIsDirectory(tdir.c_str()))
828 {
829 // Set the tcl_library Tcl variable.
830 char tcl_library[1024];
831 strcpy(tcl_library, tdir.c_str());
832 Tcl_SetVar(interp, "tcl_library", tcl_library,
833 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
834 break;
835 }
836 }
837 }
838 if(!has_tklibpath_env)
839 {
840 std::string tdir;
841 for(const char* const* p = relative_dirs; *p; ++p)
842 {
843 tdir = selfdir;
844 tdir += "/";
845 tdir += *p;
846 tdir += "/tk" TCL_VERSION;
847 tdir = vtksys::SystemTools::CollapseFullPath(tdir.c_str());
848 if(vtksys::SystemTools::FileExists(tdir.c_str()) &&
849 vtksys::SystemTools::FileIsDirectory(tdir.c_str()))
850 {
851 // Set the tk_library Tcl variable.
852 char tk_library[1024];
853 strcpy(tk_library, tdir.c_str());
854 Tcl_SetVar(interp, "tk_library", tk_library,
855 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
856 break;
857 }
858 }
859 }
860 }
861 }
862