The Fmt interface provides procedures for formatting numbers and
   other data as text.
   \index{writing formatted data}
   \index{formatted data!writing}
INTERFACEFmt ; IMPORT Word, Long, Real AS R, LongReal AS LR, Extended AS ER; PROCEDURE Bool(b: BOOLEAN): TEXT;
 Format b as {\tt "TRUE"} or  {\tt "FALSE"}. PROCEDURE Char(c: CHAR): TEXT;
 Return a text containing the character c. TYPE Base = [2..16]; PROCEDURE Int(n: INTEGER; base: Base := 10): TEXT; PROCEDURE Unsigned(n: Word.T; base: Base := 16): TEXT;
 Format the signed or unsigned number n in the specified base. The value returned by
Int or Unsigned never contains upper-case
   letters, and it never starts with an explicit base and underscore.
   For example, to render an unsigned number N in hexadecimal as a
   legal Modula-3 literal, you must write something like:
      "16_" & Fmt.Unsigned(N, 16)
PROCEDURE LongInt(n: LONGINT; base: Base := 10): TEXT;
PROCEDURE LongUnsigned(n: Long.T; base: Base := 16): TEXT;
 Format the signed or unsigned number n in the specified base. 
 The value returned by LongInt or LongUnsigned never contains upper-case
   letters, never starts with an explicit base and underscore, and never ends
   with a trailing L.  For example, to render an unsigned number N in
   hexadecimal as a legal Modula-3 literal, you must write something like:
      "16_" & Fmt.Unsigned(N, 16) & "L"
TYPE Style = {Sci, Fix, Auto};
PROCEDURE Real(
    x: REAL;
    style := Style.Auto;
    prec: CARDINAL := R.MaxSignifDigits - 1;
    literal := FALSE)
  : TEXT;
PROCEDURE LongReal(
    x: LONGREAL;
    style := Style.Auto;
    prec: CARDINAL := LR.MaxSignifDigits - 1;
    literal := FALSE)
  : TEXT;
PROCEDURE Extended(
    x: EXTENDED;
    style := Style.Auto;
    prec: CARDINAL := ER.MaxSignifDigits - 1;
    literal := FALSE)
  : TEXT;
 Format the floating-point number x. 
\paragraph*{Overview.}
   Style.Sci gives scientific notation with fields padded to fixed
   widths, suitable for making a table.  The parameter prec
   specifies the number of digits after the decimal point---that is,
   the relative precision.
   \index{scientific notation}
   Style.Fix gives fixed point, with prec once again specifying
   the number of digits after the decimal point---in this case, the
   absolute precision.  The results of Style.Fix have varying
   widths, but they will form a table if they are right-aligned (using
   Fmt.Pad) in a sufficiently wide field.
   \index{fixed-point notation}
   Style.Auto is not intended for tables.  It gives scientific
   notation with at most prec digits after the decimal point for
   numbers that are very big or very small.  There may be fewer than
   prec digits after the decimal point because trailing zeros are
   suppressed.  For numbers that are neither too big nor too small, it
   formats the same significant digits---at most prec+1 of them---in
   fixed point, for greater legibility.
   All styles omit the decimal point unless it is followed by at least
   one digit.
   Setting literal to TRUE alters all styles as necessary to make
   the result a legal Modula-3 literal of the appropriate type.
\paragraph*{Accuracy.}
   As discussed in the Float interface, the call ToDecimal(x)
   converts x to a floating-decimal number with automatic precision
   control~\cite{Steele,Gay}: Just enough digits are retained to
   distinguish x from other values of type T, which implies that
   at most T.MaxSignifDigits are retained.  The Real, LongReal,
   and Extended procedures format those digits as an appropriate
   string of characters.  If the precision requested by prec is
   higher than the automatic precision provided by ToDecimal(x),
   they append trailing zeros.  If the precision requested by prec
   is lower, they round ToDecimal(x) as necessary, obeying the
   current rounding mode.  Because they exploit the errorSign field
   of the record ToDecimal(x) in doing this rounding, they get the
   same result that rounding x itself would give.
   As a consequence, setting prec higher than T.MaxSignifDigits-1
   in Style.Sci isn't very useful: The trailing digits of all of the
   resulting numbers will be zero.  Setting prec higher than
   T.MaxSignifDigits-1 in Style.Auto actually has no effect at
   all, since trailing zeros are suppressed.
