1 // Created on: 1993-08-13
2 // Created by: Bruno DUMORTIER
3 // Copyright (c) 1993-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.
19 #include <Draw_Appli.hxx>
20 #include <Draw_Drawable3D.hxx>
21 #include <Draw_Failure.hxx>
22 #include <Draw_Interpretor.hxx>
23 #include <Draw_ProgressIndicator.hxx>
24 #include <Draw_Window.hxx>
25 #include <gp_Pnt2d.hxx>
27 #include <OSD_Environment.hxx>
28 #include <OSD_File.hxx>
29 #include <OSD_Process.hxx>
30 #include <OSD_SharedLibrary.hxx>
31 #include <OSD_Timer.hxx>
32 #include <Plugin_MapOfFunctions.hxx>
33 #include <Resource_Manager.hxx>
34 #include <Standard_ErrorHandler.hxx>
35 #include <Standard_Stream.hxx>
36 #include <Standard_Version.hxx>
37 #include <TCollection_AsciiString.hxx>
40 // on MSVC, use #pragma to define name of the Tcl library to link with,
41 // depending on Tcl version number
43 // two helper macros are needed to convert version number macro to string literal
44 #define STRINGIZE1(a) #a
45 #define STRINGIZE2(a) STRINGIZE1(a)
46 #pragma comment (lib, "tcl" STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
47 #pragma comment (lib, "tk" STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
52 extern Standard_Boolean Draw_ParseFailed;
54 Standard_EXPORT Draw_Viewer dout;
55 Standard_EXPORT Draw_Interpretor theCommands;
56 Standard_EXPORT Standard_Boolean Draw_Batch;
57 Standard_EXPORT Standard_Boolean Draw_Spying = Standard_False;
58 Standard_EXPORT Standard_Boolean Draw_Chrono = Standard_False;
59 Standard_EXPORT Standard_Boolean Draw_VirtualWindows = Standard_False;
60 Standard_EXPORT Standard_Boolean ErrorMessages = Standard_True;
62 static const char* ColorNames[MAXCOLOR] = {
63 "White","Red","Green","Blue","Cyan","Gold","Magenta",
64 "Maroon","Orange","Pink","Salmon","Violet","Yellow","Khaki","Coral"
69 static ostream spystream(&Draw_Spyfile);
71 static Handle(Draw_ProgressIndicator) PInd = NULL;
73 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
74 // true if complete command
76 // *******************************************************************
78 // *******************************************************************
80 static void interpreteTclCommand (const TCollection_AsciiString& theCmd)
87 while (console_semaphore == HAS_CONSOLE_COMMAND)
92 TCollection_ExtendedString aCmdWide (theCmd);
93 wcscpy_s (console_command, aCmdWide.ToWideString());
95 console_semaphore = HAS_CONSOLE_COMMAND;
96 while (console_semaphore == HAS_CONSOLE_COMMAND)
103 std::cout << "Error while reading a script file.\n";
110 Draw_Interprete (theCmd.ToCString());
114 static void ReadInitFile (const TCollection_AsciiString& theFileName)
116 TCollection_AsciiString aCmd = theFileName;
118 aCmd.ChangeAll ('\\', '/');
120 aCmd = TCollection_AsciiString ("source -encoding utf-8 \"") + aCmd + "\"";
121 interpreteTclCommand (aCmd);
124 //! Define environment variable available from Tcl and OCCT.
125 static void setOcctTclEnv (const TCollection_AsciiString& theName,
126 TCollection_AsciiString& thePath)
128 if (thePath.IsEmpty())
133 thePath.ChangeAll ('\\', '/');
134 OSD_Environment aRedPathEnv (theName);
135 aRedPathEnv.SetValue (thePath);
138 const TCollection_AsciiString aPutEnv = theName + "=" + thePath;
139 Tcl_PutEnv (aPutEnv.ToCString());
142 //! Look for resource within standard installation layouts relative to executable location.
144 //! Bin (INSTALL_DIR_BIN):
145 //! - Windows: <prefix>/win64/vc10/bin(d)
146 //! - Unix: <prefix>/bin
147 //! Resources (INSTALL_DIR_RESOURCE):
148 //! - Windows: <prefix>/src
149 //! - Unix: <prefix>/share/opencascade-7.0.0/resources
150 //! Samples (INSTALL_DIR_SAMPLES):
151 //! - Windows: <prefix>/samples
152 //! - Unix: <prefix>/share/opencascade-7.0.0/samples
153 //! Tests (INSTALL_DIR_TESTS):
154 //! - Windows: <prefix>/tests
155 //! - Unix: <prefix>/share/opencascade-7.0.0/tests
157 //! @param theCasRoot [out] found CASROOT location (e.g. installation folder)
158 //! @param theResRoot [out] found resources root location
159 //! @param theResName [in] resource to find ("resources", "samples", etc.)
160 //! @param theProbeFile [in] file to probe within resources location (e.g. "DrawResources/DrawDefault" within "resources")
161 static bool searchResources (TCollection_AsciiString& theCasRoot,
162 TCollection_AsciiString& theResRoot,
163 const TCollection_AsciiString& theResName,
164 const TCollection_AsciiString& theProbeFile)
166 const TCollection_AsciiString aResLayouts[] =
168 TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING_EXT "/") + theResName,
169 TCollection_AsciiString("/share/opencascade-" OCC_VERSION_COMPLETE "/") + theResName,
170 TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING "/") + theResName,
171 TCollection_AsciiString("/share/opencascade/") + theResName,
172 TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING_EXT "/") + theResName,
173 TCollection_AsciiString("/share/occt-" OCC_VERSION_COMPLETE "/") + theResName,
174 TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING "/") + theResName,
175 TCollection_AsciiString("/share/occt/") + theResName,
176 TCollection_AsciiString("/") + theResName,
177 TCollection_AsciiString("/share/opencascade"),
178 TCollection_AsciiString("/share/occt"),
179 TCollection_AsciiString("/share"),
180 TCollection_AsciiString("/src"),
181 TCollection_AsciiString("")
184 const TCollection_AsciiString anExeDir (OSD_Process::ExecutableFolder());
185 for (Standard_Integer aLayIter = 0;; ++aLayIter)
187 const TCollection_AsciiString& aResLayout = aResLayouts[aLayIter];
188 const TCollection_AsciiString aProbeFile = aResLayout + "/" + theProbeFile;
189 if (OSD_File (anExeDir + aProbeFile).Exists())
191 theCasRoot = anExeDir;
192 theResRoot = theCasRoot + aResLayout;
196 else if (OSD_File (anExeDir + "../" + aProbeFile).Exists())
198 theCasRoot = anExeDir + "..";
199 theResRoot = theCasRoot + aResLayout;
202 // <prefix>/gcc/bin(d)
203 else if (OSD_File (anExeDir + "../../" + aProbeFile).Exists())
205 theCasRoot = anExeDir + "../..";
206 theResRoot = theCasRoot + aResLayout;
209 // <prefix>/win64/vc10/bin(d)
210 else if (OSD_File (anExeDir + "../../../" + aProbeFile).Exists())
212 theCasRoot = anExeDir + "../../..";
213 theResRoot = theCasRoot + aResLayout;
217 if (aResLayout.IsEmpty())
224 //=======================================================================
225 //function : GetInterpretor
227 //=======================================================================
228 Draw_Interpretor& Draw::GetInterpretor()
233 //=======================================================================
235 //purpose : Set/Get Progress Indicator
236 //=======================================================================
237 void Draw::SetProgressBar(const Handle(Draw_ProgressIndicator)& thePI)
242 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
248 /*--------------------------------------------------------*\
249 | exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
250 \*--------------------------------------------------------*/
251 void exitProc(ClientData /*dc*/)
254 for (Standard_Integer id = 0; id < MAXVIEW; id++)
260 // *******************************************************************
262 // *******************************************************************
264 Standard_EXPORT void Draw_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, int argc, wchar_t** argv, const FDraw_InitAppli Draw_InitAppli)
266 void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
270 // prepend extra DLL search path to override system libraries like opengl32.dll
272 OSD_Environment aUserDllEnv ("CSF_UserDllPath");
273 const TCollection_ExtendedString aUserDllPath (aUserDllEnv.Value());
274 if (!aUserDllPath.IsEmpty())
276 // This function available since Win XP SP1 #if (_WIN32_WINNT >= 0x0502).
277 // We retrieve dynamically here (kernel32 should be always preloaded).
278 typedef BOOL (WINAPI *SetDllDirectoryW_t)(const wchar_t* thePathName);
279 HMODULE aKern32Module = GetModuleHandleW (L"kernel32");
280 SetDllDirectoryW_t aFunc = (aKern32Module != NULL)
281 ? (SetDllDirectoryW_t )GetProcAddress (aKern32Module, "SetDllDirectoryW") : NULL;
284 aFunc (aUserDllPath.ToWideString());
288 //std::cerr << "SetDllDirectoryW() is not available on this system!\n";
290 if (aKern32Module != NULL)
292 FreeLibrary (aKern32Module);
297 // *****************************************************************
299 // *****************************************************************
300 Draw_Batch = Standard_False;
301 TCollection_AsciiString aRunFile, aCommand;
302 Standard_Boolean isInteractiveForced = Standard_False;
304 // parse command line
305 for (int anArgIter = 1; anArgIter < argc; ++anArgIter)
307 TCollection_AsciiString anArg (argv[anArgIter]);
310 || anArg == "--help")
312 std::cout << "Open CASCADE " << OCC_VERSION_STRING_EXT << " DRAW Test Harness\n\n";
313 std::cout << "Options:\n";
314 std::cout << " -b: batch mode (no GUI, no viewers)\n";
315 std::cout << " -v: no GUI, use virtual (off-screen) windows for viewers\n";
316 std::cout << " -i: interactive mode\n";
317 std::cout << " -f file: execute script from file\n";
318 std::cout << " -c command args...: execute command (with optional arguments)\n\n";
319 std::cout << "Options -b, -v, and -i are mutually exclusive.\n";
320 std::cout << "If -c or -f are given, -v is default; otherwise default is -i.\n";
321 std::cout << "Options -c and -f are alternatives and should be at the end \n";
322 std::cout << "of the command line.\n";
323 std::cout << "Option -c can accept set of commands separated by ';'.\n";
326 else if (anArg == "-b")
328 Draw_Batch = Standard_True;
330 else if (anArg == "-v")
332 // force virtual windows
333 Draw_VirtualWindows = Standard_True;
335 else if (anArg == "-i")
338 Draw_VirtualWindows = Standard_False;
339 isInteractiveForced = Standard_True;
341 else if (anArg == "-f") // -f option should be LAST!
343 Draw_VirtualWindows = !isInteractiveForced;
344 if (++anArgIter < argc)
346 aRunFile = TCollection_AsciiString (argv[anArgIter]);
350 else if (anArg == "-c") // -c option should be LAST!
352 Draw_VirtualWindows = !isInteractiveForced;
353 if (++anArgIter < argc)
355 aCommand = TCollection_AsciiString (argv[anArgIter]);
357 while (++anArgIter < argc)
359 aCommand.AssignCat (" ");
360 aCommand.AssignCat (argv[anArgIter]);
366 std::cout << "Error: unsupported option " << TCollection_AsciiString (argv[anArgIter]) << "\n";
370 // *****************************************************************
372 // *****************************************************************
373 OSD::SetSignal(Standard_False);
376 // in interactive mode, force Windows to report dll loading problems interactively
377 if ( ! Draw_VirtualWindows && ! Draw_Batch )
381 // *****************************************************************
382 // init X window and create display
383 // *****************************************************************
390 Draw_Batch=!Init_Appli(hInst, hPrevInst, nShow, hWnd);
392 Draw_Batch=!Init_Appli();
396 cout << "DRAW is running in batch mode" << endl;
398 Tcl_Init(theCommands.Interp());
404 for (int i = 0; i < MAXCOLOR; ++i)
406 if (!dout.DefineColor (i, ColorNames[i]))
408 std::cout <<"Could not allocate default color " << ColorNames[i] << std::endl;
413 // *****************************************************************
414 // set maximum precision for cout
415 // *****************************************************************
418 // *****************************************************************
420 // *****************************************************************
421 Draw::BasicCommands(theCommands);
422 Draw::VariableCommands(theCommands);
423 Draw::UnitCommands(theCommands);
424 if (!Draw_Batch) Draw::GraphicCommands(theCommands);
426 // *****************************************************************
428 // *****************************************************************
429 Draw_InitAppli(theCommands);
432 Tcl_CreateExitHandler(exitProc, 0);
435 // *****************************************************************
437 // *****************************************************************
439 const TCollection_AsciiString aDrawDef (OSD_Environment ("DRAWDEFAULT").Value());
440 if (!aDrawDef.IsEmpty())
442 ReadInitFile (aDrawDef);
446 TCollection_AsciiString aDrawHome;
447 TCollection_AsciiString aCasRoot (OSD_Environment ("CASROOT").Value());
448 if (!aCasRoot.IsEmpty())
450 aDrawHome = aCasRoot + "/src/DrawResources";
454 // search for relative locations within standard development environment
455 TCollection_AsciiString aResPath;
456 if (searchResources (aCasRoot, aResPath, "resources", "DrawResources/DrawDefault"))
458 aDrawHome = aResPath + "/DrawResources";
459 setOcctTclEnv ("CASROOT", aCasRoot);
460 setOcctTclEnv ("DRAWHOME", aDrawHome);
461 setOcctTclEnv ("CSF_OCCTResourcePath", aResPath);
464 TCollection_AsciiString aSamplesPath;
465 if (OSD_Environment ("CSF_OCCTSamplesPath").Value().IsEmpty()
466 && searchResources (aCasRoot, aSamplesPath, "samples", "tcl/Readme.txt"))
468 setOcctTclEnv ("CSF_OCCTSamplesPath", aSamplesPath);
471 TCollection_AsciiString aTestsPath;
472 if (OSD_Environment ("CSF_TestScriptsPath").Value().IsEmpty()
473 && searchResources (aCasRoot, aTestsPath, "tests", "parse.rules"))
475 setOcctTclEnv ("CSF_TestScriptsPath", aTestsPath);
479 if (!aDrawHome.IsEmpty())
481 const TCollection_AsciiString aDefStr = aDrawHome + "/DrawDefault";
482 ReadInitFile (aDefStr);
487 ReadInitFile ("ddefault");
489 cout << " the CASROOT variable is mandatory to Run OpenCascade "<< endl;
490 cout << "No default file" << endl;
495 // read commands from file
496 if (!aRunFile.IsEmpty()) {
497 ReadInitFile (aRunFile);
498 // provide a clean exit, this is useful for some analysis tools
499 if ( ! isInteractiveForced )
507 // execute command from command line
508 if (!aCommand.IsEmpty())
513 // on Windows except batch mode, commands are executed in separate thread
514 while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
515 TCollection_ExtendedString aCmdWide(aCommand);
516 wcscpy_s(console_command, aCmdWide.ToWideString());
517 console_semaphore = HAS_CONSOLE_COMMAND;
518 while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
522 Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
523 // provide a clean exit, this is useful for some analysis tools
524 if ( ! isInteractiveForced )
532 // *****************************************************************
534 // *****************************************************************
539 Run_Appli(Draw_Interprete);
544 const int MAXCMD = 2048;
546 for (int ncmd = 1;; ++ncmd)
548 cout << "Draw[" << ncmd << "]> ";
549 if (cin.getline (cmd, MAXCMD).fail())
553 Draw_Interprete(cmd);
557 // Destruction de l'application
558 Destroy_Appli(hInst);
563 // User functions called before and after each command
564 void (*Draw_BeforeCommand)() = NULL;
565 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
567 Standard_Boolean Draw_Interprete(const char* com)
570 static Standard_Boolean first = Standard_True;
571 static Tcl_DString command;
574 first = Standard_False;
575 Tcl_DStringInit(&command);
579 // string is already converted into UTF-8
580 Tcl_DStringAppend(&command, com, -1);
581 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
582 // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
583 Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
585 Tcl_DStringAppend(&command,com,-1);
588 if (!theCommands.Complete(Tcl_DStringValue(&command)))
589 return Standard_False;
591 // *******************************************************************
592 // Command interpreter
593 // *******************************************************************
595 // Standard_Integer i = 0;
596 // Standard_Integer j = 0;
598 Standard_Boolean wasspying = Draw_Spying;
601 Standard_Boolean hadchrono = Draw_Chrono;
602 if (hadchrono) tictac.Start();
604 if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
608 c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
610 if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
612 if (wasspying && Draw_Spying) {
613 if (c > 0) spystream << "# ";
614 spystream << Tcl_DStringValue(&command) << "\n";
619 if (*theCommands.Result())
622 const TCollection_ExtendedString aResWide (theCommands.Result());
623 std::wcout << aResWide.ToWideString() << std::endl;
625 std::cout << theCommands.Result() << std::endl;
629 if (Draw_Chrono && hadchrono) {
634 Tcl_DStringFree(&command);
636 return Standard_True;
643 Standard_Integer Tcl_AppInit (Tcl_Interp *)
654 Standard_Integer Draw_Call (char *c)
656 Standard_Integer r = theCommands.Eval(c);
657 cout << theCommands.Result() << endl;
661 //=================================================================================
663 //=================================================================================
664 void Draw::Load(Draw_Interpretor& theDI, const TCollection_AsciiString& theKey,
665 const TCollection_AsciiString& theResourceFileName,
666 TCollection_AsciiString& theDefaultsDirectory,
667 TCollection_AsciiString& theUserDefaultsDirectory,
668 const Standard_Boolean Verbose ) {
670 static Plugin_MapOfFunctions theMapOfFunctions;
673 if(!theMapOfFunctions.IsBound(theKey)) {
675 Handle(Resource_Manager) aPluginResource = new Resource_Manager(theResourceFileName.ToCString(), theDefaultsDirectory, theUserDefaultsDirectory, Verbose);
677 if(!aPluginResource->Find(theKey.ToCString())) {
678 Standard_SStream aMsg; aMsg << "Could not find the resource:";
679 aMsg << theKey.ToCString()<< endl;
680 cout << "could not find the resource:"<<theKey.ToCString()<< endl;
681 throw Draw_Failure(aMsg.str().c_str());
684 TCollection_AsciiString aPluginLibrary("");
685 #if !defined(_WIN32) || defined(__MINGW32__)
686 aPluginLibrary += "lib";
688 aPluginLibrary += aPluginResource->Value(theKey.ToCString());
690 aPluginLibrary += ".dll";
692 aPluginLibrary += ".dylib";
693 #elif defined (HPUX) || defined(_hpux)
694 aPluginLibrary += ".sl";
696 aPluginLibrary += ".so";
698 OSD_SharedLibrary aSharedLibrary(aPluginLibrary.ToCString());
699 if(!aSharedLibrary.DlOpen(OSD_RTLD_LAZY)) {
700 TCollection_AsciiString error(aSharedLibrary.DlError());
701 Standard_SStream aMsg; aMsg << "Could not open: ";
702 aMsg << aPluginResource->Value(theKey.ToCString());
703 aMsg << "; reason: ";
704 aMsg << error.ToCString();
706 cout << "could not open: " << aPluginResource->Value(theKey.ToCString())<< " ; reason: "<< error.ToCString() << endl;
708 throw Draw_Failure(aMsg.str().c_str());
710 f = aSharedLibrary.DlSymb("PLUGINFACTORY");
712 TCollection_AsciiString error(aSharedLibrary.DlError());
713 Standard_SStream aMsg; aMsg << "Could not find the factory in: ";
714 aMsg << aPluginResource->Value(theKey.ToCString());
715 aMsg << error.ToCString();
716 throw Draw_Failure(aMsg.str().c_str());
718 theMapOfFunctions.Bind(theKey, f);
721 f = theMapOfFunctions(theKey);
723 // void (*fp) (Draw_Interpretor&, const TCollection_AsciiString&) = NULL;
724 // fp = (void (*)(Draw_Interpretor&, const TCollection_AsciiString&)) f;
725 // (*fp) (theDI, theKey);
727 void (*fp) (Draw_Interpretor&) = NULL;
728 fp = (void (*)(Draw_Interpretor&)) f;