/core/src/main/java/org/renjin/primitives/text/Formatter.java
Java | 1909 lines | 1037 code | 19 blank | 853 comment | 358 complexity | 40e36d5866f2f6004d18fa0a2adb249e MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-4.0, GPL-2.0, GPL-3.0
Large files files are truncated, but you can click here to view the full file
-
- //
- // (c) 2000 Sun Microsystems, Inc.
- // ALL RIGHTS RESERVED
- //
- // License Grant-
- //
- //
- // Permission to use, copy, modify, and distribute this Software and its
- // documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
- // hereby granted.
- //
- // This Software is provided "AS IS". All express warranties, including any
- // implied warranty of merchantability, satisfactory quality, fitness for a
- // particular purpose, or non-infringement, are disclaimed, except to the extent
- // that such disclaimers are held to be legally invalid.
- //
- // You acknowledge that Software is not designed, licensed or intended for use in
- // the design, construction, operation or maintenance of any nuclear facility
- // ("High Risk Activities"). Sun disclaims any express or implied warranty of
- // fitness for such uses.
- //
- // Please refer to the file http://www.sun.com/policies/trademarks/ for further
- // important trademark information and to
- // http://java.sun.com/nav/business/index.html for further important licensing
- // information for the Java Technology.
- //
-
-
- // Source: http://java.sun.com/developer/technicalArticles/Programming/sprintf/
- // Adapted to match the R Language
-
- package org.renjin.primitives.text;
-
- import java.text.DecimalFormatSymbols;
- import java.util.Enumeration;
- import java.util.Locale;
- import java.util.Vector;
-
- import org.renjin.eval.EvalException;
- import org.renjin.sexp.AtomicVector;
- import org.renjin.sexp.DoubleVector;
- import org.renjin.sexp.IntVector;
- import org.renjin.sexp.LogicalVector;
- import org.renjin.sexp.SEXP;
- import org.renjin.sexp.StringVector;
-
-
- /**
- * PrintfFormat allows the formatting of an array of
- * objects embedded within a string. Primitive types
- * must be passed using wrapper types. The formatting
- * is controlled by a control string.
- *<p>
- * A control string is a Java string that contains a
- * control specification. The control specification
- * starts at the first percent sign (%) in the string,
- * provided that this percent sign
- *<ol>
- *<li>is not escaped protected by a matching % or is
- * not an escape % character,
- *<li>is not at the end of the format string, and
- *<li>precedes a sequence of characters that parses as
- * a valid control specification.
- *</ol>
- *</p><p>
- * A control specification usually takes the form:
- *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
- * { [hlL] }+ [idfgGoxXeEcs]
- *</pre>
- * There are variants of this basic form that are
- * discussed below.</p>
- *<p>
- * The format is composed of zero or more directives
- * defined as follows:
- *<ul>
- *<li>ordinary characters, which are simply copied to
- * the output stream;
- *<li>escape sequences, which represent non-graphic
- * characters; and
- *<li>conversion specifications, each of which
- * results in the fetching of zero or more arguments.
- *</ul></p>
- *<p>
- * The results are undefined if there are insufficient
- * arguments for the format. Usually an unchecked
- * exception will be thrown. If the format is
- * exhausted while arguments remain, the excess
- * arguments are evaluated but are otherwise ignored.
- * In format strings containing the % form of
- * conversion specifications, each argument in the
- * argument list is used exactly once.</p>
- * <p>
- * Conversions can be applied to the <code>n</code>th
- * argument after the format in the argument list,
- * rather than to the next unused argument. In this
- * case, the conversion characer % is replaced by the
- * sequence %<code>n</code>$, where <code>n</code> is
- * a decimal integer giving the position of the
- * argument in the argument list.</p>
- * <p>
- * In format strings containing the %<code>n</code>$
- * form of conversion specifications, each argument
- * in the argument list is used exactly once.</p>
- *
- *<h4>Escape Sequences</h4>
- *<p>
- * The following table lists escape sequences and
- * associated actions on display devices capable of
- * the action.
- *<table>
- *<tr><th align=left>Sequence</th>
- * <th align=left>Name</th>
- * <th align=left>Description</th></tr>
- *<tr><td>\\</td><td>backlash</td><td>None.
- *</td></tr>
- *<tr><td>\a</td><td>alert</td><td>Attempts to alert
- * the user through audible or visible
- * notification.
- *</td></tr>
- *<tr><td>\b</td><td>backspace</td><td>Moves the
- * printing position to one column before
- * the current position, unless the
- * current position is the start of a line.
- *</td></tr>
- *<tr><td>\f</td><td>form-feed</td><td>Moves the
- * printing position to the initial
- * printing position of the next logical
- * page.
- *</td></tr>
- *<tr><td>\n</td><td>newline</td><td>Moves the
- * printing position to the start of the
- * next line.
- *</td></tr>
- *<tr><td>\r</td><td>carriage-return</td><td>Moves
- * the printing position to the start of
- * the current line.
- *</td></tr>
- *<tr><td>\t</td><td>tab</td><td>Moves the printing
- * position to the next implementation-
- * defined horizontal tab position.
- *</td></tr>
- *<tr><td>\v</td><td>vertical-tab</td><td>Moves the
- * printing position to the start of the
- * next implementation-defined vertical
- * tab position.
- *</td></tr>
- *</table></p>
- *<h4>Conversion Specifications</h4>
- *<p>
- * Each conversion specification is introduced by
- * the percent sign character (%). After the character
- * %, the following appear in sequence:</p>
- *<p>
- * Zero or more flags (in any order), which modify the
- * meaning of the conversion specification.</p>
- *<p>
- * An optional minimum field width. If the converted
- * value has fewer characters than the field width, it
- * will be padded with spaces by default on the left;
- * t will be padded on the right, if the left-
- * adjustment flag (-), described below, is given to
- * the field width. The field width takes the form
- * of a decimal integer. If the conversion character
- * is s, the field width is the the minimum number of
- * characters to be printed.</p>
- *<p>
- * An optional precision that gives the minumum number
- * of digits to appear for the d, i, o, x or X
- * conversions (the field is padded with leading
- * zeros); the number of digits to appear after the
- * radix character for the e, E, and f conversions,
- * the maximum number of significant digits for the g
- * and G conversions; or the maximum number of
- * characters to be written from a string is s and S
- * conversions. The precision takes the form of an
- * optional decimal digit string, where a null digit
- * string is treated as 0. If a precision appears
- * with a c conversion character the precision is
- * ignored.
- * </p>
- *<p>
- * An optional h specifies that a following d, i, o,
- * x, or X conversion character applies to a type
- * short argument (the argument will be promoted
- * according to the integral promotions and its value
- * converted to type short before printing).</p>
- *<p>
- * An optional l (ell) specifies that a following
- * d, i, o, x, or X conversion character applies to a
- * type long argument.</p>
- *<p>
- * A field width or precision may be indicated by an
- * asterisk (*) instead of a digit string. In this
- * case, an integer argument supplised the field width
- * precision. The argument that is actually converted
- * is not fetched until the conversion letter is seen,
- * so the the arguments specifying field width or
- * precision must appear before the argument (if any)
- * to be converted. If the precision argument is
- * negative, it will be changed to zero. A negative
- * field width argument is taken as a - flag, followed
- * by a positive field width.</p>
- * <p>
- * In format strings containing the %<code>n</code>$
- * form of a conversion specification, a field width
- * or precision may be indicated by the sequence
- * *<code>m</code>$, where m is a decimal integer
- * giving the position in the argument list (after the
- * format argument) of an integer argument containing
- * the field width or precision.</p>
- * <p>
- * The format can contain either numbered argument
- * specifications (that is, %<code>n</code>$ and
- * *<code>m</code>$), or unnumbered argument
- * specifications (that is % and *), but normally not
- * both. The only exception to this is that %% can
- * be mixed with the %<code>n</code>$ form. The
- * results of mixing numbered and unnumbered argument
- * specifications in a format string are undefined.</p>
- *
- *<h4>Flag Characters</h4>
- *<p>
- * The flags and their meanings are:</p>
- *<dl>
- * <dt>'<dd> integer portion of the result of a
- * decimal conversion (%i, %d, %f, %g, or %G) will
- * be formatted with thousands' grouping
- * characters. For other conversions the flag
- * is ignored. The non-monetary grouping
- * character is used.
- * <dt>-<dd> result of the conversion is left-justified
- * within the field. (It will be right-justified
- * if this flag is not specified).</td></tr>
- * <dt>+<dd> result of a signed conversion always
- * begins with a sign (+ or -). (It will begin
- * with a sign only when a negative value is
- * converted if this flag is not specified.)
- * <dt><space><dd> If the first character of a
- * signed conversion is not a sign, a space
- * character will be placed before the result.
- * This means that if the space character and +
- * flags both appear, the space flag will be
- * ignored.
- * <dt>#<dd> value is to be converted to an alternative
- * form. For c, d, i, and s conversions, the flag
- * has no effect. For o conversion, it increases
- * the precision to force the first digit of the
- * result to be a zero. For x or X conversion, a
- * non-zero result has 0x or 0X prefixed to it,
- * respectively. For e, E, f, g, and G
- * conversions, the result always contains a radix
- * character, even if no digits follow the radix
- * character (normally, a decimal point appears in
- * the result of these conversions only if a digit
- * follows it). For g and G conversions, trailing
- * zeros will not be removed from the result as
- * they normally are.
- * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
- * conversions, leading zeros (following any
- * indication of sign or base) are used to pad to
- * the field width; no space padding is
- * performed. If the 0 and - flags both appear,
- * the 0 flag is ignored. For d, i, o, x, and X
- * conversions, if a precision is specified, the
- * 0 flag will be ignored. For c conversions,
- * the flag is ignored.
- *</dl>
- *
- *<h4>Conversion Characters</h4>
- *<p>
- * Each conversion character results in fetching zero
- * or more arguments. The results are undefined if
- * there are insufficient arguments for the format.
- * Usually, an unchecked exception will be thrown.
- * If the format is exhausted while arguments remain,
- * the excess arguments are ignored.</p>
- *
- *<p>
- * The conversion characters and their meanings are:
- *</p>
- *<dl>
- * <dt>d,i<dd>The int argument is converted to a
- * signed decimal in the style [-]dddd. The
- * precision specifies the minimum number of
- * digits to appear; if the value being
- * converted can be represented in fewer
- * digits, it will be expanded with leading
- * zeros. The default precision is 1. The
- * result of converting 0 with an explicit
- * precision of 0 is no characters.
- * <dt>o<dd> The int argument is converted to unsigned
- * octal format in the style ddddd. The
- * precision specifies the minimum number of
- * digits to appear; if the value being
- * converted can be represented in fewer
- * digits, it will be expanded with leading
- * zeros. The default precision is 1. The
- * result of converting 0 with an explicit
- * precision of 0 is no characters.
- * <dt>x<dd> The int argument is converted to unsigned
- * hexadecimal format in the style dddd; the
- * letters abcdef are used. The precision
- * specifies the minimum numberof digits to
- * appear; if the value being converted can be
- * represented in fewer digits, it will be
- * expanded with leading zeros. The default
- * precision is 1. The result of converting 0
- * with an explicit precision of 0 is no
- * characters.
- * <dt>X<dd> Behaves the same as the x conversion
- * character except that letters ABCDEF are
- * used instead of abcdef.
- * <dt>f<dd> The floating point number argument is
- * written in decimal notation in the style
- * [-]ddd.ddd, where the number of digits after
- * the radix character (shown here as a decimal
- * point) is equal to the precision
- * specification. A Locale is used to determine
- * the radix character to use in this format.
- * If the precision is omitted from the
- * argument, six digits are written after the
- * radix character; if the precision is
- * explicitly 0 and the # flag is not specified,
- * no radix character appears. If a radix
- * character appears, at least 1 digit appears
- * before it. The value is rounded to the
- * appropriate number of digits.
- * <dt>e,E<dd>The floating point number argument is
- * written in the style [-]d.ddde{+-}dd
- * (the symbols {+-} indicate either a plus or
- * minus sign), where there is one digit before
- * the radix character (shown here as a decimal
- * point) and the number of digits after it is
- * equal to the precision. A Locale is used to
- * determine the radix character to use in this
- * format. When the precision is missing, six
- * digits are written after the radix character;
- * if the precision is 0 and the # flag is not
- * specified, no radix character appears. The
- * E conversion will produce a number with E
- * instead of e introducing the exponent. The
- * exponent always contains at least two digits.
- * However, if the value to be written requires
- * an exponent greater than two digits,
- * additional exponent digits are written as
- * necessary. The value is rounded to the
- * appropriate number of digits.
- * <dt>g,G<dd>The floating point number argument is
- * written in style f or e (or in sytle E in the
- * case of a G conversion character), with the
- * precision specifying the number of
- * significant digits. If the precision is
- * zero, it is taken as one. The style used
- * depends on the value converted: style e
- * (or E) will be used only if the exponent
- * resulting from the conversion is less than
- * -4 or greater than or equal to the precision.
- * Trailing zeros are removed from the result.
- * A radix character appears only if it is
- * followed by a digit.
- * <dt>c,C<dd>The integer argument is converted to a
- * char and the result is written.
- *
- * <dt>s,S<dd>The argument is taken to be a string and
- * bytes from the string are written until the
- * end of the string or the number of bytes
- * indicated by the precision specification of
- * the argument is reached. If the precision
- * is omitted from the argument, it is taken to
- * be infinite, so all characters up to the end
- * of the string are written.
- * <dt>%<dd>Write a % character; no argument is
- * converted.
- *</dl>
- *<p>
- * If a conversion specification does not match one of
- * the above forms, an IllegalArgumentException is
- * thrown and the instance of PrintfFormat is not
- * created.</p>
- *<p>
- * If a floating point value is the internal
- * representation for infinity, the output is
- * [+]Infinity, where Infinity is either Infinity or
- * Inf, depending on the desired output string length.
- * Printing of the sign follows the rules described
- * above.</p>
- *<p>
- * If a floating point value is the internal
- * representation for "not-a-number," the output is
- * [+]NaN. Printing of the sign follows the rules
- * described above.</p>
- *<p>
- * In no case does a non-existent or small field width
- * cause truncation of a field; if the result of a
- * conversion is wider than the field width, the field
- * is simply expanded to contain the conversion result.
- *</p>
- *<p>
- * The behavior is like printf. One exception is that
- * the minimum number of exponent digits is 3 instead
- * of 2 for e and E formats when the optional L is used
- * before the e, E, g, or G conversion character. The
- * optional L does not imply conversion to a long long
- * double. </p>
- * <p>
- * The biggest divergence from the C printf
- * specification is in the use of 16 bit characters.
- * This allows the handling of characters beyond the
- * small ASCII character set and allows the utility to
- * interoperate correctly with the rest of the Java
- * runtime environment.</p>
- *<p>
- * Omissions from the C printf specification are
- * numerous. All the known omissions are present
- * because Java never uses bytes to represent
- * characters and does not have pointers:</p>
- *<ul>
- * <li>%c is the same as %C.
- * <li>%s is the same as %S.
- * <li>u, p, and n conversion characters.
- * <li>%ws format.
- * <li>h modifier applied to an n conversion character.
- * <li>l (ell) modifier applied to the c, n, or s
- * conversion characters.
- * <li>ll (ell ell) modifier to d, i, o, u, x, or X
- * conversion characters.
- * <li>ll (ell ell) modifier to an n conversion
- * character.
- * <li>c, C, d,i,o,u,x, and X conversion characters
- * apply to Byte, Character, Short, Integer, Long
- * types.
- * <li>f, e, E, g, and G conversion characters apply
- * to Float and Double types.
- * <li>s and S conversion characters apply to String
- * types.
- * <li>All other reference types can be formatted
- * using the s or S conversion characters only.
- *</ul>
- * <p>
- * Most of this specification is quoted from the Unix
- * man page for the sprintf utility.</p>
- *
- * @author Allan Jacobs
- * @version 1
- * Release 1: Initial release.
- * Release 2: Asterisk field widths and precisions
- * %n$ and *m$
- * Bug fixes
- * g format fix (2 digits in e form corrupt)
- * rounding in f format implemented
- * round up when digit not printed is 5
- * formatting of -0.0f
- * round up/down when last digits are 50000...
- */
- public class Formatter {
- /**
- * Constructs an array of control specifications
- * possibly preceded, separated, or followed by
- * ordinary strings. Control strings begin with
- * unpaired percent signs. A pair of successive
- * percent signs designates a single percent sign in
- * the format.
- * @param fmtArg Control string.
- * @exception IllegalArgumentException if the control
- * string is null, zero length, or otherwise
- * malformed.
- */
- public Formatter(String fmtArg)
- throws IllegalArgumentException {
- this(Locale.getDefault(),fmtArg);
- }
- /**
- * Constructs an array of control specifications
- * possibly preceded, separated, or followed by
- * ordinary strings. Control strings begin with
- * unpaired percent signs. A pair of successive
- * percent signs designates a single percent sign in
- * the format.
- * @param fmtArg Control string.
- * @exception IllegalArgumentException if the control
- * string is null, zero length, or otherwise
- * malformed.
- */
- public Formatter(Locale locale, String fmtArg)
- throws IllegalArgumentException {
- dfs = new DecimalFormatSymbols(locale);
- int ePos=0;
- ConversionSpecification sFmt=null;
- String unCS = this.nonControl(fmtArg,0);
- if (unCS!=null) {
- sFmt = new ConversionSpecification();
- sFmt.setLiteral(unCS);
- vFmt.addElement(sFmt);
- }
- while(cPos!=-1 && cPos<fmtArg.length()) {
- for (ePos=cPos+1; ePos<fmtArg.length();
- ePos++) {
- char c=0;
- c = fmtArg.charAt(ePos);
- if (c == 'i') break;
- if (c == 'd') break;
- if (c == 'f') break;
- if (c == 'g') break;
- if (c == 'G') break;
- if (c == 'o') break;
- if (c == 'x') break;
- if (c == 'X') break;
- if (c == 'e') break;
- if (c == 'E') break;
- if (c == 'c') break;
- if (c == 's') break;
- if (c == '%') break;
- }
- ePos=Math.min(ePos+1,fmtArg.length());
- sFmt = new ConversionSpecification(
- fmtArg.substring(cPos,ePos));
- vFmt.addElement(sFmt);
- unCS = this.nonControl(fmtArg,ePos);
- if (unCS!=null) {
- sFmt = new ConversionSpecification();
- sFmt.setLiteral(unCS);
- vFmt.addElement(sFmt);
- }
- }
- }
- /**
- * Return a substring starting at
- * <code>start</code> and ending at either the end
- * of the String <code>s</code>, the next unpaired
- * percent sign, or at the end of the String if the
- * last character is a percent sign.
- * @param s Control string.
- * @param start Position in the string
- * <code>s</code> to begin looking for the start
- * of a control string.
- * @return the substring from the start position
- * to the beginning of the control string.
- */
- private String nonControl(String s,int start) {
- String ret="";
- cPos=s.indexOf("%",start);
- if (cPos==-1) cPos=s.length();
- return s.substring(start,cPos);
- }
-
- public boolean isFormattedString(int argIndex) {
- Enumeration e = vFmt.elements();
- ConversionSpecification cs = null;
- char c = 0;
- int i=0;
- while (e.hasMoreElements()) {
- cs = (ConversionSpecification)
- e.nextElement();
- c = cs.getConversionCharacter();
- if (c!='\0' && c!='%') {
- if (cs.isPositionalSpecification()) {
- i=cs.getArgumentPosition()-1;
- } else {
- if (cs.isVariableFieldWidth()) {
- i++;
- }
- if (cs.isVariablePrecision()) {
- i++;
- }
- }
-
- if(argIndex == i) {
- return c == 's';
- }
- if (!cs.isPositionalSpecification())
- i++;
- }
- }
- return false;
-
- }
-
-
- /**
- * Format an array of objects. Byte, Short,
- * Integer, Long, Float, Double, and Character
- * arguments are treated as wrappers for primitive
- * types.
- * @param o The array of objects to format.
- * @param rho
- * @param context
- * @return The formatted String.
- */
- public String sprintf(AtomicVector[] o, int cycleIndex) {
- Enumeration e = vFmt.elements();
- ConversionSpecification cs = null;
- char c = 0;
- int i=0;
- StringBuffer sb=new StringBuffer();
- while (e.hasMoreElements()) {
- cs = (ConversionSpecification)
- e.nextElement();
- c = cs.getConversionCharacter();
- if (c=='\0') sb.append(cs.getLiteral());
- else if (c=='%') sb.append("%");
- else {
- if (cs.isPositionalSpecification()) {
- i=cs.getArgumentPosition()-1;
- if (cs.isPositionalFieldWidth()) {
- int ifw=cs.getArgumentPositionForFieldWidth()-1;
- cs.setFieldWidthWithArg( getInteger(o, ifw, cycleIndex) );
- }
- if (cs.isPositionalPrecision()) {
- int ipr=cs.getArgumentPositionForPrecision()-1;
- cs.setPrecisionWithArg( getInteger(o, ipr, cycleIndex) );
- }
- }
- else {
- if (cs.isVariableFieldWidth()) {
- cs.setFieldWidthWithArg( getInteger(o, i, cycleIndex));
- i++;
- }
- if (cs.isVariablePrecision()) {
- cs.setPrecisionWithArg( getInteger(o, i, cycleIndex));
- i++;
- }
- }
- AtomicVector vector = o[i];
-
- // handle recycling: the same argument may be used
- // over and over again if multiple format strings are provided
- int j = cycleIndex % vector.length();
-
- if(vector.isElementNA(j)) {
- sb.append("NA");
- } else if(vector instanceof DoubleVector) {
- sb.append(cs.internalsprintf(vector.getElementAsDouble(j)));
- } else if(vector instanceof IntVector) {
- sb.append(cs.internalsprintf(vector.getElementAsInt(j)));
- } else if(vector instanceof StringVector) {
- sb.append(cs.internalsprintf(vector.getElementAsString(j)));
- } else {
- throw new EvalException("Cannot use '%s' as an sprintf argument", vector.getTypeName());
- }
- if (!cs.isPositionalSpecification())
- i++;
- }
- }
- return sb.toString();
- }
-
- private int getInteger(AtomicVector[] o, int i, int cycleIndex) {
- SEXP exp = o[i];
- if(exp instanceof LogicalVector || exp instanceof DoubleVector || exp instanceof IntVector) {
- int j = cycleIndex % exp.length();
- return ((AtomicVector)exp).getElementAsInt(j);
- } else {
- throw new EvalException("expected integer at argument %d", i+1);
- }
- }
-
- /**
- *<p>
- * ConversionSpecification allows the formatting of
- * a single primitive or object embedded within a
- * string. The formatting is controlled by a
- * format string. Only one Java primitive or
- * object can be formatted at a time.
- *<p>
- * A format string is a Java string that contains
- * a control string. The control string starts at
- * the first percent sign (%) in the string,
- * provided that this percent sign
- *<ol>
- *<li>is not escaped protected by a matching % or
- * is not an escape % character,
- *<li>is not at the end of the format string, and
- *<li>precedes a sequence of characters that parses
- * as a valid control string.
- *</ol>
- *<p>
- * A control string takes the form:
- *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
- * { [hlL] }+ [idfgGoxXeEcs]
- *</pre>
- *<p>
- * The behavior is like printf. One (hopefully the
- * only) exception is that the minimum number of
- * exponent digits is 3 instead of 2 for e and E
- * formats when the optional L is used before the
- * e, E, g, or G conversion character. The
- * optional L does not imply conversion to a long
- * long double.
- */
- public class ConversionSpecification {
- /**
- * Constructor. Used to prepare an instance
- * to hold a literal, not a control string.
- */
- ConversionSpecification() { }
- /**
- * Constructor for a conversion specification.
- * The argument must begin with a % and end
- * with the conversion character for the
- * conversion specification.
- * @param fmtArg String specifying the
- * conversion specification.
- * @exception IllegalArgumentException if the
- * input string is null, zero length, or
- * otherwise malformed.
- */
- ConversionSpecification(String fmtArg)
- throws IllegalArgumentException {
- if (fmtArg==null)
- throw new NullPointerException();
- if (fmtArg.length()==0)
- throw new IllegalArgumentException(
- "Control strings must have positive"+
- " lengths.");
- if (fmtArg.charAt(0)=='%') {
- fmt = fmtArg;
- pos=1;
- setArgPosition();
- setFlagCharacters();
- setFieldWidth();
- setPrecision();
- setOptionalHL();
- if (setConversionCharacter()) {
- if (pos==fmtArg.length()) {
- if(leadingZeros&&leftJustify)
- leadingZeros=false;
- if(precisionSet&&leadingZeros){
- if(conversionCharacter=='d'
- ||conversionCharacter=='i'
- ||conversionCharacter=='o'
- ||conversionCharacter=='x')
- {
- leadingZeros=false;
- }
- }
- }
- else
- throw new IllegalArgumentException(
- "Malformed conversion specification="+
- fmtArg);
- }
- else
- throw new IllegalArgumentException(
- "Malformed conversion specification="+
- fmtArg);
- }
- else
- throw new IllegalArgumentException(
- "Control strings must begin with %.");
- }
- /**
- * Set the String for this instance.
- * @param s the String to store.
- */
- void setLiteral(String s) {
- fmt = s;
- }
- /**
- * Get the String for this instance. Translate
- * any escape sequences.
- *
- * @return s the stored String.
- */
- String getLiteral() {
- StringBuffer sb=new StringBuffer();
- int i=0;
- while (i<fmt.length()) {
- if (fmt.charAt(i)=='\\') {
- i++;
- if (i<fmt.length()) {
- char c=fmt.charAt(i);
- switch(c) {
- case 'a':
- sb.append((char)0x07);
- break;
- case 'b':
- sb.append('\b');
- break;
- case 'f':
- sb.append('\f');
- break;
- case 'n':
- sb.append(java.lang.System.getProperty("line.separator"));
- break;
- case 'r':
- sb.append('\r');
- break;
- case 't':
- sb.append('\t');
- break;
- case 'v':
- sb.append((char)0x0b);
- break;
- case '\\':
- sb.append('\\');
- break;
- }
- i++;
- }
- else
- sb.append('\\');
- }
- else
- i++;
- }
- return fmt;
- }
- /**
- * Get the conversion character that tells what
- * type of control character this instance has.
- *
- * @return the conversion character.
- */
- char getConversionCharacter() {
- return conversionCharacter;
- }
- /**
- * Check whether the specifier has a variable
- * field width that is going to be set by an
- * argument.
- * @return <code>true</code> if the conversion
- * uses an * field width; otherwise
- * <code>false</code>.
- */
- boolean isVariableFieldWidth() {
- return variableFieldWidth;
- }
- /**
- * Set the field width with an argument. A
- * negative field width is taken as a - flag
- * followed by a positive field width.
- * @param fw the field width.
- */
- void setFieldWidthWithArg(int fw) {
- if (fw<0) leftJustify = true;
- fieldWidthSet = true;
- fieldWidth = Math.abs(fw);
- }
- /**
- * Check whether the specifier has a variable
- * precision that is going to be set by an
- * argument.
- * @return <code>true</code> if the conversion
- * uses an * precision; otherwise
- * <code>false</code>.
- */
- boolean isVariablePrecision() {
- return variablePrecision;
- }
- /**
- * Set the precision with an argument. A
- * negative precision will be changed to zero.
- * @param pr the precision.
- */
- void setPrecisionWithArg(int pr) {
- precisionSet = true;
- precision = Math.max(pr,0);
- }
- /**
- * Format an int argument using this conversion
- * specification.
- * @param s the int to format.
- * @return the formatted String.
- * @exception IllegalArgumentException if the
- * conversion character is f, e, E, g, or G.
- */
- String internalsprintf(int s)
- throws IllegalArgumentException {
- String s2 = "";
- switch(conversionCharacter) {
- case 'd':
- case 'i':
- if (optionalh)
- s2 = printDFormat((short)s);
- else if (optionall)
- s2 = printDFormat((long)s);
- else
- s2 = printDFormat(s);
- break;
- case 'x':
- case 'X':
- if (optionalh)
- s2 = printXFormat((short)s);
- else if (optionall)
- s2 = printXFormat((long)s);
- else
- s2 = printXFormat(s);
- break;
- case 'o':
- if (optionalh)
- s2 = printOFormat((short)s);
- else if (optionall)
- s2 = printOFormat((long)s);
- else
- s2 = printOFormat(s);
- break;
- case 'c':
- case 'C':
- s2 = printCFormat((char)s);
- break;
- default:
- throw new IllegalArgumentException(
- "Cannot format a int with a format using a "+
- conversionCharacter+
- " conversion character.");
- }
- return s2;
- }
- /**
- * Format a long argument using this conversion
- * specification.
- * @param s the long to format.
- * @return the formatted String.
- * @exception IllegalArgumentException if the
- * conversion character is f, e, E, g, or G.
- */
- String internalsprintf(long s)
- throws IllegalArgumentException {
- String s2 = "";
- switch(conversionCharacter) {
- case 'd':
- case 'i':
- if (optionalh)
- s2 = printDFormat((short)s);
- else if (optionall)
- s2 = printDFormat(s);
- else
- s2 = printDFormat((int)s);
- break;
- case 'x':
- case 'X':
- if (optionalh)
- s2 = printXFormat((short)s);
- else if (optionall)
- s2 = printXFormat(s);
- else
- s2 = printXFormat((int)s);
- break;
- case 'o':
- if (optionalh)
- s2 = printOFormat((short)s);
- else if (optionall)
- s2 = printOFormat(s);
- else
- s2 = printOFormat((int)s);
- break;
- case 'c':
- case 'C':
- s2 = printCFormat((char)s);
- break;
- default:
- throw new IllegalArgumentException(
- "Cannot format a long with a format using a "+
- conversionCharacter+" conversion character.");
- }
- return s2;
- }
- /**
- * Format a double argument using this conversion
- * specification.
- * @param s the double to format.
- * @return the formatted String.
- * @exception IllegalArgumentException if the
- * conversion character is c, C, s, S, i, d,
- * x, X, or o.
- */
- String internalsprintf(double s)
- throws IllegalArgumentException {
- String s2 = "";
- switch(conversionCharacter) {
- case 'f':
- s2 = printFFormat(s);
- break;
- case 'E':
- case 'e':
- s2 = printEFormat(s);
- break;
- case 'G':
- case 'g':
- s2 = printGFormat(s);
- break;
- case 'd':
- s2 = printDFormat((long)s);
- break;
- default:
- throw new IllegalArgumentException("Cannot "+
- "format a double with a format using a "+
- conversionCharacter+" conversion character.");
- }
- return s2;
- }
- /**
- * Format a String argument using this conversion
- * specification.
- * @param s the String to format.
- * @return the formatted String.
- * @exception IllegalArgumentException if the
- * conversion character is neither s nor S.
- */
- String internalsprintf(String s)
- throws IllegalArgumentException {
- String s2 = "";
- if(conversionCharacter=='s'
- || conversionCharacter=='S')
- s2 = printSFormat(s);
- else
- throw new IllegalArgumentException("Cannot "+
- "format a String with a format using a "+
- conversionCharacter+" conversion character.");
- return s2;
- }
- /**
- * Format an Object argument using this conversion
- * specification.
- * @param s the Object to format.
- * @return the formatted String.
- * @exception IllegalArgumentException if the
- * conversion character is neither s nor S.
- */
- String internalsprintf(Object s) {
- String s2 = "";
- if(conversionCharacter=='s'
- || conversionCharacter=='S')
- s2 = printSFormat(s.toString());
- else
- throw new IllegalArgumentException(
- "Cannot format a String with a format using"+
- " a "+conversionCharacter+
- " conversion character.");
- return s2;
- }
- /**
- * For f format, the flag character '-', means that
- * the output should be left justified within the
- * field. The default is to pad with blanks on the
- * left. '+' character means that the conversion
- * will always begin with a sign (+ or -). The
- * blank flag character means that a non-negative
- * input will be preceded with a blank. If both
- * a '+' and a ' ' are specified, the blank flag
- * is ignored. The '0' flag character implies that
- * padding to the field width will be done with
- * zeros instead of blanks.
- *
- * The field width is treated as the minimum number
- * of characters to be printed. The default is to
- * add no padding. Padding is with blanks by
- * default.
- *
- * The precision, if set, is the number of digits
- * to appear after the radix character. Padding is
- * with trailing 0s.
- */
- private char[] fFormatDigits(double x) {
- // int defaultDigits=6;
- String sx,sxOut;
- int i,j,k;
- int n1In,n2In;
- int expon=0;
- boolean minusSign=false;
- if (x>0.0)
- sx = Double.toString(x);
- else if (x<0.0) {
- sx = Double.toString(-x);
- minusSign=true;
- }
- else {
- sx = Double.toString(x);
- if (sx.charAt(0)=='-') {
- minusSign=true;
- sx=sx.substring(1);
- }
- }
- int ePos = sx.indexOf('E');
- int rPos = sx.indexOf('.');
- if (rPos!=-1) n1In=rPos;
- else if (ePos!=-1) n1In=ePos;
- else n1In=sx.length();
- if (rPos!=-1) {
- if (ePos!=-1) n2In = ePos-rPos-1;
- else n2In = sx.length()-rPos-1;
- }
- else
- n2In = 0;
- if (ePos!=-1) {
- int ie=ePos+1;
- expon=0;
- if (sx.charAt(ie)=='-') {
- for (++ie; ie<sx.length(); ie++)
- if (sx.charAt(ie)!='0') break;
- if (ie<sx.length())
- expon=-Integer.parseInt(sx.substring(ie));
- }
- else {
- if (sx.charAt(ie)=='+') ++ie;
- for (; ie<sx.length(); ie++)
- if (sx.charAt(ie)!='0') break;
- if (ie<sx.length())
- expon=Integer.parseInt(sx.substring(ie));
- }
- }
- int p;
- if (precisionSet) p = precision;
- else p = defaultDigits;
- char[] ca1 = sx.toCharArray();
- char[] ca2 = new char[n1In+n2In];
- char[] ca3,ca4,ca5;
- for (j=0; j<n1In; j++)
- ca2[j] = ca1[j];
- i = j+1;
- for (k=0; k<n2In; j++,i++,k++)
- ca2[j] = ca1[i];
- if (n1In+expon<=0) {
- ca3 = new char[-expon+n2In];
- for (j=0,k=0; k<(-n1In-expon); k++,j++)
- ca3[j]='0';
- for (i=0; i<(n1In+n2In); i++,j++)
- ca3[j]=ca2[i];
- }
- else
- ca3 = ca2;
- boolean carry=false;
- if (p<-expon+n2In) {
- if (expon<0) i = p;
- else i = p+n1In;
- carry=checkForCarry(ca3,i);
- if (carry)
- carry=startSymbolicCarry(ca3,i-1,0);
- }
- if (n1In+expon<=0) {
- ca4 = new char[2+p];
- if (!carry) ca4[0]='0';
- else ca4[0]='1';
- if(alternateForm||!precisionSet||precision!=0){
- ca4[1]='.';
- for(i=0,j=2;i<Math.min(p,ca3.length);i++,j++)
- ca4[j]=ca3[i];
- for (; j<ca4.length; j++) ca4[j]='0';
- }
- }
- else {
- if (!carry) {
- if(alternateForm||!precisionSet
- ||precision!=0)
- ca4 = new char[n1In+expon+p+1];
- else
- ca4 = new char[n1In+expon];
- j=0;
- }
- else {
- if(alternateForm||!precisionSet
- ||precision!=0)
- ca4 = new char[n1In+expon+p+2];
- else
- ca4 = new char[n1In+expon+1];
- ca4[0]='1';
- j=1;
- }
- for (i=0; i<Math.min(n1In+expon,ca3.length); i++,j++)
- ca4[j]=ca3[i];
- for (; i<n1In+expon; i++,j++)
- ca4[j]='0';
- if(alternateForm||!precisionSet||precision!=0){
- ca4[j]='.'; j++;
- for (k=0; i<ca3.length && k<p; i++,j++,k++)
- ca4[j]=ca3[i];
- for (; j<ca4.length; j++) ca4[j]='0';
- }
- }
- int nZeros=0;
- if (!leftJustify && leadingZeros) {
- int xThousands=0;
- if (thousands) {
- int xlead=0;
- if (ca4[0]=='+'||ca4[0]=='-'||ca4[0]==' ')
- xlead=1;
- int xdp=xlead;
- for (; xdp<ca4.length; xdp++)
- if (ca4[xdp]=='.') break;
- xThousands=(xdp-xlead)/3;
- }
- if (fieldWidthSet)
- nZeros = fieldWidth-ca4.length;
- if ((!minusSign&&(leadingSign||leadingSpace))||minusSign)
- nZeros--;
- nZeros-=xThousands;
- if (nZeros<0) nZeros=0;
- }
- j=0;
- if ((!minusSign&&(leadingSign||leadingSpace))||minusSign) {
- ca5 = new char[ca4.length+nZeros+1];
- j++;
- }
- else
- ca5 = new char[ca4.length+nZeros];
- if (!minusSign) {
- if (leadingSign) ca5[0]='+';
- if (leadingSpace) ca5[0]=' ';
- }
- else
- ca5[0]='-';
- for (i=0; i<nZeros; i++,j++)
- ca5[j]='0';
- for (i=0; i<ca4.length; i++,j++) ca5[j]=ca4[i];
-
- int lead=0;
- if (ca5[0]=='+'||ca5[0]=='-'||ca5[0]==' ')
- lead=1;
- int dp=lead;
- for (; dp<ca5.length; dp++)
- if (ca5[dp]=='.') break;
- int nThousands=(dp-lead)/3;
- // Localize the decimal point.
- if (dp<ca5.length)
- ca5[dp]=dfs.getDecimalSeparator();
- char[] ca6 = ca5;
- if (thousands && nThousands>0) {
- ca6 = new char[ca5.length+nThousands+lead];
- ca6[0]=ca5[0];
- for (i=lead,k=lead; i<dp; i++) {
- if (i>0 && (dp-i)%3==0) {
- // ca6[k]=',';
- ca6[k]=dfs.getGroupingSeparator();
- ca6[k+1]=ca5[i];
- k+=2;
- }
- else {
- ca6[k]=ca5[i]; k++;
- }
- }
- for (; i<ca5.length; i++,k++) {
- ca6[k]=ca5[i];
- }
- }
- return ca6;
- }
- /**
- * An intermediate routine on the way to creating
- * an f format String. The method decides whether
- * the input double value is an infinity,
- * not-a-number, or a finite double and formats
- * each type of input appropriately.
- * @param x the double value to be formatted.
- * @return the converted double value.
- */
- private String fFormatString(double x) {
- boolean noDigits=false;
- char[] ca6,ca7;
- if (Double.isInfinite(x)) {
- if (x==Double.POSITIVE_INFINITY) {
- if (leadingSign) ca6 = "+Inf".toCharArray();
- else if (leadingSpace)
- ca6 = " Inf".toCharArray();
- else ca6 = "Inf".toCharArray();
- }
- else
- ca6 = "-Inf".toCharArray();
- noDigits = true;
- }
- else if (Double.isNaN(x)) {
- if (leadingSign) ca6 = "+NaN".toCharArray();
- else if (leadingSpace)
- ca6 = " NaN".toCharArray();
- else ca6 = "NaN".toCharArray();
- noDigits = true;
- }
- else
- ca6 = fFormatDigits(x);
- ca7 = applyFloatPadding(ca6,false);
- return new String(ca7);
- }
- /**
- * For e format, the flag character '-', means that
- * the output should be left justified within the
- * field. The default is to pad with blanks on the
- * left. '+' character means that the conversion
- * will always begin with a sign (+ or -). The
- * blank flag character means that a non-negative
- * input will be preceded with a blank. If both a
- * '+' and a ' ' are specified, the blank flag is
- * ignored. The '0' flag character implies that
- * padding to the field width will be done with
- * zeros instead of blanks.
- *
- * The field width is treated as the minimum number
- * of characters to be printed. The default is to
- * add no padding. Padding is with blanks by
- * default.
- *
- * The precision, if set, is the minimum number of
- * digits to appear after the radix character.
- * Padding is with trailing 0s.
- *
- * The behavior is like printf. One (hopefully the
- * only) exception is that the minimum number of
- * exponent digits is 3 instead of 2 for e and E
- * formats when the optional L is used before the
- * e, E, g, or G conversion character. The optional
- * L does not imply conversion to a long long
- * double.
- */
- private char[] eFormatDigits(double x,char eChar) {
- char[] ca1,ca2,ca3;
- // int defaultDigits=6;
- String sx,sxOut;
- int i,j,k,p;
- int n1In,n2In;
- int expon=0;
- int ePos,rPos,eSize;
- boolean minusSign=false;
- if (x>0.0)
- sx = Double.toString(x);
- else if (x<0.0) {
- sx = Double.toString(-x);
- minusSign=true;
- }
- else {
- sx = Double.toString(x);
- if (sx.charAt(0)=='-') {
- minusSign=true;
- sx=sx.substring(1);
- }
- }
- ePos = sx.indexOf('E');
- if (ePos==-1) ePos = sx.indexOf('e');
- rPos = sx.indexOf('.');
- if (rPos!=-1) n1In=rPos;
- else if (ePos!=-1) n1In=ePos;
- else n1In=sx.length();
- if (rPos!=-1) {
- if (ePos!=-1) n2In = ePos-rPos-1;
- else n2In = sx.length()-rPos-1;
- }
- else
- n2In = 0;
- if (ePos!=-1) {
- int ie=ePos+1;
- expon=0;
- if (sx.charAt(ie)=='-') {
- for (++ie; ie<sx.length(); ie++)
- if (sx.charAt(ie)!='0') break;
- if (ie<sx.length())
- expon=-Integer.parseInt(sx.substring(ie));
- }
- else {
- if (sx.charAt(ie)=='+') ++ie;
- for (; ie<sx.length(); ie++)
- if (sx.charAt(ie)!='0') break;
- if (ie<sx.length())
- expon=Integer.parseInt(sx.substring(ie));
- }
- }
- if (rPos!=-1) expon += rPos-1;
- if (precisionSet) p = precision;
- else p = defaultDigits;
- if (rPos!=-1 && ePos!=-1)
- ca1=(sx.substring(0,rPos)+
- sx.substring(rPos+1,ePos)).toCharArray();
- else if (rPos!=-1)
- ca1 = (sx.substring(0,rPos)+
- sx.substring(rPos+1)).toCharArray();
- else if (ePos!=-1)
- ca1 = sx.substring(0,ePos).toCharArray();
- else
- ca1 = sx.toCharArray();
- boolean carry=false;
- int i0=0;
- if (ca1[0]!='0')
- i0 = 0;
- else
- for (i0=0; i0<ca1.length; i0++)
- if (ca1[i0]!='0') break;
- if (i0+p<ca1.length-1) {
- carry=checkForCarry(ca1,i0+p+1);
- if (carry)
- carry = startSymbolicCarry(ca1,i0+p,i0);
- if (carry) {
- ca2 = new char[i0+p+1];
- ca2[i0]='1';
- for (j=0; j<i0; j++) ca2[j]='0';
- for (i=i0,j=i0+1; j<p+1; i++,j++)
- ca2[j] = ca1[i];
- expon++;
- ca1 = ca2;
- }
- }
- if (Math.abs(expon)<100 && !optionalL) eSize=4;
- else eSize=5;
- if (alternateForm||!precisionSet||precision!=0)
- ca2 = new char[2+p+eSize];
- else
- ca2 = new char[1+eSize];
- if (ca1[0]!='0') {
- ca2[0] = ca1[0];
- j=1;
- }
- else {
- for (j=1; j<(ePos==-1?ca1.length:ePos); j++)
- if (ca1[j]!='0') break;
- if ((ePos!=-1 && j<ePos)||
- (ePos==-1 && j<ca1.length)) {
- ca2[0] = ca1[j];
- expon -= j;
- j++;
- }
- else {
- ca2[0]='0';
- j=2;
- }
- }
- if (alternateForm||!precisionSet||precision!=0) {
- ca2[1] = '.';
- i=2;
- }
- else
- i=1;
- for (k=0; k<p && j<ca1.length; j++,i++,k++)
- ca2[i] = ca1[j];
- for (;i<ca2.length-eSize; i++)
- ca2[i] = '0';
- ca2[i++] = eChar;
- if (expon<0) ca2[i++]='-';
- else ca2[i++]='+';
- expon = Math.abs(expon);
- if (expon>=100) {
- switch(expon/100) {
- case 1: ca2[i]='1'; break;
- case 2: ca2[i]='2'; break;
- case 3: ca2[i]='3'; break;
- case 4: ca2[i]='4'; break;
- case 5: ca2[i]='5'; break;
- case 6: ca2[i]='6'; break;
- case 7: ca2[i]='7'; break;
- case 8: ca2[i]='8'; break;
- case 9: ca2[i]='9'; break;
- }
- i++;
- }
- switch((expon%100)/10) {
- case 0: ca2[i]='0'; break;
- case 1: ca2[i]='1'; break;
- case 2: ca2[i]='2'; break;
- case 3: ca2[i]='3'; break;
- case 4: ca2[i]='4'; break;
- case 5: ca2[i]='5'; break;
- case 6: ca2[i]='6'; break;
- case 7: ca2[i]='7'; break;
- case 8: ca2[i]='8'; break;
- case 9: ca2[i]='9'; break;
- }
- i++;
- switch(expon%10) {
- case 0: ca2[i]='0'; break;
- case 1: ca2[i]='1'; break;
- case 2: ca2[i]='2'; break;
- …
Large files files are truncated, but you can click here to view the full file