1 28 29 package com.caucho.util; 30 31 public class Sprintf { 32 private static final L10N L = new L10N(Sprintf.class); 33 34 35 36 private final static int ALT = 0x01; 37 private final static int ZERO_FILL = 0x02; 38 private final static int POS_PLUS = 0x04; 39 private final static int POS_SPACE = 0x08; 40 private final static int LALIGN = 0x10; 41 private final static int BIG = 0x20; 42 private final static int NO_TRAIL_ZERO = 0x40; 43 private final static int JAVAESCAPE = 0x80; 44 private final static int CSVESCAPE = 0x100; 45 private final static int XMLESCAPE = 0x200; 46 47 private static char []digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 48 'a', 'b', 'c', 'd', 'e', 'f'}; 49 private static char []bigDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 50 'A', 'B', 'C', 'D', 'E', 'F'}; 51 52 133 134 public static String sprintf(String format, Object [] args) 135 { 136 String ret; 137 CharBuffer cb = CharBuffer.allocate(); 138 try { 139 sprintf(cb,format,args); 140 } 141 finally { 142 ret = cb.close(); 143 } 144 return ret; 145 } 146 147 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) 148 { 149 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 } ); 150 } 151 152 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) 153 { 154 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 } ); 155 } 156 157 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) 158 { 159 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 } ); 160 } 161 162 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) 163 { 164 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4, arg5, arg6 } ); 165 } 166 167 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) 168 { 169 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4, arg5 } ); 170 } 171 172 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4) 173 { 174 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3, arg4 } ); 175 } 176 177 public static String sprintf(String format, Object arg0, Object arg1, Object arg2, Object arg3) 178 { 179 return sprintf(format, new Object [] { arg0, arg1, arg2, arg3 } ); 180 } 181 182 public static String sprintf(String format, Object arg0, Object arg1, Object arg2) 183 { 184 return sprintf(format, new Object [] { arg0, arg1, arg2 } ); 185 } 186 187 public static String sprintf(String format, Object arg0, Object arg1) 188 { 189 return sprintf(format, new Object [] { arg0, arg1 } ); 190 } 191 192 public static String sprintf(String format, Object arg0) 193 { 194 return sprintf(format, new Object [] { arg0 } ); 195 } 196 197 public static CharBuffer sprintf(CharBuffer result, 198 String format, 199 Object ... args) 200 { 201 int length = args.length; 202 int arg = 0; 203 int len = format.length(); 204 205 for (int i = 0; i < len; i++) { 206 int ch; 207 int start = i; 208 209 if ((ch = format.charAt(i)) != '%') { 210 result.append((char) ch); 211 continue; 212 } 213 214 int flags = 0; 215 loop: 216 while (++i < len) { 217 switch ((ch = format.charAt(i))) { 218 case '0': flags |= ZERO_FILL; break; 219 case '+': flags |= POS_PLUS; break; 220 case ' ': flags |= POS_SPACE; break; 221 case '#': flags |= ALT; break; 222 case '-': flags |= LALIGN; break; 223 case 'j': flags |= JAVAESCAPE; break; 224 case 'v': flags |= JAVAESCAPE; flags |= CSVESCAPE; break; 225 case 'm': flags |= XMLESCAPE; break; 226 227 default: break loop; 228 } 229 } 230 231 int width = 0; 232 for (; i < len && (ch = format.charAt(i)) >= '0' && ch <= '9'; i++) { 233 width = 10 * width + ch - '0'; 234 } 235 236 if (i >= len) { 237 fixBits(result, format, start, i); 238 break; 239 } 240 241 int prec = 0; 242 if (ch == '.') { 243 while (++i < len && (ch = format.charAt(i)) >= '0' && ch <= '9') { 244 prec = 10 * prec + ch - '0'; 245 } 246 } else 247 prec = -1; 248 249 if (i >= len) { 250 fixBits(result, format, start, i); 251 break; 252 } 253 254 switch (ch) { 255 case '%': 256 result.append((char) '%'); 257 break; 258 259 case 'd': 260 case 'D': 261 case 'i': 262 case 'u': 263 case 'U': 264 if (arg >= length) 265 missing(arg); 266 formatInteger(result, toLong(args[arg++]), width, prec, flags, 10); 267 break; 268 269 case 'o': 270 case 'O': 271 if (arg >= length) 272 missing(arg); 273 formatInteger(result, toLong(args[arg++]), width, prec, flags, 8); 274 break; 275 276 case 'X': 277 flags |= BIG; 278 case 'x': 279 if (arg >= length) 280 missing(arg); 281 formatInteger(result, toLong(args[arg++]), width, prec, flags, 16); 282 break; 283 284 case 'E': 285 case 'G': 286 flags |= BIG; 287 case 'f': 288 case 'e': 289 case 'g': 290 if (arg >= length) 291 missing(arg); 292 formatDouble(result, toDouble(args[arg++]), width, prec, flags, ch); 293 break; 294 295 case 'c': 296 if (arg >= length) 297 missing(arg); 298 formatChar(result, toLong(args[arg++]), width, flags); 299 break; 300 301 case 's': 302 if (arg >= length) 303 missing(arg); 304 formatString(result, toString(args[arg++],"#null"), prec, width, flags); 305 break; 306 307 case 'z': 308 if (arg >= length) 309 missing(arg); 310 formatString(result, toString(args[arg++],""), prec, width, flags); 311 break; 312 313 case 'p': 314 if (arg >= length) 315 missing(arg); 316 317 Object o = args[arg++]; 319 result.append(o.getClass().getName()); 320 result.append('@'); 321 result.append(Integer.toHexString(o.hashCode())); 322 323 default: 324 fixBits(result, format, start, i + 1); 325 break; 326 } 327 } 328 329 return result; 330 } 331 332 private static void missing(int arg) 333 { 334 throw new IllegalArgumentException (L.l("missing sprintf argument {0}",arg)); 335 } 336 337 public static void formatDouble(CharBuffer cb, double value, 338 int prec, int flags, int type) 339 { 340 String raw = Double.toString(value); 341 int expt = 0; 342 int i = 0; 343 CharBuffer digits = new CharBuffer(); 344 int ch = raw.charAt(i); 345 boolean seenDigit = false; 346 347 for (; i < raw.length(); i++) { 349 if ((ch = raw.charAt(i)) == '.' || ch == 'e' || ch == 'E') 350 break; 351 else if (! seenDigit && ch == '0') { 352 } 353 else { 354 seenDigit = true; 355 digits.append((char) ch); 356 expt++; 357 } 358 } 359 360 if (ch == '.') 361 i++; 362 363 for (; i < raw.length(); i++) { 364 ch = raw.charAt(i); 365 366 if (! seenDigit && ch == '0') { 367 expt--; 368 } else if (ch >= '0' && ch <= '9') { 369 digits.append((char) ch); 370 seenDigit = true; 371 } 372 else { 373 int sign = 1; 374 i++; 375 if ((ch = raw.charAt(i)) == '+') { 376 i++; 377 } 378 else if (ch == '-') { 379 i++; 380 sign = -1; 381 } 382 383 int e = 0; 384 for (; i < raw.length() && (ch = raw.charAt(i)) >= '0' && ch <= '9'; 385 i++) { 386 e = 10 * e + ch - '0'; 387 } 388 389 expt += sign * e; 390 break; 391 } 392 } 393 394 if (! seenDigit) 395 expt = 1; 396 397 while (digits.length() > 0 && digits.charAt(digits.length() - 1) == '0') 398 digits.setLength(digits.length() - 1); 399 400 if (type == 'f') { 401 if (roundDigits(digits, expt + prec)) { 402 expt++; 403 } 404 405 formatFixed(cb, digits, expt, prec, flags); 406 } 407 else if (type == 'e' || type == 'E') { 408 if (roundDigits(digits, prec + 1)) 409 expt++; 410 411 formatExpt(cb, digits, expt, prec, flags); 412 } 413 else { 414 if (roundDigits(digits, prec)) 415 expt++; 416 417 if (expt < -3 || expt > prec) 418 formatExpt(cb, digits, expt, prec - 1, flags|NO_TRAIL_ZERO); 419 else 420 formatFixed(cb, digits, expt, prec - expt, flags|NO_TRAIL_ZERO); 421 } 422 } 423 424 public static void formatDouble(CharBuffer cb, double value, 425 int width, int prec, int flags, 426 int type) 427 { 428 if (prec < 0) 429 prec = 6; 430 431 int offset = cb.length(); 432 433 if ((flags & ZERO_FILL) != 0 && 434 (value < 0 || (flags & (POS_PLUS|POS_SPACE)) != 0)) { 435 offset++; 436 width--; 437 } 438 439 if (value < 0) { 440 cb.append((char) '-'); 441 value = -value; 442 } else if ((flags & POS_PLUS) != 0) { 443 cb.append((char) '+'); 444 } else if ((flags & POS_SPACE) != 0) { 445 cb.append((char) ' '); 446 } 447 448 formatDouble(cb, value, prec, flags, type); 449 450 width -= cb.length() - offset; 451 452 for (int i = 0; i < width; i++) { 453 if ((flags & LALIGN) != 0) 454 cb.append(' '); 455 else 456 cb.insert(offset, (flags & ZERO_FILL) == 0 ? ' ' : '0'); 457 } 458 } 459 460 private static boolean roundDigits(CharBuffer digits, int len) 461 { 462 if (len < 0 || digits.length() <= len) 463 return false; 464 465 int value = digits.charAt(len); 466 if (value < '5') 467 return false; 468 469 for (int i = len - 1; i >= 0; i--) { 470 int ch = digits.charAt(i); 471 472 if (ch != '9') { 473 digits.setCharAt(i, (char) (ch + 1)); 474 return false; 475 } 476 digits.setCharAt(i, '0'); 477 } 478 479 digits.insert(0, '1'); 480 481 return true; 482 } 483 484 private static void formatFixed(CharBuffer cb, CharBuffer digits, 485 int expt, int prec, int flags) 486 { 487 int i = 0; 488 int origExpt = expt; 489 490 for (; expt > 0; expt--) { 491 if (i < digits.length()) 492 cb.append((char) digits.charAt(i++)); 493 else 494 cb.append('0'); 495 } 496 497 if (origExpt <= 0) cb.append('0'); 499 500 if (prec > 0 || (flags & ALT) != 0) 501 cb.append('.'); 502 503 for (; expt < 0 && prec > 0; expt++) { 504 cb.append('0'); 505 prec--; 506 } 507 508 for (; prec > 0 && i < digits.length(); i++) { 509 cb.append(digits.charAt(i)); 510 prec--; 511 } 512 513 for (; prec > 0 && (flags & (NO_TRAIL_ZERO|ALT)) != NO_TRAIL_ZERO; prec--) 514 cb.append('0'); 515 } 516 517 private static void formatExpt(CharBuffer cb, CharBuffer digits, 518 int expt, int prec, int flags) 519 { 520 if (digits.length() == 0) 521 cb.append('0'); 522 else 523 cb.append((char) digits.charAt(0)); 524 525 if (prec > 0 || (flags & ALT) != 0) 526 cb.append('.'); 527 528 for (int i = 1; i < digits.length(); i++) { 529 if (prec > 0) 530 cb.append((char) digits.charAt(i)); 531 prec--; 532 } 533 534 for (; prec > 0 && (flags & (NO_TRAIL_ZERO|ALT)) != NO_TRAIL_ZERO; prec--) 535 cb.append('0'); 536 537 if ((flags & BIG) != 0) 538 cb.append('E'); 539 else 540 cb.append('e'); 541 542 formatInteger(cb, expt - 1, 0, 2, POS_PLUS, 10); 543 } 544 545 public static void formatInteger(CharBuffer cb, long dvalue, 546 int width, int prec, int flags, int radix) 547 { 548 boolean isBig = (flags & BIG) != 0; 549 int begin = cb.length(); 550 551 long value; 552 if (dvalue > 0) 553 value = (long) (dvalue + 0.5); 554 else 555 value = (long) (dvalue - 0.5); 556 557 if (value < 0 && radix == 10) { 558 cb.append((char) '-'); 559 value = -value; 560 } else if (value >= 0 && radix == 10 && (flags & POS_PLUS) != 0) 561 cb.append((char) '+'); 562 else if (value >= 0 && radix == 10 && (flags & POS_SPACE) != 0) 563 cb.append((char) ' '); 564 else if (value < 0) 565 value &= 0xffffffffL; 566 else if (radix == 8 && (flags & ALT) != 0 && value != 0) 567 cb.append('0'); 568 else if (radix == 16 && (flags & ALT) != 0) 569 cb.append((flags & BIG) == 0 ? "0x" : "0X"); 570 571 if ((flags & ZERO_FILL) != 0) { 572 width -= cb.length() - begin; 573 begin = cb.length(); 574 } 575 576 int offset = cb.length(); 577 int len = 0; 578 while (value != 0) { 579 len++; 580 cb.insert(offset, (isBig ? bigDigits : digits)[(int) (value % radix)]); 581 value /= radix; 582 } 583 584 for (int i = 0; i < prec - len; i++) 585 cb.insert(offset, '0'); 586 if (len == 0 && prec == 0) 587 cb.insert(offset, '0'); 588 589 width -= cb.length() - begin; 590 for (; width > 0; width--) { 591 if ((flags & LALIGN) != 0) 592 cb.append(' '); 593 else if ((flags & ZERO_FILL) != 0 && prec < 0) 594 cb.insert(begin, '0'); 595 else 596 cb.insert(begin, ' '); 597 } 598 599 if (cb.length() == begin) 600 cb.append('0'); 601 } 602 603 public static void formatInteger(CharBuffer cb, double dvalue, 604 int width, int prec, int flags, int radix) 605 { 606 long value; 607 if (dvalue > 0) 608 value = (long) (dvalue + 0.5); 609 else 610 value = (long) (dvalue - 0.5); 611 612 formatInteger(cb,value,width,prec,flags,radix); 613 } 614 615 public static void formatChar(CharBuffer cb, long ch, int width, int flags) 616 { 617 int offset = cb.length(); 618 619 cb.append((char) ch); 620 621 if ((flags & LALIGN) == 0) { 622 for (int i = 0; i < width - 1; i++) 623 cb.insert(offset, (char) ' '); 624 } else { 625 for (int i = 0; i < width - 1; i++) 626 cb.append((char) ' '); 627 } 628 } 629 630 public static void formatString(CharBuffer cb, String string, 631 int prec, int width, int flags) 632 { 633 int offset = cb.length(); 634 635 if (prec < 0) 636 prec = Integer.MAX_VALUE; 637 638 if ((flags & CSVESCAPE) != 0) { cb.append('\"'); offset+=1; width -= 1; } 639 640 for (int i = 0; i < string.length() && i < prec; i++) { 641 width--; 642 char ch = string.charAt(i); 643 if ((flags & JAVAESCAPE) != 0) { 644 switch (ch) { 645 case '\\': 646 cb.append("\\\\"); offset+=1; width-=1; continue; 647 case '\n': 648 cb.append("\\n"); offset+=1; width-=1; continue; 649 case '\r': 650 cb.append("\\r"); offset+=1; width-=1; continue; 651 case '\"': 652 cb.append("\\\""); offset+=1; width-=1; continue; 653 } 654 } 655 if ((flags & XMLESCAPE) != 0) { 656 switch (ch) { 657 case '<': 658 cb.append("<"); offset+=3; width-=3; continue; 659 case '>': 660 cb.append(">"); offset+=3; width-=3; continue; 661 case '&': 662 cb.append("&"); offset+=4; width-=4; continue; 663 case '\'': 664 cb.append("'"); offset+=5; width-=5; continue; 665 case '"': 666 cb.append("""); offset+=5; width-=5; continue; 667 } 668 } 669 cb.append(ch); 670 } 671 672 if ((flags & CSVESCAPE) != 0) { cb.append('\"'); offset+=1; width -= 1; } 673 674 if ((flags & LALIGN) == 0) { 675 for (int i = 0; i < width; i++) 676 cb.insert(offset, (char) ' '); 677 } else { 678 for (int i = 0; i < width; i++) 679 cb.append((char) ' '); 680 } 681 } 682 683 private static void fixBits(CharBuffer cb, String format, int s, int i) 684 { 685 for (; s < i; s++) 686 cb.append((char) format.charAt(s)); 687 } 688 689 696 public static double toDouble(Object value) 697 { 698 699 700 if (value == null) 701 return 0; 702 else if (value instanceof Number ) { 703 double dValue = ((Number ) value).doubleValue(); 704 705 if (Double.isNaN(dValue)) 706 return 0; 707 else 708 return dValue; 709 } 710 else if (value.equals("")) 711 return 0; 712 else if (value instanceof String ) { 713 double dValue = Double.parseDouble((String ) value); 714 715 if (Double.isNaN(dValue)) 716 return 0; 717 else 718 return dValue; 719 } 720 else { 721 throw new IllegalArgumentException (L.l("can't convert {0} to double.", 722 value.getClass().getName())); 723 } 724 } 725 726 733 public static long toLong(Object value) 734 { 735 736 737 if (value == null) 738 return 0; 739 else if (value instanceof Number ) 740 return ((Number ) value).longValue(); 741 else if (value.equals("")) 742 return 0; 743 else if (value instanceof String ) { 744 int sign = 1; 745 String string = (String ) value; 746 int length = string.length(); 747 long intValue = 0; 748 749 int i = 0; 750 for (; i < length && Character.isWhitespace(string.charAt(i)); i++) { 751 } 752 753 if (length <= i) 754 return 0; 755 756 int ch = string.charAt(i); 757 if (ch == '-') { 758 sign = -1; 759 i++; 760 } 761 else if (ch == '+') 762 i++; 763 764 for (; i < length; i++) { 765 ch = string.charAt(i); 766 767 if (ch >= '0' && ch <= '9') { 768 intValue = 10 * intValue + ch - '0'; 769 } 770 else if (ch == '.') { 771 i = length; 773 break; 774 } else 775 break; 776 } 777 778 for (; i < length && Character.isWhitespace(string.charAt(i)); i++) { 779 } 780 781 if (i < length) 782 throw new IllegalArgumentException (L.l("can't convert '{0}' to long.", string)); 783 784 return sign * intValue; 785 786 } 787 else { 788 throw new IllegalArgumentException (L.l("can't convert {0} to long.", 789 value.getClass().getName())); 790 } 791 } 792 793 801 public static String toString(Object value, String nullValue) 802 { 803 return (value == null) ? nullValue : value.toString(); 804 } 805 806 } 807 | Popular Tags |