001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028// 029// (c) 2000 Sun Microsystems, Inc. 030// ALL RIGHTS RESERVED 031// 032// License Grant- 033// 034// 035// Permission to use, copy, modify, and distribute this Software and its 036// documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is 037// hereby granted. 038// 039// This Software is provided "AS IS". All express warranties, including any 040// implied warranty of merchantability, satisfactory quality, fitness for a 041// particular purpose, or non-infringement, are disclaimed, except to the extent 042// that such disclaimers are held to be legally invalid. 043// 044// You acknowledge that Software is not designed, licensed or intended for use in 045// the design, construction, operation or maintenance of any nuclear facility 046// ("High Risk Activities"). Sun disclaims any express or implied warranty of 047// fitness for such uses. 048// 049// Please refer to the file http://www.sun.com/policies/trademarks/ for further 050// important trademark information and to 051// http://java.sun.com/nav/business/index.html for further important licensing 052// information for the Java Technology. 053// 054 055package org.opencms.util; 056 057import org.opencms.main.CmsIllegalArgumentException; 058 059import java.text.DecimalFormatSymbols; 060import java.util.Enumeration; 061import java.util.Locale; 062import java.util.Vector; 063 064/** 065 * PrintfFormat allows the formatting of an array of 066 * objects embedded within a string. Primitive types 067 * must be passed using wrapper types. The formatting 068 * is controlled by a control string. 069 *<p> 070 * A control string is a Java string that contains a 071 * control specification. The control specification 072 * starts at the first percent sign (%) in the string, 073 * provided that this percent sign 074 *<ol> 075 *<li>is not escaped protected by a matching % or is 076 * not an escape % character, 077 *<li>is not at the end of the format string, and 078 *<li>precedes a sequence of characters that parses as 079 * a valid control specification. 080 *</ol> 081 *</p><p> 082 * A control specification usually takes the form: 083 *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ 084 * { [hlL] }+ [idfgGoxXeEcs] 085 *</pre> 086 * There are variants of this basic form that are 087 * discussed below.</p> 088 *<p> 089 * The format is composed of zero or more directives 090 * defined as follows: 091 *<ul> 092 *<li>ordinary characters, which are simply copied to 093 * the output stream; 094 *<li>escape sequences, which represent non-graphic 095 * characters; and 096 *<li>conversion specifications, each of which 097 * results in the fetching of zero or more arguments. 098 *</ul></p> 099 *<p> 100 * The results are undefined if there are insufficient 101 * arguments for the format. Usually an unchecked 102 * exception will be thrown. If the format is 103 * exhausted while arguments remain, the excess 104 * arguments are evaluated but are otherwise ignored. 105 * In format strings containing the % form of 106 * conversion specifications, each argument in the 107 * argument list is used exactly once.</p> 108 * <p> 109 * Conversions can be applied to the <code>n</code>th 110 * argument after the format in the argument list, 111 * rather than to the next unused argument. In this 112 * case, the conversion characer % is replaced by the 113 * sequence %<code>n</code>$, where <code>n</code> is 114 * a decimal integer giving the position of the 115 * argument in the argument list.</p> 116 * <p> 117 * In format strings containing the %<code>n</code>$ 118 * form of conversion specifications, each argument 119 * in the argument list is used exactly once.</p> 120 * 121 *<h4>Escape Sequences</h4> 122 *<p> 123 * The following table lists escape sequences and 124 * associated actions on display devices capable of 125 * the action. 126 *<table> 127 *<tr><th align=left>Sequence</th> 128 * <th align=left>Name</th> 129 * <th align=left>Description</th></tr> 130 *<tr><td>\\</td><td>backlash</td><td>None. 131 *</td></tr> 132 *<tr><td>\a</td><td>alert</td><td>Attempts to alert 133 * the user through audible or visible 134 * notification. 135 *</td></tr> 136 *<tr><td>\b</td><td>backspace</td><td>Moves the 137 * printing position to one column before 138 * the current position, unless the 139 * current position is the start of a line. 140 *</td></tr> 141 *<tr><td>\f</td><td>form-feed</td><td>Moves the 142 * printing position to the initial 143 * printing position of the next logical 144 * page. 145 *</td></tr> 146 *<tr><td>\n</td><td>newline</td><td>Moves the 147 * printing position to the start of the 148 * next line. 149 *</td></tr> 150 *<tr><td>\r</td><td>carriage-return</td><td>Moves 151 * the printing position to the start of 152 * the current line. 153 *</td></tr> 154 *<tr><td>\t</td><td>tab</td><td>Moves the printing 155 * position to the next implementation- 156 * defined horizontal tab position. 157 *</td></tr> 158 *<tr><td>\v</td><td>vertical-tab</td><td>Moves the 159 * printing position to the start of the 160 * next implementation-defined vertical 161 * tab position. 162 *</td></tr> 163 *</table></p> 164 *<h4>Conversion Specifications</h4> 165 *<p> 166 * Each conversion specification is introduced by 167 * the percent sign character (%). After the character 168 * %, the following appear in sequence:</p> 169 *<p> 170 * Zero or more flags (in any order), which modify the 171 * meaning of the conversion specification.</p> 172 *<p> 173 * An optional minimum field width. If the converted 174 * value has fewer characters than the field width, it 175 * will be padded with spaces by default on the left; 176 * t will be padded on the right, if the left- 177 * adjustment flag (-), described below, is given to 178 * the field width. The field width takes the form 179 * of a decimal integer. If the conversion character 180 * is s, the field width is the the minimum number of 181 * characters to be printed.</p> 182 *<p> 183 * An optional precision that gives the minumum number 184 * of digits to appear for the d, i, o, x or X 185 * conversions (the field is padded with leading 186 * zeros); the number of digits to appear after the 187 * radix character for the e, E, and f conversions, 188 * the maximum number of significant digits for the g 189 * and G conversions; or the maximum number of 190 * characters to be written from a string is s and S 191 * conversions. The precision takes the form of an 192 * optional decimal digit string, where a null digit 193 * string is treated as 0. If a precision appears 194 * with a c conversion character the precision is 195 * ignored. 196 * </p> 197 *<p> 198 * An optional h specifies that a following d, i, o, 199 * x, or X conversion character applies to a type 200 * short argument (the argument will be promoted 201 * according to the integral promotions and its value 202 * converted to type short before printing).</p> 203 *<p> 204 * An optional l (ell) specifies that a following 205 * d, i, o, x, or X conversion character applies to a 206 * type long argument.</p> 207 *<p> 208 * A field width or precision may be indicated by an 209 * asterisk (*) instead of a digit string. In this 210 * case, an integer argument supplised the field width 211 * precision. The argument that is actually converted 212 * is not fetched until the conversion letter is seen, 213 * so the the arguments specifying field width or 214 * precision must appear before the argument (if any) 215 * to be converted. If the precision argument is 216 * negative, it will be changed to zero. A negative 217 * field width argument is taken as a - flag, followed 218 * by a positive field width.</p> 219 * <p> 220 * In format strings containing the %<code>n</code>$ 221 * form of a conversion specification, a field width 222 * or precision may be indicated by the sequence 223 * *<code>m</code>$, where m is a decimal integer 224 * giving the position in the argument list (after the 225 * format argument) of an integer argument containing 226 * the field width or precision.</p> 227 * <p> 228 * The format can contain either numbered argument 229 * specifications (that is, %<code>n</code>$ and 230 * *<code>m</code>$), or unnumbered argument 231 * specifications (that is % and *), but normally not 232 * both. The only exception to this is that %% can 233 * be mixed with the %<code>n</code>$ form. The 234 * results of mixing numbered and unnumbered argument 235 * specifications in a format string are undefined.</p> 236 * 237 *<h4>Flag Characters</h4> 238 *<p> 239 * The flags and their meanings are:</p> 240 *<dl> 241 * <dt>'<dd> integer portion of the result of a 242 * decimal conversion (%i, %d, %f, %g, or %G) will 243 * be formatted with thousands' grouping 244 * characters. For other conversions the flag 245 * is ignored. The non-monetary grouping 246 * character is used. 247 * <dt>-<dd> result of the conversion is left-justified 248 * within the field. (It will be right-justified 249 * if this flag is not specified). 250 * <dt>+<dd> result of a signed conversion always 251 * begins with a sign (+ or -). (It will begin 252 * with a sign only when a negative value is 253 * converted if this flag is not specified.) 254 * <dt><space><dd> If the first character of a 255 * signed conversion is not a sign, a space 256 * character will be placed before the result. 257 * This means that if the space character and + 258 * flags both appear, the space flag will be 259 * ignored. 260 * <dt>#<dd> value is to be converted to an alternative 261 * form. For c, d, i, and s conversions, the flag 262 * has no effect. For o conversion, it increases 263 * the precision to force the first digit of the 264 * result to be a zero. For x or X conversion, a 265 * non-zero result has 0x or 0X prefixed to it, 266 * respectively. For e, E, f, g, and G 267 * conversions, the result always contains a radix 268 * character, even if no digits follow the radix 269 * character (normally, a decimal point appears in 270 * the result of these conversions only if a digit 271 * follows it). For g and G conversions, trailing 272 * zeros will not be removed from the result as 273 * they normally are. 274 * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G 275 * conversions, leading zeros (following any 276 * indication of sign or base) are used to pad to 277 * the field width; no space padding is 278 * performed. If the 0 and - flags both appear, 279 * the 0 flag is ignored. For d, i, o, x, and X 280 * conversions, if a precision is specified, the 281 * 0 flag will be ignored. For c conversions, 282 * the flag is ignored. 283 *</dl> 284 * 285 *<h4>Conversion Characters</h4> 286 *<p> 287 * Each conversion character results in fetching zero 288 * or more arguments. The results are undefined if 289 * there are insufficient arguments for the format. 290 * Usually, an unchecked exception will be thrown. 291 * If the format is exhausted while arguments remain, 292 * the excess arguments are ignored.</p> 293 * 294 *<p> 295 * The conversion characters and their meanings are: 296 *</p> 297 *<dl> 298 * <dt>d,i<dd>The int argument is converted to a 299 * signed decimal in the style [-]dddd. The 300 * precision specifies the minimum number of 301 * digits to appear; if the value being 302 * converted can be represented in fewer 303 * digits, it will be expanded with leading 304 * zeros. The default precision is 1. The 305 * result of converting 0 with an explicit 306 * precision of 0 is no characters. 307 * <dt>o<dd> The int argument is converted to unsigned 308 * octal format in the style ddddd. The 309 * precision specifies the minimum number of 310 * digits to appear; if the value being 311 * converted can be represented in fewer 312 * digits, it will be expanded with leading 313 * zeros. The default precision is 1. The 314 * result of converting 0 with an explicit 315 * precision of 0 is no characters. 316 * <dt>x<dd> The int argument is converted to unsigned 317 * hexadecimal format in the style dddd; the 318 * letters abcdef are used. The precision 319 * specifies the minimum numberof digits to 320 * appear; if the value being converted can be 321 * represented in fewer digits, it will be 322 * expanded with leading zeros. The default 323 * precision is 1. The result of converting 0 324 * with an explicit precision of 0 is no 325 * characters. 326 * <dt>X<dd> Behaves the same as the x conversion 327 * character except that letters ABCDEF are 328 * used instead of abcdef. 329 * <dt>f<dd> The floating point number argument is 330 * written in decimal notation in the style 331 * [-]ddd.ddd, where the number of digits after 332 * the radix character (shown here as a decimal 333 * point) is equal to the precision 334 * specification. A Locale is used to determine 335 * the radix character to use in this format. 336 * If the precision is omitted from the 337 * argument, six digits are written after the 338 * radix character; if the precision is 339 * explicitly 0 and the # flag is not specified, 340 * no radix character appears. If a radix 341 * character appears, at least 1 digit appears 342 * before it. The value is rounded to the 343 * appropriate number of digits. 344 * <dt>e,E<dd>The floating point number argument is 345 * written in the style [-]d.ddde{+-}dd 346 * (the symbols {+-} indicate either a plus or 347 * minus sign), where there is one digit before 348 * the radix character (shown here as a decimal 349 * point) and the number of digits after it is 350 * equal to the precision. A Locale is used to 351 * determine the radix character to use in this 352 * format. When the precision is missing, six 353 * digits are written after the radix character; 354 * if the precision is 0 and the # flag is not 355 * specified, no radix character appears. The 356 * E conversion will produce a number with E 357 * instead of e introducing the exponent. The 358 * exponent always contains at least two digits. 359 * However, if the value to be written requires 360 * an exponent greater than two digits, 361 * additional exponent digits are written as 362 * necessary. The value is rounded to the 363 * appropriate number of digits. 364 * <dt>g,G<dd>The floating point number argument is 365 * written in style f or e (or in sytle E in the 366 * case of a G conversion character), with the 367 * precision specifying the number of 368 * significant digits. If the precision is 369 * zero, it is taken as one. The style used 370 * depends on the value converted: style e 371 * (or E) will be used only if the exponent 372 * resulting from the conversion is less than 373 * -4 or greater than or equal to the precision. 374 * Trailing zeros are removed from the result. 375 * A radix character appears only if it is 376 * followed by a digit. 377 * <dt>c,C<dd>The integer argument is converted to a 378 * char and the result is written. 379 * 380 * <dt>s,S<dd>The argument is taken to be a string and 381 * bytes from the string are written until the 382 * end of the string or the number of bytes 383 * indicated by the precision specification of 384 * the argument is reached. If the precision 385 * is omitted from the argument, it is taken to 386 * be infinite, so all characters up to the end 387 * of the string are written. 388 * <dt>%<dd>Write a % character; no argument is 389 * converted. 390 *</dl> 391 *<p> 392 * If a conversion specification does not match one of 393 * the above forms, an IllegalArgumentException is 394 * thrown and the instance of PrintfFormat is not 395 * created.</p> 396 *<p> 397 * If a floating point value is the internal 398 * representation for infinity, the output is 399 * [+]Infinity, where Infinity is either Infinity or 400 * Inf, depending on the desired output string length. 401 * Printing of the sign follows the rules described 402 * above.</p> 403 *<p> 404 * If a floating point value is the internal 405 * representation for "not-a-number," the output is 406 * [+]NaN. Printing of the sign follows the rules 407 * described above.</p> 408 *<p> 409 * In no case does a non-existent or small field width 410 * cause truncation of a field; if the result of a 411 * conversion is wider than the field width, the field 412 * is simply expanded to contain the conversion result. 413 *</p> 414 *<p> 415 * The behavior is like printf. One exception is that 416 * the minimum number of exponent digits is 3 instead 417 * of 2 for e and E formats when the optional L is used 418 * before the e, E, g, or G conversion character. The 419 * optional L does not imply conversion to a long long 420 * double. </p> 421 * <p> 422 * The biggest divergence from the C printf 423 * specification is in the use of 16 bit characters. 424 * This allows the handling of characters beyond the 425 * small ASCII character set and allows the utility to 426 * interoperate correctly with the rest of the Java 427 * runtime environment.</p> 428 *<p> 429 * Omissions from the C printf specification are 430 * numerous. All the known omissions are present 431 * because Java never uses bytes to represent 432 * characters and does not have pointers:</p> 433 *<ul> 434 * <li>%c is the same as %C. 435 * <li>%s is the same as %S. 436 * <li>u, p, and n conversion characters. 437 * <li>%ws format. 438 * <li>h modifier applied to an n conversion character. 439 * <li>l (ell) modifier applied to the c, n, or s 440 * conversion characters. 441 * <li>ll (ell ell) modifier to d, i, o, u, x, or X 442 * conversion characters. 443 * <li>ll (ell ell) modifier to an n conversion 444 * character. 445 * <li>c, C, d,i,o,u,x, and X conversion characters 446 * apply to Byte, Character, Short, Integer, Long 447 * types. 448 * <li>f, e, E, g, and G conversion characters apply 449 * to Float and Double types. 450 * <li>s and S conversion characters apply to String 451 * types. 452 * <li>All other reference types can be formatted 453 * using the s or S conversion characters only. 454 *</ul> 455 * <p> 456 * Most of this specification is quoted from the Unix 457 * man page for the sprintf utility.</p> 458 * 459 * @since 6.0.0 460 */ 461public class PrintfFormat { 462 463 /** 464 *<p> 465 * ConversionSpecification allows the formatting of 466 * a single primitive or object embedded within a 467 * string. The formatting is controlled by a 468 * format string. Only one Java primitive or 469 * object can be formatted at a time. 470 *<p> 471 * A format string is a Java string that contains 472 * a control string. The control string starts at 473 * the first percent sign (%) in the string, 474 * provided that this percent sign 475 *<ol> 476 *<li>is not escaped protected by a matching % or 477 * is not an escape % character, 478 *<li>is not at the end of the format string, and 479 *<li>precedes a sequence of characters that parses 480 * as a valid control string. 481 *</ol> 482 *<p> 483 * A control string takes the form: 484 *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+ 485 * { [hlL] }+ [idfgGoxXeEcs] 486 *</pre> 487 *<p> 488 * The behavior is like printf. One (hopefully the 489 * only) exception is that the minimum number of 490 * exponent digits is 3 instead of 2 for e and E 491 * formats when the optional L is used before the 492 * e, E, g, or G conversion character. The 493 * optional L does not imply conversion to a long 494 * long double. 495 */ 496 private final class ConversionSpecification { 497 498 /** Default precision. */ 499 private static final int DEFAULT_DIGITS = 6; 500 501 /** 502 * For an o conversion, increase the precision to 503 * force the first digit of the result to be a 504 * zero. For x (or X) conversions, a non-zero 505 * result will have 0x (or 0X) prepended to it. 506 * For e, E, f, g, or G conversions, the result 507 * will always contain a radix character, even if 508 * no digits follow the point. For g and G 509 * conversions, trailing zeros will not be removed 510 * from the result. 511 */ 512 private boolean m_alternateForm; 513 514 /** Internal variable. */ 515 private int m_argumentPosition; 516 517 /** Internal variable. */ 518 private int m_argumentPositionForFieldWidth; 519 520 /** Internal variable. */ 521 private int m_argumentPositionForPrecision; 522 523 /** Control string type. */ 524 private char m_conversionCharacter; 525 526 /** 527 * If the converted value has fewer bytes than the 528 * field width, it will be padded with spaces or 529 * zeroes. 530 */ 531 private int m_fieldWidth; 532 533 /** 534 * Flag indicating whether or not the field width 535 * has been set. 536 */ 537 private boolean m_fieldWidthSet; 538 539 /** Literal or control format string. */ 540 private String m_fmt; 541 542 /** 543 * The result of a signed conversion will always 544 * begin with a sign (+ or -). 545 */ 546 private boolean m_leadingSign; 547 548 /** 549 * Flag indicating that left padding with spaces is 550 * specified. 551 */ 552 private boolean m_leadingSpace; 553 554 /** 555 * Flag indicating that left padding with zeroes is 556 * specified. 557 */ 558 private boolean m_leadingZeros; 559 560 /** 561 * The result of the conversion will be 562 * left-justified within the field. 563 */ 564 private boolean m_leftJustify; 565 566 /** 567 * Flag specifying that a following d, i, o, u, x, 568 * or X conversion character applies to a type 569 * short int. 570 */ 571 private boolean m_optionalh; 572 573 /** 574 * Flag specifying that a following d, i, o, u, x, 575 * or X conversion character applies to a type lont 576 * int argument. 577 */ 578 private boolean m_optionall; 579 580 /** 581 * Flag specifying that a following e, E, f, g, or 582 * G conversion character applies to a type double 583 * argument. This is a noop in Java. 584 */ 585 private boolean m_optionalL; 586 587 /** 588 * Position within the control string. Used by 589 * the constructor. 590 */ 591 private int m_pos; 592 593 /** Internal variable. */ 594 private boolean m_positionalFieldWidth; 595 596 /** Internal variable. */ 597 private boolean m_positionalPrecision; 598 599 /** Internal variable. */ 600 private boolean m_positionalSpecification; 601 602 /** 603 * The minimum number of digits to appear for the 604 * d, i, o, u, x, or X conversions. The number of 605 * digits to appear after the radix character for 606 * the e, E, and f conversions. The maximum number 607 * of significant digits for the g and G 608 * conversions. The maximum number of bytes to be 609 * printed from a string in s and S conversions. 610 */ 611 private int m_precision; 612 613 /** 614 * Flag indicating whether or not the precision has 615 * been set. 616 */ 617 private boolean m_precisionSet; 618 619 /** 620 * The integer portion of the result of a decimal 621 * conversion (i, d, u, f, g, or G) will be 622 * formatted with thousands' grouping characters. 623 * For other conversions the flag is ignored. 624 */ 625 private boolean m_thousands; 626 627 /** 628 * Flag indicating that the field width is *. 629 */ 630 private boolean m_variableFieldWidth; 631 632 /** 633 * Flag indicating that the precision is *. 634 */ 635 private boolean m_variablePrecision; 636 637 /** 638 * Constructor. Used to prepare an instance 639 * to hold a literal, not a control string. 640 */ 641 ConversionSpecification() { 642 643 // empty 644 } 645 646 /** 647 * Constructor for a conversion specification. 648 * The argument must begin with a % and end 649 * with the conversion character for the 650 * conversion specification. 651 * @param fmtArg String specifying the 652 * conversion specification. 653 * @exception CmsIllegalArgumentException if the 654 * input string is null, zero length, or 655 * otherwise malformed. 656 */ 657 ConversionSpecification(String fmtArg) 658 throws CmsIllegalArgumentException { 659 660 if (fmtArg == null) { 661 throw new NullPointerException(); 662 } 663 if (fmtArg.length() == 0) { 664 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_CONTROL_STRING_LENGTH_0)); 665 } 666 if (fmtArg.charAt(0) == '%') { 667 m_fmt = fmtArg; 668 m_pos = 1; 669 setArgPosition(); 670 setFlagCharacters(); 671 setFieldWidth(); 672 setPrecision(); 673 setOptionalHL(); 674 if (setConversionCharacter()) { 675 if (m_pos == fmtArg.length()) { 676 if (m_leadingZeros && m_leftJustify) { 677 m_leadingZeros = false; 678 } 679 if (m_precisionSet && m_leadingZeros) { 680 if ((m_conversionCharacter == 'd') 681 || (m_conversionCharacter == 'i') 682 || (m_conversionCharacter == 'o') 683 || (m_conversionCharacter == 'x')) { 684 m_leadingZeros = false; 685 } 686 } 687 } else { 688 throw new CmsIllegalArgumentException( 689 Messages.get().container(Messages.ERR_INVALID_CONVERSION_SPEC_1, fmtArg)); 690 } 691 } else { 692 throw new CmsIllegalArgumentException( 693 Messages.get().container(Messages.ERR_INVALID_CONVERSION_SPEC_1, fmtArg)); 694 } 695 } else { 696 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_CONTROL_STRING_START_0)); 697 } 698 } 699 700 /** 701 * Internal helper.<p> 702 * 703 * @return the result 704 */ 705 int getArgumentPosition() { 706 707 return m_argumentPosition; 708 } 709 710 /** 711 * Internal helper.<p> 712 * 713 * @return the result 714 */ 715 int getArgumentPositionForFieldWidth() { 716 717 return m_argumentPositionForFieldWidth; 718 } 719 720 /** 721 * Internal helper.<p> 722 * 723 * @return the result 724 */ 725 int getArgumentPositionForPrecision() { 726 727 return m_argumentPositionForPrecision; 728 } 729 730 /** 731 * Get the conversion character that tells what 732 * type of control character this instance has. 733 * 734 * @return the conversion character. 735 */ 736 char getConversionCharacter() { 737 738 return m_conversionCharacter; 739 } 740 741 /** 742 * Get the String for this instance. Translate 743 * any escape sequences. 744 * 745 * @return s the stored String. 746 */ 747 String getLiteral() { 748 749 StringBuffer sb = new StringBuffer(); 750 int i = 0; 751 while (i < m_fmt.length()) { 752 if (m_fmt.charAt(i) == '\\') { 753 i++; 754 if (i < m_fmt.length()) { 755 char c = m_fmt.charAt(i); 756 switch (c) { 757 case 'a': 758 sb.append((char)0x07); 759 break; 760 case 'b': 761 sb.append('\b'); 762 break; 763 case 'f': 764 sb.append('\f'); 765 break; 766 case 'n': 767 sb.append(System.getProperty("line.separator")); 768 break; 769 case 'r': 770 sb.append('\r'); 771 break; 772 case 't': 773 sb.append('\t'); 774 break; 775 case 'v': 776 sb.append((char)0x0b); 777 break; 778 case '\\': 779 sb.append('\\'); 780 break; 781 default: 782 // noop 783 } 784 i++; 785 } else { 786 sb.append('\\'); 787 } 788 } else { 789 i++; 790 } 791 } 792 return m_fmt; 793 } 794 795 /** 796 * Format a double argument using this conversion 797 * specification. 798 * @param s the double to format. 799 * @return the formatted String. 800 * @exception CmsIllegalArgumentException if the 801 * conversion character is c, C, s, S, i, d, 802 * x, X, or o. 803 */ 804 String internalsprintf(double s) throws CmsIllegalArgumentException { 805 806 String s2 = ""; 807 switch (m_conversionCharacter) { 808 case 'f': 809 s2 = printFFormat(s); 810 break; 811 case 'E': 812 case 'e': 813 s2 = printEFormat(s); 814 break; 815 case 'G': 816 case 'g': 817 s2 = printGFormat(s); 818 break; 819 default: 820 throw new CmsIllegalArgumentException(Messages.get().container( 821 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 822 "double", 823 Character.valueOf(m_conversionCharacter))); 824 } 825 return s2; 826 } 827 828 /** 829 * Format an int argument using this conversion 830 * specification. 831 * @param s the int to format. 832 * @return the formatted String. 833 * @exception CmsIllegalArgumentException if the 834 * conversion character is f, e, E, g, or G. 835 */ 836 String internalsprintf(int s) throws CmsIllegalArgumentException { 837 838 String s2 = ""; 839 switch (m_conversionCharacter) { 840 case 'd': 841 case 'i': 842 if (m_optionalh) { 843 s2 = printDFormat((short)s); 844 } else if (m_optionall) { 845 s2 = printDFormat((long)s); 846 } else { 847 s2 = printDFormat(s); 848 } 849 break; 850 case 'x': 851 case 'X': 852 if (m_optionalh) { 853 s2 = printXFormat((short)s); 854 } else if (m_optionall) { 855 s2 = printXFormat((long)s); 856 } else { 857 s2 = printXFormat(s); 858 } 859 break; 860 case 'o': 861 if (m_optionalh) { 862 s2 = printOFormat((short)s); 863 } else if (m_optionall) { 864 s2 = printOFormat((long)s); 865 } else { 866 s2 = printOFormat(s); 867 } 868 break; 869 case 'c': 870 case 'C': 871 s2 = printCFormat((char)s); 872 break; 873 default: 874 throw new CmsIllegalArgumentException(Messages.get().container( 875 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 876 "int", 877 Character.valueOf(m_conversionCharacter))); 878 } 879 return s2; 880 } 881 882 /** 883 * Format a long argument using this conversion 884 * specification. 885 * @param s the long to format. 886 * @return the formatted String. 887 * @exception CmsIllegalArgumentException if the 888 * conversion character is f, e, E, g, or G. 889 */ 890 String internalsprintf(long s) throws CmsIllegalArgumentException { 891 892 String s2 = ""; 893 switch (m_conversionCharacter) { 894 case 'd': 895 case 'i': 896 if (m_optionalh) { 897 s2 = printDFormat((short)s); 898 } else if (m_optionall) { 899 s2 = printDFormat(s); 900 } else { 901 s2 = printDFormat((int)s); 902 } 903 break; 904 case 'x': 905 case 'X': 906 if (m_optionalh) { 907 s2 = printXFormat((short)s); 908 } else if (m_optionall) { 909 s2 = printXFormat(s); 910 } else { 911 s2 = printXFormat((int)s); 912 } 913 break; 914 case 'o': 915 if (m_optionalh) { 916 s2 = printOFormat((short)s); 917 } else if (m_optionall) { 918 s2 = printOFormat(s); 919 } else { 920 s2 = printOFormat((int)s); 921 } 922 break; 923 case 'c': 924 case 'C': 925 s2 = printCFormat((char)s); 926 break; 927 default: 928 throw new CmsIllegalArgumentException(Messages.get().container( 929 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 930 "long", 931 Character.valueOf(m_conversionCharacter))); 932 } 933 return s2; 934 } 935 936 /** 937 * Format an Object argument using this conversion 938 * specification. 939 * @param s the Object to format. 940 * @return the formatted String. 941 * @exception CmsIllegalArgumentException if the 942 * conversion character is neither s nor S. 943 */ 944 String internalsprintf(Object s) throws CmsIllegalArgumentException { 945 946 String s2 = ""; 947 if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) { 948 s2 = printSFormat(s.toString()); 949 } else { 950 throw new CmsIllegalArgumentException( 951 Messages.get().container( 952 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 953 "String", 954 Character.valueOf(m_conversionCharacter))); 955 } 956 return s2; 957 } 958 959 /** 960 * Format a String argument using this conversion 961 * specification. 962 * @param s the String to format. 963 * @return the formatted String. 964 * @exception CmsIllegalArgumentException if the 965 * conversion character is neither s nor S. 966 */ 967 String internalsprintf(String s) throws CmsIllegalArgumentException { 968 969 String s2 = ""; 970 if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) { 971 s2 = printSFormat(s); 972 } else { 973 throw new CmsIllegalArgumentException(Messages.get().container( 974 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 975 "String", 976 Character.valueOf(m_conversionCharacter))); 977 } 978 return s2; 979 } 980 981 /** 982 * Internal helper.<p> 983 * 984 * @return the result 985 */ 986 boolean isPositionalFieldWidth() { 987 988 return m_positionalFieldWidth; 989 } 990 991 /** 992 * Internal helper.<p> 993 * 994 * @return the result 995 */ 996 boolean isPositionalPrecision() { 997 998 return m_positionalPrecision; 999 } 1000 1001 /** 1002 * Internal helper.<p> 1003 * 1004 * @return the result 1005 */ 1006 boolean isPositionalSpecification() { 1007 1008 return m_positionalSpecification; 1009 } 1010 1011 /** 1012 * Check whether the specifier has a variable 1013 * field width that is going to be set by an 1014 * argument. 1015 * @return <code>true</code> if the conversion 1016 * uses an * field width; otherwise 1017 * <code>false</code>. 1018 */ 1019 boolean isVariableFieldWidth() { 1020 1021 return m_variableFieldWidth; 1022 } 1023 1024 /** 1025 * Check whether the specifier has a variable 1026 * precision that is going to be set by an 1027 * argument. 1028 * @return <code>true</code> if the conversion 1029 * uses an * precision; otherwise 1030 * <code>false</code>. 1031 */ 1032 boolean isVariablePrecision() { 1033 1034 return m_variablePrecision; 1035 } 1036 1037 /** 1038 * Set the field width with an argument. A 1039 * negative field width is taken as a - flag 1040 * followed by a positive field width. 1041 * @param fw the field width. 1042 */ 1043 void setFieldWidthWithArg(int fw) { 1044 1045 if (fw < 0) { 1046 m_leftJustify = true; 1047 } 1048 m_fieldWidthSet = true; 1049 m_fieldWidth = Math.abs(fw); 1050 } 1051 1052 /** 1053 * Set the String for this instance. 1054 * @param s the String to store. 1055 */ 1056 void setLiteral(String s) { 1057 1058 m_fmt = s; 1059 } 1060 1061 /** 1062 * Set the precision with an argument. A 1063 * negative precision will be changed to zero. 1064 * @param pr the precision. 1065 */ 1066 void setPrecisionWithArg(int pr) { 1067 1068 m_precisionSet = true; 1069 m_precision = Math.max(pr, 0); 1070 } 1071 1072 /** 1073 * Apply zero or blank, left or right padding. 1074 * @param ca4 array of characters before padding is 1075 * finished 1076 * @param noDigits NaN or signed Inf 1077 * @return a padded array of characters 1078 */ 1079 private char[] applyFloatPadding(char[] ca4, boolean noDigits) { 1080 1081 char[] ca5 = ca4; 1082 if (m_fieldWidthSet) { 1083 int i, j, nBlanks; 1084 if (m_leftJustify) { 1085 nBlanks = m_fieldWidth - ca4.length; 1086 if (nBlanks > 0) { 1087 ca5 = new char[ca4.length + nBlanks]; 1088 for (i = 0; i < ca4.length; i++) { 1089 ca5[i] = ca4[i]; 1090 } 1091 for (j = 0; j < nBlanks; j++, i++) { 1092 ca5[i] = ' '; 1093 } 1094 } 1095 } else if (!m_leadingZeros || noDigits) { 1096 nBlanks = m_fieldWidth - ca4.length; 1097 if (nBlanks > 0) { 1098 ca5 = new char[ca4.length + nBlanks]; 1099 for (i = 0; i < nBlanks; i++) { 1100 ca5[i] = ' '; 1101 } 1102 for (j = 0; j < ca4.length; i++, j++) { 1103 ca5[i] = ca4[j]; 1104 } 1105 } 1106 } else if (m_leadingZeros) { 1107 nBlanks = m_fieldWidth - ca4.length; 1108 if (nBlanks > 0) { 1109 ca5 = new char[ca4.length + nBlanks]; 1110 i = 0; 1111 j = 0; 1112 if (ca4[0] == '-') { 1113 ca5[0] = '-'; 1114 i++; 1115 j++; 1116 } 1117 for (int k = 0; k < nBlanks; i++, k++) { 1118 ca5[i] = '0'; 1119 } 1120 for (; j < ca4.length; i++, j++) { 1121 ca5[i] = ca4[j]; 1122 } 1123 } 1124 } 1125 } 1126 return ca5; 1127 } 1128 1129 /** 1130 * Check to see if the digits that are going to 1131 * be truncated because of the precision should 1132 * force a round in the preceding digits. 1133 * @param ca1 the array of digits 1134 * @param icarry the index of the first digit that 1135 * is to be truncated from the print 1136 * @return <code>true</code> if the truncation forces 1137 * a round that will change the print 1138 */ 1139 private boolean checkForCarry(char[] ca1, int icarry) { 1140 1141 boolean carry = false; 1142 if (icarry < ca1.length) { 1143 if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) { 1144 carry = true; 1145 } else if (ca1[icarry] == '5') { 1146 int ii = icarry + 1; 1147 for (; ii < ca1.length; ii++) { 1148 if (ca1[ii] != '0') { 1149 break; 1150 } 1151 } 1152 carry = ii < ca1.length; 1153 if (!carry && (icarry > 0)) { 1154 carry = ((ca1[icarry - 1] == '1') 1155 || (ca1[icarry - 1] == '3') 1156 || (ca1[icarry - 1] == '5') 1157 || (ca1[icarry - 1] == '7') 1158 || (ca1[icarry - 1] == '9')); 1159 } 1160 } 1161 } 1162 return carry; 1163 } 1164 1165 /** 1166 * For e format, the flag character '-', means that 1167 * the output should be left justified within the 1168 * field. The default is to pad with blanks on the 1169 * left. '+' character means that the conversion 1170 * will always begin with a sign (+ or -). The 1171 * blank flag character means that a non-negative 1172 * input will be preceded with a blank. If both a 1173 * '+' and a ' ' are specified, the blank flag is 1174 * ignored. The '0' flag character implies that 1175 * padding to the field width will be done with 1176 * zeros instead of blanks. 1177 * 1178 * The field width is treated as the minimum number 1179 * of characters to be printed. The default is to 1180 * add no padding. Padding is with blanks by 1181 * default. 1182 * 1183 * The precision, if set, is the minimum number of 1184 * digits to appear after the radix character. 1185 * Padding is with trailing 0s. 1186 * 1187 * The behavior is like printf. One (hopefully the 1188 * only) exception is that the minimum number of 1189 * exponent digits is 3 instead of 2 for e and E 1190 * formats when the optional L is used before the 1191 * e, E, g, or G conversion character. The optional 1192 * L does not imply conversion to a long long 1193 * double. 1194 * 1195 * @param x the x parameter 1196 * @param eChar the eChar parameter 1197 * @return the result 1198 */ 1199 private char[] eFormatDigits(double x, char eChar) { 1200 1201 char[] ca1, ca2, ca3; 1202 // int defaultDigits=6; 1203 String sx; 1204 int i, j, k, p; 1205 int expon = 0; 1206 int ePos, rPos, eSize; 1207 boolean minusSign = false; 1208 if (x > 0.0) { 1209 sx = Double.toString(x); 1210 } else if (x < 0.0) { 1211 sx = Double.toString(-x); 1212 minusSign = true; 1213 } else { 1214 sx = Double.toString(x); 1215 if (sx.charAt(0) == '-') { 1216 minusSign = true; 1217 sx = sx.substring(1); 1218 } 1219 } 1220 ePos = sx.indexOf('E'); 1221 if (ePos == -1) { 1222 ePos = sx.indexOf('e'); 1223 } 1224 rPos = sx.indexOf('.'); 1225 if (ePos != -1) { 1226 int ie = ePos + 1; 1227 expon = 0; 1228 if (sx.charAt(ie) == '-') { 1229 for (++ie; ie < sx.length(); ie++) { 1230 if (sx.charAt(ie) != '0') { 1231 break; 1232 } 1233 } 1234 if (ie < sx.length()) { 1235 expon = -Integer.parseInt(sx.substring(ie)); 1236 } 1237 } else { 1238 if (sx.charAt(ie) == '+') { 1239 ++ie; 1240 } 1241 for (; ie < sx.length(); ie++) { 1242 if (sx.charAt(ie) != '0') { 1243 break; 1244 } 1245 } 1246 if (ie < sx.length()) { 1247 expon = Integer.parseInt(sx.substring(ie)); 1248 } 1249 } 1250 } 1251 if (rPos != -1) { 1252 expon += rPos - 1; 1253 } 1254 if (m_precisionSet) { 1255 p = m_precision; 1256 } else { 1257 p = DEFAULT_DIGITS - 1; 1258 } 1259 if ((rPos != -1) && (ePos != -1)) { 1260 ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray(); 1261 } else if (rPos != -1) { 1262 ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray(); 1263 } else if (ePos != -1) { 1264 ca1 = sx.substring(0, ePos).toCharArray(); 1265 } else { 1266 ca1 = sx.toCharArray(); 1267 } 1268 boolean carry = false; 1269 int i0 = 0; 1270 if (ca1[0] != '0') { 1271 i0 = 0; 1272 } else { 1273 for (i0 = 0; i0 < ca1.length; i0++) { 1274 if (ca1[i0] != '0') { 1275 break; 1276 } 1277 } 1278 } 1279 if ((i0 + p) < (ca1.length - 1)) { 1280 carry = checkForCarry(ca1, i0 + p + 1); 1281 if (carry) { 1282 carry = startSymbolicCarry(ca1, i0 + p, i0); 1283 } 1284 if (carry) { 1285 ca2 = new char[i0 + p + 1]; 1286 ca2[i0] = '1'; 1287 for (j = 0; j < i0; j++) { 1288 ca2[j] = '0'; 1289 } 1290 for (i = i0, j = i0 + 1; j < (p + 1); i++, j++) { 1291 ca2[j] = ca1[i]; 1292 } 1293 expon++; 1294 ca1 = ca2; 1295 } 1296 } 1297 if ((Math.abs(expon) < 100) && !m_optionalL) { 1298 eSize = 4; 1299 } else { 1300 eSize = 5; 1301 } 1302 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1303 ca2 = new char[2 + p + eSize]; 1304 } else { 1305 ca2 = new char[1 + eSize]; 1306 } 1307 if (ca1[0] != '0') { 1308 ca2[0] = ca1[0]; 1309 j = 1; 1310 } else { 1311 for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++) { 1312 if (ca1[j] != '0') { 1313 break; 1314 } 1315 } 1316 if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) { 1317 ca2[0] = ca1[j]; 1318 expon -= j; 1319 j++; 1320 } else { 1321 ca2[0] = '0'; 1322 j = 2; 1323 } 1324 } 1325 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1326 ca2[1] = '.'; 1327 i = 2; 1328 } else { 1329 i = 1; 1330 } 1331 for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) { 1332 ca2[i] = ca1[j]; 1333 } 1334 for (; i < (ca2.length - eSize); i++) { 1335 ca2[i] = '0'; 1336 } 1337 ca2[i++] = eChar; 1338 if (expon < 0) { 1339 ca2[i++] = '-'; 1340 } else { 1341 ca2[i++] = '+'; 1342 } 1343 expon = Math.abs(expon); 1344 if (expon >= 100) { 1345 switch (expon / 100) { 1346 case 1: 1347 ca2[i] = '1'; 1348 break; 1349 case 2: 1350 ca2[i] = '2'; 1351 break; 1352 case 3: 1353 ca2[i] = '3'; 1354 break; 1355 case 4: 1356 ca2[i] = '4'; 1357 break; 1358 case 5: 1359 ca2[i] = '5'; 1360 break; 1361 case 6: 1362 ca2[i] = '6'; 1363 break; 1364 case 7: 1365 ca2[i] = '7'; 1366 break; 1367 case 8: 1368 ca2[i] = '8'; 1369 break; 1370 case 9: 1371 ca2[i] = '9'; 1372 break; 1373 default: 1374 // noop 1375 } 1376 i++; 1377 } 1378 switch ((expon % 100) / 10) { 1379 case 0: 1380 ca2[i] = '0'; 1381 break; 1382 case 1: 1383 ca2[i] = '1'; 1384 break; 1385 case 2: 1386 ca2[i] = '2'; 1387 break; 1388 case 3: 1389 ca2[i] = '3'; 1390 break; 1391 case 4: 1392 ca2[i] = '4'; 1393 break; 1394 case 5: 1395 ca2[i] = '5'; 1396 break; 1397 case 6: 1398 ca2[i] = '6'; 1399 break; 1400 case 7: 1401 ca2[i] = '7'; 1402 break; 1403 case 8: 1404 ca2[i] = '8'; 1405 break; 1406 case 9: 1407 ca2[i] = '9'; 1408 break; 1409 default: 1410 // noop 1411 } 1412 i++; 1413 switch (expon % 10) { 1414 case 0: 1415 ca2[i] = '0'; 1416 break; 1417 case 1: 1418 ca2[i] = '1'; 1419 break; 1420 case 2: 1421 ca2[i] = '2'; 1422 break; 1423 case 3: 1424 ca2[i] = '3'; 1425 break; 1426 case 4: 1427 ca2[i] = '4'; 1428 break; 1429 case 5: 1430 ca2[i] = '5'; 1431 break; 1432 case 6: 1433 ca2[i] = '6'; 1434 break; 1435 case 7: 1436 ca2[i] = '7'; 1437 break; 1438 case 8: 1439 ca2[i] = '8'; 1440 break; 1441 case 9: 1442 ca2[i] = '9'; 1443 break; 1444 default: 1445 // noop 1446 } 1447 int nZeros = 0; 1448 if (!m_leftJustify && m_leadingZeros) { 1449 int xThousands = 0; 1450 if (m_thousands) { 1451 int xlead = 0; 1452 if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) { 1453 xlead = 1; 1454 } 1455 int xdp = xlead; 1456 for (; xdp < ca2.length; xdp++) { 1457 if (ca2[xdp] == '.') { 1458 break; 1459 } 1460 } 1461 xThousands = (xdp - xlead) / 3; 1462 } 1463 if (m_fieldWidthSet) { 1464 nZeros = m_fieldWidth - ca2.length; 1465 } 1466 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1467 nZeros--; 1468 } 1469 nZeros -= xThousands; 1470 if (nZeros < 0) { 1471 nZeros = 0; 1472 } 1473 } 1474 j = 0; 1475 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1476 ca3 = new char[ca2.length + nZeros + 1]; 1477 j++; 1478 } else { 1479 ca3 = new char[ca2.length + nZeros]; 1480 } 1481 if (!minusSign) { 1482 if (m_leadingSign) { 1483 ca3[0] = '+'; 1484 } 1485 if (m_leadingSpace) { 1486 ca3[0] = ' '; 1487 } 1488 } else { 1489 ca3[0] = '-'; 1490 } 1491 for (k = 0; k < nZeros; j++, k++) { 1492 ca3[j] = '0'; 1493 } 1494 for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) { 1495 ca3[j] = ca2[i]; 1496 } 1497 1498 int lead = 0; 1499 if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) { 1500 lead = 1; 1501 } 1502 int dp = lead; 1503 for (; dp < ca3.length; dp++) { 1504 if (ca3[dp] == '.') { 1505 break; 1506 } 1507 } 1508 int nThousands = dp / 3; 1509 // Localize the decimal point. 1510 if (dp < ca3.length) { 1511 ca3[dp] = m_dfs.getDecimalSeparator(); 1512 } 1513 char[] ca4 = ca3; 1514 if (m_thousands && (nThousands > 0)) { 1515 ca4 = new char[ca3.length + nThousands + lead]; 1516 ca4[0] = ca3[0]; 1517 for (i = lead, k = lead; i < dp; i++) { 1518 if ((i > 0) && (((dp - i) % 3) == 0)) { 1519 // ca4[k]=','; 1520 ca4[k] = m_dfs.getGroupingSeparator(); 1521 ca4[k + 1] = ca3[i]; 1522 k += 2; 1523 } else { 1524 ca4[k] = ca3[i]; 1525 k++; 1526 } 1527 } 1528 for (; i < ca3.length; i++, k++) { 1529 ca4[k] = ca3[i]; 1530 } 1531 } 1532 return ca4; 1533 } 1534 1535 /** 1536 * An intermediate routine on the way to creating 1537 * an e format String. The method decides whether 1538 * the input double value is an infinity, 1539 * not-a-number, or a finite double and formats 1540 * each type of input appropriately. 1541 * @param x the double value to be formatted. 1542 * @param eChar an 'e' or 'E' to use in the 1543 * converted double value. 1544 * @return the converted double value. 1545 */ 1546 private String eFormatString(double x, char eChar) { 1547 1548 char[] ca4, ca5; 1549 if (Double.isInfinite(x)) { 1550 if (x == Double.POSITIVE_INFINITY) { 1551 if (m_leadingSign) { 1552 ca4 = "+Inf".toCharArray(); 1553 } else if (m_leadingSpace) { 1554 ca4 = " Inf".toCharArray(); 1555 } else { 1556 ca4 = "Inf".toCharArray(); 1557 } 1558 } else { 1559 ca4 = "-Inf".toCharArray(); 1560 } 1561 } else if (Double.isNaN(x)) { 1562 if (m_leadingSign) { 1563 ca4 = "+NaN".toCharArray(); 1564 } else if (m_leadingSpace) { 1565 ca4 = " NaN".toCharArray(); 1566 } else { 1567 ca4 = "NaN".toCharArray(); 1568 } 1569 } else { 1570 ca4 = eFormatDigits(x, eChar); 1571 } 1572 ca5 = applyFloatPadding(ca4, false); 1573 return new String(ca5); 1574 } 1575 1576 /** 1577 * For f format, the flag character '-', means that 1578 * the output should be left justified within the 1579 * field. The default is to pad with blanks on the 1580 * left. '+' character means that the conversion 1581 * will always begin with a sign (+ or -). The 1582 * blank flag character means that a non-negative 1583 * input will be preceded with a blank. If both 1584 * a '+' and a ' ' are specified, the blank flag 1585 * is ignored. The '0' flag character implies that 1586 * padding to the field width will be done with 1587 * zeros instead of blanks. 1588 * 1589 * The field width is treated as the minimum number 1590 * of characters to be printed. The default is to 1591 * add no padding. Padding is with blanks by 1592 * default. 1593 * 1594 * The precision, if set, is the number of digits 1595 * to appear after the radix character. Padding is 1596 * with trailing 0s. 1597 * 1598 * @param x the paramater 1599 * @return the result 1600 */ 1601 private char[] fFormatDigits(double x) { 1602 1603 // int defaultDigits=6; 1604 String sx; 1605 int i, j, k; 1606 int n1In, n2In; 1607 int expon = 0; 1608 boolean minusSign = false; 1609 if (x > 0.0) { 1610 sx = Double.toString(x); 1611 } else if (x < 0.0) { 1612 sx = Double.toString(-x); 1613 minusSign = true; 1614 } else { 1615 sx = Double.toString(x); 1616 if (sx.charAt(0) == '-') { 1617 minusSign = true; 1618 sx = sx.substring(1); 1619 } 1620 } 1621 int ePos = sx.indexOf('E'); 1622 int rPos = sx.indexOf('.'); 1623 if (rPos != -1) { 1624 n1In = rPos; 1625 } else if (ePos != -1) { 1626 n1In = ePos; 1627 } else { 1628 n1In = sx.length(); 1629 } 1630 if (rPos != -1) { 1631 if (ePos != -1) { 1632 n2In = ePos - rPos - 1; 1633 } else { 1634 n2In = sx.length() - rPos - 1; 1635 } 1636 } else { 1637 n2In = 0; 1638 } 1639 if (ePos != -1) { 1640 int ie = ePos + 1; 1641 expon = 0; 1642 if (sx.charAt(ie) == '-') { 1643 for (++ie; ie < sx.length(); ie++) { 1644 if (sx.charAt(ie) != '0') { 1645 break; 1646 } 1647 } 1648 if (ie < sx.length()) { 1649 expon = -Integer.parseInt(sx.substring(ie)); 1650 } 1651 } else { 1652 if (sx.charAt(ie) == '+') { 1653 ++ie; 1654 } 1655 for (; ie < sx.length(); ie++) { 1656 if (sx.charAt(ie) != '0') { 1657 break; 1658 } 1659 } 1660 if (ie < sx.length()) { 1661 expon = Integer.parseInt(sx.substring(ie)); 1662 } 1663 } 1664 } 1665 int p; 1666 if (m_precisionSet) { 1667 p = m_precision; 1668 } else { 1669 p = DEFAULT_DIGITS - 1; 1670 } 1671 char[] ca1 = sx.toCharArray(); 1672 char[] ca2 = new char[n1In + n2In]; 1673 char[] ca3, ca4, ca5; 1674 for (j = 0; j < n1In; j++) { 1675 ca2[j] = ca1[j]; 1676 } 1677 i = j + 1; 1678 for (k = 0; k < n2In; j++, i++, k++) { 1679 ca2[j] = ca1[i]; 1680 } 1681 if ((n1In + expon) <= 0) { 1682 ca3 = new char[-expon + n2In]; 1683 for (j = 0, k = 0; k < (-n1In - expon); k++, j++) { 1684 ca3[j] = '0'; 1685 } 1686 for (i = 0; i < (n1In + n2In); i++, j++) { 1687 ca3[j] = ca2[i]; 1688 } 1689 } else { 1690 ca3 = ca2; 1691 } 1692 boolean carry = false; 1693 if (p < (-expon + n2In)) { 1694 if (expon < 0) { 1695 i = p; 1696 } else { 1697 i = p + n1In; 1698 } 1699 carry = checkForCarry(ca3, i); 1700 if (carry) { 1701 carry = startSymbolicCarry(ca3, i - 1, 0); 1702 } 1703 } 1704 if ((n1In + expon) <= 0) { 1705 ca4 = new char[2 + p]; 1706 if (!carry) { 1707 ca4[0] = '0'; 1708 } else { 1709 ca4[0] = '1'; 1710 } 1711 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1712 ca4[1] = '.'; 1713 for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) { 1714 ca4[j] = ca3[i]; 1715 } 1716 for (; j < ca4.length; j++) { 1717 ca4[j] = '0'; 1718 } 1719 } 1720 } else { 1721 if (!carry) { 1722 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1723 ca4 = new char[n1In + expon + p + 1]; 1724 } else { 1725 ca4 = new char[n1In + expon]; 1726 } 1727 j = 0; 1728 } else { 1729 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1730 ca4 = new char[n1In + expon + p + 2]; 1731 } else { 1732 ca4 = new char[n1In + expon + 1]; 1733 } 1734 ca4[0] = '1'; 1735 j = 1; 1736 } 1737 for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) { 1738 ca4[j] = ca3[i]; 1739 } 1740 for (; i < (n1In + expon); i++, j++) { 1741 ca4[j] = '0'; 1742 } 1743 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1744 ca4[j] = '.'; 1745 j++; 1746 for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) { 1747 ca4[j] = ca3[i]; 1748 } 1749 for (; j < ca4.length; j++) { 1750 ca4[j] = '0'; 1751 } 1752 } 1753 } 1754 int nZeros = 0; 1755 if (!m_leftJustify && m_leadingZeros) { 1756 int xThousands = 0; 1757 if (m_thousands) { 1758 int xlead = 0; 1759 if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) { 1760 xlead = 1; 1761 } 1762 int xdp = xlead; 1763 for (; xdp < ca4.length; xdp++) { 1764 if (ca4[xdp] == '.') { 1765 break; 1766 } 1767 } 1768 xThousands = (xdp - xlead) / 3; 1769 } 1770 if (m_fieldWidthSet) { 1771 nZeros = m_fieldWidth - ca4.length; 1772 } 1773 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1774 nZeros--; 1775 } 1776 nZeros -= xThousands; 1777 if (nZeros < 0) { 1778 nZeros = 0; 1779 } 1780 } 1781 j = 0; 1782 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1783 ca5 = new char[ca4.length + nZeros + 1]; 1784 j++; 1785 } else { 1786 ca5 = new char[ca4.length + nZeros]; 1787 } 1788 if (!minusSign) { 1789 if (m_leadingSign) { 1790 ca5[0] = '+'; 1791 } 1792 if (m_leadingSpace) { 1793 ca5[0] = ' '; 1794 } 1795 } else { 1796 ca5[0] = '-'; 1797 } 1798 for (i = 0; i < nZeros; i++, j++) { 1799 ca5[j] = '0'; 1800 } 1801 for (i = 0; i < ca4.length; i++, j++) { 1802 ca5[j] = ca4[i]; 1803 } 1804 int lead = 0; 1805 if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) { 1806 lead = 1; 1807 } 1808 int dp = lead; 1809 for (; dp < ca5.length; dp++) { 1810 if (ca5[dp] == '.') { 1811 break; 1812 } 1813 } 1814 int nThousands = (dp - lead) / 3; 1815 // Localize the decimal point. 1816 if (dp < ca5.length) { 1817 ca5[dp] = m_dfs.getDecimalSeparator(); 1818 } 1819 char[] ca6 = ca5; 1820 if (m_thousands && (nThousands > 0)) { 1821 ca6 = new char[ca5.length + nThousands + lead]; 1822 ca6[0] = ca5[0]; 1823 for (i = lead, k = lead; i < dp; i++) { 1824 if ((i > 0) && (((dp - i) % 3) == 0)) { 1825 // ca6[k]=','; 1826 ca6[k] = m_dfs.getGroupingSeparator(); 1827 ca6[k + 1] = ca5[i]; 1828 k += 2; 1829 } else { 1830 ca6[k] = ca5[i]; 1831 k++; 1832 } 1833 } 1834 for (; i < ca5.length; i++, k++) { 1835 ca6[k] = ca5[i]; 1836 } 1837 } 1838 return ca6; 1839 } 1840 1841 /** 1842 * An intermediate routine on the way to creating 1843 * an f format String. The method decides whether 1844 * the input double value is an infinity, 1845 * not-a-number, or a finite double and formats 1846 * each type of input appropriately. 1847 * @param x the double value to be formatted. 1848 * @return the converted double value. 1849 */ 1850 private String fFormatString(double x) { 1851 1852 char[] ca6, ca7; 1853 if (Double.isInfinite(x)) { 1854 if (x == Double.POSITIVE_INFINITY) { 1855 if (m_leadingSign) { 1856 ca6 = "+Inf".toCharArray(); 1857 } else if (m_leadingSpace) { 1858 ca6 = " Inf".toCharArray(); 1859 } else { 1860 ca6 = "Inf".toCharArray(); 1861 } 1862 } else { 1863 ca6 = "-Inf".toCharArray(); 1864 } 1865 } else if (Double.isNaN(x)) { 1866 if (m_leadingSign) { 1867 ca6 = "+NaN".toCharArray(); 1868 } else if (m_leadingSpace) { 1869 ca6 = " NaN".toCharArray(); 1870 } else { 1871 ca6 = "NaN".toCharArray(); 1872 } 1873 } else { 1874 ca6 = fFormatDigits(x); 1875 } 1876 ca7 = applyFloatPadding(ca6, false); 1877 return new String(ca7); 1878 } 1879 1880 /** 1881 * Format method for the c conversion character and 1882 * char argument. 1883 * 1884 * The only flag character that affects c format is 1885 * the '-', meaning that the output should be left 1886 * justified within the field. The default is to 1887 * pad with blanks on the left. 1888 * 1889 * The field width is treated as the minimum number 1890 * of characters to be printed. Padding is with 1891 * blanks by default. The default width is 1. 1892 * 1893 * The precision, if set, is ignored. 1894 * @param x the char to format. 1895 * @return the formatted String. 1896 */ 1897 private String printCFormat(char x) { 1898 1899 int nPrint = 1; 1900 int width = m_fieldWidth; 1901 if (!m_fieldWidthSet) { 1902 width = nPrint; 1903 } 1904 char[] ca = new char[width]; 1905 int i = 0; 1906 if (m_leftJustify) { 1907 ca[0] = x; 1908 for (i = 1; i <= (width - nPrint); i++) { 1909 ca[i] = ' '; 1910 } 1911 } else { 1912 for (i = 0; i < (width - nPrint); i++) { 1913 ca[i] = ' '; 1914 } 1915 ca[i] = x; 1916 } 1917 return new String(ca); 1918 } 1919 1920 /** 1921 * Format method for the d conversion character and 1922 * int argument. 1923 * 1924 * For d format, the flag character '-', means that 1925 * the output should be left justified within the 1926 * field. The default is to pad with blanks on the 1927 * left. A '+' character means that the conversion 1928 * will always begin with a sign (+ or -). The 1929 * blank flag character means that a non-negative 1930 * input will be preceded with a blank. If both a 1931 * '+' and a ' ' are specified, the blank flag is 1932 * ignored. The '0' flag character implies that 1933 * padding to the field width will be done with 1934 * zeros instead of blanks. 1935 * 1936 * The field width is treated as the minimum number 1937 * of characters to be printed. The default is to 1938 * add no padding. Padding is with blanks by 1939 * default. 1940 * 1941 * The precision, if set, is the minimum number of 1942 * digits to appear. Padding is with leading 0s. 1943 * @param x the int to format. 1944 * @return the formatted String. 1945 */ 1946 private String printDFormat(int x) { 1947 1948 return printDFormat(Integer.toString(x)); 1949 } 1950 1951 /** 1952 * Format method for the d conversion character and 1953 * long argument. 1954 * 1955 * For d format, the flag character '-', means that 1956 * the output should be left justified within the 1957 * field. The default is to pad with blanks on the 1958 * left. A '+' character means that the conversion 1959 * will always begin with a sign (+ or -). The 1960 * blank flag character means that a non-negative 1961 * input will be preceded with a blank. If both a 1962 * '+' and a ' ' are specified, the blank flag is 1963 * ignored. The '0' flag character implies that 1964 * padding to the field width will be done with 1965 * zeros instead of blanks. 1966 * 1967 * The field width is treated as the minimum number 1968 * of characters to be printed. The default is to 1969 * add no padding. Padding is with blanks by 1970 * default. 1971 * 1972 * The precision, if set, is the minimum number of 1973 * digits to appear. Padding is with leading 0s. 1974 * @param x the long to format. 1975 * @return the formatted String. 1976 */ 1977 private String printDFormat(long x) { 1978 1979 return printDFormat(Long.toString(x)); 1980 } 1981 1982 /** 1983 * Format method for the d conversion specifer and 1984 * short argument. 1985 * 1986 * For d format, the flag character '-', means that 1987 * the output should be left justified within the 1988 * field. The default is to pad with blanks on the 1989 * left. A '+' character means that the conversion 1990 * will always begin with a sign (+ or -). The 1991 * blank flag character means that a non-negative 1992 * input will be preceded with a blank. If both a 1993 * '+' and a ' ' are specified, the blank flag is 1994 * ignored. The '0' flag character implies that 1995 * padding to the field width will be done with 1996 * zeros instead of blanks. 1997 * 1998 * The field width is treated as the minimum number 1999 * of characters to be printed. The default is to 2000 * add no padding. Padding is with blanks by 2001 * default. 2002 * 2003 * The precision, if set, is the minimum number of 2004 * digits to appear. Padding is with leading 0s. 2005 * @param x the short to format. 2006 * @return the formatted String. 2007 */ 2008 private String printDFormat(short x) { 2009 2010 return printDFormat(Short.toString(x)); 2011 } 2012 2013 /** 2014 * Utility method for formatting using the d 2015 * conversion character. 2016 * @param sx the String to format, the result of 2017 * converting a short, int, or long to a 2018 * String. 2019 * @return the formatted String. 2020 */ 2021 private String printDFormat(String sx) { 2022 2023 int nLeadingZeros = 0; 2024 int nBlanks = 0, n = 0; 2025 int i = 0, jFirst = 0; 2026 boolean neg = sx.charAt(0) == '-'; 2027 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2028 sx = ""; 2029 } 2030 if (!neg) { 2031 if (m_precisionSet && (sx.length() < m_precision)) { 2032 nLeadingZeros = m_precision - sx.length(); 2033 } 2034 } else { 2035 if (m_precisionSet && ((sx.length() - 1) < m_precision)) { 2036 nLeadingZeros = (m_precision - sx.length()) + 1; 2037 } 2038 } 2039 if (nLeadingZeros < 0) { 2040 nLeadingZeros = 0; 2041 } 2042 if (m_fieldWidthSet) { 2043 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2044 if (!neg && (m_leadingSign || m_leadingSpace)) { 2045 nBlanks--; 2046 } 2047 } 2048 if (nBlanks < 0) { 2049 nBlanks = 0; 2050 } 2051 if (m_leadingSign) { 2052 n++; 2053 } else if (m_leadingSpace) { 2054 n++; 2055 } 2056 n += nBlanks; 2057 n += nLeadingZeros; 2058 n += sx.length(); 2059 char[] ca = new char[n]; 2060 if (m_leftJustify) { 2061 if (neg) { 2062 ca[i++] = '-'; 2063 } else if (m_leadingSign) { 2064 ca[i++] = '+'; 2065 } else if (m_leadingSpace) { 2066 ca[i++] = ' '; 2067 } 2068 char[] csx = sx.toCharArray(); 2069 jFirst = neg ? 1 : 0; 2070 for (int j = 0; j < nLeadingZeros; i++, j++) { 2071 ca[i] = '0'; 2072 } 2073 for (int j = jFirst; j < csx.length; j++, i++) { 2074 ca[i] = csx[j]; 2075 } 2076 for (int j = 0; j < nBlanks; i++, j++) { 2077 ca[i] = ' '; 2078 } 2079 } else { 2080 if (!m_leadingZeros) { 2081 for (i = 0; i < nBlanks; i++) { 2082 ca[i] = ' '; 2083 } 2084 if (neg) { 2085 ca[i++] = '-'; 2086 } else if (m_leadingSign) { 2087 ca[i++] = '+'; 2088 } else if (m_leadingSpace) { 2089 ca[i++] = ' '; 2090 } 2091 } else { 2092 if (neg) { 2093 ca[i++] = '-'; 2094 } else if (m_leadingSign) { 2095 ca[i++] = '+'; 2096 } else if (m_leadingSpace) { 2097 ca[i++] = ' '; 2098 } 2099 for (int j = 0; j < nBlanks; j++, i++) { 2100 ca[i] = '0'; 2101 } 2102 } 2103 for (int j = 0; j < nLeadingZeros; j++, i++) { 2104 ca[i] = '0'; 2105 } 2106 char[] csx = sx.toCharArray(); 2107 jFirst = neg ? 1 : 0; 2108 for (int j = jFirst; j < csx.length; j++, i++) { 2109 ca[i] = csx[j]; 2110 } 2111 } 2112 return new String(ca); 2113 } 2114 2115 /** 2116 * Format method for the e or E conversion 2117 * character. 2118 * @param x the double to format. 2119 * @return the formatted String. 2120 */ 2121 private String printEFormat(double x) { 2122 2123 if (m_conversionCharacter == 'e') { 2124 return eFormatString(x, 'e'); 2125 } else { 2126 return eFormatString(x, 'E'); 2127 } 2128 } 2129 2130 /** 2131 * Format method for the f conversion character. 2132 * @param x the double to format. 2133 * @return the formatted String. 2134 */ 2135 private String printFFormat(double x) { 2136 2137 return fFormatString(x); 2138 } 2139 2140 /** 2141 * Format method for the g conversion character. 2142 * 2143 * For g format, the flag character '-', means that 2144 * the output should be left justified within the 2145 * field. The default is to pad with blanks on the 2146 * left. '+' character means that the conversion 2147 * will always begin with a sign (+ or -). The 2148 * blank flag character means that a non-negative 2149 * input will be preceded with a blank. If both a 2150 * '+' and a ' ' are specified, the blank flag is 2151 * ignored. The '0' flag character implies that 2152 * padding to the field width will be done with 2153 * zeros instead of blanks. 2154 * 2155 * The field width is treated as the minimum number 2156 * of characters to be printed. The default is to 2157 * add no padding. Padding is with blanks by 2158 * default. 2159 * 2160 * The precision, if set, is the minimum number of 2161 * digits to appear after the radix character. 2162 * Padding is with trailing 0s. 2163 * @param x the double to format. 2164 * @return the formatted String. 2165 */ 2166 private String printGFormat(double x) { 2167 2168 String sx, sy, sz, ret; 2169 int savePrecision = m_precision; 2170 int i; 2171 char[] ca4, ca5; 2172 if (Double.isInfinite(x)) { 2173 if (x == Double.POSITIVE_INFINITY) { 2174 if (m_leadingSign) { 2175 ca4 = "+Inf".toCharArray(); 2176 } else if (m_leadingSpace) { 2177 ca4 = " Inf".toCharArray(); 2178 } else { 2179 ca4 = "Inf".toCharArray(); 2180 } 2181 } else { 2182 ca4 = "-Inf".toCharArray(); 2183 } 2184 } else if (Double.isNaN(x)) { 2185 if (m_leadingSign) { 2186 ca4 = "+NaN".toCharArray(); 2187 } else if (m_leadingSpace) { 2188 ca4 = " NaN".toCharArray(); 2189 } else { 2190 ca4 = "NaN".toCharArray(); 2191 } 2192 } else { 2193 if (!m_precisionSet) { 2194 m_precision = DEFAULT_DIGITS; 2195 } 2196 if (m_precision == 0) { 2197 m_precision = 1; 2198 } 2199 int ePos = -1; 2200 if (m_conversionCharacter == 'g') { 2201 sx = eFormatString(x, 'e').trim(); 2202 ePos = sx.indexOf('e'); 2203 } else { 2204 sx = eFormatString(x, 'E').trim(); 2205 ePos = sx.indexOf('E'); 2206 } 2207 i = ePos + 1; 2208 int expon = 0; 2209 if (sx.charAt(i) == '-') { 2210 for (++i; i < sx.length(); i++) { 2211 if (sx.charAt(i) != '0') { 2212 break; 2213 } 2214 } 2215 if (i < sx.length()) { 2216 expon = -Integer.parseInt(sx.substring(i)); 2217 } 2218 } else { 2219 if (sx.charAt(i) == '+') { 2220 ++i; 2221 } 2222 for (; i < sx.length(); i++) { 2223 if (sx.charAt(i) != '0') { 2224 break; 2225 } 2226 } 2227 if (i < sx.length()) { 2228 expon = Integer.parseInt(sx.substring(i)); 2229 } 2230 } 2231 // Trim trailing zeros. 2232 // If the radix character is not followed by 2233 // a digit, trim it, too. 2234 if (!m_alternateForm) { 2235 if ((expon >= -4) && (expon < m_precision)) { 2236 sy = fFormatString(x).trim(); 2237 } else { 2238 sy = sx.substring(0, ePos); 2239 } 2240 i = sy.length() - 1; 2241 for (; i >= 0; i--) { 2242 if (sy.charAt(i) != '0') { 2243 break; 2244 } 2245 } 2246 if ((i >= 0) && (sy.charAt(i) == '.')) { 2247 i--; 2248 } 2249 if (i == -1) { 2250 sz = "0"; 2251 } else if (!Character.isDigit(sy.charAt(i))) { 2252 sz = sy.substring(0, i + 1) + "0"; 2253 } else { 2254 sz = sy.substring(0, i + 1); 2255 } 2256 if ((expon >= -4) && (expon < m_precision)) { 2257 ret = sz; 2258 } else { 2259 ret = sz + sx.substring(ePos); 2260 } 2261 } else { 2262 if ((expon >= -4) && (expon < m_precision)) { 2263 ret = fFormatString(x).trim(); 2264 } else { 2265 ret = sx; 2266 } 2267 } 2268 // leading space was trimmed off during 2269 // construction 2270 if (m_leadingSpace) { 2271 if (x >= 0) { 2272 ret = " " + ret; 2273 } 2274 } 2275 ca4 = ret.toCharArray(); 2276 } 2277 // Pad with blanks or zeros. 2278 ca5 = applyFloatPadding(ca4, false); 2279 m_precision = savePrecision; 2280 return new String(ca5); 2281 } 2282 2283 /** 2284 * Format method for the o conversion character and 2285 * int argument. 2286 * 2287 * For o format, the flag character '-', means that 2288 * the output should be left justified within the 2289 * field. The default is to pad with blanks on the 2290 * left. The '#' flag character means that the 2291 * output begins with a leading 0 and the precision 2292 * is increased by 1. 2293 * 2294 * The field width is treated as the minimum number 2295 * of characters to be printed. The default is to 2296 * add no padding. Padding is with blanks by 2297 * default. 2298 * 2299 * The precision, if set, is the minimum number of 2300 * digits to appear. Padding is with leading 0s. 2301 * @param x the int to format. 2302 * @return the formatted String. 2303 */ 2304 private String printOFormat(int x) { 2305 2306 String sx = null; 2307 if (x == Integer.MIN_VALUE) { 2308 sx = "20000000000"; 2309 } else if (x < 0) { 2310 String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8); 2311 switch (t.length()) { 2312 case 1: 2313 sx = "2000000000" + t; 2314 break; 2315 case 2: 2316 sx = "200000000" + t; 2317 break; 2318 case 3: 2319 sx = "20000000" + t; 2320 break; 2321 case 4: 2322 sx = "2000000" + t; 2323 break; 2324 case 5: 2325 sx = "200000" + t; 2326 break; 2327 case 6: 2328 sx = "20000" + t; 2329 break; 2330 case 7: 2331 sx = "2000" + t; 2332 break; 2333 case 8: 2334 sx = "200" + t; 2335 break; 2336 case 9: 2337 sx = "20" + t; 2338 break; 2339 case 10: 2340 sx = "2" + t; 2341 break; 2342 case 11: 2343 sx = "3" + t.substring(1); 2344 break; 2345 default: 2346 // noop 2347 } 2348 } else { 2349 sx = Integer.toString(x, 8); 2350 } 2351 return printOFormat(sx); 2352 } 2353 2354 /** 2355 * Format method for the o conversion character and 2356 * long argument. 2357 * 2358 * For o format, the flag character '-', means that 2359 * the output should be left justified within the 2360 * field. The default is to pad with blanks on the 2361 * left. The '#' flag character means that the 2362 * output begins with a leading 0 and the precision 2363 * is increased by 1. 2364 * 2365 * The field width is treated as the minimum number 2366 * of characters to be printed. The default is to 2367 * add no padding. Padding is with blanks by 2368 * default. 2369 * 2370 * The precision, if set, is the minimum number of 2371 * digits to appear. Padding is with leading 0s. 2372 * @param x the long to format. 2373 * @return the formatted String. 2374 */ 2375 private String printOFormat(long x) { 2376 2377 String sx = null; 2378 if (x == Long.MIN_VALUE) { 2379 sx = "1000000000000000000000"; 2380 } else if (x < 0) { 2381 String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8); 2382 switch (t.length()) { 2383 case 1: 2384 sx = "100000000000000000000" + t; 2385 break; 2386 case 2: 2387 sx = "10000000000000000000" + t; 2388 break; 2389 case 3: 2390 sx = "1000000000000000000" + t; 2391 break; 2392 case 4: 2393 sx = "100000000000000000" + t; 2394 break; 2395 case 5: 2396 sx = "10000000000000000" + t; 2397 break; 2398 case 6: 2399 sx = "1000000000000000" + t; 2400 break; 2401 case 7: 2402 sx = "100000000000000" + t; 2403 break; 2404 case 8: 2405 sx = "10000000000000" + t; 2406 break; 2407 case 9: 2408 sx = "1000000000000" + t; 2409 break; 2410 case 10: 2411 sx = "100000000000" + t; 2412 break; 2413 case 11: 2414 sx = "10000000000" + t; 2415 break; 2416 case 12: 2417 sx = "1000000000" + t; 2418 break; 2419 case 13: 2420 sx = "100000000" + t; 2421 break; 2422 case 14: 2423 sx = "10000000" + t; 2424 break; 2425 case 15: 2426 sx = "1000000" + t; 2427 break; 2428 case 16: 2429 sx = "100000" + t; 2430 break; 2431 case 17: 2432 sx = "10000" + t; 2433 break; 2434 case 18: 2435 sx = "1000" + t; 2436 break; 2437 case 19: 2438 sx = "100" + t; 2439 break; 2440 case 20: 2441 sx = "10" + t; 2442 break; 2443 case 21: 2444 sx = "1" + t; 2445 break; 2446 default: 2447 // noop 2448 } 2449 } else { 2450 sx = Long.toString(x, 8); 2451 } 2452 return printOFormat(sx); 2453 } 2454 2455 /** 2456 * Format method for the o conversion character and 2457 * short argument. 2458 * 2459 * For o format, the flag character '-', means that 2460 * the output should be left justified within the 2461 * field. The default is to pad with blanks on the 2462 * left. The '#' flag character means that the 2463 * output begins with a leading 0 and the precision 2464 * is increased by 1. 2465 * 2466 * The field width is treated as the minimum number 2467 * of characters to be printed. The default is to 2468 * add no padding. Padding is with blanks by 2469 * default. 2470 * 2471 * The precision, if set, is the minimum number of 2472 * digits to appear. Padding is with leading 0s. 2473 * @param x the short to format. 2474 * @return the formatted String. 2475 */ 2476 private String printOFormat(short x) { 2477 2478 String sx = null; 2479 if (x == Short.MIN_VALUE) { 2480 sx = "100000"; 2481 } else if (x < 0) { 2482 String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8); 2483 switch (t.length()) { 2484 case 1: 2485 sx = "10000" + t; 2486 break; 2487 case 2: 2488 sx = "1000" + t; 2489 break; 2490 case 3: 2491 sx = "100" + t; 2492 break; 2493 case 4: 2494 sx = "10" + t; 2495 break; 2496 case 5: 2497 sx = "1" + t; 2498 break; 2499 default: 2500 // noop 2501 } 2502 } else { 2503 sx = Integer.toString(x, 8); 2504 } 2505 return printOFormat(sx); 2506 } 2507 2508 /** 2509 * Utility method for formatting using the o 2510 * conversion character. 2511 * @param sx the String to format, the result of 2512 * converting a short, int, or long to a 2513 * String. 2514 * @return the formatted String. 2515 */ 2516 private String printOFormat(String sx) { 2517 2518 int nLeadingZeros = 0; 2519 int nBlanks = 0; 2520 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2521 sx = ""; 2522 } 2523 if (m_precisionSet) { 2524 nLeadingZeros = m_precision - sx.length(); 2525 } 2526 if (m_alternateForm) { 2527 nLeadingZeros++; 2528 } 2529 if (nLeadingZeros < 0) { 2530 nLeadingZeros = 0; 2531 } 2532 if (m_fieldWidthSet) { 2533 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2534 } 2535 if (nBlanks < 0) { 2536 nBlanks = 0; 2537 } 2538 int n = nLeadingZeros + sx.length() + nBlanks; 2539 char[] ca = new char[n]; 2540 int i; 2541 if (m_leftJustify) { 2542 for (i = 0; i < nLeadingZeros; i++) { 2543 ca[i] = '0'; 2544 } 2545 char[] csx = sx.toCharArray(); 2546 for (int j = 0; j < csx.length; j++, i++) { 2547 ca[i] = csx[j]; 2548 } 2549 for (int j = 0; j < nBlanks; j++, i++) { 2550 ca[i] = ' '; 2551 } 2552 } else { 2553 if (m_leadingZeros) { 2554 for (i = 0; i < nBlanks; i++) { 2555 ca[i] = '0'; 2556 } 2557 } else { 2558 for (i = 0; i < nBlanks; i++) { 2559 ca[i] = ' '; 2560 } 2561 } 2562 for (int j = 0; j < nLeadingZeros; j++, i++) { 2563 ca[i] = '0'; 2564 } 2565 char[] csx = sx.toCharArray(); 2566 for (int j = 0; j < csx.length; j++, i++) { 2567 ca[i] = csx[j]; 2568 } 2569 } 2570 return new String(ca); 2571 } 2572 2573 /** 2574 * Format method for the s conversion character and 2575 * String argument. 2576 * 2577 * The only flag character that affects s format is 2578 * the '-', meaning that the output should be left 2579 * justified within the field. The default is to 2580 * pad with blanks on the left. 2581 * 2582 * The field width is treated as the minimum number 2583 * of characters to be printed. The default is the 2584 * smaller of the number of characters in the the 2585 * input and the precision. Padding is with blanks 2586 * by default. 2587 * 2588 * The precision, if set, specifies the maximum 2589 * number of characters to be printed from the 2590 * string. A null digit string is treated 2591 * as a 0. The default is not to set a maximum 2592 * number of characters to be printed. 2593 * @param x the String to format. 2594 * @return the formatted String. 2595 */ 2596 private String printSFormat(String x) { 2597 2598 int nPrint = x.length(); 2599 int width = m_fieldWidth; 2600 if (m_precisionSet && (nPrint > m_precision)) { 2601 nPrint = m_precision; 2602 } 2603 if (!m_fieldWidthSet) { 2604 width = nPrint; 2605 } 2606 int n = 0; 2607 if (width > nPrint) { 2608 n += width - nPrint; 2609 } 2610 if (nPrint >= x.length()) { 2611 n += x.length(); 2612 } else { 2613 n += nPrint; 2614 } 2615 char[] ca = new char[n]; 2616 int i = 0; 2617 if (m_leftJustify) { 2618 if (nPrint >= x.length()) { 2619 char[] csx = x.toCharArray(); 2620 for (i = 0; i < x.length(); i++) { 2621 ca[i] = csx[i]; 2622 } 2623 } else { 2624 char[] csx = x.substring(0, nPrint).toCharArray(); 2625 for (i = 0; i < nPrint; i++) { 2626 ca[i] = csx[i]; 2627 } 2628 } 2629 for (int j = 0; j < (width - nPrint); j++, i++) { 2630 ca[i] = ' '; 2631 } 2632 } else { 2633 for (i = 0; i < (width - nPrint); i++) { 2634 ca[i] = ' '; 2635 } 2636 if (nPrint >= x.length()) { 2637 char[] csx = x.toCharArray(); 2638 for (int j = 0; j < x.length(); i++, j++) { 2639 ca[i] = csx[j]; 2640 } 2641 } else { 2642 char[] csx = x.substring(0, nPrint).toCharArray(); 2643 for (int j = 0; j < nPrint; i++, j++) { 2644 ca[i] = csx[j]; 2645 } 2646 } 2647 } 2648 return new String(ca); 2649 } 2650 2651 /** 2652 * Format method for the x conversion character and 2653 * int argument. 2654 * 2655 * For x format, the flag character '-', means that 2656 * the output should be left justified within the 2657 * field. The default is to pad with blanks on the 2658 * left. The '#' flag character means to lead with 2659 * '0x'. 2660 * 2661 * The field width is treated as the minimum number 2662 * of characters to be printed. The default is to 2663 * add no padding. Padding is with blanks by 2664 * default. 2665 * 2666 * The precision, if set, is the minimum number of 2667 * digits to appear. Padding is with leading 0s. 2668 * @param x the int to format. 2669 * @return the formatted String. 2670 */ 2671 private String printXFormat(int x) { 2672 2673 String sx = null; 2674 if (x == Integer.MIN_VALUE) { 2675 sx = "80000000"; 2676 } else if (x < 0) { 2677 String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16); 2678 switch (t.length()) { 2679 case 1: 2680 sx = "8000000" + t; 2681 break; 2682 case 2: 2683 sx = "800000" + t; 2684 break; 2685 case 3: 2686 sx = "80000" + t; 2687 break; 2688 case 4: 2689 sx = "8000" + t; 2690 break; 2691 case 5: 2692 sx = "800" + t; 2693 break; 2694 case 6: 2695 sx = "80" + t; 2696 break; 2697 case 7: 2698 sx = "8" + t; 2699 break; 2700 case 8: 2701 switch (t.charAt(0)) { 2702 case '1': 2703 sx = "9" + t.substring(1, 8); 2704 break; 2705 case '2': 2706 sx = "a" + t.substring(1, 8); 2707 break; 2708 case '3': 2709 sx = "b" + t.substring(1, 8); 2710 break; 2711 case '4': 2712 sx = "c" + t.substring(1, 8); 2713 break; 2714 case '5': 2715 sx = "d" + t.substring(1, 8); 2716 break; 2717 case '6': 2718 sx = "e" + t.substring(1, 8); 2719 break; 2720 case '7': 2721 sx = "f" + t.substring(1, 8); 2722 break; 2723 default: 2724 // noop 2725 } 2726 break; 2727 default: 2728 // noop 2729 } 2730 } else { 2731 sx = Integer.toString(x, 16); 2732 } 2733 return printXFormat(sx); 2734 } 2735 2736 /** 2737 * Format method for the x conversion character and 2738 * long argument. 2739 * 2740 * For x format, the flag character '-', means that 2741 * the output should be left justified within the 2742 * field. The default is to pad with blanks on the 2743 * left. The '#' flag character means to lead with 2744 * '0x'. 2745 * 2746 * The field width is treated as the minimum number 2747 * of characters to be printed. The default is to 2748 * add no padding. Padding is with blanks by 2749 * default. 2750 * 2751 * The precision, if set, is the minimum number of 2752 * digits to appear. Padding is with leading 0s. 2753 * @param x the long to format. 2754 * @return the formatted String. 2755 */ 2756 private String printXFormat(long x) { 2757 2758 String sx = null; 2759 if (x == Long.MIN_VALUE) { 2760 sx = "8000000000000000"; 2761 } else if (x < 0) { 2762 String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16); 2763 switch (t.length()) { 2764 case 1: 2765 sx = "800000000000000" + t; 2766 break; 2767 case 2: 2768 sx = "80000000000000" + t; 2769 break; 2770 case 3: 2771 sx = "8000000000000" + t; 2772 break; 2773 case 4: 2774 sx = "800000000000" + t; 2775 break; 2776 case 5: 2777 sx = "80000000000" + t; 2778 break; 2779 case 6: 2780 sx = "8000000000" + t; 2781 break; 2782 case 7: 2783 sx = "800000000" + t; 2784 break; 2785 case 8: 2786 sx = "80000000" + t; 2787 break; 2788 case 9: 2789 sx = "8000000" + t; 2790 break; 2791 case 10: 2792 sx = "800000" + t; 2793 break; 2794 case 11: 2795 sx = "80000" + t; 2796 break; 2797 case 12: 2798 sx = "8000" + t; 2799 break; 2800 case 13: 2801 sx = "800" + t; 2802 break; 2803 case 14: 2804 sx = "80" + t; 2805 break; 2806 case 15: 2807 sx = "8" + t; 2808 break; 2809 case 16: 2810 switch (t.charAt(0)) { 2811 case '1': 2812 sx = "9" + t.substring(1, 16); 2813 break; 2814 case '2': 2815 sx = "a" + t.substring(1, 16); 2816 break; 2817 case '3': 2818 sx = "b" + t.substring(1, 16); 2819 break; 2820 case '4': 2821 sx = "c" + t.substring(1, 16); 2822 break; 2823 case '5': 2824 sx = "d" + t.substring(1, 16); 2825 break; 2826 case '6': 2827 sx = "e" + t.substring(1, 16); 2828 break; 2829 case '7': 2830 sx = "f" + t.substring(1, 16); 2831 break; 2832 default: 2833 // noop 2834 } 2835 break; 2836 default: 2837 // noop 2838 } 2839 } else { 2840 sx = Long.toString(x, 16); 2841 } 2842 return printXFormat(sx); 2843 } 2844 2845 /** 2846 * Format method for the x conversion character and 2847 * short argument. 2848 * 2849 * For x format, the flag character '-', means that 2850 * the output should be left justified within the 2851 * field. The default is to pad with blanks on the 2852 * left. The '#' flag character means to lead with 2853 * '0x'. 2854 * 2855 * The field width is treated as the minimum number 2856 * of characters to be printed. The default is to 2857 * add no padding. Padding is with blanks by 2858 * default. 2859 * 2860 * The precision, if set, is the minimum number of 2861 * digits to appear. Padding is with leading 0s. 2862 * @param x the short to format. 2863 * @return the formatted String. 2864 */ 2865 private String printXFormat(short x) { 2866 2867 String sx = null; 2868 if (x == Short.MIN_VALUE) { 2869 sx = "8000"; 2870 } else if (x < 0) { 2871 String t; 2872 if (x == Short.MIN_VALUE) { 2873 t = "0"; 2874 } else { 2875 t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16); 2876 if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) { 2877 t = t.substring(16, 32); 2878 } 2879 } 2880 switch (t.length()) { 2881 case 1: 2882 sx = "800" + t; 2883 break; 2884 case 2: 2885 sx = "80" + t; 2886 break; 2887 case 3: 2888 sx = "8" + t; 2889 break; 2890 case 4: 2891 switch (t.charAt(0)) { 2892 case '1': 2893 sx = "9" + t.substring(1, 4); 2894 break; 2895 case '2': 2896 sx = "a" + t.substring(1, 4); 2897 break; 2898 case '3': 2899 sx = "b" + t.substring(1, 4); 2900 break; 2901 case '4': 2902 sx = "c" + t.substring(1, 4); 2903 break; 2904 case '5': 2905 sx = "d" + t.substring(1, 4); 2906 break; 2907 case '6': 2908 sx = "e" + t.substring(1, 4); 2909 break; 2910 case '7': 2911 sx = "f" + t.substring(1, 4); 2912 break; 2913 default: 2914 // noop 2915 } 2916 break; 2917 default: 2918 // noop 2919 } 2920 } else { 2921 sx = Integer.toString(x, 16); 2922 } 2923 return printXFormat(sx); 2924 } 2925 2926 /** 2927 * Utility method for formatting using the x 2928 * conversion character. 2929 * @param sx the String to format, the result of 2930 * converting a short, int, or long to a 2931 * String. 2932 * @return the formatted String. 2933 */ 2934 private String printXFormat(String sx) { 2935 2936 int nLeadingZeros = 0; 2937 int nBlanks = 0; 2938 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2939 sx = ""; 2940 } 2941 if (m_precisionSet) { 2942 nLeadingZeros = m_precision - sx.length(); 2943 } 2944 if (nLeadingZeros < 0) { 2945 nLeadingZeros = 0; 2946 } 2947 if (m_fieldWidthSet) { 2948 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2949 if (m_alternateForm) { 2950 nBlanks = nBlanks - 2; 2951 } 2952 } 2953 if (nBlanks < 0) { 2954 nBlanks = 0; 2955 } 2956 int n = 0; 2957 if (m_alternateForm) { 2958 n += 2; 2959 } 2960 n += nLeadingZeros; 2961 n += sx.length(); 2962 n += nBlanks; 2963 char[] ca = new char[n]; 2964 int i = 0; 2965 if (m_leftJustify) { 2966 if (m_alternateForm) { 2967 ca[i++] = '0'; 2968 ca[i++] = 'x'; 2969 } 2970 for (int j = 0; j < nLeadingZeros; j++, i++) { 2971 ca[i] = '0'; 2972 } 2973 char[] csx = sx.toCharArray(); 2974 for (int j = 0; j < csx.length; j++, i++) { 2975 ca[i] = csx[j]; 2976 } 2977 for (int j = 0; j < nBlanks; j++, i++) { 2978 ca[i] = ' '; 2979 } 2980 } else { 2981 if (!m_leadingZeros) { 2982 for (int j = 0; j < nBlanks; j++, i++) { 2983 ca[i] = ' '; 2984 } 2985 } 2986 if (m_alternateForm) { 2987 ca[i++] = '0'; 2988 ca[i++] = 'x'; 2989 } 2990 if (m_leadingZeros) { 2991 for (int j = 0; j < nBlanks; j++, i++) { 2992 ca[i] = '0'; 2993 } 2994 } 2995 for (int j = 0; j < nLeadingZeros; j++, i++) { 2996 ca[i] = '0'; 2997 } 2998 char[] csx = sx.toCharArray(); 2999 for (int j = 0; j < csx.length; j++, i++) { 3000 ca[i] = csx[j]; 3001 } 3002 } 3003 String caReturn = new String(ca); 3004 if (m_conversionCharacter == 'X') { 3005 caReturn = caReturn.toUpperCase(); 3006 } 3007 return caReturn; 3008 } 3009 3010 /** 3011 * Store the digits <code>n</code> in %n$ forms. 3012 */ 3013 private void setArgPosition() { 3014 3015 int xPos; 3016 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3017 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3018 break; 3019 } 3020 } 3021 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3022 if (m_fmt.charAt(xPos) == '$') { 3023 m_positionalSpecification = true; 3024 m_argumentPosition = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3025 m_pos = xPos + 1; 3026 } 3027 } 3028 } 3029 3030 /** 3031 * Check for a conversion character. If it is 3032 * there, store it. 3033 * @return <code>true</code> if the conversion 3034 * character is there, and 3035 * <code>false</code> otherwise. 3036 */ 3037 private boolean setConversionCharacter() { 3038 3039 /* idfgGoxXeEcs */ 3040 boolean ret = false; 3041 m_conversionCharacter = '\0'; 3042 if (m_pos < m_fmt.length()) { 3043 char c = m_fmt.charAt(m_pos); 3044 if ((c == 'i') 3045 || (c == 'd') 3046 || (c == 'f') 3047 || (c == 'g') 3048 || (c == 'G') 3049 || (c == 'o') 3050 || (c == 'x') 3051 || (c == 'X') 3052 || (c == 'e') 3053 || (c == 'E') 3054 || (c == 'c') 3055 || (c == 's') 3056 || (c == '%')) { 3057 m_conversionCharacter = c; 3058 m_pos++; 3059 ret = true; 3060 } 3061 } 3062 return ret; 3063 } 3064 3065 /** 3066 * Set the field width. 3067 */ 3068 private void setFieldWidth() { 3069 3070 int firstPos = m_pos; 3071 m_fieldWidth = 0; 3072 m_fieldWidthSet = false; 3073 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) { 3074 m_pos++; 3075 if (!setFieldWidthArgPosition()) { 3076 m_variableFieldWidth = true; 3077 m_fieldWidthSet = true; 3078 } 3079 } else { 3080 while (m_pos < m_fmt.length()) { 3081 char c = m_fmt.charAt(m_pos); 3082 if (Character.isDigit(c)) { 3083 m_pos++; 3084 } else { 3085 break; 3086 } 3087 } 3088 if ((firstPos < m_pos) && (firstPos < m_fmt.length())) { 3089 String sz = m_fmt.substring(firstPos, m_pos); 3090 m_fieldWidth = Integer.parseInt(sz); 3091 m_fieldWidthSet = true; 3092 } 3093 } 3094 } 3095 3096 /** 3097 * Store the digits <code>n</code> in *n$ forms. 3098 * 3099 * @return the result 3100 */ 3101 private boolean setFieldWidthArgPosition() { 3102 3103 boolean ret = false; 3104 int xPos; 3105 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3106 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3107 break; 3108 } 3109 } 3110 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3111 if (m_fmt.charAt(xPos) == '$') { 3112 m_positionalFieldWidth = true; 3113 m_argumentPositionForFieldWidth = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3114 m_pos = xPos + 1; 3115 ret = true; 3116 } 3117 } 3118 return ret; 3119 } 3120 3121 /** 3122 * Set flag characters, one of '-+#0 or a space. 3123 */ 3124 private void setFlagCharacters() { 3125 3126 /* '-+ #0 */ 3127 m_thousands = false; 3128 m_leftJustify = false; 3129 m_leadingSign = false; 3130 m_leadingSpace = false; 3131 m_alternateForm = false; 3132 m_leadingZeros = false; 3133 for (; m_pos < m_fmt.length(); m_pos++) { 3134 char c = m_fmt.charAt(m_pos); 3135 if (c == '\'') { 3136 m_thousands = true; 3137 } else if (c == '-') { 3138 m_leftJustify = true; 3139 m_leadingZeros = false; 3140 } else if (c == '+') { 3141 m_leadingSign = true; 3142 m_leadingSpace = false; 3143 } else if (c == ' ') { 3144 if (!m_leadingSign) { 3145 m_leadingSpace = true; 3146 } 3147 } else if (c == '#') { 3148 m_alternateForm = true; 3149 } else if (c == '0') { 3150 if (!m_leftJustify) { 3151 m_leadingZeros = true; 3152 } 3153 } else { 3154 break; 3155 } 3156 } 3157 } 3158 3159 /** 3160 * Check for an h, l, or L in a format. An L is 3161 * used to control the minimum number of digits 3162 * in an exponent when using floating point 3163 * formats. An l or h is used to control 3164 * conversion of the input to a long or short, 3165 * respectively, before formatting. If any of 3166 * these is present, store them. 3167 */ 3168 private void setOptionalHL() { 3169 3170 m_optionalh = false; 3171 m_optionall = false; 3172 m_optionalL = false; 3173 if (m_pos < m_fmt.length()) { 3174 char c = m_fmt.charAt(m_pos); 3175 if (c == 'h') { 3176 m_optionalh = true; 3177 m_pos++; 3178 } else if (c == 'l') { 3179 m_optionall = true; 3180 m_pos++; 3181 } else if (c == 'L') { 3182 m_optionalL = true; 3183 m_pos++; 3184 } 3185 } 3186 } 3187 3188 /** 3189 * Set the precision. 3190 */ 3191 private void setPrecision() { 3192 3193 int firstPos = m_pos; 3194 m_precisionSet = false; 3195 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '.')) { 3196 m_pos++; 3197 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) { 3198 m_pos++; 3199 if (!setPrecisionArgPosition()) { 3200 m_variablePrecision = true; 3201 m_precisionSet = true; 3202 } 3203 return; 3204 } else { 3205 while (m_pos < m_fmt.length()) { 3206 char c = m_fmt.charAt(m_pos); 3207 if (Character.isDigit(c)) { 3208 m_pos++; 3209 } else { 3210 break; 3211 } 3212 } 3213 if (m_pos > (firstPos + 1)) { 3214 String sz = m_fmt.substring(firstPos + 1, m_pos); 3215 m_precision = Integer.parseInt(sz); 3216 m_precisionSet = true; 3217 } 3218 } 3219 } 3220 } 3221 3222 /** 3223 * Store the digits <code>n</code> in *n$ forms. 3224 * 3225 * @return the result 3226 */ 3227 private boolean setPrecisionArgPosition() { 3228 3229 boolean ret = false; 3230 int xPos; 3231 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3232 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3233 break; 3234 } 3235 } 3236 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3237 if (m_fmt.charAt(xPos) == '$') { 3238 m_positionalPrecision = true; 3239 m_argumentPositionForPrecision = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3240 m_pos = xPos + 1; 3241 ret = true; 3242 } 3243 } 3244 return ret; 3245 } 3246 3247 /** 3248 * Start the symbolic carry process. The process 3249 * is not quite finished because the symbolic 3250 * carry may change the length of the string and 3251 * change the exponent (in e format). 3252 * @param cLast index of the last digit changed 3253 * by the round 3254 * @param cFirst index of the first digit allowed 3255 * to be changed by this phase of the round 3256 * @param ca the ca parameter 3257 * @return <code>true</code> if the carry forces 3258 * a round that will change the print still 3259 * more 3260 */ 3261 private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) { 3262 3263 boolean carry = true; 3264 for (int i = cLast; carry && (i >= cFirst); i--) { 3265 carry = false; 3266 switch (ca[i]) { 3267 case '0': 3268 ca[i] = '1'; 3269 break; 3270 case '1': 3271 ca[i] = '2'; 3272 break; 3273 case '2': 3274 ca[i] = '3'; 3275 break; 3276 case '3': 3277 ca[i] = '4'; 3278 break; 3279 case '4': 3280 ca[i] = '5'; 3281 break; 3282 case '5': 3283 ca[i] = '6'; 3284 break; 3285 case '6': 3286 ca[i] = '7'; 3287 break; 3288 case '7': 3289 ca[i] = '8'; 3290 break; 3291 case '8': 3292 ca[i] = '9'; 3293 break; 3294 case '9': 3295 ca[i] = '0'; 3296 carry = true; 3297 break; 3298 default: 3299 // noop 3300 } 3301 } 3302 return carry; 3303 } 3304 } 3305 3306 /** Character position. Used by the constructor. */ 3307 DecimalFormatSymbols m_dfs; 3308 3309 /** Character position. Used by the constructor. */ 3310 private int m_cPos; 3311 3312 /** Vector of control strings and format literals. */ 3313 private Vector<ConversionSpecification> m_vFmt = new Vector<ConversionSpecification>(); 3314 3315 /** 3316 * Constructs an array of control specifications 3317 * possibly preceded, separated, or followed by 3318 * ordinary strings. Control strings begin with 3319 * unpaired percent signs. A pair of successive 3320 * percent signs designates a single percent sign in 3321 * the format. 3322 * @param locale the locale 3323 * @param fmtArg Control string. 3324 * @exception CmsIllegalArgumentException if the control 3325 * string is null, zero length, or otherwise 3326 * malformed. 3327 */ 3328 public PrintfFormat(Locale locale, String fmtArg) 3329 throws CmsIllegalArgumentException { 3330 3331 m_dfs = new DecimalFormatSymbols(locale); 3332 int ePos = 0; 3333 ConversionSpecification sFmt = null; 3334 String unCS = nonControl(fmtArg, 0); 3335 if (unCS != null) { 3336 sFmt = new ConversionSpecification(); 3337 sFmt.setLiteral(unCS); 3338 m_vFmt.addElement(sFmt); 3339 } 3340 while ((m_cPos != -1) && (m_cPos < fmtArg.length())) { 3341 for (ePos = m_cPos + 1; ePos < fmtArg.length(); ePos++) { 3342 char c = 0; 3343 c = fmtArg.charAt(ePos); 3344 if (c == 'i') { 3345 break; 3346 } 3347 if (c == 'd') { 3348 break; 3349 } 3350 if (c == 'f') { 3351 break; 3352 } 3353 if (c == 'g') { 3354 break; 3355 } 3356 if (c == 'G') { 3357 break; 3358 } 3359 if (c == 'o') { 3360 break; 3361 } 3362 if (c == 'x') { 3363 break; 3364 } 3365 if (c == 'X') { 3366 break; 3367 } 3368 if (c == 'e') { 3369 break; 3370 } 3371 if (c == 'E') { 3372 break; 3373 } 3374 if (c == 'c') { 3375 break; 3376 } 3377 if (c == 's') { 3378 break; 3379 } 3380 if (c == '%') { 3381 break; 3382 } 3383 } 3384 ePos = Math.min(ePos + 1, fmtArg.length()); 3385 sFmt = new ConversionSpecification(fmtArg.substring(m_cPos, ePos)); 3386 m_vFmt.addElement(sFmt); 3387 unCS = nonControl(fmtArg, ePos); 3388 if (unCS != null) { 3389 sFmt = new ConversionSpecification(); 3390 sFmt.setLiteral(unCS); 3391 m_vFmt.addElement(sFmt); 3392 } 3393 } 3394 } 3395 3396 /** 3397 * Constructs an array of control specifications 3398 * possibly preceded, separated, or followed by 3399 * ordinary strings. Control strings begin with 3400 * unpaired percent signs. A pair of successive 3401 * percent signs designates a single percent sign in 3402 * the format. 3403 * @param fmtArg Control string. 3404 * @exception IllegalArgumentException if the control 3405 * string is null, zero length, or otherwise 3406 * malformed. 3407 */ 3408 public PrintfFormat(String fmtArg) 3409 throws IllegalArgumentException { 3410 3411 this(Locale.getDefault(), fmtArg); 3412 } 3413 3414 /** 3415 * Format nothing. Just use the control string. 3416 * @return the formatted String. 3417 */ 3418 public String sprintf() { 3419 3420 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3421 ConversionSpecification cs = null; 3422 char c = 0; 3423 StringBuffer sb = new StringBuffer(); 3424 while (e.hasMoreElements()) { 3425 cs = e.nextElement(); 3426 c = cs.getConversionCharacter(); 3427 if (c == '\0') { 3428 sb.append(cs.getLiteral()); 3429 } else if (c == '%') { 3430 sb.append("%"); 3431 } 3432 } 3433 return sb.toString(); 3434 } 3435 3436 /** 3437 * Format a double. 3438 * @param x The double to format. 3439 * @return The formatted String. 3440 * @exception CmsIllegalArgumentException if the 3441 * conversion character is c, C, s, S, 3442 * d, d, x, X, or o. 3443 */ 3444 public String sprintf(double x) throws CmsIllegalArgumentException { 3445 3446 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3447 ConversionSpecification cs = null; 3448 char c = 0; 3449 StringBuffer sb = new StringBuffer(); 3450 while (e.hasMoreElements()) { 3451 cs = e.nextElement(); 3452 c = cs.getConversionCharacter(); 3453 if (c == '\0') { 3454 sb.append(cs.getLiteral()); 3455 } else if (c == '%') { 3456 sb.append("%"); 3457 } else { 3458 sb.append(cs.internalsprintf(x)); 3459 } 3460 } 3461 return sb.toString(); 3462 } 3463 3464 /** 3465 * Format an int. 3466 * @param x The int to format. 3467 * @return The formatted String. 3468 * @exception CmsIllegalArgumentException if the 3469 * conversion character is f, e, E, g, G, s, 3470 * or S. 3471 */ 3472 public String sprintf(int x) throws CmsIllegalArgumentException { 3473 3474 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3475 ConversionSpecification cs = null; 3476 char c = 0; 3477 StringBuffer sb = new StringBuffer(); 3478 while (e.hasMoreElements()) { 3479 cs = e.nextElement(); 3480 c = cs.getConversionCharacter(); 3481 if (c == '\0') { 3482 sb.append(cs.getLiteral()); 3483 } else if (c == '%') { 3484 sb.append("%"); 3485 } else { 3486 sb.append(cs.internalsprintf(x)); 3487 } 3488 } 3489 return sb.toString(); 3490 } 3491 3492 /** 3493 * Format an long. 3494 * @param x The long to format. 3495 * @return The formatted String. 3496 * @exception CmsIllegalArgumentException if the 3497 * conversion character is f, e, E, g, G, s, 3498 * or S. 3499 */ 3500 public String sprintf(long x) throws CmsIllegalArgumentException { 3501 3502 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3503 ConversionSpecification cs = null; 3504 char c = 0; 3505 StringBuffer sb = new StringBuffer(); 3506 while (e.hasMoreElements()) { 3507 cs = e.nextElement(); 3508 c = cs.getConversionCharacter(); 3509 if (c == '\0') { 3510 sb.append(cs.getLiteral()); 3511 } else if (c == '%') { 3512 sb.append("%"); 3513 } else { 3514 sb.append(cs.internalsprintf(x)); 3515 } 3516 } 3517 return sb.toString(); 3518 } 3519 3520 /** 3521 * Format an Object. Convert wrapper types to 3522 * their primitive equivalents and call the 3523 * appropriate internal formatting method. Convert 3524 * Strings using an internal formatting method for 3525 * Strings. Otherwise use the default formatter 3526 * (use toString). 3527 * @param x the Object to format. 3528 * @return the formatted String. 3529 * @exception CmsIllegalArgumentException if the 3530 * conversion character is inappropriate for 3531 * formatting an unwrapped value. 3532 */ 3533 public String sprintf(Object x) throws CmsIllegalArgumentException { 3534 3535 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3536 ConversionSpecification cs = null; 3537 char c = 0; 3538 StringBuffer sb = new StringBuffer(); 3539 while (e.hasMoreElements()) { 3540 cs = e.nextElement(); 3541 c = cs.getConversionCharacter(); 3542 if (c == '\0') { 3543 sb.append(cs.getLiteral()); 3544 } else if (c == '%') { 3545 sb.append("%"); 3546 } else { 3547 if (x instanceof Byte) { 3548 sb.append(cs.internalsprintf(((Byte)x).byteValue())); 3549 } else if (x instanceof Short) { 3550 sb.append(cs.internalsprintf(((Short)x).shortValue())); 3551 } else if (x instanceof Integer) { 3552 sb.append(cs.internalsprintf(((Integer)x).intValue())); 3553 } else if (x instanceof Long) { 3554 sb.append(cs.internalsprintf(((Long)x).longValue())); 3555 } else if (x instanceof Float) { 3556 sb.append(cs.internalsprintf(((Float)x).floatValue())); 3557 } else if (x instanceof Double) { 3558 sb.append(cs.internalsprintf(((Double)x).doubleValue())); 3559 } else if (x instanceof Character) { 3560 sb.append(cs.internalsprintf(((Character)x).charValue())); 3561 } else if (x instanceof String) { 3562 sb.append(cs.internalsprintf((String)x)); 3563 } else { 3564 sb.append(cs.internalsprintf(x)); 3565 } 3566 } 3567 } 3568 return sb.toString(); 3569 } 3570 3571 /** 3572 * Format an array of objects. Byte, Short, 3573 * Integer, Long, Float, Double, and Character 3574 * arguments are treated as wrappers for primitive 3575 * types. 3576 * @param o The array of objects to format. 3577 * @return The formatted String. 3578 */ 3579 public String sprintf(Object[] o) { 3580 3581 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3582 ConversionSpecification cs = null; 3583 char c = 0; 3584 int i = 0; 3585 StringBuffer sb = new StringBuffer(); 3586 while (e.hasMoreElements()) { 3587 cs = e.nextElement(); 3588 c = cs.getConversionCharacter(); 3589 if (c == '\0') { 3590 sb.append(cs.getLiteral()); 3591 } else if (c == '%') { 3592 sb.append("%"); 3593 } else { 3594 if (cs.isPositionalSpecification()) { 3595 i = cs.getArgumentPosition() - 1; 3596 if (cs.isPositionalFieldWidth()) { 3597 int ifw = cs.getArgumentPositionForFieldWidth() - 1; 3598 cs.setFieldWidthWithArg(((Integer)o[ifw]).intValue()); 3599 } 3600 if (cs.isPositionalPrecision()) { 3601 int ipr = cs.getArgumentPositionForPrecision() - 1; 3602 cs.setPrecisionWithArg(((Integer)o[ipr]).intValue()); 3603 } 3604 } else { 3605 if (cs.isVariableFieldWidth()) { 3606 cs.setFieldWidthWithArg(((Integer)o[i]).intValue()); 3607 i++; 3608 } 3609 if (cs.isVariablePrecision()) { 3610 cs.setPrecisionWithArg(((Integer)o[i]).intValue()); 3611 i++; 3612 } 3613 } 3614 if (o[i] instanceof Byte) { 3615 sb.append(cs.internalsprintf(((Byte)o[i]).byteValue())); 3616 } else if (o[i] instanceof Short) { 3617 sb.append(cs.internalsprintf(((Short)o[i]).shortValue())); 3618 } else if (o[i] instanceof Integer) { 3619 sb.append(cs.internalsprintf(((Integer)o[i]).intValue())); 3620 } else if (o[i] instanceof Long) { 3621 sb.append(cs.internalsprintf(((Long)o[i]).longValue())); 3622 } else if (o[i] instanceof Float) { 3623 sb.append(cs.internalsprintf(((Float)o[i]).floatValue())); 3624 } else if (o[i] instanceof Double) { 3625 sb.append(cs.internalsprintf(((Double)o[i]).doubleValue())); 3626 } else if (o[i] instanceof Character) { 3627 sb.append(cs.internalsprintf(((Character)o[i]).charValue())); 3628 } else if (o[i] instanceof String) { 3629 sb.append(cs.internalsprintf((String)o[i])); 3630 } else { 3631 sb.append(cs.internalsprintf(o[i])); 3632 } 3633 if (!cs.isPositionalSpecification()) { 3634 i++; 3635 } 3636 } 3637 } 3638 return sb.toString(); 3639 } 3640 3641 /** 3642 * Format a String. 3643 * @param x The String to format. 3644 * @return The formatted String. 3645 * @exception CmsIllegalArgumentException if the 3646 * conversion character is neither s nor S. 3647 */ 3648 public String sprintf(String x) throws CmsIllegalArgumentException { 3649 3650 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3651 ConversionSpecification cs = null; 3652 char c = 0; 3653 StringBuffer sb = new StringBuffer(); 3654 while (e.hasMoreElements()) { 3655 cs = e.nextElement(); 3656 c = cs.getConversionCharacter(); 3657 if (c == '\0') { 3658 sb.append(cs.getLiteral()); 3659 } else if (c == '%') { 3660 sb.append("%"); 3661 } else { 3662 sb.append(cs.internalsprintf(x)); 3663 } 3664 } 3665 return sb.toString(); 3666 } 3667 3668 /** 3669 * Return a substring starting at 3670 * <code>start</code> and ending at either the end 3671 * of the String <code>s</code>, the next unpaired 3672 * percent sign, or at the end of the String if the 3673 * last character is a percent sign. 3674 * @param s Control string. 3675 * @param start Position in the string 3676 * <code>s</code> to begin looking for the start 3677 * of a control string. 3678 * @return the substring from the start position 3679 * to the beginning of the control string. 3680 */ 3681 private String nonControl(String s, int start) { 3682 3683 m_cPos = s.indexOf("%", start); 3684 if (m_cPos == -1) { 3685 m_cPos = s.length(); 3686 } 3687 return s.substring(start, m_cPos); 3688 } 3689}