Initial revision
[gcc.git] / libjava / java / text / ChoiceFormat.java
1 // ChoiceFormat.java - Formatter for `switch'-like string substitution.
2
3 /* Copyright (C) 1999 Cygnus Solutions
4
5 This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
10
11 package java.text;
12
13 import java.util.Vector;
14
15 /**
16 * @author Tom Tromey <tromey@cygnus.com>
17 * @date March 9, 1999
18 */
19 /* Written using "Java Class Libraries", 2nd edition, plus online
20 * API docs for JDK 1.2 from http://www.javasoft.com.
21 * Status: Believed complete and correct to 1.1.
22 */
23
24 public class ChoiceFormat extends NumberFormat
25 {
26 // Note: we assume the same kind of quoting rules apply here.
27 // This isn't explicitly documented. But for instance we accept
28 // '#' as a literal hash in a format string.
29 public void applyPattern (String newPattern)
30 {
31 int index = 0, max = newPattern.length();
32 Vector stringVec = new Vector ();
33 Vector limitVec = new Vector ();
34 StringBuffer buf = new StringBuffer ();
35
36 while (true)
37 {
38 // Find end of double.
39 int dstart = index;
40 while (index < max)
41 {
42 char c = newPattern.charAt(index);
43 if (c == '#' || c == '\u2064' || c == '<')
44 break;
45 ++index;
46 }
47
48 if (index == max)
49 throw new IllegalArgumentException ("unexpected end of text");
50 Double d = new Double (newPattern.substring(dstart, index));
51
52 if (newPattern.charAt(index) == '<')
53 d = new Double (nextDouble (d.doubleValue()));
54
55 limitVec.addElement(d);
56
57 // Scan text.
58 ++index;
59 buf.setLength(0);
60 while (index < max)
61 {
62 char c = newPattern.charAt(index);
63 if (c == '\'' && index < max + 1
64 && newPattern.charAt(index + 1) == '\'')
65 {
66 buf.append(c);
67 ++index;
68 }
69 else if (c == '\'' && index < max + 2)
70 {
71 buf.append(newPattern.charAt(index + 1));
72 index += 2;
73 }
74 else if (c == '|')
75 break;
76 else
77 buf.append(c);
78 ++index;
79 }
80
81 stringVec.addElement(buf.toString());
82 if (index == max)
83 break;
84 ++index;
85 }
86
87 strings = new String[stringVec.size()];
88 stringVec.copyInto(strings);
89
90 limits = new double[limitVec.size()];
91 for (int i = 0; i < limits.length; ++i)
92 {
93 Double d = (Double) limitVec.elementAt(i);
94 limits[i] = d.doubleValue();
95 }
96 }
97
98 public ChoiceFormat (String newPattern)
99 {
100 super ();
101 applyPattern (newPattern);
102 }
103
104 public ChoiceFormat (double[] limits, String[] strings)
105 {
106 super ();
107 setChoices (limits, strings);
108 }
109
110 public Object clone ()
111 {
112 return new ChoiceFormat (limits, strings);
113 }
114
115 public boolean equals (Object obj)
116 {
117 if (! (obj instanceof ChoiceFormat))
118 return false;
119 ChoiceFormat cf = (ChoiceFormat) obj;
120 if (limits.length != cf.limits.length)
121 return false;
122 for (int i = limits.length - 1; i >= 0; --i)
123 {
124 if (limits[i] != cf.limits[i]
125 || !strings[i].equals(cf.strings[i]))
126 return false;
127 }
128 return true;
129 }
130
131 public StringBuffer format (long num, StringBuffer appendBuf,
132 FieldPosition pos)
133 {
134 return format ((double) num, appendBuf, pos);
135 }
136
137 public StringBuffer format (double num, StringBuffer appendBuf,
138 FieldPosition pos)
139 {
140 if (limits.length == 0)
141 return appendBuf;
142
143 int index = 0;
144 if (! Double.isNaN(num) && num >= limits[0])
145 {
146 for (; index < limits.length - 1; ++index)
147 {
148 if (limits[index] <= num
149 && index != limits.length - 2
150 && num < limits[index + 1])
151 break;
152 }
153 }
154
155 return appendBuf.append(strings[index]);
156 }
157
158 public Object[] getFormats ()
159 {
160 return (Object[]) strings.clone();
161 }
162
163 public double[] getLimits ()
164 {
165 return (double[]) limits.clone();
166 }
167
168 public int hashCode ()
169 {
170 int hash = 0;
171 for (int i = 0; i < limits.length; ++i)
172 {
173 long v = Double.doubleToLongBits(limits[i]);
174 hash ^= (v ^ (v >>> 32));
175 hash ^= strings[i].hashCode();
176 }
177 return hash;
178 }
179
180 public static final double nextDouble (double d)
181 {
182 return nextDouble (d, true);
183 }
184
185 public static final double nextDouble (double d, boolean next)
186 {
187 if (Double.isInfinite(d) || Double.isNaN(d))
188 return d;
189
190 long bits = Double.doubleToLongBits(d);
191
192 long mantMask = (1L << mantissaBits) - 1;
193 long mantissa = bits & mantMask;
194
195 long expMask = (1L << exponentBits) - 1;
196 long exponent = (bits >>> mantissaBits) & expMask;
197
198 if (next ^ (bits < 0)) // Increment magnitude
199 {
200 if (mantissa == (1L << mantissaBits) - 1)
201 {
202 mantissa = 0L;
203 exponent++;
204
205 // Check for absolute overflow.
206 if (exponent >= (1L << mantissaBits))
207 return (bits > 0) ? Double.POSITIVE_INFINITY
208 : Double.NEGATIVE_INFINITY;
209 }
210 else
211 mantissa++;
212 }
213 else // Decrement magnitude
214 {
215 if (exponent == 0L && mantissa == 0L)
216 {
217 // The only case where there is a change of sign
218 return next ? Double.MIN_VALUE : -Double.MIN_VALUE;
219 }
220 else
221 {
222 if (mantissa == 0L)
223 {
224 mantissa = (1L << mantissaBits) - 1;
225 exponent--;
226 }
227 else
228 mantissa--;
229 }
230 }
231
232 long result = bits < 0 ? 1 : 0;
233 result = (result << exponentBits) | exponent;
234 result = (result << mantissaBits) | mantissa;
235 return Double.longBitsToDouble(result);
236 }
237
238 public Number parse (String sourceStr, ParsePosition pos)
239 {
240 int index = pos.getIndex();
241 for (int i = 0; i < limits.length; ++i)
242 {
243 if (sourceStr.startsWith(strings[i], index))
244 {
245 pos.setIndex(index + strings[i].length());
246 return new Double (limits[i]);
247 }
248 }
249 pos.setErrorIndex(index);
250 return new Double (Double.NaN);
251 }
252
253 public static final double previousDouble (double d)
254 {
255 return nextDouble (d, false);
256 }
257
258 public void setChoices (double[] limits, String[] strings)
259 {
260 if (limits == null || strings == null)
261 throw new NullPointerException ();
262 if (limits.length != strings.length)
263 throw new IllegalArgumentException ();
264 this.strings = (String[]) strings.clone();
265 this.limits = (double[]) limits.clone();
266 }
267
268 private final void quoteString (StringBuffer dest, String text)
269 {
270 int max = text.length();
271 for (int i = 0; i < max; ++i)
272 {
273 char c = text.charAt(i);
274 if (c == '\'')
275 {
276 dest.append(c);
277 dest.append(c);
278 }
279 else if (c == '#' || c == '|' || c == '\u2064' || c == '<')
280 {
281 dest.append('\'');
282 dest.append(c);
283 dest.append('\'');
284 }
285 else
286 dest.append(c);
287 }
288 }
289
290 public String toPattern ()
291 {
292 StringBuffer result = new StringBuffer ();
293 for (int i = 0; i < limits.length; ++i)
294 {
295 result.append(limits[i]);
296 result.append('#');
297 quoteString (result, strings[i]);
298 }
299 return result.toString();
300 }
301
302 // Formats and limits.
303 private String[] strings;
304 private double[] limits;
305
306 // Number of mantissa bits in double.
307 private static final int mantissaBits = 52;
308 // Number of exponent bits in a double.
309 private static final int exponentBits = 11;
310 }