| 1 | /* MessageFormat.java - Localized message formatting.
|
|---|
| 2 | Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
|---|
| 3 |
|
|---|
| 4 | This file is part of GNU Classpath.
|
|---|
| 5 |
|
|---|
| 6 | GNU Classpath is free software; you can redistribute it and/or modify
|
|---|
| 7 | it under the terms of the GNU General Public License as published by
|
|---|
| 8 | the Free Software Foundation; either version 2, or (at your option)
|
|---|
| 9 | any later version.
|
|---|
| 10 |
|
|---|
| 11 | GNU Classpath is distributed in the hope that it will be useful, but
|
|---|
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 14 | General Public License for more details.
|
|---|
| 15 |
|
|---|
| 16 | You should have received a copy of the GNU General Public License
|
|---|
| 17 | along with GNU Classpath; see the file COPYING. If not, write to the
|
|---|
| 18 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 19 | 02111-1307 USA.
|
|---|
| 20 |
|
|---|
| 21 | Linking this library statically or dynamically with other modules is
|
|---|
| 22 | making a combined work based on this library. Thus, the terms and
|
|---|
| 23 | conditions of the GNU General Public License cover the whole
|
|---|
| 24 | combination.
|
|---|
| 25 |
|
|---|
| 26 | As a special exception, the copyright holders of this library give you
|
|---|
| 27 | permission to link this library with independent modules to produce an
|
|---|
| 28 | executable, regardless of the license terms of these independent
|
|---|
| 29 | modules, and to copy and distribute the resulting executable under
|
|---|
| 30 | terms of your choice, provided that you also meet, for each linked
|
|---|
| 31 | independent module, the terms and conditions of the license of that
|
|---|
| 32 | module. An independent module is a module which is not derived from
|
|---|
| 33 | or based on this library. If you modify this library, you may extend
|
|---|
| 34 | this exception to your version of the library, but you are not
|
|---|
| 35 | obligated to do so. If you do not wish to do so, delete this
|
|---|
| 36 | exception statement from your version. */
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 | package java.text;
|
|---|
| 40 |
|
|---|
| 41 | import java.util.Date;
|
|---|
| 42 | import java.util.Locale;
|
|---|
| 43 | import java.util.Vector;
|
|---|
| 44 |
|
|---|
| 45 | /**
|
|---|
| 46 | * @author Tom Tromey <[email protected]>
|
|---|
| 47 | * @author Jorge Aliss <[email protected]>
|
|---|
| 48 | * @date March 3, 1999
|
|---|
| 49 | */
|
|---|
| 50 | /* Written using "Java Class Libraries", 2nd edition, plus online
|
|---|
| 51 | * API docs for JDK 1.2 from http://www.javasoft.com.
|
|---|
| 52 | * Status: Believed complete and correct to 1.2, except serialization.
|
|---|
| 53 | * and parsing.
|
|---|
| 54 | */
|
|---|
| 55 | final class MessageFormatElement
|
|---|
| 56 | {
|
|---|
| 57 | // Argument number.
|
|---|
| 58 | int argNumber;
|
|---|
| 59 | // Formatter to be used. This is the format set by setFormat.
|
|---|
| 60 | Format setFormat;
|
|---|
| 61 | // Formatter to be used based on the type.
|
|---|
| 62 | Format format;
|
|---|
| 63 |
|
|---|
| 64 | // Argument will be checked to make sure it is an instance of this
|
|---|
| 65 | // class.
|
|---|
| 66 | Class formatClass;
|
|---|
| 67 |
|
|---|
| 68 | // Formatter type.
|
|---|
| 69 | String type;
|
|---|
| 70 | // Formatter style.
|
|---|
| 71 | String style;
|
|---|
| 72 |
|
|---|
| 73 | // Text to follow this element.
|
|---|
| 74 | String trailer;
|
|---|
| 75 |
|
|---|
| 76 | // Recompute the locale-based formatter.
|
|---|
| 77 | void setLocale (Locale loc)
|
|---|
| 78 | {
|
|---|
| 79 | if (type == null)
|
|---|
| 80 | ;
|
|---|
| 81 | else if (type.equals("number"))
|
|---|
| 82 | {
|
|---|
| 83 | formatClass = java.lang.Number.class;
|
|---|
| 84 |
|
|---|
| 85 | if (style == null)
|
|---|
| 86 | format = NumberFormat.getInstance(loc);
|
|---|
| 87 | else if (style.equals("currency"))
|
|---|
| 88 | format = NumberFormat.getCurrencyInstance(loc);
|
|---|
| 89 | else if (style.equals("percent"))
|
|---|
| 90 | format = NumberFormat.getPercentInstance(loc);
|
|---|
| 91 | else if (style.equals("integer"))
|
|---|
| 92 | {
|
|---|
| 93 | NumberFormat nf = NumberFormat.getNumberInstance(loc);
|
|---|
| 94 | nf.setMaximumFractionDigits(0);
|
|---|
| 95 | nf.setGroupingUsed(false);
|
|---|
| 96 | format = nf;
|
|---|
| 97 | }
|
|---|
| 98 | else
|
|---|
| 99 | {
|
|---|
| 100 | format = NumberFormat.getNumberInstance(loc);
|
|---|
| 101 | DecimalFormat df = (DecimalFormat) format;
|
|---|
| 102 | df.applyPattern(style);
|
|---|
| 103 | }
|
|---|
| 104 | }
|
|---|
| 105 | else if (type.equals("time") || type.equals("date"))
|
|---|
| 106 | {
|
|---|
| 107 | formatClass = java.util.Date.class;
|
|---|
| 108 |
|
|---|
| 109 | int val = DateFormat.DEFAULT;
|
|---|
| 110 | if (style == null)
|
|---|
| 111 | ;
|
|---|
| 112 | else if (style.equals("short"))
|
|---|
| 113 | val = DateFormat.SHORT;
|
|---|
| 114 | else if (style.equals("medium"))
|
|---|
| 115 | val = DateFormat.MEDIUM;
|
|---|
| 116 | else if (style.equals("long"))
|
|---|
| 117 | val = DateFormat.LONG;
|
|---|
| 118 | else if (style.equals("full"))
|
|---|
| 119 | val = DateFormat.FULL;
|
|---|
| 120 |
|
|---|
| 121 | if (type.equals("time"))
|
|---|
| 122 | format = DateFormat.getTimeInstance(val, loc);
|
|---|
| 123 | else
|
|---|
| 124 | format = DateFormat.getDateInstance(val, loc);
|
|---|
| 125 |
|
|---|
| 126 | if (style != null && val == DateFormat.DEFAULT)
|
|---|
| 127 | {
|
|---|
| 128 | SimpleDateFormat sdf = (SimpleDateFormat) format;
|
|---|
| 129 | sdf.applyPattern(style);
|
|---|
| 130 | }
|
|---|
| 131 | }
|
|---|
| 132 | else if (type.equals("choice"))
|
|---|
| 133 | {
|
|---|
| 134 | formatClass = java.lang.Number.class;
|
|---|
| 135 |
|
|---|
| 136 | if (style == null)
|
|---|
| 137 | throw new
|
|---|
| 138 | IllegalArgumentException ("style required for choice format");
|
|---|
| 139 | format = new ChoiceFormat (style);
|
|---|
| 140 | }
|
|---|
| 141 | }
|
|---|
| 142 | }
|
|---|
| 143 |
|
|---|
| 144 | public class MessageFormat extends Format
|
|---|
| 145 | {
|
|---|
| 146 | // Helper that returns the text up to the next format opener. The
|
|---|
| 147 | // text is put into BUFFER. Returns index of character after end of
|
|---|
| 148 | // string. Throws IllegalArgumentException on error.
|
|---|
| 149 | private static final int scanString (String pat, int index,
|
|---|
| 150 | StringBuffer buffer)
|
|---|
| 151 | {
|
|---|
| 152 | int max = pat.length();
|
|---|
| 153 | buffer.setLength(0);
|
|---|
| 154 | for (; index < max; ++index)
|
|---|
| 155 | {
|
|---|
| 156 | char c = pat.charAt(index);
|
|---|
| 157 | if (c == '\'' && index + 2 < max && pat.charAt(index + 2) == '\'')
|
|---|
| 158 | {
|
|---|
| 159 | buffer.append(pat.charAt(index + 1));
|
|---|
| 160 | index += 2;
|
|---|
| 161 | }
|
|---|
| 162 | else if (c == '\'' && index + 1 < max
|
|---|
| 163 | && pat.charAt(index + 1) == '\'')
|
|---|
| 164 | {
|
|---|
| 165 | buffer.append(c);
|
|---|
| 166 | ++index;
|
|---|
| 167 | }
|
|---|
| 168 | else if (c == '{')
|
|---|
| 169 | break;
|
|---|
| 170 | else if (c == '}')
|
|---|
| 171 | throw new IllegalArgumentException ();
|
|---|
| 172 | else
|
|---|
| 173 | buffer.append(c);
|
|---|
| 174 | }
|
|---|
| 175 | return index;
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | // This helper retrieves a single part of a format element. Returns
|
|---|
| 179 | // the index of the terminating character.
|
|---|
| 180 | private static final int scanFormatElement (String pat, int index,
|
|---|
| 181 | StringBuffer buffer,
|
|---|
| 182 | char term)
|
|---|
| 183 | {
|
|---|
| 184 | int max = pat.length();
|
|---|
| 185 | buffer.setLength(0);
|
|---|
| 186 | int brace_depth = 1;
|
|---|
| 187 |
|
|---|
| 188 | for (; index < max; ++index)
|
|---|
| 189 | {
|
|---|
| 190 | char c = pat.charAt(index);
|
|---|
| 191 | if (c == '\'' && index + 2 < max && pat.charAt(index + 2) == '\'')
|
|---|
| 192 | {
|
|---|
| 193 | buffer.append(c);
|
|---|
| 194 | buffer.append(pat.charAt(index + 1));
|
|---|
| 195 | buffer.append(c);
|
|---|
| 196 | index += 2;
|
|---|
| 197 | }
|
|---|
| 198 | else if (c == '\'' && index + 1 < max
|
|---|
| 199 | && pat.charAt(index + 1) == '\'')
|
|---|
| 200 | {
|
|---|
| 201 | buffer.append(c);
|
|---|
| 202 | ++index;
|
|---|
| 203 | }
|
|---|
| 204 | else if (c == '{')
|
|---|
| 205 | {
|
|---|
| 206 | buffer.append(c);
|
|---|
| 207 | ++brace_depth;
|
|---|
| 208 | }
|
|---|
| 209 | else if (c == '}')
|
|---|
| 210 | {
|
|---|
| 211 | if (--brace_depth == 0)
|
|---|
| 212 | break;
|
|---|
| 213 | buffer.append(c);
|
|---|
| 214 | }
|
|---|
| 215 | // Check for TERM after braces, because TERM might be `}'.
|
|---|
| 216 | else if (c == term)
|
|---|
| 217 | break;
|
|---|
| 218 | else
|
|---|
| 219 | buffer.append(c);
|
|---|
| 220 | }
|
|---|
| 221 | return index;
|
|---|
| 222 | }
|
|---|
| 223 |
|
|---|
| 224 | // This is used to parse a format element and whatever non-format
|
|---|
| 225 | // text might trail it.
|
|---|
| 226 | private static final int scanFormat (String pat, int index,
|
|---|
| 227 | StringBuffer buffer, Vector elts,
|
|---|
| 228 | Locale locale)
|
|---|
| 229 | {
|
|---|
| 230 | MessageFormatElement mfe = new MessageFormatElement ();
|
|---|
| 231 | elts.addElement(mfe);
|
|---|
| 232 |
|
|---|
| 233 | int max = pat.length();
|
|---|
| 234 |
|
|---|
| 235 | // Skip the opening `{'.
|
|---|
| 236 | ++index;
|
|---|
| 237 |
|
|---|
| 238 | // Fetch the argument number.
|
|---|
| 239 | index = scanFormatElement (pat, index, buffer, ',');
|
|---|
| 240 | try
|
|---|
| 241 | {
|
|---|
| 242 | mfe.argNumber = Integer.parseInt(buffer.toString());
|
|---|
| 243 | }
|
|---|
| 244 | catch (NumberFormatException nfx)
|
|---|
| 245 | {
|
|---|
| 246 | throw new IllegalArgumentException ();
|
|---|
| 247 | }
|
|---|
| 248 |
|
|---|
| 249 | // Extract the element format.
|
|---|
| 250 | if (index < max && pat.charAt(index) == ',')
|
|---|
| 251 | {
|
|---|
| 252 | index = scanFormatElement (pat, index + 1, buffer, ',');
|
|---|
| 253 | mfe.type = buffer.toString();
|
|---|
| 254 |
|
|---|
| 255 | // Extract the style.
|
|---|
| 256 | if (index < max && pat.charAt(index) == ',')
|
|---|
| 257 | {
|
|---|
| 258 | index = scanFormatElement (pat, index + 1, buffer, '}');
|
|---|
| 259 | mfe.style = buffer.toString ();
|
|---|
| 260 | }
|
|---|
| 261 | }
|
|---|
| 262 |
|
|---|
| 263 | // Advance past the last terminator.
|
|---|
| 264 | if (index >= max || pat.charAt(index) != '}')
|
|---|
| 265 | throw new IllegalArgumentException ();
|
|---|
| 266 | ++index;
|
|---|
| 267 |
|
|---|
| 268 | // Now fetch trailing string.
|
|---|
| 269 | index = scanString (pat, index, buffer);
|
|---|
| 270 | mfe.trailer = buffer.toString ();
|
|---|
| 271 |
|
|---|
| 272 | mfe.setLocale(locale);
|
|---|
| 273 |
|
|---|
| 274 | return index;
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | /**
|
|---|
| 278 | * Applies the specified pattern to this MessageFormat.
|
|---|
| 279 | *
|
|---|
| 280 | * @param aPattern The Pattern
|
|---|
| 281 | */
|
|---|
| 282 | public void applyPattern (String newPattern)
|
|---|
| 283 | {
|
|---|
| 284 | pattern = newPattern;
|
|---|
| 285 |
|
|---|
| 286 | StringBuffer tempBuffer = new StringBuffer ();
|
|---|
| 287 |
|
|---|
| 288 | int index = scanString (newPattern, 0, tempBuffer);
|
|---|
| 289 | leader = tempBuffer.toString();
|
|---|
| 290 |
|
|---|
| 291 | Vector elts = new Vector ();
|
|---|
| 292 | while (index < newPattern.length())
|
|---|
| 293 | index = scanFormat (newPattern, index, tempBuffer, elts, locale);
|
|---|
| 294 |
|
|---|
| 295 | elements = new MessageFormatElement[elts.size()];
|
|---|
| 296 | elts.copyInto(elements);
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | /**
|
|---|
| 300 | * Overrides Format.clone()
|
|---|
| 301 | */
|
|---|
| 302 | public Object clone ()
|
|---|
| 303 | {
|
|---|
| 304 | MessageFormat c = (MessageFormat) super.clone ();
|
|---|
| 305 | c.elements = (MessageFormatElement[]) elements.clone ();
|
|---|
| 306 | return c;
|
|---|
| 307 | }
|
|---|
| 308 |
|
|---|
| 309 | /**
|
|---|
| 310 | * Overrides Format.equals(Object obj)
|
|---|
| 311 | */
|
|---|
| 312 | public boolean equals (Object obj)
|
|---|
| 313 | {
|
|---|
| 314 | if (! (obj instanceof MessageFormat))
|
|---|
| 315 | return false;
|
|---|
| 316 | MessageFormat mf = (MessageFormat) obj;
|
|---|
| 317 | return (pattern.equals(mf.pattern)
|
|---|
| 318 | && locale.equals(mf.locale));
|
|---|
| 319 | }
|
|---|
| 320 |
|
|---|
| 321 | /**
|
|---|
| 322 | * A convinience method to format patterns.
|
|---|
| 323 | *
|
|---|
| 324 | * @param aPattern The pattern used when formatting.
|
|---|
| 325 | * @param arguments The array containing the objects to be formatted.
|
|---|
| 326 | */
|
|---|
| 327 | public static String format (String pattern, Object arguments[])
|
|---|
| 328 | {
|
|---|
| 329 | MessageFormat mf = new MessageFormat (pattern);
|
|---|
| 330 | StringBuffer sb = new StringBuffer ();
|
|---|
| 331 | FieldPosition fp = new FieldPosition (NumberFormat.INTEGER_FIELD);
|
|---|
| 332 | return mf.format(arguments, sb, fp).toString();
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | /**
|
|---|
| 336 | * Returns the pattern with the formatted objects.
|
|---|
| 337 | *
|
|---|
| 338 | * @param source The array containing the objects to be formatted.
|
|---|
| 339 | * @param result The StringBuffer where the text is appened.
|
|---|
| 340 | * @param fp A FieldPosition object (it is ignored).
|
|---|
| 341 | */
|
|---|
| 342 | public final StringBuffer format (Object arguments[], StringBuffer appendBuf,
|
|---|
| 343 | FieldPosition ignore)
|
|---|
| 344 | {
|
|---|
| 345 | appendBuf.append(leader);
|
|---|
| 346 |
|
|---|
| 347 | for (int i = 0; i < elements.length; ++i)
|
|---|
| 348 | {
|
|---|
| 349 | if (elements[i].argNumber >= arguments.length)
|
|---|
| 350 | throw new IllegalArgumentException ();
|
|---|
| 351 | Object thisArg = arguments[elements[i].argNumber];
|
|---|
| 352 |
|
|---|
| 353 | Format formatter = null;
|
|---|
| 354 | if (elements[i].setFormat != null)
|
|---|
| 355 | formatter = elements[i].setFormat;
|
|---|
| 356 | else if (elements[i].format != null)
|
|---|
| 357 | {
|
|---|
| 358 | if (elements[i].formatClass != null
|
|---|
| 359 | && ! elements[i].formatClass.isInstance(thisArg))
|
|---|
| 360 | throw new IllegalArgumentException ();
|
|---|
| 361 | formatter = elements[i].format;
|
|---|
| 362 | }
|
|---|
| 363 | else if (thisArg instanceof Number)
|
|---|
| 364 | formatter = NumberFormat.getInstance(locale);
|
|---|
| 365 | else if (thisArg instanceof Date)
|
|---|
| 366 | formatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
|
|---|
| 367 | else
|
|---|
| 368 | appendBuf.append(thisArg);
|
|---|
| 369 |
|
|---|
| 370 | if (formatter != null)
|
|---|
| 371 | {
|
|---|
| 372 | // Special-case ChoiceFormat.
|
|---|
| 373 | if (formatter instanceof ChoiceFormat)
|
|---|
| 374 | {
|
|---|
| 375 | StringBuffer buf = new StringBuffer ();
|
|---|
| 376 | // FIXME: don't actually know what is correct here.
|
|---|
| 377 | // Can a sub-format refer to any argument, or just
|
|---|
| 378 | // the single argument passed to it? Must test
|
|---|
| 379 | // against JDK.
|
|---|
| 380 | formatter.format(thisArg, buf, ignore);
|
|---|
| 381 | MessageFormat mf = new MessageFormat ();
|
|---|
| 382 | mf.setLocale(locale);
|
|---|
| 383 | mf.applyPattern(buf.toString());
|
|---|
| 384 | formatter = mf;
|
|---|
| 385 | }
|
|---|
| 386 | formatter.format(thisArg, appendBuf, ignore);
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | appendBuf.append(elements[i].trailer);
|
|---|
| 390 | }
|
|---|
| 391 |
|
|---|
| 392 | return appendBuf;
|
|---|
| 393 | }
|
|---|
| 394 |
|
|---|
| 395 | /**
|
|---|
| 396 | * Returns the pattern with the formatted objects.
|
|---|
| 397 | *
|
|---|
| 398 | * @param source The object to be formatted.
|
|---|
| 399 | * @param result The StringBuffer where the text is appened.
|
|---|
| 400 | * @param fp A FieldPosition object (it is ignored).
|
|---|
| 401 | */
|
|---|
| 402 | public final StringBuffer format (Object singleArg, StringBuffer appendBuf,
|
|---|
| 403 | FieldPosition ignore)
|
|---|
| 404 | {
|
|---|
| 405 | Object[] args;
|
|---|
| 406 |
|
|---|
| 407 | if (singleArg instanceof Object[])
|
|---|
| 408 | {
|
|---|
| 409 | // This isn't specified in any manual, but it follows the
|
|---|
| 410 | // JDK implementation.
|
|---|
| 411 | args = (Object[]) singleArg;
|
|---|
| 412 | }
|
|---|
| 413 | else
|
|---|
| 414 | {
|
|---|
| 415 | args = new Object[1];
|
|---|
| 416 | args[0] = singleArg;
|
|---|
| 417 | }
|
|---|
| 418 | return format (args, appendBuf, ignore);
|
|---|
| 419 | }
|
|---|
| 420 |
|
|---|
| 421 | /**
|
|---|
| 422 | * Returns an array with the Formats for
|
|---|
| 423 | * the arguments.
|
|---|
| 424 | */
|
|---|
| 425 | public Format[] getFormats ()
|
|---|
| 426 | {
|
|---|
| 427 | Format[] f = new Format[elements.length];
|
|---|
| 428 | for (int i = elements.length - 1; i >= 0; --i)
|
|---|
| 429 | f[i] = elements[i].setFormat;
|
|---|
| 430 | return f;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 | /**
|
|---|
| 434 | * Returns the locale.
|
|---|
| 435 | */
|
|---|
| 436 | public Locale getLocale ()
|
|---|
| 437 | {
|
|---|
| 438 | return locale;
|
|---|
| 439 | }
|
|---|
| 440 |
|
|---|
| 441 | /**
|
|---|
| 442 | * Overrides Format.hashCode()
|
|---|
| 443 | */
|
|---|
| 444 | public int hashCode ()
|
|---|
| 445 | {
|
|---|
| 446 | // FIXME: not a very good hash.
|
|---|
| 447 | return pattern.hashCode() + locale.hashCode();
|
|---|
| 448 | }
|
|---|
| 449 |
|
|---|
| 450 | private MessageFormat ()
|
|---|
| 451 | {
|
|---|
| 452 | }
|
|---|
| 453 |
|
|---|
| 454 | /**
|
|---|
| 455 | * Creates a new MessageFormat object with
|
|---|
| 456 | * the specified pattern
|
|---|
| 457 | *
|
|---|
| 458 | * @param aPattern The Pattern
|
|---|
| 459 | */
|
|---|
| 460 | public MessageFormat (String pattern)
|
|---|
| 461 | {
|
|---|
| 462 | locale = Locale.getDefault();
|
|---|
| 463 | applyPattern (pattern);
|
|---|
| 464 | }
|
|---|
| 465 |
|
|---|
| 466 | public Object[] parse (String sourceStr, ParsePosition pos)
|
|---|
| 467 | {
|
|---|
| 468 | // Check initial text.
|
|---|
| 469 | int index = pos.getIndex();
|
|---|
| 470 | if (! sourceStr.startsWith(leader, index))
|
|---|
| 471 | {
|
|---|
| 472 | pos.setErrorIndex(index);
|
|---|
| 473 | return null;
|
|---|
| 474 | }
|
|---|
| 475 | index += leader.length();
|
|---|
| 476 |
|
|---|
| 477 | Vector results = new Vector (elements.length, 1);
|
|---|
| 478 | // Now check each format.
|
|---|
| 479 | for (int i = 0; i < elements.length; ++i)
|
|---|
| 480 | {
|
|---|
| 481 | Format formatter = null;
|
|---|
| 482 | if (elements[i].setFormat != null)
|
|---|
| 483 | formatter = elements[i].setFormat;
|
|---|
| 484 | else if (elements[i].format != null)
|
|---|
| 485 | formatter = elements[i].format;
|
|---|
| 486 |
|
|---|
| 487 | Object value = null;
|
|---|
| 488 | if (formatter instanceof ChoiceFormat)
|
|---|
| 489 | {
|
|---|
| 490 | // We must special-case a ChoiceFormat because it might
|
|---|
| 491 | // have recursive formatting.
|
|---|
| 492 | ChoiceFormat cf = (ChoiceFormat) formatter;
|
|---|
| 493 | String[] formats = (String[]) cf.getFormats();
|
|---|
| 494 | double[] limits = (double[]) cf.getLimits();
|
|---|
| 495 | MessageFormat subfmt = new MessageFormat ();
|
|---|
| 496 | subfmt.setLocale(locale);
|
|---|
| 497 | ParsePosition subpos = new ParsePosition (index);
|
|---|
| 498 |
|
|---|
| 499 | int j;
|
|---|
| 500 | for (j = 0; value == null && j < limits.length; ++j)
|
|---|
| 501 | {
|
|---|
| 502 | subfmt.applyPattern(formats[j]);
|
|---|
| 503 | subpos.setIndex(index);
|
|---|
| 504 | value = subfmt.parse(sourceStr, subpos);
|
|---|
| 505 | }
|
|---|
| 506 | if (value != null)
|
|---|
| 507 | {
|
|---|
| 508 | index = subpos.getIndex();
|
|---|
| 509 | value = new Double (limits[j]);
|
|---|
| 510 | }
|
|---|
| 511 | }
|
|---|
| 512 | else if (formatter != null)
|
|---|
| 513 | {
|
|---|
| 514 | pos.setIndex(index);
|
|---|
| 515 | value = formatter.parseObject(sourceStr, pos);
|
|---|
| 516 | if (value != null)
|
|---|
| 517 | index = pos.getIndex();
|
|---|
| 518 | }
|
|---|
| 519 | else
|
|---|
| 520 | {
|
|---|
| 521 | // We have a String format. This can lose in a number
|
|---|
| 522 | // of ways, but we give it a shot.
|
|---|
| 523 | int next_index = sourceStr.indexOf(elements[i].trailer, index);
|
|---|
| 524 | if (next_index == -1)
|
|---|
| 525 | {
|
|---|
| 526 | pos.setErrorIndex(index);
|
|---|
| 527 | return null;
|
|---|
| 528 | }
|
|---|
| 529 | value = sourceStr.substring(index, next_index);
|
|---|
| 530 | index = next_index;
|
|---|
| 531 | }
|
|---|
| 532 |
|
|---|
| 533 | if (value == null
|
|---|
| 534 | || ! sourceStr.startsWith(elements[i].trailer, index))
|
|---|
| 535 | {
|
|---|
| 536 | pos.setErrorIndex(index);
|
|---|
| 537 | return null;
|
|---|
| 538 | }
|
|---|
| 539 |
|
|---|
| 540 | if (elements[i].argNumber >= results.size())
|
|---|
| 541 | results.setSize(elements[i].argNumber + 1);
|
|---|
| 542 | results.setElementAt(value, elements[i].argNumber);
|
|---|
| 543 |
|
|---|
| 544 | index += elements[i].trailer.length();
|
|---|
| 545 | }
|
|---|
| 546 |
|
|---|
| 547 | Object[] r = new Object[results.size()];
|
|---|
| 548 | results.copyInto(r);
|
|---|
| 549 | return r;
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | public Object[] parse (String sourceStr) throws ParseException
|
|---|
| 553 | {
|
|---|
| 554 | ParsePosition pp = new ParsePosition (0);
|
|---|
| 555 | Object[] r = parse (sourceStr, pp);
|
|---|
| 556 | if (r == null)
|
|---|
| 557 | throw new ParseException ("couldn't parse string", pp.getErrorIndex());
|
|---|
| 558 | return r;
|
|---|
| 559 | }
|
|---|
| 560 |
|
|---|
| 561 | public Object parseObject (String sourceStr, ParsePosition pos)
|
|---|
| 562 | {
|
|---|
| 563 | return parse (sourceStr, pos);
|
|---|
| 564 | }
|
|---|
| 565 |
|
|---|
| 566 | /**
|
|---|
| 567 | * Sets the format for the argument at an specified
|
|---|
| 568 | * index.
|
|---|
| 569 | *
|
|---|
| 570 | * @param index The index.
|
|---|
| 571 | * @format The Format object.
|
|---|
| 572 | */
|
|---|
| 573 | public void setFormat (int variableNum, Format newFormat)
|
|---|
| 574 | {
|
|---|
| 575 | elements[variableNum].setFormat = newFormat;
|
|---|
| 576 | }
|
|---|
| 577 |
|
|---|
| 578 | /**
|
|---|
| 579 | * Sets the formats for the arguments.
|
|---|
| 580 | *
|
|---|
| 581 | * @param formats An array of Format objects.
|
|---|
| 582 | */
|
|---|
| 583 | public void setFormats (Format[] newFormats)
|
|---|
| 584 | {
|
|---|
| 585 | if (newFormats.length < elements.length)
|
|---|
| 586 | throw new IllegalArgumentException ();
|
|---|
| 587 | int len = Math.min(newFormats.length, elements.length);
|
|---|
| 588 | for (int i = 0; i < len; ++i)
|
|---|
| 589 | elements[i].setFormat = newFormats[i];
|
|---|
| 590 | }
|
|---|
| 591 |
|
|---|
| 592 | /**
|
|---|
| 593 | * Sets the locale.
|
|---|
| 594 | *
|
|---|
| 595 | * @param locale A Locale
|
|---|
| 596 | */
|
|---|
| 597 | public void setLocale (Locale loc)
|
|---|
| 598 | {
|
|---|
| 599 | locale = loc;
|
|---|
| 600 | if (elements != null)
|
|---|
| 601 | {
|
|---|
| 602 | for (int i = 0; i < elements.length; ++i)
|
|---|
| 603 | elements[i].setLocale(loc);
|
|---|
| 604 | }
|
|---|
| 605 | }
|
|---|
| 606 |
|
|---|
| 607 | /**
|
|---|
| 608 | * Returns the pattern.
|
|---|
| 609 | */
|
|---|
| 610 | public String toPattern ()
|
|---|
| 611 | {
|
|---|
| 612 | return pattern;
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 | // The pattern string.
|
|---|
| 616 | private String pattern;
|
|---|
| 617 | // The locale.
|
|---|
| 618 | private Locale locale;
|
|---|
| 619 | // Variables.
|
|---|
| 620 | private MessageFormatElement[] elements;
|
|---|
| 621 | // Leader text.
|
|---|
| 622 | private String leader;
|
|---|
| 623 | }
|
|---|