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