0030959: OSD_Parallel_TBB: number of execution threads is strictly limited by the...
[occt.git] / src / OSD / OSD_Environment.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #ifndef _WIN32
16
17 #include <OSD_Environment.hxx>
18 #include <OSD_OSDError.hxx>
19 #include <OSD_WhoAmI.hxx>
20 #include <Standard_ConstructionError.hxx>
21 #include <Standard_Failure.hxx>
22 #include <Standard_Mutex.hxx>
23 #include <Standard_NullObject.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <NCollection_UtfString.hxx>
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 static const OSD_WhoAmI Iam = OSD_WEnvironment;
32
33 // ----------------------------------------------------------------------
34 //
35 // Updated by : JPT Dec,7 1992
36 // What       : OSD_Environment::OSD_Environment
37 //                              (const TCollection_AsciiString& Name,
38 //                               const TCollection_AsciiString& Value)
39 //              Value could contain the character $ (Ex setenv a = $c)
40 // 
41 // ----------------------------------------------------------------------
42 // Create object
43
44 OSD_Environment::OSD_Environment()
45 {
46 }
47
48
49 // ----------------------------------------------------------------------
50 // Constructor
51 // ----------------------------------------------------------------------
52
53 OSD_Environment::OSD_Environment(const TCollection_AsciiString& Name)
54 {
55
56  if (!Name.IsAscii() || Name.Search("$") != -1 ) 
57    throw Standard_ConstructionError("OSD_Environment::OSD_Environment: bad argument");
58
59  myName = Name; 
60 }
61
62
63 // ----------------------------------------------------------------------
64 // Create an environment variable and initialize it
65 // ----------------------------------------------------------------------
66
67 OSD_Environment::OSD_Environment(const TCollection_AsciiString& Name,
68                                  const TCollection_AsciiString& Value)
69 {
70
71  if (!Name.IsAscii() || !Value.IsAscii() || 
72 // JPT : Dec-7-1992     Name.Search("$") != -1 || Value.Search("$") != -1) 
73      Name.Search("$") != -1 ) 
74    throw Standard_ConstructionError("OSD_Environment::OSD_Environment: bad argument");
75
76  myName = Name; 
77  myValue = Value;
78 }
79
80
81 // ----------------------------------------------------------------------
82 // Returns the name of the symbol
83 // ----------------------------------------------------------------------
84
85 TCollection_AsciiString OSD_Environment::Name () const
86 {
87  return myName;
88 }
89
90 // ----------------------------------------------------------------------
91 // Set new value for environment variable
92 // ----------------------------------------------------------------------
93
94 void OSD_Environment::SetName (const TCollection_AsciiString& Name)
95 {
96  myError.Reset();
97  if (!Name.IsAscii() || Name.Search("$") != -1 ) 
98    throw Standard_ConstructionError("OSD_Environment::SetName: bad argument");
99
100  myName = Name;
101 }
102
103 // ----------------------------------------------------------------------
104 // Change value 
105 // ----------------------------------------------------------------------
106
107 void OSD_Environment::SetValue (const TCollection_AsciiString& Value)
108 {
109  if (!Value.IsAscii() || Value.Search("$") != -1) 
110    throw Standard_ConstructionError("OSD_Environment::Change: bad argument");
111
112  myValue = Value;
113 }
114
115 // ----------------------------------------------------------------------
116 // Get environment variable physically
117 // ----------------------------------------------------------------------
118
119 TCollection_AsciiString OSD_Environment::Value()
120 {
121  char *result = getenv(myName.ToCString());
122  if (result == NULL) myValue.Clear();
123  else myValue = result;
124  return myValue;
125 }
126
127 // ----------------------------------------------------------------------
128 // Sets physically the environment variable
129 // ----------------------------------------------------------------------
130
131 void OSD_Environment::Build ()
132 {
133   // Static buffer to hold definitions of new variables for the environment.
134   // Note that they need to be static since putenv does not make a copy
135   // of the string, but just adds its pointer to the environment.
136   static char **buffer  = 0 ;     // JPT:
137   static int    Ibuffer = 0 ;     // Tout ca pour putenv,getenv
138
139   // Use mutex to avoid concurrent access to the buffer
140   static Standard_Mutex theMutex;
141   Standard_Mutex::Sentry aSentry ( theMutex );
142
143   // check if such variable has already been created in the buffer
144   int index = -1, len = myName.Length();
145   for ( int i=0; i < Ibuffer; i++ ) {
146     if ( ! strncmp ( buffer[i], myName.ToCString(), len ) && buffer[i][len] == '=' ) {
147       index = i;
148       break;
149     }
150   }
151
152   // and either add a new entry, or remember the old entry for a while
153   char *old_value = 0;
154   if ( index >=0 ) {
155     old_value = buffer[index];
156   }
157   else {
158     // Allocation memoire. Surtout tout la heap!
159     index = Ibuffer++;
160     char **aTmp;
161     aTmp = (char **) realloc ( buffer, Ibuffer * sizeof(char*) );
162     if (aTmp)
163     {
164       buffer = aTmp;
165     }
166     else
167     {
168       myError.SetValue(errno, Iam, "Memory realloc failure");
169       return;
170     }
171   }
172    
173   // create a new entry in the buffer and add it to environment
174   buffer[index] = (char *) malloc ( len + myValue.Length() + 2 );
175   sprintf(buffer[index], "%s=%s", myName.ToCString(), myValue.ToCString());
176   putenv(buffer[index]);
177
178   // then (and only then!) free old entry, if existed
179   if ( old_value ) 
180     free ( old_value );
181   
182   // check the result
183   char *result = getenv(myName.ToCString());
184   if (result == NULL)
185     myError.SetValue(errno, Iam, "Set Environment");
186 }
187
188 // ----------------------------------------------------------------------
189 // Remove physically the environment variable
190 // ----------------------------------------------------------------------
191
192 void OSD_Environment::Remove ()
193 {
194   myValue.Clear();
195   Build();
196 }
197
198
199
200 // ----------------------------------------------------------------------
201 // ----------------------------------------------------------------------
202 void OSD_Environment::Reset()
203 {
204   myError.Reset();
205 }
206
207 // ----------------------------------------------------------------------
208 // ----------------------------------------------------------------------
209 Standard_Boolean OSD_Environment::Failed() const
210 {
211   return myError.Failed();
212 }
213
214 // ----------------------------------------------------------------------
215 // ----------------------------------------------------------------------
216 void OSD_Environment::Perror() 
217 {
218   myError.Perror();
219 }
220
221
222 // ----------------------------------------------------------------------
223 // ----------------------------------------------------------------------
224 Standard_Integer OSD_Environment::Error() const
225 {
226   return myError.Error();
227 }
228
229 #else
230
231 //------------------------------------------------------------------------
232 //-------------------  WNT Sources of OSD_Environment --------------------
233 //------------------------------------------------------------------------
234
235 #include <windows.h>
236
237 #include <OSD_Environment.hxx>
238
239 #include <OSD_WNT.hxx>
240
241 #include <NCollection_DataMap.hxx>
242 #include <NCollection_UtfString.hxx>
243 #include <Standard_Mutex.hxx>
244
245 #ifdef OCCT_UWP
246 namespace
247 {
248   // emulate global map of environment variables
249   static Standard_Mutex THE_ENV_LOCK;
250   static NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> THE_ENV_MAP;
251 }
252 #else
253 static void __fastcall _set_error ( OSD_Error&, DWORD );
254 #endif
255
256 OSD_Environment :: OSD_Environment () {
257
258 }  // end constructor ( 1 )
259
260 OSD_Environment :: OSD_Environment ( const TCollection_AsciiString& Name ) {
261
262  myName = Name;
263
264 }  // end constructor ( 2 )
265
266 OSD_Environment :: OSD_Environment (
267                     const TCollection_AsciiString& Name,
268                     const TCollection_AsciiString& Value
269                    ) {
270
271  myName  = Name;
272  myValue = Value;
273
274 }  // end constructor ( 3 )
275
276 void OSD_Environment :: SetValue ( const TCollection_AsciiString& Value ) {
277
278  myValue = Value;
279
280 }  // end OSD_Environment :: SetValue
281
282 TCollection_AsciiString OSD_Environment::Value()
283 {
284   myValue.Clear();
285 #ifdef OCCT_UWP
286   Standard_Mutex::Sentry aLock (THE_ENV_LOCK);
287   THE_ENV_MAP.Find (myName, myValue);
288 #else
289
290   // msvc C-runtime (_wputenv()) puts variable using WinAPI internally (calls SetEnvironmentVariableW())
291   // and also caches its value in its own map,
292   // so that _wgetenv() ignores WinAPI and retieves variable from this cache.
293   //
294   // Using _wgetenv() might lead to awkward results in context when several C-runtimes are used
295   // at once within application or WinAPI is used directly for setting environment variable.
296   //
297   // Using _wputenv() + GetEnvironmentVariableW() pair should provide most robust behavior in tricky scenarios.
298   // So that  _wgetenv() users will retrieve proper value set by OSD_Environment if used C-runtime library is the same as used by OCCT,
299   // and OSD_Environment will retreieve most up-to-date value of environment variable nevertheless C-runtime version used (or not used at all) for setting value externally,
300   // considering msvc C-runtime implementation details.
301   SetLastError (ERROR_SUCCESS);
302   NCollection_UtfWideString aNameWide (myName.ToCString());
303   DWORD aSize = GetEnvironmentVariableW (aNameWide.ToCString(), NULL, 0);
304   if (aSize == 0 && GetLastError() != ERROR_SUCCESS)
305   {
306     _set_error (myError, ERROR_ENVVAR_NOT_FOUND);
307     return myValue;
308   }
309
310   NCollection_Utf8String aValue;
311   aSize += 1; // NULL-terminator
312   wchar_t* aBuff = new wchar_t[aSize];
313   GetEnvironmentVariableW (aNameWide.ToCString(), aBuff, aSize);
314   aBuff[aSize - 1] = L'\0';
315   aValue.FromUnicode (aBuff);
316   delete[] aBuff;
317   Reset();
318
319   myValue = aValue.ToCString();
320 #endif
321   return myValue;
322 }
323
324 void OSD_Environment :: SetName ( const TCollection_AsciiString& name ) {
325
326  myName = name;
327
328 }  // end OSD_Environment :: SetName
329
330 TCollection_AsciiString OSD_Environment :: Name () const {
331
332  return myName;
333
334 }  // end OSD_Environment :: Name
335
336 void OSD_Environment::Build()
337 {
338 #ifdef OCCT_UWP
339   Standard_Mutex::Sentry aLock(THE_ENV_LOCK);
340   THE_ENV_MAP.Bind (myName, myValue);
341 #else
342   NCollection_Utf8String aSetVariable = NCollection_Utf8String(myName.ToCString()) + "=" + myValue.ToCString();
343   _wputenv (aSetVariable.ToUtfWide().ToCString());
344 #endif
345 }
346
347 void OSD_Environment::Remove()
348 {
349 #ifdef OCCT_UWP
350   Standard_Mutex::Sentry aLock(THE_ENV_LOCK);
351   THE_ENV_MAP.UnBind (myName);
352 #else
353   NCollection_Utf8String aSetVariable = NCollection_Utf8String(myName.ToCString()) + "=";
354   _wputenv (aSetVariable.ToUtfWide().ToCString());
355 #endif
356 }
357
358 Standard_Boolean OSD_Environment :: Failed () const {
359
360  return myError.Failed ();
361
362 }  // end OSD_Environment :: Failed
363
364 void OSD_Environment :: Reset () {
365
366  myError.Reset ();
367
368 }  // end OSD_Environment :: Reset
369
370 void OSD_Environment :: Perror ()
371 {
372   myError.Perror ();
373 }  // end OSD_Environment :: Perror
374
375 Standard_Integer OSD_Environment :: Error () const {
376
377  return myError.Error ();
378
379 }  // end OSD_Environment :: Error
380
381 #ifndef OCCT_UWP
382 static void __fastcall _set_error (OSD_Error& theErr, DWORD theCode)
383 {
384   wchar_t aBuffer[2048];
385   const DWORD anErrCode = theCode != 0 ? theCode : GetLastError();
386   if (!FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
387                        0, anErrCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ),
388                        aBuffer, 2048, NULL))
389   {
390     theErr.SetValue (anErrCode, OSD_WEnvironment, TCollection_AsciiString ("error code ") + (Standard_Integer)anErrCode);
391     SetLastError (anErrCode);
392   }
393   else
394   {
395     theErr.SetValue (anErrCode, OSD_WEnvironment, TCollection_AsciiString (aBuffer));
396   }
397 }
398 #endif
399
400 #endif