mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			539 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			539 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* java.util.Properties
 | |
|    Copyright (C) 1998, 1999, 2000 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.
 | |
| 
 | |
| As a special exception, if you link this library with other files to
 | |
| produce an executable, this library does not by itself cause the
 | |
| resulting executable to be covered by the GNU General Public License.
 | |
| This exception does not however invalidate any other reasons why the
 | |
| executable file might be covered by the GNU General Public License. */
 | |
| 
 | |
| 
 | |
| package java.util;
 | |
| import java.io.*;
 | |
| 
 | |
| /**
 | |
|  * 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>
 | |
|  *
 | |
|  * 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
 | |
|  * @author Jochen Hoenicke */
 | |
| public class Properties extends Hashtable
 | |
| {
 | |
|   /**
 | |
|    * The property list that contains default values for any keys not
 | |
|    * in this property list.  
 | |
|    */
 | |
|   protected Properties defaults;
 | |
| 
 | |
|   private static final long serialVersionUID = 4112578634029874840L;
 | |
| 
 | |
|   /**
 | |
|    * Creates a new empty property list.
 | |
|    */
 | |
|   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.
 | |
|    */
 | |
|   public Properties(Properties defaults)
 | |
|   {
 | |
|     this.defaults = defaults;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Reads a property list from an input stream.  The stream should
 | |
|    * have the following format: <br>
 | |
|    *
 | |
|    * An empty line or a line starting with <code>#</code> or
 | |
|    * <code>!</code> is ignored.  An backslash (<code>\</code>) at the
 | |
|    * end of the line makes the line continueing on the next line
 | |
|    * (but make sure there is no whitespace after the backslash).
 | |
|    * Otherwise, each line describes a key/value pair. <br>
 | |
|    *
 | |
|    * The chars up to the first whitespace, = or : are the key.  You
 | |
|    * can include this caracters in the key, if you precede them with
 | |
|    * a backslash (<code>\</code>). The key is followed by optional
 | |
|    * whitespaces, optionally one <code>=</code> or <code>:</code>,
 | |
|    * and optionally some more whitespaces.  The rest of the line is
 | |
|    * the resource belonging to the key. <br>
 | |
|    *
 | |
|    * Escape sequences <code>\t, \n, \r, \\, \", \', \!, \#, \ </code>(a
 | |
|    * space), and unicode characters with the
 | |
|    * <code>\</code><code>u</code>xxxx 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>
 | |
|    *
 | |
|    * @param in the input stream
 | |
|    * @exception IOException if an error occured when reading
 | |
|    * from the input.  */
 | |
|   public void load(InputStream inStream) throws IOException
 | |
|   {
 | |
|     BufferedReader reader =
 | |
|       new BufferedReader(new InputStreamReader(inStream));
 | |
|     String line;
 | |
|     
 | |
|     while ((line = reader.readLine()) != null)
 | |
|       {
 | |
| 	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;
 | |
| 
 | |
| 	// The characaters 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);
 | |
| 			  }	// 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++;
 | |
| 
 | |
| 	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);
 | |
| 			  }	// 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.
 | |
|    */
 | |
|   public void save(OutputStream out, String header)
 | |
|   {
 | |
|     try
 | |
|       {
 | |
| 	store(out, header);
 | |
|       }
 | |
|     catch (IOException ex)
 | |
|       {
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Writes the key/value pairs to the given output stream. <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>
 | |
|    *
 | |
|    * Each line has the form <code>key = value</code>.  Newlines,
 | |
|    * Returns and tabs are written as <code>\n,\t,\r</code> resp.
 | |
|    * The characters <code>\, !, #, =</code> and <code>:</code> are
 | |
|    * 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.
 | |
|    *
 | |
|    * @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.
 | |
|    */
 | |
|   public void store(OutputStream out, String header) throws IOException
 | |
|   {
 | |
|     PrintWriter writer = new PrintWriter(out);
 | |
|     if (header != null)
 | |
|       writer.println("#" + header);
 | |
|     writer.println("#" + new Date().toString());
 | |
|     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.
 | |
|    */
 | |
|   public String getProperty(String key)
 | |
|   {
 | |
|     return getProperty(key, null);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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.
 | |
|    */
 | |
|   public String getProperty(String key, String defaultValue)
 | |
|   {
 | |
|     Properties prop = this;
 | |
|     // Eliminate tail recursion.
 | |
|     do
 | |
|       {
 | |
| 	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.
 | |
|    */
 | |
|   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();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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
 | |
|    */
 | |
|   private String formatForOutput(String key, String value)
 | |
|   {
 | |
|     // 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++)
 | |
|       {
 | |
| 	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;
 | |
|       }
 | |
|     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
 | |
|    * 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
 | |
|    */
 | |
|   public void list(PrintStream out)
 | |
|   {
 | |
|     Enumeration keys = keys();
 | |
|     Enumeration elts = elements();
 | |
|     while (keys.hasMoreElements())
 | |
|       {
 | |
| 	String key = (String) keys.nextElement();
 | |
| 	String elt = (String) elts.nextElement();
 | |
| 	String output = formatForOutput(key, elt);
 | |
| 	out.println(output);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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
 | |
|    */
 | |
|   public void list(PrintWriter out)
 | |
|   {
 | |
|     Enumeration keys = keys();
 | |
|     Enumeration elts = elements();
 | |
|     while (keys.hasMoreElements())
 | |
|       {
 | |
| 	String key = (String) keys.nextElement();
 | |
| 	String elt = (String) elts.nextElement();
 | |
| 	String output = formatForOutput(key, elt);
 | |
| 	out.println(output);
 | |
|       }
 | |
|   }
 | |
| }
 |