0031188: Draw Harness - enable colorized messages output to console by default
[occt.git] / src / Draw / Draw.cxx
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
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Draw.hxx>
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>
26 #include <Message.hxx>
27 #include <Message_Messenger.hxx>
28 #include <Message_PrinterOStream.hxx>
29 #include <OSD.hxx>
30 #include <OSD_Environment.hxx>
31 #include <OSD_File.hxx>
32 #include <OSD_Process.hxx>
33 #include <OSD_SharedLibrary.hxx>
34 #include <OSD_Timer.hxx>
35 #include <Plugin_MapOfFunctions.hxx>
36 #include <Resource_Manager.hxx>
37 #include <Standard_ErrorHandler.hxx>
38 #include <Standard_Stream.hxx>
39 #include <Standard_Version.hxx>
40 #include <TCollection_AsciiString.hxx>
41
42 #include <tcl.h>
43
44 #include <Standard_WarningDisableFunctionCast.hxx>
45
46 // on MSVC, use #pragma to define name of the Tcl library to link with,
47 // depending on Tcl version number
48 #ifdef _MSC_VER
49 // two helper macros are needed to convert version number macro to string literal
50 #define STRINGIZE1(a) #a
51 #define STRINGIZE2(a) STRINGIZE1(a)
52 #pragma comment (lib, "tcl" STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
53 #pragma comment (lib, "tk"  STRINGIZE2(TCL_MAJOR_VERSION) STRINGIZE2(TCL_MINOR_VERSION) ".lib")
54 #undef STRINGIZE2
55 #undef STRINGIZE1
56 #endif
57
58 extern Standard_Boolean Draw_ParseFailed;
59
60 Standard_EXPORT Draw_Viewer dout;
61 Standard_EXPORT Draw_Interpretor theCommands;
62 Standard_EXPORT Standard_Boolean Draw_Batch;
63 Standard_EXPORT Standard_Boolean Draw_Spying = Standard_False;
64 Standard_EXPORT Standard_Boolean Draw_Chrono = Standard_False;
65 Standard_EXPORT Standard_Boolean Draw_VirtualWindows = Standard_False;
66 Standard_EXPORT Standard_Boolean ErrorMessages = Standard_True;
67
68 static const char* ColorNames[MAXCOLOR] = {
69   "White","Red","Green","Blue","Cyan","Gold","Magenta",
70   "Maroon","Orange","Pink","Salmon","Violet","Yellow","Khaki","Coral"
71   };
72
73 std::filebuf Draw_Spyfile;
74
75 static std::ostream spystream(&Draw_Spyfile);
76
77 static Handle(Draw_ProgressIndicator) PInd = NULL;
78
79 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
80 // true if complete command
81
82 // *******************************************************************
83 // read an init file
84 // *******************************************************************
85
86 static void interpreteTclCommand (const TCollection_AsciiString& theCmd)
87 {
88 #ifdef _WIN32
89   if (!Draw_Batch)
90   {
91     try
92     {
93       while (console_semaphore == HAS_CONSOLE_COMMAND)
94       {
95         Sleep(10);
96       }
97       {
98         TCollection_ExtendedString aCmdWide (theCmd);
99         wcscpy_s (console_command, aCmdWide.ToWideString());
100       }
101       console_semaphore = HAS_CONSOLE_COMMAND;
102       while (console_semaphore == HAS_CONSOLE_COMMAND)
103       {
104         Sleep(10);
105       }
106     }
107     catch (...)
108     {
109       std::cout << "Error while reading a script file.\n";
110       ExitProcess(0);
111     }
112   }
113   else
114 #endif
115   {
116     Draw_Interprete (theCmd.ToCString());
117   }
118 }
119
120 static void ReadInitFile (const TCollection_AsciiString& theFileName)
121 {
122   TCollection_AsciiString aCmd = theFileName;
123 #ifdef _WIN32
124   aCmd.ChangeAll ('\\', '/');
125 #endif
126   aCmd = TCollection_AsciiString ("source -encoding utf-8 \"") + aCmd + "\"";
127   interpreteTclCommand (aCmd);
128 }
129
130 //! Define environment variable available from Tcl and OCCT.
131 static void setOcctTclEnv (const TCollection_AsciiString& theName,
132                            TCollection_AsciiString& thePath)
133 {
134   if (thePath.IsEmpty())
135   {
136     return;
137   }
138
139   thePath.ChangeAll ('\\', '/');
140   OSD_Environment aRedPathEnv (theName);
141   aRedPathEnv.SetValue (thePath);
142   aRedPathEnv.Build();
143
144   const TCollection_AsciiString aPutEnv = theName + "=" + thePath;
145   Tcl_PutEnv (aPutEnv.ToCString());
146 }
147
148 //! Look for resource within standard installation layouts relative to executable location.
149 //!
150 //! Bin (INSTALL_DIR_BIN):
151 //!  - Windows: <prefix>/win64/vc10/bin(d)
152 //!  - Unix:    <prefix>/bin
153 //! Resources (INSTALL_DIR_RESOURCE):
154 //!  - Windows: <prefix>/src
155 //!  - Unix:    <prefix>/share/opencascade-7.0.0/resources
156 //! Samples (INSTALL_DIR_SAMPLES):
157 //!  - Windows: <prefix>/samples
158 //!  - Unix:    <prefix>/share/opencascade-7.0.0/samples
159 //! Tests (INSTALL_DIR_TESTS):
160 //!  - Windows: <prefix>/tests
161 //!  - Unix:    <prefix>/share/opencascade-7.0.0/tests
162 //!
163 //! @param theCasRoot  [out] found CASROOT location (e.g. installation folder)
164 //! @param theResRoot  [out] found resources root location
165 //! @param theResName   [in] resource to find ("resources", "samples", etc.)
166 //! @param theProbeFile [in] file to probe within resources location (e.g. "DrawResources/DrawDefault" within "resources")
167 static bool searchResources (TCollection_AsciiString& theCasRoot,
168                              TCollection_AsciiString& theResRoot,
169                              const TCollection_AsciiString& theResName,
170                              const TCollection_AsciiString& theProbeFile)
171 {
172   const TCollection_AsciiString aResLayouts[] =
173   {
174     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING_EXT "/") + theResName,
175     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_COMPLETE "/") + theResName,
176     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING "/") + theResName,
177     TCollection_AsciiString("/share/opencascade/") + theResName,
178     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING_EXT "/") + theResName,
179     TCollection_AsciiString("/share/occt-" OCC_VERSION_COMPLETE "/") + theResName,
180     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING "/") + theResName,
181     TCollection_AsciiString("/share/occt/") + theResName,
182     TCollection_AsciiString("/") + theResName,
183     TCollection_AsciiString("/share/opencascade"),
184     TCollection_AsciiString("/share/occt"),
185     TCollection_AsciiString("/share"),
186     TCollection_AsciiString("/src"),
187     TCollection_AsciiString("")
188   };
189
190   const TCollection_AsciiString anExeDir (OSD_Process::ExecutableFolder());
191   for (Standard_Integer aLayIter = 0;; ++aLayIter)
192   {
193     const TCollection_AsciiString& aResLayout = aResLayouts[aLayIter];
194     const TCollection_AsciiString  aProbeFile = aResLayout + "/" + theProbeFile;
195     if (OSD_File (anExeDir + aProbeFile).Exists())
196     {
197       theCasRoot = anExeDir;
198       theResRoot = theCasRoot + aResLayout;
199       return true;
200     }
201     // <prefix>/bin(d)
202     else if (OSD_File (anExeDir + "../" + aProbeFile).Exists())
203     {
204       theCasRoot = anExeDir + "..";
205       theResRoot = theCasRoot + aResLayout;
206       return true;
207     }
208     // <prefix>/gcc/bin(d)
209     else if (OSD_File (anExeDir + "../../" + aProbeFile).Exists())
210     {
211       theCasRoot = anExeDir + "../..";
212       theResRoot = theCasRoot + aResLayout;
213       return true;
214     }
215     // <prefix>/win64/vc10/bin(d)
216     else if (OSD_File (anExeDir + "../../../" + aProbeFile).Exists())
217     {
218       theCasRoot = anExeDir + "../../..";
219       theResRoot = theCasRoot + aResLayout;
220       return true;
221     }
222
223     if (aResLayout.IsEmpty())
224     {
225       return false;
226     }
227   }
228 }
229
230 //=======================================================================
231 //function : GetInterpretor
232 //purpose  :
233 //=======================================================================
234 Draw_Interpretor& Draw::GetInterpretor()
235 {
236   return theCommands;
237 }
238
239 //=======================================================================
240 //function :
241 //purpose  : Set/Get Progress Indicator
242 //=======================================================================
243 void Draw::SetProgressBar(const Handle(Draw_ProgressIndicator)& thePI)
244 {
245   PInd = thePI;
246 }
247
248 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
249 {
250   return PInd;
251 }
252
253 #ifndef _WIN32
254 /*--------------------------------------------------------*\
255 |  exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
256 \*--------------------------------------------------------*/
257 void exitProc(ClientData /*dc*/)
258 {
259   if (!Draw_Batch) {
260     for (Standard_Integer id = 0; id < MAXVIEW; id++)
261       dout.DeleteView(id);
262   }
263 }
264 #endif
265
266 // *******************************************************************
267 // main
268 // *******************************************************************
269 #ifdef _WIN32
270 Standard_EXPORT void Draw_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, int argc, wchar_t** argv, const FDraw_InitAppli Draw_InitAppli)
271 #else
272 void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
273 #endif
274 {
275
276 // prepend extra DLL search path to override system libraries like opengl32.dll
277 #ifdef _WIN32
278   OSD_Environment aUserDllEnv ("CSF_UserDllPath");
279   const TCollection_ExtendedString aUserDllPath (aUserDllEnv.Value());
280   if (!aUserDllPath.IsEmpty())
281   {
282     // This function available since Win XP SP1 #if (_WIN32_WINNT >= 0x0502).
283     // We retrieve dynamically here (kernel32 should be always preloaded).
284     typedef BOOL (WINAPI *SetDllDirectoryW_t)(const wchar_t* thePathName);
285     HMODULE aKern32Module = GetModuleHandleW (L"kernel32");
286     SetDllDirectoryW_t aFunc = (aKern32Module != NULL)
287                              ? (SetDllDirectoryW_t )GetProcAddress (aKern32Module, "SetDllDirectoryW") : NULL;
288     if (aFunc != NULL)
289     {
290       aFunc (aUserDllPath.ToWideString());
291     }
292     else
293     {
294       //std::cerr << "SetDllDirectoryW() is not available on this system!\n";
295     }
296     if (aKern32Module != NULL)
297     {
298       FreeLibrary (aKern32Module);
299     }
300   }
301 #endif
302
303   // *****************************************************************
304   // analyze arguments
305   // *****************************************************************
306   Draw_Batch = Standard_False;
307   TCollection_AsciiString aRunFile, aCommand;
308   Standard_Boolean isInteractiveForced = Standard_False;
309
310   // parse command line
311   for (int anArgIter = 1; anArgIter < argc; ++anArgIter)
312   {
313     TCollection_AsciiString anArg (argv[anArgIter]);
314     anArg.LowerCase();
315     if (anArg == "-h"
316      || anArg == "--help")
317     {
318       std::cout << "Open CASCADE " << OCC_VERSION_STRING_EXT << " DRAW Test Harness\n\n";
319       std::cout << "Options:\n";
320       std::cout << "  -b: batch mode (no GUI, no viewers)\n";
321       std::cout << "  -v: no GUI, use virtual (off-screen) windows for viewers\n";
322       std::cout << "  -i: interactive mode\n";
323       std::cout << "  -f file: execute script from file\n";
324       std::cout << "  -c command args...: execute command (with optional arguments)\n\n";
325       std::cout << "Options -b, -v, and -i are mutually exclusive.\n";
326       std::cout << "If -c or -f are given, -v is default; otherwise default is -i.\n";
327       std::cout << "Options -c and -f are alternatives and should be at the end \n";
328       std::cout << "of the command line.\n";
329       std::cout << "Option -c can accept set of commands separated by ';'.\n";
330       return;
331     }
332     else if (anArg == "-b")
333     {
334       Draw_Batch = Standard_True;
335     }
336     else if (anArg == "-v")
337     {
338       // force virtual windows
339       Draw_VirtualWindows = Standard_True;
340     }
341     else if (anArg == "-i")
342     {
343       // force interactive
344       Draw_VirtualWindows = Standard_False;
345       isInteractiveForced = Standard_True;
346     }
347     else if (anArg == "-f") // -f option should be LAST!
348     {
349       Draw_VirtualWindows = !isInteractiveForced;
350       if (++anArgIter < argc)
351       {
352         aRunFile = TCollection_AsciiString (argv[anArgIter]);
353       }
354       break;
355     }
356     else if (anArg == "-c") // -c option should be LAST!
357     {
358       Draw_VirtualWindows = !isInteractiveForced;
359       if (++anArgIter < argc)
360       {
361         aCommand = TCollection_AsciiString (argv[anArgIter]);
362       }
363       while (++anArgIter < argc)
364       {
365         aCommand.AssignCat (" ");
366         aCommand.AssignCat (argv[anArgIter]);
367       }
368       break;
369     }
370     else
371     {
372       std::cout << "Error: unsupported option " << TCollection_AsciiString (argv[anArgIter]) << "\n";
373     }
374   }
375
376   // *****************************************************************
377   // set signals
378   // *****************************************************************
379   OSD::SetSignal(Standard_False);
380
381 #ifdef _WIN32
382   // in interactive mode, force Windows to report dll loading problems interactively
383   if ( ! Draw_VirtualWindows && ! Draw_Batch )
384     ::SetErrorMode (0);
385 #endif
386
387   // *****************************************************************
388   // init X window and create display
389   // *****************************************************************
390 #ifdef _WIN32
391   HWND hWnd = NULL;
392 #endif
393
394   if (!Draw_Batch)
395 #ifdef _WIN32
396     Draw_Batch=!Init_Appli(hInst, hPrevInst, nShow, hWnd);
397 #else
398     Draw_Batch=!Init_Appli();
399 #endif
400   else
401   {
402     std::cout << "DRAW is running in batch mode" << std::endl;
403     theCommands.Init();
404     Tcl_Init(theCommands.Interp());
405   }
406
407   if (! Draw_Batch)
408   {
409     // Default colors
410     for (int i = 0; i < MAXCOLOR; ++i)
411     {
412       if (!dout.DefineColor (i, ColorNames[i]))
413       {
414         std::cout <<"Could not allocate default color " << ColorNames[i] << std::endl;
415       }
416     }
417   }
418
419   // *****************************************************************
420   // set maximum precision for cout
421   // *****************************************************************
422   std::cout.precision(15);
423
424   // *****************************************************************
425   // standard commands
426   // *****************************************************************
427   Draw::BasicCommands(theCommands);
428   Draw::VariableCommands(theCommands);
429   Draw::UnitCommands(theCommands);
430   if (!Draw_Batch) Draw::GraphicCommands(theCommands);
431
432   // *****************************************************************
433   // user commands
434   // *****************************************************************
435   Draw_InitAppli(theCommands);
436
437 #ifndef _WIN32
438   Tcl_CreateExitHandler(exitProc, 0);
439 #endif
440
441   // *****************************************************************
442   // read init files
443   // *****************************************************************
444   // default
445   const TCollection_AsciiString aDrawDef (OSD_Environment ("DRAWDEFAULT").Value());
446   if (!aDrawDef.IsEmpty())
447   {
448     ReadInitFile (aDrawDef);
449   }
450   else
451   {
452     TCollection_AsciiString aDrawHome;
453     TCollection_AsciiString aCasRoot (OSD_Environment ("CASROOT").Value());
454     if (!aCasRoot.IsEmpty())
455     {
456       aDrawHome = aCasRoot + "/src/DrawResources";
457     }
458     else
459     {
460       // search for relative locations within standard development environment
461       TCollection_AsciiString aResPath;
462       if (searchResources (aCasRoot, aResPath, "resources", "DrawResources/DrawDefault"))
463       {
464         aDrawHome = aResPath + "/DrawResources";
465         setOcctTclEnv ("CASROOT",  aCasRoot);
466         setOcctTclEnv ("DRAWHOME", aDrawHome);
467         setOcctTclEnv ("CSF_OCCTResourcePath", aResPath);
468       }
469
470       TCollection_AsciiString aSamplesPath;
471       if (OSD_Environment ("CSF_OCCTSamplesPath").Value().IsEmpty()
472        && searchResources (aCasRoot, aSamplesPath, "samples", "tcl/Readme.txt"))
473       {
474         setOcctTclEnv ("CSF_OCCTSamplesPath", aSamplesPath);
475       }
476
477       TCollection_AsciiString aTestsPath;
478       if (OSD_Environment ("CSF_TestScriptsPath").Value().IsEmpty()
479        && searchResources (aCasRoot, aTestsPath, "tests", "parse.rules"))
480       {
481         setOcctTclEnv ("CSF_TestScriptsPath", aTestsPath);
482       }
483     }
484
485     if (!aDrawHome.IsEmpty())
486     {
487       const TCollection_AsciiString aDefStr = aDrawHome + "/DrawDefault";
488       ReadInitFile (aDefStr);
489     }
490     else
491     {
492 #ifdef _WIN32
493       ReadInitFile ("ddefault");
494 #else
495       std::cout << " the CASROOT variable is mandatory to Run OpenCascade "<< std::endl;
496       std::cout << "No default file" << std::endl;
497 #endif
498     }
499   }
500
501   // read commands from file
502   if (!aRunFile.IsEmpty())
503   {
504     if (!isInteractiveForced)
505     {
506       // disable console messages colorization to avoid spoiling log with color codes
507       for (Message_SequenceOfPrinters::Iterator aPrinterIter (Message::DefaultMessenger()->Printers());
508            aPrinterIter.More(); aPrinterIter.Next())
509       {
510         if (Handle(Message_PrinterOStream) aPrinter = Handle(Message_PrinterOStream)::DownCast (aPrinterIter.Value()))
511         {
512           aPrinter->SetToColorize (Standard_False);
513         }
514       }
515     }
516     ReadInitFile (aRunFile);
517     // provide a clean exit, this is useful for some analysis tools
518     if ( ! isInteractiveForced )
519 #ifndef _WIN32
520       return;
521 #else
522       ExitProcess(0);
523 #endif
524   }
525
526   // execute command from command line
527   if (!aCommand.IsEmpty())
528   {
529 #ifdef _WIN32
530     if (!Draw_Batch)
531     {
532       // on Windows except batch mode, commands are executed in separate thread
533       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
534       TCollection_ExtendedString aCmdWide(aCommand);
535       wcscpy_s(console_command, aCmdWide.ToWideString());
536       console_semaphore = HAS_CONSOLE_COMMAND;
537       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
538     }
539     else
540 #endif
541     Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
542     // provide a clean exit, this is useful for some analysis tools
543     if ( ! isInteractiveForced )
544 #ifndef _WIN32
545       return;
546 #else
547       ExitProcess(0);
548 #endif
549   }
550
551   // *****************************************************************
552   // X loop
553   // *****************************************************************
554   if (! Draw_Batch) {
555 #ifdef _WIN32
556     Run_Appli(hWnd);
557 #else
558     Run_Appli(Draw_Interprete);
559 #endif
560   }
561   else
562   {
563     const int MAXCMD = 2048;
564     char cmd[MAXCMD];
565     for (int ncmd = 1;; ++ncmd)
566     {
567       std::cout << "Draw[" << ncmd << "]> ";
568       if (std::cin.getline (cmd, MAXCMD).fail())
569       {
570         break;
571       }
572       Draw_Interprete(cmd);
573     }
574   }
575 #ifdef _WIN32
576   // Destruction de l'application
577   Destroy_Appli(hInst);
578 #endif
579 }
580 //#endif
581
582 // User functions called before and after each command
583 void (*Draw_BeforeCommand)() = NULL;
584 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
585
586 Standard_Boolean Draw_Interprete(const char* com)
587 {
588
589   static Standard_Boolean first = Standard_True;
590   static Tcl_DString command;
591
592   if (first) {
593     first = Standard_False;
594     Tcl_DStringInit(&command);
595   }
596
597 #ifdef _WIN32
598   // string is already converted into UTF-8
599   Tcl_DStringAppend(&command, com, -1);
600 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
601   // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
602   Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
603 #else
604   Tcl_DStringAppend(&command,com,-1);
605 #endif
606
607   if (!theCommands.Complete(Tcl_DStringValue(&command)))
608     return Standard_False;
609
610   // *******************************************************************
611   // Command interpreter
612   // *******************************************************************
613
614 //  Standard_Integer i = 0;
615 //  Standard_Integer j = 0;
616
617   Standard_Boolean wasspying = Draw_Spying;
618
619   OSD_Timer tictac;
620   Standard_Boolean hadchrono = Draw_Chrono;
621   if (hadchrono) tictac.Start();
622
623   if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
624
625   Standard_Integer c;
626
627   c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
628
629   if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
630
631   if (wasspying && Draw_Spying) {
632     if (c > 0) spystream << "# ";
633     spystream << Tcl_DStringValue(&command) << "\n";
634   }
635
636   dout.Flush();
637
638   if (*theCommands.Result())
639   {
640     std::cout << theCommands.Result() << std::endl;
641   }
642
643   if (Draw_Chrono && hadchrono) {
644     tictac.Stop();
645     tictac.Show();
646   }
647
648   Tcl_DStringFree(&command);
649
650   return Standard_True;
651 }
652
653 //
654 // for TCl
655 //
656
657 Standard_Integer Tcl_AppInit (Tcl_Interp *)
658 {
659   return 0;
660 }
661
662 //
663 // for debug call
664 //
665
666
667
668 Standard_Integer  Draw_Call (char *c)
669 {
670    Standard_Integer r = theCommands.Eval(c);
671    std::cout << theCommands.Result() << std::endl;
672    return r;
673 }
674
675 //=================================================================================
676 //
677 //=================================================================================
678 void Draw::Load(Draw_Interpretor& theDI, const TCollection_AsciiString& theKey,
679                 const TCollection_AsciiString& theResourceFileName,
680                 TCollection_AsciiString& theDefaultsDirectory,
681                 TCollection_AsciiString& theUserDefaultsDirectory,
682                 const Standard_Boolean Verbose ) {
683
684   static Plugin_MapOfFunctions theMapOfFunctions;
685   OSD_Function f;
686
687   if(!theMapOfFunctions.IsBound(theKey)) {
688
689     Handle(Resource_Manager) aPluginResource = new Resource_Manager(theResourceFileName.ToCString(), theDefaultsDirectory, theUserDefaultsDirectory, Verbose);
690
691     if(!aPluginResource->Find(theKey.ToCString())) {
692       Standard_SStream aMsg; aMsg << "Could not find the resource:";
693       aMsg << theKey.ToCString()<< std::endl;
694       std::cout << "could not find the resource:"<<theKey.ToCString()<< std::endl;
695       throw Draw_Failure(aMsg.str().c_str());
696     }
697
698     TCollection_AsciiString aPluginLibrary("");
699 #if !defined(_WIN32) || defined(__MINGW32__)
700     aPluginLibrary += "lib";
701 #endif
702     aPluginLibrary +=  aPluginResource->Value(theKey.ToCString());
703 #ifdef _WIN32
704     aPluginLibrary += ".dll";
705 #elif __APPLE__
706     aPluginLibrary += ".dylib";
707 #elif defined (HPUX) || defined(_hpux)
708     aPluginLibrary += ".sl";
709 #else
710     aPluginLibrary += ".so";
711 #endif
712     OSD_SharedLibrary aSharedLibrary(aPluginLibrary.ToCString());
713     if(!aSharedLibrary.DlOpen(OSD_RTLD_LAZY)) {
714       TCollection_AsciiString error(aSharedLibrary.DlError());
715       Standard_SStream aMsg; aMsg << "Could not open: ";
716       aMsg << aPluginResource->Value(theKey.ToCString());
717       aMsg << "; reason: ";
718       aMsg << error.ToCString();
719 #ifdef OCCT_DEBUG
720       std::cout << "could not open: "  << aPluginResource->Value(theKey.ToCString())<< " ; reason: "<< error.ToCString() << std::endl;
721 #endif
722       throw Draw_Failure(aMsg.str().c_str());
723     }
724     f = aSharedLibrary.DlSymb("PLUGINFACTORY");
725     if( f == NULL ) {
726       TCollection_AsciiString error(aSharedLibrary.DlError());
727       Standard_SStream aMsg; aMsg << "Could not find the factory in: ";
728       aMsg << aPluginResource->Value(theKey.ToCString());
729       aMsg << error.ToCString();
730       throw Draw_Failure(aMsg.str().c_str());
731     }
732     theMapOfFunctions.Bind(theKey, f);
733   }
734   else
735     f = theMapOfFunctions(theKey);
736
737 //   void (*fp) (Draw_Interpretor&, const TCollection_AsciiString&) = NULL;
738 //   fp = (void (*)(Draw_Interpretor&, const TCollection_AsciiString&)) f;
739 //   (*fp) (theDI, theKey);
740
741   void (*fp) (Draw_Interpretor&) = NULL;
742   fp = (void (*)(Draw_Interpretor&)) f;
743   (*fp) (theDI);
744
745 }