1 // Created on: 1995-02-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <Draw_Interpretor.hxx>
18 #include <Draw_Appli.hxx>
19 #include <Standard_SStream.hxx>
20 #include <Standard_RangeError.hxx>
21 #include <Standard_ErrorHandler.hxx>
22 #include <Standard_Macro.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <TCollection_ExtendedString.hxx>
26 #include <OSD_Process.hxx>
27 #include <OSD_Path.hxx>
29 #include <OSD_File.hxx>
37 // for capturing of cout and cerr (dup(), dup2())
42 #if ! defined(STDOUT_FILENO)
43 #define STDOUT_FILENO fileno(stdout)
45 #if ! defined(STDERR_FILENO)
46 #define STDERR_FILENO fileno(stderr)
49 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
55 void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
57 for (int i=0; i < argc; i++)
62 void flush_standard_streams ()
70 int capture_start (OSD_File& theTmpFile, int std_fd)
72 theTmpFile.BuildTemporary();
73 if (theTmpFile.Failed())
75 cerr << "Error: cannot create temporary file for capturing console output" << endl;
79 // remember current file descriptors of standard stream, and replace it by temporary
80 return theTmpFile.Capture(std_fd);
83 void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
88 // restore normal descriptors of console stream
90 _dup2(save_fd, std_fd);
93 dup2(save_fd, std_fd);
97 // extract all output and copy it to log and optionally to cout
98 const int BUFSIZE = 2048;
99 TCollection_AsciiString buf;
101 while (tmp_file->ReadLine (buf, BUFSIZE) > 0)
108 // close temporary file
111 // remove temporary file if this is not done by the system
112 if (tmp_file->Exists())
116 } // anonymous namespace
119 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
120 static Standard_Integer CommandCmd
121 (ClientData theClientData, Tcl_Interp *interp,
122 Standard_Integer argc, const char* argv[])
124 static Standard_Integer CommandCmd
125 (ClientData theClientData, Tcl_Interp *interp,
126 Standard_Integer argc, char* argv[])
129 static Standard_Integer code;
131 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
132 Draw_Interpretor& di = *(aCallback->myDI);
134 // log command execution, except commands manipulating log itself and echo
135 Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
136 strcmp (argv[0], "decho") == 0);
137 Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
138 Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
140 dumpArgs (di.Log(), argc, argv);
142 dumpArgs (cout, argc, argv);
144 // flush cerr and cout
145 flush_standard_streams();
147 // capture cout and cerr to log
148 OSD_File aFile_out, aFile_err;
149 int fd_err_save = -1;
150 int fd_out_save = -1;
153 fd_out_save = capture_start (aFile_out, STDOUT_FILENO);
154 fd_err_save = capture_start (aFile_err, STDERR_FILENO);
161 // get exception if control-break has been pressed
164 // OCC680: Transfer UTF-8 directly to OCC commands without locale usage
166 Standard_Integer fres = aCallback->Invoke ( di, argc, argv /*anArgs.GetArgv()*/ );
170 catch (Standard_Failure) {
172 Handle(Standard_Failure) E = Standard_Failure::Caught();
174 // fail if Draw_ExitOnCatch is set
176 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
177 const char* cc = Tcl_GetVar(interp,
178 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
180 char* const cc = Tcl_GetVar(interp,
181 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
184 cout << "An exception was caught " << E << endl;
186 if (cc && Draw::Atoi(cc)) {
190 Tcl_Eval(interp,"exit");
194 // get the error message
196 ss << "** Exception ** " << E << ends;
197 Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
202 flush_standard_streams();
204 // end capturing cout and cerr
207 capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
208 capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
211 // log command result
212 const char* aResultStr = NULL;
215 aResultStr = Tcl_GetStringResult (interp);
216 if (aResultStr != 0 && aResultStr[0] != '\0' )
217 di.Log() << Tcl_GetStringResult (interp) << endl;
221 if (aResultStr == NULL)
222 aResultStr = Tcl_GetStringResult (interp);
223 if (aResultStr != 0 && aResultStr[0] != '\0' )
224 cout << Tcl_GetStringResult (interp) << endl;
230 static void CommandDelete (ClientData theClientData)
232 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
236 //=======================================================================
237 //function : Draw_Interpretor
239 //=======================================================================
241 Draw_Interpretor::Draw_Interpretor() :
242 isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
244 // The tcl interpreter is not created immediately as it is kept
245 // by a global variable and created and deleted before the main().
249 //=======================================================================
251 //purpose : It is necessary to call this function
252 //=======================================================================
254 void Draw_Interpretor::Init()
257 Tcl_DeleteInterp(myInterp);
258 isAllocated=Standard_True;
259 myInterp=Tcl_CreateInterp();
262 //=======================================================================
263 //function : Draw_Interpretor
265 //=======================================================================
267 Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
268 isAllocated(Standard_False),
270 myDoLog(Standard_False),
271 myDoEcho(Standard_False)
275 //=======================================================================
278 //=======================================================================
279 void Draw_Interpretor::add (const Standard_CString theCommandName,
280 const Standard_CString theHelp,
281 const Standard_CString theFileName,
282 Draw_Interpretor::CallBackData* theCallback,
283 const Standard_CString theGroup)
285 if (myInterp == NULL)
290 Standard_PCharacter aName = (Standard_PCharacter )theCommandName;
291 Standard_PCharacter aHelp = (Standard_PCharacter )theHelp;
292 Standard_PCharacter aGroup = (Standard_PCharacter )theGroup;
293 Tcl_CreateCommand (myInterp, aName, CommandCmd, (ClientData )theCallback, CommandDelete);
296 Tcl_SetVar2 (myInterp, "Draw_Helps", aName, aHelp, TCL_GLOBAL_ONLY);
297 Tcl_SetVar2 (myInterp, "Draw_Groups", aGroup, aName,
298 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
300 // add path to source file (keep not more than two last subdirectories)
301 if (theFileName == NULL
302 || *theFileName == '\0')
307 OSD_Path aPath (theFileName);
308 Standard_Integer nbTrek = aPath.TrekLength();
309 for (Standard_Integer i = 2; i < nbTrek; ++i)
311 aPath.RemoveATrek (1);
315 TCollection_AsciiString aSrcPath;
316 aPath.SystemName (aSrcPath);
317 Tcl_SetVar2 (myInterp, "Draw_Files", aName, aSrcPath.ToCString(), TCL_GLOBAL_ONLY);
320 //=======================================================================
323 //=======================================================================
325 Standard_Boolean Draw_Interpretor::Remove(Standard_CString const n)
327 Standard_PCharacter pN;
329 pN=(Standard_PCharacter)n;
331 Standard_Integer result = Tcl_DeleteCommand(myInterp,pN);
335 //=======================================================================
338 //=======================================================================
340 Standard_CString Draw_Interpretor::Result() const
342 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
343 return Tcl_GetStringResult(myInterp);
345 return myInterp->result;
349 //=======================================================================
352 //=======================================================================
354 void Draw_Interpretor::Reset()
356 Tcl_ResetResult(myInterp);
359 //=======================================================================
362 //=======================================================================
364 Draw_Interpretor& Draw_Interpretor::Append(const Standard_CString s)
367 // Convert string to UTF-8 format for Tcl
368 Tcl_DString TclString;
369 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
370 Tcl_AppendResult ( myInterp, Tcl_DStringValue ( &TclString ), (Standard_CString)0 );
371 Tcl_DStringFree ( &TclString );
373 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
378 //=======================================================================
381 //=======================================================================
383 Draw_Interpretor& Draw_Interpretor::Append(const TCollection_AsciiString& s)
385 return Append (s.ToCString());
388 //=======================================================================
391 //=======================================================================
393 Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& theString)
396 // Convert string to UTF-8 format for Tcl
397 char *str = new char[theString.LengthOfCString()+1];
398 theString.ToUTF8CString (str);
399 Tcl_AppendResult ( myInterp, str, (Standard_CString)0 );
402 // put as ascii string, replacing non-ascii characters by '?'
403 TCollection_AsciiString str (theString, '?');
404 Tcl_AppendResult(myInterp,str.ToCString(),(Standard_CString)0);
409 //=======================================================================
412 //=======================================================================
414 Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
418 Tcl_AppendResult(myInterp,c,(Standard_CString)0);
422 //=======================================================================
425 //=======================================================================
427 Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
430 Sprintf(s,"%.17g",r);
431 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
435 //=======================================================================
438 //=======================================================================
440 Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
442 return Append (s.str().c_str());
445 //=======================================================================
446 //function : AppendElement
448 //=======================================================================
450 void Draw_Interpretor::AppendElement(const Standard_CString s)
453 // Convert string to UTF-8 format for Tcl
454 Tcl_DString TclString;
455 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
456 Tcl_AppendElement ( myInterp, Tcl_DStringValue ( &TclString ) );
457 Tcl_DStringFree ( &TclString );
460 //AppendElement is declared as (Tcl_Interp *interp, char *string)
462 Tcl_AppendElement(myInterp,(char*) s);
464 Tcl_AppendElement(myInterp, s);
469 //=======================================================================
472 //=======================================================================
474 Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
476 Standard_PCharacter pLine;
478 pLine=(Standard_PCharacter)line;
480 return Tcl_Eval(myInterp,pLine);
484 //=======================================================================
487 //=======================================================================
489 Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
490 const Standard_Integer flags)
492 Standard_PCharacter pLine;
494 pLine=(Standard_PCharacter)line;
495 return Tcl_RecordAndEval(myInterp,pLine,flags);
498 //=======================================================================
499 //function : EvalFile
501 //=======================================================================
503 Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
505 Standard_PCharacter pfname;
507 pfname=(Standard_PCharacter)fname;
508 return Tcl_EvalFile(myInterp,pfname);
511 //=======================================================================
512 //function : PrintHelp
514 //=======================================================================
516 Standard_Integer Draw_Interpretor::PrintHelp (const Standard_CString theCommandName)
518 TCollection_AsciiString aCmd = TCollection_AsciiString ("help ") + theCommandName;
519 Standard_PCharacter aLinePtr = (Standard_PCharacter )aCmd.ToCString();
520 return Tcl_Eval (myInterp, aLinePtr);
523 //=======================================================================
526 //=======================================================================
528 Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line)
530 Standard_PCharacter pLine;
532 pLine=(Standard_PCharacter)line;
533 return Tcl_CommandComplete (pLine) != 0;
536 //=======================================================================
539 //=======================================================================
541 Draw_Interpretor::~Draw_Interpretor()
544 #if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
549 catch (Standard_Failure) {
551 cout <<"Tcl_Exit have an exeption" << endl;
561 //=======================================================================
564 //=======================================================================
566 Draw_PInterp Draw_Interpretor::Interp() const
568 Standard_DomainError_Raise_if (myInterp==NULL , "No call for Draw_Interpretor::Init()");
572 void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
575 Tcl_DeleteInterp(myInterp);
576 isAllocated = Standard_False;
580 //=======================================================================
583 //=======================================================================
585 void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
590 void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
595 Standard_Boolean Draw_Interpretor::GetDoLog () const
600 Standard_Boolean Draw_Interpretor::GetDoEcho () const
605 Standard_SStream& Draw_Interpretor::Log ()