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: if (arg == null)
682: {
683: genericFormat("null", flags, width, precision);
684: return;
685: }
686:
687: int theChar;
688: if (arg instanceof Character)
689: theChar = ((Character) arg).charValue();
690: else if (arg instanceof Byte)
691: theChar = (char) (((Byte) arg).byteValue ());
692: else if (arg instanceof Short)
693: theChar = (char) (((Short) arg).shortValue ());
694: else if (arg instanceof Integer)
695: {
696: theChar = ((Integer) arg).intValue();
697: if (! Character.isValidCodePoint(theChar))
698: throw new IllegalFormatCodePointException(theChar);
699: }
700: else
701: throw new IllegalFormatConversionException(conversion, arg.getClass());
702: String result = new String(Character.toChars(theChar));
703: genericFormat(result, flags, width, precision);
704: }
705:
706:
714: private void percentFormat(int flags, int width, int precision)
715: throws IOException
716: {
717: checkFlags(flags, FormattableFlags.LEFT_JUSTIFY, '%');
718: noPrecision(precision);
719: genericFormat("%", flags, width, precision);
720: }
721:
722:
730: private void newLineFormat(int flags, int width, int precision)
731: throws IOException
732: {
733: checkFlags(flags, 0, 'n');
734: noPrecision(precision);
735: if (width != -1)
736: throw new IllegalFormatWidthException(width);
737: genericFormat(lineSeparator, flags, width, precision);
738: }
739:
740:
752: private CPStringBuilder basicIntegralConversion(Object arg, int flags,
753: int width, int precision,
754: int radix, char conversion)
755: {
756: assert radix == 8 || radix == 10 || radix == 16;
757:
758: if (arg == null)
759: {
760: return new CPStringBuilder("null");
761: }
762:
763: noPrecision(precision);
764:
765:
766: if ((flags & FormattableFlags.PLUS) != 0
767: && (flags & FormattableFlags.SPACE) != 0)
768: throw new IllegalFormatFlagsException(getName(flags));
769:
770: if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0 && width == -1)
771: throw new MissingFormatWidthException("fixme");
772:
773:
774: String result;
775: int basicFlags = (FormattableFlags.LEFT_JUSTIFY
776:
777:
778: | FormattableFlags.UPPERCASE
779: | FormattableFlags.ZERO);
780: if (radix == 10)
781: basicFlags |= (FormattableFlags.PLUS
782: | FormattableFlags.SPACE
783: | FormattableFlags.COMMA
784: | FormattableFlags.PAREN);
785: else
786: basicFlags |= FormattableFlags.ALTERNATE;
787:
788: if (arg instanceof BigInteger)
789: {
790: checkFlags(flags,
791: (basicFlags
792: | FormattableFlags.PLUS
793: | FormattableFlags.SPACE
794: | FormattableFlags.PAREN),
795: conversion);
796: BigInteger bi = (BigInteger) arg;
797: result = bi.toString(radix);
798: }
799: else if (arg instanceof Number
800: && ! (arg instanceof Float)
801: && ! (arg instanceof Double))
802: {
803: checkFlags(flags, basicFlags, conversion);
804: long value = ((Number) arg).longValue ();
805: if (radix == 8)
806: result = Long.toOctalString(value);
807: else if (radix == 16)
808: result = Long.toHexString(value);
809: else
810: result = Long.toString(value);
811: }
812: else
813: throw new IllegalFormatConversionException(conversion, arg.getClass());
814:
815: return new CPStringBuilder(result);
816: }
817:
818:
829: private void hexOrOctalConversion(Object arg, int flags, int width,
830: int precision, int radix,
831: char conversion)
832: throws IOException
833: {
834: assert radix == 8 || radix == 16;
835:
836: CPStringBuilder builder = basicIntegralConversion(arg, flags, width,
837: precision, radix,
838: conversion);
839: int insertPoint = 0;
840:
841:
842: if (builder.charAt(0) == '-')
843: {
844:
845:
846:
847: ++insertPoint;
848: }
849: else if ((flags & FormattableFlags.PLUS) != 0)
850: {
851: builder.insert(insertPoint, '+');
852: ++insertPoint;
853: }
854: else if ((flags & FormattableFlags.SPACE) != 0)
855: {
856: builder.insert(insertPoint, ' ');
857: ++insertPoint;
858: }
859:
860:
861: if ((flags & FormattableFlags.ALTERNATE) != 0)
862: {
863: builder.insert(insertPoint, radix == 8 ? "0" : "0x");
864: insertPoint += radix == 8 ? 1 : 2;
865: }
866:
867:
868: int resultWidth = builder.length();
869: if (resultWidth < width)
870: {
871: char fill = ((flags & FormattableFlags.ZERO) != 0) ? '0' : ' ';
872: if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0)
873: {
874:
875: if (fill == ' ')
876: insertPoint = builder.length();
877: }
878: else
879: {
880:
881:
882: insertPoint = 0;
883: }
884: while (resultWidth++ < width)
885: builder.insert(insertPoint, fill);
886: }
887:
888: String result = builder.toString();
889: if ((flags & FormattableFlags.UPPERCASE) != 0)
890: {
891: if (fmtLocale == null)
892: result = result.toUpperCase();
893: else
894: result = result.toUpperCase(fmtLocale);
895: }
896:
897: out.append(result);
898: }
899:
900:
910: private void decimalConversion(Object arg, int flags, int width,
911: int precision, char conversion)
912: throws IOException
913: {
914: CPStringBuilder builder = basicIntegralConversion(arg, flags, width,
915: precision, 10,
916: conversion);
917: boolean isNegative = false;
918: if (builder.charAt(0) == '-')
919: {
920:
921: builder.deleteCharAt(0);
922: isNegative = true;
923: }
924:
925: applyLocalization(builder, flags, width, isNegative);
926: genericFormat(builder.toString(), flags, width, precision);
927: }
928:
929:
937: private void singleDateTimeConversion(CPStringBuilder builder, Calendar cal,
938: char conversion,
939: DateFormatSymbols syms)
940: {
941: int oldLen = builder.length();
942: int digits = -1;
943: switch (conversion)
944: {
945: case 'H':
946: builder.append(cal.get(Calendar.HOUR_OF_DAY));
947: digits = 2;
948: break;
949: case 'I':
950: builder.append(cal.get(Calendar.HOUR));
951: digits = 2;
952: break;
953: case 'k':
954: builder.append(cal.get(Calendar.HOUR_OF_DAY));
955: break;
956: case 'l':
957: builder.append(cal.get(Calendar.HOUR));
958: break;
959: case 'M':
960: builder.append(cal.get(Calendar.MINUTE));
961: digits = 2;
962: break;
963: case 'S':
964: builder.append(cal.get(Calendar.SECOND));
965: digits = 2;
966: break;
967: case 'N':
968:
969: digits = 9;
970: break;
971: case 'p':
972: {
973: int ampm = cal.get(Calendar.AM_PM);
974: builder.append(syms.getAmPmStrings()[ampm]);
975: }
976: break;
977: case 'z':
978: {
979: int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60);
980: builder.append(zone);
981: digits = 4;
982:
983: if (zone < 0)
984: ++oldLen;
985: }
986: break;
987: case 'Z':
988: {
989:
990: int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
991: String[][] zs = syms.getZoneStrings();
992: builder.append(zs[zone + 12][1]);
993: }
994: break;
995: case 's':
996: {
997: long val = cal.getTime().getTime();
998: builder.append(val / 1000);
999: }
1000: break;
1001: case 'Q':
1002: {
1003: long val = cal.getTime().getTime();
1004: builder.append(val);
1005: }
1006: break;
1007: case 'B':
1008: {
1009: int month = cal.get(Calendar.MONTH);
1010: builder.append(syms.getMonths()[month]);
1011: }
1012: break;
1013: case 'b':
1014: case 'h':
1015: {
1016: int month = cal.get(Calendar.MONTH);
1017: builder.append(syms.getShortMonths()[month]);
1018: }
1019: break;
1020: case 'A':
1021: {
1022: int day = cal.get(Calendar.DAY_OF_WEEK);
1023: builder.append(syms.getWeekdays()[day]);
1024: }
1025: break;
1026: case 'a':
1027: {
1028: int day = cal.get(Calendar.DAY_OF_WEEK);
1029: builder.append(syms.getShortWeekdays()[day]);
1030: }
1031: break;
1032: case 'C':
1033: builder.append(cal.get(Calendar.YEAR) / 100);
1034: digits = 2;
1035: break;
1036: case 'Y':
1037: builder.append(cal.get(Calendar.YEAR));
1038: digits = 4;
1039: break;
1040: case 'y':
1041: builder.append(cal.get(Calendar.YEAR) % 100);
1042: digits = 2;
1043: break;
1044: case 'j':
1045: builder.append(cal.get(Calendar.DAY_OF_YEAR));
1046: digits = 3;
1047: break;
1048: case 'm':
1049: builder.append(cal.get(Calendar.MONTH) + 1);
1050: digits = 2;
1051: break;
1052: case 'd':
1053: builder.append(cal.get(Calendar.DAY_OF_MONTH));
1054: digits = 2;
1055: break;
1056: case 'e':
1057: builder.append(cal.get(Calendar.DAY_OF_MONTH));
1058: break;
1059: case 'R':
1060: singleDateTimeConversion(builder, cal, 'H', syms);
1061: builder.append(':');
1062: singleDateTimeConversion(builder, cal, 'M', syms);
1063: break;
1064: case 'T':
1065: singleDateTimeConversion(builder, cal, 'H', syms);
1066: builder.append(':');
1067: singleDateTimeConversion(builder, cal, 'M', syms);
1068: builder.append(':');
1069: singleDateTimeConversion(builder, cal, 'S', syms);
1070: break;
1071: case 'r':
1072: singleDateTimeConversion(builder, cal, 'I', syms);
1073: builder.append(':');
1074: singleDateTimeConversion(builder, cal, 'M', syms);
1075: builder.append(':');
1076: singleDateTimeConversion(builder, cal, 'S', syms);
1077: builder.append(' ');
1078: singleDateTimeConversion(builder, cal, 'p', syms);
1079: break;
1080: case 'D':
1081: singleDateTimeConversion(builder, cal, 'm', syms);
1082: builder.append('/');
1083: singleDateTimeConversion(builder, cal, 'd', syms);
1084: builder.append('/');
1085: singleDateTimeConversion(builder, cal, 'y', syms);
1086: break;
1087: case 'F':
1088: singleDateTimeConversion(builder, cal, 'Y', syms);
1089: builder.append('-');
1090: singleDateTimeConversion(builder, cal, 'm', syms);
1091: builder.append('-');
1092: singleDateTimeConversion(builder, cal, 'd', syms);
1093: break;
1094: case 'c':
1095: singleDateTimeConversion(builder, cal, 'a', syms);
1096: builder.append(' ');
1097: singleDateTimeConversion(builder, cal, 'b', syms);
1098: builder.append(' ');
1099: singleDateTimeConversion(builder, cal, 'd', syms);
1100: builder.append(' ');
1101: singleDateTimeConversion(builder, cal, 'T', syms);
1102: builder.append(' ');
1103: singleDateTimeConversion(builder, cal, 'Z', syms);
1104: builder.append(' ');
1105: singleDateTimeConversion(builder, cal, 'Y', syms);
1106: break;
1107: default:
1108: throw new UnknownFormatConversionException(String.valueOf(conversion));
1109: }
1110:
1111: if (digits > 0)
1112: {
1113: int newLen = builder.length();
1114: int delta = newLen - oldLen;
1115: while (delta++ < digits)
1116: builder.insert(oldLen, '0');
1117: }
1118: }
1119:
1120:
1131: private void dateTimeConversion(Object arg, int flags, int width,
1132: int precision, char conversion,
1133: char subConversion)
1134: throws IOException
1135: {
1136: noPrecision(precision);
1137: checkFlags(flags,
1138: FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
1139: conversion);
1140:
1141: Calendar cal;
1142: if (arg instanceof Calendar)
1143: cal = (Calendar) arg;
1144: else
1145: {
1146: Date date;
1147: if (arg instanceof Date)
1148: date = (Date) arg;
1149: else if (arg instanceof Long)
1150: date = new Date(((Long) arg).longValue());
1151: else
1152: throw new IllegalFormatConversionException(conversion,
1153: arg.getClass());
1154: if (fmtLocale == null)
1155: cal = Calendar.getInstance();
1156: else
1157: cal = Calendar.getInstance(fmtLocale);
1158: cal.setTime(date);
1159: }
1160:
1161:
1162: DateFormatSymbols syms;
1163: if (fmtLocale == null)
1164: syms = new DateFormatSymbols();
1165: else
1166: syms = new DateFormatSymbols(fmtLocale);
1167:
1168: CPStringBuilder result = new CPStringBuilder();
1169: singleDateTimeConversion(result, cal, subConversion, syms);
1170:
1171: genericFormat(result.toString(), flags, width, precision);
1172: }
1173:
1174:
1180: private void advance()
1181: {
1182: ++index;
1183: if (index >= length)
1184: {
1185:
1186: throw new IllegalArgumentException();
1187: }
1188: }
1189:
1190:
1196: private int parseInt()
1197: {
1198: int start = index;
1199: while (Character.isDigit(format.charAt(index)))
1200: advance();
1201: if (start == index)
1202: return -1;
1203: return Integer.parseInt(format.substring(start, index));
1204: }
1205:
1206:
1213: private int parseArgumentIndex()
1214: {
1215: int result = -1;
1216: int start = index;
1217: if (format.charAt(index) == '<')
1218: {
1219: result = 0;
1220: advance();
1221: }
1222: else if (Character.isDigit(format.charAt(index)))
1223: {
1224: result = parseInt();
1225: if (format.charAt(index) == '$')
1226: advance();
1227: else
1228: {
1229:
1230: index = start;
1231: result = -1;
1232: }
1233: }
1234: return result;
1235: }
1236:
1237:
1244: private int parseFlags()
1245: {
1246: int value = 0;
1247: int start = index;
1248: while (true)
1249: {
1250: int x = FLAGS.indexOf(format.charAt(index));
1251: if (x == -1)
1252: break;
1253: int newValue = 1 << x;
1254: if ((value & newValue) != 0)
1255: throw new DuplicateFormatFlagsException(format.substring(start,
1256: index + 1));
1257: value |= newValue;
1258: advance();
1259: }
1260: return value;
1261: }
1262:
1263:
1269: private int parseWidth()
1270: {
1271: return parseInt();
1272: }
1273:
1274:
1280: private int parsePrecision()
1281: {
1282: if (format.charAt(index) != '.')
1283: return -1;
1284: advance();
1285: int precision = parseInt();
1286: if (precision == -1)
1287:
1288: throw new IllegalArgumentException();
1289: return precision;
1290: }
1291:
1292:
1309: public Formatter format(Locale loc, String fmt, Object... args)
1310: {
1311: if (closed)
1312: throw new FormatterClosedException();
1313:
1314:
1315: int implicitArgumentIndex = 1;
1316: int previousArgumentIndex = 0;
1317:
1318: try
1319: {
1320: fmtLocale = loc;
1321: format = fmt;
1322: length = format.length();
1323: for (index = 0; index < length; ++index)
1324: {
1325: char c = format.charAt(index);
1326: if (c != '%')
1327: {
1328: out.append(c);
1329: continue;
1330: }
1331:
1332: int start = index;
1333: advance();
1334:
1335:
1336:
1337:
1338: int argumentIndex = parseArgumentIndex();
1339:
1340: int flags = parseFlags();
1341: int width = parseWidth();
1342: int precision = parsePrecision();
1343: char origConversion = format.charAt(index);
1344: char conversion = origConversion;
1345: if (Character.isUpperCase(conversion))
1346: {
1347: flags |= FormattableFlags.UPPERCASE;
1348: conversion = Character.toLowerCase(conversion);
1349: }
1350:
1351: Object argument = null;
1352: if (conversion == '%' || conversion == 'n')
1353: {
1354: if (argumentIndex != -1)
1355: {
1356:
1357: throw new UnknownFormatConversionException("FIXME");
1358: }
1359: }
1360: else
1361: {
1362: if (argumentIndex == -1)
1363: argumentIndex = implicitArgumentIndex++;
1364: else if (argumentIndex == 0)
1365: argumentIndex = previousArgumentIndex;
1366:
1367: --argumentIndex;
1368: if (args != null)
1369: {
1370: if (argumentIndex < 0 || argumentIndex >= args.length)
1371: throw new MissingFormatArgumentException(format.substring(start, index));
1372: argument = args[argumentIndex];
1373: }
1374: }
1375:
1376: switch (conversion)
1377: {
1378: case 'b':
1379: booleanFormat(argument, flags, width, precision,
1380: origConversion);
1381: break;
1382: case 'h':
1383: hashCodeFormat(argument, flags, width, precision,
1384: origConversion);
1385: break;
1386: case 's':
1387: stringFormat(argument, flags, width, precision,
1388: origConversion);
1389: break;
1390: case 'c':
1391: characterFormat(argument, flags, width, precision,
1392: origConversion);
1393: break;
1394: case 'd':
1395: checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'd');
1396: decimalConversion(argument, flags, width, precision,
1397: origConversion);
1398: break;
1399: case 'o':
1400: checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'o');
1401: hexOrOctalConversion(argument, flags, width, precision, 8,
1402: origConversion);
1403: break;
1404: case 'x':
1405: hexOrOctalConversion(argument, flags, width, precision, 16,
1406: origConversion);
1407: case 'e':
1408:
1409: break;
1410: case 'f':
1411:
1412: break;
1413: case 'g':
1414:
1415: break;
1416: case 'a':
1417:
1418: break;
1419: case 't':
1420: advance();
1421: char subConversion = format.charAt(index);
1422: dateTimeConversion(argument, flags, width, precision,
1423: origConversion, subConversion);
1424: break;
1425: case '%':
1426: percentFormat(flags, width, precision);
1427: break;
1428: case 'n':
1429: newLineFormat(flags, width, precision);
1430: break;
1431: default:
1432: throw new UnknownFormatConversionException(String.valueOf(origConversion));
1433: }
1434: }
1435: }
1436: catch (IOException exc)
1437: {
1438: ioException = exc;
1439: }
1440: return this;
1441: }
1442:
1443:
1455: public Formatter format(String format, Object... args)
1456: {
1457: return format(locale, format, args);
1458: }
1459:
1460:
1467: public IOException ioException()
1468: {
1469: return ioException;
1470: }
1471:
1472:
1478: public Locale locale()
1479: {
1480: if (closed)
1481: throw new FormatterClosedException();
1482: return locale;
1483: }
1484:
1485:
1491: public Appendable out()
1492: {
1493: if (closed)
1494: throw new FormatterClosedException();
1495: return out;
1496: }
1497:
1498:
1507: public String toString()
1508: {
1509: if (closed)
1510: throw new FormatterClosedException();
1511: return out.toString();
1512: }
1513: }