126 }
127
128 private static class CheckedEntrySet
129 extends AbstractSet<Map.Entry<String,String>>
130 {
131 private final Set<Map.Entry<String,String>> s;
132 public CheckedEntrySet(Set<Map.Entry<String,String>> s) {this.s = s;}
133 public int size() {return s.size();}
134 public boolean isEmpty() {return s.isEmpty();}
135 public void clear() { s.clear();}
136 public Iterator<Map.Entry<String,String>> iterator() {
137 return new Iterator<Map.Entry<String,String>>() {
138 Iterator<Map.Entry<String,String>> i = s.iterator();
139 public boolean hasNext() { return i.hasNext();}
140 public Map.Entry<String,String> next() {
141 return new CheckedEntry(i.next());
142 }
143 public void remove() { i.remove();}
144 };
145 }
146 private static Map.Entry<String,String> checkedEntry (Object o) {
147 Map.Entry<String,String> e = (Map.Entry<String,String>) o;
148 nonNullString(e.getKey());
149 nonNullString(e.getValue());
150 return e;
151 }
152 public boolean contains(Object o) {return s.contains(checkedEntry(o));}
153 public boolean remove(Object o) {return s.remove(checkedEntry(o));}
154 }
155
156 private static class CheckedValues extends AbstractCollection<String> {
157 private final Collection<String> c;
158 public CheckedValues(Collection<String> c) {this.c = c;}
159 public int size() {return c.size();}
160 public boolean isEmpty() {return c.isEmpty();}
161 public void clear() { c.clear();}
162 public Iterator<String> iterator() {return c.iterator();}
163 public boolean contains(Object o) {return c.contains(nonNullString(o));}
164 public boolean remove(Object o) {return c.remove(nonNullString(o));}
165 }
166
268 // but it turns out that _wgetenv is only consistent with
269 // GetEnvironmentStringsW (for non-ASCII) if `wmain' is used
270 // instead of `main', even in a process created using
271 // CREATE_UNICODE_ENVIRONMENT. Instead we perform the
272 // case-insensitive comparison ourselves. At least this
273 // guarantees that System.getenv().get(String) will be
274 // consistent with System.getenv(String).
275 return theCaseInsensitiveEnvironment.get(name);
276 }
277
278 // Only for use by System.getenv()
279 static Map<String,String> getenv() {
280 return theUnmodifiableEnvironment;
281 }
282
283 // Only for use by ProcessBuilder.environment()
284 static Map<String,String> environment() {
285 return (Map<String,String>) theEnvironment.clone();
286 }
287
288 // Only for use by Runtime.exec(...String[]envp...)
289 static Map<String,String> emptyEnvironment(int capacity) {
290 return new ProcessEnvironment(capacity);
291 }
292
293 private static native String environmentBlock();
294
295 // Only for use by ProcessImpl.start()
296 String toEnvironmentBlock() {
297 // Sort Unicode-case-insensitively by name
298 List<Map.Entry<String,String>> list = new ArrayList<>(entrySet());
299 Collections.sort(list, entryComparator);
300
301 StringBuilder sb = new StringBuilder(size()*30);
302 for (Map.Entry<String,String> e : list)
303 sb.append(e.getKey())
304 .append('=')
305 .append(e.getValue())
306 .append('\u0000');
307 // Ensure double NUL termination,
308 // even if environment is empty.
309 if (sb.length() == 0)
310 sb.append('\u0000');
311 sb.append('\u0000');
312 return sb.toString();
313 }
314
315 static String toEnvironmentBlock(Map<String,String> map) {
316 return map == null ? null :
317 ((ProcessEnvironment)map).toEnvironmentBlock();
318 }
319 }
|
126 }
127
128 private static class CheckedEntrySet
129 extends AbstractSet<Map.Entry<String,String>>
130 {
131 private final Set<Map.Entry<String,String>> s;
132 public CheckedEntrySet(Set<Map.Entry<String,String>> s) {this.s = s;}
133 public int size() {return s.size();}
134 public boolean isEmpty() {return s.isEmpty();}
135 public void clear() { s.clear();}
136 public Iterator<Map.Entry<String,String>> iterator() {
137 return new Iterator<Map.Entry<String,String>>() {
138 Iterator<Map.Entry<String,String>> i = s.iterator();
139 public boolean hasNext() { return i.hasNext();}
140 public Map.Entry<String,String> next() {
141 return new CheckedEntry(i.next());
142 }
143 public void remove() { i.remove();}
144 };
145 }
146 private static Map.Entry<String,String> checkedEntry(Object o) {
147 Map.Entry<String,String> e = (Map.Entry<String,String>) o;
148 nonNullString(e.getKey());
149 nonNullString(e.getValue());
150 return e;
151 }
152 public boolean contains(Object o) {return s.contains(checkedEntry(o));}
153 public boolean remove(Object o) {return s.remove(checkedEntry(o));}
154 }
155
156 private static class CheckedValues extends AbstractCollection<String> {
157 private final Collection<String> c;
158 public CheckedValues(Collection<String> c) {this.c = c;}
159 public int size() {return c.size();}
160 public boolean isEmpty() {return c.isEmpty();}
161 public void clear() { c.clear();}
162 public Iterator<String> iterator() {return c.iterator();}
163 public boolean contains(Object o) {return c.contains(nonNullString(o));}
164 public boolean remove(Object o) {return c.remove(nonNullString(o));}
165 }
166
268 // but it turns out that _wgetenv is only consistent with
269 // GetEnvironmentStringsW (for non-ASCII) if `wmain' is used
270 // instead of `main', even in a process created using
271 // CREATE_UNICODE_ENVIRONMENT. Instead we perform the
272 // case-insensitive comparison ourselves. At least this
273 // guarantees that System.getenv().get(String) will be
274 // consistent with System.getenv(String).
275 return theCaseInsensitiveEnvironment.get(name);
276 }
277
278 // Only for use by System.getenv()
279 static Map<String,String> getenv() {
280 return theUnmodifiableEnvironment;
281 }
282
283 // Only for use by ProcessBuilder.environment()
284 static Map<String,String> environment() {
285 return (Map<String,String>) theEnvironment.clone();
286 }
287
288 // Only for use by ProcessBuilder.environment(String[] envp)
289 static Map<String,String> emptyEnvironment(int capacity) {
290 return new ProcessEnvironment(capacity);
291 }
292
293 private static native String environmentBlock();
294
295 // Only for use by ProcessImpl.start()
296 String toEnvironmentBlock() {
297 // Sort Unicode-case-insensitively by name
298 List<Map.Entry<String,String>> list = new ArrayList<>(entrySet());
299 Collections.sort(list, entryComparator);
300
301 StringBuilder sb = new StringBuilder(size()*30);
302 int cmp = -1;
303
304 // Some versions of MSVCRT.DLL require SystemRoot to be set.
305 // So, we make sure that it is always set, even if not provided
306 // by the caller.
307 final String SYSTEMROOT = "SystemRoot";
308
309 for (Map.Entry<String,String> e : list) {
310 String key = e.getKey();
311 String value = e.getValue();
312 if (cmp < 0 && (cmp = nameComparator.compare(key, SYSTEMROOT)) > 0) {
313 // Not set, so add it here
314 addToEnvIfSet(sb, SYSTEMROOT);
315 }
316 addToEnv(sb, key, value);
317 }
318 if (cmp < 0) {
319 // Got to end of list and still not found
320 addToEnvIfSet(sb, SYSTEMROOT);
321 }
322 if (sb.length() == 0) {
323 // Environment was empty and SystemRoot not set in parent
324 sb.append('\u0000');
325 }
326 // Block is double NUL terminated
327 sb.append('\u0000');
328 return sb.toString();
329 }
330
331 // add the environment variable to the child, if it exists in parent
332 private static void addToEnvIfSet(StringBuilder sb, String name) {
333 String s = getenv(name);
334 if (s != null)
335 addToEnv(sb, name, s);
336 }
337
338 private static void addToEnv(StringBuilder sb, String name, String val) {
339 sb.append(name).append("=").append(val).append('\u0000');
340 }
341
342 static String toEnvironmentBlock(Map<String,String> map) {
343 return map == null ? null :
344 ((ProcessEnvironment)map).toEnvironmentBlock();
345 }
346 }
|