001: // Copyright (c) 2001, 2003 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.text;
005:
006: import java.text.FieldPosition;
007: import java.io.Writer;
008:
009: /** Handle formatting of integers.
010: * Used to implement the Common Lisp ~D (Decimal), ~X (Hexadecimal),
011: * ~O (Octal), ~B (Binary), and ~R (Radix) Common Lisp formats operators. */
012:
013: public class IntegerFormat extends ReportFormat {
014: public int base;
015:
016: /** Minimal width of the result, includiing sign, commas, etc.
017: * However, if the MIN_DIGITS flag is given, it's the minimum number
018: * of digits instead. This is used for printf-style "precision". */
019: public int minWidth;
020:
021: /** The padding characters, by default ' '. */
022: public int padChar;
023:
024: public int commaChar;
025: public int commaInterval;
026:
027: public int flags;
028: /** Do groups (for example thousands, using commas). */
029: public static final int SHOW_GROUPS = 1;
030:
031: /** If value is non-negative, emit a '+'. */
032: public static final int SHOW_PLUS = 2;
033:
034: /** If value is non-negative, emit an initial ' '. */
035: public static final int SHOW_SPACE = 4;
036:
037: /** Add "0x" (hex) or "0" (octal) prefix. */
038: public static final int SHOW_BASE = 8;
039:
040: public static final int PAD_RIGHT = 16;
041:
042: public static final int UPPERCASE = 32;
043:
044: /** The minWidth is minimum number of digits, not minimum total width. */
045: public static final int MIN_DIGITS = 64;
046:
047: public IntegerFormat() {
048: base = 10;
049: minWidth = 1;
050: padChar = (int) ' ';
051: commaChar = (int) ',';
052: commaInterval = 3;
053: flags = 0;
054: }
055:
056: public int format(Object[] args, int start, Writer dst,
057: FieldPosition fpos) throws java.io.IOException {
058: return format((Object) args, start, dst, fpos);
059: }
060:
061: public int format(Object arg, int start, Writer dst,
062: FieldPosition fpos) throws java.io.IOException {
063: Object[] args = arg instanceof Object[] ? (Object[]) arg : null;
064: int minWidth = getParam(this .minWidth, 1, args, start);
065: if (this .minWidth == PARAM_FROM_LIST)
066: start++;
067: char padChar = getParam(this .padChar, ' ', args, start);
068: if (this .padChar == PARAM_FROM_LIST)
069: start++;
070: char commaChar = getParam(this .commaChar, ',', args, start);
071: if (this .commaChar == PARAM_FROM_LIST)
072: start++;
073: int commaInterval = getParam(this .commaInterval, 3, args, start);
074: if (this .commaInterval == PARAM_FROM_LIST)
075: start++;
076: boolean printCommas = (flags & SHOW_GROUPS) != 0;
077: boolean padRight = (flags & PAD_RIGHT) != 0;
078: boolean padInternal = padChar == '0';
079: if (args != null) {
080: if (start >= args.length) {
081: dst.write("#<missing format argument>");
082: return start;
083: }
084: arg = args[start];
085: }
086: String sarg = convertToIntegerString(arg, base);
087: if (sarg != null) {
088: char sarg0 = sarg.charAt(0);
089: boolean neg = sarg0 == '-';
090: int slen = sarg.length();
091: int ndigits = neg ? slen - 1 : slen;
092: int numCommas = printCommas ? (ndigits - 1) / commaInterval
093: : 0;
094: int unpadded_len = ndigits + numCommas;
095: if (neg || (flags & (SHOW_PLUS | SHOW_SPACE)) != 0)
096: unpadded_len++;
097:
098: if ((flags & SHOW_BASE) != 0) {
099: if (base == 16)
100: unpadded_len += 2;
101: else if (base == 8 && sarg0 != '0')
102: unpadded_len += 1;
103: }
104: if ((flags & MIN_DIGITS) != 0) {
105: unpadded_len = ndigits;
106: if (slen == 1 && sarg0 == '0' && minWidth == 0)
107: slen = 0;
108: }
109: if (!padRight && !padInternal)
110: for (; minWidth > unpadded_len; --minWidth)
111: dst.write(padChar);
112: int i = 0;
113: if (neg) {
114: dst.write('-');
115: i++;
116: slen--;
117: } else if ((flags & SHOW_PLUS) != 0)
118: dst.write('+');
119: else if ((flags & SHOW_SPACE) != 0)
120: dst.write(' ');
121: boolean uppercase = base > 10 && (flags & UPPERCASE) != 0;
122: if ((flags & SHOW_BASE) != 0) {
123: if (base == 16) {
124: dst.write('0');
125: dst.write(uppercase ? 'X' : 'x');
126: } else if (base == 8 && sarg0 != '0')
127: dst.write('0');
128: }
129: if (padInternal)
130: for (; minWidth > unpadded_len; --minWidth)
131: dst.write(padChar);
132: for (;;) {
133: if (slen == 0)
134: break;
135: char ch = sarg.charAt(i++);
136: if (uppercase)
137: ch = Character.toUpperCase(ch);
138: dst.write(ch);
139: --slen;
140: if (printCommas && slen > 0
141: && (slen % commaInterval) == 0)
142: dst.write(commaChar);
143: }
144: if (padRight)
145: for (; minWidth > unpadded_len; --minWidth)
146: dst.write(padChar);
147: } else
148: print(dst, arg.toString());
149: return start + 1;
150: }
151:
152: public String convertToIntegerString(Object x, int radix) {
153: if (!(x instanceof Number))
154: return null;
155: else if (x instanceof java.math.BigInteger)
156: return ((java.math.BigInteger) x).toString(radix);
157: else
158: return Long.toString(((Number) x).longValue(), radix);
159: }
160: }
|