diff options
author | Tom Tromey <tromey@redhat.com> | 2002-06-18 15:40:16 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2002-06-18 15:40:16 +0000 |
commit | 3831381763ca5f41d6f7406d590e1e38a8531e1c (patch) | |
tree | 6b8dcd38b7dbb7c4c618080eb1958b6f042d581c /libjava/java/util | |
parent | 0fd534ed06e92a7232b2373321f113ee8dd482c4 (diff) | |
download | gcc-3831381763ca5f41d6f7406d590e1e38a8531e1c.zip gcc-3831381763ca5f41d6f7406d590e1e38a8531e1c.tar.gz gcc-3831381763ca5f41d6f7406d590e1e38a8531e1c.tar.bz2 |
javaprims.h: Updated class declaration list.
* gcj/javaprims.h: Updated class declaration list.
* Makefile.in: Rebuilt.
* Makefile.am (core_java_source_files): Added
PropertyPermissionCollection.java.
* java/lang/Thread.java (group, name): Now package-private.
* java/lang/ThreadGroup.java: Re-merge with Classpath.
* java/util/AbstractList.java: Likewise.
* java/util/AbstractMap.java: Likewise.
* java/util/Calendar.java: Likewise.
* java/util/Collections.java: Likewise.
* java/util/HashMap.java: Likewise.
* java/util/Hashtable.java: Likewise.
* java/util/LinkedHashMap.java: Likewise.
* java/util/LinkedList.java: Likewise.
* java/util/List.java: Likewise.
* java/util/ListResourceBundle.java: Likewise.
* java/util/Map.java: Likewise.
* java/util/Observable.java: Likewise.
* java/util/Properties.java: Likewise.
* java/util/PropertyPermission.java: Likewise.
* java/util/PropertyPermissionCollection.java: Likewise.
* java/util/PropertyResourceBundle.java: Likewise.
* java/util/Random.java: Likewise.
* java/util/SimpleTimeZone.java: Likewise.
* java/util/StringTokenizer.java: Likewise.
* java/util/TimerTask.java: Likewise.
* java/util/TreeMap.java: Likewise.
* java/util/WeakHashMap.java: Likewise.
* java/util/jar/Attributes.java: Likewise.
* java/util/jar/JarException.java: Likewise.
* java/util/jar/Manifest.java: Likewise.
From-SVN: r54743
Diffstat (limited to 'libjava/java/util')
25 files changed, 1693 insertions, 1068 deletions
diff --git a/libjava/java/util/AbstractList.java b/libjava/java/util/AbstractList.java index 1c2d1de..be0bc30 100644 --- a/libjava/java/util/AbstractList.java +++ b/libjava/java/util/AbstractList.java @@ -1,5 +1,5 @@ /* AbstractList.java -- Abstract implementation of most of List - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -237,20 +237,22 @@ public abstract class AbstractList extends AbstractCollection implements List } /** - * Obtain a hash code for this list. In order to obey the general contract of - * the hashCode method of class Object, this value is calculated as follows: - * <pre> - * hashCode = 1; - * Iterator i = list.iterator(); - * while (i.hasNext()) - * { - * Object obj = i.next(); - * hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); - * } - * </pre> + * Obtains a hash code for this list. In order to obey the general + * contract of the hashCode method of class Object, this value is + * calculated as follows: + * +<pre>hashCode = 1; +Iterator i = list.iterator(); +while (i.hasNext()) +{ + Object obj = i.next(); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); +}</pre> + * * This ensures that the general contract of Object.hashCode() is adhered to. * * @return the hash code of this list + * * @see Object#hashCode() * @see #equals(Object) */ @@ -611,19 +613,21 @@ public abstract class AbstractList extends AbstractCollection implements List /** * This class follows the implementation requirements set forth in - * {@link AbstractList#subList(int, int)}. Some compilers have problems - * with AbstractList.this.modCount if this class is nested in AbstractList, - * even though the JLS defines that to be legal, so we make it a top-level - * class. + * {@link AbstractList#subList(int, int)}. It matches Sun's implementation + * by using a non-public top-level class in the same package. * * @author Original author unknown * @author Eric Blake <ebb9@email.byu.edu> */ class SubList extends AbstractList { - private final AbstractList backingList; - private final int offset; - private int size; + // Package visible, for use by iterator. + /** The original list. */ + final AbstractList backingList; + /** The index of the first element of the sublist. */ + final int offset; + /** The size of the sublist. */ + int size; /** * Construct the sublist. @@ -647,8 +651,8 @@ class SubList extends AbstractList * @throws ConcurrentModificationException if the backing list has been * modified externally to this sublist */ - // This will get inlined, since it is private. - private void checkMod() + // This can be inlined. Package visible, for use by iterator. + void checkMod() { if (modCount != backingList.modCount) throw new ConcurrentModificationException(); diff --git a/libjava/java/util/AbstractMap.java b/libjava/java/util/AbstractMap.java index 555d055..11c8f5b 100644 --- a/libjava/java/util/AbstractMap.java +++ b/libjava/java/util/AbstractMap.java @@ -1,5 +1,5 @@ /* AbstractMap.java -- Abstract implementation of most of Map - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -518,4 +518,130 @@ public abstract class AbstractMap implements Map { return o == null ? 0 : o.hashCode(); } + + /** + * A class which implements Map.Entry. It is shared by HashMap, TreeMap, + * Hashtable, and Collections. It is not specified by the JDK, but makes + * life much easier. + * + * @author Jon Zeppieri + * @author Eric Blake <ebb9@email.byu.edu> + */ + static class BasicMapEntry implements Map.Entry + { // XXX - FIXME Use fully qualified implements as gcj 3.1 workaround. + /** + * The key. Package visible for direct manipulation. + */ + Object key; + + /** + * The value. Package visible for direct manipulation. + */ + Object value; + + /** + * Basic constructor initializes the fields. + * @param newKey the key + * @param newValue the value + */ + BasicMapEntry(Object newKey, Object newValue) + { + key = newKey; + value = newValue; + } + + /** + * Compares the specified object with this entry. Returns true only if + * the object is a mapping of identical key and value. In other words, + * this must be: + * +<pre>(o instanceof Map.Entry) && +(getKey() == null ? ((HashMap) o).getKey() == null + : getKey().equals(((HashMap) o).getKey())) && +(getValue() == null ? ((HashMap) o).getValue() == null + : getValue().equals(((HashMap) o).getValue()))</pre> + * + * @param o the object to compare + * + * @return <code>true</code> if it is equal + */ + public final boolean equals(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + // Optimize for our own entries. + if (o instanceof BasicMapEntry) + { + BasicMapEntry e = (BasicMapEntry) o; + return (AbstractMap.equals(key, e.key) + && AbstractMap.equals(value, e.value)); + } + Map.Entry e = (Map.Entry) o; + return (AbstractMap.equals(key, e.getKey()) + && AbstractMap.equals(value, e.getValue())); + } + + /** + * Get the key corresponding to this entry. + * + * @return the key + */ + public final Object getKey() + { + return key; + } + + /** + * Get the value corresponding to this entry. If you already called + * Iterator.remove(), the behavior undefined, but in this case it works. + * + * @return the value + */ + public final Object getValue() + { + return value; + } + + /** + * Returns the hash code of the entry. This is defined as the exclusive-or + * of the hashcodes of the key and value (using 0 for null). In other + * words, this must be: + * +<pre>(getKey() == null ? 0 : getKey().hashCode()) +^ (getValue() == null ? 0 : getValue().hashCode())</pre> + * + * @return the hash code + */ + public final int hashCode() + { + return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value)); + } + + /** + * Replaces the value with the specified object. This writes through + * to the map, unless you have already called Iterator.remove(). It + * may be overridden to restrict a null value. + * + * @param newVal the new value to store + * @return the old value + * @throws NullPointerException if the map forbids null values + */ + public Object setValue(Object newVal) + { + Object r = value; + value = newVal; + return r; + } + + /** + * This provides a string representation of the entry. It is of the form + * "key=value", where string concatenation is used on key and value. + * + * @return the string representation + */ + public final String toString() + { + return key + "=" + value; + } + } // class BasicMapEntry } diff --git a/libjava/java/util/Calendar.java b/libjava/java/util/Calendar.java index 8271779..999f105 100644 --- a/libjava/java/util/Calendar.java +++ b/libjava/java/util/Calendar.java @@ -73,13 +73,12 @@ import java.io.*; * and for the first line all fields are set, that line is used to * compute the day. <br> * - * <pre> - * month + day_of_month - * month + week_of_month + day_of_week - * month + day_of_week_of_month + day_of_week - * day_of_year - * day_of_week + week_of_year - * </pre> + * +<pre>month + day_of_month +month + week_of_month + day_of_week +month + day_of_week_of_month + day_of_week +day_of_year +day_of_week + week_of_year</pre> * * The hour_of_day-field takes precedence over the ampm and * hour_of_ampm fields. <br> diff --git a/libjava/java/util/Collections.java b/libjava/java/util/Collections.java index 9c10a4b..815afcc 100644 --- a/libjava/java/util/Collections.java +++ b/libjava/java/util/Collections.java @@ -1,5 +1,5 @@ /* Collections.java -- Utility class with methods to operate on collections - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -60,7 +60,6 @@ import java.io.Serializable; * modify the set. * * @author Original author unknown - * @author Bryce McKinlay * @author Eric Blake <ebb9@email.byu.edu> * @see Collection * @see Set @@ -108,24 +107,6 @@ public class Collections */ public static final Set EMPTY_SET = new EmptySet(); - private static final Iterator EMPTY_ITERATOR = new Iterator() - { - public boolean hasNext() - { - return false; - } - - public Object next() - { - throw new NoSuchElementException(); - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - }; - /** * The implementation of {@link #EMPTY_SET}. This class name is required * for compatibility with Sun's JDK serializability. @@ -158,9 +139,94 @@ public class Collections /** * Returns an iterator that does not iterate. */ + // This is really cheating! I think it's perfectly valid, though. public Iterator iterator() { - return EMPTY_ITERATOR; + return EMPTY_LIST.iterator(); + } + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractSet. + /** + * The empty set never contains anything. + */ + public boolean contains(Object o) + { + return false; + } + + /** + * This is true only if the given collection is also empty. + */ + public boolean containsAll(Collection c) + { + return c.isEmpty(); + } + + /** + * Equal only if the other set is empty. + */ + public boolean equals(Object o) + { + return o instanceof Set && ((Set) o).isEmpty(); + } + + /** + * The hashcode is always 0. + */ + public int hashCode() + { + return 0; + } + + /** + * Always succeeds with false result. + */ + public boolean remove(Object o) + { + return false; + } + + /** + * Always succeeds with false result. + */ + public boolean removeAll(Collection c) + { + return false; + } + + /** + * Always succeeds with false result. + */ + public boolean retainAll(Collection c) + { + return false; + } + + /** + * The array is always empty. + */ + public Object[] toArray() + { + return new Object[0]; + } + + /** + * We don't even need to use reflection! + */ + public Object[] toArray(Object[] a) + { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * The string never changes. + */ + public String toString() + { + return "[]"; } } // class EmptySet @@ -207,15 +273,106 @@ public class Collections { throw new IndexOutOfBoundsException(); } - + + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractList. /** - * Returns an iterator that does not iterate. Optional, but avoids - * allocation of an iterator in AbstractList. + * Never contains anything. */ - public Iterator iterator() + public boolean contains(Object o) { - return EMPTY_ITERATOR; - } + return false; + } + + /** + * This is true only if the given collection is also empty. + */ + public boolean containsAll(Collection c) + { + return c.isEmpty(); + } + + /** + * Equal only if the other set is empty. + */ + public boolean equals(Object o) + { + return o instanceof List && ((List) o).isEmpty(); + } + + /** + * The hashcode is always 1. + */ + public int hashCode() + { + return 1; + } + + /** + * Returns -1. + */ + public int indexOf(Object o) + { + return -1; + } + + /** + * Returns -1. + */ + public int lastIndexOf(Object o) + { + return -1; + } + + /** + * Always succeeds with false result. + */ + public boolean remove(Object o) + { + return false; + } + + /** + * Always succeeds with false result. + */ + public boolean removeAll(Collection c) + { + return false; + } + + /** + * Always succeeds with false result. + */ + public boolean retainAll(Collection c) + { + return false; + } + + /** + * The array is always empty. + */ + public Object[] toArray() + { + return new Object[0]; + } + + /** + * We don't even need to use reflection! + */ + public Object[] toArray(Object[] a) + { + if (a.length > 0) + a[0] = null; + return a; + } + + /** + * The string never changes. + */ + public String toString() + { + return "[]"; + } } // class EmptyList /** @@ -253,6 +410,64 @@ public class Collections return EMPTY_SET; } + // The remaining methods are optional, but provide a performance + // advantage by not allocating unnecessary iterators in AbstractMap. + /** + * No entries! + */ + public boolean containsKey(Object key) + { + return false; + } + + /** + * No entries! + */ + public boolean containsValue(Object value) + { + return false; + } + + /** + * Equal to all empty maps. + */ + public boolean equals(Object o) + { + return o instanceof Map && ((Map) o).isEmpty(); + } + + /** + * No mappings, so this returns null. + */ + public Object get(Object o) + { + return null; + } + + /** + * The hashcode is always 0. + */ + public int hashCode() + { + return 0; + } + + /** + * No entries. + */ + public Set keySet() + { + return EMPTY_SET; + } + + /** + * Remove always succeeds, with null result. + */ + public Object remove(Object o) + { + return null; + } + /** * Size is always 0. */ @@ -269,8 +484,17 @@ public class Collections { return EMPTY_SET; } + + /** + * The string never changes. + */ + public String toString() + { + return "[]"; + } } // class EmptyMap + /** * Compare two objects with or without a Comparator. If c is null, uses the * natural ordering. Slightly slower than doing it inline if the JVM isn't @@ -502,7 +726,7 @@ public class Collections } /** - * Returns an array list holding the elements visited by a given + * Returns an ArrayList holding the elements visited by a given * Enumeration. This method exists for interoperability between legacy * APIs and the new Collection API. * @@ -511,9 +735,9 @@ public class Collections * @see ArrayList * @since 1.4 */ - public static List list(Enumeration e) + public static ArrayList list(Enumeration e) { - List l = new ArrayList(); + ArrayList l = new ArrayList(); while (e.hasMoreElements()) l.add(e.nextElement()); return l; @@ -1353,7 +1577,7 @@ public class Collections public Set entrySet() { if (entries == null) - entries = singleton(new BasicMapEntry(k, v) + entries = singleton(new AbstractMap.BasicMapEntry(k, v) { public Object setValue(Object o) { @@ -1500,6 +1724,7 @@ public class Collections l.set(i, l.set(j, l.get(i))); } + /** * Returns a synchronized (thread-safe) collection wrapper backed by the * given collection. Notice that element access through the iterators @@ -2682,6 +2907,7 @@ public class Collections } } // class SynchronizedSortedSet + /** * Returns an unmodifiable view of the given collection. This allows * "read-only" access, although changes in the backing collection show up diff --git a/libjava/java/util/HashMap.java b/libjava/java/util/HashMap.java index 9451744..a78eb9a 100644 --- a/libjava/java/util/HashMap.java +++ b/libjava/java/util/HashMap.java @@ -1,6 +1,6 @@ /* HashMap.java -- a class providing a basic hashtable data structure, mapping Object --> Object - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -162,7 +162,7 @@ public class HashMap extends AbstractMap * * @author Eric Blake <ebb9@email.byu.edu> */ - static class HashEntry extends BasicMapEntry + static class HashEntry extends AbstractMap.BasicMapEntry { /** * The next entry in the linked list. Package visible for use by subclass. @@ -373,9 +373,9 @@ public class HashMap extends AbstractMap { Map.Entry e = (Map.Entry) itr.next(); // Optimize in case the Entry is one of our own. - if (e instanceof BasicMapEntry) + if (e instanceof AbstractMap.BasicMapEntry) { - BasicMapEntry entry = (BasicMapEntry) e; + AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e; put(entry.key, entry.value); } else @@ -647,7 +647,8 @@ public class HashMap extends AbstractMap * @return the matching entry, if found, or null * @see #entrySet() */ - private HashEntry getEntry(Object o) + // Package visible, for use in nested classes. + HashEntry getEntry(Object o) { if (!(o instanceof Map.Entry)) return null; @@ -710,14 +711,13 @@ public class HashMap extends AbstractMap } /** - * Increases the size of the HashMap and rehashes all keys to new array - * indices; this is called when the addition of a new value would cause - * size() > threshold. Note that the existing Entry objects are reused in - * the new hash table. - * <p> + * Increases the size of the HashMap and rehashes all keys to new + * array indices; this is called when the addition of a new value + * would cause size() > threshold. Note that the existing Entry + * objects are reused in the new hash table. * - * This is not specified, but the new size is twice the current size plus - * one; this number is not always prime, unfortunately. + * <p>This is not specified, but the new size is twice the current size + * plus one; this number is not always prime, unfortunately. */ private void rehash() { diff --git a/libjava/java/util/Hashtable.java b/libjava/java/util/Hashtable.java index 71ec4b80..a94143b 100644 --- a/libjava/java/util/Hashtable.java +++ b/libjava/java/util/Hashtable.java @@ -1,6 +1,6 @@ /* Hashtable.java -- a class providing a basic hashtable data structure, mapping Object --> Object - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -102,6 +102,9 @@ import java.io.ObjectOutputStream; public class Hashtable extends Dictionary implements Map, Cloneable, Serializable { + // WARNING: Hashtable is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + /** Default number of buckets. This is the value the JDK 1.3 uses. Some * early documentation specified this value as 101. That is incorrect. */ @@ -176,7 +179,7 @@ public class Hashtable extends Dictionary * pair. A Hashtable Entry is identical to a HashMap Entry, except that * `null' is not allowed for keys and values. */ - private static final class HashEntry extends BasicMapEntry + private static final class HashEntry extends AbstractMap.BasicMapEntry { /** The next entry in the linked list. */ HashEntry next; @@ -340,9 +343,9 @@ public class Hashtable extends Dictionary * * @param value the value to search for in this Hashtable * @return true if at least one key maps to the value - * @throws NullPointerException if <code>value</code> is null * @see #contains(Object) * @see #containsKey(Object) + * @throws NullPointerException if <code>value</code> is null * @since 1.2 */ public boolean containsValue(Object value) @@ -361,7 +364,7 @@ public class Hashtable extends Dictionary // Must throw on null argument even if the table is empty if (value == null) throw new NullPointerException(); - + return false; } @@ -511,9 +514,9 @@ public class Hashtable extends Dictionary { Map.Entry e = (Map.Entry) itr.next(); // Optimize in case the Entry is one of our own. - if (e instanceof BasicMapEntry) + if (e instanceof AbstractMap.BasicMapEntry) { - BasicMapEntry entry = (BasicMapEntry) e; + AbstractMap.BasicMapEntry entry = (AbstractMap.BasicMapEntry) e; put(entry.key, entry.value); } else @@ -763,9 +766,9 @@ public class Hashtable extends Dictionary /** * Returns true if this Hashtable equals the supplied Object <code>o</code>. * As specified by Map, this is: - * <pre> + * <code> * (o instanceof Map) && entrySet().equals(((Map) o).entrySet()); - * </pre> + * </code> * * @param o the object to compare to * @return true if o is an equal map @@ -812,7 +815,10 @@ public class Hashtable extends Dictionary */ private int hash(Object key) { - return Math.abs(key.hashCode() % buckets.length); + // Note: Inline Math.abs here, for less method overhead, and to avoid + // a bootstrap dependency, since Math relies on native methods. + int hash = key.hashCode() % buckets.length; + return hash < 0 ? -hash : hash; } /** @@ -823,7 +829,8 @@ public class Hashtable extends Dictionary * @return the matching entry, if found, or null * @see #entrySet() */ - private HashEntry getEntry(Object o) + // Package visible, for use in nested classes. + HashEntry getEntry(Object o) { if (! (o instanceof Map.Entry)) return null; @@ -869,7 +876,7 @@ public class Hashtable extends Dictionary /** * Increases the size of the Hashtable and rehashes all keys to new array * indices; this is called when the addition of a new value would cause - * size() > threshold. Note that the existing Entry objects are reused in + * size() > threshold. Note that the existing Entry objects are reused in * the new hash table. * <p> * @@ -1139,4 +1146,4 @@ public class Hashtable extends Dictionary return type == VALUES ? e.value : e.key; } } // class Enumerator -} +} // class Hashtable diff --git a/libjava/java/util/LinkedHashMap.java b/libjava/java/util/LinkedHashMap.java index 0709bdf..2716ac1 100644 --- a/libjava/java/util/LinkedHashMap.java +++ b/libjava/java/util/LinkedHashMap.java @@ -71,7 +71,7 @@ package java.util; * <p> * * Under ideal circumstances (no collisions), LinkedHashMap offers O(1) - * performance on most operations (<pre>containsValue()</pre> is, + * performance on most operations (<code>containsValue()</code> is, * of course, O(n)). In the worst case (all keys map to the same * hash code -- very unlikely), most operations are O(n). * <p> @@ -87,7 +87,7 @@ package java.util; * {@link ConcurrentModificationException} rather than exhibit * non-deterministic behavior. * - * @author Eric Blake <ebb9@email.byu.edu> + * @author Eric Blake (ebb9@email.byu.edu) * @see Object#hashCode() * @see Collection * @see Map @@ -256,8 +256,9 @@ public class LinkedHashMap extends HashMap * @param initialCapacity the initial capacity (>=0) * @param loadFactor the load factor (>0, not NaN) * @param accessOrder true for access-order, false for insertion-order - * @throws IllegalArgumentException if (initialCapacity < 0) || - * ! (loadFactor > 0.0) + * + * @throws IllegalArgumentException if (initialCapacity < 0) || + * ! (loadFactor > 0.0) */ public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) @@ -277,11 +278,12 @@ public class LinkedHashMap extends HashMap } /** - * Returns true if this HashMap contains a value <pre>o</pre>, such that - * <pre>o.equals(value)</pre>. + * Returns <code>true</code> if this HashMap contains a value + * <code>o</code>, such that <code>o.equals(value)</code>. * * @param value the value to search for in this HashMap - * @return true if at least one key maps to the value + * + * @return <code>true</code> if at least one key maps to the value */ public boolean containsValue(Object value) { @@ -297,7 +299,7 @@ public class LinkedHashMap extends HashMap /** * Return the value in this Map associated with the supplied key, - * or <pre>null</pre> if the key maps to nothing. If this is an + * or <code>null</code> if the key maps to nothing. If this is an * access-ordered Map and the key is found, this performs structural * modification, moving the key to the newest end of the list. NOTE: * Since the value could also be null, you must use containsKey to @@ -350,14 +352,14 @@ public class LinkedHashMap extends HashMap * <p> * * For example, to keep the Map limited to 100 entries, override as follows: - * <pre> - * private static final int MAX_ENTRIES = 100; - * - * protected boolean removeEldestEntry(Map.Entry eldest) - * { - * return size() > MAX_ENTRIES; - * } - * </pre><p> + * +<pre>private static final int MAX_ENTRIES = 100; + +protected boolean removeEldestEntry(Map.Entry eldest) +{ + return size() > MAX_ENTRIES; +} +</pre><p> * * Typically, this method does not modify the map, but just uses the * return value as an indication to <code>put</code> whether to proceed. @@ -376,6 +378,7 @@ public class LinkedHashMap extends HashMap * returns true. For an access-order map, this is the least * recently accessed; for an insertion-order map, this is the * earliest element inserted. + * * @return true if <code>eldest</code> should be removed */ protected boolean removeEldestEntry(Map.Entry eldest) @@ -467,8 +470,10 @@ public class LinkedHashMap extends HashMap /** * Removes from the backing HashMap the last element which was fetched - * with the <pre>next()</pre> method. + * with the <code>next()</code> method. + * * @throws ConcurrentModificationException if the HashMap was modified + * * @throws IllegalStateException if called when there is no last element */ public void remove() diff --git a/libjava/java/util/LinkedList.java b/libjava/java/util/LinkedList.java index d87e95a..c891f82 100644 --- a/libjava/java/util/LinkedList.java +++ b/libjava/java/util/LinkedList.java @@ -1,5 +1,5 @@ /* LinkedList.java -- Linked list implementation of the List interface - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -125,12 +125,13 @@ public class LinkedList extends AbstractSequentialList * entry in the list is obtained in constant time, which is a very desirable * property. * For speed and flexibility, range checking is not done in this method: - * Incorrect values will be returned if (n < 0) or (n >= size). + * Incorrect values will be returned if (n < 0) or (n >= size). * * @param n the number of the entry to get * @return the entry at position n */ - private Entry getEntry(int n) + // Package visible for use in nested classes. + Entry getEntry(int n) { Entry e; if (n < size / 2) @@ -156,7 +157,8 @@ public class LinkedList extends AbstractSequentialList * * @param e the entry to remove */ - private void removeEntry(Entry e) + // Package visible for use in nested classes. + void removeEntry(Entry e) { modCount++; size--; diff --git a/libjava/java/util/List.java b/libjava/java/util/List.java index 0d8df5d1..22a6b83 100644 --- a/libjava/java/util/List.java +++ b/libjava/java/util/List.java @@ -201,7 +201,7 @@ public interface List extends Collection * @see Object#equals(Object) * @see #hashCode() */ - /* boolean equals(Object o);*/ + boolean equals(Object o); /** * Get the element at a given index in this list. @@ -213,18 +213,20 @@ public interface List extends Collection Object get(int index); /** - * Obtain a hash code for this list. In order to obey the general contract of - * the hashCode method of class Object, this value is calculated as follows: - * <pre> - * hashCode = 1; - * Iterator i = list.iterator(); - * while (i.hasNext()) - * { - * Object obj = i.next(); - * hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); - * } - * </pre> - * This ensures that the general contract of Object.hashCode() is adhered to. + * Obtains a hash code for this list. In order to obey the general + * contract of the hashCode method of class Object, this value is + * calculated as follows: + * +<p><pre>hashCode = 1; +Iterator i = list.iterator(); +while (i.hasNext()) +{ + Object obj = i.next(); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); +}</pre> + * + * <p>This ensures that the general contract of Object.hashCode() + * is adhered to. * * @return the hash code of this list * @see Object#hashCode() diff --git a/libjava/java/util/ListResourceBundle.java b/libjava/java/util/ListResourceBundle.java index 45508c7..b7b32c2 100644 --- a/libjava/java/util/ListResourceBundle.java +++ b/libjava/java/util/ListResourceBundle.java @@ -1,5 +1,5 @@ -/* java.util.ListResourceBundle - Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. +/* ListResourceBundle -- a resource bundle build around a list + Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,73 +39,102 @@ exception statement from your version. */ package java.util; /** - * A <code>ListResouceBundle</code> provides an easy way, to create - * your own resource bundle. It is an abstract class that you can - * subclass. You should then overwrite the getContents method, that - * provides a key/value list. - * <br> - * The key/value list is a two dimensional list of Object. The first - * dimension ranges over the resources. The second dimension ranges - * from zero (key) to one (value). The keys must be of type String. - * <br> - * XXX Example! + * A <code>ListResouceBundle</code> provides an easy way, to create your own + * resource bundle. It is an abstract class that you can subclass. You should + * then overwrite the getContents method, that provides a key/value list. * + * <p>The key/value list is a two dimensional list of Object. The first + * dimension ranges over the resources. The second dimension ranges from + * zero (key) to one (value). The keys must be of type String, and they are + * case-sensitive. For example: + * +<br><pre>public class MyResources + extends ListResourceBundle +{ + public Object[][] getContents() + { + return contents; + } + + static final Object[][] contents = + { + // LOCALIZED STRINGS + {"s1", "The disk \"{1}\" contains {0}."}, // MessageFormat pattern + {"s2", "1"}, // location of {0} in pattern + {"s3", "My Disk"}, // sample disk name + {"s4", "no files"}, // first ChoiceFormat choice + {"s5", "one file"}, // second ChoiceFormat choice + {"s6", "{0,number} files"} // third ChoiceFormat choice + {"s7", "3 Mar 96"}, // sample date + {"s8", new Dimension(1,5)} // real object, not just string + // END OF LOCALIZED MATERIAL + }; +}</pre> + * + * @author Jochen Hoenicke + * @author Eric Blake <ebb9@email.byu.edu> * @see Locale * @see PropertyResourceBundle - * @author Jochen Hoenicke */ + * @since 1.1 + * @status updated to 1.4 + */ public abstract class ListResourceBundle extends ResourceBundle { /** - * The constructor. It does nothing special. + * The constructor. It does nothing special. */ public ListResourceBundle() { } /** - * Gets the key/value list. You must override this method. - * @return a two dimensional list of Objects. The first dimension - * ranges over the objects, and the second dimension ranges from - * zero (key) to one (value). - */ - protected abstract Object[][] getContents(); - - /** - * Override this method to provide the resource for a keys. This gets - * called by <code>getObject</code>. - * @param key The key of the resource. - * @return The resource for the key or null if it doesn't exists. + * Gets a resource for a given key. This is called by <code>getObject</code>. + * + * @param key the key of the resource + * @return the resource for the key, or null if it doesn't exist */ public final Object handleGetObject(String key) { Object[][] contents = getContents(); - for (int i = 0; i < contents.length; i++) - { - if (key.equals(contents[i][0])) - return contents[i][1]; - } + int i = contents.length; + while (--i >= 0) + if (key.equals(contents[i][0])) + return contents[i][1]; return null; } /** * This method should return all keys for which a resource exists. - * @return An enumeration of the keys. + * + * @return an enumeration of the keys */ public Enumeration getKeys() { + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. final Object[][] contents = getContents(); - - return new Enumeration() - { - int i = 0; - public boolean hasMoreElements() - { - return i < contents.length; - } - public Object nextElement() + Set s = new HashSet(); + int i = contents.length; + while (--i >= 0) + s.add(contents[i][0]); + ResourceBundle bundle = parent; + // Eliminate tail recursion. + while (bundle != null) { - return contents[i++][0]; + Enumeration e = bundle.getKeys(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + bundle = bundle.parent; } - }; + return Collections.enumeration(s); } -} + + /** + * Gets the key/value list. You must override this method, and should not + * provide duplicate keys or null entries. + * + * @return a two dimensional list of String key / Object resouce pairs + */ + protected abstract Object[][] getContents(); +} // class ListResourceBundle diff --git a/libjava/java/util/Map.java b/libjava/java/util/Map.java index 5918a41..01f9b23 100644 --- a/libjava/java/util/Map.java +++ b/libjava/java/util/Map.java @@ -296,14 +296,14 @@ public interface Map */ public Object setValue(Object value); + /** - * Returns the hash code of the entry. This is defined as the exclusive-or - * of the hashcodes of the key and value (using 0 for null). In other - * words, this must be: - * <pre> - * (getKey() == null ? 0 : getKey().hashCode()) ^ - * (getValue() == null ? 0 : getValue().hashCode()) - * </pre> + * Returns the hash code of the entry. This is defined as the + * exclusive-or of the hashcodes of the key and value (using 0 for + * <code>null</code>). In other words, this must be: + * +<p><pre>(getKey() == null ? 0 : getKey().hashCode()) +^ (getValue() == null ? 0 : getValue().hashCode())</pre> * * @return the hash code */ @@ -313,16 +313,16 @@ public interface Map * Compares the specified object with this entry. Returns true only if * the object is a mapping of identical key and value. In other words, * this must be: - * <pre> - * (o instanceof Map.Entry) - * && (getKey() == null ? ((HashMap) o).getKey() == null - * : getKey().equals(((HashMap) o).getKey())) - * && (getValue() == null ? ((HashMap) o).getValue() == null - * : getValue().equals(((HashMap) o).getValue())) - * </pre> + * +<p><pre>(o instanceof Map.Entry) +&& (getKey() == null ? ((HashMap) o).getKey() == null + : getKey().equals(((HashMap) o).getKey())) +&& (getValue() == null ? ((HashMap) o).getValue() == null + : getValue().equals(((HashMap) o).getValue()))</pre> * * @param o the object to compare - * @return true if it is equal + * + * @return <code>true</code> if it is equal */ public boolean equals(Object o); } diff --git a/libjava/java/util/Observable.java b/libjava/java/util/Observable.java index 4760713..7616f51 100644 --- a/libjava/java/util/Observable.java +++ b/libjava/java/util/Observable.java @@ -1,5 +1,5 @@ -/* java.util.Observable - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. +/* Observable.java -- an object to be observed + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,55 +38,53 @@ exception statement from your version. */ package java.util; -/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 - * "The Java Language Specification", ISBN 0-201-63451-1 - * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. - * Status: Believed complete and correct. - */ - /** + * This class represents an object which is observable. Other objects may + * register their intent to be notified when this object changes; and when + * this object does change, it will trigger the <code>update</code> method + * of each observer. + * + * Note that the <code>notifyObservers()</code> method of this class is + * unrelated to the <code>notify()</code> of Object. + * * @author Warren Levy <warrenl@cygnus.com> - * @date September 2, 1998. + * @author Eric Blake <ebb9@email.byu.edu> + * @see Observer + * @status updated to 1.4 */ public class Observable { - /** tracks whether this object has changed */ + /** Tracks whether this object has changed. */ private boolean changed; - /* list of the Observers registered as interested in this Observable */ - private Vector observers; - - /* TBD: This might be better implemented as an Observer[] - * but that would mean writing more code rather than making use of - * the existing Vector class (this also implies a larger text code - * space in resulting executables). The tradeoff is one of speed - * (manipulating the Observer[] directly) vs. size/reuse. In the future, - * we may decide to make the tradeoff and reimplement with an Observer[]. - */ + /* List of the Observers registered as interested in this Observable. */ + private LinkedHashSet observers; /** * Constructs an Observable with zero Observers. */ public Observable() { - changed = false; - observers = new Vector(); + observers = new LinkedHashSet(); } /** * Adds an Observer. If the observer was already added this method does * nothing. * - * @param observer Observer to add. + * @param observer Observer to add + * @throws NullPointerException if observer is null */ public synchronized void addObserver(Observer observer) { - if (!observers.contains(observer)) - observers.addElement(observer); + observers.add(observer); } /** - * Reset this Observable's state to unchanged. + * Reset this Observable's state to unchanged. This is called automatically + * by <code>notifyObservers</code> once all observers have been notified. + * + * @see #notifyObservers() */ protected synchronized void clearChanged() { @@ -94,7 +92,9 @@ public class Observable } /** - * @return Number of Observers for this Observable. + * Returns the number of observers for this object. + * + * @return number of Observers for this */ public synchronized int countObservers() { @@ -104,11 +104,11 @@ public class Observable /** * Deletes an Observer of this Observable. * - * @param victim Observer to delete. + * @param victim Observer to delete */ public synchronized void deleteObserver(Observer victim) { - observers.removeElement(victim); + observers.remove(victim); } /** @@ -116,11 +116,14 @@ public class Observable */ public synchronized void deleteObservers() { - observers.removeAllElements(); + observers.clear(); } /** - * @return Whether or not this Observable has changed. + * True if <code>setChanged</code> has been called more recently than + * <code>clearChanged</code>. + * + * @return whether or not this Observable has changed */ public synchronized boolean hasChanged() { @@ -129,7 +132,10 @@ public class Observable /** * If the Observable has actually changed then tell all Observers about it, - * then resets state to unchanged. + * then reset state to unchanged. + * + * @see #notifyObservers(Object) + * @see Observer#update(Observable, Object) */ public void notifyObservers() { @@ -138,21 +144,29 @@ public class Observable /** * If the Observable has actually changed then tell all Observers about it, - * then resets state to unchanged. - * Note that though the order of notification is unspecified in subclasses, - * in Observable it is in the order of registration. + * then reset state to unchanged. Note that though the order of + * notification is unspecified in subclasses, in Observable it is in the + * order of registration. * - * @param obj Arguement to Observer's update method. + * @param obj argument to Observer's update method + * @see Observer#update(Observable, Object) */ public void notifyObservers(Object obj) { - if (!hasChanged()) + if (! hasChanged()) return; - Vector ob1 = (Vector) observers.clone(); - - for (int i = 0; i < ob1.size(); i++) - ((Observer) ob1.elementAt(i)).update(this, obj); - + // Create clone inside monitor, as that is relatively fast and still + // important to keep threadsafe, but update observers outside of the + // lock since update() can call arbitrary code. + Set s; + synchronized (this) + { + s = (Set) observers.clone(); + } + int i = s.size(); + Iterator iter = s.iterator(); + while (--i >= 0) + ((Observer) iter.next()).update(this, obj); clearChanged(); } diff --git a/libjava/java/util/Properties.java b/libjava/java/util/Properties.java index fa3a754..adad250 100644 --- a/libjava/java/util/Properties.java +++ b/libjava/java/util/Properties.java @@ -1,5 +1,5 @@ -/* java.util.Properties - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +/* Properties.java -- a set of persistent properties + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,64 +37,88 @@ exception statement from your version. */ package java.util; -import java.io.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.PrintStream; +import java.io.OutputStreamWriter; /** + * A set of persistent properties, which can be saved or loaded from a stream. + * A property list may also contain defaults, searched if the main list + * does not contain a property for a given key. + * * An example of a properties file for the german language is given * here. This extends the example given in ListResourceBundle. * Create a file MyResource_de.properties with the following contents * and put it in the CLASSPATH. (The character * <code>\</code><code>u00e4</code> is the german ä) + * * - * <pre> - * s1=3 - * s2=MeineDisk - * s3=3. M\<code></code>u00e4rz 96 - * s4=Die Diskette ''{1}'' enth\<code></code>u00e4lt {0} in {2}. - * s5=0 - * s6=keine Dateien - * s7=1 - * s8=eine Datei - * s9=2 - * s10={0,number} Dateien - * s11=Das Formatieren schlug fehl mit folgender Exception: {0} - * s12=FEHLER - * s13=Ergebnis - * s14=Dialog - * s15=Auswahlkriterium - * s16=1,3 - * </pre> +<pre>s1=3 +s2=MeineDisk +s3=3. M\<code></code>u00e4rz 96 +s4=Die Diskette ''{1}'' enth\<code></code>u00e4lt {0} in {2}. +s5=0 +s6=keine Dateien +s7=1 +s8=eine Datei +s9=2 +s10={0,number} Dateien +s11=Das Formatieren schlug fehl mit folgender Exception: {0} +s12=FEHLER +s13=Ergebnis +s14=Dialog +s15=Auswahlkriterium +s16=1,3</pre> * - * Although this is a sub class of a hash table, you should never + * <p>Although this is a sub class of a hash table, you should never * insert anything other than strings to this property, or several * methods, that need string keys and values, will fail. To ensure * this, you should use the <code>get/setProperty</code> method instead * of <code>get/put</code>. * - * @see PropertyResourceBundle + * Properties are saved in ISO 8859-1 encoding, using Unicode escapes with + * a single <code>u</code> for any character which cannot be represented. + * * @author Jochen Hoenicke + * @author Eric Blake <ebb9@email.byu.edu> + * @see PropertyResourceBundle + * @status updated to 1.4 */ public class Properties extends Hashtable { + // WARNING: Properties is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + /** * The property list that contains default values for any keys not - * in this property list. + * in this property list. + * + * @serial the default properties */ protected Properties defaults; + /** + * Compatible with JDK 1.0+. + */ private static final long serialVersionUID = 4112578634029874840L; /** - * Creates a new empty property list. + * Creates a new empty property list with no default values. */ public Properties() { - this.defaults = null; } /** * Create a new empty property list with the specified default values. - * @param defaults a Properties object containing the default values. + * + * @param defaults a Properties object containing the default values */ public Properties(Properties defaults) { @@ -102,6 +126,21 @@ public class Properties extends Hashtable } /** + * Adds the given key/value pair to this properties. This calls + * the hashtable method put. + * + * @param key the key for this property + * @param value the value for this property + * @return The old value for the given key + * @see #getProperty(String) + * @since 1.2 + */ + public Object setProperty(String key, String value) + { + return put(key, value); + } + + /** * Reads a property list from an input stream. The stream should * have the following format: <br> * @@ -120,173 +159,176 @@ public class Properties extends Hashtable * * Escape sequences <code>\t, \n, \r, \\, \", \', \!, \#, \ </code>(a * space), and unicode characters with the - * <code>\</code><code>u</code>xxxx notation are detected, and + * <code>\\u</code><em>xxxx</em> notation are detected, and * converted to the corresponding single character. <br> * - * <pre> - * # This is a comment - * key = value - * k\:5 \ a string starting with space and ending with newline\n - * # This is a multiline specification; note that the value contains - * # no white space. - * weekdays: Sunday,Monday,Tuesday,Wednesday,\ - * Thursday,Friday,Saturday - * # The safest way to include a space at the end of a value: - * label = Name:\<code></code>u0020 - * </pre> + * +<pre># This is a comment +key = value +k\:5 \ a string starting with space and ending with newline\n +# This is a multiline specification; note that the value contains +# no white space. +weekdays: Sunday,Monday,Tuesday,Wednesday,\\ + Thursday,Friday,Saturday +# The safest way to include a space at the end of a value: +label = Name:\\u0020</pre> * * @param in the input stream - * @exception IOException if an error occurred when reading - * from the input. */ + * @throws IOException if an error occurred when reading the input + * @throws NullPointerException if in is null + */ public void load(InputStream inStream) throws IOException { // The spec says that the file must be encoded using ISO-8859-1. BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1")); String line; - + while ((line = reader.readLine()) != null) { - char c = 0; - int pos = 0; - while (pos < line.length() - && Character.isWhitespace(c = line.charAt(pos))) - pos++; + char c = 0; + int pos = 0; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; - // If line is empty or begins with a comment character, - // skip this line. - if (pos == line.length() || c == '#' || c == '!') - continue; + // If line is empty or begins with a comment character, + // skip this line. + if (pos == line.length() || c == '#' || c == '!') + continue; - // The characters up to the next Whitespace, ':', or '=' - // describe the key. But look for escape sequences. - StringBuffer key = new StringBuffer(); - while (pos < line.length() - && !Character.isWhitespace(c = line.charAt(pos++)) - && c != '=' && c != ':') - { - if (c == '\\') - { - if (pos == line.length()) - { - // The line continues on the next line. - line = reader.readLine(); - pos = 0; - while (pos < line.length() - && Character.isWhitespace(c = line.charAt(pos))) - pos++; - } - else - { - c = line.charAt(pos++); - switch (c) - { - case 'n': - key.append('\n'); - break; - case 't': - key.append('\t'); - break; - case 'r': - key.append('\r'); - break; - case 'u': - if (pos + 4 <= line.length()) - { - char uni = (char) Integer.parseInt - (line.substring(pos, pos + 4), 16); - key.append(uni); - pos += 4; - } // else throw exception? - break; - default: - key.append(c); - break; - } - } - } - else - key.append(c); - } + // The characters up to the next Whitespace, ':', or '=' + // describe the key. But look for escape sequences. + StringBuffer key = new StringBuffer(); + while (pos < line.length() + && ! Character.isWhitespace(c = line.charAt(pos++)) + && c != '=' && c != ':') + { + if (c == '\\') + { + if (pos == line.length()) + { + // The line continues on the next line. + line = reader.readLine(); + pos = 0; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + } + else + { + c = line.charAt(pos++); + switch (c) + { + case 'n': + key.append('\n'); + break; + case 't': + key.append('\t'); + break; + case 'r': + key.append('\r'); + break; + case 'u': + if (pos + 4 <= line.length()) + { + char uni = (char) Integer.parseInt + (line.substring(pos, pos + 4), 16); + key.append(uni); + pos += 4; + } // else throw exception? + break; + default: + key.append(c); + break; + } + } + } + else + key.append(c); + } - boolean isDelim = (c == ':' || c == '='); - while (pos < line.length() - && Character.isWhitespace(c = line.charAt(pos))) - pos++; + boolean isDelim = (c == ':' || c == '='); + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; - if (!isDelim && (c == ':' || c == '=')) - { - pos++; - while (pos < line.length() - && Character.isWhitespace(c = line.charAt(pos))) - pos++; - } + if (! isDelim && (c == ':' || c == '=')) + { + pos++; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + } - StringBuffer element = new StringBuffer(line.length() - pos); - while (pos < line.length()) - { - c = line.charAt(pos++); - if (c == '\\') - { - if (pos == line.length()) - { - // The line continues on the next line. - line = reader.readLine(); - pos = 0; - while (pos < line.length() - && Character.isWhitespace(c = line.charAt(pos))) - pos++; - element.ensureCapacity(line.length() - pos + - element.length()); - } - else - { - c = line.charAt(pos++); - switch (c) - { - case 'n': - element.append('\n'); - break; - case 't': - element.append('\t'); - break; - case 'r': - element.append('\r'); - break; - case 'u': - if (pos + 4 <= line.length()) - { - char uni = (char) Integer.parseInt - (line.substring(pos, pos + 4), 16); - element.append(uni); - pos += 4; - } // else throw exception? - break; - default: - element.append(c); - break; - } - } - } - else - element.append(c); - } - put(key.toString(), element.toString()); + StringBuffer element = new StringBuffer(line.length() - pos); + while (pos < line.length()) + { + c = line.charAt(pos++); + if (c == '\\') + { + if (pos == line.length()) + { + // The line continues on the next line. + line = reader.readLine(); + pos = 0; + while (pos < line.length() + && Character.isWhitespace(c = line.charAt(pos))) + pos++; + element.ensureCapacity(line.length() - pos + + element.length()); + } + else + { + c = line.charAt(pos++); + switch (c) + { + case 'n': + element.append('\n'); + break; + case 't': + element.append('\t'); + break; + case 'r': + element.append('\r'); + break; + case 'u': + if (pos + 4 <= line.length()) + { + char uni = (char) Integer.parseInt + (line.substring(pos, pos + 4), 16); + element.append(uni); + pos += 4; + } // else throw exception? + break; + default: + element.append(c); + break; + } + } + } + else + element.append(c); + } + put(key.toString(), element.toString()); } } /** * Calls <code>store(OutputStream out, String header)</code> and * ignores the IOException that may be thrown. - * @deprecated use store instead. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. + * + * @param out the stream to write to + * @param header a description of the property list + * @throws ClassCastException if this property contains any key or + * value that are not strings + * @deprecated use {@link #store(OutputStream, String)} instead */ public void save(OutputStream out, String header) { try { - store(out, header); + store(out, header); } catch (IOException ex) { @@ -294,13 +336,14 @@ public class Properties extends Hashtable } /** - * Writes the key/value pairs to the given output stream. <br> + * Writes the key/value pairs to the given output stream, in a format + * suitable for <code>load</code>.<br> * * If header is not null, this method writes a comment containing * the header as first line to the stream. The next line (or first * line if header is null) contains a comment with the current date. * Afterwards the key/value pairs are written to the stream in the - * following format. <br> + * following format.<br> * * Each line has the form <code>key = value</code>. Newlines, * Returns and tabs are written as <code>\n,\t,\r</code> resp. @@ -308,47 +351,42 @@ public class Properties extends Hashtable * preceeded by a backslash. Spaces are preceded with a backslash, * if and only if they are at the beginning of the key. Characters * that are not in the ascii range 33 to 127 are written in the - * <code>\</code><code>u</code>xxxx Form. + * <code>\</code><code>u</code>xxxx Form.<br> + * + * Following the listing, the output stream is flushed but left open. * * @param out the output stream - * @param header the header written in the first line, may be null. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. + * @param header the header written in the first line, may be null + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @throws IOException if writing to the stream fails + * @throws NullPointerException if out is null + * @since 1.2 */ public void store(OutputStream out, String header) throws IOException { // The spec says that the file must be encoded using ISO-8859-1. PrintWriter writer - = new PrintWriter(new OutputStreamWriter (out, "ISO-8859-1")); + = new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1")); if (header != null) writer.println("#" + header); - writer.println("#" + new Date().toString()); + writer.println("#" + new Date()); list(writer); writer.flush(); } /** - * Adds the given key/value pair to this properties. This calls - * the hashtable method put. - * @param key the key for this property - * @param value the value for this property - * @return The old value for the given key. - * @since JDK1.2 */ - public Object setProperty(String key, String value) - { - return put(key, value); - } - - /** * Gets the property with the specified key in this property list. * If the key is not found, the default property list is searched. - * If the property is not found in default or the default of - * default, null is returned. - * @param key The key for this property. - * @param defaulValue A default value - * @return The value for the given key, or null if not found. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. + * If the property is not found in the default, null is returned. + * + * @param key The key for this property + * @return the value for the given key, or null if not found + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #defaults + * @see #setProperty(String, String) + * @see #getProperty(String, String) */ public String getProperty(String key) { @@ -358,13 +396,16 @@ public class Properties extends Hashtable /** * Gets the property with the specified key in this property list. If * the key is not found, the default property list is searched. If the - * property is not found in default or the default of default, the - * specified defaultValue is returned. - * @param key The key for this property. - * @param defaulValue A default value - * @return The value for the given key. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. + * property is not found in the default, the specified defaultValue is + * returned. + * + * @param key The key for this property + * @param defaultValue A default value + * @return The value for the given key + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #defaults + * @see #setProperty(String, String) */ public String getProperty(String key, String defaultValue) { @@ -372,184 +413,145 @@ public class Properties extends Hashtable // Eliminate tail recursion. do { - String value = (String) prop.get(key); - if (value != null) - return value; - prop = prop.defaults; + String value = (String) prop.get(key); + if (value != null) + return value; + prop = prop.defaults; } while (prop != null); return defaultValue; } - private final void addHashEntries(Hashtable base) - { - if (defaults != null) - defaults.addHashEntries(base); - Enumeration keys = keys(); - while (keys.hasMoreElements()) - base.put(keys.nextElement(), base); - } - /** * Returns an enumeration of all keys in this property list, including * the keys in the default property list. + * + * @return an Enumeration of all defined keys */ 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(); + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. + Properties prop = this; + Set s = new HashSet(); + // Eliminate tail recursion. + do + { + s.addAll(prop.keySet()); + prop = prop.defaults; + } + while (prop != null); + return Collections.enumeration(s); } /** - * Formats a key/value pair for output in a properties file. - * See store for a description of the format. - * @param key the key. - * @param value the value. - * @see #store + * Writes the key/value pairs to the given print stream. They are + * written in the way described in the method store. This does not visit + * the keys in the default properties. + * + * @param out the stream, where the key/value pairs are written to + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #store(OutputStream, String) */ - private String formatForOutput(String key, String value) + public void list(PrintStream out) { - // This is a simple approximation of the expected line size. - StringBuffer result = - new StringBuffer(key.length() + value.length() + 16); - boolean head = true; - for (int i = 0; i < key.length(); i++) + Iterator iter = entrySet().iterator(); + int i = size(); + StringBuffer s = new StringBuffer(); // Reuse the same buffer. + while (--i >= 0) { - char c = key.charAt(i); - switch (c) - { - case '\n': - result.append("\\n"); - break; - case '\r': - result.append("\\r"); - break; - case '\t': - result.append("\\t"); - break; - case '\\': - result.append("\\\\"); - break; - case '!': - result.append("\\!"); - break; - case '#': - result.append("\\#"); - break; - case '=': - result.append("\\="); - break; - case ':': - result.append("\\:"); - break; - case ' ': - result.append("\\ "); - 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; + Map.Entry entry = (Map.Entry) iter.next(); + formatForOutput((String) entry.getKey(), s, true); + s.append('='); + formatForOutput((String) entry.getValue(), s, false); + out.println(s); } - 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"); - break; - case '\\': - result.append("\\\\"); - break; - case '!': - result.append("\\!"); - break; - case '#': - result.append("\\#"); - break; - case ' ': - result.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; - } - return result.toString(); } /** - * Writes the key/value pairs to the given print stream. They are + * Writes the key/value pairs to the given print writer. They are * written in the way, described in the method store. - * @param out the stream, where the key/value pairs are written to. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. - * @see #store + * + * @param out the writer, where the key/value pairs are written to + * @throws ClassCastException if this property contains any key or + * value that isn't a string + * @see #store(OutputStream, String) + * @see #list(PrintStream) + * @since 1.1 */ - public void list(PrintStream out) + public void list(PrintWriter out) { - Enumeration keys = keys(); - Enumeration elts = elements(); - while (keys.hasMoreElements()) + Iterator iter = entrySet().iterator(); + int i = size(); + StringBuffer s = new StringBuffer(); // Reuse the same buffer. + while (--i >= 0) { - String key = (String) keys.nextElement(); - String elt = (String) elts.nextElement(); - String output = formatForOutput(key, elt); - out.println(output); + Map.Entry entry = (Map.Entry) iter.next(); + formatForOutput((String) entry.getKey(), s, true); + s.append('='); + formatForOutput((String) entry.getValue(), s, false); + out.println(s); } } /** - * Writes the key/value pairs to the given print writer. They are - * written in the way, described in the method store. - * @param out the writer, where the key/value pairs are written to. - * @exception ClassCastException if this property contains any key or - * value that isn't a string. - * @see #store - * @see #list(java.io.PrintStream) - * @since JDK1.1 + * Formats a key or value for output in a properties file. + * See store for a description of the format. + * + * @param str the string to format + * @param buffer the buffer to add it to + * @param key true if all ' ' must be escaped for the key, false if only + * leading spaces must be escaped for the value + * @see #store(OutputStream, String) */ - public void list(PrintWriter out) + private void formatForOutput(String str, StringBuffer buffer, boolean key) { - Enumeration keys = keys(); - Enumeration elts = elements(); - while (keys.hasMoreElements()) + if (key) + { + buffer.setLength(0); + buffer.ensureCapacity(str.length()); + } + else + buffer.ensureCapacity(buffer.length() + str.length()); + boolean head = true; + int size = str.length(); + for (int i = 0; i < size; i++) { - String key = (String) keys.nextElement(); - String elt = (String) elts.nextElement(); - String output = formatForOutput(key, elt); - out.println(output); + char c = str.charAt(i); + switch (c) + { + case '\n': + buffer.append("\\n"); + break; + case '\r': + buffer.append("\\r"); + break; + case '\t': + buffer.append("\\t"); + break; + case ' ': + buffer.append(head ? "\\ " : " "); + break; + case '\\': + case '!': + case '#': + case '=': + case ':': + buffer.append('\\').append(c); + default: + if (c < ' ' || c > '~') + { + String hex = Integer.toHexString(c); + buffer.append("\\u0000".substring(0, 6 - hex.length())); + buffer.append(hex); + } + else + buffer.append(c); + } + if (c != ' ') + head = key; } } -} +} // class Properties diff --git a/libjava/java/util/PropertyPermission.java b/libjava/java/util/PropertyPermission.java index ec9673f..bb03e45 100644 --- a/libjava/java/util/PropertyPermission.java +++ b/libjava/java/util/PropertyPermission.java @@ -1,5 +1,5 @@ -/* java.util.PropertyPermission - Copyright (C) 1999, 2000 Free Software Foundation, Inc. +/* PropertyPermission.java -- permission to get and set System properties + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,7 @@ exception statement from your version. */ package java.util; + import java.security.Permission; import java.security.BasicPermission; import java.security.PermissionCollection; @@ -49,79 +50,127 @@ import java.io.IOException; * This class represents the permission to access and modify a property.<br> * * The name is the name of the property, e.g. xxx. You can also - * use an asterisk "*" as described in BasicPermission <br> + * use an asterisk "*" as described in BasicPermission.<br> * - * The action string is a comma-separated list if keywords. There are + * The action string is a comma-separated list of keywords. There are * two possible actions: * <dl> - * <dt>read</dt> + * <dt>read</dt> * <dd>Allows to read the property via <code>System.getProperty</code>.</dd> - * <dt>write</dt> + * <dt>write</dt> * <dd>Allows to write the property via <code>System.setProperty</code>.</dd> * </dl> - * + * * The action string is case insensitive (it is converted to lower case). * * @see Permission * @see BasicPermission - * @author Jochen Hoenicke + * @see SecurityManager + * @author Jochen Hoenicke + * @since 1.2 + * @status updated to 1.4 */ public final class PropertyPermission extends BasicPermission { /** - * @serialField action String - * The action string. + * PropertyPermission uses a more efficient representation than the + * serialized form; this documents the difference. + * + * @serialField action String the action string */ private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("action", String.class) }; + /** + * Compatible with JDK 1.2+. + */ private static final long serialVersionUID = 885438825399942851L; + /** Permission to read. */ private static final int READ = 1; + /** Permission to write. */ private static final int WRITE = 2; - private transient int actions; + /** The set of actions permitted. */ + // Package visible for use by PropertyPermissionCollection. + transient int actions; + + /** + * The String forms of the actions permitted. + */ private static final String actionStrings[] = { "", "read", "write", "read,write" }; /** - * Constructs a PropertyPermission witha he specified property. Possible - * actions are read and write. - * @param name the name of the property. - * @param actions the action string. - * @exception IllegalArgumentException if name string contains an - * illegal wildcard or actions string contains an illegal action + * Constructs a PropertyPermission with the specified property. Possible + * actions are read and write, comma-separated and case-insensitive. + * + * @param name the name of the property + * @param actions the action string + * @throws NullPointerException if name is null + * @throws IllegalArgumentException if name string contains an + * illegal wildcard or actions string contains an illegal action + * (this includes a null actions string) */ public PropertyPermission(String name, String actions) { super(name); + if (actions == null) + throw new IllegalArgumentException(); setActions(actions.toLowerCase()); } /** * Parse the action string and convert actions from external to internal * form. This will set the internal actions field. - * @param actions the action string. - * @exception IllegalArgumentException if actions string contains an - * illegal action */ - private void setActions(String actions) + * + * @param str the action string + * @throws IllegalArgumentException if actions string contains an + * illegal action + */ + private void setActions(String str) { - this.actions = 0; - StringTokenizer actionTokenizer = new StringTokenizer(actions, ","); - while (actionTokenizer.hasMoreElements()) - { - String anAction = actionTokenizer.nextToken(); - if ("read".equals(anAction)) - this.actions |= READ; - else if ("write".equals(anAction)) - this.actions |= WRITE; - else - throw new IllegalArgumentException("illegal action " + anAction); - } + if ("read".equals(str)) + actions = READ; + else if ("write".equals(str)) + actions = WRITE; + else if ("read,write".equals(str) || "write,read".equals(str)) + actions = READ | WRITE; + else + throw new IllegalArgumentException("illegal action " + str); + } + + /** + * Reads an object from the stream. This converts the external to the + * internal representation. + * + * @param s the stream to read from + * @throws IOException if the stream fails + * @throws ClassNotFoundException if reserialization fails + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + ObjectInputStream.GetField fields = s.readFields(); + setActions((String) fields.get("actions", null)); + } + + /** + * Writes an object to the stream. This converts the internal to the + * external representation. + * + * @param s the stram to write to + * @throws IOException if the stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("actions", getActions()); + s.writeFields(); } /** @@ -129,134 +178,70 @@ public final class PropertyPermission extends BasicPermission * the following conditions are true: * <ul> * <li> p is a PropertyPermission </li> - * <li> this.getName() implies p.getName(), + * <li> this.getName() implies p.getName(), * e.g. <code>java.*</code> implies <code>java.home</code> </li> * <li> this.getActions is a subset of p.getActions </li> * </ul> + * + * @param p the permission to check + * @return true if this permission implies p */ public boolean implies(Permission p) { - if (!(p instanceof PropertyPermission)) - return false; - - // We have to check the actions. - PropertyPermission pp = (PropertyPermission) p; - if ((pp.actions & ~actions) != 0) - return false; - - // BasicPermission checks for name. - if (!super.implies(p)) - return false; - - return true; - } - - /** - * Returns the action string. Note that this may differ from the string - * given at the constructor: The actions are converted to lowercase and - * may be reordered. - */ - public String getActions() - { - return actionStrings[actions]; + // BasicPermission checks for name and type. + if (super.implies(p)) + { + // We have to check the actions. + PropertyPermission pp = (PropertyPermission) p; + return (pp.actions & ~actions) == 0; + } + return false; } /** * Check to see whether this object is the same as another - * PropertyPermission object. + * PropertyPermission object; this is true if it has the same name and + * actions. * - * @param obj The other object + * @param obj the other object + * @return true if the two are equivalent */ - public boolean equals (Object obj) + public boolean equals(Object obj) { - if (! (obj instanceof PropertyPermission)) - return false; - PropertyPermission p = (PropertyPermission) obj; - return actions == p.actions && super.equals (p); + return super.equals(obj) && actions == ((PropertyPermission) obj).actions; } /** - * Reads an object from the stream. This converts the external to the - * internal representation. + * Returns the hash code for this permission. It is equivalent to + * <code>getName().hashCode()</code>. + * + * @return the hash code */ - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException + public int hashCode() { - ObjectInputStream.GetField fields = s.readFields(); - setActions((String) fields.get("actions", null)); + return super.hashCode(); } /** - * Writes an object to the stream. This converts the internal to the - * external representation. + * Returns the action string. Note that this may differ from the string + * given at the constructor: The actions are converted to lowercase and + * may be reordered. + * + * @return one of "read", "write", or "read,write" */ - private void writeObject(ObjectOutputStream s) throws IOException + public String getActions() { - ObjectOutputStream.PutField fields = s.putFields(); - fields.put("actions", getActions()); - s.writeFields(); + return actionStrings[actions]; } /** * Returns a permission collection suitable to take * PropertyPermission objects. - * @return a new empty PermissionCollection. + * + * @return a new empty PermissionCollection */ public PermissionCollection newPermissionCollection() { - return new PermissionCollection() - { - Hashtable permissions = new Hashtable(); - int allActions = 0; - - public void add(Permission permission) - { - if (isReadOnly()) - throw new IllegalStateException("readonly"); - - // also check that permission is of correct type. - PropertyPermission pp = (PropertyPermission) permission; - String name = pp.getName(); - if (name.equals("*")) - allActions |= pp.actions; - permissions.put(name, pp); - } - - public boolean implies(Permission permission) - { - if (!(permission instanceof PropertyPermission)) - return false; - - PropertyPermission toImply = (PropertyPermission) permission; - if ((toImply.actions & ~allActions) == 0) - return true; - - String name = toImply.getName(); - if (name.equals("*")) - return false; - - int prefixLength = name.length(); - if (name.endsWith("*")) - prefixLength -= 2; - - while (true) - { - PropertyPermission forName = - (PropertyPermission) permissions.get(name); - if (forName != null && (toImply.actions & ~forName.actions) == 0) - return true; - - prefixLength = name.lastIndexOf('.', prefixLength); - if (prefixLength < 0) - return false; - name = name.substring(0, prefixLength + 1) + '*'; - } - } - - public Enumeration elements() - { - return permissions.elements(); - } - }; + return new PropertyPermissionCollection(); } } diff --git a/libjava/java/util/PropertyPermissionCollection.java b/libjava/java/util/PropertyPermissionCollection.java new file mode 100644 index 0000000..8f9c71d --- /dev/null +++ b/libjava/java/util/PropertyPermissionCollection.java @@ -0,0 +1,164 @@ +/* PropertyPermissionCollection.java -- a collection of PropertyPermissions + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import java.security.Permission; +import java.security.PermissionCollection; + +/** + * This class provides the implementation for + * <code>PropertyPermission.newPermissionCollection()</code>. It only accepts + * PropertyPermissions, and correctly implements <code>implies</code>. It + * is synchronized, as specified in the superclass. + * + * @author Eric Blake <ebb9@email.byu.edu> + * @status an undocumented class, but this matches Sun's serialization + */ +class PropertyPermissionCollection extends PermissionCollection +{ + /** + * Compatible with JDK 1.4. + */ + private static final long serialVersionUID = 7015263904581634791L; + + /** + * The permissions. + * + * @serial the table of permissions in the collection + */ + private final Hashtable permissions = new Hashtable(); + + /** + * A flag to detect if "*" is in the collection. + * + * @serial true if "*" is in the collection + */ + private boolean all_allowed; + + /** + * Adds a PropertyPermission to this collection. + * + * @param permission the permission to add + * @throws IllegalArgumentException if permission is not a PropertyPermission + * @throws SecurityException if collection is read-only + */ + public void add(Permission permission) + { + if (isReadOnly()) + throw new SecurityException("readonly"); + if (! (permission instanceof PropertyPermission)) + throw new IllegalArgumentException(); + PropertyPermission pp = (PropertyPermission) permission; + String name = pp.getName(); + if (name.equals("*")) + all_allowed = true; + PropertyPermission old = (PropertyPermission) permissions.get(name); + if (old != null) + { + if ((pp.actions | old.actions) == old.actions) + pp = old; // Old implies pp. + else if ((pp.actions | old.actions) != pp.actions) + // Here pp doesn't imply old; the only case left is both actions. + pp = new PropertyPermission(name, "read,write"); + } + permissions.put(name, pp); + } + + /** + * Returns true if this collection implies the given permission. This even + * returns true for this case: + * <p> +<pre>collection.add(new PropertyPermission("a.*", "read")); +collection.add(new PropertyPermission("a.b.*", "write")); +collection.implies(new PropertyPermission("a.b.c", "read,write"));</pre> + * + * @param permission the permission to check + * @return true if it is implied by this + */ + public boolean implies(Permission permission) + { + if (! (permission instanceof PropertyPermission)) + return false; + PropertyPermission toImply = (PropertyPermission) permission; + int actions = toImply.actions; + + if (all_allowed) + { + int all_actions = ((PropertyPermission) permissions.get("*")).actions; + actions &= ~all_actions; + if (actions == 0) + return true; + } + + String name = toImply.getName(); + if (name.equals("*")) + return false; + + int prefixLength = name.length(); + if (name.endsWith("*")) + prefixLength -= 2; + + while (true) + { + PropertyPermission forName = + (PropertyPermission) permissions.get(name); + if (forName != null) + { + actions &= ~forName.actions; + if (actions == 0) + return true; + } + + prefixLength = name.lastIndexOf('.', prefixLength); + if (prefixLength < 0) + return false; + name = name.substring(0, prefixLength + 1) + '*'; + } + } + + /** + * Enumerate over the collection. + * + * @return an enumeration of the collection contents + */ + public Enumeration elements() + { + return permissions.elements(); + } +} diff --git a/libjava/java/util/PropertyResourceBundle.java b/libjava/java/util/PropertyResourceBundle.java index 55fb413..a3173cf 100644 --- a/libjava/java/util/PropertyResourceBundle.java +++ b/libjava/java/util/PropertyResourceBundle.java @@ -1,5 +1,5 @@ -/* java.util.PropertyResourceBundle - Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. +/* PropertyResourceBundle -- a resource bundle built from a Property file + Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,11 +38,13 @@ exception statement from your version. */ package java.util; +import java.io.IOException; +import java.io.InputStream; import gnu.java.util.DoubleEnumeration; /** * This class is a concrete <code>ResourceBundle</code> that gets it - * resources from a property file. This implies that the resources are + * resources from a property file. This implies that the resources are * strings. For more information about resource bundles see the class * <code>ResourceBundle</code>. * @@ -52,75 +54,68 @@ import gnu.java.util.DoubleEnumeration; * file. * * If there is also a class for this resource and the same locale, the - * class does win. - * - * The properties file should have the name of the resource bundle, - * appended with the locale (e.g. <code>_de</code) and the extension - * <code>.properties</code>. The file should have the same format + * class will be chosen. The properties file should have the name of the + * resource bundle, appended with the locale (e.g. <code>_de</code) and the + * extension <code>.properties</code>. The file should have the same format * as for <code>Properties.load()</code> * - * XXX- move this to properties. - * The file should have the following - * format: An empty line or a line starting with <code>#</code> is - * ignored. An backslash (<code>\</code>) at the end of the line - * makes the line continueing on the next line. Otherwise, each line - * describes a key/value pair. The chars up to the first whitespace, - * = or : are the key. The key is followed by one or more - * whitespaces, <code>=</code> or <code>:</code>. The rest of the - * line is the resource belonging to the key. You can give unicode - * characters with the <code>\\uxxxx</code> notation, where - * <code>xxxx</code> is the hex encoding of the 16 bit unicode char - * number. - * * An example of a properties file for the german language is given - * here. This extends the example given in ListResourceBundle. + * here. This extends the example given in ListResourceBundle. * Create a file MyResource_de.properties with the following contents - * and put it in the CLASSPATH. (The char <code>\u00e4<char> is the + * and put it in the CLASSPATH. (The char <code>\u00e4<char> is the * german ä) - * - * <pre> - * s1=3 - * s2=MeineDisk - * s3=3. M\u00e4rz 96 - * s4=Die Diskette ''{1}'' enth\u00e4lt {0} in {2}. - * s5=0 - * s6=keine Dateien - * s7=1 - * s8=eine Datei - * s9=2 - * s10={0,number} Dateien - * s11=Die Formatierung warf eine Exception: {0} - * s12=FEHLER - * s13=Ergebnis - * s14=Dialog - * s15=Auswahlkriterium - * s16=1,3 - * </pre> * + * +<pre> +s1=3 +s2=MeineDisk +s3=3. M\u00e4rz 96 +s4=Die Diskette ''{1}'' enth\u00e4lt {0} in {2}. +s5=0 +s6=keine Dateien +s7=1 +s8=eine Datei +s9=2 +s10={0,number} Dateien +s11=Die Formatierung warf eine Exception: {0} +s12=FEHLER +s13=Ergebnis +s14=Dialog +s15=Auswahlkriterium +s16=1,3 +</pre> + * + * @author Jochen Hoenicke * @see ResourceBundle * @see ListResourceBundle * @see Properties#load() - * @author Jochen Hoenicke */ + * @since 1.1 + * @status updated to 1.4 + */ public class PropertyResourceBundle extends ResourceBundle { - Properties properties; + /** The properties file this bundle is based on. */ + private Properties properties; /** * Creates a new property resource bundle. - * @param stream An input stream, where the resources are read from. + * + * @param stream an input stream, where the resources are read from + * @throws NullPointerException if stream is null + * @throws IOException if reading the stream fails */ - public PropertyResourceBundle(java.io.InputStream stream) - throws java.io.IOException + public PropertyResourceBundle(InputStream stream) throws IOException { properties = new Properties(); properties.load(stream); } /** - * Called by <code>getObject</code> when a resource is needed. This + * Called by <code>getObject</code> when a resource is needed. This * returns the resource given by the key. - * @param key The key of the resource. - * @return The resource for the key or null if it doesn't exists. + * + * @param key the key of the resource + * @return the resource for the key, or null if it doesn't exist */ public Object handleGetObject(String key) { @@ -129,16 +124,30 @@ public class PropertyResourceBundle extends ResourceBundle /** * This method should return all keys for which a resource exists. - * @return An enumeration of the keys. + * + * @return an enumeration of the keys */ public Enumeration getKeys() { - // We must also return the keys of our parent. - if (parent != null) + if (parent == null) + return properties.propertyNames(); + // We make a new Set that holds all the keys, then return an enumeration + // for that. This prevents modifications from ruining the enumeration, + // as well as ignoring duplicates. + Set s = new HashSet(); + Enumeration e = properties.propertyNames(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + ResourceBundle bundle = parent; + // Eliminate tail recursion. + do { - return new DoubleEnumeration(properties.propertyNames(), - parent.getKeys()); + e = bundle.getKeys(); + while (e.hasMoreElements()) + s.add(e.nextElement()); + bundle = bundle.parent; } - return properties.propertyNames(); + while (bundle != null); + return Collections.enumeration(s); } -} +} // class PropertyResourceBundle diff --git a/libjava/java/util/Random.java b/libjava/java/util/Random.java index 1365acd..500a02d 100644 --- a/libjava/java/util/Random.java +++ b/libjava/java/util/Random.java @@ -1,5 +1,5 @@ -/* java.util.Random - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +/* Random.java -- a pseudo-random number generator + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,13 +38,16 @@ exception statement from your version. */ package java.util; +import java.io.Serializable; + /** * This class generates pseudorandom numbers. It uses the same * algorithm as the original JDK-class, so that your programs behave * exactly the same way, if started with the same seed. * * The algorithm is described in <em>The Art of Computer Programming, - * Volume 2</em> by Donald Knuth in Section 3.2.1. + * Volume 2</em> by Donald Knuth in Section 3.2.1. It is a 48-bit seed, + * linear congruential formula. * * If two instances of this class are created with the same seed and * the same calls to these classes are made, they behave exactly the @@ -57,7 +60,7 @@ package java.util; * <code>setSeed(long)</code> method. In that case the above * paragraph doesn't apply to you. * - * This class shouldn't be used for security sensitive purposes (like + * This class shouldn't be used for security sensitive purposes (like * generating passwords or encryption keys. See <code>SecureRandom</code> * in package <code>java.security</code> for this purpose. * @@ -66,51 +69,65 @@ package java.util; * * @see java.security.SecureRandom * @see Math#random() - * @author Jochen Hoenicke */ -public class Random implements java.io.Serializable + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class Random implements Serializable { /** * True if the next nextGaussian is available. This is used by * nextGaussian, which generates two gaussian numbers by one call, - * and returns the second on the second call. - * @see #nextGaussian. */ + * and returns the second on the second call. + * + * @serial whether nextNextGaussian is available + * @see #nextGaussian() + * @see #nextNextGaussian + */ private boolean haveNextNextGaussian; + /** - * The next nextGaussian if available. This is used by nextGaussian, + * The next nextGaussian, when available. This is used by nextGaussian, * which generates two gaussian numbers by one call, and returns the * second on the second call. - * @see #nextGaussian. + * + * @serial the second gaussian of a pair + * @see #nextGaussian() + * @see #haveNextNextGaussian */ private double nextNextGaussian; + /** * The seed. This is the number set by setSeed and which is used * in next. - * @see #next + * + * @serial the internal state of this generator + * @see #next() */ private long seed; + /** + * Compatible with JDK 1.0+. + */ private static final long serialVersionUID = 3905348978240129619L; /** * Creates a new pseudorandom number generator. The seed is initialized - * to the current time as follows. - * <pre> - * setSeed(System.currentTimeMillis()); - * </pre> + * to the current time, as if by + * <code>setSeed(System.currentTimeMillis());</code>. + * * @see System#currentTimeMillis() */ public Random() { - setSeed(System.currentTimeMillis()); + this(System.currentTimeMillis()); } /** * Creates a new pseudorandom number generator, starting with the - * specified seed. This does: - * <pre> - * setSeed(seed); - * </pre> - * @param seed the initial seed. + * specified seed, using <code>setSeed(seed);</code>. + * + * @param seed the initial seed */ public Random(long seed) { @@ -122,12 +139,14 @@ public class Random implements java.io.Serializable * above, two instances of the same random class, starting with the * same seed, should produce the same results, if the same methods * are called. The implementation for java.util.Random is: - * <pre> - * public synchronized void setSeed(long seed) { - * this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); - * haveNextNextGaussian = false; - * } - * </pre> + * +<pre>public synchronized void setSeed(long seed) +{ + this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1); + haveNextNextGaussian = false; +}</pre> + * + * @param seed the new seed */ public synchronized void setSeed(long seed) { @@ -140,20 +159,18 @@ public class Random implements java.io.Serializable * an int value whose <code>bits</code> low order bits are * independent chosen random bits (0 and 1 are equally likely). * The implementation for java.util.Random is: - * <pre> - * protected synchronized int next(int bits) { - * seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); - * return (int) (seed >>> (48 - bits)); - * } - * </pre> - * @param bits the number of random bits to generate. Must be in range - * 1..32. - * @return the next pseudorandom value. - * @since JDK1.1 + * +<pre>protected synchronized int next(int bits) +{ + seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); + return (int) (seed >>> (48 - bits)); +}</pre> + * + * @param bits the number of random bits to generate, in the range 1..32 + * @return the next pseudorandom value + * @since 1.1 */ protected synchronized int next(int bits) - /*{ require { 1 <= bits && bits <=32 :: - "bits "+bits+" not in range [1..32]" } } */ { seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); return (int) (seed >>> (48 - bits)); @@ -163,42 +180,45 @@ public class Random implements java.io.Serializable * Fills an array of bytes with random numbers. All possible values * are (approximately) equally likely. * The JDK documentation gives no implementation, but it seems to be: - * <pre> - * public void nextBytes(byte[] bytes) { - * for (int i=0; i< bytes.length; i+=4) { - * int random = next(32); - * for (int j=0; i+j< bytes.length && j<4; j++) - * bytes[i+j] = (byte) (random & 0xff) - * random >>= 8; - * } - * } - * } - * </pre> - * @param bytes The byte array that should be filled. - * @since JDK1.1 + * +<pre>public void nextBytes(byte[] bytes) +{ + for (int i = 0; i < bytes.length; i += 4) + { + int random = next(32); + for (int j = 0; i + j < bytes.length && j < 4; j++) + { + bytes[i+j] = (byte) (random & 0xff) + random >>= 8; + } + } +}</pre> + * + * @param bytes the byte array that should be filled + * @throws NullPointerException if bytes is null + * @since 1.1 */ public void nextBytes(byte[] bytes) - /*{ require { bytes != null :: "bytes is null"; } } */ { int random; - /* Do a little bit unrolling of the above algorithm. */ + // Do a little bit unrolling of the above algorithm. int max = bytes.length & ~0x3; for (int i = 0; i < max; i += 4) { - random = next(32); - bytes[i] = (byte) random; - bytes[i + 1] = (byte) (random >> 8); - bytes[i + 2] = (byte) (random >> 16); - bytes[i + 3] = (byte) (random >> 24); + random = next(32); + bytes[i] = (byte) random; + bytes[i + 1] = (byte) (random >> 8); + bytes[i + 2] = (byte) (random >> 16); + bytes[i + 3] = (byte) (random >> 24); } if (max < bytes.length) { - random = next(32); - for (int j = max; j < bytes.length; j++) - { - bytes[j] = (byte) random; - random >>= 8; - } + random = next(32); + for (int j = max; j < bytes.length; j++) + { + bytes[j] = (byte) random; + random >>= 8; + } } } @@ -207,13 +227,14 @@ public class Random implements java.io.Serializable * an int value whose 32 bits are independent chosen random bits * (0 and 1 are equally likely). The implementation for * java.util.Random is: - * <pre> - * public int nextInt() { - * return next(32); - * } - * </pre> + * +<pre>public int nextInt() +{ + return next(32); +}</pre> * - * @return the next pseudorandom value. */ + * @return the next pseudorandom value + */ public int nextInt() { return next(32); @@ -225,51 +246,58 @@ public class Random implements java.io.Serializable * each value has the same likelihodd (1/<code>n</code>). * (0 and 1 are equally likely). The implementation for * java.util.Random is: - * <pre> - * public int nextInt(int n) { - * if (n<=0) - * throw new IllegalArgumentException("n must be positive"); - * if ((n & -n) == n) // i.e., n is a power of 2 - * return (int)((n * (long)next(31)) >> 31); - * int bits, val; - * do { - * bits = next(32); - * val = bits % n; - * } while(bits - val + (n-1) < 0); - * return val; - * } - * </pre> - * This algorithm would return every value with exactly the same + * +<pre> +public int nextInt(int n) +{ + if (n <= 0) + throw new IllegalArgumentException("n must be positive"); + + if ((n & -n) == n) // i.e., n is a power of 2 + return (int)((n * (long) next(31)) >> 31); + + int bits, val; + do + { + bits = next(32); + val = bits % n; + } + while(bits - val + (n-1) < 0); + + return val; +}</pre> + * + * <p>This algorithm would return every value with exactly the same * probability, if the next()-method would be a perfect random number * generator. - * + * * The loop at the bottom only accepts a value, if the random * number was between 0 and the highest number less then 1<<31, * which is divisible by n. The probability for this is high for small * n, and the worst case is 1/2 (for n=(1<<30)+1). * - * The special treatment for n = power of 2, selects the high bits of + * The special treatment for n = power of 2, selects the high bits of * the random number (the loop at the bottom would select the low order * bits). This is done, because the low order bits of linear congruential - * number generators (like the one used in this class) are known to be + * number generators (like the one used in this class) are known to be * ``less random'' than the high order bits. * - * @param n the upper bound. - * @exception IllegalArgumentException if the given upper bound is negative - * @return the next pseudorandom value. + * @param n the upper bound + * @throws IllegalArgumentException if the given upper bound is negative + * @return the next pseudorandom value + * @since 1.2 */ public int nextInt(int n) - /*{ require { n > 0 :: "n must be positive"; } } */ { if (n <= 0) throw new IllegalArgumentException("n must be positive"); - if ((n & -n) == n) // i.e., n is a power of 2 + if ((n & -n) == n) // i.e., n is a power of 2 return (int) ((n * (long) next(31)) >> 31); int bits, val; do { - bits = next(32); - val = bits % n; + bits = next(32); + val = bits % n; } while (bits - val + (n - 1) < 0); return val; @@ -279,12 +307,13 @@ public class Random implements java.io.Serializable * Generates the next pseudorandom long number. All bits of this * long are independently chosen and 0 and 1 have equal likelihood. * The implementation for java.util.Random is: - * <pre> - * public long nextLong() { - * return ((long)next(32) << 32) + next(32); - * } - * </pre> - * @return the next pseudorandom value. + * +<pre>public long nextLong() +{ + return ((long) next(32) << 32) + next(32); +}</pre> + * + * @return the next pseudorandom value */ public long nextLong() { @@ -294,12 +323,14 @@ public class Random implements java.io.Serializable /** * Generates the next pseudorandom boolean. True and false have * the same probability. The implementation is: - * <pre> - * public boolean nextBoolean() { - * return next(1) != 0; - * } - * </pre> - * @return the next pseudorandom boolean. + * +<pre>public boolean nextBoolean() +{ + return next(1) != 0; +}</pre> + * + * @return the next pseudorandom boolean + * @since 1.2 */ public boolean nextBoolean() { @@ -308,83 +339,91 @@ public class Random implements java.io.Serializable /** * Generates the next pseudorandom float uniformly distributed - * between 0.0f (inclusive) and 1.0 (exclusive). The + * between 0.0f (inclusive) and 1.0f (exclusive). The * implementation is as follows. - * <pre> - * public float nextFloat() { - * return next(24) / ((float)(1 << 24)); - * } - * </pre> - * @return the next pseudorandom float. */ + * +<pre>public float nextFloat() +{ + return next(24) / ((float)(1 << 24)); +}</pre> + * + * @return the next pseudorandom float + */ public float nextFloat() { - return next(24) / ((float) (1 << 24)); + return next(24) / (float) (1 << 24); } /** * Generates the next pseudorandom double uniformly distributed - * between 0.0f (inclusive) and 1.0 (exclusive). The + * between 0.0 (inclusive) and 1.0 (exclusive). The * implementation is as follows. - * <pre> - * public double nextDouble() { - * return (((long)next(26) << 27) + next(27)) / (double)(1 << 53); - * } - * </pre> - * @return the next pseudorandom double. */ + * +<pre>public double nextDouble() +{ + return (((long) next(26) << 27) + next(27)) / (double)(1L << 53); +}</pre> + * + * @return the next pseudorandom double + */ public double nextDouble() { return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); } /** - * Generates the next pseudorandom, Gaussian (normally) distributed + * Generates the next pseudorandom, Gaussian (normally) distributed * double value, with mean 0.0 and standard deviation 1.0. * The algorithm is as follows. - * <pre> - * public synchronized double nextGaussian() { - * if (haveNextNextGaussian) { - * haveNextNextGaussian = false; - * return nextNextGaussian; - * } else { - * double v1, v2, s; - * do { - * v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0 - * v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0 - * s = v1 * v1 + v2 * v2; - * } while (s >= 1); - * double norm = Math.sqrt(-2 * Math.log(s)/s); - * nextNextGaussian = v2 * norm; - * haveNextNextGaussian = true; - * return v1 * norm; - * } - * } - * </pre> - * This is described in section 3.4.1 of <em>The Art of Computer + * +<pre>public synchronized double nextGaussian() +{ + if (haveNextNextGaussian) + { + haveNextNextGaussian = false; + return nextNextGaussian; + } + else + { + double v1, v2, s; + do + { + v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0 + v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0 + s = v1 * v1 + v2 * v2; + } + while (s >= 1); + + double norm = Math.sqrt(-2 * Math.log(s) / s); + nextNextGaussian = v2 * norm; + haveNextNextGaussian = true; + return v1 * norm; + } +}</pre> + * + * <p>This is described in section 3.4.1 of <em>The Art of Computer * Programming, Volume 2</em> by Donald Knuth. * - * @return the next pseudorandom Gaussian distributed double. + * @return the next pseudorandom Gaussian distributed double */ public synchronized double nextGaussian() { if (haveNextNextGaussian) { - haveNextNextGaussian = false; - return nextNextGaussian; + haveNextNextGaussian = false; + return nextNextGaussian; } - else + double v1, v2, s; + do { - double v1, v2, s; - do - { - v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0 - v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0 - s = v1 * v1 + v2 * v2; - } - while (s >= 1); - double norm = Math.sqrt(-2 * Math.log(s) / s); - nextNextGaussian = v2 * norm; - haveNextNextGaussian = true; - return v1 * norm; + v1 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + v2 = 2 * nextDouble() - 1; // Between -1.0 and 1.0. + s = v1 * v1 + v2 * v2; } + while (s >= 1); + double norm = Math.sqrt(-2 * Math.log(s) / s); + nextNextGaussian = v2 * norm; + haveNextNextGaussian = true; + return v1 * norm; } } diff --git a/libjava/java/util/SimpleTimeZone.java b/libjava/java/util/SimpleTimeZone.java index 91d2d08..c2e2560 100644 --- a/libjava/java/util/SimpleTimeZone.java +++ b/libjava/java/util/SimpleTimeZone.java @@ -52,7 +52,8 @@ import java.text.DateFormatSymbols; * * @see Calendar * @see GregorianCalender - * @author Jochen Hoenicke */ + * @author Jochen Hoenicke + */ public class SimpleTimeZone extends TimeZone { /** @@ -436,9 +437,9 @@ public class SimpleTimeZone extends TimeZone * In the standard JDK the results given by this method may result in * inaccurate results at the end of February or the beginning of March. * To avoid this, you should use Calendar instead: - * <pre> - * offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); - * </pre> + * <code>offset = cal.get(Calendar.ZONE_OFFSET) + * + cal.get(Calendar.DST_OFFSET);</code> + * * You could also use in * * This version doesn't suffer this inaccuracy. diff --git a/libjava/java/util/StringTokenizer.java b/libjava/java/util/StringTokenizer.java index 707ddd4..e7fc6fd 100644 --- a/libjava/java/util/StringTokenizer.java +++ b/libjava/java/util/StringTokenizer.java @@ -1,5 +1,5 @@ -/* java.util.StringTokenizer - Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc. +/* StringTokenizer -- breaks a String into tokens + Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,75 +39,79 @@ exception statement from your version. */ package java.util; /** - * This class splits a string into tokens. The caller can set on which + * This class splits a string into tokens. The caller can set on which * delimiters the string should be split and if the delimiters should be - * returned. + * returned. This is much simpler than {@link java.io.StreamTokenizer}. * - * You may change the delimiter set on the fly by calling + * <p>You may change the delimiter set on the fly by calling * nextToken(String). But the semantic is quite difficult; it even * depends on calling <code>hasMoreTokens()</code>. You should call * <code>hasMoreTokens()</code> before, otherwise the old delimiters - * after the last token are returned. + * after the last token are candidates for being returned. * - * If you want to get the delimiters, you have to use the three argument + * <p>If you want to get the delimiters, you have to use the three argument * constructor. The delimiters are returned as token consisting of a - * single character. + * single character. * * @author Jochen Hoenicke * @author Warren Levy <warrenl@cygnus.com> + * @see java.io.StreamTokenizer + * @status updated to 1.4 */ public class StringTokenizer implements Enumeration { + // WARNING: StringTokenizer is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + /** * The position in the str, where we currently are. */ private int pos; + /** * The string that should be split into tokens. */ - private String str; + private final String str; + + /** + * The length of the string. + */ + private final int len; + /** * The string containing the delimiter characters. */ private String delim; + /** * Tells, if we should return the delimiters. */ - private boolean retDelims; - - /*{ - invariant { - pos >= 0 :: "position is negative"; - pos <= str.length() :: "position is out of string"; - str != null :: "String is null"; - delim != null :: "Delimiters are null"; - } - } */ + private final boolean retDelims; /** * Creates a new StringTokenizer for the string <code>str</code>, - * that should split on the default delimiter set (space, tap, + * that should split on the default delimiter set (space, tab, * newline, return and formfeed), and which doesn't return the * delimiters. - * @param str The string to split. + * + * @param str The string to split + * @throws NullPointerException if str is null */ public StringTokenizer(String str) - /*{ require { str != null :: "str must not be null"; } } */ { this(str, " \t\n\r\f", false); } /** - * Create a new StringTokenizer, that splits the given string on + * Create a new StringTokenizer, that splits the given string on * the given delimiter characters. It doesn't return the delimiter * characters. * - * @param str The string to split. - * @param delim A string containing all delimiter characters. + * @param str the string to split + * @param delim a string containing all delimiter characters + * @throws NullPointerException if either argument is null */ public StringTokenizer(String str, String delim) - /*{ require { str != null :: "str must not be null"; - delim != null :: "delim must not be null"; } } */ { this(str, delim, false); } @@ -119,34 +123,34 @@ public class StringTokenizer implements Enumeration * characters are returned as tokens of their own. The delimiter * tokens always consist of a single character. * - * @param str The string to split. - * @param delim A string containing all delimiter characters. - * @param returnDelims Tells, if you want to get the delimiters. + * @param str the string to split + * @param delim a string containing all delimiter characters + * @param returnDelims tells, if you want to get the delimiters + * @throws NullPointerException if str or delim is null */ public StringTokenizer(String str, String delim, boolean returnDelims) - /*{ require { str != null :: "str must not be null"; - delim != null :: "delim must not be null"; } } */ { + len = str.length(); this.str = str; - this.delim = delim; + // The toString() hack causes the NullPointerException. + this.delim = delim.toString(); this.retDelims = returnDelims; this.pos = 0; } /** * Tells if there are more tokens. - * @return True, if the next call of nextToken() succeeds, false otherwise. + * + * @return true if the next call of nextToken() will succeed */ public boolean hasMoreTokens() { - if (!retDelims) + if (! retDelims) { - while (pos < str.length() && delim.indexOf(str.charAt(pos)) > -1) - { - pos++; - } + while (pos < len && delim.indexOf(str.charAt(pos)) >= 0) + pos++; } - return pos < str.length(); + return pos < len; } /** @@ -154,13 +158,13 @@ public class StringTokenizer implements Enumeration * <code>delim</code>. The change of the delimiter set is * permanent, ie. the next call of nextToken(), uses the same * delimiter set. - * @param delim a string containing the new delimiter characters. - * @return the next token with respect to the new delimiter characters. - * @exception NoSuchElementException if there are no more tokens. + * + * @param delim a string containing the new delimiter characters + * @return the next token with respect to the new delimiter characters + * @throws NoSuchElementException if there are no more tokens + * @throws NullPointerException if delim is null */ public String nextToken(String delim) throws NoSuchElementException - /*{ require { hasMoreTokens() :: "no more Tokens available"; - ensure { $return != null && $return.length() > 0; } } */ { this.delim = delim; return nextToken(); @@ -168,32 +172,24 @@ public class StringTokenizer implements Enumeration /** * Returns the nextToken of the string. - * @param delim a string containing the new delimiter characters. - * @return the next token with respect to the new delimiter characters. - * @exception NoSuchElementException if there are no more tokens. + * + * @return the next token with respect to the current delimiter characters + * @throws NoSuchElementException if there are no more tokens */ public String nextToken() throws NoSuchElementException - /*{ require { hasMoreTokens() :: "no more Tokens available"; - ensure { $return != null && $return.length() > 0; } } */ { - if (pos < str.length() && delim.indexOf(str.charAt(pos)) > -1) + if (pos < len && delim.indexOf(str.charAt(pos)) >= 0) { - if (retDelims) - return str.substring(pos, ++pos); - - while (++pos < str.length() && delim.indexOf(str.charAt(pos)) > -1) - { - /* empty */ - } + if (retDelims) + return str.substring(pos, ++pos); + while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0); } - if (pos < str.length()) + if (pos < len) { - int start = pos; - while (++pos < str.length() && delim.indexOf(str.charAt(pos)) == -1) - { - /* empty */ - } - return str.substring(start, pos); + int start = pos; + while (++pos < len && delim.indexOf(str.charAt(pos)) < 0); + + return str.substring(start, pos); } throw new NoSuchElementException(); } @@ -201,9 +197,9 @@ public class StringTokenizer implements Enumeration /** * This does the same as hasMoreTokens. This is the * <code>Enumeration</code interface method. - * @return True, if the next call of nextElement() succeeds, false - * otherwise. - * @see #hasMoreTokens + * + * @return true, if the next call of nextElement() will succeed + * @see #hasMoreTokens() */ public boolean hasMoreElements() { @@ -213,9 +209,10 @@ public class StringTokenizer implements Enumeration /** * This does the same as nextTokens. This is the * <code>Enumeration</code interface method. - * @return the next token with respect to the new delimiter characters. - * @exception NoSuchElementException if there are no more tokens. - * @see #nextToken + * + * @return the next token with respect to the current delimiter characters + * @throws NoSuchElementException if there are no more tokens + * @see #nextToken() */ public Object nextElement() throws NoSuchElementException { @@ -225,49 +222,47 @@ public class StringTokenizer implements Enumeration /** * This counts the number of remaining tokens in the string, with * respect to the current delimiter set. - * @return the number of times <code>nextTokens()</code> will - * succeed. - * @see #nextToken + * + * @return the number of times <code>nextTokens()</code> will succeed + * @see #nextToken() */ public int countTokens() { int count = 0; int delimiterCount = 0; - boolean tokenFound = false; // Set when a non-delimiter is found + boolean tokenFound = false; // Set when a non-delimiter is found int tmpPos = pos; // Note for efficiency, we count up the delimiters rather than check // retDelims every time we encounter one. That way, we can // just do the conditional once at the end of the method - while (tmpPos < str.length()) + while (tmpPos < len) { - if (delim.indexOf(str.charAt(tmpPos++)) > -1) - { - if (tokenFound) - { - // Got to the end of a token - count++; - tokenFound = false; - } - - delimiterCount++; // Increment for this delimiter - } - else - { - tokenFound = true; - - // Get to the end of the token - while (tmpPos < str.length() - && delim.indexOf(str.charAt(tmpPos)) == -1) - ++tmpPos; - } + if (delim.indexOf(str.charAt(tmpPos++)) >= 0) + { + if (tokenFound) + { + // Got to the end of a token + count++; + tokenFound = false; + } + delimiterCount++; // Increment for this delimiter + } + else + { + tokenFound = true; + // Get to the end of the token + while (tmpPos < len + && delim.indexOf(str.charAt(tmpPos)) < 0) + ++tmpPos; + } } - // Make sure to count the last token + // Make sure to count the last token if (tokenFound) count++; // if counting delmiters add them into the token count return retDelims ? count + delimiterCount : count; } -} +} // class StringTokenizer diff --git a/libjava/java/util/TimerTask.java b/libjava/java/util/TimerTask.java index cb841e5..1b32b67 100644 --- a/libjava/java/util/TimerTask.java +++ b/libjava/java/util/TimerTask.java @@ -44,11 +44,11 @@ package java.util; * it should have been scheduled and cancel itself when no longer needed. * <p> * Example: - * <code> + * <pre> * Timer timer = new Timer(); * TimerTask task = new TimerTask() { * public void run() { - * if (this.scheduledExecutionTime() < System.currentTimeMillis() + 500) + * if (this.scheduledExecutionTime() < System.currentTimeMillis() + 500) * // Do something * else * // Complain: We are more then half a second late! @@ -56,7 +56,7 @@ package java.util; * this.cancel(); // This was our last execution * }; * timer.scheduleAtFixedRate(task, 1000, 1000); // schedule every second - * </code> + * </pre> * <p> * Note that a TimerTask object is a one shot object and can only given once * to a Timer. (The Timer will use the TimerTask object for bookkeeping, diff --git a/libjava/java/util/TreeMap.java b/libjava/java/util/TreeMap.java index 8799682..dfa9bc6 100644 --- a/libjava/java/util/TreeMap.java +++ b/libjava/java/util/TreeMap.java @@ -1,6 +1,6 @@ /* TreeMap.java -- a class providing a basic Red-Black Tree data structure, mapping Object --> Object - Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -162,7 +162,7 @@ public class TreeMap extends AbstractMap * * @author Eric Blake <ebb9@email.byu.edu> */ - private static final class Node extends BasicMapEntry + private static final class Node extends AbstractMap.BasicMapEntry { // All fields package visible for use by nested classes. /** The color of this node. */ @@ -623,8 +623,10 @@ public class TreeMap extends AbstractMap Node n = getNode(key); if (n == nil) return null; + // Note: removeNode can alter the contents of n, so save value now. + Object result = n.value; removeNode(n); - return n.value; + return result; } /** @@ -1768,7 +1770,7 @@ public class TreeMap extends AbstractMap SubMap.this.clear(); } }; - return this.keys; + return this.values; } } // class SubMap } // class TreeMap diff --git a/libjava/java/util/WeakHashMap.java b/libjava/java/util/WeakHashMap.java index 8c55ae0..3431ac9 100644 --- a/libjava/java/util/WeakHashMap.java +++ b/libjava/java/util/WeakHashMap.java @@ -1,4 +1,4 @@ -/* java.util.WeakHashMap -- a hashtable that keeps only weak references +/* WeakHashMap -- a hashtable that keeps only weak references to its keys, allowing the virtual machine to reclaim them Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. @@ -43,41 +43,41 @@ import java.lang.ref.WeakReference; import java.lang.ref.ReferenceQueue; /** - * A weak hash map has only weak references to the key. This means - * that it allows the key to be garbage collected if they are not used - * otherwise. If this happens, the weak hash map will eventually - * remove the whole entry from this map. <br> + * A weak hash map has only weak references to the key. This means that it + * allows the key to be garbage collected if it is not used otherwise. If + * this happens, the entry will eventually disappear from the map, + * asynchronously. * - * A weak hash map makes most sense, if the keys doesn't override the - * <code>equals</code>-method: If there is no other reference to the + * <p>A weak hash map makes most sense when the keys doesn't override the + * <code>equals</code> method: If there is no other reference to the * key nobody can ever look up the key in this table and so the entry - * can be removed. This table also works, if the <code>equals</code> - * method is overloaded, e.g. with Strings as keys, but you should be - * prepared that some entries disappear spontaneously. <br> + * can be removed. This table also works when the <code>equals</code> + * method is overloaded, such as String keys, but you should be prepared + * to deal with some entries disappearing spontaneously. * - * You should also be prepared that this hash map behaves very - * strange: The size of this map may spontaneously shrink (even if you - * use a synchronized map and synchronize it); it behaves as if - * another thread removes entries from this table without - * synchronizations. The entry set returned by <code>entrySet</code> + * <p>Other strange behaviors to be aware of: The size of this map may + * spontaneously shrink (even if you use a synchronized map and synchronize + * it); it behaves as if another thread removes entries from this table + * without synchronization. The entry set returned by <code>entrySet</code> * has similar phenomenons: The size may spontaneously shrink, or an - * entry, that was in the set before, suddenly disappears. <br> + * entry, that was in the set before, suddenly disappears. * - * A weak hash map is not meant for caches; use a normal map, with - * soft references as values instead, or try {@link LinkedHashMap}. <br> + * <p>A weak hash map is not meant for caches; use a normal map, with + * soft references as values instead, or try {@link LinkedHashMap}. * - * The weak hash map supports null values and null keys. The null key - * is never deleted from the map (except explictly of course). - * The performance of the methods are similar to that of a hash map. <br> + * <p>The weak hash map supports null values and null keys. The null key + * is never deleted from the map (except explictly of course). The + * performance of the methods are similar to that of a hash map. * - * The value objects are strongly referenced by this table. So if a + * <p>The value objects are strongly referenced by this table. So if a * value object maintains a strong reference to the key (either direct * or indirect) the key will never be removed from this map. According * to Sun, this problem may be fixed in a future release. It is not * possible to do it with the jdk 1.2 reference model, though. * * @author Jochen Hoenicke - * @author Eric Blake <ebb9@email.byu.edu> + * @author Eric Blake (ebb9@email.byu.edu) + * * @see HashMap * @see WeakReference * @see LinkedHashMap @@ -86,6 +86,9 @@ import java.lang.ref.ReferenceQueue; */ public class WeakHashMap extends AbstractMap implements Map { + // WARNING: WeakHashMap is a CORE class in the bootstrap cycle. See the + // comments in vm/reference/java/lang/Runtime for implications of this fact. + /** * The default capacity for an instance of HashMap. * Sun's documentation mildly suggests that this (11) is the correct @@ -148,7 +151,7 @@ public class WeakHashMap extends AbstractMap implements Map /** * The rounded product of the capacity (i.e. number of buckets) and * the load factor. When the number of elements exceeds the - * threshold, the HashMap calls <pre>rehash()</pre>. + * threshold, the HashMap calls <code>rehash()</code>. */ private int threshold; @@ -364,11 +367,11 @@ public class WeakHashMap extends AbstractMap implements Map /** * The slot of this entry. This should be - * <pre> - * Math.abs(key.hashCode() % buckets.length) - * </pre> + * <code>Math.abs(key.hashCode() % buckets.length)</code>. + * * But since the key may be silently removed we have to remember * the slot number. + * * If this bucket was removed the slot is -1. This marker will * prevent the bucket from being removed twice. */ @@ -503,9 +506,10 @@ public class WeakHashMap extends AbstractMap implements Map private final WeakEntrySet theEntrySet; /** - * The hash buckets. These are linked lists. + * The hash buckets. These are linked lists. Package visible for use in + * nested classes. */ - private WeakBucket[] buckets; + WeakBucket[] buckets; /** * Creates a new weak hash map with default load factor and default @@ -676,10 +680,12 @@ public class WeakHashMap extends AbstractMap implements Map /** * Removes a bucket from this hash map, if it wasn't removed before - * (e.g. one time through rehashing and one time through reference queue) + * (e.g. one time through rehashing and one time through reference queue). + * Package visible for use in nested classes. + * * @param bucket the bucket to remove. */ - private void internalRemove(WeakBucket bucket) + void internalRemove(WeakBucket bucket) { int slot = bucket.slot; if (slot == -1) @@ -870,4 +876,4 @@ public class WeakHashMap extends AbstractMap implements Map cleanQueue(); return super.values(); } -} +} // class WeakHashMap diff --git a/libjava/java/util/jar/Attributes.java b/libjava/java/util/jar/Attributes.java index 46d4ada..0bf27bd 100644 --- a/libjava/java/util/jar/Attributes.java +++ b/libjava/java/util/jar/Attributes.java @@ -430,7 +430,7 @@ public class Attributes implements Cloneable, Map * @returns the old value of the attribute name or null if it didn't exist * yet */ - private String putValue(Name name, String value) + String putValue(Name name, String value) { return (String) put(name, value); } diff --git a/libjava/java/util/jar/JarException.java b/libjava/java/util/jar/JarException.java index c8c0fba..54291c6 100644 --- a/libjava/java/util/jar/JarException.java +++ b/libjava/java/util/jar/JarException.java @@ -1,5 +1,5 @@ -/* Attributes.java -- exception thrown to indicate an problem with a jar file - Copyright (C) 2000 Free Software Foundation, Inc. +/* JarException.java -- thrown to indicate an problem with a jar file + Copyright (C) 2000, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,35 +41,34 @@ import java.util.zip.ZipException; /** * This exception is thrown to indicate an problem with a jar file. - * It can be constructed with or without a descriptive message of the problem. - * <p> * Note that none of the methods in the java.util.jar package actually declare * to throw this exception, most just declare that they throw an IOException * which is super class of JarException. - * - * @since 1.2 + * * @author Mark Wielaard (mark@klomp.org) + * @since 1.2 */ - public class JarException extends ZipException { - // Constructors + /** + * Compatible with JDK 1.2+. + */ + private static final long serialVersionUID = 7159778400963954473L; /** * Create a new JarException without a descriptive error message. */ public JarException() { - super(); } /** * Create a new JarException with a descriptive error message indicating * what went wrong. This message can later be retrieved by calling the * <code>getMessage()</code> method. - * @see java.lang.Throwable@getMessage() * * @param message The descriptive error message + * @see #getMessage() */ public JarException(String message) { diff --git a/libjava/java/util/jar/Manifest.java b/libjava/java/util/jar/Manifest.java index 20220b1..9a15376 100644 --- a/libjava/java/util/jar/Manifest.java +++ b/libjava/java/util/jar/Manifest.java @@ -174,10 +174,19 @@ public class Manifest implements Cloneable private static void read_main_section(Attributes attr, BufferedReader br) throws IOException { - read_version_info(attr, br); + // According to the spec we should actually call read_version_info() here. read_attributes(attr, br); + // Explicitly set Manifest-Version attribute if not set in Main + // attributes of Manifest. + if (attr.getValue(Attributes.Name.MANIFEST_VERSION) == null) + attr.putValue(Attributes.Name.MANIFEST_VERSION, "0.0"); } + /** + * Pedantic method that requires the next attribute in the Manifest to be + * the "Manifest-Version". This follows the Manifest spec closely but + * reject some jar Manifest files out in the wild. + */ private static void read_version_info(Attributes attr, BufferedReader br) throws IOException { @@ -185,7 +194,7 @@ public class Manifest implements Cloneable try { String value = expect_header(version_header, br); - attr.putValue(version_header, value); + attr.putValue(Attributes.Name.MANIFEST_VERSION, value); } catch (IOException ioe) { |