1 /* java.util.Properties
2 Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
21 As a special exception, if you link this library with other files to
22 produce an executable, this library does not by itself cause the
23 resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
32 * An example of a properties file for the german language is given
33 * here. This extends the example given in ListResourceBundle.
34 * Create a file MyResource_de.properties with the following contents
35 * and put it in the CLASSPATH. (The character
36 * <code>\</code><code>u00e4</code> is the german ä)
41 * s3=3. M\<code></code>u00e4rz 96
42 * s4=Die Diskette ''{1}'' enth\<code></code>u00e4lt {0} in {2}.
48 * s10={0,number} Dateien
49 * s11=Das Formatieren schlug fehl mit folgender Exception: {0}
53 * s15=Auswahlkriterium
57 * Although this is a sub class of a hash table, you should never
58 * insert anything other than strings to this property, or several
59 * methods, that need string keys and values, will fail. To ensure
60 * this, you should use the <code>get/setProperty</code> method instead
61 * of <code>get/put</code>.
63 * @see PropertyResourceBundle
64 * @author Jochen Hoenicke
66 public class Properties extends Hashtable
69 * The property list that contains default values for any keys not
70 * in this property list.
72 protected Properties defaults;
74 private static final long serialVersionUID = 4112578634029874840L;
77 * Creates a new empty property list.
85 * Create a new empty property list with the specified default values.
86 * @param defaults a Properties object containing the default values.
88 public Properties(Properties defaults)
90 this.defaults = defaults;
94 * Reads a property list from an input stream. The stream should
95 * have the following format: <br>
97 * An empty line or a line starting with <code>#</code> or
98 * <code>!</code> is ignored. An backslash (<code>\</code>) at the
99 * end of the line makes the line continueing on the next line
100 * (but make sure there is no whitespace after the backslash).
101 * Otherwise, each line describes a key/value pair. <br>
103 * The chars up to the first whitespace, = or : are the key. You
104 * can include this caracters in the key, if you precede them with
105 * a backslash (<code>\</code>). The key is followed by optional
106 * whitespaces, optionally one <code>=</code> or <code>:</code>,
107 * and optionally some more whitespaces. The rest of the line is
108 * the resource belonging to the key. <br>
110 * Escape sequences <code>\t, \n, \r, \\, \", \', \!, \#, \ </code>(a
111 * space), and unicode characters with the
112 * <code>\</code><code>u</code>xxxx notation are detected, and
113 * converted to the corresponding single character. <br>
116 * # This is a comment
118 * k\:5 \ a string starting with space and ending with newline\n
119 * # This is a multiline specification; note that the value contains
121 * weekdays: Sunday,Monday,Tuesday,Wednesday,\
122 * Thursday,Friday,Saturday
123 * # The safest way to include a space at the end of a value:
124 * label = Name:\<code></code>u0020
127 * @param in the input stream
128 * @exception IOException if an error occured when reading
130 public void load(InputStream inStream) throws IOException
132 // The spec says that the file must be encoded using ISO-8859-1.
133 BufferedReader reader =
134 new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
137 while ((line = reader.readLine()) != null)
141 while (pos < line.length()
142 && Character.isWhitespace(c = line.charAt(pos)))
145 // If line is empty or begins with a comment character,
147 if (pos == line.length() || c == '#' || c == '!')
150 // The characaters up to the next Whitespace, ':', or '='
151 // describe the key. But look for escape sequences.
152 StringBuffer key = new StringBuffer();
153 while (pos < line.length()
154 && !Character.isWhitespace(c = line.charAt(pos++))
155 && c != '=' && c != ':')
159 if (pos == line.length())
161 // The line continues on the next line.
162 line = reader.readLine();
164 while (pos < line.length()
165 && Character.isWhitespace(c = line.charAt(pos)))
170 c = line.charAt(pos++);
183 if (pos + 4 <= line.length())
185 char uni = (char) Integer.parseInt
186 (line.substring(pos, pos + 4), 16);
188 } // else throw exception?
200 boolean isDelim = (c == ':' || c == '=');
201 while (pos < line.length()
202 && Character.isWhitespace(c = line.charAt(pos)))
205 if (!isDelim && (c == ':' || c == '='))
208 while (pos < line.length()
209 && Character.isWhitespace(c = line.charAt(pos)))
213 StringBuffer element = new StringBuffer(line.length() - pos);
214 while (pos < line.length())
216 c = line.charAt(pos++);
219 if (pos == line.length())
221 // The line continues on the next line.
222 line = reader.readLine();
224 while (pos < line.length()
225 && Character.isWhitespace(c = line.charAt(pos)))
227 element.ensureCapacity(line.length() - pos +
232 c = line.charAt(pos++);
236 element.append('\n');
239 element.append('\t');
242 element.append('\r');
245 if (pos + 4 <= line.length())
247 char uni = (char) Integer.parseInt
248 (line.substring(pos, pos + 4), 16);
250 } // else throw exception?
261 put(key.toString(), element.toString());
266 * Calls <code>store(OutputStream out, String header)</code> and
267 * ignores the IOException that may be thrown.
268 * @deprecated use store instead.
269 * @exception ClassCastException if this property contains any key or
270 * value that isn't a string.
272 public void save(OutputStream out, String header)
278 catch (IOException ex)
284 * Writes the key/value pairs to the given output stream. <br>
286 * If header is not null, this method writes a comment containing
287 * the header as first line to the stream. The next line (or first
288 * line if header is null) contains a comment with the current date.
289 * Afterwards the key/value pairs are written to the stream in the
290 * following format. <br>
292 * Each line has the form <code>key = value</code>. Newlines,
293 * Returns and tabs are written as <code>\n,\t,\r</code> resp.
294 * The characters <code>\, !, #, =</code> and <code>:</code> are
295 * preceeded by a backslash. Spaces are preceded with a backslash,
296 * if and only if they are at the beginning of the key. Characters
297 * that are not in the ascii range 33 to 127 are written in the
298 * <code>\</code><code>u</code>xxxx Form.
300 * @param out the output stream
301 * @param header the header written in the first line, may be null.
302 * @exception ClassCastException if this property contains any key or
303 * value that isn't a string.
305 public void store(OutputStream out, String header) throws IOException
307 // The spec says that the file must be encoded using ISO-8859-1.
309 = new PrintWriter(new OutputStreamWriter (out, "ISO-8859-1"));
311 writer.println("#" + header);
312 writer.println("#" + new Date().toString());
318 * Adds the given key/value pair to this properties. This calls
319 * the hashtable method put.
320 * @param key the key for this property
321 * @param value the value for this property
322 * @return The old value for the given key.
324 public Object setProperty(String key, String value)
326 return put(key, value);
330 * Gets the property with the specified key in this property list.
331 * If the key is not found, the default property list is searched.
332 * If the property is not found in default or the default of
333 * default, null is returned.
334 * @param key The key for this property.
335 * @param defaulValue A default value
336 * @return The value for the given key, or null if not found.
337 * @exception ClassCastException if this property contains any key or
338 * value that isn't a string.
340 public String getProperty(String key)
342 return getProperty(key, null);
346 * Gets the property with the specified key in this property list. If
347 * the key is not found, the default property list is searched. If the
348 * property is not found in default or the default of default, the
349 * specified defaultValue is returned.
350 * @param key The key for this property.
351 * @param defaulValue A default value
352 * @return The value for the given key.
353 * @exception ClassCastException if this property contains any key or
354 * value that isn't a string.
356 public String getProperty(String key, String defaultValue)
358 Properties prop = this;
359 // Eliminate tail recursion.
362 String value = (String) prop.get(key);
365 prop = prop.defaults;
367 while (prop != null);
371 private final void addHashEntries(Hashtable base)
373 if (defaults != null)
374 defaults.addHashEntries(base);
375 Enumeration keys = keys();
376 while (keys.hasMoreElements())
377 base.put(keys.nextElement(), base);
381 * Returns an enumeration of all keys in this property list, including
382 * the keys in the default property list.
384 public Enumeration propertyNames()
386 // We make a new Hashtable that holds all the keys. Then we
387 // return an enumeration for this hash. We do this because we
388 // don't want modifications to be reflected in the enumeration
389 // (per JCL), and because there doesn't seem to be a
390 // particularly better way to ensure that duplicates are
392 Hashtable t = new Hashtable();
398 * Formats a key/value pair for output in a properties file.
399 * See store for a description of the format.
400 * @param key the key.
401 * @param value the value.
404 private String formatForOutput(String key, String value)
406 // This is a simple approximation of the expected line size.
407 StringBuffer result =
408 new StringBuffer(key.length() + value.length() + 16);
410 for (int i = 0; i < key.length(); i++)
412 char c = key.charAt(i);
416 result.append("\\n");
419 result.append("\\r");
422 result.append("\\t");
425 result.append("\\\\");
428 result.append("\\!");
431 result.append("\\#");
434 result.append("\\=");
437 result.append("\\:");
440 result.append("\\ ");
443 if (c < 32 || c > '~')
445 String hex = Integer.toHexString(c);
446 result.append("\\u0000".substring(0, 6 - hex.length()));
457 for (int i = 0; i < value.length(); i++)
459 char c = value.charAt(i);
463 result.append("\\n");
466 result.append("\\r");
469 result.append("\\t");
472 result.append("\\\\");
475 result.append("\\!");
478 result.append("\\#");
481 result.append(head ? "\\ " : " ");
484 if (c < 32 || c > '~')
486 String hex = Integer.toHexString(c);
487 result.append("\\u0000".substring(0, 6 - hex.length()));
496 return result.toString();
500 * Writes the key/value pairs to the given print stream. They are
501 * written in the way, described in the method store.
502 * @param out the stream, where the key/value pairs are written to.
503 * @exception ClassCastException if this property contains any key or
504 * value that isn't a string.
507 public void list(PrintStream out)
509 Enumeration keys = keys();
510 Enumeration elts = elements();
511 while (keys.hasMoreElements())
513 String key = (String) keys.nextElement();
514 String elt = (String) elts.nextElement();
515 String output = formatForOutput(key, elt);
521 * Writes the key/value pairs to the given print writer. They are
522 * written in the way, described in the method store.
523 * @param out the writer, where the key/value pairs are written to.
524 * @exception ClassCastException if this property contains any key or
525 * value that isn't a string.
527 * @see #list(java.io.PrintStream)
530 public void list(PrintWriter out)
532 Enumeration keys = keys();
533 Enumeration elts = elements();
534 while (keys.hasMoreElements())
536 String key = (String) keys.nextElement();
537 String elt = (String) elts.nextElement();
538 String output = formatForOutput(key, elt);