001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.misc;
066:
067: /*
068: * Format.java
069: *
070: * Copyright 1999, 2000, 2001 Jcorporate Ltd.
071: */
072:
073: import java.io.PrintStream;
074: import java.io.PrintWriter;
075:
076: /**
077: * @author Michael Nash
078: */
079: public class Format {
080: private int width;
081: private int precision;
082: private String pre;
083: private String post;
084: private boolean leadingZeroes;
085: private boolean showPlus;
086: private boolean alternate;
087: private boolean showSpace;
088: private boolean leftAlign;
089: private char fmt; // one of cdeEfgGiosxXos
090:
091: /**
092: * Formats a number in a printf format, like C
093: *
094: * @param s the format string following printf format string
095: * The string has a prefix, a format code and a suffix. The prefix and suffix
096: * become part of the formatted output. The format code directs the
097: * formatting of the (single) parameter to be formatted. The code has the
098: * following structure
099: * <ul>
100: * <li> a % (required)
101: * <li> a modifier (optional)
102: * <dl>
103: * <dt> + <dd> forces display of + for positive numbers
104: * <dt> 0 <dd> show leading zeroes
105: * <dt> - <dd> align left in the field
106: * <dt> space <dd> prepend a space in front of positive numbers
107: * <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers.
108: * Don't suppress trailing zeroes in general floating point format.
109: * </dl>
110: * <li> an integer denoting field width (optional)
111: * <li> a period followed by an integer denoting precision (optional)
112: * <li> a format descriptor (required)
113: * <dl>
114: * <dt>f <dd> floating point number in fixed format
115: * <dt>e, E <dd> floating point number in exponential notation (scientific format).
116: * The E format results in an uppercase E for the exponent (1.14130E+003), the e
117: * format in a lowercase e.
118: * <dt>g, G <dd> floating point number in general format (fixed format for small
119: * numbers, exponential format for large numbers). Trailing zeroes are suppressed.
120: * The G format results in an uppercase E for the exponent (if any), the g format
121: * in a lowercase e.
122: * <dt>d, i <dd> integer in decimal
123: * <dt>x <dd> integer in hexadecimal
124: * <dt>o <dd> integer in octal
125: * <dt>s <dd> string
126: * <dt>c <dd> character
127: * </dl>
128: * </ul>
129: */
130: public Format(String s) {
131: width = 0;
132: precision = -1;
133: pre = "";
134: post = "";
135: leadingZeroes = false;
136: showPlus = false;
137: alternate = false;
138: showSpace = false;
139: leftAlign = false;
140: fmt = ' ';
141:
142: int length = s.length();
143: int parseState = 0;
144:
145: // 0 = prefix, 1 = flags, 2 = width, 3 = precision,
146: // 4 = format, 5 = end
147: int i = 0;
148:
149: while (parseState == 0) {
150: if (i >= length) {
151: parseState = 5;
152: } else if (s.charAt(i) == '%') {
153: if (i < length - 1) {
154: if (s.charAt(i + 1) == '%') {
155: pre = pre + '%';
156: i++;
157: } else {
158: parseState = 1;
159: }
160: } else {
161: throw new java.lang.IllegalArgumentException();
162: }
163: } else {
164: pre = pre + s.charAt(i);
165: }
166:
167: i++;
168: } /* while parseState == 0 */
169:
170: while (parseState == 1) {
171: if (i >= length) {
172: parseState = 5;
173: } else if (s.charAt(i) == ' ') {
174: showSpace = true;
175: } else if (s.charAt(i) == '-') {
176: leftAlign = true;
177: } else if (s.charAt(i) == '+') {
178: showPlus = true;
179: } else if (s.charAt(i) == '0') {
180: leadingZeroes = true;
181: } else if (s.charAt(i) == '#') {
182: alternate = true;
183: } else {
184: parseState = 2;
185: i--;
186: }
187:
188: i++;
189: } /* while parseState == 1 */
190:
191: while (parseState == 2) {
192: if (i >= length) {
193: parseState = 5;
194: } else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') {
195: width = width * 10 + s.charAt(i) - '0';
196: i++;
197: } else if (s.charAt(i) == '.') {
198: parseState = 3;
199: precision = 0;
200: i++;
201: } else {
202: parseState = 4;
203: }
204: } /* while parseState == 2 */
205:
206: while (parseState == 3) {
207: if (i >= length) {
208: parseState = 5;
209: } else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') {
210: precision = precision * 10 + s.charAt(i) - '0';
211: i++;
212: } else {
213: parseState = 4;
214: }
215: } /* while parseState == 3 */
216:
217: if (parseState == 4) {
218: if (i >= length) {
219: parseState = 5;
220: } else {
221: fmt = s.charAt(i);
222: }
223:
224: i++;
225: }
226: if (i < length) {
227: post = s.substring(i, length);
228: }
229: } /* Format(String) */
230:
231: /**
232: * Converts a string of digits to an double
233: *
234: * @param s a string
235: * @return
236: */
237: public static double atof(String s) {
238: int i = 0;
239: int sign = 1;
240: double r = 0; // integer part
241: double f = 0; // fractional part
242: double p = 1; // exponent of fractional part
243: int state = 0; // 0 = int part, 1 = frac part
244:
245: while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
246: i++;
247: }
248: if (i < s.length() && s.charAt(i) == '-') {
249: sign = -1;
250: i++;
251: } else if (i < s.length() && s.charAt(i) == '+') {
252: i++;
253: }
254: while (i < s.length()) {
255: char ch = s.charAt(i);
256:
257: if ('0' <= ch && ch <= '9') {
258: if (state == 0) {
259: r = r * 10 + ch - '0';
260: } else if (state == 1) {
261: p = p / 10;
262: r = r + p * (ch - '0');
263: }
264: } else if (ch == '.') {
265: if (state == 0) {
266: state = 1;
267: } else {
268: return sign * r;
269: }
270: } else if (ch == 'e' || ch == 'E') {
271: long e = (int) parseLong(s.substring(i + 1), 10);
272:
273: return sign * r * Math.pow(10, e);
274: } else {
275: return sign * r;
276: }
277:
278: i++;
279: }
280:
281: return sign * r;
282: } /* atof(String) */
283:
284: /**
285: * Converts a string of digits (decimal, octal or hex) to an integer
286: *
287: * @param s a string
288: * @return the numeric value of the prefix of s representing a
289: * base 10 integer
290: */
291: public static int atoi(String s) {
292: return (int) atol(s);
293: } /* atoi(String) */
294:
295: /**
296: * Converts a string of digits (decimal, octal or hex) to a long integer
297: *
298: * @param s a string
299: * @return the numeric value of the prefix of s representing a
300: * base 10 integer
301: */
302: public static long atol(String s) {
303: int i = 0;
304:
305: while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
306: i++;
307: }
308: if (i < s.length() && s.charAt(i) == '0') {
309: if (i + 1 < s.length()
310: && (s.charAt(i + 1) == 'x' || s.charAt(i + 1) == 'X')) {
311: return parseLong(s.substring(i + 2), 16);
312: } else {
313: return parseLong(s, 8);
314: }
315: } else {
316: return parseLong(s, 10);
317: }
318: } /* atol(String) */
319:
320: /**
321: * @param x
322: * @param n
323: * @param m
324: * @param d
325: * @return
326: */
327: private static String convert(long x, int n, int m, String d) {
328: if (x == 0) {
329: return ("0");
330: }
331:
332: String r = "";
333:
334: while (x != 0) {
335: r = d.charAt((int) (x & m)) + r;
336: x = x >>> n;
337: }
338:
339: return r;
340: } /* convert(long, int, int, String) */
341:
342: /**
343: * @param d
344: * @return
345: */
346: private String expFormat(double d) {
347: String f = "";
348: int e = 0;
349: double dd = d;
350: double factor = 1;
351:
352: if (d != 0) {
353: while (dd > 10) {
354: e++;
355: factor /= 10;
356: dd = dd / 10;
357: }
358: while (dd < 1) {
359: e--;
360: factor *= 10;
361: dd = dd * 10;
362: }
363: }
364: if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision) {
365: return fixedFormat(d);
366: }
367:
368: d = d * factor;
369: f = f + fixedFormat(d);
370:
371: if (fmt == 'e' || fmt == 'g') {
372: f = f + "e";
373: } else {
374: f = f + "E";
375: }
376:
377: String p = "000";
378:
379: if (e >= 0) {
380: f = f + "+";
381: p = p + e;
382: } else {
383: f = f + "-";
384: p = p + (-e);
385: }
386:
387: return f + p.substring(p.length() - 3, p.length());
388: } /* expFormat(double) */
389:
390: /**
391: * @param d
392: * @return
393: */
394: private String fixedFormat(double d) {
395: boolean removeTrailing = (fmt == 'G' || fmt == 'g')
396: && !alternate;
397:
398: // remove trailing zeroes and decimal point
399: if (d > 0x7FFFFFFFFFFFFFFFL) {
400: return expFormat(d);
401: }
402: if (precision == 0) {
403: return (long) (d + 0.5) + (removeTrailing ? "" : ".");
404: }
405:
406: long whole = (long) d;
407: double fr = d - whole; // fractional part
408:
409: if (fr >= 1 || fr < 0) {
410: return expFormat(d);
411: }
412:
413: double factor = 1;
414: String leadingZeroes = "";
415:
416: for (int i = 1; i <= precision && factor <= 0x7FFFFFFFFFFFFFFFL; i++) {
417: factor *= 10;
418: leadingZeroes = leadingZeroes + "0";
419: }
420:
421: long l = (long) (factor * fr + 0.5);
422:
423: if (l >= factor) { // CSH 10-25-97
424: l = 0;
425: whole++;
426: }
427:
428: String z = leadingZeroes + l;
429: z = "." + z.substring(z.length() - precision, z.length());
430:
431: if (removeTrailing) {
432: int t = z.length() - 1;
433:
434: while (t >= 0 && z.charAt(t) == '0') {
435: t--;
436: }
437: if (t >= 0 && z.charAt(t) == '.') {
438: t--;
439: }
440:
441: z = z.substring(0, t + 1);
442: }
443:
444: return whole + z;
445: } /* fixedFormat(double) */
446:
447: /**
448: * Formats a character into a string (like sprintf in C)
449: *
450: * @param c the value to format
451: * @return the formatted string
452: */
453: public String form(char c) {
454: if (fmt != 'c') {
455: throw new java.lang.IllegalArgumentException();
456: }
457:
458: String r = "" + c;
459:
460: return pad(r);
461: } /* form(char) */
462:
463: /**
464: * Formats a double into a string (like sprintf in C)
465: *
466: * @param x the number to format
467: * @return the formatted string
468: */
469: public String form(double x) {
470: String r;
471:
472: if (precision < 0) {
473: precision = 6;
474: }
475:
476: int s = 1;
477:
478: if (x < 0) {
479: x = -x;
480: s = -1;
481: }
482: if (fmt == 'f') {
483: r = fixedFormat(x);
484: } else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G') {
485: r = expFormat(x);
486: } else {
487: throw new java.lang.IllegalArgumentException();
488: }
489:
490: return pad(sign(s, r));
491: } /* form(double) */
492:
493: /**
494: * Formats a long integer into a string (like sprintf in C)
495: *
496: * @param x the number to format
497: * @return the formatted string
498: */
499: public String form(long x) {
500: String r;
501: int s = 0;
502:
503: if (fmt == 'd' || fmt == 'i') {
504: if (x < 0) {
505: r = ("" + x).substring(1);
506: s = -1;
507: } else {
508: r = "" + x;
509: s = 1;
510: }
511: } else if (fmt == 'o') {
512: r = convert(x, 3, 7, "01234567");
513: } else if (fmt == 'x') {
514: r = convert(x, 4, 15, "0123456789abcdef");
515: } else if (fmt == 'X') {
516: r = convert(x, 4, 15, "0123456789ABCDEF");
517: } else {
518: throw new java.lang.IllegalArgumentException();
519: }
520:
521: return pad(sign(s, r));
522: } /* form(long) */
523:
524: /**
525: * Formats a string into a larger string (like sprintf in C)
526: *
527: * @param s the value to format
528: * @return the formatted string
529: */
530: public String form(String s) {
531: if (fmt != 's') {
532: throw new java.lang.IllegalArgumentException();
533: }
534: if (precision >= 0 && precision < s.length()) {
535: s = s.substring(0, precision);
536: }
537:
538: return pad(s);
539: } /* form(String) */
540:
541: /**
542: * @param r
543: * @return
544: */
545: private String pad(String r) {
546: String p = repeat(' ', width - r.length());
547:
548: if (leftAlign) {
549: return pre + r + p + post;
550: } else {
551: return pre + p + r + post;
552: }
553: } /* pad(String) */
554:
555: /**
556: * @param s
557: * @param base
558: * @return
559: */
560: private static long parseLong(String s, int base) {
561: int i = 0;
562: int sign = 1;
563: long r = 0;
564:
565: while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
566: i++;
567: }
568: if (i < s.length() && s.charAt(i) == '-') {
569: sign = -1;
570: i++;
571: } else if (i < s.length() && s.charAt(i) == '+') {
572: i++;
573: }
574: while (i < s.length()) {
575: char ch = s.charAt(i);
576:
577: if ('0' <= ch && ch < '0' + base) {
578: r = r * base + ch - '0';
579: } else if ('A' <= ch && ch < 'A' + base - 10) {
580: r = r * base + ch - 'A' + 10;
581: } else if ('a' <= ch && ch < 'a' + base - 10) {
582: r = r * base + ch - 'a' + 10;
583: } else {
584: return r * sign;
585: }
586:
587: i++;
588: }
589:
590: return r * sign;
591: } /* parseLong(String, int) */
592:
593: /**
594: * prints a formatted number following printf conventions
595: *
596: * @param s a PrintStream
597: * @param fmt the format string
598: * @param x the character to
599: */
600: public static void print(PrintStream s, String fmt, char x) {
601: s.print(new Format(fmt).form(x));
602: } /* print(PrintStream, String, char) */
603:
604: /**
605: * prints a formatted number following printf conventions
606: *
607: * @param s a PrintStream
608: * @param fmt the format string
609: * @param x the double to print
610: */
611: public static void print(PrintStream s, String fmt, double x) {
612: s.print(new Format(fmt).form(x));
613: } /* print(PrintStream, String, double) */
614:
615: /**
616: * prints a formatted number following printf conventions
617: *
618: * @param s a PrintStream
619: * @param fmt the format string
620: * @param x the long to print
621: */
622: public static void print(PrintStream s, String fmt, long x) {
623: s.print(new Format(fmt).form(x));
624: } /* print(PrintStream, String, long) */
625:
626: /**
627: * prints a formatted number following printf conventions
628: *
629: * @param s a PrintStream, fmt the format string
630: * @param fmt
631: * @param x a string that represents the digits to print
632: */
633: public static void print(PrintStream s, String fmt, String x) {
634: s.print(new Format(fmt).form(x));
635: } /* print(PrintStream, String, String) */
636:
637: /**
638: * prints a formatted number following printf conventions
639: *
640: * @param s a PrintStream
641: * @param fmt the format string
642: * @param x the double to print
643: */
644: public static void print(PrintWriter s, String fmt, double x) {
645: s.print(new Format(fmt).form(x));
646: } /* print(PrintWriter, String, double) */
647:
648: /**
649: * prints a formatted number following printf conventions
650: *
651: * @param s a PrintStream, fmt the format string
652: * @param fmt
653: * @param x a string that represents the digits to print
654: */
655: public static void print(PrintWriter s, String fmt, String x) {
656: s.print(new Format(fmt).form(x));
657: } /* print(PrintWriter, String, String) */
658:
659: /**
660: * @param c
661: * @param n
662: * @return
663: */
664: private static String repeat(char c, int n) {
665: if (n <= 0) {
666: return ("");
667: }
668:
669: StringBuffer s = new StringBuffer(n);
670:
671: for (int i = 0; i < n; i++) {
672: s.append(c);
673: }
674:
675: return s.toString();
676: } /* repeat(char, int) */
677:
678: /**
679: * @param s
680: * @param r
681: * @return
682: */
683: private String sign(int s, String r) {
684: String p = ("");
685:
686: if (s < 0) {
687: p = "-";
688: } else if (s > 0) {
689: if (showPlus) {
690: p = "+";
691: } else if (showSpace) {
692: p = " ";
693: }
694: } else {
695: if (fmt == 'o' && alternate && r.length() > 0
696: && r.charAt(0) != '0') {
697: p = "0";
698: } else if (fmt == 'x' && alternate) {
699: p = "0x";
700: } else if (fmt == 'X' && alternate) {
701: p = "0X";
702: }
703: }
704:
705: int w = 0;
706:
707: if (leadingZeroes) {
708: w = width;
709: } else if ((fmt == 'd' || fmt == 'i' || fmt == 'x'
710: || fmt == 'X' || fmt == 'o')
711: && precision > 0) {
712: w = precision;
713: }
714:
715: return p + repeat('0', w - p.length() - r.length()) + r;
716: } /* sign(int, String) */
717:
718: } /* Format */
|