Modula-2 Reloaded

A Modern Typesafe & Literate Programming Notation

Site Menu

Project

Specification

Implementation

Recommendations

Reference

Needs Updating

Work in Progress

Wastebasket

Wiki Manual

edit SideBar

Universal Write F

PROCEDURE WriteF( f : File; fmtStr : ARRAY OF CHAR; items : ARGLIST OF <Type> );
 (* Writes the textual representation of one or more data items to output stream f.
    The output format is determined by fmtStr. *)

BYTE output

A WriteF procedure is required for type BYTE. If the value of SYSTEM.BITSPERBYTE is other than eight BYTE and ADDRESS may possibly share a single implementation.

The syntax of a format string for byte output is as follows:

ByteFmtStr : '"' noFormatting? numeralOptions? alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
numeralOptions : 'b' | 'x' | "d" ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, base-16, all digits
'b' - numerals are written as base-2 literals
'x' - numerals are written as base-16 literals
'd' - numerals are written in decimal format
'<' - values are left aligned, option requires field width
'>' - values are right aligned, option requires field width
'~' - concatenate values to their respective predecessor without separators
'!' - values are written in columns, option may be followed by the number of columns

Examples:

byte1 := CAST (BYTE, 0);
byte2 := CAST (BYTE, 123);
ByteIO.WriteF(f, "N", byte1, byte2);
=> 00, 7B

BYTE.WriteF( f, "b", byte1, byte2 );
=> 0b0, 0b01111001

BYTE.WriteF( f, "x", byte1, byte2 );
=> 0x0, 0x7B

WORD and ADDRESS output

For word and address output one WriteF procedure each is required for types WORD and ADDRESS.

The syntax of a format string for word and address output is as follows:

wordOrAddrFmtStr : '"' noFormatting? numeralOptions? alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
numeralOptions : literalOptions | digit digit? digitGrouping? ;
literalOptions : 'b' | 'x' | "d" ;
digitGrouping : ( '_' | '.' | ':' ) digit digit? ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, base-16, all digits
'b' - numerals are written as base-2 literals
'x' - numerals are written as base-16 literals
'd' - numerals are written in decimal format
'_' - numerals are written in whitespace separated groups, option requires number of digits per group
'.' - numerals are written in period separated groups, option requires number of digits per group
':' - numerals are written in colon separated groups, option requires number of digits per group
'<' - numerals are left aligned, option requires field width
'>' - numerals are right aligned, option requires field width
'~' - concatenate values to their respective predecessor without separators
'!' - values are written in columns, option may be followed by the number of columns

Examples:

  word1 := CAST (WORD, 0);
  word2 := CAST (WORD, 123);
  word3 := CAST (WORD, 65535);
  WordIO.Write3F( f, "N|\n", word1, word2, word3 ); (* first two in default array format *)
  WordIO.Write3F( f, "b|\n", word1, word2, word3 );
  WordIO.Write3F( f, "x\n", word1, word2, word3 );
  WordIO.Write3F( f, "d\n", word1, word2, word3 );
  WordIO.Write3F( f, "_4\n", word1, word2, word3 );
=> { 00000000, 0000007B, 0000FFFF }
   { 0b0, 0b00000000'00000000'00000000'01111011, 0b00000000'00000000'11111111'11111111 }
   0x0, 0x0000007B, 0x0000FFFF
   0, 123, 65535
   0000 0000, 0000 007B, 0000 FFFF

BOOLEAN output

For boolean value output one WriteF procedure is required for type BOOLEAN.

The syntax of a format string for character based output is as follows:

boolFmtStr : '"' noFormatting? boolOptions? alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
boolOptions : 'T' | 'Y' ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, equivalent to "T"
'T' - true values are written as TRUE, false values are written as FALSE
'Y' - true values are written as YES, false values are written as NO
'<' - values are left aligned, option requires field width
'>' - values are right aligned, option requires field width
'~' - concatenate values to their respective predecessor without separators
'!' - values are written in columns, option may be followed by the number of columns

Examples:

BooleanIO.WriteF( f, "T", TRUE, FALSE );
=>  TRUE, FALSE

