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