michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsEnvironment.h" michael@0: #include "prenv.h" michael@0: #include "prprf.h" michael@0: #include "nsBaseHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: #include "nsPromiseFlatString.h" michael@0: #include "nsDependentString.h" michael@0: #include "nsNativeCharsetUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsEnvironment, nsIEnvironment) michael@0: michael@0: nsresult michael@0: nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID, michael@0: void **aResult) michael@0: { michael@0: nsresult rv; michael@0: *aResult = nullptr; michael@0: michael@0: if (aOuter != nullptr) { michael@0: return NS_ERROR_NO_AGGREGATION; michael@0: } michael@0: michael@0: nsEnvironment* obj = new nsEnvironment(); michael@0: if (!obj) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: rv = obj->QueryInterface(aIID, aResult); michael@0: if (NS_FAILED(rv)) { michael@0: delete obj; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsEnvironment::~nsEnvironment() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsEnvironment::Exists(const nsAString& aName, bool *aOutValue) michael@0: { michael@0: nsAutoCString nativeName; michael@0: nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) michael@0: return rv; michael@0: michael@0: nsAutoCString nativeVal; michael@0: #if defined(XP_UNIX) michael@0: /* For Unix/Linux platforms we follow the Unix definition: michael@0: * An environment variable exists when |getenv()| returns a non-nullptr michael@0: * value. An environment variable does not exist when |getenv()| returns michael@0: * nullptr. michael@0: */ michael@0: const char *value = PR_GetEnv(nativeName.get()); michael@0: *aOutValue = value && *value; michael@0: #else michael@0: /* For non-Unix/Linux platforms we have to fall back to a michael@0: * "portable" definition (which is incorrect for Unix/Linux!!!!) michael@0: * which simply checks whether the string returned by |Get()| is empty michael@0: * or not. michael@0: */ michael@0: nsAutoString value; michael@0: Get(aName, value); michael@0: *aOutValue = !value.IsEmpty(); michael@0: #endif /* XP_UNIX */ michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue) michael@0: { michael@0: nsAutoCString nativeName; michael@0: nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) michael@0: return rv; michael@0: michael@0: nsAutoCString nativeVal; michael@0: const char *value = PR_GetEnv(nativeName.get()); michael@0: if (value && *value) { michael@0: rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue); michael@0: } else { michael@0: aOutValue.Truncate(); michael@0: rv = NS_OK; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* Environment strings must have static duration; We're gonna leak all of this michael@0: * at shutdown: this is by design, caused how Unix/Linux implement environment michael@0: * vars. michael@0: */ michael@0: michael@0: typedef nsBaseHashtableET EnvEntryType; michael@0: typedef nsTHashtable EnvHashType; michael@0: michael@0: static EnvHashType *gEnvHash = nullptr; michael@0: michael@0: static bool michael@0: EnsureEnvHash() michael@0: { michael@0: if (gEnvHash) michael@0: return true; michael@0: michael@0: gEnvHash = new EnvHashType; michael@0: if (!gEnvHash) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) michael@0: { michael@0: nsAutoCString nativeName; michael@0: nsAutoCString nativeVal; michael@0: michael@0: nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) michael@0: return rv; michael@0: michael@0: rv = NS_CopyUnicodeToNative(aValue, nativeVal); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) michael@0: return rv; michael@0: michael@0: MutexAutoLock lock(mLock); michael@0: michael@0: if (!EnsureEnvHash()){ michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get()); michael@0: if (!entry) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: char* newData = PR_smprintf("%s=%s", michael@0: nativeName.get(), michael@0: nativeVal.get()); michael@0: if (!newData) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: PR_SetEnv(newData); michael@0: if (entry->mData) { michael@0: PR_smprintf_free(entry->mData); michael@0: } michael@0: entry->mData = newData; michael@0: return NS_OK; michael@0: } michael@0: michael@0: