0026179: Coding rules - eliminate -Wdeprecated-declarations CLang warnings on tmpnam...
[occt.git] / src / Draw / Draw_Interpretor.cxx
CommitLineData
b311480e 1// Created on: 1995-02-23
2// Created by: Remi LEQUETTE
3// Copyright (c) 1995-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
dda67c1c 17#include <Draw_Interpretor.hxx>
7fd59977 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>
23
24#include <TCollection_AsciiString.hxx>
25#include <TCollection_ExtendedString.hxx>
e9b037ef 26#include <OSD_Process.hxx>
d33dea30 27#include <OSD_Path.hxx>
8a262fa1 28#include <OSD.hxx>
95e05159 29#include <OSD_File.hxx>
7fd59977 30
31#include <string.h>
7fd59977 32#include <tcl.h>
03155c18 33#ifndef _WIN32
34#include <unistd.h>
35#endif
7fd59977 36
aa02980d 37// for capturing of cout and cerr (dup(), dup2())
38#ifdef _MSC_VER
39#include <io.h>
40#endif
aa02980d 41
42#if ! defined(STDOUT_FILENO)
43#define STDOUT_FILENO fileno(stdout)
44#endif
45#if ! defined(STDERR_FILENO)
46#define STDERR_FILENO fileno(stderr)
47#endif
48
7fd59977 49#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
50#define TCL_USES_UTF8
51#endif
52
aa02980d 53// logging helpers
54namespace {
55 void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
56 {
57 for (int i=0; i < argc; i++)
58 os << argv[i] << " ";
59 os << endl;
60 }
61
62 void flush_standard_streams ()
63 {
64 fflush (stderr);
65 fflush (stdout);
66 cerr << flush;
67 cout << flush;
68 }
69
95e05159 70 int capture_start (OSD_File& theTmpFile, int std_fd)
aa02980d 71 {
95e05159 72 theTmpFile.BuildTemporary();
73 if (theTmpFile.Failed())
aa02980d 74 {
75 cerr << "Error: cannot create temporary file for capturing console output" << endl;
95e05159 76 return -1;
aa02980d 77 }
78
79 // remember current file descriptors of standard stream, and replace it by temporary
95e05159 80 return theTmpFile.Capture(std_fd);
aa02980d 81 }
82
95e05159 83 void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
aa02980d 84 {
95e05159 85 if (!tmp_file)
e9b037ef 86 return;
87
aa02980d 88 // restore normal descriptors of console stream
95e05159 89 dup2(save_fd, std_fd);
aa02980d 90 close(save_fd);
91
92 // extract all output and copy it to log and optionally to cout
93 const int BUFSIZE = 2048;
95e05159 94 TCollection_AsciiString buf;
95 tmp_file->Rewind();
96 while (tmp_file->ReadLine (buf, BUFSIZE) > 0)
aa02980d 97 {
98 log << buf;
99 if (doEcho)
100 cout << buf;
101 }
102
103 // close temporary file
95e05159 104 tmp_file->Close();
e9b037ef 105
106 // remove temporary file if this is not done by the system
95e05159 107 if (tmp_file->Exists())
108 tmp_file->Remove();
aa02980d 109 }
95e05159 110
aa02980d 111};
112
7fd59977 113// MKV 29.03.05
114#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
115static Standard_Integer CommandCmd
dda67c1c 116(ClientData theClientData, Tcl_Interp *interp,
7fd59977 117 Standard_Integer argc, const char* argv[])
118#else
119static Standard_Integer CommandCmd
dda67c1c 120(ClientData theClientData, Tcl_Interp *interp,
7fd59977 121 Standard_Integer argc, char* argv[])
122#endif
123{
124 static Standard_Integer code;
125 code = TCL_OK;
dda67c1c 126 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
127 Draw_Interpretor& di = *(aCallback->myDI);
aa02980d 128
129 // log command execution, except commands manipulating log itself and echo
130 Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
131 strcmp (argv[0], "decho") == 0);
132 Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
133 Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
134 if (doLog)
135 dumpArgs (di.Log(), argc, argv);
136 if (doEcho)
137 dumpArgs (cout, argc, argv);
138
139 // flush cerr and cout
140 flush_standard_streams();
141
142 // capture cout and cerr to log
95e05159 143 OSD_File aFile_out, aFile_err;
144 int fd_err_save = -1;
145 int fd_out_save = -1;
aa02980d 146 if (doLog)
147 {
95e05159 148 fd_out_save = capture_start (aFile_out, STDOUT_FILENO);
149 fd_err_save = capture_start (aFile_err, STDERR_FILENO);
aa02980d 150 }
7fd59977 151
aa02980d 152 // run command
7fd59977 153 try {
154 OCC_CATCH_SIGNALS
155
8a262fa1 156 // get exception if control-break has been pressed
157 OSD::ControlBreak();
158
d9ff84e8 159 // OCC680: Transfer UTF-8 directly to OCC commands without locale usage
7fd59977 160
d9ff84e8 161 Standard_Integer fres = aCallback->Invoke ( di, argc, argv /*anArgs.GetArgv()*/ );
7fd59977 162 if (fres != 0)
163 code = TCL_ERROR;
164 }
165 catch (Standard_Failure) {
166
167 Handle(Standard_Failure) E = Standard_Failure::Caught();
168
169 // fail if Draw_ExitOnCatch is set
170 // MKV 29.03.05
171#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
172 const char* cc = Tcl_GetVar(interp,
173 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
174#else
175 char* const cc = Tcl_GetVar(interp,
176 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
177#endif
178
179 cout << "An exception was caught " << E << endl;
180
91322f44 181 if (cc && Draw::Atoi(cc)) {
57c28b61 182#ifdef _WIN32
7fd59977 183 Tcl_Exit(0);
184#else
185 Tcl_Eval(interp,"exit");
186#endif
187 }
188
189 // get the error message
190 Standard_SStream ss;
d41f6af3 191 ss << "** Exception ** " << E << ends;
7fd59977 192 Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
7fd59977 193 code = TCL_ERROR;
194 }
aa02980d 195
196 // flush streams
197 flush_standard_streams();
198
199 // end capturing cout and cerr
200 if (doLog)
201 {
95e05159 202 capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
203 capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
aa02980d 204 }
205
206 // log command result
207 const char* aResultStr = NULL;
208 if (doLog)
209 {
210 aResultStr = Tcl_GetStringResult (interp);
211 if (aResultStr != 0 && aResultStr[0] != '\0' )
212 di.Log() << Tcl_GetStringResult (interp) << endl;
213 }
214 if (doEcho)
215 {
216 if (aResultStr == NULL)
217 aResultStr = Tcl_GetStringResult (interp);
218 if (aResultStr != 0 && aResultStr[0] != '\0' )
219 cout << Tcl_GetStringResult (interp) << endl;
220 }
221
7fd59977 222 return code;
223}
224
dda67c1c 225static void CommandDelete (ClientData theClientData)
7fd59977 226{
dda67c1c 227 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
228 delete aCallback;
7fd59977 229}
230
231//=======================================================================
232//function : Draw_Interpretor
233//purpose :
234//=======================================================================
235
236Draw_Interpretor::Draw_Interpretor() :
aa02980d 237 isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
7fd59977 238{
0d969553
Y
239// The tcl interpreter is not created immediately as it is kept
240// by a global variable and created and deleted before the main().
7fd59977 241 myInterp = NULL;
242}
243
244//=======================================================================
245//function : Init
0d969553 246//purpose : It is necessary to call this function
7fd59977 247//=======================================================================
248
249void Draw_Interpretor::Init()
250{
251 if (isAllocated)
252 Tcl_DeleteInterp(myInterp);
253 isAllocated=Standard_True;
254 myInterp=Tcl_CreateInterp();
255}
256
257//=======================================================================
258//function : Draw_Interpretor
259//purpose :
260//=======================================================================
261
262Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
263 isAllocated(Standard_False),
aa02980d 264 myInterp(p),
265 myDoLog(Standard_False),
266 myDoEcho(Standard_False)
7fd59977 267{
268}
269
270//=======================================================================
dda67c1c 271//function : add
272//purpose :
7fd59977 273//=======================================================================
dda67c1c 274void Draw_Interpretor::add (const Standard_CString theCommandName,
275 const Standard_CString theHelp,
276 const Standard_CString theFileName,
277 Draw_Interpretor::CallBackData* theCallback,
278 const Standard_CString theGroup)
7fd59977 279{
dda67c1c 280 if (myInterp == NULL)
281 {
282 Init();
283 }
7fd59977 284
dda67c1c 285 Standard_PCharacter aName = (Standard_PCharacter )theCommandName;
286 Standard_PCharacter aHelp = (Standard_PCharacter )theHelp;
287 Standard_PCharacter aGroup = (Standard_PCharacter )theGroup;
288 Tcl_CreateCommand (myInterp, aName, CommandCmd, (ClientData )theCallback, CommandDelete);
7fd59977 289
290 // add the help
dda67c1c 291 Tcl_SetVar2 (myInterp, "Draw_Helps", aName, aHelp, TCL_GLOBAL_ONLY);
292 Tcl_SetVar2 (myInterp, "Draw_Groups", aGroup, aName,
293 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
938a360f 294
d33dea30 295 // add path to source file (keep not more than two last subdirectories)
dda67c1c 296 if (theFileName == NULL
297 || *theFileName == '\0')
298 {
299 return;
300 }
301
302 OSD_Path aPath (theFileName);
d33dea30 303 Standard_Integer nbTrek = aPath.TrekLength();
dda67c1c 304 for (Standard_Integer i = 2; i < nbTrek; ++i)
305 {
d33dea30 306 aPath.RemoveATrek (1);
dda67c1c 307 }
308 aPath.SetDisk ("");
309 aPath.SetNode ("");
d33dea30
PK
310 TCollection_AsciiString aSrcPath;
311 aPath.SystemName (aSrcPath);
dda67c1c 312 Tcl_SetVar2 (myInterp, "Draw_Files", aName, aSrcPath.ToCString(), TCL_GLOBAL_ONLY);
7fd59977 313}
314
7fd59977 315//=======================================================================
316//function : Remove
317//purpose :
318//=======================================================================
319
320Standard_Boolean Draw_Interpretor::Remove(Standard_CString const n)
321{
322 Standard_PCharacter pN;
323 //
324 pN=(Standard_PCharacter)n;
325
326 Standard_Integer result = Tcl_DeleteCommand(myInterp,pN);
327 return result == 0;
328}
329
330//=======================================================================
331//function : Result
332//purpose :
333//=======================================================================
334
335Standard_CString Draw_Interpretor::Result() const
336{
337#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
338 return Tcl_GetStringResult(myInterp);
339#else
340 return myInterp->result;
341#endif
342}
343
344//=======================================================================
345//function : Reset
346//purpose :
347//=======================================================================
348
349void Draw_Interpretor::Reset()
350{
351 Tcl_ResetResult(myInterp);
352}
353
354//=======================================================================
355//function : Append
356//purpose :
357//=======================================================================
358
359Draw_Interpretor& Draw_Interpretor::Append(const Standard_CString s)
360{
361#ifdef TCL_USES_UTF8
362 // Convert string to UTF-8 format for Tcl
363 Tcl_DString TclString;
364 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
365 Tcl_AppendResult ( myInterp, Tcl_DStringValue ( &TclString ), (Standard_CString)0 );
366 Tcl_DStringFree ( &TclString );
367#else
368 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
369#endif
370 return *this;
371}
372
373//=======================================================================
374//function : Append
375//purpose :
376//=======================================================================
377
378Draw_Interpretor& Draw_Interpretor::Append(const TCollection_AsciiString& s)
379{
380 return Append (s.ToCString());
381}
382
383//=======================================================================
384//function : Append
385//purpose :
386//=======================================================================
387
388Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& theString)
389{
390#ifdef TCL_USES_UTF8
391 // Convert string to UTF-8 format for Tcl
392 char *str = new char[theString.LengthOfCString()+1];
393 theString.ToUTF8CString (str);
394 Tcl_AppendResult ( myInterp, str, (Standard_CString)0 );
395 delete[] str;
396#else
397 // put as ascii string, replacing non-ascii characters by '?'
398 TCollection_AsciiString str (theString, '?');
399 Tcl_AppendResult(myInterp,str.ToCString(),(Standard_CString)0);
400#endif
401 return *this;
402}
403
404//=======================================================================
405//function : Append
406//purpose :
407//=======================================================================
408
409Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
410{
411 char c[100];
91322f44 412 Sprintf(c,"%d",i);
7fd59977 413 Tcl_AppendResult(myInterp,c,(Standard_CString)0);
414 return *this;
415}
416
417//=======================================================================
418//function : Append
419//purpose :
420//=======================================================================
421
422Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
423{
424 char s[100];
91322f44 425 Sprintf(s,"%.17g",r);
7fd59977 426 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
427 return *this;
428}
429
430//=======================================================================
431//function : Append
432//purpose :
433//=======================================================================
434
435Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
436{
7fd59977 437 return Append (s.str().c_str());
7fd59977 438}
439
440//=======================================================================
441//function : AppendElement
442//purpose :
443//=======================================================================
444
445void Draw_Interpretor::AppendElement(const Standard_CString s)
446{
447#ifdef TCL_USES_UTF8
448 // Convert string to UTF-8 format for Tcl
449 Tcl_DString TclString;
450 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
451 Tcl_AppendElement ( myInterp, Tcl_DStringValue ( &TclString ) );
452 Tcl_DStringFree ( &TclString );
453#else
454#ifdef IRIX
455 //AppendElement is declared as (Tcl_Interp *interp, char *string)
456 //on SGI 32
457 Tcl_AppendElement(myInterp,(char*) s);
458#else
459 Tcl_AppendElement(myInterp, s);
460#endif
461#endif
462}
463
464//=======================================================================
465//function : Eval
466//purpose :
467//=======================================================================
468
469Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
470{
471 Standard_PCharacter pLine;
472 //
473 pLine=(Standard_PCharacter)line;
474 //
475 return Tcl_Eval(myInterp,pLine);
476}
477
478
479//=======================================================================
480//function : Eval
481//purpose :
482//=======================================================================
483
484Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
485 const Standard_Integer flags)
486{
487 Standard_PCharacter pLine;
488 //
489 pLine=(Standard_PCharacter)line;
490 return Tcl_RecordAndEval(myInterp,pLine,flags);
491}
492
493//=======================================================================
494//function : EvalFile
495//purpose :
496//=======================================================================
497
498Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
499{
500 Standard_PCharacter pfname;
501 //
502 pfname=(Standard_PCharacter)fname;
503 return Tcl_EvalFile(myInterp,pfname);
504}
505
785a9540 506//=======================================================================
507//function : PrintHelp
508//purpose :
509//=======================================================================
510
511Standard_Integer Draw_Interpretor::PrintHelp (const Standard_CString theCommandName)
512{
513 TCollection_AsciiString aCmd = TCollection_AsciiString ("help ") + theCommandName;
514 Standard_PCharacter aLinePtr = (Standard_PCharacter )aCmd.ToCString();
515 return Tcl_Eval (myInterp, aLinePtr);
516}
517
7fd59977 518//=======================================================================
519//function :Complete
520//purpose :
521//=======================================================================
522
523Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line)
524{
525 Standard_PCharacter pLine;
526 //
527 pLine=(Standard_PCharacter)line;
528 return Tcl_CommandComplete(pLine);
529}
530
531//=======================================================================
532//function : Destroy
533//purpose :
534//=======================================================================
535
dda67c1c 536Draw_Interpretor::~Draw_Interpretor()
7fd59977 537{
538 // MKV 01.02.05
539#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
540 try {
541 OCC_CATCH_SIGNALS
542 Tcl_Exit(0);
543 }
544 catch (Standard_Failure) {
0797d9d3 545#ifdef OCCT_DEBUG
7fd59977 546 cout <<"Tcl_Exit have an exeption" << endl;
547#endif
548 }
549#else
57c28b61 550#ifdef _WIN32
7fd59977 551 Tcl_Exit(0);
552#endif
553#endif
554}
555
556//=======================================================================
557//function : Interp
558//purpose :
559//=======================================================================
560
561Draw_PInterp Draw_Interpretor::Interp() const
562{
563 Standard_DomainError_Raise_if (myInterp==NULL , "No call for Draw_Interpretor::Init()");
564 return myInterp;
565}
566
567void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
568{
569 if (isAllocated)
570 Tcl_DeleteInterp(myInterp);
571 isAllocated = Standard_False;
572 myInterp = PIntrp;
573}
aa02980d 574
575//=======================================================================
576//function : Logging
577//purpose :
578//=======================================================================
579
580void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
581{
582 myDoLog = doLog;
583}
584
585void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
586{
587 myDoEcho = doEcho;
588}
589
590Standard_Boolean Draw_Interpretor::GetDoLog () const
591{
592 return myDoLog;
593}
594
595Standard_Boolean Draw_Interpretor::GetDoEcho () const
596{
597 return myDoEcho;
598}
599
600Standard_SStream& Draw_Interpretor::Log ()
601{
602 return myLog;
60be1f9b 603}