\paragraph*{Details.}
   We restrict ourselves at first to those cases where Class(x) is
   either Normal or Denormal.
   In those cases, Style.Sci returns: a minus sign or blank, the
   leading nonzero digit of x, a decimal point, prec more digits
   of x, a character 'e', a minus sign or plus sign, and
   T.MaxExpDigits of exponent (with leading zeros as necessary).
   When prec is zero, the decimal point is omitted.
   Style.Fix returns: a minus sign if necessary, one or more digits,
   a decimal point, and prec more digits---never any blanks.  When
   prec is zero, the decimal point is omitted.
   Style.Auto first formats x as in Style.Sci, using scientific
   notation with prec digits after the decimal point.  Call this
   intermediate result R.
   If the exponent of R is at least 6 in magnitude, Style.Auto
   leaves R in scientific notation, but condenses it by omitting all
   blanks, plus signs, trailing zero digits, and leading zeros in the
   exponent.  If this leaves no digits after the decimal point, the
   decimal point itself is omitted.
   If the exponent of R is at most 5 in magnitude, Style.Auto
   reformats the digits of R in fixed point, first deleting any
   trailing zeros and then adding leading or trailing zeros as
   necessary to bridge the gap from the digits of R to the unit's
   place.
   For example, assuming the current rounding mode is NearestElseEven:
      Fmt.Real(1.287e6,  Style.Auto, prec := 2) = "1.29e6"
      Fmt.Real(1.297e6,  Style.Auto, prec := 2) = "1.3e6"
      Fmt.Real(1.297e5,  Style.Auto, prec := 2) = "130000"
      Fmt.Real(1.297e-5, Style.Auto, prec := 2) = "0.000013"
      Fmt.Real(1.297e-6, Style.Auto, prec := 2) = "1.3e-6"
      Fmt.Real(9.997e5,  Style.Auto, prec := 2) = "1e6"
      Fmt.Real(9.997e-6, Style.Auto, prec := 2) = "0.00001"
   Style.Sci handles zero by replacing the entire exponent field by
   blanks, for example: {\tt " 0.00    "}.  Style.Fix renders zero
   with all digits zero; for example, "0.00".
   Style.Auto renders zero as "0".  On IEEE
   implementations, the value minus zero is rendered as a negative
   number.
   Also on IEEE implementations, Style.Sci formats infinities or
   NaN's with a minus sign or blank, the string "Infinity" or "NaN", and enough trailing
   blanks to get the correct overall width.  Style.Fix and
   Style.Auto omit the blanks.  In Style.Sci, if "Infinity" doesn't fit, "Inf" is used
   instead.
   Setting literal to TRUE alters things as follows: Numbers that
   are rendered without a decimal point when literal is FALSE have
   a decimal point and one trailing zero appended to their digits.
   For the routines Fmt.LongReal and Fmt.Extended, an exponent
   field of d0 or x0 is appended to numbers in fixed point and
   'd' or 'x' is used, rather than 'e', to introduce the
   exponents of numbers in scientific notation.  On IEEE
   implementations, the string "Infinity" is
   replaced by "1.0/0.0", "1.0d0/0.0d0", or "1.0x0/0.0x0" as
   appropriate, and "NaN" is similarly replaced by
   a representation of the quotient 0/0.  (Unfortunately, these
   quotient strings are so long that they may ruin the formatting of
   Style.Sci tables when prec is small and literal is TRUE.)
TYPE Align = {Left, Right};
PROCEDURE Pad(
    text: TEXT;
    length: CARDINAL;
    padChar: CHAR := ' ';
    align: Align := Align.Right): TEXT;
 If Text.Length(text) >= length, then text is returned
   unchanged.  Otherwise, text is padded with padChar until it has
   the given length.  The text goes to the right or left, according
   to align. 
PROCEDURE F(fmt: TEXT; t1, t2, t3, t4, t5: TEXT := NIL)
  : TEXT;
 Uses fmt as a format string. The result is a copy of fmt in
   which all format specifiers have been replaced, in order, by the
   text arguments t1, t2, etc. 
 A format specifier contains a field width, alignment and one of two
   padding characters. The procedure F evaluates the specifier and
   replaces it by the corresponding text argument padded as it would
   be by a call to Pad with the specified field width, padding
   character and alignment.
   The syntax of a format specifier is:
      %[-]{0-9}s
   
that is, a percent character followed by an optional minus sign, an
   optional number and a compulsory terminating s.
   If the minus sign is present the alignment is Align.Left,
   otherwise it is Align.Right. The alignment corresponds to the
   align argument to Pad.
   The number specifies the field width (this corresponds to the
   length argument to Pad). If the number is omitted it defaults
   to zero.
   If the number is present and starts with the digit 0 the padding character
   is '0'; otherwise it is the space character. The padding character
   corresponds to the padChar argument to Pad.
   It is a checked runtime error if fmt is NIL or the number of
   format specifiers in fmt is not equal to the number of non-nil
   arguments to F.
   Non-nil arguments to F must precede any NIL arguments; it is a
   checked runtime error if they do not.
   If t1 to t5 are all NIL and fmt contains no format
   specifiers, the result is fmt.
   Examples:
      F("%s %s\n", "Hello", "World") returns "Hello World\n".
      F("%s", Int(3))                returns "3"
      F("%2s", Int(3))               returns " 3"
      F("%-2s", Int(3))              returns "3 "
      F("%02s", Int(3))              returns "03"
      F("%-02s", Int(3))             returns "30"
      F("%s", "%s")                  returns "%s"
      F("%s% tax", Int(3))           returns "3% tax"
   The following examples are legal but pointless:
      F("%-s", Int(3))               returns "3"
      F("%0s", Int(3))               returns "3"
      F("%-0s", Int(3))              returns "3"
PROCEDURE FN(fmt: TEXT; READONLY texts: ARRAY OF TEXT)
  : TEXT;
 Similar to F but accepts an array of text arguments. It is a
   checked runtime error if the number of format specifiers in fmt
   is not equal to NUMBER(texts) or if any element of texts is
   NIL. If NUMBER(texts) = 0 and fmt contains no format
   specifiers the result is fmt. 
 Example:
      FN("%s %s %s %s %s %s %s",
        ARRAY OF TEXT{"Too", "many", "arguments",
          "for", "F", "to", "handle"})
   returns {\tt "Too many arguments for F to handle"}.
END Fmt.
<*PRAGMA SPEC *>
<*SPEC Bool(b)                           ENSURES RES # NIL *>
<*SPEC Char(c)                           ENSURES RES # NIL *>
<*SPEC Int(n, base)                      ENSURES RES # NIL *>
<*SPEC Unsigned(n, base)                 ENSURES RES # NIL *>
<*SPEC Real(x, style, prec, literal)     ENSURES RES # NIL *>
<*SPEC LongReal(x, style, prec, literal) ENSURES RES # NIL *>
<*SPEC Extended(x, style, prec, literal) ENSURES RES # NIL *>