| 1 | /* Properties.java -- a set of persistent properties
|
|---|
| 2 | Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This file is part of GNU Classpath.
|
|---|
| 5 |
|
|---|
| 6 | GNU Classpath is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 9 | any later version.
|
|---|
| 10 |
|
|---|
| 11 | GNU Classpath is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 14 | General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
|---|
| 18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 19 | 02111-1307 USA.
|
|---|
| 20 |
|
|---|
| 21 | Linking this library statically or dynamically with other modules is
|
|---|
| 22 | making a combined work based on this library. Thus, the terms and
|
|---|
| 23 | conditions of the GNU General Public License cover the whole
|
|---|
| 24 | combination.
|
|---|
| 25 |
|
|---|
| 26 | As a special exception, the copyright holders of this library give you
|
|---|
| 27 | permission to link this library with independent modules to produce an
|
|---|
| 28 | executable, regardless of the license terms of these independent
|
|---|
| 29 | modules, and to copy and distribute the resulting executable under
|
|---|
| 30 | terms of your choice, provided that you also meet, for each linked
|
|---|
| 31 | independent module, the terms and conditions of the license of that
|
|---|
| 32 | module. An independent module is a module which is not derived from
|
|---|
| 33 | or based on this library. If you modify this library, you may extend
|
|---|
| 34 | this exception to your version of the library, but you are not
|
|---|
| 35 | obligated to do so. If you do not wish to do so, delete this
|
|---|
| 36 | exception statement from your version. */
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 | package java.util;
|
|---|
| 40 |
|
|---|
| 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.
|
|---|
| 52 | * A property list may also contain defaults, searched if the main list
|
|---|
| 53 | * does not contain a property for a given key.
|
|---|
| 54 | *
|
|---|
| 55 | * An example of a properties file for the german language is given
|
|---|
| 56 | * here. This extends the example given in ListResourceBundle.
|
|---|
| 57 | * Create a file MyResource_de.properties with the following contents
|
|---|
| 58 | * and put it in the CLASSPATH. (The character
|
|---|
| 59 | * <code>\</code><code>u00e4</code> is the german ä)
|
|---|
| 60 | *
|
|---|
| 61 | *
|
|---|
| 62 | <pre>s1=3
|
|---|
| 63 | s2=MeineDisk
|
|---|
| 64 | s3=3. M\<code></code>u00e4rz 96
|
|---|
| 65 | s4=Die Diskette ''{1}'' enth\<code></code>u00e4lt {0} in {2}.
|
|---|
| 66 | s5=0
|
|---|
| 67 | s6=keine Dateien
|
|---|
| 68 | s7=1
|
|---|
| 69 | s8=eine Datei
|
|---|
| 70 | s9=2
|
|---|
| 71 | s10={0,number} Dateien
|
|---|
| 72 | s11=Das Formatieren schlug fehl mit folgender Exception: {0}
|
|---|
| 73 | s12=FEHLER
|
|---|
| 74 | s13=Ergebnis
|
|---|
| 75 | s14=Dialog
|
|---|
| 76 | s15=Auswahlkriterium
|
|---|
| 77 | s16=1,3</pre>
|
|---|
| 78 | *
|
|---|
| 79 | * <p>Although this is a sub class of a hash table, you should never
|
|---|
| 80 | * insert anything other than strings to this property, or several
|
|---|
| 81 | * methods, that need string keys and values, will fail. To ensure
|
|---|
| 82 | * this, you should use the <code>get/setProperty</code> method instead
|
|---|
| 83 | * of <code>get/put</code>.
|
|---|
| 84 | *
|
|---|
| 85 | * Properties are saved in ISO 8859-1 encoding, using Unicode escapes with
|
|---|
| 86 | * a single <code>u</code> for any character which cannot be represented.
|
|---|
| 87 | *
|
|---|
| 88 | * @author Jochen Hoenicke
|
|---|
| 89 | * @author Eric Blake <[email protected]>
|
|---|
| 90 | * @see PropertyResourceBundle
|
|---|
| 91 | * @status updated to 1.4
|
|---|
| 92 | */
|
|---|
| 93 | public class Properties extends Hashtable
|
|---|
| 94 | {
|
|---|
| 95 | // WARNING: Properties is a CORE class in the bootstrap cycle. See the
|
|---|
| 96 | // comments in vm/reference/java/lang/Runtime for implications of this fact.
|
|---|
| 97 |
|
|---|
| 98 | /**
|
|---|
| 99 | * The property list that contains default values for any keys not
|
|---|
| 100 | * in this property list.
|
|---|
| 101 | *
|
|---|
| 102 | * @serial the default properties
|
|---|
| 103 | */
|
|---|
| 104 | protected Properties defaults;
|
|---|
| 105 |
|
|---|
| 106 | /**
|
|---|
| 107 | * Compatible with JDK 1.0+.
|
|---|
| 108 | */
|
|---|
| 109 | private static final long serialVersionUID = 4112578634029874840L;
|
|---|
| 110 |
|
|---|
| 111 | /**
|
|---|
| 112 | * Creates a new empty property list with no default values.
|
|---|
| 113 | */
|
|---|
| 114 | public Properties()
|
|---|
| 115 | {
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | /**
|
|---|
| 119 | * Create a new empty property list with the specified default values.
|
|---|
| 120 | *
|
|---|
| 121 | * @param defaults a Properties object containing the default values
|
|---|
| 122 | */
|
|---|
| 123 | public Properties(Properties defaults)
|
|---|
| 124 | {
|
|---|
| 125 | this.defaults = defaults;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | /**
|
|---|
| 129 | * Adds the given key/value pair to this properties. This calls
|
|---|
| 130 | * the hashtable method put.
|
|---|
| 131 | *
|
|---|
| 132 | * @param key the key for this property
|
|---|
| 133 | * @param value the value for this property
|
|---|
| 134 | * @return The old value for the given key
|
|---|
| 135 | * @see #getProperty(String)
|
|---|
| 136 | * @since 1.2
|
|---|
| 137 | */
|
|---|
| 138 | public Object setProperty(String key, String value)
|
|---|
| 139 | {
|
|---|
| 140 | return put(key, value);
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | /**
|
|---|
| 144 | * Reads a property list from an input stream. The stream should
|
|---|
| 145 | * have the following format: <br>
|
|---|
| 146 | *
|
|---|
| 147 | * An empty line or a line starting with <code>#</code> or
|
|---|
| 148 | * <code>!</code> is ignored. An backslash (<code>\</code>) at the
|
|---|
| 149 | * end of the line makes the line continueing on the next line
|
|---|
| 150 | * (but make sure there is no whitespace after the backslash).
|
|---|
| 151 | * Otherwise, each line describes a key/value pair. <br>
|
|---|
| 152 | *
|
|---|
| 153 | * The chars up to the first whitespace, = or : are the key. You
|
|---|
| 154 | * can include this caracters in the key, if you precede them with
|
|---|
| 155 | * a backslash (<code>\</code>). The key is followed by optional
|
|---|
| 156 | * whitespaces, optionally one <code>=</code> or <code>:</code>,
|
|---|
| 157 | * and optionally some more whitespaces. The rest of the line is
|
|---|
| 158 | * the resource belonging to the key. <br>
|
|---|
| 159 | *
|
|---|
| 160 | * Escape sequences <code>\t, \n, \r, \\, \", \', \!, \#, \ </code>(a
|
|---|
| 161 | * space), and unicode characters with the
|
|---|
| 162 | * <code>\\u</code><em>xxxx</em> notation are detected, and
|
|---|
| 163 | * converted to the corresponding single character. <br>
|
|---|
| 164 | *
|
|---|
| 165 | *
|
|---|
| 166 | <pre># This is a comment
|
|---|
| 167 | key = value
|
|---|
| 168 | k\:5 \ a string starting with space and ending with newline\n
|
|---|
| 169 | # This is a multiline specification; note that the value contains
|
|---|
| 170 | # no white space.
|
|---|
| 171 | weekdays: Sunday,Monday,Tuesday,Wednesday,\\
|
|---|
| 172 | Thursday,Friday,Saturday
|
|---|
| 173 | # The safest way to include a space at the end of a value:
|
|---|
| 174 | label = Name:\\u0020</pre>
|
|---|
| 175 | *
|
|---|
| 176 | * @param in the input stream
|
|---|
| 177 | * @throws IOException if an error occurred when reading the input
|
|---|
| 178 | * @throws NullPointerException if in is null
|
|---|
| 179 | */
|
|---|
| 180 | public void load(InputStream inStream) throws IOException
|
|---|
| 181 | {
|
|---|
| 182 | // The spec says that the file must be encoded using ISO-8859-1.
|
|---|
| 183 | BufferedReader reader =
|
|---|
| 184 | new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
|
|---|
| 185 | String line;
|
|---|
| 186 |
|
|---|
| 187 | while ((line = reader.readLine()) != null)
|
|---|
| 188 | {
|
|---|
| 189 | char c = 0;
|
|---|
| 190 | int pos = 0;
|
|---|
| 191 | // If empty line or begins with a comment character, skip this line.
|
|---|
| 192 | if (line.length() == 0
|
|---|
| 193 | || line.charAt(0) == '#' || line.charAt(0) == '!')
|
|---|
| 194 | continue;
|
|---|
| 195 |
|
|---|
| 196 | while (pos < line.length()
|
|---|
| 197 | && Character.isWhitespace(c = line.charAt(pos)))
|
|---|
| 198 | pos++;
|
|---|
| 199 |
|
|---|
| 200 | // If line is empty skip this line.
|
|---|
| 201 | if (pos == line.length())
|
|---|
| 202 | continue;
|
|---|
| 203 |
|
|---|
| 204 | // The characters up to the next Whitespace, ':', or '='
|
|---|
| 205 | // describe the key. But look for escape sequences.
|
|---|
| 206 | StringBuffer key = new StringBuffer();
|
|---|
| 207 | while (pos < line.length()
|
|---|
| 208 | && ! Character.isWhitespace(c = line.charAt(pos++))
|
|---|
| 209 | && c != '=' && c != ':')
|
|---|
| 210 | {
|
|---|
| 211 | if (c == '\\')
|
|---|
| 212 | {
|
|---|
| 213 | if (pos == line.length())
|
|---|
| 214 | {
|
|---|
| 215 | // The line continues on the next line.
|
|---|
| 216 | line = reader.readLine();
|
|---|
| 217 | pos = 0;
|
|---|
| 218 | while (pos < line.length()
|
|---|
| 219 | && Character.isWhitespace(c = line.charAt(pos)))
|
|---|
| 220 | pos++;
|
|---|
| 221 | }
|
|---|
| 222 | else
|
|---|
| 223 | {
|
|---|
| 224 | c = line.charAt(pos++);
|
|---|
| 225 | switch (c)
|
|---|
| 226 | {
|
|---|
| 227 | case 'n':
|
|---|
| 228 | key.append('\n');
|
|---|
| 229 | break;
|
|---|
| 230 | case 't':
|
|---|
| 231 | key.append('\t');
|
|---|
| 232 | break;
|
|---|
| 233 | case 'r':
|
|---|
| 234 | key.append('\r');
|
|---|
| 235 | break;
|
|---|
| 236 | case 'u':
|
|---|
| 237 | if (pos + 4 <= line.length())
|
|---|
| 238 | {
|
|---|
| 239 | char uni = (char) Integer.parseInt
|
|---|
| 240 | (line.substring(pos, pos + 4), 16);
|
|---|
| 241 | key.append(uni);
|
|---|
| 242 | pos += 4;
|
|---|
| 243 | } // else throw exception?
|
|---|
| 244 | break;
|
|---|
| 245 | default:
|
|---|
| 246 | key.append(c);
|
|---|
| 247 | break;
|
|---|
| 248 | }
|
|---|
| 249 | }
|
|---|
| 250 | }
|
|---|
| 251 | else
|
|---|
| 252 | key.append(c);
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | boolean isDelim = (c == ':' || c == '=');
|
|---|
| 256 | while (pos < line.length()
|
|---|
| 257 | && Character.isWhitespace(c = line.charAt(pos)))
|
|---|
| 258 | pos++;
|
|---|
| 259 |
|
|---|
| 260 | if (! isDelim && (c == ':' || c == '='))
|
|---|
| 261 | {
|
|---|
| 262 | pos++;
|
|---|
| 263 | while (pos < line.length()
|
|---|
| 264 | && Character.isWhitespace(c = line.charAt(pos)))
|
|---|
| 265 | pos++;
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 | StringBuffer element = new StringBuffer(line.length() - pos);
|
|---|
| 269 | while (pos < line.length())
|
|---|
| 270 | {
|
|---|
| 271 | c = line.charAt(pos++);
|
|---|
| 272 | if (c == '\\')
|
|---|
| 273 | {
|
|---|
| 274 | if (pos == line.length())
|
|---|
| 275 | {
|
|---|
| 276 | // The line continues on the next line.
|
|---|
| 277 | line = reader.readLine();
|
|---|
| 278 |
|
|---|
| 279 | // We might have seen a backslash at the end of
|
|---|
| 280 | // the file. The JDK ignores the backslash in
|
|---|
| 281 | // this case, so we follow for compatibility.
|
|---|
| 282 | if (line == null)
|
|---|
| 283 | break;
|
|---|
| 284 |
|
|---|
| 285 | pos = 0;
|
|---|
| 286 | while (pos < line.length()
|
|---|
| 287 | && Character.isWhitespace(c = line.charAt(pos)))
|
|---|
| 288 | pos++;
|
|---|
| 289 | element.ensureCapacity(line.length() - pos +
|
|---|
| 290 | element.length());
|
|---|
| 291 | }
|
|---|
| 292 | else
|
|---|
| 293 | {
|
|---|
| 294 | c = line.charAt(pos++);
|
|---|
| 295 | switch (c)
|
|---|
| 296 | {
|
|---|
| 297 | case 'n':
|
|---|
| 298 | element.append('\n');
|
|---|
| 299 | break;
|
|---|
| 300 | case 't':
|
|---|
| 301 | element.append('\t');
|
|---|
| 302 | break;
|
|---|
| 303 | case 'r':
|
|---|
| 304 | element.append('\r');
|
|---|
| 305 | break;
|
|---|
| 306 | case 'u':
|
|---|
| 307 | if (pos + 4 <= line.length())
|
|---|
| 308 | {
|
|---|
| 309 | char uni = (char) Integer.parseInt
|
|---|
| 310 | (line.substring(pos, pos + 4), 16);
|
|---|
| 311 | element.append(uni);
|
|---|
| 312 | pos += 4;
|
|---|
| 313 | } // else throw exception?
|
|---|
| 314 | break;
|
|---|
| 315 | default:
|
|---|
| 316 | element.append(c);
|
|---|
| 317 | break;
|
|---|
| 318 | }
|
|---|
| 319 | }
|
|---|
| 320 | }
|
|---|
| 321 | else
|
|---|
| 322 | element.append(c);
|
|---|
| 323 | }
|
|---|
| 324 | put(key.toString(), element.toString());
|
|---|
| 325 | }
|
|---|
| 326 | }
|
|---|
| 327 |
|
|---|
| 328 | /**
|
|---|
| 329 | * Calls <code>store(OutputStream out, String header)</code> and
|
|---|
| 330 | * ignores the IOException that may be thrown.
|
|---|
| 331 | *
|
|---|
| 332 | * @param out the stream to write to
|
|---|
| 333 | * @param header a description of the property list
|
|---|
| 334 | * @throws ClassCastException if this property contains any key or
|
|---|
| 335 | * value that are not strings
|
|---|
| 336 | * @deprecated use {@link #store(OutputStream, String)} instead
|
|---|
| 337 | */
|
|---|
| 338 | public void save(OutputStream out, String header)
|
|---|
| 339 | {
|
|---|
| 340 | try
|
|---|
| 341 | {
|
|---|
| 342 | store(out, header);
|
|---|
| 343 | }
|
|---|
| 344 | catch (IOException ex)
|
|---|
| 345 | {
|
|---|
| 346 | }
|
|---|
| 347 | }
|
|---|
| 348 |
|
|---|
| 349 | /**
|
|---|
| 350 | * Writes the key/value pairs to the given output stream, in a format
|
|---|
| 351 | * suitable for <code>load</code>.<br>
|
|---|
| 352 | *
|
|---|
| 353 | * If header is not null, this method writes a comment containing
|
|---|
| 354 | * the header as first line to the stream. The next line (or first
|
|---|
| 355 | * line if header is null) contains a comment with the current date.
|
|---|
| 356 | * Afterwards the key/value pairs are written to the stream in the
|
|---|
| 357 | * following format.<br>
|
|---|
| 358 | *
|
|---|
| 359 | * Each line has the form <code>key = value</code>. Newlines,
|
|---|
| 360 | * Returns and tabs are written as <code>\n,\t,\r</code> resp.
|
|---|
| 361 | * The characters <code>\, !, #, =</code> and <code>:</code> are
|
|---|
| 362 | * preceeded by a backslash. Spaces are preceded with a backslash,
|
|---|
| 363 | * if and only if they are at the beginning of the key. Characters
|
|---|
| 364 | * that are not in the ascii range 33 to 127 are written in the
|
|---|
| 365 | * <code>\</code><code>u</code>xxxx Form.<br>
|
|---|
| 366 | *
|
|---|
| 367 | * Following the listing, the output stream is flushed but left open.
|
|---|
| 368 | *
|
|---|
| 369 | * @param out the output stream
|
|---|
| 370 | * @param header the header written in the first line, may be null
|
|---|
| 371 | * @throws ClassCastException if this property contains any key or
|
|---|
| 372 | * value that isn't a string
|
|---|
| 373 | * @throws IOException if writing to the stream fails
|
|---|
| 374 | * @throws NullPointerException if out is null
|
|---|
| 375 | * @since 1.2
|
|---|
| 376 | */
|
|---|
| 377 | public void store(OutputStream out, String header) throws IOException
|
|---|
| 378 | {
|
|---|
| 379 | // The spec says that the file must be encoded using ISO-8859-1.
|
|---|
| 380 | PrintWriter writer
|
|---|
| 381 | = new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1"));
|
|---|
| 382 | if (header != null)
|
|---|
| 383 | writer.println("#" + header);
|
|---|
| 384 | writer.println ("#" + Calendar.getInstance ().getTime ());
|
|---|
| 385 |
|
|---|
| 386 | Iterator iter = entrySet ().iterator ();
|
|---|
| 387 | int i = size ();
|
|---|
| 388 | StringBuffer s = new StringBuffer (); // Reuse the same buffer.
|
|---|
| 389 | while (--i >= 0)
|
|---|
| 390 | {
|
|---|
| 391 | Map.Entry entry = (Map.Entry) iter.next ();
|
|---|
| 392 | formatForOutput ((String) entry.getKey (), s, true);
|
|---|
| 393 | s.append ('=');
|
|---|
| 394 | formatForOutput ((String) entry.getValue (), s, false);
|
|---|
| 395 | writer.println (s);
|
|---|
| 396 | }
|
|---|
| 397 |
|
|---|
| 398 | writer.flush ();
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | /**
|
|---|
| 402 | * Gets the property with the specified key in this property list.
|
|---|
| 403 | * If the key is not found, the default property list is searched.
|
|---|
| 404 | * If the property is not found in the default, null is returned.
|
|---|
| 405 | *
|
|---|
| 406 | * @param key The key for this property
|
|---|
| 407 | * @return the value for the given key, or null if not found
|
|---|
| 408 | * @throws ClassCastException if this property contains any key or
|
|---|
| 409 | * value that isn't a string
|
|---|
| 410 | * @see #defaults
|
|---|
| 411 | * @see #setProperty(String, String)
|
|---|
| 412 | * @see #getProperty(String, String)
|
|---|
| 413 | */
|
|---|
| 414 | public String getProperty(String key)
|
|---|
| 415 | {
|
|---|
| 416 | return getProperty(key, null);
|
|---|
| 417 | }
|
|---|
| 418 |
|
|---|
| 419 | /**
|
|---|
| 420 | * Gets the property with the specified key in this property list. If
|
|---|
| 421 | * the key is not found, the default property list is searched. If the
|
|---|
| 422 | * property is not found in the default, the specified defaultValue is
|
|---|
| 423 | * returned.
|
|---|
| 424 | *
|
|---|
| 425 | * @param key The key for this property
|
|---|
| 426 | * @param defaultValue A default value
|
|---|
| 427 | * @return The value for the given key
|
|---|
| 428 | * @throws ClassCastException if this property contains any key or
|
|---|
| 429 | * value that isn't a string
|
|---|
| 430 | * @see #defaults
|
|---|
| 431 | * @see #setProperty(String, String)
|
|---|
| 432 | */
|
|---|
| 433 | public String getProperty(String key, String defaultValue)
|
|---|
| 434 | {
|
|---|
| 435 | Properties prop = this;
|
|---|
| 436 | // Eliminate tail recursion.
|
|---|
| 437 | do
|
|---|
| 438 | {
|
|---|
| 439 | String value = (String) prop.get(key);
|
|---|
| 440 | if (value != null)
|
|---|
| 441 | return value;
|
|---|
| 442 | prop = prop.defaults;
|
|---|
| 443 | }
|
|---|
| 444 | while (prop != null);
|
|---|
| 445 | return defaultValue;
|
|---|
| 446 | }
|
|---|
| 447 |
|
|---|
| 448 | /**
|
|---|
| 449 | * Returns an enumeration of all keys in this property list, including
|
|---|
| 450 | * the keys in the default property list.
|
|---|
| 451 | *
|
|---|
| 452 | * @return an Enumeration of all defined keys
|
|---|
| 453 | */
|
|---|
| 454 | public Enumeration propertyNames()
|
|---|
| 455 | {
|
|---|
| 456 | // We make a new Set that holds all the keys, then return an enumeration
|
|---|
| 457 | // for that. This prevents modifications from ruining the enumeration,
|
|---|
| 458 | // as well as ignoring duplicates.
|
|---|
| 459 | Properties prop = this;
|
|---|
| 460 | Set s = new HashSet();
|
|---|
| 461 | // Eliminate tail recursion.
|
|---|
| 462 | do
|
|---|
| 463 | {
|
|---|
| 464 | s.addAll(prop.keySet());
|
|---|
| 465 | prop = prop.defaults;
|
|---|
| 466 | }
|
|---|
| 467 | while (prop != null);
|
|---|
| 468 | return Collections.enumeration(s);
|
|---|
| 469 | }
|
|---|
| 470 |
|
|---|
| 471 | /**
|
|---|
| 472 | * Prints the key/value pairs to the given print stream. This is
|
|---|
| 473 | * mainly useful for debugging purposes.
|
|---|
| 474 | *
|
|---|
| 475 | * @param out the print stream, where the key/value pairs are written to
|
|---|
| 476 | * @throws ClassCastException if this property contains a key or a
|
|---|
| 477 | * value that isn't a string
|
|---|
| 478 | * @see #list(PrintWriter)
|
|---|
| 479 | */
|
|---|
| 480 | public void list(PrintStream out)
|
|---|
| 481 | {
|
|---|
| 482 | PrintWriter writer = new PrintWriter (out);
|
|---|
| 483 | list (writer);
|
|---|
| 484 | }
|
|---|
| 485 |
|
|---|
| 486 | /**
|
|---|
| 487 | * Prints the key/value pairs to the given print writer. This is
|
|---|
| 488 | * mainly useful for debugging purposes.
|
|---|
| 489 | *
|
|---|
| 490 | * @param out the print writer where the key/value pairs are written to
|
|---|
| 491 | * @throws ClassCastException if this property contains a key or a
|
|---|
| 492 | * value that isn't a string
|
|---|
| 493 | * @see #list(PrintStream)
|
|---|
| 494 | * @since 1.1
|
|---|
| 495 | */
|
|---|
| 496 | public void list(PrintWriter out)
|
|---|
| 497 | {
|
|---|
| 498 | out.println ("-- listing properties --");
|
|---|
| 499 |
|
|---|
| 500 | Iterator iter = entrySet ().iterator ();
|
|---|
| 501 | int i = size ();
|
|---|
| 502 | while (--i >= 0)
|
|---|
| 503 | {
|
|---|
| 504 | Map.Entry entry = (Map.Entry) iter.next ();
|
|---|
| 505 | out.print ((String) entry.getKey () + "=");
|
|---|
| 506 |
|
|---|
| 507 | // JDK 1.3/1.4 restrict the printed value, but not the key,
|
|---|
| 508 | // to 40 characters, including the truncating ellipsis.
|
|---|
| 509 | String s = (String ) entry.getValue ();
|
|---|
| 510 | if (s != null && s.length () > 40)
|
|---|
| 511 | out.println (s.substring (0, 37) + "...");
|
|---|
| 512 | else
|
|---|
| 513 | out.println (s);
|
|---|
| 514 | }
|
|---|
| 515 | out.flush ();
|
|---|
| 516 | }
|
|---|
| 517 |
|
|---|
| 518 | /**
|
|---|
| 519 | * Formats a key or value for output in a properties file.
|
|---|
| 520 | * See store for a description of the format.
|
|---|
| 521 | *
|
|---|
| 522 | * @param str the string to format
|
|---|
| 523 | * @param buffer the buffer to add it to
|
|---|
| 524 | * @param key true if all ' ' must be escaped for the key, false if only
|
|---|
| 525 | * leading spaces must be escaped for the value
|
|---|
| 526 | * @see #store(OutputStream, String)
|
|---|
| 527 | */
|
|---|
| 528 | private void formatForOutput(String str, StringBuffer buffer, boolean key)
|
|---|
| 529 | {
|
|---|
| 530 | if (key)
|
|---|
| 531 | {
|
|---|
| 532 | buffer.setLength(0);
|
|---|
| 533 | buffer.ensureCapacity(str.length());
|
|---|
| 534 | }
|
|---|
| 535 | else
|
|---|
| 536 | buffer.ensureCapacity(buffer.length() + str.length());
|
|---|
| 537 | boolean head = true;
|
|---|
| 538 | int size = str.length();
|
|---|
| 539 | for (int i = 0; i < size; i++)
|
|---|
| 540 | {
|
|---|
| 541 | char c = str.charAt(i);
|
|---|
| 542 | switch (c)
|
|---|
| 543 | {
|
|---|
| 544 | case '\n':
|
|---|
| 545 | buffer.append("\\n");
|
|---|
| 546 | break;
|
|---|
| 547 | case '\r':
|
|---|
| 548 | buffer.append("\\r");
|
|---|
| 549 | break;
|
|---|
| 550 | case '\t':
|
|---|
| 551 | buffer.append("\\t");
|
|---|
| 552 | break;
|
|---|
| 553 | case ' ':
|
|---|
| 554 | buffer.append(head ? "\\ " : " ");
|
|---|
| 555 | break;
|
|---|
| 556 | case '\\':
|
|---|
| 557 | case '!':
|
|---|
| 558 | case '#':
|
|---|
| 559 | case '=':
|
|---|
| 560 | case ':':
|
|---|
| 561 | buffer.append('\\').append(c);
|
|---|
| 562 | break;
|
|---|
| 563 | default:
|
|---|
| 564 | if (c < ' ' || c > '~')
|
|---|
| 565 | {
|
|---|
| 566 | String hex = Integer.toHexString(c);
|
|---|
| 567 | buffer.append("\\u0000".substring(0, 6 - hex.length()));
|
|---|
| 568 | buffer.append(hex);
|
|---|
| 569 | }
|
|---|
| 570 | else
|
|---|
| 571 | buffer.append(c);
|
|---|
| 572 | }
|
|---|
| 573 | if (c != ' ')
|
|---|
| 574 | head = key;
|
|---|
| 575 | }
|
|---|
| 576 | }
|
|---|
| 577 | } // class Properties
|
|---|