BooleanIO.WriteF( f, "Y", TRUE, FALSE );
=>  YES, NO

BITSET output

For bitset output one WriteF procedure is required for type BITSET.

The syntax of a format string for bitset output is as follows:

bitsetFmtStr : '"' noFormatting? bitsetOptions alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
bitsetOptions : setLiteral | groupedBinary? ;
setLiteral : 'S' ;
groupedBinary : ( '_' | '.' ) digit digit? ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, equivalent to "S"
'S' - value is written as a Modula-2 bitset literal
'_' - value is written as a binary bit group separated by whitespace, requires number of bits per group
'.' - value is written as a binary bit group separated by periods, requires number of bits per group
The meaning of formatting options for the bitset taken as a whole is as follows:

'<' - values are left aligned, option requires field width
'>' - values are right aligned, option requires field width
'~' - concatenate values to their respective predecessor without separators
'!' - values are written in columns, option may be followed by the number of columns

Examples:

BitsetIO.WriteF( f, "N", { } , { 2, 5, 7 } );
=> {  }, { 2, 5, 7 }

BitsetIO.WriteF( f, "S", { } , { 2, 5, 7 } );
=> {  }, { 2, 5, 7 }

BitsetIO.WriteF( f, "_4", { } , { 2, 5, 7 } ); (* assuming 8-bit bitset *)
=> { 0000 0000 }, { 0010 0101 }

Character based data output

For character based data output one WriteF procedure is required for each of the pervasive types CHAR, UNICHAR and each of their composite types ARRAY OF CHAR and ARRAY OF UNICHAR.

The syntax of a format string for character based output is as follows:

charFmtStr : '"' noFormatting? literalOption? quotingOptions? alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
literalOption : 'u' ;
quotingOptions : 'Q' | 'D' ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, raw characters, no quoting
'u' - data items are written as character literals
'Q' - data items are enclosed in single quotation marks
'D' - data items are enclosed in double quotation marks
'<' - data items are left aligned, option requires field width
'>' - data items are right aligned, option requires field width
'~' - concatenate data items to their respective predecessor without separators
'!' - data items are written in columns, option may be followed by the number of columns

Examples:

CharIO.WriteF( f, "~", "A", "B", "C", "D", "E" );
=>  ABCDE

CharIO.WriteF( f, "N", "A", "B", "C", "D", "E" );
=>  A, B, C, D, E

CharIO.WriteF( f, "Q", "A", "B", "C", "D", "E" );
=>  'A', 'B', 'C', 'D', 'E'

CharIO.WriteF ("u", "A");
=>  0u41

ARRAYOFCHAR.WriteF( f, "N", "foo", "bar", "baz" );
=>  foo, bar, baz

ARRAYOFCHAR.WriteF( f, "Q", "foo", "bar", "baz" );
=>  'foo', 'bar', 'baz'

ARRAYOFCHAR.WriteF( f, "<16!5",  "ALIAS","AND","ARGLIST","ARRAY","BEGIN"
 "BLUEPRINT","BY","CASE","CONST","COPY"
 "DEFINITION","DIV","DO","ELSE","ELSIF"
 "END","EXIT","FOR","FROM","GENLIB"
 "IF","IMPLEMENTATION","IMPORT","IN","INDETERMINATE"
 "LITERAL","LOOP","MOD","MODULE","NEW"
 "NONE","NOT","OF","OPAQUE","OR"
 "POINTER","PROCEDURE","RECORD","REFERENTIAL","RELEASE"
 "REPEAT","RETAIN","RETURN","SET","THEN"
 "TO","TYPE","UNTIL","VAR","WHILE" );
=>

           ALIAS             AND         ARGLIST           ARRAY           BEGIN
       BLUEPRINT              BY            CASE           CONST            COPY
      DEFINITION             DIV              DO            ELSE           ELSIF
             END            EXIT             FOR            FROM          GENLIB
              IF  IMPLEMENTATION          IMPORT              IN   INDETERMINATE
         LITERAL            LOOP             MOD          MODULE             NEW
            NONE             NOT              OF          OPAQUE              OR
         POINTER       PROCEDURE          RECORD     REFERENTIAL         RELEASE
          REPEAT          RETAIN          RETURN             SET            THEN
              TO            TYPE           UNTIL             VAR           WHILE

