summaryrefslogtreecommitdiffstats
path: root/base/util/src/com/netscape/cmsutil/util/Fmt.java
diff options
context:
space:
mode:
Diffstat (limited to 'base/util/src/com/netscape/cmsutil/util/Fmt.java')
-rw-r--r--base/util/src/com/netscape/cmsutil/util/Fmt.java605
1 files changed, 605 insertions, 0 deletions
diff --git a/base/util/src/com/netscape/cmsutil/util/Fmt.java b/base/util/src/com/netscape/cmsutil/util/Fmt.java
new file mode 100644
index 000000000..a24b8d090
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/util/Fmt.java
@@ -0,0 +1,605 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.util;
+
+// Fmt - some simple single-arg sprintf-like routines
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+/// Some simple single-arg sprintf-like routines.
+// <P>
+// It is apparently impossible to declare a Java method that accepts
+// variable numbers of any type of argument. You can declare it to take
+// Objects, but numeric variables and constants are not in fact Objects.
+// <P>
+// However, using the built-in string concatenation, it's almost as
+// convenient to make a series of single-argument formatting routines.
+// <P>
+// Fmt can format the following types:
+// <BLOCKQUOTE><CODE>
+// byte short int long float double char String Object
+// </CODE></BLOCKQUOTE>
+// For each type there is a set of overloaded methods, each returning
+// a formatted String. There's the plain formatting version:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x )
+// </PRE></BLOCKQUOTE>
+// There's a version specifying a minimum field width:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth )
+// </PRE></BLOCKQUOTE>
+// And there's a version that takes flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( x, minWidth, flags )
+// </PRE></BLOCKQUOTE>
+// Currently available flags are:
+// <BLOCKQUOTE><PRE>
+// Fmt.ZF - zero-fill
+// Fmt.LJ - left justify
+// Fmt.HX - hexadecimal
+// Fmt.OC - octal
+// </PRE></BLOCKQUOTE>
+// The HX and OC flags imply unsigned output.
+// <P>
+// For doubles and floats, there's a significant-figures parameter before
+// the flags:
+// <BLOCKQUOTE><PRE>
+// Fmt.fmt( d )
+// Fmt.fmt( d, minWidth )
+// Fmt.fmt( d, minWidth, sigFigs )
+// Fmt.fmt( d, minWidth, sigFigs, flags )
+// </PRE></BLOCKQUOTE>
+// <P>
+// <A HREF="/resources/classes/Acme/Fmt.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
+// <HR>
+// Similar classes:
+// <UL>
+// <LI> Andrew Scherpbier's <A HREF="http://www.sdsu.edu/doc/java-SDSU/sdsu.FormatString.html">FormatString</A>
+// Tries to allow variable numbers of arguments by
+// supplying overloaded routines with different combinations of parameters,
+// but doesn't actually supply that many. The floating point conversion
+// is described as "very incomplete".
+// <LI> Core Java's <A HREF="http://www.apl.jhu.edu/~hall/java/CoreJava-Format.html">Format</A>.
+// The design seems a little weird. They want you to create an instance,
+// passing the format string to the constructor, and then call an instance
+// method with your data to do the actual formatting. The extra steps are
+// pointless; better to just use static methods.
+// </UL>
+
+public class Fmt {
+
+ // Flags.
+ /// Zero-fill.
+ public static final int ZF = 1;
+ /// Left justify.
+ public static final int LJ = 2;
+ /// Hexadecimal.
+ public static final int HX = 4;
+ /// Octal.
+ public static final int OC = 8;
+ // Was a number - internal use.
+ private static final int WN = 16;
+
+ // byte
+ public static String fmt(byte b) {
+ return fmt(b, 0, 0);
+ }
+
+ public static String fmt(byte b, int minWidth) {
+ return fmt(b, minWidth, 0);
+ }
+
+ public static String fmt(byte b, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(Integer.toString(b & 0xff, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(Integer.toString(b & 0xff, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(b & 0xff), minWidth, flags | WN);
+ }
+
+ // short
+ public static String fmt(short s) {
+ return fmt(s, 0, 0);
+ }
+
+ public static String fmt(short s, int minWidth) {
+ return fmt(s, minWidth, 0);
+ }
+
+ public static String fmt(short s, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(
+ Integer.toString(s & 0xffff, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(
+ Integer.toString(s & 0xffff, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(s), minWidth, flags | WN);
+ }
+
+ // int
+ public static String fmt(int i) {
+ return fmt(i, 0, 0);
+ }
+
+ public static String fmt(int i, int minWidth) {
+ return fmt(i, minWidth, 0);
+ }
+
+ public static String fmt(int i, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal)
+ return fmt(
+ Long.toString(i & 0xffffffffL, 16), minWidth, flags | WN);
+ else if (octal)
+ return fmt(
+ Long.toString(i & 0xffffffffL, 8), minWidth, flags | WN);
+ else
+ return fmt(Integer.toString(i), minWidth, flags | WN);
+ }
+
+ // long
+ public static String fmt(long l) {
+ return fmt(l, 0, 0);
+ }
+
+ public static String fmt(long l, int minWidth) {
+ return fmt(l, minWidth, 0);
+ }
+
+ public static String fmt(long l, int minWidth, int flags) {
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+
+ if (hexadecimal) {
+ if ((l & 0xf000000000000000L) != 0)
+ return fmt(
+ Long.toString(l >>> 60, 16) +
+ fmt(l & 0x0fffffffffffffffL, 15, HX | ZF),
+ minWidth, flags | WN);
+ else
+ return fmt(Long.toString(l, 16), minWidth, flags | WN);
+ } else if (octal) {
+ if ((l & 0x8000000000000000L) != 0)
+ return fmt(
+ Long.toString(l >>> 63, 8) +
+ fmt(l & 0x7fffffffffffffffL, 21, OC | ZF),
+ minWidth, flags | WN);
+ else
+ return fmt(Long.toString(l, 8), minWidth, flags | WN);
+ } else
+ return fmt(Long.toString(l), minWidth, flags | WN);
+ }
+
+ // float
+ public static String fmt(float f) {
+ return fmt(f, 0, 0, 0);
+ }
+
+ public static String fmt(float f, int minWidth) {
+ return fmt(f, minWidth, 0, 0);
+ }
+
+ public static String fmt(float f, int minWidth, int sigFigs) {
+ return fmt(f, minWidth, sigFigs, 0);
+ }
+
+ public static String fmt(float f, int minWidth, int sigFigs, int flags) {
+ if (sigFigs != 0)
+ return fmt(
+ sigFigFix(Float.toString(f), sigFigs), minWidth,
+ flags | WN);
+ else
+ return fmt(Float.toString(f), minWidth, flags | WN);
+ }
+
+ // double
+ public static String fmt(double d) {
+ return fmt(d, 0, 0, 0);
+ }
+
+ public static String fmt(double d, int minWidth) {
+ return fmt(d, minWidth, 0, 0);
+ }
+
+ public static String fmt(double d, int minWidth, int sigFigs) {
+ return fmt(d, minWidth, sigFigs, 0);
+ }
+
+ public static String fmt(double d, int minWidth, int sigFigs, int flags) {
+ if (sigFigs != 0)
+ return fmt(
+ sigFigFix(doubleToString(d), sigFigs), minWidth,
+ flags | WN);
+ else
+ return fmt(doubleToString(d), minWidth, flags | WN);
+ }
+
+ // char
+ public static String fmt(char c) {
+ return fmt(c, 0, 0);
+ }
+
+ public static String fmt(char c, int minWidth) {
+ return fmt(c, minWidth, 0);
+ }
+
+ public static String fmt(char c, int minWidth, int flags) {
+ // return fmt( Character.toString( c ), minWidth, flags );
+ // Character currently lacks a static toString method. Workaround
+ // is to make a temporary instance and use the instance toString.
+ return fmt(Character.valueOf(c).toString(), minWidth, flags);
+ }
+
+ // Object
+ public static String fmt(Object o) {
+ return fmt(o, 0, 0);
+ }
+
+ public static String fmt(Object o, int minWidth) {
+ return fmt(o, minWidth, 0);
+ }
+
+ public static String fmt(Object o, int minWidth, int flags) {
+ return fmt(o.toString(), minWidth, flags);
+ }
+
+ // String
+ public static String fmt(String s) {
+ return fmt(s, 0, 0);
+ }
+
+ public static String fmt(String s, int minWidth) {
+ return fmt(s, minWidth, 0);
+ }
+
+ public static String fmt(String s, int minWidth, int flags) {
+ int len = s.length();
+ boolean zeroFill = ((flags & ZF) != 0);
+ boolean leftJustify = ((flags & LJ) != 0);
+ boolean hexadecimal = ((flags & HX) != 0);
+ boolean octal = ((flags & OC) != 0);
+ boolean wasNumber = ((flags & WN) != 0);
+
+ if ((hexadecimal || octal || zeroFill) && !wasNumber)
+ throw new InternalError("Acme.Fmt: number flag on a non-number");
+ if (zeroFill && leftJustify)
+ throw new InternalError("Acme.Fmt: zero-fill left-justify is silly");
+ if (hexadecimal && octal)
+ throw new InternalError("Acme.Fmt: can't do both hex and octal");
+ if (len >= minWidth)
+ return s;
+ int fillWidth = minWidth - len;
+ StringBuffer fill = new StringBuffer(fillWidth);
+
+ for (int i = 0; i < fillWidth; ++i)
+ if (zeroFill)
+ fill.append('0');
+ else
+ fill.append(' ');
+ if (leftJustify)
+ return s + fill;
+ else if (zeroFill && s.startsWith("-"))
+ return "-" + fill + s.substring(1);
+ else
+ return fill + s;
+ }
+
+ // Internal routines.
+
+ private static String sigFigFix(String s, int sigFigs) {
+ // First dissect the floating-point number string into sign,
+ // integer part, fraction part, and exponent.
+ String sign;
+ String unsigned;
+
+ if (s.startsWith("-") || s.startsWith("+")) {
+ sign = s.substring(0, 1);
+ unsigned = s.substring(1);
+ } else {
+ sign = "";
+ unsigned = s;
+ }
+ String mantissa;
+ String exponent;
+ int eInd = unsigned.indexOf('e');
+
+ if (eInd == -1) {
+ mantissa = unsigned;
+ exponent = "";
+ } else {
+ mantissa = unsigned.substring(0, eInd);
+ exponent = unsigned.substring(eInd);
+ }
+ StringBuffer number, fraction;
+ int dotInd = mantissa.indexOf('.');
+
+ if (dotInd == -1) {
+ number = new StringBuffer(mantissa);
+ fraction = new StringBuffer("");
+ } else {
+ number = new StringBuffer(mantissa.substring(0, dotInd));
+ fraction = new StringBuffer(mantissa.substring(dotInd + 1));
+ }
+
+ int numFigs = number.length();
+ int fracFigs = fraction.length();
+
+ if ((numFigs == 0 || number.toString().equals("0")) &&
+ fracFigs > 0) {
+ // Don't count leading zeros in the fraction.
+ numFigs = 0;
+ for (int i = 0; i < fraction.length(); ++i) {
+ if (fraction.charAt(i) != '0')
+ break;
+ --fracFigs;
+ }
+ }
+ int mantFigs = numFigs + fracFigs;
+
+ if (sigFigs > mantFigs) {
+ // We want more figures; just append zeros to the fraction.
+ for (int i = mantFigs; i < sigFigs; ++i)
+ fraction.append('0');
+ } else if (sigFigs < mantFigs && sigFigs >= numFigs) {
+ // Want fewer figures in the fraction; chop.
+ fraction.setLength(
+ fraction.length() - (fracFigs - (sigFigs - numFigs)));
+ // Round?
+ } else if (sigFigs < numFigs) {
+ // Want fewer figures in the number; turn them to zeros.
+ fraction.setLength(0); // should already be zero, but make sure
+ for (int i = sigFigs; i < numFigs; ++i)
+ number.setCharAt(i, '0');
+ // Round?
+ }
+ // Else sigFigs == mantFigs, which is fine.
+
+ if (fraction.length() == 0)
+ return sign + number + exponent;
+ else
+ return sign + number + "." + fraction + exponent;
+ }
+
+ /// Improved version of Double.toString(), returns more decimal places.
+ // <P>
+ // The JDK 1.0.2 version of Double.toString() returns only six decimal
+ // places on some systems. In JDK 1.1 full precision is returned on
+ // all platforms.
+ // @deprecated
+ // @see java.lang.Double.toString
+ public static String doubleToString(double d) {
+ // Handle special numbers first, to avoid complications.
+ if (Double.isNaN(d))
+ return "NaN";
+ if (d == Double.NEGATIVE_INFINITY)
+ return "-Inf";
+ if (d == Double.POSITIVE_INFINITY)
+ return "Inf";
+
+ // Grab the sign, and then make the number positive for simplicity.
+ boolean negative = false;
+
+ if (d < 0.0D) {
+ negative = true;
+ d = -d;
+ }
+
+ // Get the native version of the unsigned value, as a template.
+ String unsStr = Double.toString(d);
+
+ // Dissect out the exponent.
+ String mantStr, expStr;
+ int exp;
+ int eInd = unsStr.indexOf('e');
+
+ if (eInd == -1) {
+ mantStr = unsStr;
+ expStr = "";
+ exp = 0;
+ } else {
+ mantStr = unsStr.substring(0, eInd);
+ expStr = unsStr.substring(eInd + 1);
+ if (expStr.startsWith("+"))
+ exp = Integer.parseInt(expStr.substring(1));
+ else
+ exp = Integer.parseInt(expStr);
+ }
+
+ // Dissect out the number part.
+ String numStr;
+ int dotInd = mantStr.indexOf('.');
+
+ if (dotInd == -1)
+ numStr = mantStr;
+ else
+ numStr = mantStr.substring(0, dotInd);
+ long num;
+
+ if (numStr.length() == 0)
+ num = 0;
+ else
+ num = Integer.parseInt(numStr);
+
+ // Build the new mantissa.
+ StringBuffer newMantBuf = new StringBuffer(numStr + ".");
+ double p = Math.pow(10, exp);
+ double frac = d - num * p;
+ String digits = "0123456789";
+ int nDigits = 16 - numStr.length(); // about 16 digits in a double
+
+ for (int i = 0; i < nDigits; ++i) {
+ p /= 10.0D;
+ int dig = (int) (frac / p);
+
+ if (dig < 0)
+ dig = 0;
+ if (dig > 9)
+ dig = 9;
+ newMantBuf.append(digits.charAt(dig));
+ frac -= dig * p;
+ }
+
+ if ((int) (frac / p + 0.5D) == 1) {
+ // Round up.
+ boolean roundMore = true;
+
+ for (int i = newMantBuf.length() - 1; i >= 0; --i) {
+ int dig = digits.indexOf(newMantBuf.charAt(i));
+
+ if (dig == -1)
+ continue;
+ ++dig;
+ if (dig == 10) {
+ newMantBuf.setCharAt(i, '0');
+ continue;
+ }
+ newMantBuf.setCharAt(i, digits.charAt(dig));
+ roundMore = false;
+ break;
+ }
+ if (roundMore) {
+ // If this happens, we need to prepend a 1. But I haven't
+ // found a test case yet, so I'm leaving it out for now.
+ // But if you get this message, please let me know!
+ newMantBuf.append("ROUNDMORE");
+ }
+ }
+
+ // Chop any trailing zeros.
+ int len = newMantBuf.length();
+
+ while (newMantBuf.charAt(len - 1) == '0')
+ newMantBuf.setLength(--len);
+ // And chop a trailing dot, if any.
+ if (newMantBuf.charAt(len - 1) == '.')
+ newMantBuf.setLength(--len);
+
+ // Done.
+ return (negative ? "-" : "") +
+ newMantBuf +
+ (expStr.length() != 0 ? ("e" + expStr) : "");
+ }
+
+ /******************************************************************************
+ * /// Test program.
+ * public static void main( String[] args )
+ * {
+ * System.out.println( "Starting tests." );
+ * show( Fmt.fmt( "Hello there." ) );
+ * show( Fmt.fmt( 123 ) );
+ * show( Fmt.fmt( 123, 10 ) );
+ * show( Fmt.fmt( 123, 10, Fmt.ZF ) );
+ * show( Fmt.fmt( 123, 10, Fmt.LJ ) );
+ * show( Fmt.fmt( -123 ) );
+ * show( Fmt.fmt( -123, 10 ) );
+ * show( Fmt.fmt( -123, 10, Fmt.ZF ) );
+ * show( Fmt.fmt( -123, 10, Fmt.LJ ) );
+ * show( Fmt.fmt( (byte) 0xbe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( (short) 0xbabe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0xcafebabe, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0xdeadbeefcafebabeL, 22, Fmt.OC ) );
+ * show( Fmt.fmt( 0x8000000000000000L, 22, Fmt.OC ) );
+ * show( Fmt.fmt( (byte) 0xbe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( (short) 0xbabe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0xcafebabe, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0xdeadbeefcafebabeL, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 0x8000000000000000L, 16, Fmt.HX ) );
+ * show( Fmt.fmt( 'c' ) );
+ * show( Fmt.fmt( new java.util.Date() ) );
+ * show( Fmt.fmt( 123.456F ) );
+ * show( Fmt.fmt( 123456000000000000.0F ) );
+ * show( Fmt.fmt( 123.456F, 0, 8 ) );
+ * show( Fmt.fmt( 123.456F, 0, 7 ) );
+ * show( Fmt.fmt( 123.456F, 0, 6 ) );
+ * show( Fmt.fmt( 123.456F, 0, 5 ) );
+ * show( Fmt.fmt( 123.456F, 0, 4 ) );
+ * show( Fmt.fmt( 123.456F, 0, 3 ) );
+ * show( Fmt.fmt( 123.456F, 0, 2 ) );
+ * show( Fmt.fmt( 123.456F, 0, 1 ) );
+ * show( Fmt.fmt( 123456000000000000.0F, 0, 4 ) );
+ * show( Fmt.fmt( -123.456F, 0, 4 ) );
+ * show( Fmt.fmt( -123456000000000000.0F, 0, 4 ) );
+ * show( Fmt.fmt( 123.0F ) );
+ * show( Fmt.fmt( 123.0D ) );
+ * show( Fmt.fmt( 1.234567890123456789F ) );
+ * show( Fmt.fmt( 1.234567890123456789D ) );
+ * show( Fmt.fmt( 1234567890123456789F ) );
+ * show( Fmt.fmt( 1234567890123456789D ) );
+ * show( Fmt.fmt( 0.000000000000000000001234567890123456789F ) );
+ * show( Fmt.fmt( 0.000000000000000000001234567890123456789D ) );
+ * show( Fmt.fmt( 12300.0F ) );
+ * show( Fmt.fmt( 12300.0D ) );
+ * show( Fmt.fmt( 123000.0F ) );
+ * show( Fmt.fmt( 123000.0D ) );
+ * show( Fmt.fmt( 1230000.0F ) );
+ * show( Fmt.fmt( 1230000.0D ) );
+ * show( Fmt.fmt( 12300000.0F ) );
+ * show( Fmt.fmt( 12300000.0D ) );
+ * show( Fmt.fmt( Float.NaN ) );
+ * show( Fmt.fmt( Float.POSITIVE_INFINITY ) );
+ * show( Fmt.fmt( Float.NEGATIVE_INFINITY ) );
+ * show( Fmt.fmt( Double.NaN ) );
+ * show( Fmt.fmt( Double.POSITIVE_INFINITY ) );
+ * show( Fmt.fmt( Double.NEGATIVE_INFINITY ) );
+ * show( Fmt.fmt( 1.0F / 8.0F ) );
+ * show( Fmt.fmt( 1.0D / 8.0D ) );
+ * System.out.println( "Done with tests." );
+ * }
+ *
+ * private static void show( String str )
+ * {
+ * System.out.println( "#" + str + "#" );
+ * }
+ ******************************************************************************/
+
+}