001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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( 821 Messages.get().container( 822 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 823 "double", 824 Character.valueOf(m_conversionCharacter))); 825 } 826 return s2; 827 } 828 829 /** 830 * Format an int argument using this conversion 831 * specification. 832 * @param s the int to format. 833 * @return the formatted String. 834 * @exception CmsIllegalArgumentException if the 835 * conversion character is f, e, E, g, or G. 836 */ 837 String internalsprintf(int s) throws CmsIllegalArgumentException { 838 839 String s2 = ""; 840 switch (m_conversionCharacter) { 841 case 'd': 842 case 'i': 843 if (m_optionalh) { 844 s2 = printDFormat((short)s); 845 } else if (m_optionall) { 846 s2 = printDFormat((long)s); 847 } else { 848 s2 = printDFormat(s); 849 } 850 break; 851 case 'x': 852 case 'X': 853 if (m_optionalh) { 854 s2 = printXFormat((short)s); 855 } else if (m_optionall) { 856 s2 = printXFormat((long)s); 857 } else { 858 s2 = printXFormat(s); 859 } 860 break; 861 case 'o': 862 if (m_optionalh) { 863 s2 = printOFormat((short)s); 864 } else if (m_optionall) { 865 s2 = printOFormat((long)s); 866 } else { 867 s2 = printOFormat(s); 868 } 869 break; 870 case 'c': 871 case 'C': 872 s2 = printCFormat((char)s); 873 break; 874 default: 875 throw new CmsIllegalArgumentException( 876 Messages.get().container( 877 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 878 "int", 879 Character.valueOf(m_conversionCharacter))); 880 } 881 return s2; 882 } 883 884 /** 885 * Format a long argument using this conversion 886 * specification. 887 * @param s the long to format. 888 * @return the formatted String. 889 * @exception CmsIllegalArgumentException if the 890 * conversion character is f, e, E, g, or G. 891 */ 892 String internalsprintf(long s) throws CmsIllegalArgumentException { 893 894 String s2 = ""; 895 switch (m_conversionCharacter) { 896 case 'd': 897 case 'i': 898 if (m_optionalh) { 899 s2 = printDFormat((short)s); 900 } else if (m_optionall) { 901 s2 = printDFormat(s); 902 } else { 903 s2 = printDFormat((int)s); 904 } 905 break; 906 case 'x': 907 case 'X': 908 if (m_optionalh) { 909 s2 = printXFormat((short)s); 910 } else if (m_optionall) { 911 s2 = printXFormat(s); 912 } else { 913 s2 = printXFormat((int)s); 914 } 915 break; 916 case 'o': 917 if (m_optionalh) { 918 s2 = printOFormat((short)s); 919 } else if (m_optionall) { 920 s2 = printOFormat(s); 921 } else { 922 s2 = printOFormat((int)s); 923 } 924 break; 925 case 'c': 926 case 'C': 927 s2 = printCFormat((char)s); 928 break; 929 default: 930 throw new CmsIllegalArgumentException( 931 Messages.get().container( 932 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 933 "long", 934 Character.valueOf(m_conversionCharacter))); 935 } 936 return s2; 937 } 938 939 /** 940 * Format an Object argument using this conversion 941 * specification. 942 * @param s the Object to format. 943 * @return the formatted String. 944 * @exception CmsIllegalArgumentException if the 945 * conversion character is neither s nor S. 946 */ 947 String internalsprintf(Object s) throws CmsIllegalArgumentException { 948 949 String s2 = ""; 950 if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) { 951 s2 = printSFormat(s.toString()); 952 } else { 953 throw new CmsIllegalArgumentException( 954 Messages.get().container( 955 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 956 "String", 957 Character.valueOf(m_conversionCharacter))); 958 } 959 return s2; 960 } 961 962 /** 963 * Format a String argument using this conversion 964 * specification. 965 * @param s the String to format. 966 * @return the formatted String. 967 * @exception CmsIllegalArgumentException if the 968 * conversion character is neither s nor S. 969 */ 970 String internalsprintf(String s) throws CmsIllegalArgumentException { 971 972 String s2 = ""; 973 if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) { 974 s2 = printSFormat(s); 975 } else { 976 throw new CmsIllegalArgumentException( 977 Messages.get().container( 978 Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2, 979 "String", 980 Character.valueOf(m_conversionCharacter))); 981 } 982 return s2; 983 } 984 985 /** 986 * Internal helper.<p> 987 * 988 * @return the result 989 */ 990 boolean isPositionalFieldWidth() { 991 992 return m_positionalFieldWidth; 993 } 994 995 /** 996 * Internal helper.<p> 997 * 998 * @return the result 999 */ 1000 boolean isPositionalPrecision() { 1001 1002 return m_positionalPrecision; 1003 } 1004 1005 /** 1006 * Internal helper.<p> 1007 * 1008 * @return the result 1009 */ 1010 boolean isPositionalSpecification() { 1011 1012 return m_positionalSpecification; 1013 } 1014 1015 /** 1016 * Check whether the specifier has a variable 1017 * field width that is going to be set by an 1018 * argument. 1019 * @return <code>true</code> if the conversion 1020 * uses an * field width; otherwise 1021 * <code>false</code>. 1022 */ 1023 boolean isVariableFieldWidth() { 1024 1025 return m_variableFieldWidth; 1026 } 1027 1028 /** 1029 * Check whether the specifier has a variable 1030 * precision that is going to be set by an 1031 * argument. 1032 * @return <code>true</code> if the conversion 1033 * uses an * precision; otherwise 1034 * <code>false</code>. 1035 */ 1036 boolean isVariablePrecision() { 1037 1038 return m_variablePrecision; 1039 } 1040 1041 /** 1042 * Set the field width with an argument. A 1043 * negative field width is taken as a - flag 1044 * followed by a positive field width. 1045 * @param fw the field width. 1046 */ 1047 void setFieldWidthWithArg(int fw) { 1048 1049 if (fw < 0) { 1050 m_leftJustify = true; 1051 } 1052 m_fieldWidthSet = true; 1053 m_fieldWidth = Math.abs(fw); 1054 } 1055 1056 /** 1057 * Set the String for this instance. 1058 * @param s the String to store. 1059 */ 1060 void setLiteral(String s) { 1061 1062 m_fmt = s; 1063 } 1064 1065 /** 1066 * Set the precision with an argument. A 1067 * negative precision will be changed to zero. 1068 * @param pr the precision. 1069 */ 1070 void setPrecisionWithArg(int pr) { 1071 1072 m_precisionSet = true; 1073 m_precision = Math.max(pr, 0); 1074 } 1075 1076 /** 1077 * Apply zero or blank, left or right padding. 1078 * @param ca4 array of characters before padding is 1079 * finished 1080 * @param noDigits NaN or signed Inf 1081 * @return a padded array of characters 1082 */ 1083 private char[] applyFloatPadding(char[] ca4, boolean noDigits) { 1084 1085 char[] ca5 = ca4; 1086 if (m_fieldWidthSet) { 1087 int i, j, nBlanks; 1088 if (m_leftJustify) { 1089 nBlanks = m_fieldWidth - ca4.length; 1090 if (nBlanks > 0) { 1091 ca5 = new char[ca4.length + nBlanks]; 1092 for (i = 0; i < ca4.length; i++) { 1093 ca5[i] = ca4[i]; 1094 } 1095 for (j = 0; j < nBlanks; j++, i++) { 1096 ca5[i] = ' '; 1097 } 1098 } 1099 } else if (!m_leadingZeros || noDigits) { 1100 nBlanks = m_fieldWidth - ca4.length; 1101 if (nBlanks > 0) { 1102 ca5 = new char[ca4.length + nBlanks]; 1103 for (i = 0; i < nBlanks; i++) { 1104 ca5[i] = ' '; 1105 } 1106 for (j = 0; j < ca4.length; i++, j++) { 1107 ca5[i] = ca4[j]; 1108 } 1109 } 1110 } else if (m_leadingZeros) { 1111 nBlanks = m_fieldWidth - ca4.length; 1112 if (nBlanks > 0) { 1113 ca5 = new char[ca4.length + nBlanks]; 1114 i = 0; 1115 j = 0; 1116 if (ca4[0] == '-') { 1117 ca5[0] = '-'; 1118 i++; 1119 j++; 1120 } 1121 for (int k = 0; k < nBlanks; i++, k++) { 1122 ca5[i] = '0'; 1123 } 1124 for (; j < ca4.length; i++, j++) { 1125 ca5[i] = ca4[j]; 1126 } 1127 } 1128 } 1129 } 1130 return ca5; 1131 } 1132 1133 /** 1134 * Check to see if the digits that are going to 1135 * be truncated because of the precision should 1136 * force a round in the preceding digits. 1137 * @param ca1 the array of digits 1138 * @param icarry the index of the first digit that 1139 * is to be truncated from the print 1140 * @return <code>true</code> if the truncation forces 1141 * a round that will change the print 1142 */ 1143 private boolean checkForCarry(char[] ca1, int icarry) { 1144 1145 boolean carry = false; 1146 if (icarry < ca1.length) { 1147 if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) { 1148 carry = true; 1149 } else if (ca1[icarry] == '5') { 1150 int ii = icarry + 1; 1151 for (; ii < ca1.length; ii++) { 1152 if (ca1[ii] != '0') { 1153 break; 1154 } 1155 } 1156 carry = ii < ca1.length; 1157 if (!carry && (icarry > 0)) { 1158 carry = ((ca1[icarry - 1] == '1') 1159 || (ca1[icarry - 1] == '3') 1160 || (ca1[icarry - 1] == '5') 1161 || (ca1[icarry - 1] == '7') 1162 || (ca1[icarry - 1] == '9')); 1163 } 1164 } 1165 } 1166 return carry; 1167 } 1168 1169 /** 1170 * For e format, the flag character '-', means that 1171 * the output should be left justified within the 1172 * field. The default is to pad with blanks on the 1173 * left. '+' character means that the conversion 1174 * will always begin with a sign (+ or -). The 1175 * blank flag character means that a non-negative 1176 * input will be preceded with a blank. If both a 1177 * '+' and a ' ' are specified, the blank flag is 1178 * ignored. The '0' flag character implies that 1179 * padding to the field width will be done with 1180 * zeros instead of blanks. 1181 * 1182 * The field width is treated as the minimum number 1183 * of characters to be printed. The default is to 1184 * add no padding. Padding is with blanks by 1185 * default. 1186 * 1187 * The precision, if set, is the minimum number of 1188 * digits to appear after the radix character. 1189 * Padding is with trailing 0s. 1190 * 1191 * The behavior is like printf. One (hopefully the 1192 * only) exception is that the minimum number of 1193 * exponent digits is 3 instead of 2 for e and E 1194 * formats when the optional L is used before the 1195 * e, E, g, or G conversion character. The optional 1196 * L does not imply conversion to a long long 1197 * double. 1198 * 1199 * @param x the x parameter 1200 * @param eChar the eChar parameter 1201 * @return the result 1202 */ 1203 private char[] eFormatDigits(double x, char eChar) { 1204 1205 char[] ca1, ca2, ca3; 1206 // int defaultDigits=6; 1207 String sx; 1208 int i, j, k, p; 1209 int expon = 0; 1210 int ePos, rPos, eSize; 1211 boolean minusSign = false; 1212 if (x > 0.0) { 1213 sx = Double.toString(x); 1214 } else if (x < 0.0) { 1215 sx = Double.toString(-x); 1216 minusSign = true; 1217 } else { 1218 sx = Double.toString(x); 1219 if (sx.charAt(0) == '-') { 1220 minusSign = true; 1221 sx = sx.substring(1); 1222 } 1223 } 1224 ePos = sx.indexOf('E'); 1225 if (ePos == -1) { 1226 ePos = sx.indexOf('e'); 1227 } 1228 rPos = sx.indexOf('.'); 1229 if (ePos != -1) { 1230 int ie = ePos + 1; 1231 expon = 0; 1232 if (sx.charAt(ie) == '-') { 1233 for (++ie; ie < sx.length(); ie++) { 1234 if (sx.charAt(ie) != '0') { 1235 break; 1236 } 1237 } 1238 if (ie < sx.length()) { 1239 expon = -Integer.parseInt(sx.substring(ie)); 1240 } 1241 } else { 1242 if (sx.charAt(ie) == '+') { 1243 ++ie; 1244 } 1245 for (; ie < sx.length(); ie++) { 1246 if (sx.charAt(ie) != '0') { 1247 break; 1248 } 1249 } 1250 if (ie < sx.length()) { 1251 expon = Integer.parseInt(sx.substring(ie)); 1252 } 1253 } 1254 } 1255 if (rPos != -1) { 1256 expon += rPos - 1; 1257 } 1258 if (m_precisionSet) { 1259 p = m_precision; 1260 } else { 1261 p = DEFAULT_DIGITS - 1; 1262 } 1263 if ((rPos != -1) && (ePos != -1)) { 1264 ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray(); 1265 } else if (rPos != -1) { 1266 ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray(); 1267 } else if (ePos != -1) { 1268 ca1 = sx.substring(0, ePos).toCharArray(); 1269 } else { 1270 ca1 = sx.toCharArray(); 1271 } 1272 boolean carry = false; 1273 int i0 = 0; 1274 if (ca1[0] != '0') { 1275 i0 = 0; 1276 } else { 1277 for (i0 = 0; i0 < ca1.length; i0++) { 1278 if (ca1[i0] != '0') { 1279 break; 1280 } 1281 } 1282 } 1283 if ((i0 + p) < (ca1.length - 1)) { 1284 carry = checkForCarry(ca1, i0 + p + 1); 1285 if (carry) { 1286 carry = startSymbolicCarry(ca1, i0 + p, i0); 1287 } 1288 if (carry) { 1289 ca2 = new char[i0 + p + 1]; 1290 ca2[i0] = '1'; 1291 for (j = 0; j < i0; j++) { 1292 ca2[j] = '0'; 1293 } 1294 for (i = i0, j = i0 + 1; j < (p + 1); i++, j++) { 1295 ca2[j] = ca1[i]; 1296 } 1297 expon++; 1298 ca1 = ca2; 1299 } 1300 } 1301 if ((Math.abs(expon) < 100) && !m_optionalL) { 1302 eSize = 4; 1303 } else { 1304 eSize = 5; 1305 } 1306 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1307 ca2 = new char[2 + p + eSize]; 1308 } else { 1309 ca2 = new char[1 + eSize]; 1310 } 1311 if (ca1[0] != '0') { 1312 ca2[0] = ca1[0]; 1313 j = 1; 1314 } else { 1315 for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++) { 1316 if (ca1[j] != '0') { 1317 break; 1318 } 1319 } 1320 if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) { 1321 ca2[0] = ca1[j]; 1322 expon -= j; 1323 j++; 1324 } else { 1325 ca2[0] = '0'; 1326 j = 2; 1327 } 1328 } 1329 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1330 ca2[1] = '.'; 1331 i = 2; 1332 } else { 1333 i = 1; 1334 } 1335 for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) { 1336 ca2[i] = ca1[j]; 1337 } 1338 for (; i < (ca2.length - eSize); i++) { 1339 ca2[i] = '0'; 1340 } 1341 ca2[i++] = eChar; 1342 if (expon < 0) { 1343 ca2[i++] = '-'; 1344 } else { 1345 ca2[i++] = '+'; 1346 } 1347 expon = Math.abs(expon); 1348 if (expon >= 100) { 1349 switch (expon / 100) { 1350 case 1: 1351 ca2[i] = '1'; 1352 break; 1353 case 2: 1354 ca2[i] = '2'; 1355 break; 1356 case 3: 1357 ca2[i] = '3'; 1358 break; 1359 case 4: 1360 ca2[i] = '4'; 1361 break; 1362 case 5: 1363 ca2[i] = '5'; 1364 break; 1365 case 6: 1366 ca2[i] = '6'; 1367 break; 1368 case 7: 1369 ca2[i] = '7'; 1370 break; 1371 case 8: 1372 ca2[i] = '8'; 1373 break; 1374 case 9: 1375 ca2[i] = '9'; 1376 break; 1377 default: 1378 // noop 1379 } 1380 i++; 1381 } 1382 switch ((expon % 100) / 10) { 1383 case 0: 1384 ca2[i] = '0'; 1385 break; 1386 case 1: 1387 ca2[i] = '1'; 1388 break; 1389 case 2: 1390 ca2[i] = '2'; 1391 break; 1392 case 3: 1393 ca2[i] = '3'; 1394 break; 1395 case 4: 1396 ca2[i] = '4'; 1397 break; 1398 case 5: 1399 ca2[i] = '5'; 1400 break; 1401 case 6: 1402 ca2[i] = '6'; 1403 break; 1404 case 7: 1405 ca2[i] = '7'; 1406 break; 1407 case 8: 1408 ca2[i] = '8'; 1409 break; 1410 case 9: 1411 ca2[i] = '9'; 1412 break; 1413 default: 1414 // noop 1415 } 1416 i++; 1417 switch (expon % 10) { 1418 case 0: 1419 ca2[i] = '0'; 1420 break; 1421 case 1: 1422 ca2[i] = '1'; 1423 break; 1424 case 2: 1425 ca2[i] = '2'; 1426 break; 1427 case 3: 1428 ca2[i] = '3'; 1429 break; 1430 case 4: 1431 ca2[i] = '4'; 1432 break; 1433 case 5: 1434 ca2[i] = '5'; 1435 break; 1436 case 6: 1437 ca2[i] = '6'; 1438 break; 1439 case 7: 1440 ca2[i] = '7'; 1441 break; 1442 case 8: 1443 ca2[i] = '8'; 1444 break; 1445 case 9: 1446 ca2[i] = '9'; 1447 break; 1448 default: 1449 // noop 1450 } 1451 int nZeros = 0; 1452 if (!m_leftJustify && m_leadingZeros) { 1453 int xThousands = 0; 1454 if (m_thousands) { 1455 int xlead = 0; 1456 if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) { 1457 xlead = 1; 1458 } 1459 int xdp = xlead; 1460 for (; xdp < ca2.length; xdp++) { 1461 if (ca2[xdp] == '.') { 1462 break; 1463 } 1464 } 1465 xThousands = (xdp - xlead) / 3; 1466 } 1467 if (m_fieldWidthSet) { 1468 nZeros = m_fieldWidth - ca2.length; 1469 } 1470 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1471 nZeros--; 1472 } 1473 nZeros -= xThousands; 1474 if (nZeros < 0) { 1475 nZeros = 0; 1476 } 1477 } 1478 j = 0; 1479 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1480 ca3 = new char[ca2.length + nZeros + 1]; 1481 j++; 1482 } else { 1483 ca3 = new char[ca2.length + nZeros]; 1484 } 1485 if (!minusSign) { 1486 if (m_leadingSign) { 1487 ca3[0] = '+'; 1488 } 1489 if (m_leadingSpace) { 1490 ca3[0] = ' '; 1491 } 1492 } else { 1493 ca3[0] = '-'; 1494 } 1495 for (k = 0; k < nZeros; j++, k++) { 1496 ca3[j] = '0'; 1497 } 1498 for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) { 1499 ca3[j] = ca2[i]; 1500 } 1501 1502 int lead = 0; 1503 if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) { 1504 lead = 1; 1505 } 1506 int dp = lead; 1507 for (; dp < ca3.length; dp++) { 1508 if (ca3[dp] == '.') { 1509 break; 1510 } 1511 } 1512 int nThousands = dp / 3; 1513 // Localize the decimal point. 1514 if (dp < ca3.length) { 1515 ca3[dp] = m_dfs.getDecimalSeparator(); 1516 } 1517 char[] ca4 = ca3; 1518 if (m_thousands && (nThousands > 0)) { 1519 ca4 = new char[ca3.length + nThousands + lead]; 1520 ca4[0] = ca3[0]; 1521 for (i = lead, k = lead; i < dp; i++) { 1522 if ((i > 0) && (((dp - i) % 3) == 0)) { 1523 // ca4[k]=','; 1524 ca4[k] = m_dfs.getGroupingSeparator(); 1525 ca4[k + 1] = ca3[i]; 1526 k += 2; 1527 } else { 1528 ca4[k] = ca3[i]; 1529 k++; 1530 } 1531 } 1532 for (; i < ca3.length; i++, k++) { 1533 ca4[k] = ca3[i]; 1534 } 1535 } 1536 return ca4; 1537 } 1538 1539 /** 1540 * An intermediate routine on the way to creating 1541 * an e format String. The method decides whether 1542 * the input double value is an infinity, 1543 * not-a-number, or a finite double and formats 1544 * each type of input appropriately. 1545 * @param x the double value to be formatted. 1546 * @param eChar an 'e' or 'E' to use in the 1547 * converted double value. 1548 * @return the converted double value. 1549 */ 1550 private String eFormatString(double x, char eChar) { 1551 1552 char[] ca4, ca5; 1553 if (Double.isInfinite(x)) { 1554 if (x == Double.POSITIVE_INFINITY) { 1555 if (m_leadingSign) { 1556 ca4 = "+Inf".toCharArray(); 1557 } else if (m_leadingSpace) { 1558 ca4 = " Inf".toCharArray(); 1559 } else { 1560 ca4 = "Inf".toCharArray(); 1561 } 1562 } else { 1563 ca4 = "-Inf".toCharArray(); 1564 } 1565 } else if (Double.isNaN(x)) { 1566 if (m_leadingSign) { 1567 ca4 = "+NaN".toCharArray(); 1568 } else if (m_leadingSpace) { 1569 ca4 = " NaN".toCharArray(); 1570 } else { 1571 ca4 = "NaN".toCharArray(); 1572 } 1573 } else { 1574 ca4 = eFormatDigits(x, eChar); 1575 } 1576 ca5 = applyFloatPadding(ca4, false); 1577 return new String(ca5); 1578 } 1579 1580 /** 1581 * For f format, the flag character '-', means that 1582 * the output should be left justified within the 1583 * field. The default is to pad with blanks on the 1584 * left. '+' character means that the conversion 1585 * will always begin with a sign (+ or -). The 1586 * blank flag character means that a non-negative 1587 * input will be preceded with a blank. If both 1588 * a '+' and a ' ' are specified, the blank flag 1589 * is ignored. The '0' flag character implies that 1590 * padding to the field width will be done with 1591 * zeros instead of blanks. 1592 * 1593 * The field width is treated as the minimum number 1594 * of characters to be printed. The default is to 1595 * add no padding. Padding is with blanks by 1596 * default. 1597 * 1598 * The precision, if set, is the number of digits 1599 * to appear after the radix character. Padding is 1600 * with trailing 0s. 1601 * 1602 * @param x the paramater 1603 * @return the result 1604 */ 1605 private char[] fFormatDigits(double x) { 1606 1607 // int defaultDigits=6; 1608 String sx; 1609 int i, j, k; 1610 int n1In, n2In; 1611 int expon = 0; 1612 boolean minusSign = false; 1613 if (x > 0.0) { 1614 sx = Double.toString(x); 1615 } else if (x < 0.0) { 1616 sx = Double.toString(-x); 1617 minusSign = true; 1618 } else { 1619 sx = Double.toString(x); 1620 if (sx.charAt(0) == '-') { 1621 minusSign = true; 1622 sx = sx.substring(1); 1623 } 1624 } 1625 int ePos = sx.indexOf('E'); 1626 int rPos = sx.indexOf('.'); 1627 if (rPos != -1) { 1628 n1In = rPos; 1629 } else if (ePos != -1) { 1630 n1In = ePos; 1631 } else { 1632 n1In = sx.length(); 1633 } 1634 if (rPos != -1) { 1635 if (ePos != -1) { 1636 n2In = ePos - rPos - 1; 1637 } else { 1638 n2In = sx.length() - rPos - 1; 1639 } 1640 } else { 1641 n2In = 0; 1642 } 1643 if (ePos != -1) { 1644 int ie = ePos + 1; 1645 expon = 0; 1646 if (sx.charAt(ie) == '-') { 1647 for (++ie; ie < sx.length(); ie++) { 1648 if (sx.charAt(ie) != '0') { 1649 break; 1650 } 1651 } 1652 if (ie < sx.length()) { 1653 expon = -Integer.parseInt(sx.substring(ie)); 1654 } 1655 } else { 1656 if (sx.charAt(ie) == '+') { 1657 ++ie; 1658 } 1659 for (; ie < sx.length(); ie++) { 1660 if (sx.charAt(ie) != '0') { 1661 break; 1662 } 1663 } 1664 if (ie < sx.length()) { 1665 expon = Integer.parseInt(sx.substring(ie)); 1666 } 1667 } 1668 } 1669 int p; 1670 if (m_precisionSet) { 1671 p = m_precision; 1672 } else { 1673 p = DEFAULT_DIGITS - 1; 1674 } 1675 char[] ca1 = sx.toCharArray(); 1676 char[] ca2 = new char[n1In + n2In]; 1677 char[] ca3, ca4, ca5; 1678 for (j = 0; j < n1In; j++) { 1679 ca2[j] = ca1[j]; 1680 } 1681 i = j + 1; 1682 for (k = 0; k < n2In; j++, i++, k++) { 1683 ca2[j] = ca1[i]; 1684 } 1685 if ((n1In + expon) <= 0) { 1686 ca3 = new char[-expon + n2In]; 1687 for (j = 0, k = 0; k < (-n1In - expon); k++, j++) { 1688 ca3[j] = '0'; 1689 } 1690 for (i = 0; i < (n1In + n2In); i++, j++) { 1691 ca3[j] = ca2[i]; 1692 } 1693 } else { 1694 ca3 = ca2; 1695 } 1696 boolean carry = false; 1697 if (p < (-expon + n2In)) { 1698 if (expon < 0) { 1699 i = p; 1700 } else { 1701 i = p + n1In; 1702 } 1703 carry = checkForCarry(ca3, i); 1704 if (carry) { 1705 carry = startSymbolicCarry(ca3, i - 1, 0); 1706 } 1707 } 1708 if ((n1In + expon) <= 0) { 1709 ca4 = new char[2 + p]; 1710 if (!carry) { 1711 ca4[0] = '0'; 1712 } else { 1713 ca4[0] = '1'; 1714 } 1715 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1716 ca4[1] = '.'; 1717 for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) { 1718 ca4[j] = ca3[i]; 1719 } 1720 for (; j < ca4.length; j++) { 1721 ca4[j] = '0'; 1722 } 1723 } 1724 } else { 1725 if (!carry) { 1726 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1727 ca4 = new char[n1In + expon + p + 1]; 1728 } else { 1729 ca4 = new char[n1In + expon]; 1730 } 1731 j = 0; 1732 } else { 1733 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1734 ca4 = new char[n1In + expon + p + 2]; 1735 } else { 1736 ca4 = new char[n1In + expon + 1]; 1737 } 1738 ca4[0] = '1'; 1739 j = 1; 1740 } 1741 for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) { 1742 ca4[j] = ca3[i]; 1743 } 1744 for (; i < (n1In + expon); i++, j++) { 1745 ca4[j] = '0'; 1746 } 1747 if (m_alternateForm || !m_precisionSet || (m_precision != 0)) { 1748 ca4[j] = '.'; 1749 j++; 1750 for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) { 1751 ca4[j] = ca3[i]; 1752 } 1753 for (; j < ca4.length; j++) { 1754 ca4[j] = '0'; 1755 } 1756 } 1757 } 1758 int nZeros = 0; 1759 if (!m_leftJustify && m_leadingZeros) { 1760 int xThousands = 0; 1761 if (m_thousands) { 1762 int xlead = 0; 1763 if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) { 1764 xlead = 1; 1765 } 1766 int xdp = xlead; 1767 for (; xdp < ca4.length; xdp++) { 1768 if (ca4[xdp] == '.') { 1769 break; 1770 } 1771 } 1772 xThousands = (xdp - xlead) / 3; 1773 } 1774 if (m_fieldWidthSet) { 1775 nZeros = m_fieldWidth - ca4.length; 1776 } 1777 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1778 nZeros--; 1779 } 1780 nZeros -= xThousands; 1781 if (nZeros < 0) { 1782 nZeros = 0; 1783 } 1784 } 1785 j = 0; 1786 if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) { 1787 ca5 = new char[ca4.length + nZeros + 1]; 1788 j++; 1789 } else { 1790 ca5 = new char[ca4.length + nZeros]; 1791 } 1792 if (!minusSign) { 1793 if (m_leadingSign) { 1794 ca5[0] = '+'; 1795 } 1796 if (m_leadingSpace) { 1797 ca5[0] = ' '; 1798 } 1799 } else { 1800 ca5[0] = '-'; 1801 } 1802 for (i = 0; i < nZeros; i++, j++) { 1803 ca5[j] = '0'; 1804 } 1805 for (i = 0; i < ca4.length; i++, j++) { 1806 ca5[j] = ca4[i]; 1807 } 1808 int lead = 0; 1809 if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) { 1810 lead = 1; 1811 } 1812 int dp = lead; 1813 for (; dp < ca5.length; dp++) { 1814 if (ca5[dp] == '.') { 1815 break; 1816 } 1817 } 1818 int nThousands = (dp - lead) / 3; 1819 // Localize the decimal point. 1820 if (dp < ca5.length) { 1821 ca5[dp] = m_dfs.getDecimalSeparator(); 1822 } 1823 char[] ca6 = ca5; 1824 if (m_thousands && (nThousands > 0)) { 1825 ca6 = new char[ca5.length + nThousands + lead]; 1826 ca6[0] = ca5[0]; 1827 for (i = lead, k = lead; i < dp; i++) { 1828 if ((i > 0) && (((dp - i) % 3) == 0)) { 1829 // ca6[k]=','; 1830 ca6[k] = m_dfs.getGroupingSeparator(); 1831 ca6[k + 1] = ca5[i]; 1832 k += 2; 1833 } else { 1834 ca6[k] = ca5[i]; 1835 k++; 1836 } 1837 } 1838 for (; i < ca5.length; i++, k++) { 1839 ca6[k] = ca5[i]; 1840 } 1841 } 1842 return ca6; 1843 } 1844 1845 /** 1846 * An intermediate routine on the way to creating 1847 * an f format String. The method decides whether 1848 * the input double value is an infinity, 1849 * not-a-number, or a finite double and formats 1850 * each type of input appropriately. 1851 * @param x the double value to be formatted. 1852 * @return the converted double value. 1853 */ 1854 private String fFormatString(double x) { 1855 1856 char[] ca6, ca7; 1857 if (Double.isInfinite(x)) { 1858 if (x == Double.POSITIVE_INFINITY) { 1859 if (m_leadingSign) { 1860 ca6 = "+Inf".toCharArray(); 1861 } else if (m_leadingSpace) { 1862 ca6 = " Inf".toCharArray(); 1863 } else { 1864 ca6 = "Inf".toCharArray(); 1865 } 1866 } else { 1867 ca6 = "-Inf".toCharArray(); 1868 } 1869 } else if (Double.isNaN(x)) { 1870 if (m_leadingSign) { 1871 ca6 = "+NaN".toCharArray(); 1872 } else if (m_leadingSpace) { 1873 ca6 = " NaN".toCharArray(); 1874 } else { 1875 ca6 = "NaN".toCharArray(); 1876 } 1877 } else { 1878 ca6 = fFormatDigits(x); 1879 } 1880 ca7 = applyFloatPadding(ca6, false); 1881 return new String(ca7); 1882 } 1883 1884 /** 1885 * Format method for the c conversion character and 1886 * char argument. 1887 * 1888 * The only flag character that affects c format is 1889 * the '-', meaning that the output should be left 1890 * justified within the field. The default is to 1891 * pad with blanks on the left. 1892 * 1893 * The field width is treated as the minimum number 1894 * of characters to be printed. Padding is with 1895 * blanks by default. The default width is 1. 1896 * 1897 * The precision, if set, is ignored. 1898 * @param x the char to format. 1899 * @return the formatted String. 1900 */ 1901 private String printCFormat(char x) { 1902 1903 int nPrint = 1; 1904 int width = m_fieldWidth; 1905 if (!m_fieldWidthSet) { 1906 width = nPrint; 1907 } 1908 char[] ca = new char[width]; 1909 int i = 0; 1910 if (m_leftJustify) { 1911 ca[0] = x; 1912 for (i = 1; i <= (width - nPrint); i++) { 1913 ca[i] = ' '; 1914 } 1915 } else { 1916 for (i = 0; i < (width - nPrint); i++) { 1917 ca[i] = ' '; 1918 } 1919 ca[i] = x; 1920 } 1921 return new String(ca); 1922 } 1923 1924 /** 1925 * Format method for the d conversion character and 1926 * int argument. 1927 * 1928 * For d format, the flag character '-', means that 1929 * the output should be left justified within the 1930 * field. The default is to pad with blanks on the 1931 * left. A '+' character means that the conversion 1932 * will always begin with a sign (+ or -). The 1933 * blank flag character means that a non-negative 1934 * input will be preceded with a blank. If both a 1935 * '+' and a ' ' are specified, the blank flag is 1936 * ignored. The '0' flag character implies that 1937 * padding to the field width will be done with 1938 * zeros instead of blanks. 1939 * 1940 * The field width is treated as the minimum number 1941 * of characters to be printed. The default is to 1942 * add no padding. Padding is with blanks by 1943 * default. 1944 * 1945 * The precision, if set, is the minimum number of 1946 * digits to appear. Padding is with leading 0s. 1947 * @param x the int to format. 1948 * @return the formatted String. 1949 */ 1950 private String printDFormat(int x) { 1951 1952 return printDFormat(Integer.toString(x)); 1953 } 1954 1955 /** 1956 * Format method for the d conversion character and 1957 * long argument. 1958 * 1959 * For d format, the flag character '-', means that 1960 * the output should be left justified within the 1961 * field. The default is to pad with blanks on the 1962 * left. A '+' character means that the conversion 1963 * will always begin with a sign (+ or -). The 1964 * blank flag character means that a non-negative 1965 * input will be preceded with a blank. If both a 1966 * '+' and a ' ' are specified, the blank flag is 1967 * ignored. The '0' flag character implies that 1968 * padding to the field width will be done with 1969 * zeros instead of blanks. 1970 * 1971 * The field width is treated as the minimum number 1972 * of characters to be printed. The default is to 1973 * add no padding. Padding is with blanks by 1974 * default. 1975 * 1976 * The precision, if set, is the minimum number of 1977 * digits to appear. Padding is with leading 0s. 1978 * @param x the long to format. 1979 * @return the formatted String. 1980 */ 1981 private String printDFormat(long x) { 1982 1983 return printDFormat(Long.toString(x)); 1984 } 1985 1986 /** 1987 * Format method for the d conversion specifer and 1988 * short argument. 1989 * 1990 * For d format, the flag character '-', means that 1991 * the output should be left justified within the 1992 * field. The default is to pad with blanks on the 1993 * left. A '+' character means that the conversion 1994 * will always begin with a sign (+ or -). The 1995 * blank flag character means that a non-negative 1996 * input will be preceded with a blank. If both a 1997 * '+' and a ' ' are specified, the blank flag is 1998 * ignored. The '0' flag character implies that 1999 * padding to the field width will be done with 2000 * zeros instead of blanks. 2001 * 2002 * The field width is treated as the minimum number 2003 * of characters to be printed. The default is to 2004 * add no padding. Padding is with blanks by 2005 * default. 2006 * 2007 * The precision, if set, is the minimum number of 2008 * digits to appear. Padding is with leading 0s. 2009 * @param x the short to format. 2010 * @return the formatted String. 2011 */ 2012 private String printDFormat(short x) { 2013 2014 return printDFormat(Short.toString(x)); 2015 } 2016 2017 /** 2018 * Utility method for formatting using the d 2019 * conversion character. 2020 * @param sx the String to format, the result of 2021 * converting a short, int, or long to a 2022 * String. 2023 * @return the formatted String. 2024 */ 2025 private String printDFormat(String sx) { 2026 2027 int nLeadingZeros = 0; 2028 int nBlanks = 0, n = 0; 2029 int i = 0, jFirst = 0; 2030 boolean neg = sx.charAt(0) == '-'; 2031 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2032 sx = ""; 2033 } 2034 if (!neg) { 2035 if (m_precisionSet && (sx.length() < m_precision)) { 2036 nLeadingZeros = m_precision - sx.length(); 2037 } 2038 } else { 2039 if (m_precisionSet && ((sx.length() - 1) < m_precision)) { 2040 nLeadingZeros = (m_precision - sx.length()) + 1; 2041 } 2042 } 2043 if (nLeadingZeros < 0) { 2044 nLeadingZeros = 0; 2045 } 2046 if (m_fieldWidthSet) { 2047 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2048 if (!neg && (m_leadingSign || m_leadingSpace)) { 2049 nBlanks--; 2050 } 2051 } 2052 if (nBlanks < 0) { 2053 nBlanks = 0; 2054 } 2055 if (m_leadingSign) { 2056 n++; 2057 } else if (m_leadingSpace) { 2058 n++; 2059 } 2060 n += nBlanks; 2061 n += nLeadingZeros; 2062 n += sx.length(); 2063 char[] ca = new char[n]; 2064 if (m_leftJustify) { 2065 if (neg) { 2066 ca[i++] = '-'; 2067 } else if (m_leadingSign) { 2068 ca[i++] = '+'; 2069 } else if (m_leadingSpace) { 2070 ca[i++] = ' '; 2071 } 2072 char[] csx = sx.toCharArray(); 2073 jFirst = neg ? 1 : 0; 2074 for (int j = 0; j < nLeadingZeros; i++, j++) { 2075 ca[i] = '0'; 2076 } 2077 for (int j = jFirst; j < csx.length; j++, i++) { 2078 ca[i] = csx[j]; 2079 } 2080 for (int j = 0; j < nBlanks; i++, j++) { 2081 ca[i] = ' '; 2082 } 2083 } else { 2084 if (!m_leadingZeros) { 2085 for (i = 0; i < nBlanks; i++) { 2086 ca[i] = ' '; 2087 } 2088 if (neg) { 2089 ca[i++] = '-'; 2090 } else if (m_leadingSign) { 2091 ca[i++] = '+'; 2092 } else if (m_leadingSpace) { 2093 ca[i++] = ' '; 2094 } 2095 } else { 2096 if (neg) { 2097 ca[i++] = '-'; 2098 } else if (m_leadingSign) { 2099 ca[i++] = '+'; 2100 } else if (m_leadingSpace) { 2101 ca[i++] = ' '; 2102 } 2103 for (int j = 0; j < nBlanks; j++, i++) { 2104 ca[i] = '0'; 2105 } 2106 } 2107 for (int j = 0; j < nLeadingZeros; j++, i++) { 2108 ca[i] = '0'; 2109 } 2110 char[] csx = sx.toCharArray(); 2111 jFirst = neg ? 1 : 0; 2112 for (int j = jFirst; j < csx.length; j++, i++) { 2113 ca[i] = csx[j]; 2114 } 2115 } 2116 return new String(ca); 2117 } 2118 2119 /** 2120 * Format method for the e or E conversion 2121 * character. 2122 * @param x the double to format. 2123 * @return the formatted String. 2124 */ 2125 private String printEFormat(double x) { 2126 2127 if (m_conversionCharacter == 'e') { 2128 return eFormatString(x, 'e'); 2129 } else { 2130 return eFormatString(x, 'E'); 2131 } 2132 } 2133 2134 /** 2135 * Format method for the f conversion character. 2136 * @param x the double to format. 2137 * @return the formatted String. 2138 */ 2139 private String printFFormat(double x) { 2140 2141 return fFormatString(x); 2142 } 2143 2144 /** 2145 * Format method for the g conversion character. 2146 * 2147 * For g format, the flag character '-', means that 2148 * the output should be left justified within the 2149 * field. The default is to pad with blanks on the 2150 * left. '+' character means that the conversion 2151 * will always begin with a sign (+ or -). The 2152 * blank flag character means that a non-negative 2153 * input will be preceded with a blank. If both a 2154 * '+' and a ' ' are specified, the blank flag is 2155 * ignored. The '0' flag character implies that 2156 * padding to the field width will be done with 2157 * zeros instead of blanks. 2158 * 2159 * The field width is treated as the minimum number 2160 * of characters to be printed. The default is to 2161 * add no padding. Padding is with blanks by 2162 * default. 2163 * 2164 * The precision, if set, is the minimum number of 2165 * digits to appear after the radix character. 2166 * Padding is with trailing 0s. 2167 * @param x the double to format. 2168 * @return the formatted String. 2169 */ 2170 private String printGFormat(double x) { 2171 2172 String sx, sy, sz, ret; 2173 int savePrecision = m_precision; 2174 int i; 2175 char[] ca4, ca5; 2176 if (Double.isInfinite(x)) { 2177 if (x == Double.POSITIVE_INFINITY) { 2178 if (m_leadingSign) { 2179 ca4 = "+Inf".toCharArray(); 2180 } else if (m_leadingSpace) { 2181 ca4 = " Inf".toCharArray(); 2182 } else { 2183 ca4 = "Inf".toCharArray(); 2184 } 2185 } else { 2186 ca4 = "-Inf".toCharArray(); 2187 } 2188 } else if (Double.isNaN(x)) { 2189 if (m_leadingSign) { 2190 ca4 = "+NaN".toCharArray(); 2191 } else if (m_leadingSpace) { 2192 ca4 = " NaN".toCharArray(); 2193 } else { 2194 ca4 = "NaN".toCharArray(); 2195 } 2196 } else { 2197 if (!m_precisionSet) { 2198 m_precision = DEFAULT_DIGITS; 2199 } 2200 if (m_precision == 0) { 2201 m_precision = 1; 2202 } 2203 int ePos = -1; 2204 if (m_conversionCharacter == 'g') { 2205 sx = eFormatString(x, 'e').trim(); 2206 ePos = sx.indexOf('e'); 2207 } else { 2208 sx = eFormatString(x, 'E').trim(); 2209 ePos = sx.indexOf('E'); 2210 } 2211 i = ePos + 1; 2212 int expon = 0; 2213 if (sx.charAt(i) == '-') { 2214 for (++i; i < sx.length(); i++) { 2215 if (sx.charAt(i) != '0') { 2216 break; 2217 } 2218 } 2219 if (i < sx.length()) { 2220 expon = -Integer.parseInt(sx.substring(i)); 2221 } 2222 } else { 2223 if (sx.charAt(i) == '+') { 2224 ++i; 2225 } 2226 for (; i < sx.length(); i++) { 2227 if (sx.charAt(i) != '0') { 2228 break; 2229 } 2230 } 2231 if (i < sx.length()) { 2232 expon = Integer.parseInt(sx.substring(i)); 2233 } 2234 } 2235 // Trim trailing zeros. 2236 // If the radix character is not followed by 2237 // a digit, trim it, too. 2238 if (!m_alternateForm) { 2239 if ((expon >= -4) && (expon < m_precision)) { 2240 sy = fFormatString(x).trim(); 2241 } else { 2242 sy = sx.substring(0, ePos); 2243 } 2244 i = sy.length() - 1; 2245 for (; i >= 0; i--) { 2246 if (sy.charAt(i) != '0') { 2247 break; 2248 } 2249 } 2250 if ((i >= 0) && (sy.charAt(i) == '.')) { 2251 i--; 2252 } 2253 if (i == -1) { 2254 sz = "0"; 2255 } else if (!Character.isDigit(sy.charAt(i))) { 2256 sz = sy.substring(0, i + 1) + "0"; 2257 } else { 2258 sz = sy.substring(0, i + 1); 2259 } 2260 if ((expon >= -4) && (expon < m_precision)) { 2261 ret = sz; 2262 } else { 2263 ret = sz + sx.substring(ePos); 2264 } 2265 } else { 2266 if ((expon >= -4) && (expon < m_precision)) { 2267 ret = fFormatString(x).trim(); 2268 } else { 2269 ret = sx; 2270 } 2271 } 2272 // leading space was trimmed off during 2273 // construction 2274 if (m_leadingSpace) { 2275 if (x >= 0) { 2276 ret = " " + ret; 2277 } 2278 } 2279 ca4 = ret.toCharArray(); 2280 } 2281 // Pad with blanks or zeros. 2282 ca5 = applyFloatPadding(ca4, false); 2283 m_precision = savePrecision; 2284 return new String(ca5); 2285 } 2286 2287 /** 2288 * Format method for the o conversion character and 2289 * int argument. 2290 * 2291 * For o format, the flag character '-', means that 2292 * the output should be left justified within the 2293 * field. The default is to pad with blanks on the 2294 * left. The '#' flag character means that the 2295 * output begins with a leading 0 and the precision 2296 * is increased by 1. 2297 * 2298 * The field width is treated as the minimum number 2299 * of characters to be printed. The default is to 2300 * add no padding. Padding is with blanks by 2301 * default. 2302 * 2303 * The precision, if set, is the minimum number of 2304 * digits to appear. Padding is with leading 0s. 2305 * @param x the int to format. 2306 * @return the formatted String. 2307 */ 2308 private String printOFormat(int x) { 2309 2310 String sx = null; 2311 if (x == Integer.MIN_VALUE) { 2312 sx = "20000000000"; 2313 } else if (x < 0) { 2314 String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8); 2315 switch (t.length()) { 2316 case 1: 2317 sx = "2000000000" + t; 2318 break; 2319 case 2: 2320 sx = "200000000" + t; 2321 break; 2322 case 3: 2323 sx = "20000000" + t; 2324 break; 2325 case 4: 2326 sx = "2000000" + t; 2327 break; 2328 case 5: 2329 sx = "200000" + t; 2330 break; 2331 case 6: 2332 sx = "20000" + t; 2333 break; 2334 case 7: 2335 sx = "2000" + t; 2336 break; 2337 case 8: 2338 sx = "200" + t; 2339 break; 2340 case 9: 2341 sx = "20" + t; 2342 break; 2343 case 10: 2344 sx = "2" + t; 2345 break; 2346 case 11: 2347 sx = "3" + t.substring(1); 2348 break; 2349 default: 2350 // noop 2351 } 2352 } else { 2353 sx = Integer.toString(x, 8); 2354 } 2355 return printOFormat(sx); 2356 } 2357 2358 /** 2359 * Format method for the o conversion character and 2360 * long argument. 2361 * 2362 * For o format, the flag character '-', means that 2363 * the output should be left justified within the 2364 * field. The default is to pad with blanks on the 2365 * left. The '#' flag character means that the 2366 * output begins with a leading 0 and the precision 2367 * is increased by 1. 2368 * 2369 * The field width is treated as the minimum number 2370 * of characters to be printed. The default is to 2371 * add no padding. Padding is with blanks by 2372 * default. 2373 * 2374 * The precision, if set, is the minimum number of 2375 * digits to appear. Padding is with leading 0s. 2376 * @param x the long to format. 2377 * @return the formatted String. 2378 */ 2379 private String printOFormat(long x) { 2380 2381 String sx = null; 2382 if (x == Long.MIN_VALUE) { 2383 sx = "1000000000000000000000"; 2384 } else if (x < 0) { 2385 String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8); 2386 switch (t.length()) { 2387 case 1: 2388 sx = "100000000000000000000" + t; 2389 break; 2390 case 2: 2391 sx = "10000000000000000000" + t; 2392 break; 2393 case 3: 2394 sx = "1000000000000000000" + t; 2395 break; 2396 case 4: 2397 sx = "100000000000000000" + t; 2398 break; 2399 case 5: 2400 sx = "10000000000000000" + t; 2401 break; 2402 case 6: 2403 sx = "1000000000000000" + t; 2404 break; 2405 case 7: 2406 sx = "100000000000000" + t; 2407 break; 2408 case 8: 2409 sx = "10000000000000" + t; 2410 break; 2411 case 9: 2412 sx = "1000000000000" + t; 2413 break; 2414 case 10: 2415 sx = "100000000000" + t; 2416 break; 2417 case 11: 2418 sx = "10000000000" + t; 2419 break; 2420 case 12: 2421 sx = "1000000000" + t; 2422 break; 2423 case 13: 2424 sx = "100000000" + t; 2425 break; 2426 case 14: 2427 sx = "10000000" + t; 2428 break; 2429 case 15: 2430 sx = "1000000" + t; 2431 break; 2432 case 16: 2433 sx = "100000" + t; 2434 break; 2435 case 17: 2436 sx = "10000" + t; 2437 break; 2438 case 18: 2439 sx = "1000" + t; 2440 break; 2441 case 19: 2442 sx = "100" + t; 2443 break; 2444 case 20: 2445 sx = "10" + t; 2446 break; 2447 case 21: 2448 sx = "1" + t; 2449 break; 2450 default: 2451 // noop 2452 } 2453 } else { 2454 sx = Long.toString(x, 8); 2455 } 2456 return printOFormat(sx); 2457 } 2458 2459 /** 2460 * Format method for the o conversion character and 2461 * short argument. 2462 * 2463 * For o format, the flag character '-', means that 2464 * the output should be left justified within the 2465 * field. The default is to pad with blanks on the 2466 * left. The '#' flag character means that the 2467 * output begins with a leading 0 and the precision 2468 * is increased by 1. 2469 * 2470 * The field width is treated as the minimum number 2471 * of characters to be printed. The default is to 2472 * add no padding. Padding is with blanks by 2473 * default. 2474 * 2475 * The precision, if set, is the minimum number of 2476 * digits to appear. Padding is with leading 0s. 2477 * @param x the short to format. 2478 * @return the formatted String. 2479 */ 2480 private String printOFormat(short x) { 2481 2482 String sx = null; 2483 if (x == Short.MIN_VALUE) { 2484 sx = "100000"; 2485 } else if (x < 0) { 2486 String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8); 2487 switch (t.length()) { 2488 case 1: 2489 sx = "10000" + t; 2490 break; 2491 case 2: 2492 sx = "1000" + t; 2493 break; 2494 case 3: 2495 sx = "100" + t; 2496 break; 2497 case 4: 2498 sx = "10" + t; 2499 break; 2500 case 5: 2501 sx = "1" + t; 2502 break; 2503 default: 2504 // noop 2505 } 2506 } else { 2507 sx = Integer.toString(x, 8); 2508 } 2509 return printOFormat(sx); 2510 } 2511 2512 /** 2513 * Utility method for formatting using the o 2514 * conversion character. 2515 * @param sx the String to format, the result of 2516 * converting a short, int, or long to a 2517 * String. 2518 * @return the formatted String. 2519 */ 2520 private String printOFormat(String sx) { 2521 2522 int nLeadingZeros = 0; 2523 int nBlanks = 0; 2524 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2525 sx = ""; 2526 } 2527 if (m_precisionSet) { 2528 nLeadingZeros = m_precision - sx.length(); 2529 } 2530 if (m_alternateForm) { 2531 nLeadingZeros++; 2532 } 2533 if (nLeadingZeros < 0) { 2534 nLeadingZeros = 0; 2535 } 2536 if (m_fieldWidthSet) { 2537 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2538 } 2539 if (nBlanks < 0) { 2540 nBlanks = 0; 2541 } 2542 int n = nLeadingZeros + sx.length() + nBlanks; 2543 char[] ca = new char[n]; 2544 int i; 2545 if (m_leftJustify) { 2546 for (i = 0; i < nLeadingZeros; i++) { 2547 ca[i] = '0'; 2548 } 2549 char[] csx = sx.toCharArray(); 2550 for (int j = 0; j < csx.length; j++, i++) { 2551 ca[i] = csx[j]; 2552 } 2553 for (int j = 0; j < nBlanks; j++, i++) { 2554 ca[i] = ' '; 2555 } 2556 } else { 2557 if (m_leadingZeros) { 2558 for (i = 0; i < nBlanks; i++) { 2559 ca[i] = '0'; 2560 } 2561 } else { 2562 for (i = 0; i < nBlanks; i++) { 2563 ca[i] = ' '; 2564 } 2565 } 2566 for (int j = 0; j < nLeadingZeros; j++, i++) { 2567 ca[i] = '0'; 2568 } 2569 char[] csx = sx.toCharArray(); 2570 for (int j = 0; j < csx.length; j++, i++) { 2571 ca[i] = csx[j]; 2572 } 2573 } 2574 return new String(ca); 2575 } 2576 2577 /** 2578 * Format method for the s conversion character and 2579 * String argument. 2580 * 2581 * The only flag character that affects s format is 2582 * the '-', meaning that the output should be left 2583 * justified within the field. The default is to 2584 * pad with blanks on the left. 2585 * 2586 * The field width is treated as the minimum number 2587 * of characters to be printed. The default is the 2588 * smaller of the number of characters in the the 2589 * input and the precision. Padding is with blanks 2590 * by default. 2591 * 2592 * The precision, if set, specifies the maximum 2593 * number of characters to be printed from the 2594 * string. A null digit string is treated 2595 * as a 0. The default is not to set a maximum 2596 * number of characters to be printed. 2597 * @param x the String to format. 2598 * @return the formatted String. 2599 */ 2600 private String printSFormat(String x) { 2601 2602 int nPrint = x.length(); 2603 int width = m_fieldWidth; 2604 if (m_precisionSet && (nPrint > m_precision)) { 2605 nPrint = m_precision; 2606 } 2607 if (!m_fieldWidthSet) { 2608 width = nPrint; 2609 } 2610 int n = 0; 2611 if (width > nPrint) { 2612 n += width - nPrint; 2613 } 2614 if (nPrint >= x.length()) { 2615 n += x.length(); 2616 } else { 2617 n += nPrint; 2618 } 2619 char[] ca = new char[n]; 2620 int i = 0; 2621 if (m_leftJustify) { 2622 if (nPrint >= x.length()) { 2623 char[] csx = x.toCharArray(); 2624 for (i = 0; i < x.length(); i++) { 2625 ca[i] = csx[i]; 2626 } 2627 } else { 2628 char[] csx = x.substring(0, nPrint).toCharArray(); 2629 for (i = 0; i < nPrint; i++) { 2630 ca[i] = csx[i]; 2631 } 2632 } 2633 for (int j = 0; j < (width - nPrint); j++, i++) { 2634 ca[i] = ' '; 2635 } 2636 } else { 2637 for (i = 0; i < (width - nPrint); i++) { 2638 ca[i] = ' '; 2639 } 2640 if (nPrint >= x.length()) { 2641 char[] csx = x.toCharArray(); 2642 for (int j = 0; j < x.length(); i++, j++) { 2643 ca[i] = csx[j]; 2644 } 2645 } else { 2646 char[] csx = x.substring(0, nPrint).toCharArray(); 2647 for (int j = 0; j < nPrint; i++, j++) { 2648 ca[i] = csx[j]; 2649 } 2650 } 2651 } 2652 return new String(ca); 2653 } 2654 2655 /** 2656 * Format method for the x conversion character and 2657 * int argument. 2658 * 2659 * For x format, the flag character '-', means that 2660 * the output should be left justified within the 2661 * field. The default is to pad with blanks on the 2662 * left. The '#' flag character means to lead with 2663 * '0x'. 2664 * 2665 * The field width is treated as the minimum number 2666 * of characters to be printed. The default is to 2667 * add no padding. Padding is with blanks by 2668 * default. 2669 * 2670 * The precision, if set, is the minimum number of 2671 * digits to appear. Padding is with leading 0s. 2672 * @param x the int to format. 2673 * @return the formatted String. 2674 */ 2675 private String printXFormat(int x) { 2676 2677 String sx = null; 2678 if (x == Integer.MIN_VALUE) { 2679 sx = "80000000"; 2680 } else if (x < 0) { 2681 String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16); 2682 switch (t.length()) { 2683 case 1: 2684 sx = "8000000" + t; 2685 break; 2686 case 2: 2687 sx = "800000" + t; 2688 break; 2689 case 3: 2690 sx = "80000" + t; 2691 break; 2692 case 4: 2693 sx = "8000" + t; 2694 break; 2695 case 5: 2696 sx = "800" + t; 2697 break; 2698 case 6: 2699 sx = "80" + t; 2700 break; 2701 case 7: 2702 sx = "8" + t; 2703 break; 2704 case 8: 2705 switch (t.charAt(0)) { 2706 case '1': 2707 sx = "9" + t.substring(1, 8); 2708 break; 2709 case '2': 2710 sx = "a" + t.substring(1, 8); 2711 break; 2712 case '3': 2713 sx = "b" + t.substring(1, 8); 2714 break; 2715 case '4': 2716 sx = "c" + t.substring(1, 8); 2717 break; 2718 case '5': 2719 sx = "d" + t.substring(1, 8); 2720 break; 2721 case '6': 2722 sx = "e" + t.substring(1, 8); 2723 break; 2724 case '7': 2725 sx = "f" + t.substring(1, 8); 2726 break; 2727 default: 2728 // noop 2729 } 2730 break; 2731 default: 2732 // noop 2733 } 2734 } else { 2735 sx = Integer.toString(x, 16); 2736 } 2737 return printXFormat(sx); 2738 } 2739 2740 /** 2741 * Format method for the x conversion character and 2742 * long argument. 2743 * 2744 * For x format, the flag character '-', means that 2745 * the output should be left justified within the 2746 * field. The default is to pad with blanks on the 2747 * left. The '#' flag character means to lead with 2748 * '0x'. 2749 * 2750 * The field width is treated as the minimum number 2751 * of characters to be printed. The default is to 2752 * add no padding. Padding is with blanks by 2753 * default. 2754 * 2755 * The precision, if set, is the minimum number of 2756 * digits to appear. Padding is with leading 0s. 2757 * @param x the long to format. 2758 * @return the formatted String. 2759 */ 2760 private String printXFormat(long x) { 2761 2762 String sx = null; 2763 if (x == Long.MIN_VALUE) { 2764 sx = "8000000000000000"; 2765 } else if (x < 0) { 2766 String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16); 2767 switch (t.length()) { 2768 case 1: 2769 sx = "800000000000000" + t; 2770 break; 2771 case 2: 2772 sx = "80000000000000" + t; 2773 break; 2774 case 3: 2775 sx = "8000000000000" + t; 2776 break; 2777 case 4: 2778 sx = "800000000000" + t; 2779 break; 2780 case 5: 2781 sx = "80000000000" + t; 2782 break; 2783 case 6: 2784 sx = "8000000000" + t; 2785 break; 2786 case 7: 2787 sx = "800000000" + t; 2788 break; 2789 case 8: 2790 sx = "80000000" + t; 2791 break; 2792 case 9: 2793 sx = "8000000" + t; 2794 break; 2795 case 10: 2796 sx = "800000" + t; 2797 break; 2798 case 11: 2799 sx = "80000" + t; 2800 break; 2801 case 12: 2802 sx = "8000" + t; 2803 break; 2804 case 13: 2805 sx = "800" + t; 2806 break; 2807 case 14: 2808 sx = "80" + t; 2809 break; 2810 case 15: 2811 sx = "8" + t; 2812 break; 2813 case 16: 2814 switch (t.charAt(0)) { 2815 case '1': 2816 sx = "9" + t.substring(1, 16); 2817 break; 2818 case '2': 2819 sx = "a" + t.substring(1, 16); 2820 break; 2821 case '3': 2822 sx = "b" + t.substring(1, 16); 2823 break; 2824 case '4': 2825 sx = "c" + t.substring(1, 16); 2826 break; 2827 case '5': 2828 sx = "d" + t.substring(1, 16); 2829 break; 2830 case '6': 2831 sx = "e" + t.substring(1, 16); 2832 break; 2833 case '7': 2834 sx = "f" + t.substring(1, 16); 2835 break; 2836 default: 2837 // noop 2838 } 2839 break; 2840 default: 2841 // noop 2842 } 2843 } else { 2844 sx = Long.toString(x, 16); 2845 } 2846 return printXFormat(sx); 2847 } 2848 2849 /** 2850 * Format method for the x conversion character and 2851 * short argument. 2852 * 2853 * For x format, the flag character '-', means that 2854 * the output should be left justified within the 2855 * field. The default is to pad with blanks on the 2856 * left. The '#' flag character means to lead with 2857 * '0x'. 2858 * 2859 * The field width is treated as the minimum number 2860 * of characters to be printed. The default is to 2861 * add no padding. Padding is with blanks by 2862 * default. 2863 * 2864 * The precision, if set, is the minimum number of 2865 * digits to appear. Padding is with leading 0s. 2866 * @param x the short to format. 2867 * @return the formatted String. 2868 */ 2869 private String printXFormat(short x) { 2870 2871 String sx = null; 2872 if (x == Short.MIN_VALUE) { 2873 sx = "8000"; 2874 } else if (x < 0) { 2875 String t; 2876 if (x == Short.MIN_VALUE) { 2877 t = "0"; 2878 } else { 2879 t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16); 2880 if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) { 2881 t = t.substring(16, 32); 2882 } 2883 } 2884 switch (t.length()) { 2885 case 1: 2886 sx = "800" + t; 2887 break; 2888 case 2: 2889 sx = "80" + t; 2890 break; 2891 case 3: 2892 sx = "8" + t; 2893 break; 2894 case 4: 2895 switch (t.charAt(0)) { 2896 case '1': 2897 sx = "9" + t.substring(1, 4); 2898 break; 2899 case '2': 2900 sx = "a" + t.substring(1, 4); 2901 break; 2902 case '3': 2903 sx = "b" + t.substring(1, 4); 2904 break; 2905 case '4': 2906 sx = "c" + t.substring(1, 4); 2907 break; 2908 case '5': 2909 sx = "d" + t.substring(1, 4); 2910 break; 2911 case '6': 2912 sx = "e" + t.substring(1, 4); 2913 break; 2914 case '7': 2915 sx = "f" + t.substring(1, 4); 2916 break; 2917 default: 2918 // noop 2919 } 2920 break; 2921 default: 2922 // noop 2923 } 2924 } else { 2925 sx = Integer.toString(x, 16); 2926 } 2927 return printXFormat(sx); 2928 } 2929 2930 /** 2931 * Utility method for formatting using the x 2932 * conversion character. 2933 * @param sx the String to format, the result of 2934 * converting a short, int, or long to a 2935 * String. 2936 * @return the formatted String. 2937 */ 2938 private String printXFormat(String sx) { 2939 2940 int nLeadingZeros = 0; 2941 int nBlanks = 0; 2942 if (sx.equals("0") && m_precisionSet && (m_precision == 0)) { 2943 sx = ""; 2944 } 2945 if (m_precisionSet) { 2946 nLeadingZeros = m_precision - sx.length(); 2947 } 2948 if (nLeadingZeros < 0) { 2949 nLeadingZeros = 0; 2950 } 2951 if (m_fieldWidthSet) { 2952 nBlanks = m_fieldWidth - nLeadingZeros - sx.length(); 2953 if (m_alternateForm) { 2954 nBlanks = nBlanks - 2; 2955 } 2956 } 2957 if (nBlanks < 0) { 2958 nBlanks = 0; 2959 } 2960 int n = 0; 2961 if (m_alternateForm) { 2962 n += 2; 2963 } 2964 n += nLeadingZeros; 2965 n += sx.length(); 2966 n += nBlanks; 2967 char[] ca = new char[n]; 2968 int i = 0; 2969 if (m_leftJustify) { 2970 if (m_alternateForm) { 2971 ca[i++] = '0'; 2972 ca[i++] = 'x'; 2973 } 2974 for (int j = 0; j < nLeadingZeros; j++, i++) { 2975 ca[i] = '0'; 2976 } 2977 char[] csx = sx.toCharArray(); 2978 for (int j = 0; j < csx.length; j++, i++) { 2979 ca[i] = csx[j]; 2980 } 2981 for (int j = 0; j < nBlanks; j++, i++) { 2982 ca[i] = ' '; 2983 } 2984 } else { 2985 if (!m_leadingZeros) { 2986 for (int j = 0; j < nBlanks; j++, i++) { 2987 ca[i] = ' '; 2988 } 2989 } 2990 if (m_alternateForm) { 2991 ca[i++] = '0'; 2992 ca[i++] = 'x'; 2993 } 2994 if (m_leadingZeros) { 2995 for (int j = 0; j < nBlanks; j++, i++) { 2996 ca[i] = '0'; 2997 } 2998 } 2999 for (int j = 0; j < nLeadingZeros; j++, i++) { 3000 ca[i] = '0'; 3001 } 3002 char[] csx = sx.toCharArray(); 3003 for (int j = 0; j < csx.length; j++, i++) { 3004 ca[i] = csx[j]; 3005 } 3006 } 3007 String caReturn = new String(ca); 3008 if (m_conversionCharacter == 'X') { 3009 caReturn = caReturn.toUpperCase(); 3010 } 3011 return caReturn; 3012 } 3013 3014 /** 3015 * Store the digits <code>n</code> in %n$ forms. 3016 */ 3017 private void setArgPosition() { 3018 3019 int xPos; 3020 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3021 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3022 break; 3023 } 3024 } 3025 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3026 if (m_fmt.charAt(xPos) == '$') { 3027 m_positionalSpecification = true; 3028 m_argumentPosition = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3029 m_pos = xPos + 1; 3030 } 3031 } 3032 } 3033 3034 /** 3035 * Check for a conversion character. If it is 3036 * there, store it. 3037 * @return <code>true</code> if the conversion 3038 * character is there, and 3039 * <code>false</code> otherwise. 3040 */ 3041 private boolean setConversionCharacter() { 3042 3043 /* idfgGoxXeEcs */ 3044 boolean ret = false; 3045 m_conversionCharacter = '\0'; 3046 if (m_pos < m_fmt.length()) { 3047 char c = m_fmt.charAt(m_pos); 3048 if ((c == 'i') 3049 || (c == 'd') 3050 || (c == 'f') 3051 || (c == 'g') 3052 || (c == 'G') 3053 || (c == 'o') 3054 || (c == 'x') 3055 || (c == 'X') 3056 || (c == 'e') 3057 || (c == 'E') 3058 || (c == 'c') 3059 || (c == 's') 3060 || (c == '%')) { 3061 m_conversionCharacter = c; 3062 m_pos++; 3063 ret = true; 3064 } 3065 } 3066 return ret; 3067 } 3068 3069 /** 3070 * Set the field width. 3071 */ 3072 private void setFieldWidth() { 3073 3074 int firstPos = m_pos; 3075 m_fieldWidth = 0; 3076 m_fieldWidthSet = false; 3077 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) { 3078 m_pos++; 3079 if (!setFieldWidthArgPosition()) { 3080 m_variableFieldWidth = true; 3081 m_fieldWidthSet = true; 3082 } 3083 } else { 3084 while (m_pos < m_fmt.length()) { 3085 char c = m_fmt.charAt(m_pos); 3086 if (Character.isDigit(c)) { 3087 m_pos++; 3088 } else { 3089 break; 3090 } 3091 } 3092 if ((firstPos < m_pos) && (firstPos < m_fmt.length())) { 3093 String sz = m_fmt.substring(firstPos, m_pos); 3094 m_fieldWidth = Integer.parseInt(sz); 3095 m_fieldWidthSet = true; 3096 } 3097 } 3098 } 3099 3100 /** 3101 * Store the digits <code>n</code> in *n$ forms. 3102 * 3103 * @return the result 3104 */ 3105 private boolean setFieldWidthArgPosition() { 3106 3107 boolean ret = false; 3108 int xPos; 3109 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3110 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3111 break; 3112 } 3113 } 3114 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3115 if (m_fmt.charAt(xPos) == '$') { 3116 m_positionalFieldWidth = true; 3117 m_argumentPositionForFieldWidth = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3118 m_pos = xPos + 1; 3119 ret = true; 3120 } 3121 } 3122 return ret; 3123 } 3124 3125 /** 3126 * Set flag characters, one of '-+#0 or a space. 3127 */ 3128 private void setFlagCharacters() { 3129 3130 /* '-+ #0 */ 3131 m_thousands = false; 3132 m_leftJustify = false; 3133 m_leadingSign = false; 3134 m_leadingSpace = false; 3135 m_alternateForm = false; 3136 m_leadingZeros = false; 3137 for (; m_pos < m_fmt.length(); m_pos++) { 3138 char c = m_fmt.charAt(m_pos); 3139 if (c == '\'') { 3140 m_thousands = true; 3141 } else if (c == '-') { 3142 m_leftJustify = true; 3143 m_leadingZeros = false; 3144 } else if (c == '+') { 3145 m_leadingSign = true; 3146 m_leadingSpace = false; 3147 } else if (c == ' ') { 3148 if (!m_leadingSign) { 3149 m_leadingSpace = true; 3150 } 3151 } else if (c == '#') { 3152 m_alternateForm = true; 3153 } else if (c == '0') { 3154 if (!m_leftJustify) { 3155 m_leadingZeros = true; 3156 } 3157 } else { 3158 break; 3159 } 3160 } 3161 } 3162 3163 /** 3164 * Check for an h, l, or L in a format. An L is 3165 * used to control the minimum number of digits 3166 * in an exponent when using floating point 3167 * formats. An l or h is used to control 3168 * conversion of the input to a long or short, 3169 * respectively, before formatting. If any of 3170 * these is present, store them. 3171 */ 3172 private void setOptionalHL() { 3173 3174 m_optionalh = false; 3175 m_optionall = false; 3176 m_optionalL = false; 3177 if (m_pos < m_fmt.length()) { 3178 char c = m_fmt.charAt(m_pos); 3179 if (c == 'h') { 3180 m_optionalh = true; 3181 m_pos++; 3182 } else if (c == 'l') { 3183 m_optionall = true; 3184 m_pos++; 3185 } else if (c == 'L') { 3186 m_optionalL = true; 3187 m_pos++; 3188 } 3189 } 3190 } 3191 3192 /** 3193 * Set the precision. 3194 */ 3195 private void setPrecision() { 3196 3197 int firstPos = m_pos; 3198 m_precisionSet = false; 3199 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '.')) { 3200 m_pos++; 3201 if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) { 3202 m_pos++; 3203 if (!setPrecisionArgPosition()) { 3204 m_variablePrecision = true; 3205 m_precisionSet = true; 3206 } 3207 return; 3208 } else { 3209 while (m_pos < m_fmt.length()) { 3210 char c = m_fmt.charAt(m_pos); 3211 if (Character.isDigit(c)) { 3212 m_pos++; 3213 } else { 3214 break; 3215 } 3216 } 3217 if (m_pos > (firstPos + 1)) { 3218 String sz = m_fmt.substring(firstPos + 1, m_pos); 3219 m_precision = Integer.parseInt(sz); 3220 m_precisionSet = true; 3221 } 3222 } 3223 } 3224 } 3225 3226 /** 3227 * Store the digits <code>n</code> in *n$ forms. 3228 * 3229 * @return the result 3230 */ 3231 private boolean setPrecisionArgPosition() { 3232 3233 boolean ret = false; 3234 int xPos; 3235 for (xPos = m_pos; xPos < m_fmt.length(); xPos++) { 3236 if (!Character.isDigit(m_fmt.charAt(xPos))) { 3237 break; 3238 } 3239 } 3240 if ((xPos > m_pos) && (xPos < m_fmt.length())) { 3241 if (m_fmt.charAt(xPos) == '$') { 3242 m_positionalPrecision = true; 3243 m_argumentPositionForPrecision = Integer.parseInt(m_fmt.substring(m_pos, xPos)); 3244 m_pos = xPos + 1; 3245 ret = true; 3246 } 3247 } 3248 return ret; 3249 } 3250 3251 /** 3252 * Start the symbolic carry process. The process 3253 * is not quite finished because the symbolic 3254 * carry may change the length of the string and 3255 * change the exponent (in e format). 3256 * @param cLast index of the last digit changed 3257 * by the round 3258 * @param cFirst index of the first digit allowed 3259 * to be changed by this phase of the round 3260 * @param ca the ca parameter 3261 * @return <code>true</code> if the carry forces 3262 * a round that will change the print still 3263 * more 3264 */ 3265 private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) { 3266 3267 boolean carry = true; 3268 for (int i = cLast; carry && (i >= cFirst); i--) { 3269 carry = false; 3270 switch (ca[i]) { 3271 case '0': 3272 ca[i] = '1'; 3273 break; 3274 case '1': 3275 ca[i] = '2'; 3276 break; 3277 case '2': 3278 ca[i] = '3'; 3279 break; 3280 case '3': 3281 ca[i] = '4'; 3282 break; 3283 case '4': 3284 ca[i] = '5'; 3285 break; 3286 case '5': 3287 ca[i] = '6'; 3288 break; 3289 case '6': 3290 ca[i] = '7'; 3291 break; 3292 case '7': 3293 ca[i] = '8'; 3294 break; 3295 case '8': 3296 ca[i] = '9'; 3297 break; 3298 case '9': 3299 ca[i] = '0'; 3300 carry = true; 3301 break; 3302 default: 3303 // noop 3304 } 3305 } 3306 return carry; 3307 } 3308 } 3309 3310 /** Character position. Used by the constructor. */ 3311 DecimalFormatSymbols m_dfs; 3312 3313 /** Character position. Used by the constructor. */ 3314 private int m_cPos; 3315 3316 /** Vector of control strings and format literals. */ 3317 private Vector<ConversionSpecification> m_vFmt = new Vector<ConversionSpecification>(); 3318 3319 /** 3320 * Constructs an array of control specifications 3321 * possibly preceded, separated, or followed by 3322 * ordinary strings. Control strings begin with 3323 * unpaired percent signs. A pair of successive 3324 * percent signs designates a single percent sign in 3325 * the format. 3326 * @param locale the locale 3327 * @param fmtArg Control string. 3328 * @exception CmsIllegalArgumentException if the control 3329 * string is null, zero length, or otherwise 3330 * malformed. 3331 */ 3332 public PrintfFormat(Locale locale, String fmtArg) 3333 throws CmsIllegalArgumentException { 3334 3335 m_dfs = new DecimalFormatSymbols(locale); 3336 int ePos = 0; 3337 ConversionSpecification sFmt = null; 3338 String unCS = nonControl(fmtArg, 0); 3339 if (unCS != null) { 3340 sFmt = new ConversionSpecification(); 3341 sFmt.setLiteral(unCS); 3342 m_vFmt.addElement(sFmt); 3343 } 3344 while ((m_cPos != -1) && (m_cPos < fmtArg.length())) { 3345 for (ePos = m_cPos + 1; ePos < fmtArg.length(); ePos++) { 3346 char c = 0; 3347 c = fmtArg.charAt(ePos); 3348 if (c == 'i') { 3349 break; 3350 } 3351 if (c == 'd') { 3352 break; 3353 } 3354 if (c == 'f') { 3355 break; 3356 } 3357 if (c == 'g') { 3358 break; 3359 } 3360 if (c == 'G') { 3361 break; 3362 } 3363 if (c == 'o') { 3364 break; 3365 } 3366 if (c == 'x') { 3367 break; 3368 } 3369 if (c == 'X') { 3370 break; 3371 } 3372 if (c == 'e') { 3373 break; 3374 } 3375 if (c == 'E') { 3376 break; 3377 } 3378 if (c == 'c') { 3379 break; 3380 } 3381 if (c == 's') { 3382 break; 3383 } 3384 if (c == '%') { 3385 break; 3386 } 3387 } 3388 ePos = Math.min(ePos + 1, fmtArg.length()); 3389 sFmt = new ConversionSpecification(fmtArg.substring(m_cPos, ePos)); 3390 m_vFmt.addElement(sFmt); 3391 unCS = nonControl(fmtArg, ePos); 3392 if (unCS != null) { 3393 sFmt = new ConversionSpecification(); 3394 sFmt.setLiteral(unCS); 3395 m_vFmt.addElement(sFmt); 3396 } 3397 } 3398 } 3399 3400 /** 3401 * Constructs an array of control specifications 3402 * possibly preceded, separated, or followed by 3403 * ordinary strings. Control strings begin with 3404 * unpaired percent signs. A pair of successive 3405 * percent signs designates a single percent sign in 3406 * the format. 3407 * @param fmtArg Control string. 3408 * @exception IllegalArgumentException if the control 3409 * string is null, zero length, or otherwise 3410 * malformed. 3411 */ 3412 public PrintfFormat(String fmtArg) 3413 throws IllegalArgumentException { 3414 3415 this(Locale.getDefault(), fmtArg); 3416 } 3417 3418 /** 3419 * Format nothing. Just use the control string. 3420 * @return the formatted String. 3421 */ 3422 public String sprintf() { 3423 3424 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3425 ConversionSpecification cs = null; 3426 char c = 0; 3427 StringBuffer sb = new StringBuffer(); 3428 while (e.hasMoreElements()) { 3429 cs = e.nextElement(); 3430 c = cs.getConversionCharacter(); 3431 if (c == '\0') { 3432 sb.append(cs.getLiteral()); 3433 } else if (c == '%') { 3434 sb.append("%"); 3435 } 3436 } 3437 return sb.toString(); 3438 } 3439 3440 /** 3441 * Format a double. 3442 * @param x The double to format. 3443 * @return The formatted String. 3444 * @exception CmsIllegalArgumentException if the 3445 * conversion character is c, C, s, S, 3446 * d, d, x, X, or o. 3447 */ 3448 public String sprintf(double x) throws CmsIllegalArgumentException { 3449 3450 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3451 ConversionSpecification cs = null; 3452 char c = 0; 3453 StringBuffer sb = new StringBuffer(); 3454 while (e.hasMoreElements()) { 3455 cs = e.nextElement(); 3456 c = cs.getConversionCharacter(); 3457 if (c == '\0') { 3458 sb.append(cs.getLiteral()); 3459 } else if (c == '%') { 3460 sb.append("%"); 3461 } else { 3462 sb.append(cs.internalsprintf(x)); 3463 } 3464 } 3465 return sb.toString(); 3466 } 3467 3468 /** 3469 * Format an int. 3470 * @param x The int to format. 3471 * @return The formatted String. 3472 * @exception CmsIllegalArgumentException if the 3473 * conversion character is f, e, E, g, G, s, 3474 * or S. 3475 */ 3476 public String sprintf(int x) throws CmsIllegalArgumentException { 3477 3478 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3479 ConversionSpecification cs = null; 3480 char c = 0; 3481 StringBuffer sb = new StringBuffer(); 3482 while (e.hasMoreElements()) { 3483 cs = e.nextElement(); 3484 c = cs.getConversionCharacter(); 3485 if (c == '\0') { 3486 sb.append(cs.getLiteral()); 3487 } else if (c == '%') { 3488 sb.append("%"); 3489 } else { 3490 sb.append(cs.internalsprintf(x)); 3491 } 3492 } 3493 return sb.toString(); 3494 } 3495 3496 /** 3497 * Format an long. 3498 * @param x The long to format. 3499 * @return The formatted String. 3500 * @exception CmsIllegalArgumentException if the 3501 * conversion character is f, e, E, g, G, s, 3502 * or S. 3503 */ 3504 public String sprintf(long x) throws CmsIllegalArgumentException { 3505 3506 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3507 ConversionSpecification cs = null; 3508 char c = 0; 3509 StringBuffer sb = new StringBuffer(); 3510 while (e.hasMoreElements()) { 3511 cs = e.nextElement(); 3512 c = cs.getConversionCharacter(); 3513 if (c == '\0') { 3514 sb.append(cs.getLiteral()); 3515 } else if (c == '%') { 3516 sb.append("%"); 3517 } else { 3518 sb.append(cs.internalsprintf(x)); 3519 } 3520 } 3521 return sb.toString(); 3522 } 3523 3524 /** 3525 * Format an Object. Convert wrapper types to 3526 * their primitive equivalents and call the 3527 * appropriate internal formatting method. Convert 3528 * Strings using an internal formatting method for 3529 * Strings. Otherwise use the default formatter 3530 * (use toString). 3531 * @param x the Object to format. 3532 * @return the formatted String. 3533 * @exception CmsIllegalArgumentException if the 3534 * conversion character is inappropriate for 3535 * formatting an unwrapped value. 3536 */ 3537 public String sprintf(Object x) throws CmsIllegalArgumentException { 3538 3539 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3540 ConversionSpecification cs = null; 3541 char c = 0; 3542 StringBuffer sb = new StringBuffer(); 3543 while (e.hasMoreElements()) { 3544 cs = e.nextElement(); 3545 c = cs.getConversionCharacter(); 3546 if (c == '\0') { 3547 sb.append(cs.getLiteral()); 3548 } else if (c == '%') { 3549 sb.append("%"); 3550 } else { 3551 if (x instanceof Byte) { 3552 sb.append(cs.internalsprintf(((Byte)x).byteValue())); 3553 } else if (x instanceof Short) { 3554 sb.append(cs.internalsprintf(((Short)x).shortValue())); 3555 } else if (x instanceof Integer) { 3556 sb.append(cs.internalsprintf(((Integer)x).intValue())); 3557 } else if (x instanceof Long) { 3558 sb.append(cs.internalsprintf(((Long)x).longValue())); 3559 } else if (x instanceof Float) { 3560 sb.append(cs.internalsprintf(((Float)x).floatValue())); 3561 } else if (x instanceof Double) { 3562 sb.append(cs.internalsprintf(((Double)x).doubleValue())); 3563 } else if (x instanceof Character) { 3564 sb.append(cs.internalsprintf(((Character)x).charValue())); 3565 } else if (x instanceof String) { 3566 sb.append(cs.internalsprintf((String)x)); 3567 } else { 3568 sb.append(cs.internalsprintf(x)); 3569 } 3570 } 3571 } 3572 return sb.toString(); 3573 } 3574 3575 /** 3576 * Format an array of objects. Byte, Short, 3577 * Integer, Long, Float, Double, and Character 3578 * arguments are treated as wrappers for primitive 3579 * types. 3580 * @param o The array of objects to format. 3581 * @return The formatted String. 3582 */ 3583 public String sprintf(Object[] o) { 3584 3585 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3586 ConversionSpecification cs = null; 3587 char c = 0; 3588 int i = 0; 3589 StringBuffer sb = new StringBuffer(); 3590 while (e.hasMoreElements()) { 3591 cs = e.nextElement(); 3592 c = cs.getConversionCharacter(); 3593 if (c == '\0') { 3594 sb.append(cs.getLiteral()); 3595 } else if (c == '%') { 3596 sb.append("%"); 3597 } else { 3598 if (cs.isPositionalSpecification()) { 3599 i = cs.getArgumentPosition() - 1; 3600 if (cs.isPositionalFieldWidth()) { 3601 int ifw = cs.getArgumentPositionForFieldWidth() - 1; 3602 cs.setFieldWidthWithArg(((Integer)o[ifw]).intValue()); 3603 } 3604 if (cs.isPositionalPrecision()) { 3605 int ipr = cs.getArgumentPositionForPrecision() - 1; 3606 cs.setPrecisionWithArg(((Integer)o[ipr]).intValue()); 3607 } 3608 } else { 3609 if (cs.isVariableFieldWidth()) { 3610 cs.setFieldWidthWithArg(((Integer)o[i]).intValue()); 3611 i++; 3612 } 3613 if (cs.isVariablePrecision()) { 3614 cs.setPrecisionWithArg(((Integer)o[i]).intValue()); 3615 i++; 3616 } 3617 } 3618 if (o[i] instanceof Byte) { 3619 sb.append(cs.internalsprintf(((Byte)o[i]).byteValue())); 3620 } else if (o[i] instanceof Short) { 3621 sb.append(cs.internalsprintf(((Short)o[i]).shortValue())); 3622 } else if (o[i] instanceof Integer) { 3623 sb.append(cs.internalsprintf(((Integer)o[i]).intValue())); 3624 } else if (o[i] instanceof Long) { 3625 sb.append(cs.internalsprintf(((Long)o[i]).longValue())); 3626 } else if (o[i] instanceof Float) { 3627 sb.append(cs.internalsprintf(((Float)o[i]).floatValue())); 3628 } else if (o[i] instanceof Double) { 3629 sb.append(cs.internalsprintf(((Double)o[i]).doubleValue())); 3630 } else if (o[i] instanceof Character) { 3631 sb.append(cs.internalsprintf(((Character)o[i]).charValue())); 3632 } else if (o[i] instanceof String) { 3633 sb.append(cs.internalsprintf((String)o[i])); 3634 } else { 3635 sb.append(cs.internalsprintf(o[i])); 3636 } 3637 if (!cs.isPositionalSpecification()) { 3638 i++; 3639 } 3640 } 3641 } 3642 return sb.toString(); 3643 } 3644 3645 /** 3646 * Format a String. 3647 * @param x The String to format. 3648 * @return The formatted String. 3649 * @exception CmsIllegalArgumentException if the 3650 * conversion character is neither s nor S. 3651 */ 3652 public String sprintf(String x) throws CmsIllegalArgumentException { 3653 3654 Enumeration<ConversionSpecification> e = m_vFmt.elements(); 3655 ConversionSpecification cs = null; 3656 char c = 0; 3657 StringBuffer sb = new StringBuffer(); 3658 while (e.hasMoreElements()) { 3659 cs = e.nextElement(); 3660 c = cs.getConversionCharacter(); 3661 if (c == '\0') { 3662 sb.append(cs.getLiteral()); 3663 } else if (c == '%') { 3664 sb.append("%"); 3665 } else { 3666 sb.append(cs.internalsprintf(x)); 3667 } 3668 } 3669 return sb.toString(); 3670 } 3671 3672 /** 3673 * Return a substring starting at 3674 * <code>start</code> and ending at either the end 3675 * of the String <code>s</code>, the next unpaired 3676 * percent sign, or at the end of the String if the 3677 * last character is a percent sign. 3678 * @param s Control string. 3679 * @param start Position in the string 3680 * <code>s</code> to begin looking for the start 3681 * of a control string. 3682 * @return the substring from the start position 3683 * to the beginning of the control string. 3684 */ 3685 private String nonControl(String s, int start) { 3686 3687 m_cPos = s.indexOf("%", start); 3688 if (m_cPos == -1) { 3689 m_cPos = s.length(); 3690 } 3691 return s.substring(start, m_cPos); 3692 } 3693}