Whole number output

For whole number output one WriteF procedure is required for each of the pervasive types OCTET, CARDINAL, INTEGER, LONGCARD, LONGINT and any other user defined whole number type.

The syntax of a format string for whole number output is as follows:

wholeNumFmtStr : '"' noFormatting? numeralOptions alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
numeralOptions : base16Options | decimalOptions ;
base16Options : ( 'b' | 'x' ) digit? digit? ;
decimalOptions : sign? digitOptions? digitGrouping? suffix? ;
digitOptions : fillChar? digit digit? ;
sign : '+' | '-'  ;
fillChar :  '*' |  'z' ;
digitGrouping : '_' | ':' | ';' ;
suffix : "'" printableCharacter+ "'" ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, decimals, significant digits only
'b' - numerals are written as base-2 literals
'x' - numerals are written as base-16 literals
'+' - numerals are preceded by their sign or whitespace if their value is zero
'-' - numerals are preceded by their sign if negative, otherwise by whitespace
'*' - numerals are left filled with asterisks, option requires number of digits shown
'z' - numerals are left filled with zeroes, option requires number of digits shown
'_' - numerals are written with digits grouped into triads from right to left, separated by whitespace
':' - numerals are written with digits grouped into triads from right to left, separated by period
';' - numerals are written with digits grouped into triads from right to left, separated by comma
'<' - numerals are left aligned, option requires field width
'>' - numerals are right aligned, option requires field width
'~' - concatenate numerals to their respective predecessor without separators
'!' - numerals are written in columns, option may be followed by the number of columns

Examples:

(* Base-16 literal format, no fill, no padding *)
IntegerIO.WriteF( f, "x", 0, -123 );
=> 0x0, 0xFFFFFF85

(* Base-16 literal format, no fill, no padding *)
CardinalIO.WriteF( f, "x", 0, 123, 3456789 );
=> 0x0, 0x7B, 0x34BF15

(* decimal format, force sign, no fill, no grouping no padding *)
IntegerIO.WriteF( f, "+", 123, -3456789 );
=> +123, -3456789

(* decimal format, force sign, no fill, show eight digits, no grouping, no padding *)
IntegerIO.WriteF( f, "+8", 123, -3456789 );
=> +     123, - 3456789

(* decimal format, force sign, zero fill, show eight digits, no grouping, no padding *)
IntegerIO.WriteF( f, "+z8", 123, -3456789 );
=> +00000123, -03456789

(* decimal format, force sign, asterisk fill, show eight digits, no grouping, no padding *)
IntegerIO.WriteF( f, "+*8", 123, -3456789 );
=> +*****123, -*3456789

(* decimal format, force sign, asterisk fill, show eight digits, digit grouping, no padding *)
IntegerIO.WriteF( f, "+*8;", 123, -3456789 );
=> +******123, -*3,456,789

(* decimal format, force sign, asterisk fill, show eight digits, digit grouping,
    padding to right align into a field of width 15 *)
IntegerIO.WriteF( f, "+*8;>15", 123, -3456789 );
=>     +*******123,     -*3,456,789

(* same as previous example but separate items with newline by specifying one column *)
IntegerIO.WriteF( f, "+*8;>15!1", 123, -3456789 );
=>
    +*******123
    -*3,456,789
(* note that to end the entire output with a newline, one appends \n to the format string *)

Real number output

For real number output one WriteF procedure is required for each of the pervasive types REAL, LONGREAL, each of the standard library types BCD, LONGBCD and each user defined real number type.

The syntax of a format string for real number output is as follows:

realNumFmtStr : '"' noFormatting? realOptions? numeralOptions alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
realOptions : 'S' digit? digit?| 'F' | 'E' | '$'
numeralOptions : sign? intDigitOptions? fracDigitOptions? digitGrouping? suffix?;
intDigitOptions : fillChar? digit digit? ;
fracDigitOptions : ( '.' | ',' ) digit digit? ;
sign : '+' | '-'  ;
fillChar :  '*' |  'z' | 's' ;
digitGrouping : '_' | ';' ;
suffix : "'" printableCharacter+ "'" ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options is as follows:

