1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
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>
31 static const OSD_WhoAmI Iam = OSD_WEnvironment;
33 // ----------------------------------------------------------------------
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)
41 // ----------------------------------------------------------------------
44 OSD_Environment::OSD_Environment()
49 // ----------------------------------------------------------------------
51 // ----------------------------------------------------------------------
53 OSD_Environment::OSD_Environment(const TCollection_AsciiString& Name)
56 if (!Name.IsAscii() || Name.Search("$") != -1 )
57 throw Standard_ConstructionError("OSD_Environment::OSD_Environment: bad argument");
63 // ----------------------------------------------------------------------
64 // Create an environment variable and initialize it
65 // ----------------------------------------------------------------------
67 OSD_Environment::OSD_Environment(const TCollection_AsciiString& Name,
68 const TCollection_AsciiString& Value)
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");
81 // ----------------------------------------------------------------------
82 // Returns the name of the symbol
83 // ----------------------------------------------------------------------
85 TCollection_AsciiString OSD_Environment::Name () const
90 // ----------------------------------------------------------------------
91 // Set new value for environment variable
92 // ----------------------------------------------------------------------
94 void OSD_Environment::SetName (const TCollection_AsciiString& Name)
97 if (!Name.IsAscii() || Name.Search("$") != -1 )
98 throw Standard_ConstructionError("OSD_Environment::SetName: bad argument");
103 // ----------------------------------------------------------------------
105 // ----------------------------------------------------------------------
107 void OSD_Environment::SetValue (const TCollection_AsciiString& Value)
109 if (!Value.IsAscii() || Value.Search("$") != -1)
110 throw Standard_ConstructionError("OSD_Environment::Change: bad argument");
115 // ----------------------------------------------------------------------
116 // Get environment variable physically
117 // ----------------------------------------------------------------------
119 TCollection_AsciiString OSD_Environment::Value()
121 char *result = getenv(myName.ToCString());
122 if (result == NULL) myValue.Clear();
123 else myValue = result;
127 // ----------------------------------------------------------------------
128 // Sets physically the environment variable
129 // ----------------------------------------------------------------------
131 void OSD_Environment::Build ()
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
139 // Use mutex to avoid concurrent access to the buffer
140 static Standard_Mutex theMutex;
141 Standard_Mutex::Sentry aSentry ( theMutex );
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] == '=' ) {
152 // and either add a new entry, or remember the old entry for a while
155 old_value = buffer[index];
158 // Allocation memoire. Surtout tout la heap!
161 aTmp = (char **) realloc ( buffer, Ibuffer * sizeof(char*) );
168 myError.SetValue(errno, Iam, "Memory realloc failure");
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]);
178 // then (and only then!) free old entry, if existed
183 char *result = getenv(myName.ToCString());
185 myError.SetValue(errno, Iam, "Set Environment");
188 // ----------------------------------------------------------------------
189 // Remove physically the environment variable
190 // ----------------------------------------------------------------------
192 void OSD_Environment::Remove ()
200 // ----------------------------------------------------------------------
201 // ----------------------------------------------------------------------
202 void OSD_Environment::Reset()
207 // ----------------------------------------------------------------------
208 // ----------------------------------------------------------------------
209 Standard_Boolean OSD_Environment::Failed() const
211 return myError.Failed();
214 // ----------------------------------------------------------------------
215 // ----------------------------------------------------------------------
216 void OSD_Environment::Perror()
222 // ----------------------------------------------------------------------
223 // ----------------------------------------------------------------------
224 Standard_Integer OSD_Environment::Error() const
226 return myError.Error();
231 //------------------------------------------------------------------------
232 //------------------- WNT Sources of OSD_Environment --------------------
233 //------------------------------------------------------------------------
237 #include <OSD_Environment.hxx>
239 #include <OSD_WNT.hxx>
241 #include <NCollection_DataMap.hxx>
242 #include <NCollection_UtfString.hxx>
243 #include <Standard_Mutex.hxx>
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;
253 static void __fastcall _set_error ( OSD_Error&, DWORD );
256 OSD_Environment :: OSD_Environment () {
258 } // end constructor ( 1 )
260 OSD_Environment :: OSD_Environment ( const TCollection_AsciiString& Name ) {
264 } // end constructor ( 2 )
266 OSD_Environment :: OSD_Environment (
267 const TCollection_AsciiString& Name,
268 const TCollection_AsciiString& Value
274 } // end constructor ( 3 )
276 void OSD_Environment :: SetValue ( const TCollection_AsciiString& Value ) {
280 } // end OSD_Environment :: SetValue
282 TCollection_AsciiString OSD_Environment::Value()
286 Standard_Mutex::Sentry aLock (THE_ENV_LOCK);
287 THE_ENV_MAP.Find (myName, myValue);
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.
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.
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)
306 _set_error (myError, ERROR_ENVVAR_NOT_FOUND);
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);
319 myValue = aValue.ToCString();
324 void OSD_Environment :: SetName ( const TCollection_AsciiString& name ) {
328 } // end OSD_Environment :: SetName
330 TCollection_AsciiString OSD_Environment :: Name () const {
334 } // end OSD_Environment :: Name
336 void OSD_Environment::Build()
339 Standard_Mutex::Sentry aLock(THE_ENV_LOCK);
340 THE_ENV_MAP.Bind (myName, myValue);
342 NCollection_Utf8String aSetVariable = NCollection_Utf8String(myName.ToCString()) + "=" + myValue.ToCString();
343 _wputenv (aSetVariable.ToUtfWide().ToCString());
347 void OSD_Environment::Remove()
350 Standard_Mutex::Sentry aLock(THE_ENV_LOCK);
351 THE_ENV_MAP.UnBind (myName);
353 NCollection_Utf8String aSetVariable = NCollection_Utf8String(myName.ToCString()) + "=";
354 _wputenv (aSetVariable.ToUtfWide().ToCString());
358 Standard_Boolean OSD_Environment :: Failed () const {
360 return myError.Failed ();
362 } // end OSD_Environment :: Failed
364 void OSD_Environment :: Reset () {
368 } // end OSD_Environment :: Reset
370 void OSD_Environment :: Perror ()
373 } // end OSD_Environment :: Perror
375 Standard_Integer OSD_Environment :: Error () const {
377 return myError.Error ();
379 } // end OSD_Environment :: Error
382 static void __fastcall _set_error (OSD_Error& theErr, DWORD theCode)
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))
390 theErr.SetValue (anErrCode, OSD_WEnvironment, TCollection_AsciiString ("error code ") + (Standard_Integer)anErrCode);
391 SetLastError (anErrCode);
395 theErr.SetValue (anErrCode, OSD_WEnvironment, TCollection_AsciiString (aBuffer));