Dec 082017
Excellent set of Modula II routines that provide a PrintF like function.
File STDLIB.ZIP from The Programmer’s Corner in
Category Modula II Source Code
Excellent set of Modula II routines that provide a PrintF like function.
File Name File Size Zip Size Zip Type
BYTES.ASM 9597 1792 deflated
BYTES.DEF 1536 578 deflated
BYTES.OBJ 500 318 deflated
DIRECTOR.DEF 1079 520 deflated
DIRECTOR.MOD 3892 875 deflated
FILEIO.DEF 4319 1526 deflated
FILEIO.MOD 20850 4025 deflated
FILENAME.DEF 466 263 deflated
FILENAME.MOD 2486 667 deflated
FILESYST.DEF 1522 645 deflated
FILESYST.MOD 4837 1041 deflated
FPRINTF.DEF 580 184 deflated
FPRINTF.MOD 1679 330 deflated
FSCANF.DEF 609 185 deflated
FSCANF.MOD 2025 428 deflated
KEYBOARD.DEF 1437 634 deflated
KEYBOARD.MOD 3112 874 deflated
PRINTF.DEF 459 157 deflated
PRINTF.DOC 12618 4483 deflated
PRINTF.MOD 1565 308 deflated
PRINTFBA.DEF 1276 594 deflated
PRINTFBA.MOD 10336 2628 deflated
SCANF.DEF 431 151 deflated
SCANF.MOD 1924 464 deflated
SCANFBAS.DEF 3841 1607 deflated
SCANFBAS.MOD 12511 2828 deflated
SPRINTF.DEF 710 170 deflated
SPRINTF.MOD 1598 281 deflated
SSCANF.DEF 513 166 deflated
SSCANF.MOD 2036 488 deflated
STORAGE.DEF 198 121 deflated
STRINGS.DEF 2457 893 deflated
STRINGS.MOD 5519 1235 deflated
TERMINAL.ASM 2700 652 deflated
TERMINAL.DEF 777 412 deflated
TERMINAL.MOD 1042 350 deflated
TERMINAL.OBJ 239 191 deflated
TERMIO.DEF 2706 1067 deflated
TERMIO.MOD 13754 3252 deflated
WORDS.ASM 9712 1820 deflated
WORDS.DEF 1572 580 deflated
WORDS.OBJ 532 336 deflated

Download File STDLIB.ZIP Here

Contents of the PRINTF.DOC file

for the
Modula-2 PrintF/ScanF support Modules.
Don Milne, 28th January 1988

The modules which comprise the Modula-2 PrintF support are as follows:-

PrintFBase - Base module used by all other PrintF modules.
SPRINTF - PrintF with output directed to strings
FPRINTF - " " " " " char files.
PRINTF - " " " " " the display.

The ScanF modules are similarly laid out:-

ScanFBase - Base module used by all other ScanF modules
SSCANF - Take input from a string
FSCANF - Take input from a character file
SCANF - Take input from the keyboard.

If you can I would recommend that you look in any good book on C for a
definition of the C versions of PrintF and ScanF (eg "A C Reference Manual"
by Harbison & Steele, or the original K&R definition).

-------- PrintF ----------

The PrintF modules provide a method of output which is totally unlike that
found in the usual M2 I/O modules. In the latter you are expected to import
a different output procedure for each type that you wish to display. This
can be incredibly tedious to use, and can turn what would have been a
simple output statement in Pascal or C into a screenful of I/O calls.
Needless to say this has the effect of obscuring the rest of the program
which is not concerned with I/O.

We have borrowed the PrintF idea from the C language, mainly because it is
an available solution to the problem which almost anyone who has used C or
has read a book on C can recognise. The idea is to replace all of Modula's
various output statements with the single one "PrintF".

The basic parameter supplied to PrintF is called the "control string". In
the simplest case this string is merely a sequence of characters to be
output, eg:-

PrintF('Hello, World');