'N' - normalised, equivalent "S"
'S' - numerals are written in scientific notation "1.9e4"
'E' - numerals are written in engineering notation; exponent is always a multiple of three "19.0e3"
'F' - numerals are written in fixed point notation without an exponenet "19000"
'$' - numerals are written with the currency prefix and two digits after the decimal in fixed format "$19000.00"
'+' - numerals are preceded by their sign or whitespace if their value is zero
'-' - numerals are preceded by their sign if negative, otherwise by whitespace
'*' - numerals are left filled with asterisks, option requires number of integral digits shown
's' - numerals are left filled with spaces, option requires number of integral digits shown (default if it is omitted)
'z' - numerals are left filled with zeroes, option requires number of integral digits shown
'.' - numerals are written with a decimal point, option requires number of fractional digits shown
',' - numerals are written with a decimal comma, option requires number of fractional digits shown
'_' - numerals are grouped into triads from right to left, separated by whitespace
';' - numerals are grouped into triads from right to left, separated by commas if decimal point, otherwise periods
'<' - numerals are left aligned, option requires field width
'>' - numerals are right aligned, option requires field width
''' - append characters enclosed in single quotes to each numeral
'~' - concatenate numerals to their respective predecessor without separators
'!' - numerals are written in columns, option may be followed by the number of columns

Examples:

(* asterisk fill, fixed point eight integral digits, two fractional digits, single column comma digit grouping *)
LongRealIO.WriteF( f, "F*8.2!1", 123.0, 123456789.0 );
=>*****123.00
   123456789.00

(* asterisk fill, dollar format which is fixed point eight integral digits, two fractional digits, plus comma digit grouping, append " USD" *)
LongRealIO.WriteF(  f, "$*8;' USD'", 123.0, 123456789.0  );
=> $*****123.00 USD, $123,456,789.00 USD

(* zero fill, fixed point eight integral digits, three fractional digits, comma digit grouping *)
LongRealIO.WriteF( f, "Fz8.3;", 0.0, 123.0, 123456789.0 );
=> 00,000,000.000, 00,000,123.000, 123,456,789.000

(* asterisk fill, scientific notation eight integral digits, six fractional digits, space digit grouping *)
LongRealIO.WriteF( f, "S*8.6_", 0.0, 123.0, 123456789.0 );
=> *******0.000 000e+00, *******1.230 000e+002, *******1.234 568e+008

(* asterisk fill, engineering notation eight integral digits, two fractional digits, two columns, space digit grouping *)
(* note no comma separators in column format *)
LongRealIO.WriteF( f, "E*8.2_!2", 0.0, 123.0, 123456789.0 );
=> *******0.00e+000*****123.00e+000
  *****123.46e+006

(* space fill, modified floating point notation requiring six sig figs before decimal, adjusted exponent, eight integral digits, two fractional digits, space digit grouping *)
(* note no comma separators in column format *)
LongRealIO.WriteF( f, "S6s8.6_", 123.0, 123456789.0  );
=>  123 000.000 000e-003,   123 456.789 000e+003
(* the space fill trigger "s" is only needed when necessary to separate other elements; it is the default if it can be skipped. *).

Complex number output

For complex number output one WriteF procedure is required for each of the complex types COMPLEX and LONGCOMPLEX, and each user defined complex number type.

The syntax of a format string for complex number output is as follows:

realNumFmtStr : '"' noFormatting? realOptions? complexOptions? numeralOptions alignOptions? columnOptions? '"' ;
noFormatting : 'N' ;
realOptions : 'S' digit? digit?| 'F' | 'E' 
complexOptions : 'i', | 'j', 'r'
numeralOptions : sign? intDigitOptions? fracDigitOptions? digitGrouping? suffix?;
intDigitOptions : fillChar? digit digit? ;
fracDigitOptions : ( '.' | ',' ) digit digit? ;
sign : '+' | '-'  ;
fillChar :  '*' |  'z' ;
digitGrouping : '_' | ';' ;
suffix : "'" printableCharacter+ "'" ;
alignOptions : alignment fieldWidth ;
alignment : '<' | '>' ;
fieldWidth : digit digit? digit? ;
columnOptions : concatenator | columns ;
concatenator : '~' ;
columns : '!" digit? digit? ;

The meaning of formatting options for each of the two real components is as follows:

'N' - normalised, equivalent "S"
'S' - numerals are written in (possibly modified) scientific notation. The option specifies the required number of digits before the decimal; default is one "1.9e4"
'E' - numerals are written in engineering notation; exponent is always a multiple of three "19.0e3"
'F' - numerals are written in fixed point notation without an exponenet "19000"
'+' - numerals are preceded by their sign or whitespace if their value is zero
'-' - numerals are preceded by their sign if negative, otherwise by whitespace
'*' - numerals are left filled with asterisks, option requires number of integral digits shown
'z' - numerals are left filled with zeroes, option requires number of integral digits shown
'.' - numerals are written with a decimal point, option requires number of fractional digits shown
',' - numerals are written with a decimal comma, option requires number of fractional digits shown
'_' - numerals are grouped into triads from right to left, separated by whitespace
';' - numerals are grouped into triads from right to left, separated by commas if decimal point, otherwise periods
The meaning of formatting options for the complex number as a whole is as follows:

'<' - numerals are left aligned, option requires field width
'>' - numerals are right aligned, option requires field width
''' - append characters enclosed in single quotes to each numeral
'~' - concatenate numerals to their respective predecessor without separators
'!' - numerals are written in columns, option may be followed by the number of columns

