1 // Created on: 1995-02-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
23 #include <Draw_Interpretor.ixx>
24 #include <Draw_Appli.hxx>
25 #include <Standard_SStream.hxx>
26 #include <Standard_RangeError.hxx>
27 #include <Standard_ErrorHandler.hxx>
28 #include <Standard_Macro.hxx>
30 #include <TCollection_AsciiString.hxx>
31 #include <TCollection_ExtendedString.hxx>
32 #include <OSD_Path.hxx>
37 // for capturing of cout and cerr (dup(), dup2())
45 #if ! defined(STDOUT_FILENO)
46 #define STDOUT_FILENO fileno(stdout)
48 #if ! defined(STDERR_FILENO)
49 #define STDERR_FILENO fileno(stderr)
52 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
57 // Auxiliary tool to convert strings in command arguments from UTF-8
58 // (Tcl internal encoding since Tcl 8.1) to system local encoding,
59 // normally extended Ascii as expected by OCC commands
61 class TclUTFToLocalStringSentry {
65 TclUTFToLocalStringSentry (int argc, const char **argv) :
67 TclArgv(new Tcl_DString[argc]),
70 for (; nb < argc; nb++ ) {
71 Tcl_UtfToExternalDString ( NULL, argv[nb], -1, &TclArgv[nb] );
72 Argv[nb] = Tcl_DStringValue ( &TclArgv[nb] );
76 ~TclUTFToLocalStringSentry ()
79 while ( nb-- >0 ) Tcl_DStringFree ( &TclArgv[nb] );
83 TclUTFToLocalStringSentry (int, const char **argv) : Argv((char**)argv) {}
86 const char **GetArgv () const { return (const char **)Argv; }
100 CData(Draw_CommandFunction ff, Draw_Interpretor* ii) : f(ff), i(ii) {}
101 Draw_CommandFunction f;
107 void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
109 for (int i=0; i < argc; i++)
110 os << argv[i] << " ";
114 void flush_standard_streams ()
122 FILE* capture_start (int std_fd, int *save_fd)
126 // open temporary files
127 FILE * aTmpFile = tmpfile();
128 int fd_tmp = fileno(aTmpFile);
132 cerr << "Error: cannot create temporary file for capturing console output" << endl;
137 // remember current file descriptors of standard stream, and replace it by temporary
138 (*save_fd) = dup(std_fd);
139 dup2(fd_tmp, std_fd);
143 void capture_end (FILE* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
145 // restore normal descriptors of console stream
146 dup2 (save_fd, std_fd);
149 // extract all output and copy it to log and optionally to cout
150 const int BUFSIZE = 2048;
153 while (fgets (buf, BUFSIZE, tmp_file) != NULL)
160 // close temporary file
166 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
167 static Standard_Integer CommandCmd
168 (ClientData clientData, Tcl_Interp *interp,
169 Standard_Integer argc, const char* argv[])
171 static Standard_Integer CommandCmd
172 (ClientData clientData, Tcl_Interp *interp,
173 Standard_Integer argc, char* argv[])
176 static Standard_Integer code;
178 CData* C = (CData*) clientData;
179 Draw_Interpretor& di = *(C->i);
181 // log command execution, except commands manipulating log itself and echo
182 Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
183 strcmp (argv[0], "decho") == 0);
184 Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
185 Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
187 dumpArgs (di.Log(), argc, argv);
189 dumpArgs (cout, argc, argv);
191 // flush cerr and cout
192 flush_standard_streams();
194 // capture cout and cerr to log
195 FILE * aFile_err = NULL;
196 FILE * aFile_out = NULL;
201 aFile_out = capture_start (STDOUT_FILENO, &fd_out_save);
202 aFile_err = capture_start (STDERR_FILENO, &fd_err_save);
209 // OCC63: Convert strings from UTF-8 to local encoding, normally expected by OCC commands
210 TclUTFToLocalStringSentry anArgs ( argc, (const char**)argv );
212 Standard_Integer fres = C->f ( di, argc, anArgs.GetArgv() );
216 catch (Standard_Failure) {
218 Handle(Standard_Failure) E = Standard_Failure::Caught();
220 // fail if Draw_ExitOnCatch is set
222 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
223 const char* cc = Tcl_GetVar(interp,
224 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
226 char* const cc = Tcl_GetVar(interp,
227 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
230 cout << "An exception was caught " << E << endl;
232 if (cc && atoi(cc)) {
236 Tcl_Eval(interp,"exit");
240 // get the error message
242 ss << "** Exception ** " << E << ends ;
243 #ifdef USE_STL_STREAM
244 Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
246 Tcl_SetResult(interp,(char*)(ss.str()),TCL_VOLATILE);
252 flush_standard_streams();
254 // end capturing cout and cerr
257 capture_end (aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
258 capture_end (aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
261 // log command result
262 const char* aResultStr = NULL;
265 aResultStr = Tcl_GetStringResult (interp);
266 if (aResultStr != 0 && aResultStr[0] != '\0' )
267 di.Log() << Tcl_GetStringResult (interp) << endl;
271 if (aResultStr == NULL)
272 aResultStr = Tcl_GetStringResult (interp);
273 if (aResultStr != 0 && aResultStr[0] != '\0' )
274 cout << Tcl_GetStringResult (interp) << endl;
281 static void CommandDelete (ClientData clientData)
283 CData *C = (CData*) clientData;
287 //=======================================================================
288 //function : Draw_Interpretor
290 //=======================================================================
292 Draw_Interpretor::Draw_Interpretor() :
293 isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
295 // The tcl interpreter is not created immediately as it is kept
296 // by a global variable and created and deleted before the main().
300 //=======================================================================
302 //purpose : It is necessary to call this function
303 //=======================================================================
305 void Draw_Interpretor::Init()
308 Tcl_DeleteInterp(myInterp);
309 isAllocated=Standard_True;
310 myInterp=Tcl_CreateInterp();
313 //=======================================================================
314 //function : Draw_Interpretor
316 //=======================================================================
318 Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
319 isAllocated(Standard_False),
321 myDoLog(Standard_False),
322 myDoEcho(Standard_False)
326 //=======================================================================
329 //=======================================================================
331 void Draw_Interpretor::Add(const Standard_CString n,
332 const Standard_CString help,
333 const Draw_CommandFunction f,
334 const Standard_CString group)
336 //void Draw_Interpretor::Add(const Standard_CString n,
337 // const Standard_CString help,
338 // const Draw_CommandFunction& f,
339 // const Standard_CString group)
342 Standard_PCharacter pN, pHelp, pGroup;
344 pN=(Standard_PCharacter)n;
345 pHelp=(Standard_PCharacter)help;
346 pGroup=(Standard_PCharacter)group;
348 if (myInterp==NULL) Init();
350 CData* C = new CData(f,this);
352 Tcl_CreateCommand(myInterp, pN ,CommandCmd, (ClientData) C, CommandDelete);
355 Tcl_SetVar2(myInterp,"Draw_Helps", pN, pHelp, TCL_GLOBAL_ONLY);
356 Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
357 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
359 //=======================================================================
362 //=======================================================================
363 void Draw_Interpretor::Add(const Standard_CString n,
364 const Standard_CString help,
365 const Standard_CString file_name,
366 const Draw_CommandFunction f,
367 const Standard_CString group)
369 Standard_PCharacter pN, pHelp, pGroup, pFileName;
371 pN=(Standard_PCharacter)n;
372 pHelp=(Standard_PCharacter)help;
373 pGroup=(Standard_PCharacter)group;
374 pFileName=(Standard_PCharacter)file_name;
376 if (myInterp==NULL) Init();
378 CData* C = new CData(f,this);
379 Tcl_CreateCommand(myInterp,pN,CommandCmd, (ClientData) C, CommandDelete);
382 Tcl_SetVar2(myInterp,"Draw_Helps",pN,pHelp,TCL_GLOBAL_ONLY);
383 Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
384 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
386 // add path to source file (keep not more than two last subdirectories)
387 OSD_Path aPath (pFileName);
388 Standard_Integer nbTrek = aPath.TrekLength();
389 for (Standard_Integer i = 2; i < nbTrek; i++)
390 aPath.RemoveATrek (1);
393 TCollection_AsciiString aSrcPath;
394 aPath.SystemName (aSrcPath);
395 Tcl_SetVar2(myInterp,"Draw_Files",pN,aSrcPath.ToCString(),TCL_GLOBAL_ONLY);
399 //=======================================================================
402 //=======================================================================
404 Standard_Boolean Draw_Interpretor::Remove(Standard_CString const n)
406 Standard_PCharacter pN;
408 pN=(Standard_PCharacter)n;
410 Standard_Integer result = Tcl_DeleteCommand(myInterp,pN);
414 //=======================================================================
417 //=======================================================================
419 Standard_CString Draw_Interpretor::Result() const
421 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
422 return Tcl_GetStringResult(myInterp);
424 return myInterp->result;
428 //=======================================================================
431 //=======================================================================
433 void Draw_Interpretor::Reset()
435 Tcl_ResetResult(myInterp);
438 //=======================================================================
441 //=======================================================================
443 Draw_Interpretor& Draw_Interpretor::Append(const Standard_CString s)
446 // Convert string to UTF-8 format for Tcl
447 Tcl_DString TclString;
448 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
449 Tcl_AppendResult ( myInterp, Tcl_DStringValue ( &TclString ), (Standard_CString)0 );
450 Tcl_DStringFree ( &TclString );
452 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
457 //=======================================================================
460 //=======================================================================
462 Draw_Interpretor& Draw_Interpretor::Append(const TCollection_AsciiString& s)
464 return Append (s.ToCString());
467 //=======================================================================
470 //=======================================================================
472 Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& theString)
475 // Convert string to UTF-8 format for Tcl
476 char *str = new char[theString.LengthOfCString()+1];
477 theString.ToUTF8CString (str);
478 Tcl_AppendResult ( myInterp, str, (Standard_CString)0 );
481 // put as ascii string, replacing non-ascii characters by '?'
482 TCollection_AsciiString str (theString, '?');
483 Tcl_AppendResult(myInterp,str.ToCString(),(Standard_CString)0);
488 //=======================================================================
491 //=======================================================================
493 Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
497 Tcl_AppendResult(myInterp,c,(Standard_CString)0);
501 //=======================================================================
504 //=======================================================================
506 Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
509 sprintf(s,"%.17g",r);
510 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
514 //=======================================================================
517 //=======================================================================
519 Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
521 #ifdef USE_STL_STREAM
522 return Append (s.str().c_str());
524 // Note: use dirty tricks -- unavoidable with old streams
525 TCollection_AsciiString aStr (((Standard_SStream&)AReason).str(), AReason.pcount());
526 ((Standard_SStream&)AReason).freeze (false);
527 return Append (aStr.ToCString());
531 //=======================================================================
532 //function : AppendElement
534 //=======================================================================
536 void Draw_Interpretor::AppendElement(const Standard_CString s)
539 // Convert string to UTF-8 format for Tcl
540 Tcl_DString TclString;
541 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
542 Tcl_AppendElement ( myInterp, Tcl_DStringValue ( &TclString ) );
543 Tcl_DStringFree ( &TclString );
546 //AppendElement is declared as (Tcl_Interp *interp, char *string)
548 Tcl_AppendElement(myInterp,(char*) s);
550 Tcl_AppendElement(myInterp, s);
555 //=======================================================================
558 //=======================================================================
560 Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
562 Standard_PCharacter pLine;
564 pLine=(Standard_PCharacter)line;
566 return Tcl_Eval(myInterp,pLine);
570 //=======================================================================
573 //=======================================================================
575 Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
576 const Standard_Integer flags)
578 Standard_PCharacter pLine;
580 pLine=(Standard_PCharacter)line;
581 return Tcl_RecordAndEval(myInterp,pLine,flags);
584 //=======================================================================
585 //function : EvalFile
587 //=======================================================================
589 Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
591 Standard_PCharacter pfname;
593 pfname=(Standard_PCharacter)fname;
594 return Tcl_EvalFile(myInterp,pfname);
597 //=======================================================================
600 //=======================================================================
602 Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line)
604 Standard_PCharacter pLine;
606 pLine=(Standard_PCharacter)line;
607 return Tcl_CommandComplete(pLine);
610 //=======================================================================
613 //=======================================================================
615 void Draw_Interpretor::Destroy()
618 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
623 catch (Standard_Failure) {
625 cout <<"Tcl_Exit have an exeption" << endl;
635 //=======================================================================
638 //=======================================================================
640 Draw_PInterp Draw_Interpretor::Interp() const
642 Standard_DomainError_Raise_if (myInterp==NULL , "No call for Draw_Interpretor::Init()");
646 void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
649 Tcl_DeleteInterp(myInterp);
650 isAllocated = Standard_False;
654 //=======================================================================
657 //=======================================================================
659 void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
664 void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
669 Standard_Boolean Draw_Interpretor::GetDoLog () const
674 Standard_Boolean Draw_Interpretor::GetDoEcho () const
679 Standard_SStream& Draw_Interpretor::Log ()