Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsEnvironment.h"
7 #include "prenv.h"
8 #include "prprf.h"
9 #include "nsBaseHashtable.h"
10 #include "nsHashKeys.h"
11 #include "nsPromiseFlatString.h"
12 #include "nsDependentString.h"
13 #include "nsNativeCharsetUtils.h"
15 using namespace mozilla;
17 NS_IMPL_ISUPPORTS(nsEnvironment, nsIEnvironment)
19 nsresult
20 nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID,
21 void **aResult)
22 {
23 nsresult rv;
24 *aResult = nullptr;
26 if (aOuter != nullptr) {
27 return NS_ERROR_NO_AGGREGATION;
28 }
30 nsEnvironment* obj = new nsEnvironment();
31 if (!obj) {
32 return NS_ERROR_OUT_OF_MEMORY;
33 }
35 rv = obj->QueryInterface(aIID, aResult);
36 if (NS_FAILED(rv)) {
37 delete obj;
38 }
39 return rv;
40 }
42 nsEnvironment::~nsEnvironment()
43 {
44 }
46 NS_IMETHODIMP
47 nsEnvironment::Exists(const nsAString& aName, bool *aOutValue)
48 {
49 nsAutoCString nativeName;
50 nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
51 if (NS_WARN_IF(NS_FAILED(rv)))
52 return rv;
54 nsAutoCString nativeVal;
55 #if defined(XP_UNIX)
56 /* For Unix/Linux platforms we follow the Unix definition:
57 * An environment variable exists when |getenv()| returns a non-nullptr
58 * value. An environment variable does not exist when |getenv()| returns
59 * nullptr.
60 */
61 const char *value = PR_GetEnv(nativeName.get());
62 *aOutValue = value && *value;
63 #else
64 /* For non-Unix/Linux platforms we have to fall back to a
65 * "portable" definition (which is incorrect for Unix/Linux!!!!)
66 * which simply checks whether the string returned by |Get()| is empty
67 * or not.
68 */
69 nsAutoString value;
70 Get(aName, value);
71 *aOutValue = !value.IsEmpty();
72 #endif /* XP_UNIX */
74 return NS_OK;
75 }
77 NS_IMETHODIMP
78 nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue)
79 {
80 nsAutoCString nativeName;
81 nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
82 if (NS_WARN_IF(NS_FAILED(rv)))
83 return rv;
85 nsAutoCString nativeVal;
86 const char *value = PR_GetEnv(nativeName.get());
87 if (value && *value) {
88 rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue);
89 } else {
90 aOutValue.Truncate();
91 rv = NS_OK;
92 }
94 return rv;
95 }
97 /* Environment strings must have static duration; We're gonna leak all of this
98 * at shutdown: this is by design, caused how Unix/Linux implement environment
99 * vars.
100 */
102 typedef nsBaseHashtableET<nsCharPtrHashKey,char*> EnvEntryType;
103 typedef nsTHashtable<EnvEntryType> EnvHashType;
105 static EnvHashType *gEnvHash = nullptr;
107 static bool
108 EnsureEnvHash()
109 {
110 if (gEnvHash)
111 return true;
113 gEnvHash = new EnvHashType;
114 if (!gEnvHash)
115 return false;
117 return true;
118 }
120 NS_IMETHODIMP
121 nsEnvironment::Set(const nsAString& aName, const nsAString& aValue)
122 {
123 nsAutoCString nativeName;
124 nsAutoCString nativeVal;
126 nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
127 if (NS_WARN_IF(NS_FAILED(rv)))
128 return rv;
130 rv = NS_CopyUnicodeToNative(aValue, nativeVal);
131 if (NS_WARN_IF(NS_FAILED(rv)))
132 return rv;
134 MutexAutoLock lock(mLock);
136 if (!EnsureEnvHash()){
137 return NS_ERROR_UNEXPECTED;
138 }
140 EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get());
141 if (!entry) {
142 return NS_ERROR_OUT_OF_MEMORY;
143 }
145 char* newData = PR_smprintf("%s=%s",
146 nativeName.get(),
147 nativeVal.get());
148 if (!newData) {
149 return NS_ERROR_OUT_OF_MEMORY;
150 }
152 PR_SetEnv(newData);
153 if (entry->mData) {
154 PR_smprintf_free(entry->mData);
155 }
156 entry->mData = newData;
157 return NS_OK;
158 }