The meaning of the complex formatting options is as follows:
'i' - composite format with suffix i for imaginary part
'j' - composite format with suffix j for imaginary part
'r' - raw format with real and imaginary part in parentheses separated by comma

Examples:

COMPLEX.WriteF( f, "i", {3.5, 6.75} );
=> 3.5+6.75i

COMPLEX.WriteF( f, "j", {3.5, 6.75} );
=> 3.5+6.75j

COMPLEX.WriteF( f, "r", {3.5, 6.75} );
=> ( 3.5, 6.75 )

COMPLEX.WriteF( f, <format-string>, {3.5, 6.75} );
=> ( 3.500000000e+00, 6.750000000e+00 )

Output of non-character ARRAY types

For non-character array output the Write F? procedure that is required for each base type can also output an array.

The syntax of a format string for non-character array output is based on the syntax of format strings for the respective base type:

nonChrArrayFmtStr : '"' baseTypeFmtOptions arrayOptions? '"' ;
arrayOptions : '|' enclosureStart, separator, enclosureEnd | concatenator ;
enclosureStart : '{' | '[' | '(' ;
enclosureEnd : '}' | ']' | ')' ;
enclosure : ',' | ';[' | ' )' ;
concatenator : '~' ;

The meaning of array specific formatting options is as follows:

The start and end enclosures must match '{}' - array data is enclosed in curly braces, default if no array specific formatting options are present
'[]' - array data is enclosed in square brackets
'()' - array data is enclosed in parentheses
'~' - array data is written without enclosure

Examples:

VAR
    x : ARRAY 2 OF REAL = { 1.23, 4.5 };
    y : ARRAY 3 OF REAL = { 67.5, 78.0, 99.2 };

  RealIO.Write2ArrayF( f, "F2.2|{,}\n", x, y );
  RealIO.Write2ArrayF( f, "F2.2|[;]\n", x, y );
  RealIO.Write2ArrayF( f, "F2.2|{ }\n", x, y );
  RealIO.Write2ArrayF( f, "F2.2|~\n", x, y );
=> {  1.23,  4.50 }, { 67.50, 78.00, 99.20 }
   [  1.23;  4.50 ]; [ 67.50; 78.00; 99.20 ]
   {  1.23  4.50 } { 67.50 78.00 99.20 }
    1.23,  4.50, 67.50, 78.00, 99.20