|
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/. */ |
|
5 |
|
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" |
|
14 |
|
15 using namespace mozilla; |
|
16 |
|
17 NS_IMPL_ISUPPORTS(nsEnvironment, nsIEnvironment) |
|
18 |
|
19 nsresult |
|
20 nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID, |
|
21 void **aResult) |
|
22 { |
|
23 nsresult rv; |
|
24 *aResult = nullptr; |
|
25 |
|
26 if (aOuter != nullptr) { |
|
27 return NS_ERROR_NO_AGGREGATION; |
|
28 } |
|
29 |
|
30 nsEnvironment* obj = new nsEnvironment(); |
|
31 if (!obj) { |
|
32 return NS_ERROR_OUT_OF_MEMORY; |
|
33 } |
|
34 |
|
35 rv = obj->QueryInterface(aIID, aResult); |
|
36 if (NS_FAILED(rv)) { |
|
37 delete obj; |
|
38 } |
|
39 return rv; |
|
40 } |
|
41 |
|
42 nsEnvironment::~nsEnvironment() |
|
43 { |
|
44 } |
|
45 |
|
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; |
|
53 |
|
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 */ |
|
73 |
|
74 return NS_OK; |
|
75 } |
|
76 |
|
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; |
|
84 |
|
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 } |
|
93 |
|
94 return rv; |
|
95 } |
|
96 |
|
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 */ |
|
101 |
|
102 typedef nsBaseHashtableET<nsCharPtrHashKey,char*> EnvEntryType; |
|
103 typedef nsTHashtable<EnvEntryType> EnvHashType; |
|
104 |
|
105 static EnvHashType *gEnvHash = nullptr; |
|
106 |
|
107 static bool |
|
108 EnsureEnvHash() |
|
109 { |
|
110 if (gEnvHash) |
|
111 return true; |
|
112 |
|
113 gEnvHash = new EnvHashType; |
|
114 if (!gEnvHash) |
|
115 return false; |
|
116 |
|
117 return true; |
|
118 } |
|
119 |
|
120 NS_IMETHODIMP |
|
121 nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) |
|
122 { |
|
123 nsAutoCString nativeName; |
|
124 nsAutoCString nativeVal; |
|
125 |
|
126 nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); |
|
127 if (NS_WARN_IF(NS_FAILED(rv))) |
|
128 return rv; |
|
129 |
|
130 rv = NS_CopyUnicodeToNative(aValue, nativeVal); |
|
131 if (NS_WARN_IF(NS_FAILED(rv))) |
|
132 return rv; |
|
133 |
|
134 MutexAutoLock lock(mLock); |
|
135 |
|
136 if (!EnsureEnvHash()){ |
|
137 return NS_ERROR_UNEXPECTED; |
|
138 } |
|
139 |
|
140 EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get()); |
|
141 if (!entry) { |
|
142 return NS_ERROR_OUT_OF_MEMORY; |
|
143 } |
|
144 |
|
145 char* newData = PR_smprintf("%s=%s", |
|
146 nativeName.get(), |
|
147 nativeVal.get()); |
|
148 if (!newData) { |
|
149 return NS_ERROR_OUT_OF_MEMORY; |
|
150 } |
|
151 |
|
152 PR_SetEnv(newData); |
|
153 if (entry->mData) { |
|
154 PR_smprintf_free(entry->mData); |
|
155 } |
|
156 entry->mData = newData; |
|
157 return NS_OK; |
|
158 } |
|
159 |
|
160 |