001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.format;
017:
018: import java.io.IOException;
019: import java.io.Writer;
020:
021: /**
022: * Utility methods used by formatters.
023: * <p>
024: * FormatUtils is thread-safe and immutable.
025: *
026: * @author Brian S O'Neill
027: * @since 1.0
028: */
029: public class FormatUtils {
030:
031: private static final double LOG_10 = Math.log(10);
032:
033: /**
034: * Restricted constructor.
035: */
036: private FormatUtils() {
037: }
038:
039: /**
040: * Converts an integer to a string, prepended with a variable amount of '0'
041: * pad characters, and appends it to the given buffer.
042: *
043: * <p>This method is optimized for converting small values to strings.
044: *
045: * @param buf receives integer converted to a string
046: * @param value value to convert to a string
047: * @param size minumum amount of digits to append
048: */
049: public static void appendPaddedInteger(StringBuffer buf, int value,
050: int size) {
051: if (value < 0) {
052: buf.append('-');
053: if (value != Integer.MIN_VALUE) {
054: value = -value;
055: } else {
056: for (; size > 10; size--) {
057: buf.append('0');
058: }
059: buf.append("" + -(long) Integer.MIN_VALUE);
060: return;
061: }
062: }
063: if (value < 10) {
064: for (; size > 1; size--) {
065: buf.append('0');
066: }
067: buf.append((char) (value + '0'));
068: } else if (value < 100) {
069: for (; size > 2; size--) {
070: buf.append('0');
071: }
072: // Calculate value div/mod by 10 without using two expensive
073: // division operations. (2 ^ 27) / 10 = 13421772. Add one to
074: // value to correct rounding error.
075: int d = ((value + 1) * 13421772) >> 27;
076: buf.append((char) (d + '0'));
077: // Append remainder by calculating (value - d * 10).
078: buf.append((char) (value - (d << 3) - (d << 1) + '0'));
079: } else {
080: int digits;
081: if (value < 1000) {
082: digits = 3;
083: } else if (value < 10000) {
084: digits = 4;
085: } else {
086: digits = (int) (Math.log(value) / LOG_10) + 1;
087: }
088: for (; size > digits; size--) {
089: buf.append('0');
090: }
091: buf.append(Integer.toString(value));
092: }
093: }
094:
095: /**
096: * Converts an integer to a string, prepended with a variable amount of '0'
097: * pad characters, and appends it to the given buffer.
098: *
099: * <p>This method is optimized for converting small values to strings.
100: *
101: * @param buf receives integer converted to a string
102: * @param value value to convert to a string
103: * @param size minumum amount of digits to append
104: */
105: public static void appendPaddedInteger(StringBuffer buf,
106: long value, int size) {
107: int intValue = (int) value;
108: if (intValue == value) {
109: appendPaddedInteger(buf, intValue, size);
110: } else if (size <= 19) {
111: buf.append(Long.toString(value));
112: } else {
113: if (value < 0) {
114: buf.append('-');
115: if (value != Long.MIN_VALUE) {
116: value = -value;
117: } else {
118: for (; size > 19; size--) {
119: buf.append('0');
120: }
121: buf.append("9223372036854775808");
122: return;
123: }
124: }
125: int digits = (int) (Math.log(value) / LOG_10) + 1;
126: for (; size > digits; size--) {
127: buf.append('0');
128: }
129: buf.append(Long.toString(value));
130: }
131: }
132:
133: /**
134: * Converts an integer to a string, prepended with a variable amount of '0'
135: * pad characters, and writes it to the given writer.
136: *
137: * <p>This method is optimized for converting small values to strings.
138: *
139: * @param out receives integer converted to a string
140: * @param value value to convert to a string
141: * @param size minumum amount of digits to append
142: */
143: public static void writePaddedInteger(Writer out, int value,
144: int size) throws IOException {
145: if (value < 0) {
146: out.write('-');
147: if (value != Integer.MIN_VALUE) {
148: value = -value;
149: } else {
150: for (; size > 10; size--) {
151: out.write('0');
152: }
153: out.write("" + -(long) Integer.MIN_VALUE);
154: return;
155: }
156: }
157: if (value < 10) {
158: for (; size > 1; size--) {
159: out.write('0');
160: }
161: out.write(value + '0');
162: } else if (value < 100) {
163: for (; size > 2; size--) {
164: out.write('0');
165: }
166: // Calculate value div/mod by 10 without using two expensive
167: // division operations. (2 ^ 27) / 10 = 13421772. Add one to
168: // value to correct rounding error.
169: int d = ((value + 1) * 13421772) >> 27;
170: out.write(d + '0');
171: // Append remainder by calculating (value - d * 10).
172: out.write(value - (d << 3) - (d << 1) + '0');
173: } else {
174: int digits;
175: if (value < 1000) {
176: digits = 3;
177: } else if (value < 10000) {
178: digits = 4;
179: } else {
180: digits = (int) (Math.log(value) / LOG_10) + 1;
181: }
182: for (; size > digits; size--) {
183: out.write('0');
184: }
185: out.write(Integer.toString(value));
186: }
187: }
188:
189: /**
190: * Converts an integer to a string, prepended with a variable amount of '0'
191: * pad characters, and writes it to the given writer.
192: *
193: * <p>This method is optimized for converting small values to strings.
194: *
195: * @param out receives integer converted to a string
196: * @param value value to convert to a string
197: * @param size minumum amount of digits to append
198: */
199: public static void writePaddedInteger(Writer out, long value,
200: int size) throws IOException {
201: int intValue = (int) value;
202: if (intValue == value) {
203: writePaddedInteger(out, intValue, size);
204: } else if (size <= 19) {
205: out.write(Long.toString(value));
206: } else {
207: if (value < 0) {
208: out.write('-');
209: if (value != Long.MIN_VALUE) {
210: value = -value;
211: } else {
212: for (; size > 19; size--) {
213: out.write('0');
214: }
215: out.write("9223372036854775808");
216: return;
217: }
218: }
219: int digits = (int) (Math.log(value) / LOG_10) + 1;
220: for (; size > digits; size--) {
221: out.write('0');
222: }
223: out.write(Long.toString(value));
224: }
225: }
226:
227: /**
228: * Converts an integer to a string, and appends it to the given buffer.
229: *
230: * <p>This method is optimized for converting small values to strings.
231: *
232: * @param buf receives integer converted to a string
233: * @param value value to convert to a string
234: */
235: public static void appendUnpaddedInteger(StringBuffer buf, int value) {
236: if (value < 0) {
237: buf.append('-');
238: if (value != Integer.MIN_VALUE) {
239: value = -value;
240: } else {
241: buf.append("" + -(long) Integer.MIN_VALUE);
242: return;
243: }
244: }
245: if (value < 10) {
246: buf.append((char) (value + '0'));
247: } else if (value < 100) {
248: // Calculate value div/mod by 10 without using two expensive
249: // division operations. (2 ^ 27) / 10 = 13421772. Add one to
250: // value to correct rounding error.
251: int d = ((value + 1) * 13421772) >> 27;
252: buf.append((char) (d + '0'));
253: // Append remainder by calculating (value - d * 10).
254: buf.append((char) (value - (d << 3) - (d << 1) + '0'));
255: } else {
256: buf.append(Integer.toString(value));
257: }
258: }
259:
260: /**
261: * Converts an integer to a string, and appends it to the given buffer.
262: *
263: * <p>This method is optimized for converting small values to strings.
264: *
265: * @param buf receives integer converted to a string
266: * @param value value to convert to a string
267: */
268: public static void appendUnpaddedInteger(StringBuffer buf,
269: long value) {
270: int intValue = (int) value;
271: if (intValue == value) {
272: appendUnpaddedInteger(buf, intValue);
273: } else {
274: buf.append(Long.toString(value));
275: }
276: }
277:
278: /**
279: * Converts an integer to a string, and writes it to the given writer.
280: *
281: * <p>This method is optimized for converting small values to strings.
282: *
283: * @param out receives integer converted to a string
284: * @param value value to convert to a string
285: */
286: public static void writeUnpaddedInteger(Writer out, int value)
287: throws IOException {
288: if (value < 0) {
289: out.write('-');
290: if (value != Integer.MIN_VALUE) {
291: value = -value;
292: } else {
293: out.write("" + -(long) Integer.MIN_VALUE);
294: return;
295: }
296: }
297: if (value < 10) {
298: out.write(value + '0');
299: } else if (value < 100) {
300: // Calculate value div/mod by 10 without using two expensive
301: // division operations. (2 ^ 27) / 10 = 13421772. Add one to
302: // value to correct rounding error.
303: int d = ((value + 1) * 13421772) >> 27;
304: out.write(d + '0');
305: // Append remainder by calculating (value - d * 10).
306: out.write(value - (d << 3) - (d << 1) + '0');
307: } else {
308: out.write(Integer.toString(value));
309: }
310: }
311:
312: /**
313: * Converts an integer to a string, and writes it to the given writer.
314: *
315: * <p>This method is optimized for converting small values to strings.
316: *
317: * @param out receives integer converted to a string
318: * @param value value to convert to a string
319: */
320: public static void writeUnpaddedInteger(Writer out, long value)
321: throws IOException {
322: int intValue = (int) value;
323: if (intValue == value) {
324: writeUnpaddedInteger(out, intValue);
325: } else {
326: out.write(Long.toString(value));
327: }
328: }
329:
330: /**
331: * Calculates the number of decimal digits for the given value,
332: * including the sign.
333: */
334: public static int calculateDigitCount(long value) {
335: if (value < 0) {
336: if (value != Long.MIN_VALUE) {
337: return calculateDigitCount(-value) + 1;
338: } else {
339: return 20;
340: }
341: }
342: return (value < 10 ? 1 : (value < 100 ? 2 : (value < 1000 ? 3
343: : (value < 10000 ? 4
344: : ((int) (Math.log(value) / LOG_10) + 1)))));
345: }
346:
347: static int parseTwoDigits(String text, int position) {
348: int value = text.charAt(position) - '0';
349: return ((value << 3) + (value << 1))
350: + text.charAt(position + 1) - '0';
351: }
352:
353: static String createErrorMessage(final String text,
354: final int errorPos) {
355: int sampleLen = errorPos + 32;
356: String sampleText;
357: if (text.length() <= sampleLen + 3) {
358: sampleText = text;
359: } else {
360: sampleText = text.substring(0, sampleLen).concat("...");
361: }
362:
363: if (errorPos <= 0) {
364: return "Invalid format: \"" + sampleText + '"';
365: }
366:
367: if (errorPos >= text.length()) {
368: return "Invalid format: \"" + sampleText
369: + "\" is too short";
370: }
371:
372: return "Invalid format: \"" + sampleText
373: + "\" is malformed at \""
374: + sampleText.substring(errorPos) + '"';
375: }
376:
377: }
|