1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2001 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Cay S. Horstmann & Gary Cornell, Core Java 31 * Published By Sun Microsystems Press/Prentice-Hall 32 * Copyright (C) 1997 Sun Microsystems Inc. 33 * All Rights Reserved. 34 * 35 * Permission to use, copy, modify, and distribute this 36 * software and its documentation for NON-COMMERCIAL purposes 37 * and without fee is hereby granted provided that this 38 * copyright notice appears in all copies. 39 * 40 * THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR 41 * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER 42 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 44 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHORS 45 * AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED 46 * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING 47 * THIS SOFTWARE OR ITS DERIVATIVES. 48 */ 49 50 /** 51 * A class for formatting numbers that follows printf conventions. 52 * Also implements C-like atoi and atof functions 53 * @version 1.01 15 Feb 1996 54 * @author Cay Horstmann 55 */ 56 57 package com.sun.dhcpmgr.cli.common; 58 59 import java.io.*; 60 61 public class Format 62 63 { 64 /** 65 * Formats the number following printf conventions. 66 * Main limitation: Can only handle one format parameter at a time 67 * Use multiple Format objects to format more than one number 68 * @param s the format string following printf conventions 69 * The string has a prefix, a format code and a suffix. The prefix and 70 * suffix become part of the formatted output. The format code directs the 71 * formatting of the (single) parameter to be formatted. The code has the 72 * following structure 73 * <ul> 74 * <li> a % (required) 75 * <li> a modifier (optional) 76 * <dl> 77 * <dt> + <dd> forces display of + for positive numbers 78 * <dt> 0 <dd> show leading zeroes 79 * <dt> - <dd> align left in the field 80 * <dt> space <dd> prepend a space in front of positive numbers 81 * <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal 82 * numbers. Don't suppress trailing zeroes in general floating point format. 83 * </dl> 84 * <li> an integer denoting field width (optional) 85 * <li> a period followed by an integer denoting precision (optional) 86 * <li> a format descriptor (required) 87 * <dl> 88 * <dt>f <dd> floating point number in fixed format 89 * <dt>e, E <dd> floating point number in exponential notation (scientific 90 * format). The E format results in an uppercase E for the exponent 91 * (1.14130E+003), the e format in a lowercase e. 92 * <dt>g, G <dd> floating point number in general format (fixed format for 93 * small numbers, exponential format for large numbers). Trailing zeroes 94 * are suppressed. The G format results in an uppercase E for the exponent 95 * (if any), the g format in a lowercase e. 96 * <dt>d, i <dd> integer in decimal 97 * <dt>x <dd> integer in hexadecimal 98 * <dt>o <dd> integer in octal 99 * <dt>s <dd> string 100 * <dt>c <dd> character 101 * </dl> 102 * </ul> 103 * @exception IllegalArgumentException if bad format 104 */ 105 public Format(String s) { 106 width = 0; 107 precision = -1; 108 pre = ""; 109 post = ""; 110 leading_zeroes = false; 111 show_plus = false; 112 alternate = false; 113 show_space = false; 114 left_align = false; 115 fmt = ' '; 116 117 int state = 0; 118 int length = s.length(); 119 int parse_state = 0; 120 // 0 = prefix, 1 = flags, 2 = width, 3 = precision, 121 // 4 = format, 5 = end 122 int i = 0; 123 124 while (parse_state == 0) { 125 if (i >= length) { 126 parse_state = 5; 127 } else if (s.charAt(i) == '%') { 128 if (i < length - 1) { 129 if (s.charAt(i + 1) == '%') { 130 pre = pre + '%'; 131 i++; 132 } else { 133 parse_state = 1; 134 } 135 } else { 136 throw new java.lang.IllegalArgumentException(); 137 } 138 } else { 139 pre = pre + s.charAt(i); 140 } 141 i++; 142 } 143 144 while (parse_state == 1) { 145 if (i >= length) { 146 parse_state = 5; 147 } else if (s.charAt(i) == ' ') { 148 show_space = true; 149 } else if (s.charAt(i) == '-') { 150 left_align = true; 151 } else if (s.charAt(i) == '+') { 152 show_plus = true; 153 } else if (s.charAt(i) == '0') { 154 leading_zeroes = true; 155 } else if (s.charAt(i) == '#') { 156 alternate = true; 157 } else { 158 parse_state = 2; i--; 159 } 160 i++; 161 } 162 163 while (parse_state == 2) { 164 if (i >= length) { 165 parse_state = 5; 166 } else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') { 167 width = width * 10 + s.charAt(i) - '0'; 168 i++; 169 } else if (s.charAt(i) == '.') { 170 parse_state = 3; 171 precision = 0; 172 i++; 173 } else { 174 parse_state = 4; 175 } 176 } 177 178 while (parse_state == 3) { 179 if (i >= length) { 180 parse_state = 5; 181 } else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') { 182 precision = precision * 10 + s.charAt(i) - '0'; 183 i++; 184 } else { 185 parse_state = 4; 186 } 187 } 188 189 if (parse_state == 4) { 190 if (i >= length) { 191 parse_state = 5; 192 } else { 193 fmt = s.charAt(i); 194 } 195 i++; 196 } 197 198 if (i < length) { 199 post = s.substring(i, length); 200 } 201 } 202 203 /** 204 * prints a formatted number following printf conventions 205 * @param s a PrintStream 206 * @param fmt the format string 207 * @param x the double to print 208 */ 209 public static void print(java.io.PrintStream s, String fmt, double x) { 210 s.print(new Format(fmt).form(x)); 211 } 212 213 /** 214 * prints a formatted number following printf conventions 215 * @param s a PrintStream 216 * @param fmt the format string 217 * @param x the long to print 218 */ 219 public static void print(java.io.PrintStream s, String fmt, long x) { 220 s.print(new Format(fmt).form(x)); 221 } 222 223 /** 224 * prints a formatted number following printf conventions 225 * @param s a PrintStream 226 * @param fmt the format string 227 * @param x the character to 228 */ 229 public static void print(java.io.PrintStream s, String fmt, char x) { 230 s.print(new Format(fmt).form(x)); 231 } 232 233 /** 234 * prints a formatted number following printf conventions 235 * @param s a PrintStream, fmt the format string 236 * @param x a string that represents the digits to print 237 */ 238 public static void print(java.io.PrintStream s, String fmt, String x) { 239 s.print(new Format(fmt).form(x)); 240 } 241 242 /** 243 * Converts a string of digits(decimal, octal or hex) to an integer 244 * @param s a string 245 * @return the numeric value of the prefix of s representing a base 246 * 10 integer 247 */ 248 public static int atoi(String s) { 249 return (int)atol(s); 250 } 251 252 /** 253 * Converts a string of digits(decimal, octal or hex) to a long integer 254 * @param s a string 255 * @return the numeric value of the prefix of s representing a base 256 * 10 integer 257 */ 258 public static long atol(String s) { 259 int i = 0; 260 261 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { 262 i++; 263 } 264 265 if (i < s.length() && s.charAt(i) == '0') { 266 if (i + 1 < s.length() && (s.charAt(i + 1) == 'x' || 267 s.charAt(i + 1) == 'X')) { 268 return parseLong(s.substring(i + 2), 16); 269 } else { 270 return parseLong(s, 8); 271 } 272 } else { 273 return parseLong(s, 10); 274 } 275 } 276 277 private static long parseLong(String s, int base) { 278 int i = 0; 279 int sign = 1; 280 long r = 0; 281 282 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { 283 i++; 284 } 285 286 if (i < s.length() && s.charAt(i) == '-') { 287 sign = -1; i++; 288 } else if (i < s.length() && s.charAt(i) == '+') { 289 i++; 290 } 291 292 while (i < s.length()) { 293 char ch = s.charAt(i); 294 if ('0' <= ch && ch < '0' + base) { 295 r = r * base + ch - '0'; 296 } else if ('A' <= ch && ch < 'A' + base - 10) { 297 r = r * base + ch - 'A' + 10; 298 } else if ('a' <= ch && ch < 'a' + base - 10) { 299 r = r * base + ch - 'a' + 10; 300 } else { 301 return r * sign; 302 } 303 i++; 304 } 305 return r * sign; 306 } 307 308 /** 309 * Converts a string of digits to an double 310 * @param s a string 311 */ 312 public static double atof(String s) { 313 int i = 0; 314 int sign = 1; 315 double r = 0; // integer part 316 double f = 0; // fractional part 317 double p = 1; // exponent of fractional part 318 int state = 0; // 0 = int part, 1 = frac part 319 320 while (i < s.length() && Character.isWhitespace(s.charAt(i))) { 321 i++; 322 } 323 324 if (i < s.length() && s.charAt(i) == '-') { 325 sign = -1; i++; 326 } else if (i < s.length() && s.charAt(i) == '+') { 327 i++; 328 } 329 330 while (i < s.length()) { 331 char ch = s.charAt(i); 332 if ('0' <= ch && ch <= '9') { 333 if (state == 0) { 334 r = r * 10 + ch - '0'; 335 } else if (state == 1) { 336 p = p / 10; 337 r = r + p * (ch - '0'); 338 } 339 } else if (ch == '.') { 340 if (state == 0) { 341 state = 1; 342 } else { 343 return sign * r; 344 } 345 } else if (ch == 'e' || ch == 'E') { 346 long e = (int)parseLong(s.substring(i + 1), 10); 347 return sign * r * Math.pow(10, e); 348 } else { 349 return sign * r; 350 } 351 i++; 352 } 353 return sign * r; 354 } 355 356 /** 357 * Formats a double into a string (like sprintf in C) 358 * @param x the number to format 359 * @return the formatted string 360 * @exception IllegalArgumentException if bad argument 361 */ 362 public String form(double x) { 363 String r; 364 if (precision < 0) { 365 precision = 6; 366 } 367 368 int s = 1; 369 if (x < 0) { 370 x = -x; 371 s = -1; 372 } 373 374 if (fmt == 'f') { 375 r = fixed_format(x); 376 } else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G') { 377 r = exp_format(x); 378 } else { 379 throw new java.lang.IllegalArgumentException(); 380 } 381 382 return pad(sign(s, r)); 383 } 384 385 /** 386 * Formats a long integer into a string (like sprintf in C) 387 * @param x the number to format 388 * @return the formatted string 389 */ 390 public String form(long x) { 391 String r; 392 int s = 0; 393 if (fmt == 'd' || fmt == 'i') { 394 s = 1; 395 if (x < 0) { 396 x = -x; s = -1; 397 } 398 r = "" + x; 399 } else if (fmt == 'o') { 400 r = convert(x, 3, 7, "01234567"); 401 } else if (fmt == 'x') { 402 r = convert(x, 4, 15, "0123456789abcdef"); 403 } else if (fmt == 'X') { 404 r = convert(x, 4, 15, "0123456789ABCDEF"); 405 } else { 406 throw new java.lang.IllegalArgumentException(); 407 } 408 return pad(sign(s, r)); 409 } 410 411 /** 412 * Formats a character into a string (like sprintf in C) 413 * @param x the value to format 414 * @return the formatted string 415 */ 416 public String form(char c) { 417 if (fmt != 'c') { 418 throw new java.lang.IllegalArgumentException(); 419 } 420 String r = "" + c; 421 return pad(r); 422 } 423 424 /** 425 * Formats a string into a larger string (like sprintf in C) 426 * @param x the value to format 427 * @return the formatted string 428 */ 429 public String form(String s) { 430 if (fmt != 's') { 431 throw new java.lang.IllegalArgumentException(); 432 } 433 434 if (precision >= 0) { 435 s = s.substring(0, precision); 436 } 437 return pad(s); 438 } 439 440 private static String repeat(char c, int n) { 441 if (n <= 0) { 442 return ""; 443 } 444 StringBuffer s = new StringBuffer(n); 445 for (int i = 0; i < n; i++) { 446 s.append(c); 447 } 448 return s.toString(); 449 } 450 451 private static String convert(long x, int n, int m, String d) { 452 if (x == 0) { 453 return "0"; 454 } 455 String r = ""; 456 while (x != 0) { 457 r = d.charAt((int)(x & m)) + r; 458 x = x >>> n; 459 } 460 return r; 461 } 462 463 private String pad(String r) { 464 String p = repeat(' ', width - r.length()); 465 if (left_align) { 466 return pre + r + p + post; 467 } else { 468 return pre + p + r + post; 469 } 470 } 471 472 private String sign(int s, String r) { 473 String p = ""; 474 if (s < 0) { 475 p = "-"; 476 } else if (s > 0) { 477 if (show_plus) { 478 p = "+"; 479 } else if (show_space) { 480 p = " "; 481 } 482 } else { 483 if (fmt == 'o' && alternate && r.length() > 0 && 484 r.charAt(0) != '0') { 485 p = "0"; 486 } else if (fmt == 'x' && alternate) { 487 p = "0x"; 488 } else if (fmt == 'X' && alternate) { 489 p = "0X"; 490 } 491 } 492 493 int w = 0; 494 if (leading_zeroes) { 495 w = width; 496 } else if ((fmt == 'd' || fmt == 'i' || fmt == 'x' || 497 fmt == 'X' || fmt == 'o') && precision > 0) { 498 w = precision; 499 } 500 501 return p + repeat('0', w - p.length() - r.length()) + r; 502 } 503 504 505 private String fixed_format(double d) { 506 String f = ""; 507 508 if (d > 0x7FFFFFFFFFFFFFFFL) { 509 return exp_format(d); 510 } 511 512 long l = (long)(precision == 0 ? d + 0.5 : d); 513 f = f + l; 514 515 double fr = d - l; // fractional part 516 if (fr >= 1 || fr < 0) { 517 return exp_format(d); 518 } 519 520 return f + frac_part(fr); 521 } 522 523 private String frac_part(double fr) { 524 // precondition: 0 <= fr < 1 525 String z = ""; 526 if (precision > 0) { 527 double factor = 1; 528 String leading_zeroes = ""; 529 for (int i = 1; i <= precision && factor <= 0x7FFFFFFFFFFFFFFFL; 530 i++) { 531 factor *= 10; 532 leading_zeroes = leading_zeroes + "0"; 533 } 534 long l = (long) (factor * fr + 0.5); 535 536 z = leading_zeroes + l; 537 z = z.substring(z.length() - precision, z.length()); 538 } 539 540 541 if (precision > 0 || alternate) { 542 z = "." + z; 543 } 544 545 if ((fmt == 'G' || fmt == 'g') && !alternate) { 546 // remove trailing zeroes and decimal point 547 int t = z.length() - 1; 548 while (t >= 0 && z.charAt(t) == '0') { 549 t--; 550 } 551 if (t >= 0 && z.charAt(t) == '.') { 552 t--; 553 } 554 z = z.substring(0, t + 1); 555 } 556 return z; 557 } 558 559 private String exp_format(double d) { 560 String f = ""; 561 int e = 0; 562 double dd = d; 563 double factor = 1; 564 565 while (dd > 10) { 566 e++; factor /= 10; dd = dd / 10; 567 } 568 569 while (dd < 1) { 570 e--; factor *= 10; dd = dd * 10; 571 } 572 573 if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision) { 574 return fixed_format(d); 575 } 576 577 d = d * factor; 578 f = f + fixed_format(d); 579 580 if (fmt == 'e' || fmt == 'g') { 581 f = f + "e"; 582 } else { 583 f = f + "E"; 584 } 585 586 String p = "000"; 587 if (e >= 0) { 588 f = f + "+"; 589 p = p + e; 590 } else { 591 f = f + "-"; 592 p = p + (-e); 593 } 594 595 return f + p.substring(p.length() - 3, p.length()); 596 } 597 598 private int width; 599 private int precision; 600 private String pre; 601 private String post; 602 private boolean leading_zeroes; 603 private boolean show_plus; 604 private boolean alternate; 605 private boolean show_space; 606 private boolean left_align; 607 private char fmt; // one of cdeEfgGiosxXos 608 }