/*
* $Id: Format.java,v 1.5 2002/09/16 08:05:07 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.util;
import anvil.core.Any;
import java.text.DecimalFormat;
public class Format
{
private static final String[] TYPES = {
"none",
"boolean",
"int",
"double",
"string",
"char"
};
public static final int TYPE_BOOLEAN = 1;
public static final int TYPE_LONG = 2;
public static final int TYPE_DOUBLE = 3;
public static final int TYPE_DOUBLE_SIGNIFICANT = 4;
public static final int TYPE_STRING = 5;
public static final int TYPE_CHAR = 6;
public static final byte FLAG_ADJUST_LEFT = 1;
public static final byte FLAG_WITH_SIGN = 2;
public static final byte FLAG_WITH_ZEROS = 4;
public static final int STATE_INITIAL = 0;
public static final int STATE_PRECISION = 2;
public static final String format(String format, Any[] arguments)
{
int length = format.length();
int i = 0;
char ch;
StringBuffer result = new StringBuffer(length + 16);
int index = 0;
int max = (arguments != null) ? arguments.length : 0;
while(i<length) {
ch = format.charAt(i++);
if (ch == '%') {
if (i<length) {
ch = format.charAt(i);
if (ch == '%') {
result.append('%');
} else {
int type = 0;
byte flags = 0;
int width = 0;
int precision = 0;
int state = STATE_INITIAL;
boolean done = false;
while(i<length) {
switch(ch) {
case 'b':
i++;
type = TYPE_BOOLEAN;
done = true;
break;
case 'd':
case 'i':
i++;
type = TYPE_LONG;
done = true;
break;
case 'f':
i++;
type = TYPE_DOUBLE;
done = true;
break;
case 'g':
i++;
type = TYPE_DOUBLE_SIGNIFICANT;
done = true;
break;
case 'c':
i++;
type = TYPE_CHAR;
done = true;
break;
case 's':
i++;
type = TYPE_STRING;
done = true;
break;
case ' ':
i++;
if (state == STATE_INITIAL) {
flags &= ~FLAG_WITH_ZEROS;
} else {
done = true;
}
break;
case '-':
i++;
if (state == STATE_INITIAL) {
flags |= FLAG_ADJUST_LEFT;
} else {
done = true;
}
break;
case '+':
i++;
if (state == STATE_INITIAL) {
flags |= FLAG_WITH_SIGN;
} else {
done = true;
}
break;
case '.':
i++;
state = STATE_PRECISION;
break;
case '*':
i++;
if (state == STATE_PRECISION) {
precision = -1;
} else {
width = -1;
state = STATE_PRECISION;
}
break;
case '0':
i++;
if (state == STATE_INITIAL) {
flags |= FLAG_WITH_ZEROS;
break;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
int begin = i;
while(i+1 < length) {
ch = format.charAt(i+1);
if ((ch<'0') || (ch >'9')) {
break;
}
i++;
}
int num = 0;
int mul = 1;
int j = i;
while(j>=begin) {
num += mul * (format.charAt(j--) - '0');
mul *= 10;
}
if (state == STATE_PRECISION) {
precision = num;
} else {
width = num;
}
i++;
break;
default:
done = true;
}
if (done) {
break;
}
if (i<length) {
ch = format.charAt(i);
}
}
if (type != 0) {
index = append(result, type, flags, width, precision, arguments, index, max);
}
}
} else {
result.append('%');
}
} else {
result.append(ch);
}
}
return result.toString();
}
private static final void appendChar(StringBuffer result, Any value)
{
if (value.isInt()) {
result.append((char)value.toInt());
} else {
String s = value.toString();
if (s.length() > 0) {
result.append(s.charAt(0));
} else {
result.append(' ');
}
}
}
private static final int numlen(long number)
{
if (number == 0) {
return 1;
}
int length = 0;
if (number < 0) {
length++;
}
while(number != 0) {
number /= 10;
length++;
}
return length;
}
private static final void appendLong(StringBuffer result, byte flags, int width, long num)
{
switch(flags) {
case 0*FLAG_WITH_ZEROS | 0*FLAG_WITH_SIGN | 0*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (len < width) {
width -= len;
while(width-- > 0) {
result.append(' ');
}
}
result.append(num);
} else {
result.append(num);
}
break;
case 0*FLAG_WITH_ZEROS | 0*FLAG_WITH_SIGN | 1*FLAG_ADJUST_LEFT:
if (width > 0) {
result.append(num);
int len = numlen(num);
if (len < width) {
width -= len;
while(width-- > 0) {
result.append(' ');
}
}
} else {
result.append(num);
}
break;
case 0*FLAG_WITH_ZEROS | 1*FLAG_WITH_SIGN | 0*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num>=0) {
len++;
}
if (len < width) {
width -= len;
while(width-- > 0) {
result.append(' ');
}
}
if (num >= 0) {
result.append('+');
}
result.append(num);
} else {
if (num >= 0) {
result.append('+');
}
result.append(num);
}
break;
case 0*FLAG_WITH_ZEROS | 1*FLAG_WITH_SIGN | 1*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num >= 0) {
result.append('+');
len++;
}
result.append(num);
if (len < width) {
width -= len;
while(width-- > 0) {
result.append(' ');
}
}
} else {
if (num >= 0) {
result.append('+');
}
result.append(num);
}
break;
case 1*FLAG_WITH_ZEROS | 0*FLAG_WITH_SIGN | 0*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num < 0) {
result.append('-');
num = -num;
len--;
width--;
}
if (len < width) {
width -= len;
while(width-- > 0) {
result.append('0');
}
}
result.append(num);
} else {
result.append(num);
}
break;
case 1*FLAG_WITH_ZEROS | 0*FLAG_WITH_SIGN | 1*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num < 0) {
result.append('-');
num = -num;
}
if (len < width) {
width -= len;
while(width-- > 0) {
result.append('0');
}
}
result.append(num);
} else {
result.append(num);
}
break;
case 1*FLAG_WITH_ZEROS | 1*FLAG_WITH_SIGN | 0*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num >= 0) {
result.append('+');
len++;
} else {
result.append('-');
num = -num;
}
if (len < width) {
width -= len;
while(width-- > 0) {
result.append('0');
}
}
result.append(num);
} else {
if (num >= 0) {
result.append('+');
}
result.append(num);
}
break;
case 1*FLAG_WITH_ZEROS | 1*FLAG_WITH_SIGN | 1*FLAG_ADJUST_LEFT:
if (width > 0) {
int len = numlen(num);
if (num >= 0) {
result.append('+');
len++;
} else {
result.append('-');
num = -num;
}
if (len < width) {
width -= len;
while(width-- > 0) {
result.append('0');
}
}
result.append(num);
} else {
if (num >= 0) {
result.append('+');
}
result.append(num);
}
break;
}
}
private static final void appendString(StringBuffer result, byte flags,
int width, String str)
{
if (width > 0) {
int len = str.length();
if (len == width) {
result.append(str);
} else if (len > width) {
result.append(str.substring(0, width));
} else {
if ((flags & FLAG_ADJUST_LEFT) != 0) {
result.append(str);
width -= len;
while(width-- > 0) {
result.append(' ');
}
} else {
width -= len;
while(width-- > 0) {
result.append(' ');
}
result.append(str);
}
}
} else {
result.append(str);
}
}
private static final void appendFloat(StringBuffer result, byte flags,
int width, int precision, double number, boolean significant)
{
StringBuffer format = new StringBuffer(32);
boolean negative = (number < 0.0);
number = Math.abs(number);
if (width>0) {
int i = width;
if (negative || (flags & FLAG_WITH_SIGN) != 0) {
format.append(negative ? '-' : '+');
i--;
}
while(i-- > 0) {
format.append('0');
}
} else {
if (negative || (flags & FLAG_WITH_SIGN) != 0) {
format.append(negative ? '-' : '+');
}
format.append('0');
}
if (precision>0) {
format.append('.');
int i = precision;
while(i-- > 0) {
format.append('0');
}
} else if (significant) {
format.append(".##########################");
}
format.append(';');
String formatted = new java.text.DecimalFormat(format.toString()).format(number);
if ((flags & FLAG_WITH_ZEROS) == 0) {
format.setLength(0);
int n = formatted.length();
format.append(formatted);
while (n < width+1+precision) {
format.append(' ');
n++;
}
char sign = ' ';
int i = 0;
if (n>0) {
sign = format.charAt(0);
if (sign == '-' || sign == '+') {
i++;
}
while((i+1<n) && (format.charAt(i) == '0') && (format.charAt(i+1) != '.')) {
format.setCharAt(i++, ' ');
}
}
i--;
if (i>0 && (sign == '-' || sign == '+')) {
format.setCharAt(0, ' ');
format.setCharAt(i, sign);
} else {
formatted = format.toString();
}
if (i>0 && (flags & FLAG_ADJUST_LEFT) != 0) {
if (sign != '-' && sign != '+') {
formatted = format.substring(i+1) + format.substring(0, i+1);
} else {
formatted = format.substring(i) + format.substring(0, i);
}
} else {
formatted = format.toString();
}
}
result.append(formatted);
}
private static final int append(StringBuffer result, int type, byte flags,
int width, int precision, Any[] arguments, int index, int max)
{
Any value = (index < max) ? arguments[index++] : Any.NULL;
if (width == -1) {
width = (index < max) ? arguments[index++].toInt() : 0;
if (width < 0) {
width = 0;
}
}
if (precision == -1) {
precision = (index < max) ? arguments[index++].toInt() : 0;
if (precision < 0) {
precision = 0;
}
}
switch(type) {
case TYPE_CHAR:
if (width > 0) {
if ((flags & FLAG_ADJUST_LEFT) != 0) {
appendChar(result, value);
while(--width > 0) {
result.append(' ');
}
} else {
while(width-- > 1) {
result.append(' ');
}
appendChar(result, value);
}
} else {
appendChar(result, value);
}
break;
case TYPE_BOOLEAN:
case TYPE_STRING:
appendString(result, flags, width, value.toString());
break;
case TYPE_LONG:
appendLong(result, flags, width, value.toLong());
break;
case TYPE_DOUBLE:
appendFloat(result, flags, width, precision, value.toDouble(), false);
break;
case TYPE_DOUBLE_SIGNIFICANT:
appendFloat(result, flags, width, precision, value.toDouble(), true);
break;
}
return index;
}
}