diff options
Diffstat (limited to 'libjava/java/util/Properties.java')
-rw-r--r-- | libjava/java/util/Properties.java | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/libjava/java/util/Properties.java b/libjava/java/util/Properties.java new file mode 100644 index 0000000..aac7214 --- /dev/null +++ b/libjava/java/util/Properties.java @@ -0,0 +1,376 @@ +// Properties - Property list representation. + +/* Copyright (C) 1998, 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.PushbackReader; + +/** + * @author Tom Tromey <tromey@cygnus.com> + * @date October 26, 1998. + */ + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * Status: Complete to JDK 1.1. + */ + +public class Properties extends Hashtable +{ + protected Properties defaults; + + public String getProperty (String propName) + { + return getProperty (propName, null); + } + + public String getProperty (String propName, String defVal) + { + String r = (String) get (propName); + if (r == null) + { + if (defaults != null) + r = defaults.getProperty(propName, defVal); + else + r = defVal; + } + return r; + } + + public void list (PrintStream out) + { + Enumeration e = propertyNames (); + while (e.hasMoreElements()) + { + String key = (String) e.nextElement(); + String value = getProperty(key); + if (value != null) + { + if (value.length() > 40) + { + // JDK compatibility. + value = value.substring(0, 37) + "..."; + } + out.print(key); + out.print("="); + out.println(value); + } + } + } + + public void list (PrintWriter writer) + { + Enumeration e = propertyNames (); + while (e.hasMoreElements()) + { + String key = (String) e.nextElement(); + String value = getProperty(key); + if (value != null) + { + if (value.length() > 40) + { + // JDK compatibility. + value = value.substring(0, 37) + "..."; + } + writer.print(key); + writer.print("="); + writer.println(value); + } + } + } + + private final boolean skip_ws (PushbackReader reader) throws IOException + { + while (true) + { + int c = reader.read(); + if (c == -1) + return false; + // FIXME: we use our own definition of whitespace. + // Character.isWhitespace includes newlines, which we don't + // want. Character.isSpaceChar doesn't include \t. + if (c == ' ' || c == '\t') + { + reader.unread(c); + return true; + } + } + } + + // Note: this method needs to be rewritten for JDK 1.2. + // We rather arbitrarily decide that an EOF in the middle of a line + // means that the whole line should be ignored. The spec doesn't + // specifically address this, but this interpretation seems valid. + public synchronized void load (InputStream in) throws IOException + { + PushbackReader reader = new PushbackReader (new InputStreamReader (in)); + + StringBuffer key = new StringBuffer (); + StringBuffer value = new StringBuffer (); + + nextLine: + while (true) + { + key.setLength(0); + value.setLength(0); + + // Skip leading whitespace. + if (! skip_ws (reader)) + return; + + // Read key until key terminator. + boolean first_char = true; + int c; + while (true) + { + c = reader.read(); + if (c == -1) + return; + if (c == '\\') + { + first_char = false; + c = reader.read(); + if (c == -1) + return; + } + + // If we found a comment, just read to end of line and + // then keep going. + if (first_char == true && (c == '#' || c == '!')) + { + while (c != -1 && c != '\r' && c != '\n') + c = reader.read(); + if (c == -1) + return; + continue nextLine; + } + + if (c == '\r' || c == '\n') + { + if (first_char) + continue nextLine; + reader.unread(c); + break; + } + // FIXME: again, our own definitino of whitespace. + if (c == ' ' || c == '\t' || c == ':' || c == '=') + break; + + first_char = false; + key.append(c); + } + + // Found end of key. Skip whitespace. If the terminator + // was whitespace, also skip a single instance of a "real" + // terminator, and then more whitespace. + if (! skip_ws (reader)) + return; + if (c != ':' && c != '=') + { + c = reader.read(); + if (c == -1) + return; + if (c == ':' || c == '=') + { + // Skip more whitespace. + if (! skip_ws (reader)) + return; + } + else + reader.unread(c); + } + + // Now read the value. + while (true) + { + c = reader.read(); + if (c == -1) + return; + if (c == '\r' || c == '\n') + break; + if (c == '\\') + { + c = reader.read(); + switch (c) + { + case -1: + return; + case 't': + c = '\t'; + break; + case 'r': + c = '\r'; + break; + case 'n': + c = '\n'; + break; + case 'u': + c = 0; + for (int i = 0; i < 4; ++i) + { + int x = reader.read(); + if (x == -1) + return; + int d = Character.digit((char) x, 16); + // FIXME: what to do here? We call it an + // error. + if (d == -1) + throw new IOException (); + c <<= 4; + c |= d; + } + break; + default: + // Nothing. + } + } + else + value.append(c); + } + + put (key.toString(), value.toString()); + } + } + + public Properties () + { + defaults = null; + } + + public Properties (Properties defs) + { + defaults = defs; + } + + private final void addHashEntries (Hashtable base) + { + if (defaults != null) + defaults.addHashEntries(base); + Enumeration keys = keys (); + while (keys.hasMoreElements()) + base.put(keys.nextElement(), base); + } + + public Enumeration propertyNames () + { + // We make a new Hashtable that holds all the keys. Then we + // return an enumeration for this hash. We do this because we + // don't want modifications to be reflected in the enumeration + // (per JCL), and because there doesn't seem to be a + // particularly better way to ensure that duplicates are + // ignored. + Hashtable t = new Hashtable (); + addHashEntries (t); + return t.keys(); + } + + public synchronized void save (OutputStream out, String comment) + { + // Use a buffer because writing a single string through + // OutputStreamWriter is fairly expensive. + BufferedWriter output + = new BufferedWriter (new OutputStreamWriter (out)); + String newline = System.getProperty("line.separator"); + + try + { + if (comment != null) + { + // FIXME: what if COMMENT contains newlines? + output.write("#"); + output.write(comment); + output.write(newline); + } + output.write("# "); + output.write(new Date().toString()); + output.write(newline); + + Enumeration keys = keys (); + while (keys.hasMoreElements()) + { + String key = (String) keys.nextElement(); + String value = (String) get (key); + + // FIXME: JCL says that the key can contain many Unicode + // characters. But it also doesn't say we should encode + // it in any way. + // FIXME: if key contains ':', '=', or whitespace, must + // quote it here. + output.write(key); + output.write("="); + + boolean leading = true; + for (int i = 0; i < value.length(); ++i) + { + boolean new_lead = false; + char c = value.charAt(i); + switch (c) + { + case '\n': + output.write("\\n"); + break; + case '\r': + output.write("\\r"); + break; + case '\t': + output.write("\\t"); + break; + case '\\': + output.write("\\\\"); + break; + + case '#': + case '!': + case '=': + case ':': + output.write("\\"); + output.write(c); + break; + + case ' ': + new_lead = leading; + if (leading) + output.write("\\"); + output.write(c); + break; + + default: + if (c < '\u0020' || c > '\u007e') + { + output.write("\\u"); + output.write(Character.forDigit(c >>> 12, 16)); + output.write(Character.forDigit((c >>> 8) & 0xff, + 16)); + output.write(Character.forDigit((c >>> 4) & 0xff, + 16)); + output.write(Character.forDigit(c & 0xff, 16)); + } + else + output.write(c); + } + leading = new_lead; + } + output.write(newline); + } + + output.flush(); + } + catch (IOException ignore) + { + } + } +} |