Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/java/lang/ProcessEnvironment.java
32287 views
1
/*
2
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/* We use APIs that access the standard Unix environ array, which
27
* is defined by UNIX98 to look like:
28
*
29
* char **environ;
30
*
31
* These are unsorted, case-sensitive, null-terminated arrays of bytes
32
* of the form FOO=BAR\000 which are usually encoded in the user's
33
* default encoding (file.encoding is an excellent choice for
34
* encoding/decoding these). However, even though the user cannot
35
* directly access the underlying byte representation, we take pains
36
* to pass on the child the exact byte representation we inherit from
37
* the parent process for any environment name or value not created by
38
* Javaland. So we keep track of all the byte representations.
39
*
40
* Internally, we define the types Variable and Value that exhibit
41
* String/byteArray duality. The internal representation of the
42
* environment then looks like a Map<Variable,Value>. But we don't
43
* expose this to the user -- we only provide a Map<String,String>
44
* view, although we could also provide a Map<byte[],byte[]> view.
45
*
46
* The non-private methods in this class are not for general use even
47
* within this package. Instead, they are the system-dependent parts
48
* of the system-independent method of the same name. Don't even
49
* think of using this class unless your method's name appears below.
50
*
51
* @author Martin Buchholz
52
* @since 1.5
53
*/
54
55
package java.lang;
56
57
import java.io.*;
58
import java.util.*;
59
60
61
final class ProcessEnvironment
62
{
63
private static final HashMap<Variable,Value> theEnvironment;
64
private static final Map<String,String> theUnmodifiableEnvironment;
65
static final int MIN_NAME_LENGTH = 0;
66
67
static {
68
// We cache the C environment. This means that subsequent calls
69
// to putenv/setenv from C will not be visible from Java code.
70
byte[][] environ = environ();
71
theEnvironment = new HashMap<>(environ.length/2 + 3);
72
// Read environment variables back to front,
73
// so that earlier variables override later ones.
74
for (int i = environ.length-1; i > 0; i-=2)
75
theEnvironment.put(Variable.valueOf(environ[i-1]),
76
Value.valueOf(environ[i]));
77
78
theUnmodifiableEnvironment
79
= Collections.unmodifiableMap
80
(new StringEnvironment(theEnvironment));
81
}
82
83
/* Only for use by System.getenv(String) */
84
static String getenv(String name) {
85
return theUnmodifiableEnvironment.get(name);
86
}
87
88
/* Only for use by System.getenv() */
89
static Map<String,String> getenv() {
90
return theUnmodifiableEnvironment;
91
}
92
93
/* Only for use by ProcessBuilder.environment() */
94
@SuppressWarnings("unchecked")
95
static Map<String,String> environment() {
96
return new StringEnvironment
97
((Map<Variable,Value>)(theEnvironment.clone()));
98
}
99
100
/* Only for use by Runtime.exec(...String[]envp...) */
101
static Map<String,String> emptyEnvironment(int capacity) {
102
return new StringEnvironment(new HashMap<Variable,Value>(capacity));
103
}
104
105
private static native byte[][] environ();
106
107
// This class is not instantiable.
108
private ProcessEnvironment() {}
109
110
// Check that name is suitable for insertion into Environment map
111
private static void validateVariable(String name) {
112
if (name.indexOf('=') != -1 ||
113
name.indexOf('\u0000') != -1)
114
throw new IllegalArgumentException
115
("Invalid environment variable name: \"" + name + "\"");
116
}
117
118
// Check that value is suitable for insertion into Environment map
119
private static void validateValue(String value) {
120
if (value.indexOf('\u0000') != -1)
121
throw new IllegalArgumentException
122
("Invalid environment variable value: \"" + value + "\"");
123
}
124
125
// A class hiding the byteArray-String duality of
126
// text data on Unixoid operating systems.
127
private static abstract class ExternalData {
128
protected final String str;
129
protected final byte[] bytes;
130
131
protected ExternalData(String str, byte[] bytes) {
132
this.str = str;
133
this.bytes = bytes;
134
}
135
136
public byte[] getBytes() {
137
return bytes;
138
}
139
140
public String toString() {
141
return str;
142
}
143
144
public boolean equals(Object o) {
145
return o instanceof ExternalData
146
&& arrayEquals(getBytes(), ((ExternalData) o).getBytes());
147
}
148
149
public int hashCode() {
150
return arrayHash(getBytes());
151
}
152
}
153
154
private static class Variable
155
extends ExternalData implements Comparable<Variable>
156
{
157
protected Variable(String str, byte[] bytes) {
158
super(str, bytes);
159
}
160
161
public static Variable valueOfQueryOnly(Object str) {
162
return valueOfQueryOnly((String) str);
163
}
164
165
public static Variable valueOfQueryOnly(String str) {
166
return new Variable(str, str.getBytes());
167
}
168
169
public static Variable valueOf(String str) {
170
validateVariable(str);
171
return valueOfQueryOnly(str);
172
}
173
174
public static Variable valueOf(byte[] bytes) {
175
return new Variable(new String(bytes), bytes);
176
}
177
178
public int compareTo(Variable variable) {
179
return arrayCompare(getBytes(), variable.getBytes());
180
}
181
182
public boolean equals(Object o) {
183
return o instanceof Variable && super.equals(o);
184
}
185
}
186
187
private static class Value
188
extends ExternalData implements Comparable<Value>
189
{
190
protected Value(String str, byte[] bytes) {
191
super(str, bytes);
192
}
193
194
public static Value valueOfQueryOnly(Object str) {
195
return valueOfQueryOnly((String) str);
196
}
197
198
public static Value valueOfQueryOnly(String str) {
199
return new Value(str, str.getBytes());
200
}
201
202
public static Value valueOf(String str) {
203
validateValue(str);
204
return valueOfQueryOnly(str);
205
}
206
207
public static Value valueOf(byte[] bytes) {
208
return new Value(new String(bytes), bytes);
209
}
210
211
public int compareTo(Value value) {
212
return arrayCompare(getBytes(), value.getBytes());
213
}
214
215
public boolean equals(Object o) {
216
return o instanceof Value && super.equals(o);
217
}
218
}
219
220
// This implements the String map view the user sees.
221
private static class StringEnvironment
222
extends AbstractMap<String,String>
223
{
224
private Map<Variable,Value> m;
225
private static String toString(Value v) {
226
return v == null ? null : v.toString();
227
}
228
public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
229
public int size() {return m.size();}
230
public boolean isEmpty() {return m.isEmpty();}
231
public void clear() { m.clear();}
232
public boolean containsKey(Object key) {
233
return m.containsKey(Variable.valueOfQueryOnly(key));
234
}
235
public boolean containsValue(Object value) {
236
return m.containsValue(Value.valueOfQueryOnly(value));
237
}
238
public String get(Object key) {
239
return toString(m.get(Variable.valueOfQueryOnly(key)));
240
}
241
public String put(String key, String value) {
242
return toString(m.put(Variable.valueOf(key),
243
Value.valueOf(value)));
244
}
245
public String remove(Object key) {
246
return toString(m.remove(Variable.valueOfQueryOnly(key)));
247
}
248
public Set<String> keySet() {
249
return new StringKeySet(m.keySet());
250
}
251
public Set<Map.Entry<String,String>> entrySet() {
252
return new StringEntrySet(m.entrySet());
253
}
254
public Collection<String> values() {
255
return new StringValues(m.values());
256
}
257
258
// It is technically feasible to provide a byte-oriented view
259
// as follows:
260
// public Map<byte[],byte[]> asByteArrayMap() {
261
// return new ByteArrayEnvironment(m);
262
// }
263
264
265
// Convert to Unix style environ as a monolithic byte array
266
// inspired by the Windows Environment Block, except we work
267
// exclusively with bytes instead of chars, and we need only
268
// one trailing NUL on Unix.
269
// This keeps the JNI as simple and efficient as possible.
270
public byte[] toEnvironmentBlock(int[]envc) {
271
int count = m.size() * 2; // For added '=' and NUL
272
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
273
count += entry.getKey().getBytes().length;
274
count += entry.getValue().getBytes().length;
275
}
276
277
byte[] block = new byte[count];
278
279
int i = 0;
280
for (Map.Entry<Variable,Value> entry : m.entrySet()) {
281
byte[] key = entry.getKey ().getBytes();
282
byte[] value = entry.getValue().getBytes();
283
System.arraycopy(key, 0, block, i, key.length);
284
i+=key.length;
285
block[i++] = (byte) '=';
286
System.arraycopy(value, 0, block, i, value.length);
287
i+=value.length + 1;
288
// No need to write NUL byte explicitly
289
//block[i++] = (byte) '\u0000';
290
}
291
envc[0] = m.size();
292
return block;
293
}
294
}
295
296
static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
297
return map == null ? null :
298
((StringEnvironment)map).toEnvironmentBlock(envc);
299
}
300
301
302
private static class StringEntry
303
implements Map.Entry<String,String>
304
{
305
private final Map.Entry<Variable,Value> e;
306
public StringEntry(Map.Entry<Variable,Value> e) {this.e = e;}
307
public String getKey() {return e.getKey().toString();}
308
public String getValue() {return e.getValue().toString();}
309
public String setValue(String newValue) {
310
return e.setValue(Value.valueOf(newValue)).toString();
311
}
312
public String toString() {return getKey() + "=" + getValue();}
313
public boolean equals(Object o) {
314
return o instanceof StringEntry
315
&& e.equals(((StringEntry)o).e);
316
}
317
public int hashCode() {return e.hashCode();}
318
}
319
320
private static class StringEntrySet
321
extends AbstractSet<Map.Entry<String,String>>
322
{
323
private final Set<Map.Entry<Variable,Value>> s;
324
public StringEntrySet(Set<Map.Entry<Variable,Value>> s) {this.s = s;}
325
public int size() {return s.size();}
326
public boolean isEmpty() {return s.isEmpty();}
327
public void clear() { s.clear();}
328
public Iterator<Map.Entry<String,String>> iterator() {
329
return new Iterator<Map.Entry<String,String>>() {
330
Iterator<Map.Entry<Variable,Value>> i = s.iterator();
331
public boolean hasNext() {return i.hasNext();}
332
public Map.Entry<String,String> next() {
333
return new StringEntry(i.next());
334
}
335
public void remove() {i.remove();}
336
};
337
}
338
private static Map.Entry<Variable,Value> vvEntry(final Object o) {
339
if (o instanceof StringEntry)
340
return ((StringEntry)o).e;
341
return new Map.Entry<Variable,Value>() {
342
public Variable getKey() {
343
return Variable.valueOfQueryOnly(((Map.Entry)o).getKey());
344
}
345
public Value getValue() {
346
return Value.valueOfQueryOnly(((Map.Entry)o).getValue());
347
}
348
public Value setValue(Value value) {
349
throw new UnsupportedOperationException();
350
}
351
};
352
}
353
public boolean contains(Object o) { return s.contains(vvEntry(o)); }
354
public boolean remove(Object o) { return s.remove(vvEntry(o)); }
355
public boolean equals(Object o) {
356
return o instanceof StringEntrySet
357
&& s.equals(((StringEntrySet) o).s);
358
}
359
public int hashCode() {return s.hashCode();}
360
}
361
362
private static class StringValues
363
extends AbstractCollection<String>
364
{
365
private final Collection<Value> c;
366
public StringValues(Collection<Value> c) {this.c = c;}
367
public int size() {return c.size();}
368
public boolean isEmpty() {return c.isEmpty();}
369
public void clear() { c.clear();}
370
public Iterator<String> iterator() {
371
return new Iterator<String>() {
372
Iterator<Value> i = c.iterator();
373
public boolean hasNext() {return i.hasNext();}
374
public String next() {return i.next().toString();}
375
public void remove() {i.remove();}
376
};
377
}
378
public boolean contains(Object o) {
379
return c.contains(Value.valueOfQueryOnly(o));
380
}
381
public boolean remove(Object o) {
382
return c.remove(Value.valueOfQueryOnly(o));
383
}
384
public boolean equals(Object o) {
385
return o instanceof StringValues
386
&& c.equals(((StringValues)o).c);
387
}
388
public int hashCode() {return c.hashCode();}
389
}
390
391
private static class StringKeySet extends AbstractSet<String> {
392
private final Set<Variable> s;
393
public StringKeySet(Set<Variable> s) {this.s = s;}
394
public int size() {return s.size();}
395
public boolean isEmpty() {return s.isEmpty();}
396
public void clear() { s.clear();}
397
public Iterator<String> iterator() {
398
return new Iterator<String>() {
399
Iterator<Variable> i = s.iterator();
400
public boolean hasNext() {return i.hasNext();}
401
public String next() {return i.next().toString();}
402
public void remove() { i.remove();}
403
};
404
}
405
public boolean contains(Object o) {
406
return s.contains(Variable.valueOfQueryOnly(o));
407
}
408
public boolean remove(Object o) {
409
return s.remove(Variable.valueOfQueryOnly(o));
410
}
411
}
412
413
// Replace with general purpose method someday
414
private static int arrayCompare(byte[]x, byte[] y) {
415
int min = x.length < y.length ? x.length : y.length;
416
for (int i = 0; i < min; i++)
417
if (x[i] != y[i])
418
return x[i] - y[i];
419
return x.length - y.length;
420
}
421
422
// Replace with general purpose method someday
423
private static boolean arrayEquals(byte[] x, byte[] y) {
424
if (x.length != y.length)
425
return false;
426
for (int i = 0; i < x.length; i++)
427
if (x[i] != y[i])
428
return false;
429
return true;
430
}
431
432
// Replace with general purpose method someday
433
private static int arrayHash(byte[] x) {
434
int hash = 0;
435
for (int i = 0; i < x.length; i++)
436
hash = 31 * hash + x[i];
437
return hash;
438
}
439
440
}
441
442