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 extern Standard_Boolean Draw_ParseFailed;
47 
48 Standard_EXPORT Draw_Viewer dout;
49 Standard_EXPORT Draw_Interpretor theCommands;
50 Standard_EXPORT Standard_Boolean Draw_Batch = Standard_False;
51 Standard_EXPORT Standard_Boolean Draw_Spying = Standard_False;
52 Standard_EXPORT Standard_Boolean Draw_Chrono = Standard_False;
53 Standard_EXPORT Standard_Boolean Draw_VirtualWindows = Standard_False;
54 Standard_EXPORT Standard_Boolean ErrorMessages = Standard_True;
55 
56 static const char* ColorNames[MAXCOLOR] = {
57   "White","Red","Green","Blue","Cyan","Gold","Magenta",
58   "Maroon","Orange","Pink","Salmon","Violet","Yellow","Khaki","Coral"
59   };
60 
61 std::filebuf Draw_Spyfile;
62 
63 static std::ostream spystream(&Draw_Spyfile);
64 
65 static Handle(Draw_ProgressIndicator) global_Progress = NULL;
66 
67 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
68 // true if complete command
69 
70 // *******************************************************************
71 // read an init file
72 // *******************************************************************
73 
interpreteTclCommand(const TCollection_AsciiString & theCmd)74 static void interpreteTclCommand (const TCollection_AsciiString& theCmd)
75 {
76 #ifdef _WIN32
77   if (!Draw_Batch)
78   {
79     try
80     {
81       while (console_semaphore == HAS_CONSOLE_COMMAND)
82       {
83         Sleep(10);
84       }
85       {
86         TCollection_ExtendedString aCmdWide (theCmd);
87         wcscpy_s (console_command, aCmdWide.ToWideString());
88       }
89       console_semaphore = HAS_CONSOLE_COMMAND;
90       while (console_semaphore == HAS_CONSOLE_COMMAND)
91       {
92         Sleep(10);
93       }
94     }
95     catch (...)
96     {
97       std::cout << "Error while reading a script file.\n";
98       ExitProcess(0);
99     }
100   }
101   else
102 #endif
103   {
104     Draw_Interprete (theCmd.ToCString());
105   }
106 }
107 
ReadInitFile(const TCollection_AsciiString & theFileName)108 static void ReadInitFile (const TCollection_AsciiString& theFileName)
109 {
110   TCollection_AsciiString aCmd = theFileName;
111 #ifdef _WIN32
112   aCmd.ChangeAll ('\\', '/');
113 #endif
114   aCmd = TCollection_AsciiString ("source -encoding utf-8 \"") + aCmd + "\"";
115   interpreteTclCommand (aCmd);
116 }
117 
118 //! Define environment variable available from Tcl and OCCT.
setOcctTclEnv(const TCollection_AsciiString & theName,TCollection_AsciiString & thePath)119 static void setOcctTclEnv (const TCollection_AsciiString& theName,
120                            TCollection_AsciiString& thePath)
121 {
122   if (thePath.IsEmpty())
123   {
124     return;
125   }
126 
127   thePath.ChangeAll ('\\', '/');
128   OSD_Environment aRedPathEnv (theName);
129   aRedPathEnv.SetValue (thePath);
130   aRedPathEnv.Build();
131 
132   const TCollection_AsciiString aPutEnv = theName + "=" + thePath;
133   Tcl_PutEnv (aPutEnv.ToCString());
134 }
135 
136 //! Look for resource within standard installation layouts relative to executable location.
137 //!
138 //! Bin (INSTALL_DIR_BIN):
139 //!  - Windows: <prefix>/win64/vc10/bin(d)
140 //!  - Unix:    <prefix>/bin
141 //! Resources (INSTALL_DIR_RESOURCE):
142 //!  - Windows: <prefix>/src
143 //!  - Unix:    <prefix>/share/opencascade-7.0.0/resources
144 //! Samples (INSTALL_DIR_SAMPLES):
145 //!  - Windows: <prefix>/samples
146 //!  - Unix:    <prefix>/share/opencascade-7.0.0/samples
147 //! Tests (INSTALL_DIR_TESTS):
148 //!  - Windows: <prefix>/tests
149 //!  - Unix:    <prefix>/share/opencascade-7.0.0/tests
150 //!
151 //! @param theCasRoot  [out] found CASROOT location (e.g. installation folder)
152 //! @param theResRoot  [out] found resources root location
153 //! @param theResName   [in] resource to find ("resources", "samples", etc.)
154 //! @param theProbeFile [in] file to probe within resources location (e.g. "DrawResources/DrawDefault" within "resources")
searchResources(TCollection_AsciiString & theCasRoot,TCollection_AsciiString & theResRoot,const TCollection_AsciiString & theResName,const TCollection_AsciiString & theProbeFile)155 static bool searchResources (TCollection_AsciiString& theCasRoot,
156                              TCollection_AsciiString& theResRoot,
157                              const TCollection_AsciiString& theResName,
158                              const TCollection_AsciiString& theProbeFile)
159 {
160   const TCollection_AsciiString aResLayouts[] =
161   {
162     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING_EXT "/") + theResName,
163     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_COMPLETE "/") + theResName,
164     TCollection_AsciiString("/share/opencascade-" OCC_VERSION_STRING "/") + theResName,
165     TCollection_AsciiString("/share/opencascade/") + theResName,
166     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING_EXT "/") + theResName,
167     TCollection_AsciiString("/share/occt-" OCC_VERSION_COMPLETE "/") + theResName,
168     TCollection_AsciiString("/share/occt-" OCC_VERSION_STRING "/") + theResName,
169     TCollection_AsciiString("/share/occt/") + theResName,
170     TCollection_AsciiString("/") + theResName,
171     TCollection_AsciiString("/share/opencascade"),
172     TCollection_AsciiString("/share/occt"),
173     TCollection_AsciiString("/share"),
174     TCollection_AsciiString("/src"),
175     TCollection_AsciiString("")
176   };
177 
178   const TCollection_AsciiString anExeDir (OSD_Process::ExecutableFolder());
179   for (Standard_Integer aLayIter = 0;; ++aLayIter)
180   {
181     const TCollection_AsciiString& aResLayout = aResLayouts[aLayIter];
182     const TCollection_AsciiString  aProbeFile = aResLayout + "/" + theProbeFile;
183     if (OSD_File (anExeDir + aProbeFile).Exists())
184     {
185       theCasRoot = anExeDir;
186       theResRoot = theCasRoot + aResLayout;
187       return true;
188     }
189     // <prefix>/bin(d)
190     else if (OSD_File (anExeDir + "../" + aProbeFile).Exists())
191     {
192       theCasRoot = anExeDir + "..";
193       theResRoot = theCasRoot + aResLayout;
194       return true;
195     }
196     // <prefix>/gcc/bin(d)
197     else if (OSD_File (anExeDir + "../../" + aProbeFile).Exists())
198     {
199       theCasRoot = anExeDir + "../..";
200       theResRoot = theCasRoot + aResLayout;
201       return true;
202     }
203     // <prefix>/win64/vc10/bin(d)
204     else if (OSD_File (anExeDir + "../../../" + aProbeFile).Exists())
205     {
206       theCasRoot = anExeDir + "../../..";
207       theResRoot = theCasRoot + aResLayout;
208       return true;
209     }
210 
211     if (aResLayout.IsEmpty())
212     {
213       return false;
214     }
215   }
216 }
217 
218 //=======================================================================
219 //function : GetInterpretor
220 //purpose  :
221 //=======================================================================
GetInterpretor()222 Draw_Interpretor& Draw::GetInterpretor()
223 {
224   return theCommands;
225 }
226 
227 //=======================================================================
228 //function :
229 //purpose  : Set/Get Progress Indicator
230 //=======================================================================
SetProgressBar(const Handle (Draw_ProgressIndicator)& theProgress)231 void Draw::SetProgressBar(const Handle(Draw_ProgressIndicator)& theProgress)
232 {
233   global_Progress = theProgress;
234 }
235 
Handle(Draw_ProgressIndicator)236 Handle(Draw_ProgressIndicator) Draw::GetProgressBar()
237 {
238   return global_Progress;
239 }
240 
241 #ifndef _WIN32
242 /*--------------------------------------------------------*\
243 |  exitProc: finalization handler for Tcl/Tk thread. Forces parent process to die
244 \*--------------------------------------------------------*/
exitProc(ClientData)245 void exitProc(ClientData /*dc*/)
246 {
247   if (!Draw_Batch) {
248     for (Standard_Integer id = 0; id < MAXVIEW; id++)
249       dout.DeleteView(id);
250   }
251 }
252 #endif
253 
254 // *******************************************************************
255 // main
256 // *******************************************************************
257 #ifdef _WIN32
Draw_Appli(HINSTANCE hInst,HINSTANCE hPrevInst,int nShow,int argc,wchar_t ** argv,const FDraw_InitAppli Draw_InitAppli)258 Standard_EXPORT void Draw_Appli(HINSTANCE hInst, HINSTANCE hPrevInst, int nShow, int argc, wchar_t** argv, const FDraw_InitAppli Draw_InitAppli)
259 #else
260 void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
261 #endif
262 {
263 
264 // prepend extra DLL search path to override system libraries like opengl32.dll
265 #ifdef _WIN32
266   OSD_Environment aUserDllEnv ("CSF_UserDllPath");
267   const TCollection_ExtendedString aUserDllPath (aUserDllEnv.Value());
268   if (!aUserDllPath.IsEmpty())
269   {
270     // This function available since Win XP SP1 #if (_WIN32_WINNT >= 0x0502).
271     // We retrieve dynamically here (kernel32 should be always preloaded).
272     typedef BOOL (WINAPI *SetDllDirectoryW_t)(const wchar_t* thePathName);
273     HMODULE aKern32Module = GetModuleHandleW (L"kernel32");
274     SetDllDirectoryW_t aFunc = (aKern32Module != NULL)
275                              ? (SetDllDirectoryW_t )GetProcAddress (aKern32Module, "SetDllDirectoryW") : NULL;
276     if (aFunc != NULL)
277     {
278       aFunc (aUserDllPath.ToWideString());
279     }
280     else
281     {
282       //std::cerr << "SetDllDirectoryW() is not available on this system!\n";
283     }
284     if (aKern32Module != NULL)
285     {
286       FreeLibrary (aKern32Module);
287     }
288   }
289 #endif
290 
291   // *****************************************************************
292   // analyze arguments
293   // *****************************************************************
294   Draw_Batch = Standard_False;
295   TCollection_AsciiString aRunFile, aCommand;
296   Standard_Boolean isInteractiveForced = Standard_False;
297 
298   // parse command line
299   for (int anArgIter = 1; anArgIter < argc; ++anArgIter)
300   {
301     TCollection_AsciiString anArg (argv[anArgIter]);
302     anArg.LowerCase();
303     if (anArg == "-h"
304      || anArg == "--help")
305     {
306       std::cout << "Open CASCADE " << OCC_VERSION_STRING_EXT << " DRAW Test Harness\n\n";
307       std::cout << "Options:\n";
308       std::cout << "  -b: batch mode (no GUI, no viewers)\n";
309       std::cout << "  -v: no GUI, use virtual (off-screen) windows for viewers\n";
310       std::cout << "  -i: interactive mode\n";
311       std::cout << "  -f file: execute script from file\n";
312       std::cout << "  -c command args...: execute command (with optional arguments)\n\n";
313       std::cout << "Options -b, -v, and -i are mutually exclusive.\n";
314       std::cout << "If -c or -f are given, -v is default; otherwise default is -i.\n";
315       std::cout << "Options -c and -f are alternatives and should be at the end \n";
316       std::cout << "of the command line.\n";
317       std::cout << "Option -c can accept set of commands separated by ';'.\n";
318       return;
319     }
320     else if (anArg == "-b")
321     {
322       Draw_Batch = Standard_True;
323     }
324     else if (anArg == "-v")
325     {
326       // force virtual windows
327       Draw_VirtualWindows = Standard_True;
328     }
329     else if (anArg == "-i")
330     {
331       // force interactive
332       Draw_VirtualWindows = Standard_False;
333       isInteractiveForced = Standard_True;
334     }
335     else if (anArg == "-f") // -f option should be LAST!
336     {
337       Draw_VirtualWindows = !isInteractiveForced;
338       if (++anArgIter < argc)
339       {
340         aRunFile = TCollection_AsciiString (argv[anArgIter]);
341       }
342       break;
343     }
344     else if (anArg == "-c") // -c option should be LAST!
345     {
346       Draw_VirtualWindows = !isInteractiveForced;
347       if (++anArgIter < argc)
348       {
349         aCommand = TCollection_AsciiString (argv[anArgIter]);
350       }
351       while (++anArgIter < argc)
352       {
353         aCommand.AssignCat (" ");
354         aCommand.AssignCat (argv[anArgIter]);
355       }
356       break;
357     }
358     else
359     {
360       std::cout << "Error: unsupported option " << TCollection_AsciiString (argv[anArgIter]) << "\n";
361     }
362   }
363 
364   // *****************************************************************
365   // set signals
366   // *****************************************************************
367   OSD::SetSignal(Standard_False);
368   //OSD::SetSignalStackTraceLength (10);
369 
370 #ifdef _WIN32
371   // in interactive mode, force Windows to report dll loading problems interactively
372   if ( ! Draw_VirtualWindows && ! Draw_Batch )
373     ::SetErrorMode (0);
374 #endif
375 
376   // *****************************************************************
377   // init X window and create display
378   // *****************************************************************
379 #ifdef _WIN32
380   HWND hWnd = NULL;
381 #endif
382 
383   if (!Draw_Batch)
384 #ifdef _WIN32
385     Draw_Batch=!Init_Appli(hInst, hPrevInst, nShow, hWnd);
386 #else
387     Draw_Batch=!Init_Appli();
388 #endif
389   else
390   {
391     std::cout << "DRAW is running in batch mode" << std::endl;
392     theCommands.Init();
393     Tcl_Init(theCommands.Interp());
394   }
395 
396   if (! Draw_Batch)
397   {
398     // Default colors
399     for (int i = 0; i < MAXCOLOR; ++i)
400     {
401       if (!dout.DefineColor (i, ColorNames[i]))
402       {
403         std::cout <<"Could not allocate default color " << ColorNames[i] << std::endl;
404       }
405     }
406   }
407 
408   // *****************************************************************
409   // set maximum precision for cout
410   // *****************************************************************
411   std::cout.precision(15);
412 
413   // *****************************************************************
414   // standard commands
415   // *****************************************************************
416   Draw::BasicCommands(theCommands);
417   Draw::MessageCommands(theCommands);
418   Draw::VariableCommands(theCommands);
419   Draw::UnitCommands(theCommands);
420   if (!Draw_Batch) Draw::GraphicCommands(theCommands);
421 
422   // *****************************************************************
423   // user commands
424   // *****************************************************************
425   Draw_InitAppli(theCommands);
426 
427 #ifndef _WIN32
428   Tcl_CreateExitHandler(exitProc, 0);
429 #endif
430 
431   // *****************************************************************
432   // read init files
433   // *****************************************************************
434   // default
435   const TCollection_AsciiString aDrawDef (OSD_Environment ("DRAWDEFAULT").Value());
436   if (!aDrawDef.IsEmpty())
437   {
438     ReadInitFile (aDrawDef);
439   }
440   else
441   {
442     TCollection_AsciiString aDrawHome;
443     TCollection_AsciiString aCasRoot (OSD_Environment ("CASROOT").Value());
444     if (!aCasRoot.IsEmpty())
445     {
446       aDrawHome = aCasRoot + "/src/DrawResources";
447     }
448     else
449     {
450       // search for relative locations within standard development environment
451       TCollection_AsciiString aResPath;
452       if (searchResources (aCasRoot, aResPath, "resources", "DrawResources/DrawDefault"))
453       {
454         aDrawHome = aResPath + "/DrawResources";
455         setOcctTclEnv ("CASROOT",  aCasRoot);
456         setOcctTclEnv ("DRAWHOME", aDrawHome);
457         setOcctTclEnv ("CSF_OCCTResourcePath", aResPath);
458       }
459 
460       TCollection_AsciiString aSamplesPath;
461       if (OSD_Environment ("CSF_OCCTSamplesPath").Value().IsEmpty()
462        && searchResources (aCasRoot, aSamplesPath, "samples", "tcl/Readme.txt"))
463       {
464         setOcctTclEnv ("CSF_OCCTSamplesPath", aSamplesPath);
465       }
466 
467       TCollection_AsciiString aTestsPath;
468       if (OSD_Environment ("CSF_TestScriptsPath").Value().IsEmpty()
469        && searchResources (aCasRoot, aTestsPath, "tests", "parse.rules"))
470       {
471         setOcctTclEnv ("CSF_TestScriptsPath", aTestsPath);
472       }
473     }
474 
475     if (!aDrawHome.IsEmpty())
476     {
477       const TCollection_AsciiString aDefStr = aDrawHome + "/DrawDefault";
478       ReadInitFile (aDefStr);
479     }
480     else
481     {
482 #ifdef _WIN32
483       ReadInitFile ("ddefault");
484 #else
485       std::cout << " the CASROOT variable is mandatory to Run OpenCascade "<< std::endl;
486       std::cout << "No default file" << std::endl;
487 #endif
488     }
489   }
490 
491   // read commands from file
492   if (!aRunFile.IsEmpty())
493   {
494     if (!isInteractiveForced)
495     {
496       // disable console messages colorization to avoid spoiling log with color codes
497       theCommands.SetToColorize (Standard_False);
498     }
499     ReadInitFile (aRunFile);
500     // provide a clean exit, this is useful for some analysis tools
501     if ( ! isInteractiveForced )
502 #ifndef _WIN32
503       return;
504 #else
505       ExitProcess(0);
506 #endif
507   }
508 
509   // execute command from command line
510   if (!aCommand.IsEmpty())
511   {
512 #ifdef _WIN32
513     if (!Draw_Batch)
514     {
515       // on Windows except batch mode, commands are executed in separate thread
516       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
517       TCollection_ExtendedString aCmdWide(aCommand);
518       wcscpy_s(console_command, aCmdWide.ToWideString());
519       console_semaphore = HAS_CONSOLE_COMMAND;
520       while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
521     }
522     else
523 #endif
524     Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
525     // provide a clean exit, this is useful for some analysis tools
526     if ( ! isInteractiveForced )
527 #ifndef _WIN32
528       return;
529 #else
530       ExitProcess(0);
531 #endif
532   }
533 
534   // *****************************************************************
535   // X loop
536   // *****************************************************************
537   if (! Draw_Batch) {
538 #ifdef _WIN32
539     Run_Appli(hWnd);
540 #else
541     Run_Appli(Draw_Interprete);
542 #endif
543   }
544   else
545   {
546     const int MAXCMD = 2048;
547     char cmd[MAXCMD];
548     for (int ncmd = 1;; ++ncmd)
549     {
550       std::cout << "Draw[" << ncmd << "]> ";
551       if (std::cin.getline (cmd, MAXCMD).fail())
552       {
553         break;
554       }
555       Draw_Interprete(cmd);
556     }
557   }
558 #ifdef _WIN32
559   // Destruction de l'application
560   Destroy_Appli(hInst);
561 #endif
562 }
563 //#endif
564 
565 // User functions called before and after each command
566 void (*Draw_BeforeCommand)() = NULL;
567 void (*Draw_AfterCommand)(Standard_Integer) = NULL;
568 
Draw_Interprete(const char * com)569 Standard_Boolean Draw_Interprete(const char* com)
570 {
571 
572   static Standard_Boolean first = Standard_True;
573   static Tcl_DString command;
574 
575   if (first) {
576     first = Standard_False;
577     Tcl_DStringInit(&command);
578   }
579 
580 #ifdef _WIN32
581   // string is already converted into UTF-8
582   Tcl_DStringAppend(&command, com, -1);
583 #elif ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
584   // OCC63: Since Tcl 8.1 it uses UTF-8 encoding for internal representation of strings
585   Tcl_ExternalToUtfDString ( NULL, com, -1, &command );
586 #else
587   Tcl_DStringAppend(&command,com,-1);
588 #endif
589 
590   if (!theCommands.Complete(Tcl_DStringValue(&command)))
591     return Standard_False;
592 
593   // *******************************************************************
594   // Command interpreter
595   // *******************************************************************
596 
597 //  Standard_Integer i = 0;
598 //  Standard_Integer j = 0;
599 
600   Standard_Boolean wasspying = Draw_Spying;
601 
602   OSD_Timer tictac;
603   Standard_Boolean hadchrono = Draw_Chrono;
604   if (hadchrono) tictac.Start();
605 
606   if (Draw_BeforeCommand) (*Draw_BeforeCommand) ();
607 
608   Standard_Integer c;
609 
610   c = theCommands.RecordAndEval(Tcl_DStringValue(&command));
611 
612   if (Draw_AfterCommand) (*Draw_AfterCommand)(c);
613 
614   if (wasspying && Draw_Spying) {
615     if (c > 0) spystream << "# ";
616     spystream << Tcl_DStringValue(&command) << "\n";
617   }
618 
619   dout.Flush();
620 
621   if (*theCommands.Result())
622   {
623     if (c > 0 && theCommands.ToColorize())
624     {
625       Message_PrinterOStream::SetConsoleTextColor (&std::cout, Message_ConsoleColor_Red, true);
626     }
627     std::cout << theCommands.Result() << std::endl;
628     if (c > 0 && theCommands.ToColorize())
629     {
630       Message_PrinterOStream::SetConsoleTextColor (&std::cout, Message_ConsoleColor_Default, false);
631     }
632   }
633 
634   if (Draw_Chrono && hadchrono) {
635     tictac.Stop();
636     tictac.Show();
637   }
638 
639   Tcl_DStringFree(&command);
640 
641   return Standard_True;
642 }
643 
644 //
645 // for TCl
646 //
647 
Tcl_AppInit(Tcl_Interp *)648 Standard_Integer Tcl_AppInit (Tcl_Interp *)
649 {
650   return 0;
651 }
652 
653 //
654 // for debug call
655 //
656 
657 
658 
Draw_Call(char * c)659 Standard_Integer  Draw_Call (char *c)
660 {
661    Standard_Integer r = theCommands.Eval(c);
662    std::cout << theCommands.Result() << std::endl;
663    return r;
664 }
665 
666 //=================================================================================
667 //
668 //=================================================================================
Load(Draw_Interpretor & theDI,const TCollection_AsciiString & theKey,const TCollection_AsciiString & theResourceFileName,const TCollection_AsciiString & theDefaultsDirectory,const TCollection_AsciiString & theUserDefaultsDirectory,const Standard_Boolean theIsVerbose)669 void Draw::Load (Draw_Interpretor& theDI,
670                  const TCollection_AsciiString& theKey,
671                  const TCollection_AsciiString& theResourceFileName,
672                  const TCollection_AsciiString& theDefaultsDirectory,
673                  const TCollection_AsciiString& theUserDefaultsDirectory,
674                  const Standard_Boolean theIsVerbose)
675 {
676   static Plugin_MapOfFunctions theMapOfFunctions;
677   OSD_Function aFunc = NULL;
678   if (!theMapOfFunctions.Find (theKey, aFunc))
679   {
680     TCollection_AsciiString aPluginLibrary;
681     Handle(Resource_Manager) aPluginResource = new Resource_Manager (theResourceFileName, theDefaultsDirectory, theUserDefaultsDirectory, theIsVerbose);
682     if (!aPluginResource->Find (theKey, aPluginLibrary))
683     {
684       Message::SendFail() << "could not find the resource:" << theKey;
685       Standard_SStream aMsg; aMsg << "Could not find the resource:" << theKey << std::endl;
686       throw Draw_Failure (aMsg.str().c_str());
687     }
688 
689 #if !defined(_WIN32) || defined(__MINGW32__)
690     aPluginLibrary = TCollection_AsciiString ("lib") + aPluginLibrary;
691 #endif
692 #ifdef _WIN32
693     aPluginLibrary += ".dll";
694 #elif __APPLE__
695     aPluginLibrary += ".dylib";
696 #elif defined (HPUX) || defined(_hpux)
697     aPluginLibrary += ".sl";
698 #else
699     aPluginLibrary += ".so";
700 #endif
701     OSD_SharedLibrary aSharedLibrary (aPluginLibrary.ToCString());
702     if (!aSharedLibrary.DlOpen (OSD_RTLD_LAZY))
703     {
704       const TCollection_AsciiString anError (aSharedLibrary.DlError());
705       Standard_SStream aMsg;
706       aMsg << "Could not open: " << aPluginLibrary << "; reason: " << anError;
707 #ifdef OCCT_DEBUG
708       std::cout << "could not open: "  << aPluginLibrary << " ; reason: "<< anError << std::endl;
709 #endif
710       throw Draw_Failure(aMsg.str().c_str());
711     }
712 
713     aFunc = aSharedLibrary.DlSymb ("PLUGINFACTORY");
714     if (aFunc == NULL)
715     {
716       const TCollection_AsciiString anError (aSharedLibrary.DlError());
717       Standard_SStream aMsg;
718       aMsg << "Could not find the factory in: " << aPluginLibrary << anError;
719       throw Draw_Failure(aMsg.str().c_str());
720     }
721     theMapOfFunctions.Bind (theKey, aFunc);
722   }
723 
724   void (*fp) (Draw_Interpretor&) = NULL;
725   fp = (void (*)(Draw_Interpretor&) )aFunc;
726   (*fp) (theDI);
727 }
728 
729 namespace
730 {
731   const Standard_Integer THE_MAX_INTEGER_COLOR_COMPONENT = 255;
732   const Standard_ShortReal THE_MAX_REAL_COLOR_COMPONENT = 1.0f;
733 
734   //! Parses string and get an integer color component (only values within range 0 .. 255 are allowed)
735   //! @param theColorComponentString the string representing the color component
736   //! @param theIntegerColorComponent an integer color component that is a result of parsing
737   //! @return true if parsing was successful, or false otherwise
parseNumericalColorComponent(const Standard_CString theColorComponentString,Standard_Integer & theIntegerColorComponent)738   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
739                                             Standard_Integer&      theIntegerColorComponent)
740   {
741     Standard_Integer anIntegerColorComponent;
742     if (!Draw::ParseInteger (theColorComponentString, anIntegerColorComponent))
743     {
744       return false;
745     }
746     if ((anIntegerColorComponent < 0) || (anIntegerColorComponent > THE_MAX_INTEGER_COLOR_COMPONENT))
747     {
748       return false;
749     }
750     theIntegerColorComponent = anIntegerColorComponent;
751     return true;
752   }
753 
754   //! Parses the string and gets a real color component from it (only values within range 0.0 .. 1.0 are allowed)
755   //! @param theColorComponentString the string representing the color component
756   //! @param theRealColorComponent a real color component that is a result of parsing
757   //! @return true if parsing was successful, or false otherwise
parseNumericalColorComponent(const Standard_CString theColorComponentString,Standard_ShortReal & theRealColorComponent)758   static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
759                                             Standard_ShortReal&    theRealColorComponent)
760   {
761     Standard_Real aRealColorComponent;
762     if (!Draw::ParseReal (theColorComponentString, aRealColorComponent))
763     {
764       return false;
765     }
766     const Standard_ShortReal aShortRealColorComponent = static_cast<Standard_ShortReal> (aRealColorComponent);
767     if ((aShortRealColorComponent < 0.0f) || (aShortRealColorComponent > THE_MAX_REAL_COLOR_COMPONENT))
768     {
769       return false;
770     }
771     theRealColorComponent = aShortRealColorComponent;
772     return true;
773   }
774 
775   //! Parses the string and gets a real color component from it (integer values 2 .. 255 are scaled to the 0.0 .. 1.0
776   //! range, values 0 and 1 are leaved as they are)
777   //! @param theColorComponentString the string representing the color component
778   //! @param theColorComponent a color component that is a result of parsing
779   //! @return true if parsing was successful, or false otherwise
parseColorComponent(const Standard_CString theColorComponentString,Standard_ShortReal & theColorComponent)780   static bool parseColorComponent (const Standard_CString theColorComponentString,
781                                    Standard_ShortReal&    theColorComponent)
782   {
783     Standard_Integer anIntegerColorComponent;
784     if (parseNumericalColorComponent (theColorComponentString, anIntegerColorComponent))
785     {
786       if (anIntegerColorComponent == 1)
787       {
788         theColorComponent = THE_MAX_REAL_COLOR_COMPONENT;
789       }
790       else
791       {
792         theColorComponent = anIntegerColorComponent * 1.0f / THE_MAX_INTEGER_COLOR_COMPONENT;
793       }
794       return true;
795     }
796     return parseNumericalColorComponent (theColorComponentString, theColorComponent);
797   }
798 
799   //! Parses the array of strings and gets an integer color (only values within range 0 .. 255 are allowed and at least
800   //! one of components must be greater than 1)
801   //! @tparam TheNumber the type of resulting color vector elements
802   //! @param theNumberOfColorComponents the number of color components
803   //! @param theColorComponentStrings the array of strings representing color components
804   //! @param theNumericalColor a 4-component vector that is a result of parsing
805   //! @return true if parsing was successful, or false otherwise
806   template <typename TheNumber>
parseNumericalColor(Standard_Integer & theNumberOfColorComponents,const char * const * const theColorComponentStrings,NCollection_Vec4<TheNumber> & theNumericalColor)807   static bool parseNumericalColor (Standard_Integer&            theNumberOfColorComponents,
808                                    const char* const* const     theColorComponentStrings,
809                                    NCollection_Vec4<TheNumber>& theNumericalColor)
810   {
811     for (Standard_Integer aColorComponentIndex = 0; aColorComponentIndex < theNumberOfColorComponents;
812          ++aColorComponentIndex)
813     {
814       const char* const aColorComponentString = theColorComponentStrings[aColorComponentIndex];
815       TheNumber         aNumericalColorComponent;
816       if (parseNumericalColorComponent (aColorComponentString, aNumericalColorComponent))
817       {
818         theNumericalColor[aColorComponentIndex] = aNumericalColorComponent;
819       }
820       else
821       {
822         if (aColorComponentIndex == 3)
823         {
824           theNumberOfColorComponents = 3;
825         }
826         else
827         {
828           return false;
829         }
830       }
831     }
832     return true;
833   }
834 
835   //! Parses an array of strings and get an integer color (only values within range 0 .. 255 are allowed and at least
836   //! one of components must be greater than 1)
837   //! @param theNumberOfColorComponents the number of color components
838   //! @param theColorComponentStrings the array of strings representing color components
839   //! @param theColor a color that is a result of parsing
840   //! @return true if parsing was successful, or false otherwise
parseIntegerColor(Standard_Integer & theNumberOfColorComponents,const char * const * const theColorComponentStrings,Quantity_ColorRGBA & theColor)841   static bool parseIntegerColor (Standard_Integer&        theNumberOfColorComponents,
842                                  const char* const* const theColorComponentStrings,
843                                  Quantity_ColorRGBA&      theColor)
844   {
845     const Standard_Integer THE_COLOR_COMPONENT_NOT_PARSED = -1;
846     NCollection_Vec4<int>   anIntegerColor (THE_COLOR_COMPONENT_NOT_PARSED);
847     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, anIntegerColor)
848       || anIntegerColor.maxComp() <= 1)
849     {
850       return false;
851     }
852     if (anIntegerColor.a() == THE_COLOR_COMPONENT_NOT_PARSED)
853     {
854       anIntegerColor.a() = THE_MAX_INTEGER_COLOR_COMPONENT;
855     }
856 
857     const NCollection_Vec4<float> aRealColor = NCollection_Vec4<float> (anIntegerColor) / static_cast<float> (THE_MAX_INTEGER_COLOR_COMPONENT);
858     theColor = Quantity_ColorRGBA (Quantity_ColorRGBA::Convert_sRGB_To_LinearRGB (aRealColor));
859     return true;
860   }
861 
862   //! Parses an array of strings and get a real color (only values within range 0.0 .. 1.0 are allowed)
863   //! @param theNumberOfColorComponents the number of color components
864   //! @param theColorComponentStrings the array of strings representing color components
865   //! @param theColor a color that is a result of parsing
866   //! @return true if parsing was successful, or false otherwise
parseRealColor(Standard_Integer & theNumberOfColorComponents,const char * const * const theColorComponentStrings,Quantity_ColorRGBA & theColor)867   static bool parseRealColor (Standard_Integer&        theNumberOfColorComponents,
868                               const char* const* const theColorComponentStrings,
869                               Quantity_ColorRGBA&      theColor)
870   {
871     NCollection_Vec4<float> aRealColor (THE_MAX_REAL_COLOR_COMPONENT);
872     if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, aRealColor))
873     {
874       return false;
875     }
876     theColor = Quantity_ColorRGBA (aRealColor);
877     return true;
878   }
879 }
880 
881 //=======================================================================
882 // function : parseColor
883 // purpose  :
884 //=======================================================================
parseColor(const Standard_Integer theArgNb,const char * const * const theArgVec,Quantity_ColorRGBA & theColor,const bool theToParseAlpha)885 Standard_Integer Draw::parseColor (const Standard_Integer   theArgNb,
886                                    const char* const* const theArgVec,
887                                    Quantity_ColorRGBA&      theColor,
888                                    const bool               theToParseAlpha)
889 {
890   if ((theArgNb >= 1) && Quantity_ColorRGBA::ColorFromHex (theArgVec[0], theColor, !theToParseAlpha))
891   {
892     return 1;
893   }
894   if (theArgNb >= 1 && Quantity_ColorRGBA::ColorFromName (theArgVec[0], theColor))
895   {
896     if (theArgNb >= 2 && theToParseAlpha)
897     {
898       const Standard_CString anAlphaStr = theArgVec[1];
899       Standard_ShortReal     anAlphaComponent;
900       if (parseColorComponent (anAlphaStr, anAlphaComponent))
901       {
902         theColor.SetAlpha (anAlphaComponent);
903         return 2;
904       }
905     }
906     return 1;
907   }
908   if (theArgNb >= 3)
909   {
910     const Standard_Integer aNumberOfColorComponentsToParse = Min (theArgNb, theToParseAlpha ? 4 : 3);
911     Standard_Integer aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
912     if (parseIntegerColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
913     {
914       return aNumberOfColorComponentsParsed;
915     }
916     aNumberOfColorComponentsParsed = aNumberOfColorComponentsToParse;
917     if (parseRealColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
918     {
919       return aNumberOfColorComponentsParsed;
920     }
921     return 0;
922   }
923   return 0;
924 }
925 
926 //=======================================================================
927 //function : ParseOnOff
928 //purpose  :
929 //=======================================================================
ParseOnOff(Standard_CString theArg,Standard_Boolean & theIsOn)930 Standard_Boolean Draw::ParseOnOff (Standard_CString  theArg,
931                                    Standard_Boolean& theIsOn)
932 {
933   TCollection_AsciiString aFlag(theArg);
934   aFlag.LowerCase();
935   if (aFlag == "on"
936    || aFlag == "1")
937   {
938     theIsOn = Standard_True;
939     return Standard_True;
940   }
941   else if (aFlag == "off"
942         || aFlag == "0")
943   {
944     theIsOn = Standard_False;
945     return Standard_True;
946   }
947   return Standard_False;
948 }
949 
950 //=======================================================================
951 //function : ParseOnOffIterator
952 //purpose  :
953 //=======================================================================
ParseOnOffIterator(Standard_Integer theArgsNb,const char ** theArgVec,Standard_Integer & theArgIter)954 Standard_Boolean Draw::ParseOnOffIterator (Standard_Integer  theArgsNb,
955                                            const char**      theArgVec,
956                                            Standard_Integer& theArgIter)
957 {
958   Standard_Boolean isOn = Standard_True;
959   if (theArgIter + 1 < theArgsNb
960    && Draw::ParseOnOff (theArgVec[theArgIter + 1], isOn))
961   {
962     ++theArgIter;
963   }
964   return isOn;
965 }
966 
967 //=======================================================================
968 //function : ParseOnOffNoIterator
969 //purpose  :
970 //=======================================================================
ParseOnOffNoIterator(Standard_Integer theArgsNb,const char ** theArgVec,Standard_Integer & theArgIter)971 Standard_Boolean Draw::ParseOnOffNoIterator (Standard_Integer  theArgsNb,
972                                              const char**      theArgVec,
973                                              Standard_Integer& theArgIter)
974 {
975   Standard_Boolean toReverse = strncasecmp (theArgVec[theArgIter], "no", 2) == 0
976                             || strncasecmp (theArgVec[theArgIter], "-no", 3) == 0;
977   Standard_Boolean isOn = Draw::ParseOnOffIterator (theArgsNb, theArgVec, theArgIter);
978   return toReverse ? !isOn : isOn;
979 }
980