37 |
|
|
38 |
|
|
39 |
package java.util; |
package java.util; |
40 |
import java.io.*; |
|
41 |
|
import java.io.IOException; |
42 |
|
import java.io.InputStream; |
43 |
|
import java.io.BufferedReader; |
44 |
|
import java.io.InputStreamReader; |
45 |
|
import java.io.OutputStream; |
46 |
|
import java.io.PrintWriter; |
47 |
|
import java.io.PrintStream; |
48 |
|
import java.io.OutputStreamWriter; |
49 |
|
|
50 |
/** |
/** |
51 |
* A set of persistent properties, which can be saved or loaded from a stream. |
* A set of persistent properties, which can be saved or loaded from a stream. |
111 |
*/ |
*/ |
112 |
public Properties() |
public Properties() |
113 |
{ |
{ |
|
this.defaults = null; |
|
114 |
} |
} |
115 |
|
|
116 |
/** |
/** |
335 |
|
|
336 |
/** |
/** |
337 |
* Writes the key/value pairs to the given output stream, in a format |
* Writes the key/value pairs to the given output stream, in a format |
338 |
* suitable for <code>load</code>. <br> |
* suitable for <code>load</code>.<br> |
339 |
* |
* |
340 |
* If header is not null, this method writes a comment containing |
* If header is not null, this method writes a comment containing |
341 |
* the header as first line to the stream. The next line (or first |
* the header as first line to the stream. The next line (or first |
342 |
* line if header is null) contains a comment with the current date. |
* line if header is null) contains a comment with the current date. |
343 |
* Afterwards the key/value pairs are written to the stream in the |
* Afterwards the key/value pairs are written to the stream in the |
344 |
* following format. <br> |
* following format.<br> |
345 |
* |
* |
346 |
* Each line has the form <code>key = value</code>. Newlines, |
* Each line has the form <code>key = value</code>. Newlines, |
347 |
* Returns and tabs are written as <code>\n,\t,\r</code> resp. |
* Returns and tabs are written as <code>\n,\t,\r</code> resp. |
428 |
*/ |
*/ |
429 |
public Enumeration propertyNames() |
public Enumeration propertyNames() |
430 |
{ |
{ |
431 |
// We make a new Hashtable that holds all the keys. Then we |
// We make a new Set that holds all the keys, then return an enumeration |
432 |
// return an enumeration for this hash. We do this because we |
// for that. This prevents modifications from ruining the enumeration, |
433 |
// don't want modifications to be reflected in the enumeration |
// as well as ignoring duplicates. |
434 |
// (per JCL), and because there doesn't seem to be a |
Properties prop = this; |
435 |
// particularly better way to ensure that duplicates are |
Set s = new HashSet(); |
436 |
// ignored. |
// Eliminate tail recursion. |
437 |
Hashtable t = new Hashtable(); |
do |
438 |
addHashEntries(t); |
{ |
439 |
return t.keys(); |
s.addAll(prop.keySet()); |
440 |
|
prop = prop.defaults; |
441 |
|
} |
442 |
|
while (prop != null); |
443 |
|
return Collections.enumeration(s); |
444 |
} |
} |
445 |
|
|
446 |
/** |
/** |
455 |
*/ |
*/ |
456 |
public void list(PrintStream out) |
public void list(PrintStream out) |
457 |
{ |
{ |
458 |
Enumeration keys = keys(); |
Iterator iter = entrySet().iterator(); |
459 |
Enumeration elts = elements(); |
int i = size(); |
460 |
while (keys.hasMoreElements()) |
StringBuffer s = new StringBuffer(); // Reuse the same buffer. |
461 |
|
while (--i >= 0) |
462 |
{ |
{ |
463 |
String key = (String) keys.nextElement(); |
Map.Entry entry = (Map.Entry) iter.next(); |
464 |
String elt = (String) elts.nextElement(); |
formatForOutput((String) entry.getKey(), s, true); |
465 |
String output = formatForOutput(key, elt); |
s.append('='); |
466 |
out.println(output); |
formatForOutput((String) entry.getValue(), s, false); |
467 |
|
out.println(s); |
468 |
} |
} |
469 |
} |
} |
470 |
|
|
481 |
*/ |
*/ |
482 |
public void list(PrintWriter out) |
public void list(PrintWriter out) |
483 |
{ |
{ |
484 |
Enumeration keys = keys(); |
Iterator iter = entrySet().iterator(); |
485 |
Enumeration elts = elements(); |
int i = size(); |
486 |
while (keys.hasMoreElements()) |
StringBuffer s = new StringBuffer(); // Reuse the same buffer. |
487 |
|
while (--i >= 0) |
488 |
{ |
{ |
489 |
String key = (String) keys.nextElement(); |
Map.Entry entry = (Map.Entry) iter.next(); |
490 |
String elt = (String) elts.nextElement(); |
formatForOutput((String) entry.getKey(), s, true); |
491 |
String output = formatForOutput(key, elt); |
s.append('='); |
492 |
out.println(output); |
formatForOutput((String) entry.getValue(), s, false); |
493 |
|
out.println(s); |
494 |
} |
} |
495 |
} |
} |
496 |
|
|
497 |
/** |
/** |
498 |
* Formats a key/value pair for output in a properties file. |
* Formats a key or value for output in a properties file. |
499 |
* See store for a description of the format. |
* See store for a description of the format. |
500 |
* |
* |
501 |
* @param key the key |
* @param str the string to format |
502 |
* @param value the value |
* @param buffer the buffer to add it to |
503 |
|
* @param key true if all ' ' must be escaped for the key, false if only |
504 |
|
* leading spaces must be escaped for the value |
505 |
* @see #store(OutputStream, String) |
* @see #store(OutputStream, String) |
506 |
*/ |
*/ |
507 |
private String formatForOutput(String key, String value) |
private void formatForOutput(String str, StringBuffer buffer, boolean key) |
508 |
{ |
{ |
509 |
// This is a simple approximation of the expected line size. |
if (key) |
510 |
StringBuffer result = |
{ |
511 |
new StringBuffer(key.length() + value.length() + 16); |
buffer.setLength(0); |
512 |
|
buffer.ensureCapacity(str.length()); |
513 |
|
} |
514 |
|
else |
515 |
|
buffer.ensureCapacity(buffer.length() + str.length()); |
516 |
boolean head = true; |
boolean head = true; |
517 |
for (int i = 0; i < key.length(); i++) |
int size = str.length(); |
518 |
|
for (int i = 0; i < size; i++) |
519 |
{ |
{ |
520 |
char c = key.charAt(i); |
char c = str.charAt(i); |
521 |
switch (c) |
switch (c) |
522 |
{ |
{ |
523 |
case '\n': |
case '\n': |
524 |
result.append("\\n"); |
buffer.append("\\n"); |
525 |
break; |
break; |
526 |
case '\r': |
case '\r': |
527 |
result.append("\\r"); |
buffer.append("\\r"); |
528 |
break; |
break; |
529 |
case '\t': |
case '\t': |
530 |
result.append("\\t"); |
buffer.append("\\t"); |
|
break; |
|
|
case '\\': |
|
|
result.append("\\\\"); |
|
|
break; |
|
|
case '!': |
|
|
result.append("\\!"); |
|
|
break; |
|
|
case '#': |
|
|
result.append("\\#"); |
|
|
break; |
|
|
case '=': |
|
|
result.append("\\="); |
|
|
break; |
|
|
case ':': |
|
|
result.append("\\:"); |
|
531 |
break; |
break; |
532 |
case ' ': |
case ' ': |
533 |
result.append("\\ "); |
buffer.append(head ? "\\ " : " "); |
|
break; |
|
|
default: |
|
|
if (c < 32 || c > '~') |
|
|
{ |
|
|
String hex = Integer.toHexString(c); |
|
|
result.append("\\u0000".substring(0, 6 - hex.length())); |
|
|
result.append(hex); |
|
|
} |
|
|
else |
|
|
result.append(c); |
|
|
} |
|
|
if (c != 32) |
|
|
head = false; |
|
|
} |
|
|
result.append('='); |
|
|
head = true; |
|
|
for (int i = 0; i < value.length(); i++) |
|
|
{ |
|
|
char c = value.charAt(i); |
|
|
switch (c) |
|
|
{ |
|
|
case '\n': |
|
|
result.append("\\n"); |
|
|
break; |
|
|
case '\r': |
|
|
result.append("\\r"); |
|
|
break; |
|
|
case '\t': |
|
|
result.append("\\t"); |
|
534 |
break; |
break; |
535 |
case '\\': |
case '\\': |
|
result.append("\\\\"); |
|
|
break; |
|
536 |
case '!': |
case '!': |
|
result.append("\\!"); |
|
|
break; |
|
537 |
case '#': |
case '#': |
538 |
result.append("\\#"); |
case '=': |
539 |
break; |
case ':': |
540 |
case ' ': |
buffer.append('\\').append(c); |
|
result.append(head ? "\\ " : " "); |
|
|
break; |
|
541 |
default: |
default: |
542 |
if (c < 32 || c > '~') |
if (c < ' ' || c > '~') |
543 |
{ |
{ |
544 |
String hex = Integer.toHexString(c); |
String hex = Integer.toHexString(c); |
545 |
result.append("\\u0000".substring(0, 6 - hex.length())); |
buffer.append("\\u0000".substring(0, 6 - hex.length())); |
546 |
result.append(hex); |
buffer.append(hex); |
547 |
} |
} |
548 |
else |
else |
549 |
result.append(c); |
buffer.append(c); |
550 |
} |
} |
551 |
if (c != 32) |
if (c != ' ') |
552 |
head = false; |
head = key; |
553 |
} |
} |
|
return result.toString(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Recursively grabs the keys from the default properties. |
|
|
* |
|
|
* @param base the hashtable to place the keys in |
|
|
*/ |
|
|
private final void addHashEntries(Hashtable base) |
|
|
{ |
|
|
if (defaults != null) |
|
|
defaults.addHashEntries(base); |
|
|
Enumeration keys = keys(); |
|
|
while (keys.hasMoreElements()) |
|
|
base.put(keys.nextElement(), base); |
|
554 |
} |
} |
555 |
} |
} |