would write 'Hello, World' to the display. The control string is special
however in that besides allowing you to specify characters for output, you
may also embed commands in the string which specify how other objects
should be output, and if you do so you must supply those objects as further
parameters to the PrintF call. Take the following example:-

PrintF('I am %i today.', age);

This outputs the string 'I am today'. The is
replaced in the output with whatever you supply as the second parameter,
however the '%i' part of the control strings says that this parameter MUST
be an integer variable (however it can be of any integer type, eg SHORTINT,
INTEGER or LONGINT depending on what your compiler supports). In the
example given, if the integer variable 'age' equaled 12 then the string
'I am 12 today.' would be output.

You may have several of these % directives in the control string, but
each one must be matched by another parameter supplied to PrintF. Now it is
unfortunate but true that Modula-2 does not allow procedures to take a
variable numbers of parameters. To get around this several variants of
PrintF are supplied (PrintF, PrintF1, PrintF2 etc) which differ only in the
number of parameters that it takes. All PrintF calls take at least the
control string, so the number of parameters referred to does not include
the string (ie PrintF1 takes the control string plus one parameter).

Field specifiers

The format of all field specifiers is:-

'%' [optional formatting directive]

The type character can be any character from the set 'a'..'z', or 'A'..'Z'.
PrintF is case sensitive so watch out for that, ie 'a' and 'A' are not
treated as the same character. These are the type characters currently
supported by PrintF:-

'i' - output a decimal INTEGER, SHORTINT or LONGINT
'u' - output a decimal CARDINAL, SHORTCARD or LONGCARD
'c' - output a CHAR
's' - output a string (ie an ARRAY OF CHAR)
'h' - output the parameter in lower case hex (eg 0fff). The
parameter can be any of the types accepted by 'i','u'
or 'c'.
'H' - as 'h', but the hex output is upper case (eg 0FFF).
'x' - as 'h'
'X' - as 'H'

A longer example:-

PrintF5('My name is %s, aged %u, born %u/%u/%u',
name, age, day, month, year);

If name='Sam', age=20, day=10, month=1, year = 70 then the output of PrintF
would be:-

'My name is Sam, aged 20, born 10/1/70'

All the examples shown so far do not specify any formatting of the the
object to be output. If you want to do this you place the directive between
the '%' and the type character. For example, if you wanted that date to be
output dd/mm/yy then you would change that part of the control string to:-


These are the formatting directives at your disposal:-

- specifies the minimum width of the field, eg %2u specifies a
minimum width of 2 characters. The field will be padded out
with spaces unless you put a leading zero in front of the
width, in which case the field would be padded out with zeroes,
eg %3u would produce ' 1' and %03u would produce '001'.

The field width can be followed by '.' and another decimal
number, and this specifies a number of decimal places for a
floating point parameter, eg '%5.2r' would produce a real
number formatted with a total minimum field width of 5, and 2
decimal places. Note that floating point output is not built
into the standard PrintF, if you need it you have to import an
extension module which installs itself into the PrintF library.

Please remember that the field width specifies a *minumum*
field width. This means that if the conversion produces a
string whose length is less than the width then it will be
padded. If the length is greater then it will be output as is -
it will NOT be truncated to the field width!.

'*' This directive tells PrintF that the fieldwidth should be taken
from a supplied parameter instead of from the control string.
Examples of this are '%*u' and '%*.*r'.

'-' This directive tells PrintF that the field should be left
justified (the default is right justification). This directive
has no effect if no field width is given.

'+' This directive means that all decimal output should be signed,
so positive numbers would have a leading '+'.

' ' A space character means that all decimal output should be
signed if negative, or a space should be output if not.

Some examples of the above:-

'%-30s' A string parameter is supplied, and should be padded to a width
of 30, left justified.

'%+i' An integer parameter is supplied and should be signed when
output, either with '-' or '+'.

'%05i' An integer is expected, and should output with a field width of
5, padded with zeroes.

'%+05i' As above, but always sign the number.

