1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54:
55: import ;
56:
57:
85: public final class Formatter
86: implements Closeable, Flushable
87: {
88:
89:
92: private Appendable out;
93:
94:
97: private Locale locale;
98:
99:
102: private boolean closed;
103:
104:
107: private IOException ioException;
108:
109:
110:
113: private String format;
114:
115:
118: private int index;
119:
120:
123: private int length;
124:
125:
128: private Locale fmtLocale;
129:
130:
131:
132:
133:
134:
137: private static final String FLAGS = "--#+ 0,(";
138:
139:
142: private static final String lineSeparator
143: = SystemProperties.getProperty("line.separator");
144:
145:
148: public enum BigDecimalLayoutForm
149: {
150: DECIMAL_FLOAT,
151: SCIENTIFIC
152: }
153:
154:
158: public Formatter()
159: {
160: this(null, Locale.getDefault());
161: }
162:
163:
171: public Formatter(Locale loc)
172: {
173: this(null, loc);
174: }
175:
176:
182: public Formatter(Appendable app)
183: {
184: this(app, Locale.getDefault());
185: }
186:
187:
195: public Formatter(Appendable app, Locale loc)
196: {
197: this.out = app == null ? new StringBuilder() : app;
198: this.locale = loc;
199: }
200:
201:
212: public Formatter(File file)
213: throws FileNotFoundException
214: {
215: this(new OutputStreamWriter(new FileOutputStream(file)));
216: }
217:
218:
232: public Formatter(File file, String charset)
233: throws FileNotFoundException, UnsupportedEncodingException
234: {
235: this(file, charset, Locale.getDefault());
236: }
237:
238:
254: public Formatter(File file, String charset, Locale loc)
255: throws FileNotFoundException, UnsupportedEncodingException
256: {
257: this(new OutputStreamWriter(new FileOutputStream(file), charset),
258: loc);
259: }
260:
261:
267: public Formatter(OutputStream out)
268: {
269: this(new OutputStreamWriter(out));
270: }
271:
272:
282: public Formatter(OutputStream out, String charset)
283: throws UnsupportedEncodingException
284: {
285: this(out, charset, Locale.getDefault());
286: }
287:
288:
300: public Formatter(OutputStream out, String charset, Locale loc)
301: throws UnsupportedEncodingException
302: {
303: this(new OutputStreamWriter(out, charset), loc);
304: }
305:
306:
313: public Formatter(PrintStream out)
314: {
315: this((Appendable) out);
316: }
317:
318:
329: public Formatter(String file) throws FileNotFoundException
330: {
331: this(new OutputStreamWriter(new FileOutputStream(file)));
332: }
333:
334:
348: public Formatter(String file, String charset)
349: throws FileNotFoundException, UnsupportedEncodingException
350: {
351: this(file, charset, Locale.getDefault());
352: }
353:
354:
370: public Formatter(String file, String charset, Locale loc)
371: throws FileNotFoundException, UnsupportedEncodingException
372: {
373: this(new OutputStreamWriter(new FileOutputStream(file), charset),
374: loc);
375: }
376:
377:
385: public void close()
386: {
387: if (closed)
388: return;
389: try
390: {
391: if (out instanceof Closeable)
392: ((Closeable) out).close();
393: }
394: catch (IOException _)
395: {
396:
397:
398: }
399: closed = true;
400: }
401:
402:
409: public void flush()
410: {
411: if (closed)
412: throw new FormatterClosedException();
413: try
414: {
415: if (out instanceof Flushable)
416: ((Flushable) out).flush();
417: }
418: catch (IOException _)
419: {
420:
421:
422: }
423: }
424:
425:
431: private String getName(int flags)
432: {
433:
434:
435: int bit = Integer.numberOfTrailingZeros(flags);
436: return FLAGS.substring(bit, bit + 1);
437: }
438:
439:
446: private void checkFlags(int flags, int allowed, char conversion)
447: {
448: flags &= ~allowed;
449: if (flags != 0)
450: throw new FormatFlagsConversionMismatchException(getName(flags),
451: conversion);
452: }
453:
454:
459: private void noPrecision(int precision)
460: {
461: if (precision != -1)
462: throw new IllegalFormatPrecisionException(precision);
463: }
464:
465:
473: private void applyLocalization(StringBuilder builder, int flags, int width,
474: boolean isNegative)
475: {
476: DecimalFormatSymbols dfsyms;
477: if (fmtLocale == null)
478: dfsyms = new DecimalFormatSymbols();
479: else
480: dfsyms = new DecimalFormatSymbols(fmtLocale);
481:
482:
483: char zeroDigit = dfsyms.getZeroDigit();
484: int decimalOffset = -1;
485: for (int i = builder.length() - 1; i >= 0; --i)
486: {
487: char c = builder.charAt(i);
488: if (c >= '0' && c <= '9')
489: builder.setCharAt(i, (char) (c - '0' + zeroDigit));
490: else if (c == '.')
491: {
492: assert decimalOffset == -1;
493: decimalOffset = i;
494: }
495: }
496:
497:
498: if (decimalOffset != -1)
499: {
500: builder.deleteCharAt(decimalOffset);
501: builder.insert(decimalOffset, dfsyms.getDecimalSeparator());
502: }
503:
504:
505: if ((flags & FormattableFlags.COMMA) != 0)
506: {
507: char groupSeparator = dfsyms.getGroupingSeparator();
508: int groupSize = 3;
509: int offset = (decimalOffset == -1) ? builder.length() : decimalOffset;
510:
511:
512: for (int i = offset - groupSize; i > 0; i -= groupSize)
513: builder.insert(i, groupSeparator);
514: }
515:
516: if ((flags & FormattableFlags.ZERO) != 0)
517: {
518:
519:
520: for (int i = width - builder.length(); i > 0; --i)
521: builder.insert(0, zeroDigit);
522: }
523:
524: if (isNegative)
525: {
526: if ((flags & FormattableFlags.PAREN) != 0)
527: {
528: builder.insert(0, '(');
529: builder.append(')');
530: }
531: else
532: builder.insert(0, '-');
533: }
534: else if ((flags & FormattableFlags.PLUS) != 0)
535: builder.insert(0, '+');
536: else if ((flags & FormattableFlags.SPACE) != 0)
537: builder.insert(0, ' ');
538: }
539:
540:
550: private void genericFormat(String arg, int flags, int width, int precision)
551: throws IOException
552: {
553: if ((flags & FormattableFlags.UPPERCASE) != 0)
554: {
555: if (fmtLocale == null)
556: arg = arg.toUpperCase();
557: else
558: arg = arg.toUpperCase(fmtLocale);
559: }
560:
561: if (precision >= 0 && arg.length() > precision)
562: arg = arg.substring(0, precision);
563:
564: boolean leftJustify = (flags & FormattableFlags.LEFT_JUSTIFY) != 0;
565: if (leftJustify && width == -1)
566: throw new MissingFormatWidthException("fixme");
567: if (! leftJustify && arg.length() < width)
568: {
569: for (int i = width - arg.length(); i > 0; --i)
570: out.append(' ');
571: }
572: out.append(arg);
573: if (leftJustify && arg.length() < width)
574: {
575: for (int i = width - arg.length(); i > 0; --i)
576: out.append(' ');
577: }
578: }
579:
580:
590: private void booleanFormat(Object arg, int flags, int width, int precision,
591: char conversion)
592: throws IOException
593: {
594: checkFlags(flags,
595: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
596: conversion);
597: String result;
598: if (arg instanceof Boolean)
599: result = String.valueOf((Boolean) arg);
600: else
601: result = arg == null ? "false" : "true";
602: genericFormat(result, flags, width, precision);
603: }
604:
605:
615: private void hashCodeFormat(Object arg, int flags, int width, int precision,
616: char conversion)
617: throws IOException
618: {
619: checkFlags(flags,
620: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
621: conversion);
622: genericFormat(arg == null ? "null" : Integer.toHexString(arg.hashCode()),
623: flags, width, precision);
624: }
625:
626:
636: private void stringFormat(Object arg, int flags, int width, int precision,
637: char conversion)
638: throws IOException
639: {
640: if (arg instanceof Formattable)
641: {
642: checkFlags(flags,
643: (FormattableFlags.LEFT_JUSTIFY
644: | FormattableFlags.UPPERCASE
645: | FormattableFlags.ALTERNATE),
646: conversion);
647: Formattable fmt = (Formattable) arg;
648: fmt.formatTo(this, flags, width, precision);
649: }
650: else
651: {
652: checkFlags(flags,
653: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
654: conversion);
655: genericFormat(arg == null ? "null" : arg.toString(), flags, width,
656: precision);
657: }
658: }
659:
660:
670: private void characterFormat(Object arg, int flags, int width, int precision,
671: char conversion)
672: throws IOException
673: {
674: checkFlags(flags,
675: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
676: conversion);
677: noPrecision(precision);
678:
679: int theChar;
680: if (arg instanceof Character)
681: theChar = ((Character) arg).charValue();
682: else if (arg instanceof Byte)
683: theChar = (char) (((Byte) arg).byteValue ());
684: else if (arg instanceof Short)
685: theChar = (char) (((Short) arg).shortValue ());
686: else if (arg instanceof Integer)
687: {
688: theChar = ((Integer) arg).intValue();
689: if (! Character.isValidCodePoint(theChar))
690: throw new IllegalFormatCodePointException(theChar);
691: }
692: else
693: throw new IllegalFormatConversionException(conversion, arg.getClass());
694: String result = new String(Character.toChars(theChar));
695: genericFormat(result, flags, width, precision);
696: }
697:
698:
706: private void percentFormat(int flags, int width, int precision)
707: throws IOException
708: {
709: checkFlags(flags, FormattableFlags.LEFT_JUSTIFY, '%');
710: noPrecision(precision);
711: genericFormat("%", flags, width, precision);
712: }
713:
714:
722: private void newLineFormat(int flags, int width, int precision)
723: throws IOException
724: {
725: checkFlags(flags, 0, 'n');
726: noPrecision(precision);
727: if (width != -1)
728: throw new IllegalFormatWidthException(width);
729: genericFormat(lineSeparator, flags, width, precision);
730: }
731:
732:
744: private StringBuilder basicIntegralConversion(Object arg, int flags,
745: int width, int precision,
746: int radix, char conversion)
747: {
748: assert radix == 8 || radix == 10 || radix == 16;
749: noPrecision(precision);
750:
751:
752: if ((flags & FormattableFlags.PLUS) != 0
753: && (flags & FormattableFlags.SPACE) != 0)
754: throw new IllegalFormatFlagsException(getName(flags));
755:
756: if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0 && width == -1)
757: throw new MissingFormatWidthException("fixme");
758:
759:
760: String result;
761: int basicFlags = (FormattableFlags.LEFT_JUSTIFY
762:
763:
764: | FormattableFlags.UPPERCASE
765: | FormattableFlags.ZERO);
766: if (radix == 10)
767: basicFlags |= (FormattableFlags.PLUS
768: | FormattableFlags.SPACE
769: | FormattableFlags.COMMA
770: | FormattableFlags.PAREN);
771: else
772: basicFlags |= FormattableFlags.ALTERNATE;
773:
774: if (arg instanceof BigInteger)
775: {
776: checkFlags(flags,
777: (basicFlags
778: | FormattableFlags.PLUS
779: | FormattableFlags.SPACE
780: | FormattableFlags.PAREN),
781: conversion);
782: BigInteger bi = (BigInteger) arg;
783: result = bi.toString(radix);
784: }
785: else if (arg instanceof Number
786: && ! (arg instanceof Float)
787: && ! (arg instanceof Double))
788: {
789: checkFlags(flags, basicFlags, conversion);
790: long value = ((Number) arg).longValue ();
791: if (radix == 8)
792: result = Long.toOctalString(value);
793: else if (radix == 16)
794: result = Long.toHexString(value);
795: else
796: result = Long.toString(value);
797: }
798: else
799: throw new IllegalFormatConversionException(conversion, arg.getClass());
800:
801: return new StringBuilder(result);
802: }
803:
804:
815: private void hexOrOctalConversion(Object arg, int flags, int width,
816: int precision, int radix,
817: char conversion)
818: throws IOException
819: {
820: assert radix == 8 || radix == 16;
821:
822: StringBuilder builder = basicIntegralConversion(arg, flags, width,
823: precision, radix,
824: conversion);
825: int insertPoint = 0;
826:
827:
828: if (builder.charAt(0) == '-')
829: {
830:
831:
832:
833: ++insertPoint;
834: }
835: else if ((flags & FormattableFlags.PLUS) != 0)
836: {
837: builder.insert(insertPoint, '+');
838: ++insertPoint;
839: }
840: else if ((flags & FormattableFlags.SPACE) != 0)
841: {
842: builder.insert(insertPoint, ' ');
843: ++insertPoint;
844: }
845:
846:
847: if ((flags & FormattableFlags.ALTERNATE) != 0)
848: {
849: builder.insert(insertPoint, radix == 8 ? "0" : "0x");
850: insertPoint += radix == 8 ? 1 : 2;
851: }
852:
853:
854: int resultWidth = builder.length();
855: if (resultWidth < width)
856: {
857: char fill = ((flags & FormattableFlags.ZERO) != 0) ? '0' : ' ';
858: if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0)
859: {
860:
861: if (fill == ' ')
862: insertPoint = builder.length();
863: }
864: else
865: {
866:
867:
868: insertPoint = 0;
869: }
870: while (resultWidth++ < width)
871: builder.insert(insertPoint, fill);
872: }
873:
874: String result = builder.toString();
875: if ((flags & FormattableFlags.UPPERCASE) != 0)
876: {
877: if (fmtLocale == null)
878: result = result.toUpperCase();
879: else
880: result = result.toUpperCase(fmtLocale);
881: }
882:
883: out.append(result);
884: }
885:
886:
896: private void decimalConversion(Object arg, int flags, int width,
897: int precision, char conversion)
898: throws IOException
899: {
900: StringBuilder builder = basicIntegralConversion(arg, flags, width,
901: precision, 10,
902: conversion);
903: boolean isNegative = false;
904: if (builder.charAt(0) == '-')
905: {
906:
907: builder.deleteCharAt(0);
908: isNegative = true;
909: }
910:
911: applyLocalization(builder, flags, width, isNegative);
912: genericFormat(builder.toString(), flags, width, precision);
913: }
914:
915:
923: private void singleDateTimeConversion(StringBuilder builder, Calendar cal,
924: char conversion,
925: DateFormatSymbols syms)
926: {
927: int oldLen = builder.length();
928: int digits = -1;
929: switch (conversion)
930: {
931: case 'H':
932: builder.append(cal.get(Calendar.HOUR_OF_DAY));
933: digits = 2;
934: break;
935: case 'I':
936: builder.append(cal.get(Calendar.HOUR));
937: digits = 2;
938: break;
939: case 'k':
940: builder.append(cal.get(Calendar.HOUR_OF_DAY));
941: break;
942: case 'l':
943: builder.append(cal.get(Calendar.HOUR));
944: break;
945: case 'M':
946: builder.append(cal.get(Calendar.MINUTE));
947: digits = 2;
948: break;
949: case 'S':
950: builder.append(cal.get(Calendar.SECOND));
951: digits = 2;
952: break;
953: case 'N':
954:
955: digits = 9;
956: break;
957: case 'p':
958: {
959: int ampm = cal.get(Calendar.AM_PM);
960: builder.append(syms.getAmPmStrings()[ampm]);
961: }
962: break;
963: case 'z':
964: {
965: int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60);
966: builder.append(zone);
967: digits = 4;
968:
969: if (zone < 0)
970: ++oldLen;
971: }
972: break;
973: case 'Z':
974: {
975:
976: int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
977: String[][] zs = syms.getZoneStrings();
978: builder.append(zs[zone + 12][1]);
979: }
980: break;
981: case 's':
982: {
983: long val = cal.getTime().getTime();
984: builder.append(val / 1000);
985: }
986: break;
987: case 'Q':
988: {
989: long val = cal.getTime().getTime();
990: builder.append(val);
991: }
992: break;
993: case 'B':
994: {
995: int month = cal.get(Calendar.MONTH);
996: builder.append(syms.getMonths()[month]);
997: }
998: break;
999: case 'b':
1000: case 'h':
1001: {
1002: int month = cal.get(Calendar.MONTH);
1003: builder.append(syms.getShortMonths()[month]);
1004: }
1005: break;
1006: case 'A':
1007: {
1008: int day = cal.get(Calendar.DAY_OF_WEEK);
1009: builder.append(syms.getWeekdays()[day]);
1010: }
1011: break;
1012: case 'a':
1013: {
1014: int day = cal.get(Calendar.DAY_OF_WEEK);
1015: builder.append(syms.getShortWeekdays()[day]);
1016: }
1017: break;
1018: case 'C':
1019: builder.append(cal.get(Calendar.YEAR) / 100);
1020: digits = 2;
1021: break;
1022: case 'Y':
1023: builder.append(cal.get(Calendar.YEAR));
1024: digits = 4;
1025: break;
1026: case 'y':
1027: builder.append(cal.get(Calendar.YEAR) % 100);
1028: digits = 2;
1029: break;
1030: case 'j':
1031: builder.append(cal.get(Calendar.DAY_OF_YEAR));
1032: digits = 3;
1033: break;
1034: case 'm':
1035: builder.append(cal.get(Calendar.MONTH) + 1);
1036: digits = 2;
1037: break;
1038: case 'd':
1039: builder.append(cal.get(Calendar.DAY_OF_MONTH));
1040: digits = 2;
1041: break;
1042: case 'e':
1043: builder.append(cal.get(Calendar.DAY_OF_MONTH));
1044: break;
1045: case 'R':
1046: singleDateTimeConversion(builder, cal, 'H', syms);
1047: builder.append(':');
1048: singleDateTimeConversion(builder, cal, 'M', syms);
1049: break;
1050: case 'T':
1051: singleDateTimeConversion(builder, cal, 'H', syms);
1052: builder.append(':');
1053: singleDateTimeConversion(builder, cal, 'M', syms);
1054: builder.append(':');
1055: singleDateTimeConversion(builder, cal, 'S', syms);
1056: break;
1057: case 'r':
1058: singleDateTimeConversion(builder, cal, 'I', syms);
1059: builder.append(':');
1060: singleDateTimeConversion(builder, cal, 'M', syms);
1061: builder.append(':');
1062: singleDateTimeConversion(builder, cal, 'S', syms);
1063: builder.append(' ');
1064: singleDateTimeConversion(builder, cal, 'p', syms);
1065: break;
1066: case 'D':
1067: singleDateTimeConversion(builder, cal, 'm', syms);
1068: builder.append('/');
1069: singleDateTimeConversion(builder, cal, 'd', syms);
1070: builder.append('/');
1071: singleDateTimeConversion(builder, cal, 'y', syms);
1072: break;
1073: case 'F':
1074: singleDateTimeConversion(builder, cal, 'Y', syms);
1075: builder.append('-');
1076: singleDateTimeConversion(builder, cal, 'm', syms);
1077: builder.append('-');
1078: singleDateTimeConversion(builder, cal, 'd', syms);
1079: break;
1080: case 'c':
1081: singleDateTimeConversion(builder, cal, 'a', syms);
1082: builder.append(' ');
1083: singleDateTimeConversion(builder, cal, 'b', syms);
1084: builder.append(' ');
1085: singleDateTimeConversion(builder, cal, 'd', syms);
1086: builder.append(' ');
1087: singleDateTimeConversion(builder, cal, 'T', syms);
1088: builder.append(' ');
1089: singleDateTimeConversion(builder, cal, 'Z', syms);
1090: builder.append(' ');
1091: singleDateTimeConversion(builder, cal, 'Y', syms);
1092: break;
1093: default:
1094: throw new UnknownFormatConversionException(String.valueOf(conversion));
1095: }
1096:
1097: if (digits > 0)
1098: {
1099: int newLen = builder.length();
1100: int delta = newLen - oldLen;
1101: while (delta++ < digits)
1102: builder.insert(oldLen, '0');
1103: }
1104: }
1105:
1106:
1117: private void dateTimeConversion(Object arg, int flags, int width,
1118: int precision, char conversion,
1119: char subConversion)
1120: throws IOException
1121: {
1122: noPrecision(precision);
1123: checkFlags(flags,
1124: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
1125: conversion);
1126:
1127: Calendar cal;
1128: if (arg instanceof Calendar)
1129: cal = (Calendar) arg;
1130: else
1131: {
1132: Date date;
1133: if (arg instanceof Date)
1134: date = (Date) arg;
1135: else if (arg instanceof Long)
1136: date = new Date(((Long) arg).longValue());
1137: else
1138: throw new IllegalFormatConversionException(conversion,
1139: arg.getClass());
1140: if (fmtLocale == null)
1141: cal = Calendar.getInstance();
1142: else
1143: cal = Calendar.getInstance(fmtLocale);
1144: cal.setTime(date);
1145: }
1146:
1147:
1148: DateFormatSymbols syms;
1149: if (fmtLocale == null)
1150: syms = new DateFormatSymbols();
1151: else
1152: syms = new DateFormatSymbols(fmtLocale);
1153:
1154: StringBuilder result = new StringBuilder();
1155: singleDateTimeConversion(result, cal, subConversion, syms);
1156:
1157: genericFormat(result.toString(), flags, width, precision);
1158: }
1159:
1160:
1166: private void advance()
1167: {
1168: ++index;
1169: if (index >= length)
1170: {
1171:
1172: throw new IllegalArgumentException();
1173: }
1174: }
1175:
1176:
1182: private int parseInt()
1183: {
1184: int start = index;
1185: while (Character.isDigit(format.charAt(index)))
1186: advance();
1187: if (start == index)
1188: return -1;
1189: return Integer.decode(format.substring(start, index));
1190: }
1191:
1192:
1199: private int parseArgumentIndex()
1200: {
1201: int result = -1;
1202: int start = index;
1203: if (format.charAt(index) == '<')
1204: {
1205: result = 0;
1206: advance();
1207: }
1208: else if (Character.isDigit(format.charAt(index)))
1209: {
1210: result = parseInt();
1211: if (format.charAt(index) == '$')
1212: advance();
1213: else
1214: {
1215:
1216: index = start;
1217: result = -1;
1218: }
1219: }
1220: return result;
1221: }
1222:
1223:
1230: private int parseFlags()
1231: {
1232: int value = 0;
1233: int start = index;
1234: while (true)
1235: {
1236: int x = FLAGS.indexOf(format.charAt(index));
1237: if (x == -1)
1238: break;
1239: int newValue = 1 << x;
1240: if ((value & newValue) != 0)
1241: throw new DuplicateFormatFlagsException(format.substring(start,
1242: index + 1));
1243: value |= newValue;
1244: advance();
1245: }
1246: return value;
1247: }
1248:
1249:
1255: private int parseWidth()
1256: {
1257: return parseInt();
1258: }
1259:
1260:
1266: private int parsePrecision()
1267: {
1268: if (format.charAt(index) != '.')
1269: return -1;
1270: advance();
1271: int precision = parseInt();
1272: if (precision == -1)
1273:
1274: throw new IllegalArgumentException();
1275: return precision;
1276: }
1277:
1278:
1295: public Formatter format(Locale loc, String fmt, Object... args)
1296: {
1297: if (closed)
1298: throw new FormatterClosedException();
1299:
1300:
1301: int implicitArgumentIndex = 1;
1302: int previousArgumentIndex = 0;
1303:
1304: try
1305: {
1306: fmtLocale = loc;
1307: format = fmt;
1308: length = format.length();
1309: for (index = 0; index < length; ++index)
1310: {
1311: char c = format.charAt(index);
1312: if (c != '%')
1313: {
1314: out.append(c);
1315: continue;
1316: }
1317:
1318: int start = index;
1319: advance();
1320:
1321:
1322:
1323:
1324: int argumentIndex = parseArgumentIndex();
1325:
1326: int flags = parseFlags();
1327: int width = parseWidth();
1328: int precision = parsePrecision();
1329: char origConversion = format.charAt(index);
1330: char conversion = origConversion;
1331: if (Character.isUpperCase(conversion))
1332: {
1333: flags |= FormattableFlags.UPPERCASE;
1334: conversion = Character.toLowerCase(conversion);
1335: }
1336:
1337: Object argument = null;
1338: if (conversion == '%' || conversion == 'n')
1339: {
1340: if (argumentIndex != -1)
1341: {
1342:
1343: throw new UnknownFormatConversionException("FIXME");
1344: }
1345: }
1346: else
1347: {
1348: if (argumentIndex == -1)
1349: argumentIndex = implicitArgumentIndex++;
1350: else if (argumentIndex == 0)
1351: argumentIndex = previousArgumentIndex;
1352:
1353: --argumentIndex;
1354: if (argumentIndex < 0 || argumentIndex >= args.length)
1355: throw new MissingFormatArgumentException(format.substring(start, index));
1356: argument = args[argumentIndex];
1357: }
1358:
1359: switch (conversion)
1360: {
1361: case 'b':
1362: booleanFormat(argument, flags, width, precision,
1363: origConversion);
1364: break;
1365: case 'h':
1366: hashCodeFormat(argument, flags, width, precision,
1367: origConversion);
1368: break;
1369: case 's':
1370: stringFormat(argument, flags, width, precision,
1371: origConversion);
1372: break;
1373: case 'c':
1374: characterFormat(argument, flags, width, precision,
1375: origConversion);
1376: break;
1377: case 'd':
1378: checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'd');
1379: decimalConversion(argument, flags, width, precision,
1380: origConversion);
1381: break;
1382: case 'o':
1383: checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'o');
1384: hexOrOctalConversion(argument, flags, width, precision, 8,
1385: origConversion);
1386: break;
1387: case 'x':
1388: hexOrOctalConversion(argument, flags, width, precision, 16,
1389: origConversion);
1390: case 'e':
1391:
1392: break;
1393: case 'f':
1394:
1395: break;
1396: case 'g':
1397:
1398: break;
1399: case 'a':
1400:
1401: break;
1402: case 't':
1403: advance();
1404: char subConversion = format.charAt(index);
1405: dateTimeConversion(argument, flags, width, precision,
1406: origConversion, subConversion);
1407: break;
1408: case '%':
1409: percentFormat(flags, width, precision);
1410: break;
1411: case 'n':
1412: newLineFormat(flags, width, precision);
1413: break;
1414: default:
1415: throw new UnknownFormatConversionException(String.valueOf(origConversion));
1416: }
1417: }
1418: }
1419: catch (IOException exc)
1420: {
1421: ioException = exc;
1422: }
1423: return this;
1424: }
1425:
1426:
1438: public Formatter format(String format, Object... args)
1439: {
1440: return format(locale, format, args);
1441: }
1442:
1443:
1450: public IOException ioException()
1451: {
1452: return ioException;
1453: }
1454:
1455:
1461: public Locale locale()
1462: {
1463: if (closed)
1464: throw new FormatterClosedException();
1465: return locale;
1466: }
1467:
1468:
1474: public Appendable out()
1475: {
1476: if (closed)
1477: throw new FormatterClosedException();
1478: return out;
1479: }
1480:
1481:
1490: public String toString()
1491: {
1492: if (closed)
1493: throw new FormatterClosedException();
1494: return out.toString();
1495: }
1496: }