aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/util')
-rw-r--r--src/jake2/util/Lib.java525
-rw-r--r--src/jake2/util/Math3D.java564
-rw-r--r--src/jake2/util/PrintfFormat.java3215
-rw-r--r--src/jake2/util/Vargs.java121
4 files changed, 4425 insertions, 0 deletions
diff --git a/src/jake2/util/Lib.java b/src/jake2/util/Lib.java
new file mode 100644
index 0000000..8ec58e1
--- /dev/null
+++ b/src/jake2/util/Lib.java
@@ -0,0 +1,525 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+// Created on 09.12.2003 by RST.
+// $Id: Lib.java,v 1.1 2004-07-07 19:59:52 hzi Exp $
+
+package jake2.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.text.BreakIterator;
+import java.util.Arrays;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.qcommon.*;
+import jake2.render.*;
+import jake2.server.*;
+
+public class Lib {
+
+ /*
+ =============
+ TempVector
+
+ This is just a convenience function
+ for making temporary vectors for function calls
+ =============
+ */
+ public static float tv_vecs[][] = new float[8][3];
+ public static int tv_index;
+ public static float[] tv(float x, float y, float z) {
+
+ float[] v;
+
+ // use an array so that multiple tempvectors won't collide
+ // for a while
+ v = tv_vecs[tv_index];
+ tv_index = (tv_index++) & 7;
+
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+
+ return v;
+ }
+ /*
+ =============
+ VectorToString
+
+ This is just a convenience function
+ for printing vectors
+ =============
+ */
+ public static String vtos(float[] v) {
+ return (int) v[0] + " " + (int) v[1] + " " + (int) v[2];
+ }
+
+ public static String vtofs(float[] v) {
+ return v[0] + " " + v[1] + " " + v[2];
+ }
+
+ public static String vtofsbeaty(float[] v) {
+ return Com.sprintf("%8.2f %8.2f %8.2f", new Vargs().add(v[0]).add(v[1]).add(v[2]));
+ }
+ public static short rand() {
+ return (short) (Math.random() * 0x8000);
+ }
+ public static float crandom() {
+ return (float) (Math.random() - 0.5) * 2.0f;
+ }
+ public static float random() {
+ return (float) Math.random();
+ }
+ public static float crand() {
+ return (float) (Math.random() - 0.5) * 2.0f;
+ }
+ public static float frand() {
+ return (float) Math.random();
+ }
+
+ public static int strcmp(String in1, String in2) {
+ return in1.compareTo(in2);
+ }
+
+ public static int stricmp(String in1, String in2) {
+ return in1.compareToIgnoreCase(in2);
+ }
+
+ public static boolean strstr(String i1, String i2) {
+ return (i1.indexOf(i2) != -1);
+ }
+
+ public static int strncmp(String in1, String in2, int len) {
+ int i1 = Math.min(len, in1.length());
+ int i2 = Math.min(len, in2.length());
+
+ if (i1 < i2)
+ return -1;
+ if (i1 > i2)
+ return 1;
+
+ for (int n = 0; n < i1; n++) {
+ char c1 = in1.charAt(n);
+ char c2 = in2.charAt(n);
+ if (c1 < c2)
+ return -1;
+ if (c1 > c2)
+ return 1;
+ }
+ return 0;
+ }
+ public static float atof(String in) {
+ float res = 0;
+
+ try {
+ res = Float.parseFloat(in);
+ }
+ catch (Exception e) {
+ }
+
+ return res;
+ }
+
+ public static int Q_stricmp(String in1, String in2) {
+ return in1.compareToIgnoreCase(in2);
+ }
+
+ // =================================================================================
+
+ public static int atoi(String in) {
+ try {
+ return Integer.parseInt(in);
+ }
+ catch (Exception e) {
+ return 0;
+ }
+ }
+
+ public static float[] atov(String v) {
+ float[] res = { 0, 0, 0 };
+
+ int i1 = v.indexOf(" ");
+ int i2 = v.indexOf(" ", i1 + 1);
+
+ res[0] = atof(v.substring(0, i1));
+ res[1] = atof(v.substring(i1 + 1, i2));
+ res[2] = atof(v.substring(i2 + 1, v.length()));
+
+ return res;
+ }
+
+ public static int strlen(String in) {
+ return in.length();
+ }
+
+ public static int strlen(char in[]) {
+ for (int i = 0; i < in.length; i++)
+ if (in[i] == 0)
+ return i;
+ return in.length;
+ }
+
+ public static int strlen(byte in[]) {
+ for (int i = 0; i < in.length; i++)
+ if (in[i] == 0)
+ return i;
+ return in.length;
+ }
+
+ public static void strcat(String in, String i) {
+ in += i;
+ }
+
+ public static void strcpy(char dest[], char src[]) {
+ for (int i = 0; i < dest.length && i < src.length; i++)
+ if (src[i] == 0) {
+ dest[i] = 0;
+ return;
+ }
+ else
+ dest[i] = src[i];
+
+ }
+
+ public static void strcpy(byte dest[], byte src[]) {
+ for (int i = 0; i < dest.length && i < src.length; i++)
+ if (src[i] == 0) {
+ dest[i] = 0;
+ return;
+ }
+ else
+ dest[i] = src[i];
+
+ }
+
+ public static String readString(RandomAccessFile file, int len) throws IOException {
+ byte buf[] = new byte[len];
+
+ file.read(buf, 0, len);
+ return new String(buf, 0, strlen(buf));
+ }
+
+ public static String readString(ByteBuffer bb, int len) throws IOException {
+ byte buf[] = new byte[len];
+ bb.get(buf);
+ return new String(buf, 0, strlen(buf));
+ }
+
+ public static String hexdumpfile(ByteBuffer bb, int len) throws IOException {
+
+ ByteBuffer bb1 = bb.slice();
+
+ byte buf[] = new byte[len];
+
+ bb1.get(buf);
+
+ return hexDump(buf, len, false);
+ }
+
+ // dump data as hexstring
+ public static String hexDump(byte data1[], int len, boolean showAddress) {
+ StringBuffer result = new StringBuffer();
+ StringBuffer charfield = new StringBuffer();
+ int i = 0;
+ while (i < len) {
+ if ((i & 0xf) == 0) {
+ if (showAddress) {
+ String address = Integer.toHexString(i);
+ address = ("0000".substring(0, 4 - address.length()) + address).toUpperCase();
+ result.append(address + ": ");
+ }
+ }
+ int v = data1[i];
+
+ result.append(hex2(v));
+ result.append(" ");
+
+ charfield.append(readableChar(v));
+ i++;
+
+ // nach dem letzten, newline einfuegen
+ if ((i & 0xf) == 0) {
+ result.append(charfield);
+ result.append("\n");
+ charfield.setLength(0);
+ }
+ // in der Mitte ein Luecke einfuegen ?
+ else if ((i & 0xf) == 8) {
+ result.append(" ");
+ }
+ }
+ return result.toString();
+ }
+
+ //formats an hex byte
+ public static String hex2(int i) {
+ String val = Integer.toHexString(i & 0xff);
+ return ("00".substring(0, 2 - val.length()) + val).toUpperCase();
+ }
+
+ public static char readableChar(int i) {
+ if ((i < 0x20) || (i > 0x7f))
+ return '.';
+ else
+ return (char) i;
+ }
+
+ public static void printv(String in, float arr[]) {
+ for (int n = 0; n < arr.length; n++) {
+ Com.Println(in + "[" + n + "]: " + arr[n]);
+ }
+ }
+
+ public static void memset(byte[] dest, byte c, int len) {
+ Arrays.fill(dest, 0, len, c);
+ }
+
+ public static void memset(byte[] dest, int c, int len) {
+ Arrays.fill(dest, 0, len, (byte) c);
+ }
+
+ public static void memcpy(byte[] bs, byte[] bs2, int i) {
+ System.arraycopy(bs2, 0, bs, 0, i);
+ }
+
+ static byte nullfiller[] = new byte[8192];
+
+ public static void fwriteString(String s, int len, RandomAccessFile f) throws IOException {
+ if (s == null)
+ return;
+ int diff = len - s.length();
+ if (diff > 0) {
+ f.write(s.getBytes());
+
+ f.write(nullfiller, 0, diff);
+ }
+ else
+ f.write(s.getBytes(), 0, len);
+ }
+
+ public static String cut(String in, char c) {
+ int pos = in.indexOf(c);
+
+ if (pos != -1)
+ return in.substring(0, pos);
+ return in;
+ }
+
+ public static RandomAccessFile fopen(String name, String mode) {
+ try {
+ return new RandomAccessFile(name, mode);
+ }
+ catch (Exception e) {
+ Com.DPrintf("Could not open file:" + name);
+ return null;
+ }
+ }
+
+ public static void fclose(RandomAccessFile f) {
+ try {
+ f.close();
+ }
+ catch (Exception e) {
+ }
+ }
+
+ public static String freadString(RandomAccessFile f, int len) {
+ byte buffer[] = new byte[len];
+ FS.Read(buffer, len, f);
+
+ return new String(buffer).trim();
+ }
+
+ public static String rightFrom(String in, char c) {
+ int pos = in.lastIndexOf(c);
+ if (pos == -1)
+ return "";
+ else if (pos < in.length())
+ return in.substring(pos + 1, in.length());
+ return "";
+ }
+
+ public static String leftFrom(String in, char c) {
+ int pos = in.lastIndexOf(c);
+ if (pos == -1)
+ return "";
+ else if (pos < in.length())
+ return in.substring(0, pos);
+ return "";
+ }
+
+ public static String[] linesplit(String in) {
+
+ StringTokenizer tk = new StringTokenizer(in, "\r\n");
+
+ int count = tk.countTokens();
+ if (count == 0)
+ return new String[] {
+ };
+
+ String result[] = new String[count];
+
+ for (int i = 0; tk.hasMoreTokens(); i++) {
+ result[i] = tk.nextToken();
+ }
+
+ return result;
+ }
+
+ public static void main(String[] args) {
+ System.out.println("testing Lib...");
+
+ String linetest = "line 1\r\n line zwo\nline drei\n\r line4\n.line5";
+
+ String line[] = linesplit(linetest);
+
+ for (int n = 0; n < line.length; n++) {
+ System.out.println("[" + line[n] + "]");
+ }
+
+ String v = "0.234 1.23423 7.23423";
+
+ int i1 = v.indexOf(" ");
+ int i2 = v.indexOf(" ", i1 + 1);
+
+ System.out.println("testing substring...");
+
+ System.out.println("[" + v.substring(0, i1) + "]");
+ System.out.println("[" + v.substring(i1 + 1, i2) + "]");
+ System.out.println("[" + v.substring(i2 + 1, v.length()) + "]");
+
+ System.out.println("rightfrom[" + rightFrom("abcdefg#hijklm", '#') + "]");
+ System.out.println("leftfrom[" + leftFrom("abcdefghijk#12", '#') + "]");
+ System.out.println("leftfrom[" + leftFrom("abcdefghi", '#') + "]");
+ }
+
+ public static int rename(String oldn, String newn) {
+ try {
+ File f1 = new File(oldn);
+ File f2 = new File(newn);
+ f1.renameTo(f2);
+ return 0;
+ }
+ catch (Exception e) {
+ return 1;
+ }
+ return 0;
+ }
+
+ public static byte[] getIntBytes(int c) {
+ byte b[] = new byte[4];
+ b[0] = (byte) ((c & 0xff));
+ b[1] = (byte) ((c >>> 8) & 0xff);
+ b[2] = (byte) ((c >>> 16) & 0xff);
+ b[3] = (byte) ((c >>> 24) & 0xff);
+ return b;
+ }
+
+ public static int getInt(byte b[]) {
+ return (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | ((b[3] & 0xff) << 24);
+ }
+
+ public static void sleep(int sec) {
+ try {
+ Thread.sleep(sec * 1000);
+ }
+ catch (InterruptedException e) {
+ }
+ }
+
+ public static byte[] clone(byte in[]) {
+ byte out[] = new byte[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static float[] clone(float in[]) {
+ float out[] = new float[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static short[] clone(short in[]) {
+ short out[] = new short[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static long[] clone(long in[]) {
+ long out[] = new long[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static boolean[] clone(boolean in[]) {
+ boolean out[] = new boolean[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static int[] clone(int in[]) {
+ int out[] = new int[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ public static double[] clone(double in[]) {
+ double out[] = new double[in.length];
+
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+
+ // this works with Strings also.
+ public static String[] clone(String in[]) {
+ String out[] = new String[in.length];
+ if (in.length != 0)
+ System.arraycopy(in, 0, out, 0, in.length);
+
+ return out;
+ }
+}
diff --git a/src/jake2/util/Math3D.java b/src/jake2/util/Math3D.java
new file mode 100644
index 0000000..117487c
--- /dev/null
+++ b/src/jake2/util/Math3D.java
@@ -0,0 +1,564 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+// Created on 09.12.2003 by RST.
+// $Id: Math3D.java,v 1.1 2004-07-07 19:59:53 hzi Exp $
+
+package jake2.util;
+
+import jake2.Defines;
+import jake2.game.cplane_t;
+import jake2.qcommon.Com;
+
+public class Math3D extends Lib {
+
+ public static void set(float v1[], float v2[])
+ {
+ for (int i=0; i < v1.length; i++)
+ v1[i]=v2[i];
+ }
+
+
+ public static void VectorSubtract(float[] a, float[] b, float[] c) {
+ c[0] = a[0] - b[0];
+ c[1] = a[1] - b[1];
+ c[2] = a[2] - b[2];
+ }
+
+ public static void VectorSubtract(short[] a, short[] b, int[] c) {
+ c[0] = a[0] - b[0];
+ c[1] = a[1] - b[1];
+ c[2] = a[2] - b[2];
+ }
+
+ public static void VectorAdd(float[] a, float[] b, float[] to) {
+ to[0] = a[0] + b[0];
+ to[1] = a[1] + b[1];
+ to[2] = a[2] + b[2];
+ }
+
+ public static void VectorCopy(float[] from, float[] to) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ }
+
+ public static void VectorCopy(short[] from, short[] to) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ }
+
+ public static void VectorCopy(short[] from, float[] to) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ }
+
+ public static void VectorCopy(float[] from, short[] to) {
+ to[0] = (short) from[0];
+ to[1] = (short) from[1];
+ to[2] = (short) from[2];
+ }
+
+ public static void VectorClear(float[] a) {
+ a[0] = a[1] = a[2] = 0;
+ }
+ public static int VectorCompare(float[] v1, float[] v2) {
+ if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2])
+ return 0;
+
+ return 1;
+ }
+ public static void VectorNegate(float[] from, float[] to) {
+ to[0] = -from[0];
+ to[1] = -from[1];
+ to[2] = -from[2];
+ }
+ public static void VectorSet(float[] v, float x, float y, float z) {
+ v[0] = (x);
+ v[1] = (y);
+ v[2] = (z);
+ }
+ public static void VectorMA(float[] veca, float scale, float[] vecb, float[] to) {
+ to[0] = veca[0] + scale * vecb[0];
+ to[1] = veca[1] + scale * vecb[1];
+ to[2] = veca[2] + scale * vecb[2];
+ }
+ public static final float VectorNormalize(float[] v) {
+ float length, ilength;
+
+ length = VectorLength(v);
+ if (length != 0.0f) {
+ ilength = 1.0f / length;
+ v[0] *= ilength;
+ v[1] *= ilength;
+ v[2] *= ilength;
+ }
+ return length;
+ }
+ public static final float VectorNormalize2(float[] v, float[] to) {
+ float length, ilength;
+
+ length = VectorLength(v);
+ if (length != 0.0f) {
+ ilength = 1.0f / length;
+ to[0] = v[0] * length;
+ to[1] = v[1] * length;
+ to[2] = v[2] * length;
+ }
+ return length;
+ }
+ public static final float VectorLength(float v[]) {
+ return (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ }
+ public static void VectorInverse(float[] v) {
+ v[0] = -v[0];
+ v[1] = -v[1];
+ v[2] = -v[2];
+ }
+ public static void VectorScale(float[] in, float scale, float[] out) {
+ out[0] = in[0] * scale;
+ out[1] = in[1] * scale;
+ out[2] = in[2] * scale;
+ }
+
+ public static float vectoyaw(float[] vec) {
+ float yaw;
+
+ if (/*vec[YAW] == 0 &&*/
+ vec[Defines.PITCH] == 0) {
+ yaw = 0;
+ if (vec[Defines.YAW] > 0)
+ yaw = 90;
+ else if (vec[Defines.YAW] < 0)
+ yaw = -90;
+ }
+ else {
+
+ yaw = (int) (Math.atan2(vec[Defines.YAW], vec[Defines.PITCH]) * 180 / Math.PI);
+ if (yaw < 0)
+ yaw += 360;
+ }
+
+ return yaw;
+ }
+
+ public static void vectoangles(float[] value1, float[] angles) {
+ float forward;
+ float yaw, pitch;
+
+ if (value1[1] == 0 && value1[0] == 0) {
+ yaw = 0;
+ if (value1[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ }
+ else {
+ if (value1[0] != 0)
+ yaw = (int) (Math.atan2(value1[1], value1[0]) * 180 / Math.PI);
+ else if (value1[1] > 0)
+ yaw = 90;
+ else
+ yaw = -90;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = (float) Math.sqrt(value1[0] * value1[0] + value1[1] * value1[1]);
+ pitch = (int) (Math.atan2(value1[2], forward) * 180 / Math.PI);
+ if (pitch < 0)
+ pitch += 360;
+ }
+
+ angles[Defines.PITCH] = -pitch;
+ angles[Defines.YAW] = yaw;
+ angles[Defines.ROLL] = 0;
+ }
+
+ public static void RotatePointAroundVector(float[] dst, float[] dir, float[] point, float degrees) {
+ float m[][] = new float[3][3];
+ float im[][] = new float[3][3];
+ float zrot[][] = new float[3][3];
+ float tmpmat[][] = new float[3][3];
+ float rot[][] = new float[3][3];
+ int i;
+ float[] vr = { 0.0f, 0.0f, 0.0f };
+ float[] vup = { 0.0f, 0.0f, 0.0f };
+ float[] vf = { 0.0f, 0.0f, 0.0f };
+
+ vf[0] = dir[0];
+ vf[1] = dir[1];
+ vf[2] = dir[2];
+
+ Math3D.PerpendicularVector(vr, dir);
+ Math3D.CrossProduct(vr, vf, vup);
+
+ m[0][0] = vr[0];
+ m[1][0] = vr[1];
+ m[2][0] = vr[2];
+
+ m[0][1] = vup[0];
+ m[1][1] = vup[1];
+ m[2][1] = vup[2];
+
+ m[0][2] = vf[0];
+ m[1][2] = vf[1];
+ m[2][2] = vf[2];
+
+ Math3D.MatCopy(m, im); // achtung: src -> dst
+
+ im[0][1] = m[1][0];
+ im[0][2] = m[2][0];
+ im[1][0] = m[0][1];
+ im[1][2] = m[2][1];
+ im[2][0] = m[0][2];
+ im[2][1] = m[1][2];
+
+ Math3D.MatClear(zrot);
+
+ zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
+
+ zrot[0][0] = (float) Math.cos(Math3D.DEG2RAD(degrees));
+ zrot[0][1] = (float) Math.sin(Math3D.DEG2RAD(degrees));
+ zrot[1][0] = - (float) Math.sin(Math3D.DEG2RAD(degrees));
+ zrot[1][1] = (float) Math.cos(Math3D.DEG2RAD(degrees));
+
+ Math3D.R_ConcatRotations(m, zrot, tmpmat);
+ Math3D.R_ConcatRotations(tmpmat, im, rot);
+
+ for (i = 0; i < 3; i++) {
+ dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
+ }
+ }
+
+
+ public static void MakeNormalVectors(float[] forward, float[] right, float[] up) {
+ // this rotate and negat guarantees a vector
+ // not colinear with the original
+ right[1] = -forward[0];
+ right[2] = forward[1];
+ right[0] = forward[2];
+
+ float d = DotProduct(right, forward);
+ VectorMA(right, -d, forward, right);
+ VectorNormalize(right);
+ CrossProduct(right, forward, up);
+ }
+
+
+ public static float SHORT2ANGLE(int x) {
+ return ((x) * (360.0f / 65536));
+ }
+
+ /*
+ ================
+ R_ConcatTransforms
+ ================
+ */
+ public static void R_ConcatTransforms(float in1[][], float in2[][], float out[][]) {
+ out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
+ out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
+ out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
+ out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3];
+ out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];
+ out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];
+ out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];
+ out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3];
+ out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];
+ out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
+ out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
+ out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];
+ }
+
+ /**
+ * concatenates 2 matrices each [3][3].
+ */
+ public static void R_ConcatRotations(float in1[][], float in2[][], float out[][]) {
+ out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
+ out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
+ out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
+ out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];
+ out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];
+ out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];
+ out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];
+ out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
+ out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
+ }
+
+ public static void ProjectPointOnPlane(float[] dst, float[] p, float[] normal) {
+ float d;
+ float[] n = { 0.0f, 0.0f, 0.0f };
+ float inv_denom;
+
+ inv_denom = 1.0F / Math3D.DotProduct(normal, normal);
+
+ d = Math3D.DotProduct(normal, p) * inv_denom;
+
+ n[0] = normal[0] * inv_denom;
+ n[1] = normal[1] * inv_denom;
+ n[2] = normal[2] * inv_denom;
+
+ dst[0] = p[0] - d * n[0];
+ dst[1] = p[1] - d * n[1];
+ dst[2] = p[2] - d * n[2];
+ }
+
+ /** assumes "src" is normalized */
+ public static void PerpendicularVector(float[] dst, float[] src) {
+ int pos;
+ int i;
+ float minelem = 1.0F;
+ float tempvec[] = { 0.0f, 0.0f, 0.0f };
+
+ // find the smallest magnitude axially aligned vector
+ for (pos = 0, i = 0; i < 3; i++) {
+ if (Math.abs(src[i]) < minelem) {
+ pos = i;
+ minelem = Math.abs(src[i]);
+ }
+ }
+ tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
+ tempvec[pos] = 1.0F;
+
+ // project the point onto the plane defined by src
+ ProjectPointOnPlane(dst, tempvec, src);
+
+ //normalize the result
+ Math3D.VectorNormalize(dst);
+ }
+
+ //=====================================================================
+ /**
+ stellt fest, auf welcher Seite sich die Kiste befindet, wenn die Ebene
+ durch Entfernung und Senkrechten-Normale gegeben ist.
+ erste Version mit vec3_t... */
+
+ public static final int BoxOnPlaneSide(float emins[], float emaxs[], cplane_t p) {
+
+ assert (emins.length == 3 && emaxs.length == 3) : "vec3_t bug";
+
+ float dist1, dist2;
+ int sides;
+
+ // fast axial cases
+ if (p.type < 3) {
+ if (p.dist <= emins[p.type])
+ return 1;
+ if (p.dist >= emaxs[p.type])
+ return 2;
+ return 3;
+ }
+
+ // general case
+ switch (p.signbits) {
+ case 0 :
+ dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2];
+ dist2 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2];
+ break;
+ case 1 :
+ dist1 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2];
+ dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2];
+ break;
+ case 2 :
+ dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2];
+ dist2 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2];
+ break;
+ case 3 :
+ dist1 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2];
+ dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2];
+ break;
+ case 4 :
+ dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2];
+ dist2 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2];
+ break;
+ case 5 :
+ dist1 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2];
+ dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2];
+ break;
+ case 6 :
+ dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2];
+ dist2 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2];
+ break;
+ case 7 :
+ dist1 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2];
+ dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2];
+ break;
+ default :
+ dist1 = dist2 = 0;
+ assert (false) : "BoxOnPlaneSide bug";
+ break;
+ }
+
+ sides = 0;
+ if (dist1 >= p.dist)
+ sides = 1;
+ if (dist2 < p.dist)
+ sides |= 2;
+
+ assert (sides != 0) : "BoxOnPlaneSide(): sides == 0 bug";
+
+ return sides;
+ }
+
+ // this is the slow, general version
+ public static final int BoxOnPlaneSide2(float[] emins, float[] emaxs, cplane_t p) {
+ int i;
+ float dist1, dist2;
+ int sides;
+ float corners[][] = new float[2][3];
+
+ for (i = 0; i < 3; i++) {
+ if (p.normal[i] < 0) {
+ corners[0][i] = emins[i];
+ corners[1][i] = emaxs[i];
+ }
+ else {
+ corners[1][i] = emins[i];
+ corners[0][i] = emaxs[i];
+ }
+ }
+ dist1 = Math3D.DotProduct(p.normal, corners[0]) - p.dist;
+ dist2 = Math3D.DotProduct(p.normal, corners[1]) - p.dist;
+ sides = 0;
+ if (dist1 >= 0)
+ sides = 1;
+ if (dist2 < 0)
+ sides |= 2;
+
+ return sides;
+ }
+
+ public static void AngleVectors(float[] angles, float[] forward, float[] right, float[] up) {
+ float angle;
+ float sr, sp, sy, cr, cp, cy;
+
+ angle = (float) (angles[Defines.YAW] * (Math.PI * 2 / 360));
+ sy = (float) Math.sin(angle);
+ cy = (float) Math.cos(angle);
+ angle = (float) (angles[Defines.PITCH] * (Math.PI * 2 / 360));
+ sp = (float) Math.sin(angle);
+ cp = (float) Math.cos(angle);
+ angle = (float) (angles[Defines.ROLL] * (Math.PI * 2 / 360));
+ sr = (float) Math.sin(angle);
+ cr = (float) Math.cos(angle);
+
+ if (forward != null) {
+ forward[0] = cp * cy;
+ forward[1] = cp * sy;
+ forward[2] = -sp;
+ }
+ if (right != null) {
+ right[0] = (-1 * sr * sp * cy + -1 * cr * -sy);
+ right[1] = (-1 * sr * sp * sy + -1 * cr * cy);
+ right[2] = -1 * sr * cp;
+ }
+ if (up != null) {
+ up[0] = (cr * sp * cy + -sr * -sy);
+ up[1] = (cr * sp * sy + -sr * cy);
+ up[2] = cr * cp;
+ }
+ }
+
+ public static void MatClear(float m[][]) {
+ m[0][0] = m[0][1] = m[0][2] = m[1][0] = m[1][1] = m[1][2] = m[2][0] = m[2][1] = m[2][2] = 0.0f;
+ }
+
+ public static final void MatCopy(float src[][], float dst[][]) {
+ for (int i = 0; i < 3; i++)
+ {
+ VectorCopy(src[i], dst[i]);
+ }
+ }
+
+ public static void G_ProjectSource(float[] point, float[] distance, float[] forward, float[] right, float[] result) {
+ result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
+ result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
+ result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
+ }
+
+
+
+ public static float DotProduct(float[] x, float[] y) {
+ return x[0] * y[0] + x[1] * y[1] + x[2] * y[2];
+ }
+
+
+
+ public static void CrossProduct(float[] v1, float[] v2, float[] cross) {
+ cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
+ }
+
+
+
+ public static int Q_log2(int val) {
+ int answer = 0;
+ while ((val >>= 1) > 0)
+ answer++;
+ return answer;
+ }
+
+
+
+ public static float DEG2RAD(float in) {
+ return (in * (float) Math.PI) / 180.0f;
+ }
+
+
+
+ public static float anglemod(float a) {
+ return (float) (360.0f / 65536) * ((int) (a * (65536 / 360.0f)) & 65535);
+ }
+
+
+
+ public static int ANGLE2SHORT(float x) {
+ return ((int) ((x) * 65536f / 360f) & 65535);
+ }
+
+
+
+ public static float LerpAngle(float a2, float a1, float frac) {
+ if (a1 - a2 > 180)
+ a1 -= 360;
+ if (a1 - a2 < -180)
+ a1 += 360;
+ return a2 + frac * (a1 - a2);
+ }
+
+
+ public static float CalcFov(float fov_x, float width, float height) {
+ double a = 0.0f;
+ double x;
+
+ if (fov_x < 1.0f || fov_x > 179.0f)
+ Com.Error(Defines.ERR_DROP, "Bad fov: " + fov_x);
+
+ x = width / Math.tan(fov_x / 360.0 * Math.PI);
+
+ a = Math.atan(height / x);
+
+ a = a * 360 / Math.PI;
+
+ return (float)a;
+ }
+}
diff --git a/src/jake2/util/PrintfFormat.java b/src/jake2/util/PrintfFormat.java
new file mode 100644
index 0000000..3414239
--- /dev/null
+++ b/src/jake2/util/PrintfFormat.java
@@ -0,0 +1,3215 @@
+
+//
+// (c) 2000 Sun Microsystems, Inc.
+// ALL RIGHTS RESERVED
+//
+// License Grant-
+//
+//
+// Permission to use, copy, modify, and distribute this Software and its
+// documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
+// hereby granted.
+//
+// This Software is provided "AS IS". All express warranties, including any
+// implied warranty of merchantability, satisfactory quality, fitness for a
+// particular purpose, or non-infringement, are disclaimed, except to the extent
+// that such disclaimers are held to be legally invalid.
+//
+// You acknowledge that Software is not designed, licensed or intended for use in
+// the design, construction, operation or maintenance of any nuclear facility
+// ("High Risk Activities"). Sun disclaims any express or implied warranty of
+// fitness for such uses.
+//
+// Please refer to the file http://www.sun.com/policies/trademarks/ for further
+// important trademark information and to
+// http://java.sun.com/nav/business/index.html for further important licensing
+// information for the Java Technology.
+//
+package jake2.util;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.Locale;
+import java.text.DecimalFormatSymbols;
+
+/**
+ * PrintfFormat allows the formatting of an array of
+ * objects embedded within a string. Primitive types
+ * must be passed using wrapper types. The formatting
+ * is controlled by a control string.
+ *<p>
+ * A control string is a Java string that contains a
+ * control specification. The control specification
+ * starts at the first percent sign (%) in the string,
+ * provided that this percent sign
+ *<ol>
+ *<li>is not escaped protected by a matching % or is
+ * not an escape % character,
+ *<li>is not at the end of the format string, and
+ *<li>precedes a sequence of characters that parses as
+ * a valid control specification.
+ *</ol>
+ *</p><p>
+ * A control specification usually takes the form:
+ *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
+ * { [hlL] }+ [idfgGoxXeEcs]
+ *</pre>
+ * There are variants of this basic form that are
+ * discussed below.</p>
+ *<p>
+ * The format is composed of zero or more directives
+ * defined as follows:
+ *<ul>
+ *<li>ordinary characters, which are simply copied to
+ * the output stream;
+ *<li>escape sequences, which represent non-graphic
+ * characters; and
+ *<li>conversion specifications, each of which
+ * results in the fetching of zero or more arguments.
+ *</ul></p>
+ *<p>
+ * The results are undefined if there are insufficient
+ * arguments for the format. Usually an unchecked
+ * exception will be thrown. If the format is
+ * exhausted while arguments remain, the excess
+ * arguments are evaluated but are otherwise ignored.
+ * In format strings containing the % form of
+ * conversion specifications, each argument in the
+ * argument list is used exactly once.</p>
+ * <p>
+ * Conversions can be applied to the <code>n</code>th
+ * argument after the format in the argument list,
+ * rather than to the next unused argument. In this
+ * case, the conversion characer % is replaced by the
+ * sequence %<code>n</code>$, where <code>n</code> is
+ * a decimal integer giving the position of the
+ * argument in the argument list.</p>
+ * <p>
+ * In format strings containing the %<code>n</code>$
+ * form of conversion specifications, each argument
+ * in the argument list is used exactly once.</p>
+ *
+ *<h4>Escape Sequences</h4>
+ *<p>
+ * The following table lists escape sequences and
+ * associated actions on display devices capable of
+ * the action.
+ *<table>
+ *<tr><th align=left>Sequence</th>
+ * <th align=left>Name</th>
+ * <th align=left>Description</th></tr>
+ *<tr><td>\\</td><td>backlash</td><td>None.
+ *</td></tr>
+ *<tr><td>\a</td><td>alert</td><td>Attempts to alert
+ * the user through audible or visible
+ * notification.
+ *</td></tr>
+ *<tr><td>\b</td><td>backspace</td><td>Moves the
+ * printing position to one column before
+ * the current position, unless the
+ * current position is the start of a line.
+ *</td></tr>
+ *<tr><td>\f</td><td>form-feed</td><td>Moves the
+ * printing position to the initial
+ * printing position of the next logical
+ * page.
+ *</td></tr>
+ *<tr><td>\n</td><td>newline</td><td>Moves the
+ * printing position to the start of the
+ * next line.
+ *</td></tr>
+ *<tr><td>\r</td><td>carriage-return</td><td>Moves
+ * the printing position to the start of
+ * the current line.
+ *</td></tr>
+ *<tr><td>\t</td><td>tab</td><td>Moves the printing
+ * position to the next implementation-
+ * defined horizontal tab position.
+ *</td></tr>
+ *<tr><td>\v</td><td>vertical-tab</td><td>Moves the
+ * printing position to the start of the
+ * next implementation-defined vertical
+ * tab position.
+ *</td></tr>
+ *</table></p>
+ *<h4>Conversion Specifications</h4>
+ *<p>
+ * Each conversion specification is introduced by
+ * the percent sign character (%). After the character
+ * %, the following appear in sequence:</p>
+ *<p>
+ * Zero or more flags (in any order), which modify the
+ * meaning of the conversion specification.</p>
+ *<p>
+ * An optional minimum field width. If the converted
+ * value has fewer characters than the field width, it
+ * will be padded with spaces by default on the left;
+ * t will be padded on the right, if the left-
+ * adjustment flag (-), described below, is given to
+ * the field width. The field width takes the form
+ * of a decimal integer. If the conversion character
+ * is s, the field width is the the minimum number of
+ * characters to be printed.</p>
+ *<p>
+ * An optional precision that gives the minumum number
+ * of digits to appear for the d, i, o, x or X
+ * conversions (the field is padded with leading
+ * zeros); the number of digits to appear after the
+ * radix character for the e, E, and f conversions,
+ * the maximum number of significant digits for the g
+ * and G conversions; or the maximum number of
+ * characters to be written from a string is s and S
+ * conversions. The precision takes the form of an
+ * optional decimal digit string, where a null digit
+ * string is treated as 0. If a precision appears
+ * with a c conversion character the precision is
+ * ignored.
+ * </p>
+ *<p>
+ * An optional h specifies that a following d, i, o,
+ * x, or X conversion character applies to a type
+ * short argument (the argument will be promoted
+ * according to the integral promotions and its value
+ * converted to type short before printing).</p>
+ *<p>
+ * An optional l (ell) specifies that a following
+ * d, i, o, x, or X conversion character applies to a
+ * type long argument.</p>
+ *<p>
+ * A field width or precision may be indicated by an
+ * asterisk (*) instead of a digit string. In this
+ * case, an integer argument supplised the field width
+ * precision. The argument that is actually converted
+ * is not fetched until the conversion letter is seen,
+ * so the the arguments specifying field width or
+ * precision must appear before the argument (if any)
+ * to be converted. If the precision argument is
+ * negative, it will be changed to zero. A negative
+ * field width argument is taken as a - flag, followed
+ * by a positive field width.</p>
+ * <p>
+ * In format strings containing the %<code>n</code>$
+ * form of a conversion specification, a field width
+ * or precision may be indicated by the sequence
+ * *<code>m</code>$, where m is a decimal integer
+ * giving the position in the argument list (after the
+ * format argument) of an integer argument containing
+ * the field width or precision.</p>
+ * <p>
+ * The format can contain either numbered argument
+ * specifications (that is, %<code>n</code>$ and
+ * *<code>m</code>$), or unnumbered argument
+ * specifications (that is % and *), but normally not
+ * both. The only exception to this is that %% can
+ * be mixed with the %<code>n</code>$ form. The
+ * results of mixing numbered and unnumbered argument
+ * specifications in a format string are undefined.</p>
+ *
+ *<h4>Flag Characters</h4>
+ *<p>
+ * The flags and their meanings are:</p>
+ *<dl>
+ * <dt>'<dd> integer portion of the result of a
+ * decimal conversion (%i, %d, %f, %g, or %G) will
+ * be formatted with thousands' grouping
+ * characters. For other conversions the flag
+ * is ignored. The non-monetary grouping
+ * character is used.
+ * <dt>-<dd> result of the conversion is left-justified
+ * within the field. (It will be right-justified
+ * if this flag is not specified).</td></tr>
+ * <dt>+<dd> result of a signed conversion always
+ * begins with a sign (+ or -). (It will begin
+ * with a sign only when a negative value is
+ * converted if this flag is not specified.)
+ * <dt>&lt;space&gt;<dd> If the first character of a
+ * signed conversion is not a sign, a space
+ * character will be placed before the result.
+ * This means that if the space character and +
+ * flags both appear, the space flag will be
+ * ignored.
+ * <dt>#<dd> value is to be converted to an alternative
+ * form. For c, d, i, and s conversions, the flag
+ * has no effect. For o conversion, it increases
+ * the precision to force the first digit of the
+ * result to be a zero. For x or X conversion, a
+ * non-zero result has 0x or 0X prefixed to it,
+ * respectively. For e, E, f, g, and G
+ * conversions, the result always contains a radix
+ * character, even if no digits follow the radix
+ * character (normally, a decimal point appears in
+ * the result of these conversions only if a digit
+ * follows it). For g and G conversions, trailing
+ * zeros will not be removed from the result as
+ * they normally are.
+ * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
+ * conversions, leading zeros (following any
+ * indication of sign or base) are used to pad to
+ * the field width; no space padding is
+ * performed. If the 0 and - flags both appear,
+ * the 0 flag is ignored. For d, i, o, x, and X
+ * conversions, if a precision is specified, the
+ * 0 flag will be ignored. For c conversions,
+ * the flag is ignored.
+ *</dl>
+ *
+ *<h4>Conversion Characters</h4>
+ *<p>
+ * Each conversion character results in fetching zero
+ * or more arguments. The results are undefined if
+ * there are insufficient arguments for the format.
+ * Usually, an unchecked exception will be thrown.
+ * If the format is exhausted while arguments remain,
+ * the excess arguments are ignored.</p>
+ *
+ *<p>
+ * The conversion characters and their meanings are:
+ *</p>
+ *<dl>
+ * <dt>d,i<dd>The int argument is converted to a
+ * signed decimal in the style [-]dddd. The
+ * precision specifies the minimum number of
+ * digits to appear; if the value being
+ * converted can be represented in fewer
+ * digits, it will be expanded with leading
+ * zeros. The default precision is 1. The
+ * result of converting 0 with an explicit
+ * precision of 0 is no characters.
+ * <dt>o<dd> The int argument is converted to unsigned
+ * octal format in the style ddddd. The
+ * precision specifies the minimum number of
+ * digits to appear; if the value being
+ * converted can be represented in fewer
+ * digits, it will be expanded with leading
+ * zeros. The default precision is 1. The
+ * result of converting 0 with an explicit
+ * precision of 0 is no characters.
+ * <dt>x<dd> The int argument is converted to unsigned
+ * hexadecimal format in the style dddd; the
+ * letters abcdef are used. The precision
+ * specifies the minimum numberof digits to
+ * appear; if the value being converted can be
+ * represented in fewer digits, it will be
+ * expanded with leading zeros. The default
+ * precision is 1. The result of converting 0
+ * with an explicit precision of 0 is no
+ * characters.
+ * <dt>X<dd> Behaves the same as the x conversion
+ * character except that letters ABCDEF are
+ * used instead of abcdef.
+ * <dt>f<dd> The floating point number argument is
+ * written in decimal notation in the style
+ * [-]ddd.ddd, where the number of digits after
+ * the radix character (shown here as a decimal
+ * point) is equal to the precision
+ * specification. A Locale is used to determine
+ * the radix character to use in this format.
+ * If the precision is omitted from the
+ * argument, six digits are written after the
+ * radix character; if the precision is
+ * explicitly 0 and the # flag is not specified,
+ * no radix character appears. If a radix
+ * character appears, at least 1 digit appears
+ * before it. The value is rounded to the
+ * appropriate number of digits.
+ * <dt>e,E<dd>The floating point number argument is
+ * written in the style [-]d.ddde{+-}dd
+ * (the symbols {+-} indicate either a plus or
+ * minus sign), where there is one digit before
+ * the radix character (shown here as a decimal
+ * point) and the number of digits after it is
+ * equal to the precision. A Locale is used to
+ * determine the radix character to use in this
+ * format. When the precision is missing, six
+ * digits are written after the radix character;
+ * if the precision is 0 and the # flag is not
+ * specified, no radix character appears. The
+ * E conversion will produce a number with E
+ * instead of e introducing the exponent. The
+ * exponent always contains at least two digits.
+ * However, if the value to be written requires
+ * an exponent greater than two digits,
+ * additional exponent digits are written as
+ * necessary. The value is rounded to the
+ * appropriate number of digits.
+ * <dt>g,G<dd>The floating point number argument is
+ * written in style f or e (or in sytle E in the
+ * case of a G conversion character), with the
+ * precision specifying the number of
+ * significant digits. If the precision is
+ * zero, it is taken as one. The style used
+ * depends on the value converted: style e
+ * (or E) will be used only if the exponent
+ * resulting from the conversion is less than
+ * -4 or greater than or equal to the precision.
+ * Trailing zeros are removed from the result.
+ * A radix character appears only if it is
+ * followed by a digit.
+ * <dt>c,C<dd>The integer argument is converted to a
+ * char and the result is written.
+ *
+ * <dt>s,S<dd>The argument is taken to be a string and
+ * bytes from the string are written until the
+ * end of the string or the number of bytes
+ * indicated by the precision specification of
+ * the argument is reached. If the precision
+ * is omitted from the argument, it is taken to
+ * be infinite, so all characters up to the end
+ * of the string are written.
+ * <dt>%<dd>Write a % character; no argument is
+ * converted.
+ *</dl>
+ *<p>
+ * If a conversion specification does not match one of
+ * the above forms, an IllegalArgumentException is
+ * thrown and the instance of PrintfFormat is not
+ * created.</p>
+ *<p>
+ * If a floating point value is the internal
+ * representation for infinity, the output is
+ * [+]Infinity, where Infinity is either Infinity or
+ * Inf, depending on the desired output string length.
+ * Printing of the sign follows the rules described
+ * above.</p>
+ *<p>
+ * If a floating point value is the internal
+ * representation for "not-a-number," the output is
+ * [+]NaN. Printing of the sign follows the rules
+ * described above.</p>
+ *<p>
+ * In no case does a non-existent or small field width
+ * cause truncation of a field; if the result of a
+ * conversion is wider than the field width, the field
+ * is simply expanded to contain the conversion result.
+ *</p>
+ *<p>
+ * The behavior is like printf. One exception is that
+ * the minimum number of exponent digits is 3 instead
+ * of 2 for e and E formats when the optional L is used
+ * before the e, E, g, or G conversion character. The
+ * optional L does not imply conversion to a long long
+ * double. </p>
+ * <p>
+ * The biggest divergence from the C printf
+ * specification is in the use of 16 bit characters.
+ * This allows the handling of characters beyond the
+ * small ASCII character set and allows the utility to
+ * interoperate correctly with the rest of the Java
+ * runtime environment.</p>
+ *<p>
+ * Omissions from the C printf specification are
+ * numerous. All the known omissions are present
+ * because Java never uses bytes to represent
+ * characters and does not have pointers:</p>
+ *<ul>
+ * <li>%c is the same as %C.
+ * <li>%s is the same as %S.
+ * <li>u, p, and n conversion characters.
+ * <li>%ws format.
+ * <li>h modifier applied to an n conversion character.
+ * <li>l (ell) modifier applied to the c, n, or s
+ * conversion characters.
+ * <li>ll (ell ell) modifier to d, i, o, u, x, or X
+ * conversion characters.
+ * <li>ll (ell ell) modifier to an n conversion
+ * character.
+ * <li>c, C, d,i,o,u,x, and X conversion characters
+ * apply to Byte, Character, Short, Integer, Long
+ * types.
+ * <li>f, e, E, g, and G conversion characters apply
+ * to Float and Double types.
+ * <li>s and S conversion characters apply to String
+ * types.
+ * <li>All other reference types can be formatted
+ * using the s or S conversion characters only.
+ *</ul>
+ * <p>
+ * Most of this specification is quoted from the Unix
+ * man page for the sprintf utility.</p>
+ *
+ * @author Allan Jacobs
+ * @version 1
+ * Release 1: Initial release.
+ * Release 2: Asterisk field widths and precisions
+ * %n$ and *m$
+ * Bug fixes
+ * g format fix (2 digits in e form corrupt)
+ * rounding in f format implemented
+ * round up when digit not printed is 5
+ * formatting of -0.0f
+ * round up/down when last digits are 50000...
+ */
+public class PrintfFormat {
+ /**
+ * Constructs an array of control specifications
+ * possibly preceded, separated, or followed by
+ * ordinary strings. Control strings begin with
+ * unpaired percent signs. A pair of successive
+ * percent signs designates a single percent sign in
+ * the format.
+ * @param fmtArg Control string.
+ * @exception IllegalArgumentException if the control
+ * string is null, zero length, or otherwise
+ * malformed.
+ */
+ public PrintfFormat(String fmtArg) throws IllegalArgumentException {
+ this(Locale.getDefault(), fmtArg);
+ }
+ /**
+ * Constructs an array of control specifications
+ * possibly preceded, separated, or followed by
+ * ordinary strings. Control strings begin with
+ * unpaired percent signs. A pair of successive
+ * percent signs designates a single percent sign in
+ * the format.
+ * @param fmtArg Control string.
+ * @exception IllegalArgumentException if the control
+ * string is null, zero length, or otherwise
+ * malformed.
+ */
+ public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException {
+ dfs = new DecimalFormatSymbols(locale);
+ int ePos = 0;
+ ConversionSpecification sFmt = null;
+ String unCS = this.nonControl(fmtArg, 0);
+ if (unCS != null) {
+ sFmt = new ConversionSpecification();
+ sFmt.setLiteral(unCS);
+ vFmt.addElement(sFmt);
+ }
+ while (cPos != -1 && cPos < fmtArg.length()) {
+ for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++) {
+ char c = 0;
+ c = fmtArg.charAt(ePos);
+ if (c == 'i')
+ break;
+ if (c == 'd')
+ break;
+ if (c == 'f')
+ break;
+ if (c == 'g')
+ break;
+ if (c == 'G')
+ break;
+ if (c == 'o')
+ break;
+ if (c == 'x')
+ break;
+ if (c == 'X')
+ break;
+ if (c == 'e')
+ break;
+ if (c == 'E')
+ break;
+ if (c == 'c')
+ break;
+ if (c == 's')
+ break;
+ if (c == '%')
+ break;
+ }
+ ePos = Math.min(ePos + 1, fmtArg.length());
+ sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos));
+ vFmt.addElement(sFmt);
+ unCS = this.nonControl(fmtArg, ePos);
+ if (unCS != null) {
+ sFmt = new ConversionSpecification();
+ sFmt.setLiteral(unCS);
+ vFmt.addElement(sFmt);
+ }
+ }
+ }
+ /**
+ * Return a substring starting at
+ * <code>start</code> and ending at either the end
+ * of the String <code>s</code>, the next unpaired
+ * percent sign, or at the end of the String if the
+ * last character is a percent sign.
+ * @param s Control string.
+ * @param start Position in the string
+ * <code>s</code> to begin looking for the start
+ * of a control string.
+ * @return the substring from the start position
+ * to the beginning of the control string.
+ */
+ private String nonControl(String s, int start) {
+ String ret = "";
+ cPos = s.indexOf("%", start);
+ if (cPos == -1)
+ cPos = s.length();
+ return s.substring(start, cPos);
+ }
+ /**
+ * Format an array of objects. Byte, Short,
+ * Integer, Long, Float, Double, and Character
+ * arguments are treated as wrappers for primitive
+ * types.
+ * @param o The array of objects to format.
+ * @return The formatted String.
+ */
+ public String sprintf(Object[] o) {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ int i = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else {
+ if (cs.isPositionalSpecification()) {
+ i = cs.getArgumentPosition() - 1;
+ if (cs.isPositionalFieldWidth()) {
+ int ifw = cs.getArgumentPositionForFieldWidth() - 1;
+ cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue());
+ }
+ if (cs.isPositionalPrecision()) {
+ int ipr = cs.getArgumentPositionForPrecision() - 1;
+ cs.setPrecisionWithArg(((Integer) o[ipr]).intValue());
+ }
+ } else {
+ if (cs.isVariableFieldWidth()) {
+ cs.setFieldWidthWithArg(((Integer) o[i]).intValue());
+ i++;
+ }
+ if (cs.isVariablePrecision()) {
+ cs.setPrecisionWithArg(((Integer) o[i]).intValue());
+ i++;
+ }
+ }
+ if (o[i] instanceof Byte)
+ sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
+ else if (o[i] instanceof Short)
+ sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
+ else if (o[i] instanceof Integer)
+ sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
+ else if (o[i] instanceof Long)
+ sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
+ else if (o[i] instanceof Float)
+ sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
+ else if (o[i] instanceof Double)
+ sb.append(cs.internalsprintf(((Double) o[i]).doubleValue()));
+ else if (o[i] instanceof Character)
+ sb.append(cs.internalsprintf(((Character) o[i]).charValue()));
+ else if (o[i] instanceof String)
+ sb.append(cs.internalsprintf((String) o[i]));
+ else
+ sb.append(cs.internalsprintf(o[i]));
+ if (!cs.isPositionalSpecification())
+ i++;
+ }
+ }
+ return sb.toString();
+ }
+ /**
+ * Format nothing. Just use the control string.
+ * @return the formatted String.
+ */
+ public String sprintf() {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ }
+ return sb.toString();
+ }
+ /**
+ * Format an int.
+ * @param x The int to format.
+ * @return The formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is f, e, E, g, G, s,
+ * or S.
+ */
+ public String sprintf(int x) throws IllegalArgumentException {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else
+ sb.append(cs.internalsprintf(x));
+ }
+ return sb.toString();
+ }
+ /**
+ * Format an long.
+ * @param x The long to format.
+ * @return The formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is f, e, E, g, G, s,
+ * or S.
+ */
+ public String sprintf(long x) throws IllegalArgumentException {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else
+ sb.append(cs.internalsprintf(x));
+ }
+ return sb.toString();
+ }
+ /**
+ * Format a double.
+ * @param x The double to format.
+ * @return The formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is c, C, s, S,
+ * d, d, x, X, or o.
+ */
+ public String sprintf(double x) throws IllegalArgumentException {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else
+ sb.append(cs.internalsprintf(x));
+ }
+ return sb.toString();
+ }
+ /**
+ * Format a String.
+ * @param x The String to format.
+ * @return The formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is neither s nor S.
+ */
+ public String sprintf(String x) throws IllegalArgumentException {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else
+ sb.append(cs.internalsprintf(x));
+ }
+ return sb.toString();
+ }
+ /**
+ * Format an Object. Convert wrapper types to
+ * their primitive equivalents and call the
+ * appropriate internal formatting method. Convert
+ * Strings using an internal formatting method for
+ * Strings. Otherwise use the default formatter
+ * (use toString).
+ * @param x the Object to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is inappropriate for
+ * formatting an unwrapped value.
+ */
+ public String sprintf(Object x) throws IllegalArgumentException {
+ Enumeration e = vFmt.elements();
+ ConversionSpecification cs = null;
+ char c = 0;
+ StringBuffer sb = new StringBuffer();
+ while (e.hasMoreElements()) {
+ cs = (ConversionSpecification) e.nextElement();
+ c = cs.getConversionCharacter();
+ if (c == '\0')
+ sb.append(cs.getLiteral());
+ else if (c == '%')
+ sb.append("%");
+ else {
+ if (x instanceof Byte)
+ sb.append(cs.internalsprintf(((Byte) x).byteValue()));
+ else if (x instanceof Short)
+ sb.append(cs.internalsprintf(((Short) x).shortValue()));
+ else if (x instanceof Integer)
+ sb.append(cs.internalsprintf(((Integer) x).intValue()));
+ else if (x instanceof Long)
+ sb.append(cs.internalsprintf(((Long) x).longValue()));
+ else if (x instanceof Float)
+ sb.append(cs.internalsprintf(((Float) x).floatValue()));
+ else if (x instanceof Double)
+ sb.append(cs.internalsprintf(((Double) x).doubleValue()));
+ else if (x instanceof Character)
+ sb.append(cs.internalsprintf(((Character) x).charValue()));
+ else if (x instanceof String)
+ sb.append(cs.internalsprintf((String) x));
+ else
+ sb.append(cs.internalsprintf(x));
+ }
+ }
+ return sb.toString();
+ }
+ /**
+ *<p>
+ * ConversionSpecification allows the formatting of
+ * a single primitive or object embedded within a
+ * string. The formatting is controlled by a
+ * format string. Only one Java primitive or
+ * object can be formatted at a time.
+ *<p>
+ * A format string is a Java string that contains
+ * a control string. The control string starts at
+ * the first percent sign (%) in the string,
+ * provided that this percent sign
+ *<ol>
+ *<li>is not escaped protected by a matching % or
+ * is not an escape % character,
+ *<li>is not at the end of the format string, and
+ *<li>precedes a sequence of characters that parses
+ * as a valid control string.
+ *</ol>
+ *<p>
+ * A control string takes the form:
+ *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
+ * { [hlL] }+ [idfgGoxXeEcs]
+ *</pre>
+ *<p>
+ * The behavior is like printf. One (hopefully the
+ * only) exception is that the minimum number of
+ * exponent digits is 3 instead of 2 for e and E
+ * formats when the optional L is used before the
+ * e, E, g, or G conversion character. The
+ * optional L does not imply conversion to a long
+ * long double.
+ */
+ private class ConversionSpecification {
+ /**
+ * Constructor. Used to prepare an instance
+ * to hold a literal, not a control string.
+ */
+ ConversionSpecification() {
+ }
+ /**
+ * Constructor for a conversion specification.
+ * The argument must begin with a % and end
+ * with the conversion character for the
+ * conversion specification.
+ * @param fmtArg String specifying the
+ * conversion specification.
+ * @exception IllegalArgumentException if the
+ * input string is null, zero length, or
+ * otherwise malformed.
+ */
+ ConversionSpecification(String fmtArg) throws IllegalArgumentException {
+ if (fmtArg == null)
+ throw new NullPointerException();
+ if (fmtArg.length() == 0)
+ throw new IllegalArgumentException("Control strings must have positive" + " lengths.");
+ if (fmtArg.charAt(0) == '%') {
+ fmt = fmtArg;
+ pos = 1;
+ setArgPosition();
+ setFlagCharacters();
+ setFieldWidth();
+ setPrecision();
+ setOptionalHL();
+ if (setConversionCharacter()) {
+ if (pos == fmtArg.length()) {
+ if (leadingZeros && leftJustify)
+ leadingZeros = false;
+ if (precisionSet && leadingZeros) {
+ if (conversionCharacter == 'd'
+ || conversionCharacter == 'i'
+ || conversionCharacter == 'o'
+ || conversionCharacter == 'x') {
+ leadingZeros = false;
+ }
+ }
+ } else
+ throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
+ } else
+ throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
+ } else
+ throw new IllegalArgumentException("Control strings must begin with %.");
+ }
+ /**
+ * Set the String for this instance.
+ * @param s the String to store.
+ */
+ void setLiteral(String s) {
+ fmt = s;
+ }
+ /**
+ * Get the String for this instance. Translate
+ * any escape sequences.
+ *
+ * @return s the stored String.
+ */
+ String getLiteral() {
+ StringBuffer sb = new StringBuffer();
+ int i = 0;
+ while (i < fmt.length()) {
+ if (fmt.charAt(i) == '\\') {
+ i++;
+ if (i < fmt.length()) {
+ char c = fmt.charAt(i);
+ switch (c) {
+ case 'a' :
+ sb.append((char) 0x07);
+ break;
+ case 'b' :
+ sb.append('\b');
+ break;
+ case 'f' :
+ sb.append('\f');
+ break;
+ case 'n' :
+ sb.append(System.getProperty("line.separator"));
+ break;
+ case 'r' :
+ sb.append('\r');
+ break;
+ case 't' :
+ sb.append('\t');
+ break;
+ case 'v' :
+ sb.append((char) 0x0b);
+ break;
+ case '\\' :
+ sb.append('\\');
+ break;
+ }
+ i++;
+ } else
+ sb.append('\\');
+ } else
+ i++;
+ }
+ return fmt;
+ }
+ /**
+ * Get the conversion character that tells what
+ * type of control character this instance has.
+ *
+ * @return the conversion character.
+ */
+ char getConversionCharacter() {
+ return conversionCharacter;
+ }
+ /**
+ * Check whether the specifier has a variable
+ * field width that is going to be set by an
+ * argument.
+ * @return <code>true</code> if the conversion
+ * uses an * field width; otherwise
+ * <code>false</code>.
+ */
+ boolean isVariableFieldWidth() {
+ return variableFieldWidth;
+ }
+ /**
+ * Set the field width with an argument. A
+ * negative field width is taken as a - flag
+ * followed by a positive field width.
+ * @param fw the field width.
+ */
+ void setFieldWidthWithArg(int fw) {
+ if (fw < 0)
+ leftJustify = true;
+ fieldWidthSet = true;
+ fieldWidth = Math.abs(fw);
+ }
+ /**
+ * Check whether the specifier has a variable
+ * precision that is going to be set by an
+ * argument.
+ * @return <code>true</code> if the conversion
+ * uses an * precision; otherwise
+ * <code>false</code>.
+ */
+ boolean isVariablePrecision() {
+ return variablePrecision;
+ }
+ /**
+ * Set the precision with an argument. A
+ * negative precision will be changed to zero.
+ * @param pr the precision.
+ */
+ void setPrecisionWithArg(int pr) {
+ precisionSet = true;
+ precision = Math.max(pr, 0);
+ }
+ /**
+ * Format an int argument using this conversion
+ * specification.
+ * @param s the int to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is f, e, E, g, or G.
+ */
+ String internalsprintf(int s) throws IllegalArgumentException {
+ String s2 = "";
+ switch (conversionCharacter) {
+ case 'd' :
+ case 'i' :
+ if (optionalh)
+ s2 = printDFormat((short) s);
+ else if (optionall)
+ s2 = printDFormat((long) s);
+ else
+ s2 = printDFormat(s);
+ break;
+ case 'x' :
+ case 'X' :
+ if (optionalh)
+ s2 = printXFormat((short) s);
+ else if (optionall)
+ s2 = printXFormat((long) s);
+ else
+ s2 = printXFormat(s);
+ break;
+ case 'o' :
+ if (optionalh)
+ s2 = printOFormat((short) s);
+ else if (optionall)
+ s2 = printOFormat((long) s);
+ else
+ s2 = printOFormat(s);
+ break;
+ case 'c' :
+ case 'C' :
+ s2 = printCFormat((char) s);
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "Cannot format a int with a format using a " + conversionCharacter + " conversion character.");
+ }
+ return s2;
+ }
+ /**
+ * Format a long argument using this conversion
+ * specification.
+ * @param s the long to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is f, e, E, g, or G.
+ */
+ String internalsprintf(long s) throws IllegalArgumentException {
+ String s2 = "";
+ switch (conversionCharacter) {
+ case 'd' :
+ case 'i' :
+ if (optionalh)
+ s2 = printDFormat((short) s);
+ else if (optionall)
+ s2 = printDFormat(s);
+ else
+ s2 = printDFormat((int) s);
+ break;
+ case 'x' :
+ case 'X' :
+ if (optionalh)
+ s2 = printXFormat((short) s);
+ else if (optionall)
+ s2 = printXFormat(s);
+ else
+ s2 = printXFormat((int) s);
+ break;
+ case 'o' :
+ if (optionalh)
+ s2 = printOFormat((short) s);
+ else if (optionall)
+ s2 = printOFormat(s);
+ else
+ s2 = printOFormat((int) s);
+ break;
+ case 'c' :
+ case 'C' :
+ s2 = printCFormat((char) s);
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "Cannot format a long with a format using a " + conversionCharacter + " conversion character.");
+ }
+ return s2;
+ }
+ /**
+ * Format a double argument using this conversion
+ * specification.
+ * @param s the double to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is c, C, s, S, i, d,
+ * x, X, or o.
+ */
+ String internalsprintf(double s) throws IllegalArgumentException {
+ String s2 = "";
+ switch (conversionCharacter) {
+ case 'f' :
+ s2 = printFFormat(s);
+ break;
+ case 'E' :
+ case 'e' :
+ s2 = printEFormat(s);
+ break;
+ case 'G' :
+ case 'g' :
+ s2 = printGFormat(s);
+ break;
+ default :
+ throw new IllegalArgumentException(
+ "Cannot " + "format a double with a format using a " + conversionCharacter + " conversion character.");
+ }
+ return s2;
+ }
+ /**
+ * Format a String argument using this conversion
+ * specification.
+ * @param s the String to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is neither s nor S.
+ */
+ String internalsprintf(String s) throws IllegalArgumentException {
+ String s2 = "";
+ if (conversionCharacter == 's' || conversionCharacter == 'S')
+ s2 = printSFormat(s);
+ else
+ throw new IllegalArgumentException(
+ "Cannot " + "format a String with a format using a " + conversionCharacter + " conversion character.");
+ return s2;
+ }
+ /**
+ * Format an Object argument using this conversion
+ * specification.
+ * @param s the Object to format.
+ * @return the formatted String.
+ * @exception IllegalArgumentException if the
+ * conversion character is neither s nor S.
+ */
+ String internalsprintf(Object s) {
+ String s2 = "";
+ if (conversionCharacter == 's' || conversionCharacter == 'S')
+ s2 = printSFormat(s.toString());
+ else
+ throw new IllegalArgumentException(
+ "Cannot format a String with a format using" + " a " + conversionCharacter + " conversion character.");
+ return s2;
+ }
+ /**
+ * For f format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both
+ * a '+' and a ' ' are specified, the blank flag
+ * is ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the number of digits
+ * to appear after the radix character. Padding is
+ * with trailing 0s.
+ */
+ private char[] fFormatDigits(double x) {
+ // int defaultDigits=6;
+ String sx, sxOut;
+ int i, j, k;
+ int n1In, n2In;
+ int expon = 0;
+ boolean minusSign = false;
+ if (x > 0.0)
+ sx = Double.toString(x);
+ else if (x < 0.0) {
+ sx = Double.toString(-x);
+ minusSign = true;
+ } else {
+ sx = Double.toString(x);
+ if (sx.charAt(0) == '-') {
+ minusSign = true;
+ sx = sx.substring(1);
+ }
+ }
+ int ePos = sx.indexOf('E');
+ int rPos = sx.indexOf('.');
+ if (rPos != -1)
+ n1In = rPos;
+ else if (ePos != -1)
+ n1In = ePos;
+ else
+ n1In = sx.length();
+ if (rPos != -1) {
+ if (ePos != -1)
+ n2In = ePos - rPos - 1;
+ else
+ n2In = sx.length() - rPos - 1;
+ } else
+ n2In = 0;
+ if (ePos != -1) {
+ int ie = ePos + 1;
+ expon = 0;
+ if (sx.charAt(ie) == '-') {
+ for (++ie; ie < sx.length(); ie++)
+ if (sx.charAt(ie) != '0')
+ break;
+ if (ie < sx.length())
+ expon = -Integer.parseInt(sx.substring(ie));
+ } else {
+ if (sx.charAt(ie) == '+')
+ ++ie;
+ for (; ie < sx.length(); ie++)
+ if (sx.charAt(ie) != '0')
+ break;
+ if (ie < sx.length())
+ expon = Integer.parseInt(sx.substring(ie));
+ }
+ }
+ int p;
+ if (precisionSet)
+ p = precision;
+ else
+ p = defaultDigits - 1;
+ char[] ca1 = sx.toCharArray();
+ char[] ca2 = new char[n1In + n2In];
+ char[] ca3, ca4, ca5;
+ for (j = 0; j < n1In; j++)
+ ca2[j] = ca1[j];
+ i = j + 1;
+ for (k = 0; k < n2In; j++, i++, k++)
+ ca2[j] = ca1[i];
+ if (n1In + expon <= 0) {
+ ca3 = new char[-expon + n2In];
+ for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
+ ca3[j] = '0';
+ for (i = 0; i < (n1In + n2In); i++, j++)
+ ca3[j] = ca2[i];
+ } else
+ ca3 = ca2;
+ boolean carry = false;
+ if (p < -expon + n2In) {
+ if (expon < 0)
+ i = p;
+ else
+ i = p + n1In;
+ carry = checkForCarry(ca3, i);
+ if (carry)
+ carry = startSymbolicCarry(ca3, i - 1, 0);
+ }
+ if (n1In + expon <= 0) {
+ ca4 = new char[2 + p];
+ if (!carry)
+ ca4[0] = '0';
+ else
+ ca4[0] = '1';
+ if (alternateForm || !precisionSet || precision != 0) {
+ ca4[1] = '.';
+ for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
+ ca4[j] = ca3[i];
+ for (; j < ca4.length; j++)
+ ca4[j] = '0';
+ }
+ } else {
+ if (!carry) {
+ if (alternateForm || !precisionSet || precision != 0)
+ ca4 = new char[n1In + expon + p + 1];
+ else
+ ca4 = new char[n1In + expon];
+ j = 0;
+ } else {
+ if (alternateForm || !precisionSet || precision != 0)
+ ca4 = new char[n1In + expon + p + 2];
+ else
+ ca4 = new char[n1In + expon + 1];
+ ca4[0] = '1';
+ j = 1;
+ }
+ for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
+ ca4[j] = ca3[i];
+ for (; i < n1In + expon; i++, j++)
+ ca4[j] = '0';
+ if (alternateForm || !precisionSet || precision != 0) {
+ ca4[j] = '.';
+ j++;
+ for (k = 0; i < ca3.length && k < p; i++, j++, k++)
+ ca4[j] = ca3[i];
+ for (; j < ca4.length; j++)
+ ca4[j] = '0';
+ }
+ }
+ int nZeros = 0;
+ if (!leftJustify && leadingZeros) {
+ int xThousands = 0;
+ if (thousands) {
+ int xlead = 0;
+ if (ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ')
+ xlead = 1;
+ int xdp = xlead;
+ for (; xdp < ca4.length; xdp++)
+ if (ca4[xdp] == '.')
+ break;
+ xThousands = (xdp - xlead) / 3;
+ }
+ if (fieldWidthSet)
+ nZeros = fieldWidth - ca4.length;
+ if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
+ nZeros--;
+ nZeros -= xThousands;
+ if (nZeros < 0)
+ nZeros = 0;
+ }
+ j = 0;
+ if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) {
+ ca5 = new char[ca4.length + nZeros + 1];
+ j++;
+ } else
+ ca5 = new char[ca4.length + nZeros];
+ if (!minusSign) {
+ if (leadingSign)
+ ca5[0] = '+';
+ if (leadingSpace)
+ ca5[0] = ' ';
+ } else
+ ca5[0] = '-';
+ for (i = 0; i < nZeros; i++, j++)
+ ca5[j] = '0';
+ for (i = 0; i < ca4.length; i++, j++)
+ ca5[j] = ca4[i];
+
+ int lead = 0;
+ if (ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ')
+ lead = 1;
+ int dp = lead;
+ for (; dp < ca5.length; dp++)
+ if (ca5[dp] == '.')
+ break;
+ int nThousands = (dp - lead) / 3;
+ // Localize the decimal point.
+ if (dp < ca5.length)
+ ca5[dp] = dfs.getDecimalSeparator();
+ char[] ca6 = ca5;
+ if (thousands && nThousands > 0) {
+ ca6 = new char[ca5.length + nThousands + lead];
+ ca6[0] = ca5[0];
+ for (i = lead, k = lead; i < dp; i++) {
+ if (i > 0 && (dp - i) % 3 == 0) {
+ // ca6[k]=',';
+ ca6[k] = dfs.getGroupingSeparator();
+ ca6[k + 1] = ca5[i];
+ k += 2;
+ } else {
+ ca6[k] = ca5[i];
+ k++;
+ }
+ }
+ for (; i < ca5.length; i++, k++) {
+ ca6[k] = ca5[i];
+ }
+ }
+ return ca6;
+ }
+ /**
+ * An intermediate routine on the way to creating
+ * an f format String. The method decides whether
+ * the input double value is an infinity,
+ * not-a-number, or a finite double and formats
+ * each type of input appropriately.
+ * @param x the double value to be formatted.
+ * @return the converted double value.
+ */
+ private String fFormatString(double x) {
+ boolean noDigits = false;
+ char[] ca6, ca7;
+ if (Double.isInfinite(x)) {
+ if (x == Double.POSITIVE_INFINITY) {
+ if (leadingSign)
+ ca6 = "+Inf".toCharArray();
+ else if (leadingSpace)
+ ca6 = " Inf".toCharArray();
+ else
+ ca6 = "Inf".toCharArray();
+ } else
+ ca6 = "-Inf".toCharArray();
+ noDigits = true;
+ } else if (Double.isNaN(x)) {
+ if (leadingSign)
+ ca6 = "+NaN".toCharArray();
+ else if (leadingSpace)
+ ca6 = " NaN".toCharArray();
+ else
+ ca6 = "NaN".toCharArray();
+ noDigits = true;
+ } else
+ ca6 = fFormatDigits(x);
+ ca7 = applyFloatPadding(ca6, false);
+ return new String(ca7);
+ }
+ /**
+ * For e format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both a
+ * '+' and a ' ' are specified, the blank flag is
+ * ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear after the radix character.
+ * Padding is with trailing 0s.
+ *
+ * The behavior is like printf. One (hopefully the
+ * only) exception is that the minimum number of
+ * exponent digits is 3 instead of 2 for e and E
+ * formats when the optional L is used before the
+ * e, E, g, or G conversion character. The optional
+ * L does not imply conversion to a long long
+ * double.
+ */
+ private char[] eFormatDigits(double x, char eChar) {
+ char[] ca1, ca2, ca3;
+ // int defaultDigits=6;
+ String sx, sxOut;
+ int i, j, k, p;
+ int n1In, n2In;
+ int expon = 0;
+ int ePos, rPos, eSize;
+ boolean minusSign = false;
+ if (x > 0.0)
+ sx = Double.toString(x);
+ else if (x < 0.0) {
+ sx = Double.toString(-x);
+ minusSign = true;
+ } else {
+ sx = Double.toString(x);
+ if (sx.charAt(0) == '-') {
+ minusSign = true;
+ sx = sx.substring(1);
+ }
+ }
+ ePos = sx.indexOf('E');
+ if (ePos == -1)
+ ePos = sx.indexOf('e');
+ rPos = sx.indexOf('.');
+ if (rPos != -1)
+ n1In = rPos;
+ else if (ePos != -1)
+ n1In = ePos;
+ else
+ n1In = sx.length();
+ if (rPos != -1) {
+ if (ePos != -1)
+ n2In = ePos - rPos - 1;
+ else
+ n2In = sx.length() - rPos - 1;
+ } else
+ n2In = 0;
+ if (ePos != -1) {
+ int ie = ePos + 1;
+ expon = 0;
+ if (sx.charAt(ie) == '-') {
+ for (++ie; ie < sx.length(); ie++)
+ if (sx.charAt(ie) != '0')
+ break;
+ if (ie < sx.length())
+ expon = -Integer.parseInt(sx.substring(ie));
+ } else {
+ if (sx.charAt(ie) == '+')
+ ++ie;
+ for (; ie < sx.length(); ie++)
+ if (sx.charAt(ie) != '0')
+ break;
+ if (ie < sx.length())
+ expon = Integer.parseInt(sx.substring(ie));
+ }
+ }
+ if (rPos != -1)
+ expon += rPos - 1;
+ if (precisionSet)
+ p = precision;
+ else
+ p = defaultDigits - 1;
+ if (rPos != -1 && ePos != -1)
+ ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray();
+ else if (rPos != -1)
+ ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray();
+ else if (ePos != -1)
+ ca1 = sx.substring(0, ePos).toCharArray();
+ else
+ ca1 = sx.toCharArray();
+ boolean carry = false;
+ int i0 = 0;
+ if (ca1[0] != '0')
+ i0 = 0;
+ else
+ for (i0 = 0; i0 < ca1.length; i0++)
+ if (ca1[i0] != '0')
+ break;
+ if (i0 + p < ca1.length - 1) {
+ carry = checkForCarry(ca1, i0 + p + 1);
+ if (carry)
+ carry = startSymbolicCarry(ca1, i0 + p, i0);
+ if (carry) {
+ ca2 = new char[i0 + p + 1];
+ ca2[i0] = '1';
+ for (j = 0; j < i0; j++)
+ ca2[j] = '0';
+ for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
+ ca2[j] = ca1[i];
+ expon++;
+ ca1 = ca2;
+ }
+ }
+ if (Math.abs(expon) < 100 && !optionalL)
+ eSize = 4;
+ else
+ eSize = 5;
+ if (alternateForm || !precisionSet || precision != 0)
+ ca2 = new char[2 + p + eSize];
+ else
+ ca2 = new char[1 + eSize];
+ if (ca1[0] != '0') {
+ ca2[0] = ca1[0];
+ j = 1;
+ } else {
+ for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
+ if (ca1[j] != '0')
+ break;
+ if ((ePos != -1 && j < ePos) || (ePos == -1 && j < ca1.length)) {
+ ca2[0] = ca1[j];
+ expon -= j;
+ j++;
+ } else {
+ ca2[0] = '0';
+ j = 2;
+ }
+ }
+ if (alternateForm || !precisionSet || precision != 0) {
+ ca2[1] = '.';
+ i = 2;
+ } else
+ i = 1;
+ for (k = 0; k < p && j < ca1.length; j++, i++, k++)
+ ca2[i] = ca1[j];
+ for (; i < ca2.length - eSize; i++)
+ ca2[i] = '0';
+ ca2[i++] = eChar;
+ if (expon < 0)
+ ca2[i++] = '-';
+ else
+ ca2[i++] = '+';
+ expon = Math.abs(expon);
+ if (expon >= 100) {
+ switch (expon / 100) {
+ case 1 :
+ ca2[i] = '1';
+ break;
+ case 2 :
+ ca2[i] = '2';
+ break;
+ case 3 :
+ ca2[i] = '3';
+ break;
+ case 4 :
+ ca2[i] = '4';
+ break;
+ case 5 :
+ ca2[i] = '5';
+ break;
+ case 6 :
+ ca2[i] = '6';
+ break;
+ case 7 :
+ ca2[i] = '7';
+ break;
+ case 8 :
+ ca2[i] = '8';
+ break;
+ case 9 :
+ ca2[i] = '9';
+ break;
+ }
+ i++;
+ }
+ switch ((expon % 100) / 10) {
+ case 0 :
+ ca2[i] = '0';
+ break;
+ case 1 :
+ ca2[i] = '1';
+ break;
+ case 2 :
+ ca2[i] = '2';
+ break;
+ case 3 :
+ ca2[i] = '3';
+ break;
+ case 4 :
+ ca2[i] = '4';
+ break;
+ case 5 :
+ ca2[i] = '5';
+ break;
+ case 6 :
+ ca2[i] = '6';
+ break;
+ case 7 :
+ ca2[i] = '7';
+ break;
+ case 8 :
+ ca2[i] = '8';
+ break;
+ case 9 :
+ ca2[i] = '9';
+ break;
+ }
+ i++;
+ switch (expon % 10) {
+ case 0 :
+ ca2[i] = '0';
+ break;
+ case 1 :
+ ca2[i] = '1';
+ break;
+ case 2 :
+ ca2[i] = '2';
+ break;
+ case 3 :
+ ca2[i] = '3';
+ break;
+ case 4 :
+ ca2[i] = '4';
+ break;
+ case 5 :
+ ca2[i] = '5';
+ break;
+ case 6 :
+ ca2[i] = '6';
+ break;
+ case 7 :
+ ca2[i] = '7';
+ break;
+ case 8 :
+ ca2[i] = '8';
+ break;
+ case 9 :
+ ca2[i] = '9';
+ break;
+ }
+ int nZeros = 0;
+ if (!leftJustify && leadingZeros) {
+ int xThousands = 0;
+ if (thousands) {
+ int xlead = 0;
+ if (ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ')
+ xlead = 1;
+ int xdp = xlead;
+ for (; xdp < ca2.length; xdp++)
+ if (ca2[xdp] == '.')
+ break;
+ xThousands = (xdp - xlead) / 3;
+ }
+ if (fieldWidthSet)
+ nZeros = fieldWidth - ca2.length;
+ if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
+ nZeros--;
+ nZeros -= xThousands;
+ if (nZeros < 0)
+ nZeros = 0;
+ }
+ j = 0;
+ if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) {
+ ca3 = new char[ca2.length + nZeros + 1];
+ j++;
+ } else
+ ca3 = new char[ca2.length + nZeros];
+ if (!minusSign) {
+ if (leadingSign)
+ ca3[0] = '+';
+ if (leadingSpace)
+ ca3[0] = ' ';
+ } else
+ ca3[0] = '-';
+ for (k = 0; k < nZeros; j++, k++)
+ ca3[j] = '0';
+ for (i = 0; i < ca2.length && j < ca3.length; i++, j++)
+ ca3[j] = ca2[i];
+
+ int lead = 0;
+ if (ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ')
+ lead = 1;
+ int dp = lead;
+ for (; dp < ca3.length; dp++)
+ if (ca3[dp] == '.')
+ break;
+ int nThousands = dp / 3;
+ // Localize the decimal point.
+ if (dp < ca3.length)
+ ca3[dp] = dfs.getDecimalSeparator();
+ char[] ca4 = ca3;
+ if (thousands && nThousands > 0) {
+ ca4 = new char[ca3.length + nThousands + lead];
+ ca4[0] = ca3[0];
+ for (i = lead, k = lead; i < dp; i++) {
+ if (i > 0 && (dp - i) % 3 == 0) {
+ // ca4[k]=',';
+ ca4[k] = dfs.getGroupingSeparator();
+ ca4[k + 1] = ca3[i];
+ k += 2;
+ } else {
+ ca4[k] = ca3[i];
+ k++;
+ }
+ }
+ for (; i < ca3.length; i++, k++)
+ ca4[k] = ca3[i];
+ }
+ return ca4;
+ }
+ /**
+ * Check to see if the digits that are going to
+ * be truncated because of the precision should
+ * force a round in the preceding digits.
+ * @param ca1 the array of digits
+ * @param icarry the index of the first digit that
+ * is to be truncated from the print
+ * @return <code>true</code> if the truncation forces
+ * a round that will change the print
+ */
+ private boolean checkForCarry(char[] ca1, int icarry) {
+ boolean carry = false;
+ if (icarry < ca1.length) {
+ if (ca1[icarry] == '6' || ca1[icarry] == '7' || ca1[icarry] == '8' || ca1[icarry] == '9')
+ carry = true;
+ else if (ca1[icarry] == '5') {
+ int ii = icarry + 1;
+ for (; ii < ca1.length; ii++)
+ if (ca1[ii] != '0')
+ break;
+ carry = ii < ca1.length;
+ if (!carry && icarry > 0) {
+ carry =
+ (ca1[icarry - 1] == '1'
+ || ca1[icarry - 1] == '3'
+ || ca1[icarry - 1] == '5'
+ || ca1[icarry - 1] == '7'
+ || ca1[icarry - 1] == '9');
+ }
+ }
+ }
+ return carry;
+ }
+ /**
+ * Start the symbolic carry process. The process
+ * is not quite finished because the symbolic
+ * carry may change the length of the string and
+ * change the exponent (in e format).
+ * @param cLast index of the last digit changed
+ * by the round
+ * @param cFirst index of the first digit allowed
+ * to be changed by this phase of the round
+ * @return <code>true</code> if the carry forces
+ * a round that will change the print still
+ * more
+ */
+ private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) {
+ boolean carry = true;
+ for (int i = cLast; carry && i >= cFirst; i--) {
+ carry = false;
+ switch (ca[i]) {
+ case '0' :
+ ca[i] = '1';
+ break;
+ case '1' :
+ ca[i] = '2';
+ break;
+ case '2' :
+ ca[i] = '3';
+ break;
+ case '3' :
+ ca[i] = '4';
+ break;
+ case '4' :
+ ca[i] = '5';
+ break;
+ case '5' :
+ ca[i] = '6';
+ break;
+ case '6' :
+ ca[i] = '7';
+ break;
+ case '7' :
+ ca[i] = '8';
+ break;
+ case '8' :
+ ca[i] = '9';
+ break;
+ case '9' :
+ ca[i] = '0';
+ carry = true;
+ break;
+ }
+ }
+ return carry;
+ }
+ /**
+ * An intermediate routine on the way to creating
+ * an e format String. The method decides whether
+ * the input double value is an infinity,
+ * not-a-number, or a finite double and formats
+ * each type of input appropriately.
+ * @param x the double value to be formatted.
+ * @param eChar an 'e' or 'E' to use in the
+ * converted double value.
+ * @return the converted double value.
+ */
+ private String eFormatString(double x, char eChar) {
+ boolean noDigits = false;
+ char[] ca4, ca5;
+ if (Double.isInfinite(x)) {
+ if (x == Double.POSITIVE_INFINITY) {
+ if (leadingSign)
+ ca4 = "+Inf".toCharArray();
+ else if (leadingSpace)
+ ca4 = " Inf".toCharArray();
+ else
+ ca4 = "Inf".toCharArray();
+ } else
+ ca4 = "-Inf".toCharArray();
+ noDigits = true;
+ } else if (Double.isNaN(x)) {
+ if (leadingSign)
+ ca4 = "+NaN".toCharArray();
+ else if (leadingSpace)
+ ca4 = " NaN".toCharArray();
+ else
+ ca4 = "NaN".toCharArray();
+ noDigits = true;
+ } else
+ ca4 = eFormatDigits(x, eChar);
+ ca5 = applyFloatPadding(ca4, false);
+ return new String(ca5);
+ }
+ /**
+ * Apply zero or blank, left or right padding.
+ * @param ca4 array of characters before padding is
+ * finished
+ * @param noDigits NaN or signed Inf
+ * @return a padded array of characters
+ */
+ private char[] applyFloatPadding(char[] ca4, boolean noDigits) {
+ char[] ca5 = ca4;
+ if (fieldWidthSet) {
+ int i, j, nBlanks;
+ if (leftJustify) {
+ nBlanks = fieldWidth - ca4.length;
+ if (nBlanks > 0) {
+ ca5 = new char[ca4.length + nBlanks];
+ for (i = 0; i < ca4.length; i++)
+ ca5[i] = ca4[i];
+ for (j = 0; j < nBlanks; j++, i++)
+ ca5[i] = ' ';
+ }
+ } else if (!leadingZeros || noDigits) {
+ nBlanks = fieldWidth - ca4.length;
+ if (nBlanks > 0) {
+ ca5 = new char[ca4.length + nBlanks];
+ for (i = 0; i < nBlanks; i++)
+ ca5[i] = ' ';
+ for (j = 0; j < ca4.length; i++, j++)
+ ca5[i] = ca4[j];
+ }
+ } else if (leadingZeros) {
+ nBlanks = fieldWidth - ca4.length;
+ if (nBlanks > 0) {
+ ca5 = new char[ca4.length + nBlanks];
+ i = 0;
+ j = 0;
+ if (ca4[0] == '-') {
+ ca5[0] = '-';
+ i++;
+ j++;
+ }
+ for (int k = 0; k < nBlanks; i++, k++)
+ ca5[i] = '0';
+ for (; j < ca4.length; i++, j++)
+ ca5[i] = ca4[j];
+ }
+ }
+ }
+ return ca5;
+ }
+ /**
+ * Format method for the f conversion character.
+ * @param x the double to format.
+ * @return the formatted String.
+ */
+ private String printFFormat(double x) {
+ return fFormatString(x);
+ }
+ /**
+ * Format method for the e or E conversion
+ * character.
+ * @param x the double to format.
+ * @return the formatted String.
+ */
+ private String printEFormat(double x) {
+ if (conversionCharacter == 'e')
+ return eFormatString(x, 'e');
+ else
+ return eFormatString(x, 'E');
+ }
+ /**
+ * Format method for the g conversion character.
+ *
+ * For g format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both a
+ * '+' and a ' ' are specified, the blank flag is
+ * ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear after the radix character.
+ * Padding is with trailing 0s.
+ * @param x the double to format.
+ * @return the formatted String.
+ */
+ private String printGFormat(double x) {
+ String sx, sy, sz, ret;
+ int savePrecision = precision;
+ int i;
+ char[] ca4, ca5;
+ boolean noDigits = false;
+ if (Double.isInfinite(x)) {
+ if (x == Double.POSITIVE_INFINITY) {
+ if (leadingSign)
+ ca4 = "+Inf".toCharArray();
+ else if (leadingSpace)
+ ca4 = " Inf".toCharArray();
+ else
+ ca4 = "Inf".toCharArray();
+ } else
+ ca4 = "-Inf".toCharArray();
+ noDigits = true;
+ } else if (Double.isNaN(x)) {
+ if (leadingSign)
+ ca4 = "+NaN".toCharArray();
+ else if (leadingSpace)
+ ca4 = " NaN".toCharArray();
+ else
+ ca4 = "NaN".toCharArray();
+ noDigits = true;
+ } else {
+ if (!precisionSet)
+ precision = defaultDigits;
+ if (precision == 0)
+ precision = 1;
+ int ePos = -1;
+ if (conversionCharacter == 'g') {
+ sx = eFormatString(x, 'e').trim();
+ ePos = sx.indexOf('e');
+ } else {
+ sx = eFormatString(x, 'E').trim();
+ ePos = sx.indexOf('E');
+ }
+ i = ePos + 1;
+ int expon = 0;
+ if (sx.charAt(i) == '-') {
+ for (++i; i < sx.length(); i++)
+ if (sx.charAt(i) != '0')
+ break;
+ if (i < sx.length())
+ expon = -Integer.parseInt(sx.substring(i));
+ } else {
+ if (sx.charAt(i) == '+')
+ ++i;
+ for (; i < sx.length(); i++)
+ if (sx.charAt(i) != '0')
+ break;
+ if (i < sx.length())
+ expon = Integer.parseInt(sx.substring(i));
+ }
+ // Trim trailing zeros.
+ // If the radix character is not followed by
+ // a digit, trim it, too.
+ if (!alternateForm) {
+ if (expon >= -4 && expon < precision)
+ sy = fFormatString(x).trim();
+ else
+ sy = sx.substring(0, ePos);
+ i = sy.length() - 1;
+ for (; i >= 0; i--)
+ if (sy.charAt(i) != '0')
+ break;
+ if (i >= 0 && sy.charAt(i) == '.')
+ i--;
+ if (i == -1)
+ sz = "0";
+ else if (!Character.isDigit(sy.charAt(i)))
+ sz = sy.substring(0, i + 1) + "0";
+ else
+ sz = sy.substring(0, i + 1);
+ if (expon >= -4 && expon < precision)
+ ret = sz;
+ else
+ ret = sz + sx.substring(ePos);
+ } else {
+ if (expon >= -4 && expon < precision)
+ ret = fFormatString(x).trim();
+ else
+ ret = sx;
+ }
+ // leading space was trimmed off during
+ // construction
+ if (leadingSpace)
+ if (x >= 0)
+ ret = " " + ret;
+ ca4 = ret.toCharArray();
+ }
+ // Pad with blanks or zeros.
+ ca5 = applyFloatPadding(ca4, false);
+ precision = savePrecision;
+ return new String(ca5);
+ }
+ /**
+ * Format method for the d conversion specifer and
+ * short argument.
+ *
+ * For d format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. A '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both a
+ * '+' and a ' ' are specified, the blank flag is
+ * ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the short to format.
+ * @return the formatted String.
+ */
+ private String printDFormat(short x) {
+ return printDFormat(Short.toString(x));
+ }
+ /**
+ * Format method for the d conversion character and
+ * long argument.
+ *
+ * For d format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. A '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both a
+ * '+' and a ' ' are specified, the blank flag is
+ * ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the long to format.
+ * @return the formatted String.
+ */
+ private String printDFormat(long x) {
+ return printDFormat(Long.toString(x));
+ }
+ /**
+ * Format method for the d conversion character and
+ * int argument.
+ *
+ * For d format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. A '+' character means that the conversion
+ * will always begin with a sign (+ or -). The
+ * blank flag character means that a non-negative
+ * input will be preceded with a blank. If both a
+ * '+' and a ' ' are specified, the blank flag is
+ * ignored. The '0' flag character implies that
+ * padding to the field width will be done with
+ * zeros instead of blanks.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the int to format.
+ * @return the formatted String.
+ */
+ private String printDFormat(int x) {
+ return printDFormat(Integer.toString(x));
+ }
+ /**
+ * Utility method for formatting using the d
+ * conversion character.
+ * @param sx the String to format, the result of
+ * converting a short, int, or long to a
+ * String.
+ * @return the formatted String.
+ */
+ private String printDFormat(String sx) {
+ int nLeadingZeros = 0;
+ int nBlanks = 0, n = 0;
+ int i = 0, jFirst = 0;
+ boolean neg = sx.charAt(0) == '-';
+ if (sx.equals("0") && precisionSet && precision == 0)
+ sx = "";
+ if (!neg) {
+ if (precisionSet && sx.length() < precision)
+ nLeadingZeros = precision - sx.length();
+ } else {
+ if (precisionSet && (sx.length() - 1) < precision)
+ nLeadingZeros = precision - sx.length() + 1;
+ }
+ if (nLeadingZeros < 0)
+ nLeadingZeros = 0;
+ if (fieldWidthSet) {
+ nBlanks = fieldWidth - nLeadingZeros - sx.length();
+ if (!neg && (leadingSign || leadingSpace))
+ nBlanks--;
+ }
+ if (nBlanks < 0)
+ nBlanks = 0;
+ if (leadingSign)
+ n++;
+ else if (leadingSpace)
+ n++;
+ n += nBlanks;
+ n += nLeadingZeros;
+ n += sx.length();
+ char[] ca = new char[n];
+ if (leftJustify) {
+ if (neg)
+ ca[i++] = '-';
+ else if (leadingSign)
+ ca[i++] = '+';
+ else if (leadingSpace)
+ ca[i++] = ' ';
+ char[] csx = sx.toCharArray();
+ jFirst = neg ? 1 : 0;
+ for (int j = 0; j < nLeadingZeros; i++, j++)
+ ca[i] = '0';
+ for (int j = jFirst; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ for (int j = 0; j < nBlanks; i++, j++)
+ ca[i] = ' ';
+ } else {
+ if (!leadingZeros) {
+ for (i = 0; i < nBlanks; i++)
+ ca[i] = ' ';
+ if (neg)
+ ca[i++] = '-';
+ else if (leadingSign)
+ ca[i++] = '+';
+ else if (leadingSpace)
+ ca[i++] = ' ';
+ } else {
+ if (neg)
+ ca[i++] = '-';
+ else if (leadingSign)
+ ca[i++] = '+';
+ else if (leadingSpace)
+ ca[i++] = ' ';
+ for (int j = 0; j < nBlanks; j++, i++)
+ ca[i] = '0';
+ }
+ for (int j = 0; j < nLeadingZeros; j++, i++)
+ ca[i] = '0';
+ char[] csx = sx.toCharArray();
+ jFirst = neg ? 1 : 0;
+ for (int j = jFirst; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ }
+ return new String(ca);
+ }
+ /**
+ * Format method for the x conversion character and
+ * short argument.
+ *
+ * For x format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means to lead with
+ * '0x'.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the short to format.
+ * @return the formatted String.
+ */
+ private String printXFormat(short x) {
+ String sx = null;
+ if (x == Short.MIN_VALUE)
+ sx = "8000";
+ else if (x < 0) {
+ String t;
+ if (x == Short.MIN_VALUE)
+ t = "0";
+ else {
+ t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
+ if (t.charAt(0) == 'F' || t.charAt(0) == 'f')
+ t = t.substring(16, 32);
+ }
+ switch (t.length()) {
+ case 1 :
+ sx = "800" + t;
+ break;
+ case 2 :
+ sx = "80" + t;
+ break;
+ case 3 :
+ sx = "8" + t;
+ break;
+ case 4 :
+ switch (t.charAt(0)) {
+ case '1' :
+ sx = "9" + t.substring(1, 4);
+ break;
+ case '2' :
+ sx = "a" + t.substring(1, 4);
+ break;
+ case '3' :
+ sx = "b" + t.substring(1, 4);
+ break;
+ case '4' :
+ sx = "c" + t.substring(1, 4);
+ break;
+ case '5' :
+ sx = "d" + t.substring(1, 4);
+ break;
+ case '6' :
+ sx = "e" + t.substring(1, 4);
+ break;
+ case '7' :
+ sx = "f" + t.substring(1, 4);
+ break;
+ }
+ break;
+ }
+ } else
+ sx = Integer.toString((int) x, 16);
+ return printXFormat(sx);
+ }
+ /**
+ * Format method for the x conversion character and
+ * long argument.
+ *
+ * For x format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means to lead with
+ * '0x'.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the long to format.
+ * @return the formatted String.
+ */
+ private String printXFormat(long x) {
+ String sx = null;
+ if (x == Long.MIN_VALUE)
+ sx = "8000000000000000";
+ else if (x < 0) {
+ String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
+ switch (t.length()) {
+ case 1 :
+ sx = "800000000000000" + t;
+ break;
+ case 2 :
+ sx = "80000000000000" + t;
+ break;
+ case 3 :
+ sx = "8000000000000" + t;
+ break;
+ case 4 :
+ sx = "800000000000" + t;
+ break;
+ case 5 :
+ sx = "80000000000" + t;
+ break;
+ case 6 :
+ sx = "8000000000" + t;
+ break;
+ case 7 :
+ sx = "800000000" + t;
+ break;
+ case 8 :
+ sx = "80000000" + t;
+ break;
+ case 9 :
+ sx = "8000000" + t;
+ break;
+ case 10 :
+ sx = "800000" + t;
+ break;
+ case 11 :
+ sx = "80000" + t;
+ break;
+ case 12 :
+ sx = "8000" + t;
+ break;
+ case 13 :
+ sx = "800" + t;
+ break;
+ case 14 :
+ sx = "80" + t;
+ break;
+ case 15 :
+ sx = "8" + t;
+ break;
+ case 16 :
+ switch (t.charAt(0)) {
+ case '1' :
+ sx = "9" + t.substring(1, 16);
+ break;
+ case '2' :
+ sx = "a" + t.substring(1, 16);
+ break;
+ case '3' :
+ sx = "b" + t.substring(1, 16);
+ break;
+ case '4' :
+ sx = "c" + t.substring(1, 16);
+ break;
+ case '5' :
+ sx = "d" + t.substring(1, 16);
+ break;
+ case '6' :
+ sx = "e" + t.substring(1, 16);
+ break;
+ case '7' :
+ sx = "f" + t.substring(1, 16);
+ break;
+ }
+ break;
+ }
+ } else
+ sx = Long.toString(x, 16);
+ return printXFormat(sx);
+ }
+ /**
+ * Format method for the x conversion character and
+ * int argument.
+ *
+ * For x format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means to lead with
+ * '0x'.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the int to format.
+ * @return the formatted String.
+ */
+ private String printXFormat(int x) {
+ String sx = null;
+ if (x == Integer.MIN_VALUE)
+ sx = "80000000";
+ else if (x < 0) {
+ String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
+ switch (t.length()) {
+ case 1 :
+ sx = "8000000" + t;
+ break;
+ case 2 :
+ sx = "800000" + t;
+ break;
+ case 3 :
+ sx = "80000" + t;
+ break;
+ case 4 :
+ sx = "8000" + t;
+ break;
+ case 5 :
+ sx = "800" + t;
+ break;
+ case 6 :
+ sx = "80" + t;
+ break;
+ case 7 :
+ sx = "8" + t;
+ break;
+ case 8 :
+ switch (t.charAt(0)) {
+ case '1' :
+ sx = "9" + t.substring(1, 8);
+ break;
+ case '2' :
+ sx = "a" + t.substring(1, 8);
+ break;
+ case '3' :
+ sx = "b" + t.substring(1, 8);
+ break;
+ case '4' :
+ sx = "c" + t.substring(1, 8);
+ break;
+ case '5' :
+ sx = "d" + t.substring(1, 8);
+ break;
+ case '6' :
+ sx = "e" + t.substring(1, 8);
+ break;
+ case '7' :
+ sx = "f" + t.substring(1, 8);
+ break;
+ }
+ break;
+ }
+ } else
+ sx = Integer.toString(x, 16);
+ return printXFormat(sx);
+ }
+ /**
+ * Utility method for formatting using the x
+ * conversion character.
+ * @param sx the String to format, the result of
+ * converting a short, int, or long to a
+ * String.
+ * @return the formatted String.
+ */
+ private String printXFormat(String sx) {
+ int nLeadingZeros = 0;
+ int nBlanks = 0;
+ if (sx.equals("0") && precisionSet && precision == 0)
+ sx = "";
+ if (precisionSet)
+ nLeadingZeros = precision - sx.length();
+ if (nLeadingZeros < 0)
+ nLeadingZeros = 0;
+ if (fieldWidthSet) {
+ nBlanks = fieldWidth - nLeadingZeros - sx.length();
+ if (alternateForm)
+ nBlanks = nBlanks - 2;
+ }
+ if (nBlanks < 0)
+ nBlanks = 0;
+ int n = 0;
+ if (alternateForm)
+ n += 2;
+ n += nLeadingZeros;
+ n += sx.length();
+ n += nBlanks;
+ char[] ca = new char[n];
+ int i = 0;
+ if (leftJustify) {
+ if (alternateForm) {
+ ca[i++] = '0';
+ ca[i++] = 'x';
+ }
+ for (int j = 0; j < nLeadingZeros; j++, i++)
+ ca[i] = '0';
+ char[] csx = sx.toCharArray();
+ for (int j = 0; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ for (int j = 0; j < nBlanks; j++, i++)
+ ca[i] = ' ';
+ } else {
+ if (!leadingZeros)
+ for (int j = 0; j < nBlanks; j++, i++)
+ ca[i] = ' ';
+ if (alternateForm) {
+ ca[i++] = '0';
+ ca[i++] = 'x';
+ }
+ if (leadingZeros)
+ for (int j = 0; j < nBlanks; j++, i++)
+ ca[i] = '0';
+ for (int j = 0; j < nLeadingZeros; j++, i++)
+ ca[i] = '0';
+ char[] csx = sx.toCharArray();
+ for (int j = 0; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ }
+ String caReturn = new String(ca);
+ if (conversionCharacter == 'X')
+ caReturn = caReturn.toUpperCase();
+ return caReturn;
+ }
+ /**
+ * Format method for the o conversion character and
+ * short argument.
+ *
+ * For o format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means that the
+ * output begins with a leading 0 and the precision
+ * is increased by 1.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the short to format.
+ * @return the formatted String.
+ */
+ private String printOFormat(short x) {
+ String sx = null;
+ if (x == Short.MIN_VALUE)
+ sx = "100000";
+ else if (x < 0) {
+ String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
+ switch (t.length()) {
+ case 1 :
+ sx = "10000" + t;
+ break;
+ case 2 :
+ sx = "1000" + t;
+ break;
+ case 3 :
+ sx = "100" + t;
+ break;
+ case 4 :
+ sx = "10" + t;
+ break;
+ case 5 :
+ sx = "1" + t;
+ break;
+ }
+ } else
+ sx = Integer.toString((int) x, 8);
+ return printOFormat(sx);
+ }
+ /**
+ * Format method for the o conversion character and
+ * long argument.
+ *
+ * For o format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means that the
+ * output begins with a leading 0 and the precision
+ * is increased by 1.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the long to format.
+ * @return the formatted String.
+ */
+ private String printOFormat(long x) {
+ String sx = null;
+ if (x == Long.MIN_VALUE)
+ sx = "1000000000000000000000";
+ else if (x < 0) {
+ String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
+ switch (t.length()) {
+ case 1 :
+ sx = "100000000000000000000" + t;
+ break;
+ case 2 :
+ sx = "10000000000000000000" + t;
+ break;
+ case 3 :
+ sx = "1000000000000000000" + t;
+ break;
+ case 4 :
+ sx = "100000000000000000" + t;
+ break;
+ case 5 :
+ sx = "10000000000000000" + t;
+ break;
+ case 6 :
+ sx = "1000000000000000" + t;
+ break;
+ case 7 :
+ sx = "100000000000000" + t;
+ break;
+ case 8 :
+ sx = "10000000000000" + t;
+ break;
+ case 9 :
+ sx = "1000000000000" + t;
+ break;
+ case 10 :
+ sx = "100000000000" + t;
+ break;
+ case 11 :
+ sx = "10000000000" + t;
+ break;
+ case 12 :
+ sx = "1000000000" + t;
+ break;
+ case 13 :
+ sx = "100000000" + t;
+ break;
+ case 14 :
+ sx = "10000000" + t;
+ break;
+ case 15 :
+ sx = "1000000" + t;
+ break;
+ case 16 :
+ sx = "100000" + t;
+ break;
+ case 17 :
+ sx = "10000" + t;
+ break;
+ case 18 :
+ sx = "1000" + t;
+ break;
+ case 19 :
+ sx = "100" + t;
+ break;
+ case 20 :
+ sx = "10" + t;
+ break;
+ case 21 :
+ sx = "1" + t;
+ break;
+ }
+ } else
+ sx = Long.toString(x, 8);
+ return printOFormat(sx);
+ }
+ /**
+ * Format method for the o conversion character and
+ * int argument.
+ *
+ * For o format, the flag character '-', means that
+ * the output should be left justified within the
+ * field. The default is to pad with blanks on the
+ * left. The '#' flag character means that the
+ * output begins with a leading 0 and the precision
+ * is increased by 1.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is to
+ * add no padding. Padding is with blanks by
+ * default.
+ *
+ * The precision, if set, is the minimum number of
+ * digits to appear. Padding is with leading 0s.
+ * @param x the int to format.
+ * @return the formatted String.
+ */
+ private String printOFormat(int x) {
+ String sx = null;
+ if (x == Integer.MIN_VALUE)
+ sx = "20000000000";
+ else if (x < 0) {
+ String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
+ switch (t.length()) {
+ case 1 :
+ sx = "2000000000" + t;
+ break;
+ case 2 :
+ sx = "200000000" + t;
+ break;
+ case 3 :
+ sx = "20000000" + t;
+ break;
+ case 4 :
+ sx = "2000000" + t;
+ break;
+ case 5 :
+ sx = "200000" + t;
+ break;
+ case 6 :
+ sx = "20000" + t;
+ break;
+ case 7 :
+ sx = "2000" + t;
+ break;
+ case 8 :
+ sx = "200" + t;
+ break;
+ case 9 :
+ sx = "20" + t;
+ break;
+ case 10 :
+ sx = "2" + t;
+ break;
+ case 11 :
+ sx = "3" + t.substring(1);
+ break;
+ }
+ } else
+ sx = Integer.toString(x, 8);
+ return printOFormat(sx);
+ }
+ /**
+ * Utility method for formatting using the o
+ * conversion character.
+ * @param sx the String to format, the result of
+ * converting a short, int, or long to a
+ * String.
+ * @return the formatted String.
+ */
+ private String printOFormat(String sx) {
+ int nLeadingZeros = 0;
+ int nBlanks = 0;
+ if (sx.equals("0") && precisionSet && precision == 0)
+ sx = "";
+ if (precisionSet)
+ nLeadingZeros = precision - sx.length();
+ if (alternateForm)
+ nLeadingZeros++;
+ if (nLeadingZeros < 0)
+ nLeadingZeros = 0;
+ if (fieldWidthSet)
+ nBlanks = fieldWidth - nLeadingZeros - sx.length();
+ if (nBlanks < 0)
+ nBlanks = 0;
+ int n = nLeadingZeros + sx.length() + nBlanks;
+ char[] ca = new char[n];
+ int i;
+ if (leftJustify) {
+ for (i = 0; i < nLeadingZeros; i++)
+ ca[i] = '0';
+ char[] csx = sx.toCharArray();
+ for (int j = 0; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ for (int j = 0; j < nBlanks; j++, i++)
+ ca[i] = ' ';
+ } else {
+ if (leadingZeros)
+ for (i = 0; i < nBlanks; i++)
+ ca[i] = '0';
+ else
+ for (i = 0; i < nBlanks; i++)
+ ca[i] = ' ';
+ for (int j = 0; j < nLeadingZeros; j++, i++)
+ ca[i] = '0';
+ char[] csx = sx.toCharArray();
+ for (int j = 0; j < csx.length; j++, i++)
+ ca[i] = csx[j];
+ }
+ return new String(ca);
+ }
+ /**
+ * Format method for the c conversion character and
+ * char argument.
+ *
+ * The only flag character that affects c format is
+ * the '-', meaning that the output should be left
+ * justified within the field. The default is to
+ * pad with blanks on the left.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. Padding is with
+ * blanks by default. The default width is 1.
+ *
+ * The precision, if set, is ignored.
+ * @param x the char to format.
+ * @return the formatted String.
+ */
+ private String printCFormat(char x) {
+ int nPrint = 1;
+ int width = fieldWidth;
+ if (!fieldWidthSet)
+ width = nPrint;
+ char[] ca = new char[width];
+ int i = 0;
+ if (leftJustify) {
+ ca[0] = x;
+ for (i = 1; i <= width - nPrint; i++)
+ ca[i] = ' ';
+ } else {
+ for (i = 0; i < width - nPrint; i++)
+ ca[i] = ' ';
+ ca[i] = x;
+ }
+ return new String(ca);
+ }
+ /**
+ * Format method for the s conversion character and
+ * String argument.
+ *
+ * The only flag character that affects s format is
+ * the '-', meaning that the output should be left
+ * justified within the field. The default is to
+ * pad with blanks on the left.
+ *
+ * The field width is treated as the minimum number
+ * of characters to be printed. The default is the
+ * smaller of the number of characters in the the
+ * input and the precision. Padding is with blanks
+ * by default.
+ *
+ * The precision, if set, specifies the maximum
+ * number of characters to be printed from the
+ * string. A null digit string is treated
+ * as a 0. The default is not to set a maximum
+ * number of characters to be printed.
+ * @param x the String to format.
+ * @return the formatted String.
+ */
+ private String printSFormat(String x) {
+ int nPrint = x.length();
+ int width = fieldWidth;
+ if (precisionSet && nPrint > precision)
+ nPrint = precision;
+ if (!fieldWidthSet)
+ width = nPrint;
+ int n = 0;
+ if (width > nPrint)
+ n += width - nPrint;
+ if (nPrint >= x.length())
+ n += x.length();
+ else
+ n += nPrint;
+ char[] ca = new char[n];
+ int i = 0;
+ if (leftJustify) {
+ if (nPrint >= x.length()) {
+ char[] csx = x.toCharArray();
+ for (i = 0; i < x.length(); i++)
+ ca[i] = csx[i];
+ } else {
+ char[] csx = x.substring(0, nPrint).toCharArray();
+ for (i = 0; i < nPrint; i++)
+ ca[i] = csx[i];
+ }
+ for (int j = 0; j < width - nPrint; j++, i++)
+ ca[i] = ' ';
+ } else {
+ for (i = 0; i < width - nPrint; i++)
+ ca[i] = ' ';
+ if (nPrint >= x.length()) {
+ char[] csx = x.toCharArray();
+ for (int j = 0; j < x.length(); i++, j++)
+ ca[i] = csx[j];
+ } else {
+ char[] csx = x.substring(0, nPrint).toCharArray();
+ for (int j = 0; j < nPrint; i++, j++)
+ ca[i] = csx[j];
+ }
+ }
+ return new String(ca);
+ }
+ /**
+ * Check for a conversion character. If it is
+ * there, store it.
+ * @param x the String to format.
+ * @return <code>true</code> if the conversion
+ * character is there, and
+ * <code>false</code> otherwise.
+ */
+ private boolean setConversionCharacter() {
+ /* idfgGoxXeEcs */
+ boolean ret = false;
+ conversionCharacter = '\0';
+ if (pos < fmt.length()) {
+ char c = fmt.charAt(pos);
+ if (c == 'i'
+ || c == 'd'
+ || c == 'f'
+ || c == 'g'
+ || c == 'G'
+ || c == 'o'
+ || c == 'x'
+ || c == 'X'
+ || c == 'e'
+ || c == 'E'
+ || c == 'c'
+ || c == 's'
+ || c == '%') {
+ conversionCharacter = c;
+ pos++;
+ ret = true;
+ }
+ }
+ return ret;
+ }
+ /**
+ * Check for an h, l, or L in a format. An L is
+ * used to control the minimum number of digits
+ * in an exponent when using floating point
+ * formats. An l or h is used to control
+ * conversion of the input to a long or short,
+ * respectively, before formatting. If any of
+ * these is present, store them.
+ */
+ private void setOptionalHL() {
+ optionalh = false;
+ optionall = false;
+ optionalL = false;
+ if (pos < fmt.length()) {
+ char c = fmt.charAt(pos);
+ if (c == 'h') {
+ optionalh = true;
+ pos++;
+ } else if (c == 'l') {
+ optionall = true;
+ pos++;
+ } else if (c == 'L') {
+ optionalL = true;
+ pos++;
+ }
+ }
+ }
+ /**
+ * Set the precision.
+ */
+ private void setPrecision() {
+ int firstPos = pos;
+ precisionSet = false;
+ if (pos < fmt.length() && fmt.charAt(pos) == '.') {
+ pos++;
+ if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
+ pos++;
+ if (!setPrecisionArgPosition()) {
+ variablePrecision = true;
+ precisionSet = true;
+ }
+ return;
+ } else {
+ while (pos < fmt.length()) {
+ char c = fmt.charAt(pos);
+ if (Character.isDigit(c))
+ pos++;
+ else
+ break;
+ }
+ if (pos > firstPos + 1) {
+ String sz = fmt.substring(firstPos + 1, pos);
+ precision = Integer.parseInt(sz);
+ precisionSet = true;
+ }
+ }
+ }
+ }
+ /**
+ * Set the field width.
+ */
+ private void setFieldWidth() {
+ int firstPos = pos;
+ fieldWidth = 0;
+ fieldWidthSet = false;
+ if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
+ pos++;
+ if (!setFieldWidthArgPosition()) {
+ variableFieldWidth = true;
+ fieldWidthSet = true;
+ }
+ } else {
+ while (pos < fmt.length()) {
+ char c = fmt.charAt(pos);
+ if (Character.isDigit(c))
+ pos++;
+ else
+ break;
+ }
+ if (firstPos < pos && firstPos < fmt.length()) {
+ String sz = fmt.substring(firstPos, pos);
+ fieldWidth = Integer.parseInt(sz);
+ fieldWidthSet = true;
+ }
+ }
+ }
+ /**
+ * Store the digits <code>n</code> in %n$ forms.
+ */
+ private void setArgPosition() {
+ int xPos;
+ for (xPos = pos; xPos < fmt.length(); xPos++) {
+ if (!Character.isDigit(fmt.charAt(xPos)))
+ break;
+ }
+ if (xPos > pos && xPos < fmt.length()) {
+ if (fmt.charAt(xPos) == '$') {
+ positionalSpecification = true;
+ argumentPosition = Integer.parseInt(fmt.substring(pos, xPos));
+ pos = xPos + 1;
+ }
+ }
+ }
+ /**
+ * Store the digits <code>n</code> in *n$ forms.
+ */
+ private boolean setFieldWidthArgPosition() {
+ boolean ret = false;
+ int xPos;
+ for (xPos = pos; xPos < fmt.length(); xPos++) {
+ if (!Character.isDigit(fmt.charAt(xPos)))
+ break;
+ }
+ if (xPos > pos && xPos < fmt.length()) {
+ if (fmt.charAt(xPos) == '$') {
+ positionalFieldWidth = true;
+ argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos));
+ pos = xPos + 1;
+ ret = true;
+ }
+ }
+ return ret;
+ }
+ /**
+ * Store the digits <code>n</code> in *n$ forms.
+ */
+ private boolean setPrecisionArgPosition() {
+ boolean ret = false;
+ int xPos;
+ for (xPos = pos; xPos < fmt.length(); xPos++) {
+ if (!Character.isDigit(fmt.charAt(xPos)))
+ break;
+ }
+ if (xPos > pos && xPos < fmt.length()) {
+ if (fmt.charAt(xPos) == '$') {
+ positionalPrecision = true;
+ argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos));
+ pos = xPos + 1;
+ ret = true;
+ }
+ }
+ return ret;
+ }
+ boolean isPositionalSpecification() {
+ return positionalSpecification;
+ }
+ int getArgumentPosition() {
+ return argumentPosition;
+ }
+ boolean isPositionalFieldWidth() {
+ return positionalFieldWidth;
+ }
+ int getArgumentPositionForFieldWidth() {
+ return argumentPositionForFieldWidth;
+ }
+ boolean isPositionalPrecision() {
+ return positionalPrecision;
+ }
+ int getArgumentPositionForPrecision() {
+ return argumentPositionForPrecision;
+ }
+ /**
+ * Set flag characters, one of '-+#0 or a space.
+ */
+ private void setFlagCharacters() {
+ /* '-+ #0 */
+ thousands = false;
+ leftJustify = false;
+ leadingSign = false;
+ leadingSpace = false;
+ alternateForm = false;
+ leadingZeros = false;
+ for (; pos < fmt.length(); pos++) {
+ char c = fmt.charAt(pos);
+ if (c == '\'')
+ thousands = true;
+ else if (c == '-') {
+ leftJustify = true;
+ leadingZeros = false;
+ } else if (c == '+') {
+ leadingSign = true;
+ leadingSpace = false;
+ } else if (c == ' ') {
+ if (!leadingSign)
+ leadingSpace = true;
+ } else if (c == '#')
+ alternateForm = true;
+ else if (c == '0') {
+ if (!leftJustify)
+ leadingZeros = true;
+ } else
+ break;
+ }
+ }
+ /**
+ * The integer portion of the result of a decimal
+ * conversion (i, d, u, f, g, or G) will be
+ * formatted with thousands' grouping characters.
+ * For other conversions the flag is ignored.
+ */
+ private boolean thousands = false;
+ /**
+ * The result of the conversion will be
+ * left-justified within the field.
+ */
+ private boolean leftJustify = false;
+ /**
+ * The result of a signed conversion will always
+ * begin with a sign (+ or -).
+ */
+ private boolean leadingSign = false;
+ /**
+ * Flag indicating that left padding with spaces is
+ * specified.
+ */
+ private boolean leadingSpace = false;
+ /**
+ * For an o conversion, increase the precision to
+ * force the first digit of the result to be a
+ * zero. For x (or X) conversions, a non-zero
+ * result will have 0x (or 0X) prepended to it.
+ * For e, E, f, g, or G conversions, the result
+ * will always contain a radix character, even if
+ * no digits follow the point. For g and G
+ * conversions, trailing zeros will not be removed
+ * from the result.
+ */
+ private boolean alternateForm = false;
+ /**
+ * Flag indicating that left padding with zeroes is
+ * specified.
+ */
+ private boolean leadingZeros = false;
+ /**
+ * Flag indicating that the field width is *.
+ */
+ private boolean variableFieldWidth = false;
+ /**
+ * If the converted value has fewer bytes than the
+ * field width, it will be padded with spaces or
+ * zeroes.
+ */
+ private int fieldWidth = 0;
+ /**
+ * Flag indicating whether or not the field width
+ * has been set.
+ */
+ private boolean fieldWidthSet = false;
+ /**
+ * The minimum number of digits to appear for the
+ * d, i, o, u, x, or X conversions. The number of
+ * digits to appear after the radix character for
+ * the e, E, and f conversions. The maximum number
+ * of significant digits for the g and G
+ * conversions. The maximum number of bytes to be
+ * printed from a string in s and S conversions.
+ */
+ private int precision = 0;
+ /** Default precision. */
+ private final static int defaultDigits = 6;
+ /**
+ * Flag indicating that the precision is *.
+ */
+ private boolean variablePrecision = false;
+ /**
+ * Flag indicating whether or not the precision has
+ * been set.
+ */
+ private boolean precisionSet = false;
+ /*
+ */
+ private boolean positionalSpecification = false;
+ private int argumentPosition = 0;
+ private boolean positionalFieldWidth = false;
+ private int argumentPositionForFieldWidth = 0;
+ private boolean positionalPrecision = false;
+ private int argumentPositionForPrecision = 0;
+ /**
+ * Flag specifying that a following d, i, o, u, x,
+ * or X conversion character applies to a type
+ * short int.
+ */
+ private boolean optionalh = false;
+ /**
+ * Flag specifying that a following d, i, o, u, x,
+ * or X conversion character applies to a type lont
+ * int argument.
+ */
+ private boolean optionall = false;
+ /**
+ * Flag specifying that a following e, E, f, g, or
+ * G conversion character applies to a type double
+ * argument. This is a noop in Java.
+ */
+ private boolean optionalL = false;
+ /** Control string type. */
+ private char conversionCharacter = '\0';
+ /**
+ * Position within the control string. Used by
+ * the constructor.
+ */
+ private int pos = 0;
+ /** Literal or control format string. */
+ private String fmt;
+ }
+ /** Vector of control strings and format literals. */
+ private Vector vFmt = new Vector();
+ /** Character position. Used by the constructor. */
+ private int cPos = 0;
+ /** Character position. Used by the constructor. */
+ private DecimalFormatSymbols dfs = null;
+}
diff --git a/src/jake2/util/Vargs.java b/src/jake2/util/Vargs.java
new file mode 100644
index 0000000..b1ded8b
--- /dev/null
+++ b/src/jake2/util/Vargs.java
@@ -0,0 +1,121 @@
+/*
+ * Vargs.java
+ * Copyright (C) 2003
+ *
+ * $Id: Vargs.java,v 1.1 2004-07-07 19:59:56 hzi Exp $
+ */
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+package jake2.util;
+
+import java.util.Vector;
+
+/**
+ * Vargs is a helper class to encapsulate printf arguments.
+ *
+ * @author cwei
+ */
+public class Vargs {
+
+ // initial capacity
+ static final int SIZE = 5;
+
+ Vector v;
+
+ public Vargs() {
+ this(SIZE);
+ }
+
+ public Vargs(int initialSize) {
+ if (v != null)
+ v.clear(); // clear previous list for GC
+ v = new Vector(initialSize);
+ }
+
+ public Vargs add(boolean value) {
+ v.add(new Boolean(value));
+ return this;
+ }
+
+ public Vargs add(byte value) {
+ v.add(new Byte(value));
+ return this;
+ }
+
+ public Vargs add(char value) {
+ v.add(new Character(value));
+ return this;
+ }
+
+ public Vargs add(short value) {
+ v.add(new Short(value));
+ return this;
+ }
+
+ public Vargs add(int value) {
+ v.add(new Integer(value));
+ return this;
+ }
+
+ public Vargs add(long value) {
+ v.add(new Long(value));
+ return this;
+ }
+
+ public Vargs add(float value) {
+ v.add(new Float(value));
+ return this;
+ }
+
+ public Vargs add(double value) {
+ v.add(new Double(value));
+ return this;
+ }
+
+ public Vargs add(String value) {
+ v.add(value);
+ return this;
+ }
+
+ public Vargs add(Object value) {
+ v.add(value);
+ return this;
+ }
+
+ public Vargs clear() {
+ v.clear();
+ return this;
+ }
+
+ public Vector toVector() {
+ // Vector tmp = v;
+ // v = null;
+ // return tmp;
+ return (Vector) v.clone();
+ }
+
+ public Object[] toArray() {
+ return v.toArray();
+ }
+
+ public int size() {
+ return v.size();
+ }
+}