'%04H' An integer, cardinal or char is expected, and is output in
upper case hex padded with '0's to a width of 4 digits.

'%%' Produce the character '%'.

Switch Characters
Switch characters provide a way of embedding non-printable characters in
the control string so that they can be output by PrintF. The format of all
switch characters is:-


"Character Def" will be one of the following:-

nnn - A three digit *decimal* number specifies the ascii code of
the character to be output, eg '\001' means CTRL-A.

'n' - A newline character sequence is output. What characters these
actually consist of is implementation dependent. On DOS
systems it will be CR-LF. Example- '\n'

'r' - A single carriage return is output. This is not the same as
newline, instead it has the effect of moving the cursor to
the first position on the current line.

't' - Output a tab character (ascii 9)

'f' - Output a formfeed character (ascii 12)

'b' - Output a backspace character (ascii 8)

------------- ScanF -----------------

ScanF is similar to PrintF, but deals with input rather than output. ScanF
always has the form:-

ScanF( , , )

In SSCANF the input source is a string. In FSCANF the input source is a
file variable, and in SCANF the input source is the keyboard.

ScanF control strings, like PrintF's, consist of a mixture of ascii
characters, field specifiers and switch characters. The interpretation is
slightly different however. In the ScanF the control string is determining
what input is converted to one of the vars, and also what characters are
skipped in the input.

This is a simple ScanF call:-

ScanF('%u %u %u', num1, num2, num3);

This call tells ScanF to read three decimal numbers from the keyboard and
return them in the variables num1, num2 and num3. The spaces in the control
string are included for clarity but are not really required.

Field widths may also be specified in ScanF control strings, but unlike
PrintF these are treated as MAXIMUM field widths, for example if the input
to a ScanF call was '123456789012', and the ScanF call itself was:-

ScanF3('%4u %4u %4u', num1, num2, num3);

Then the results returned would be num1=1234, num2=5678, num3=9012. Notice
that ScanF stops building the number when it has read fieldwidth
characters from the input.

We have included spaces in this example, but again it was not necessary. A
space actually tells ScanF to skip any whitespace characters before
starting the conversion, but that is done by default for numeric input in
any case.

ScanF works as follows. If the control string contains an ascii character
then input is skipped until that character is met (this differs from the C
convention by the way, in that language the character is expected to be the
next one in the input, but then you have to specify many more characters).
The same applies to any switch characters given. If ScanF meets a field
specifier then a convertion is performed. The range of possible specifiers
is as defined by PrintF:-

'i' - read an INTEGER, SHORTINT or LONGINT. Whitespace is
skipped before this conversion.

'u' - read CARDINAL, SHORTCARD or LONGCARD. Whitespace is skipped.

'c' - Read a CHAR. Whitespace is NOT skipped.

's' - Read a string. The treatment of whitespace depends on whether
a field width has been specified. If no field width is given
then white space is skipped, and characters are read and
stored until a whitespace character is met (EOF or EOL are
both treated as whitespace). If a field with IS specified then
no initial whitespace is skipped and ScanF continues until
fieldwidth characters are read or until EOF.

'h' - read a hex value. The dest variable can be any numeric type
(except FP types), or it can be a CHAR.

'H','x','X' - same as 'h'

Field widths in ScanF

As mentioned above the ScanF field width specifies a MAXIMUM width for the
field. The only other thing to watch out for is the '*' directive. In ScanF
this causes what in C literature is referred to as "conversion
suppression". What this actually means is that the value is read from the
input but is then thrown away - none of the parameters are used to retain
the result. To return to our last example, if the input to ScanF is still
'123456789012', and the ScanF call itself is:-

ScanF2('%4u %*4u %4u', num1, num2);

Then the results will be num1=1234, and num2=9012. This is because although
the second 4 digits have been read they are simply discarded and do not use
up one of the vars, hence only two are supplied. This is the only exception
to the rule that for every field specifier there must be a matching
variable supplied as a parameter.

 December 8, 2017  Add comments

Leave a Reply