# ISO Modula-2 standard libraries

It is our aim to provide the full set of ISO Modula-2 libraries. However, some modules are unimplemented on a particular hardware/sortware platform. System libraries are described in the XDS Modula-2 Chapter of the XDS User's Guide.

This chapter does not contain a complete reference. A brief description and some samples are provided for each group of modules. For more information, refer to the ISO Modula-2 Library Reference.

- Input/output library
- String conversions
- Mathematical libraries
- Processes and Semaphores
- Other libraries

## Input/output library

The IO library allows one to read and write the data streams over one or more channels. Channels are connected to the source of input data, or to destination of output data, known as devices. A set of devices can be extended.

A group of modules is provided to operate on the default input and output channel (Reading and writing via default channels). Another group of modules provide facilities to operate on channels specified explicitly by a parameter (Reading and writing data). The device modules provide facilities to get a channel connected to a source (Device modules). The primitive device-independent operations are provided by the module IOChan; the module IOLink allows specialized device module to be implemented (See Low-level IO modules).

- Reading and writing via default channels
- Reading and writing data
- Device modules
- Low-level IO modules

### Reading and writing via default channels

The following modules provide procedures that operate via default input and output channels and do not take a parameter which identifies a channel:

IOConsts | Types and constants for IO modules
SLongIO | LONGREAL numbers IO operations
SRawIO | Raw IO operations (no conversion or interpretation)
SRealIO | REAL numbers IO operations
SResultIO | Read results for the default input channel
STextIO | Character and string types IO operations
SWholeIO | Whole numbers IO operations

The module STextIO resembles the well-known InOut library. The Hello, World program is implemented in the following example:

    MODULE Hello;

    IMPORT  STextIO;

    BEGIN
      STextIO.WriteString('Hello, World!');
      STextIO.WriteLn;
    END Hello.

The modules SWholeIO, SRealIO, SLongIO provides facilities for the input and output of whole and real numbers in a decimal form using text operations on a channel.

    PROCEDURE Print(stage: CARDINAL; val: REAL);
    BEGIN
      STextIO.WriteString("On stage");
      SWholeIO.WriteCard(stage,0);
      STextIO.WriteString(" the value is equal to ");
      SRealIO.WriteReal(val,15);
      STextIO.WriteLn;
    END Print;

The module SIOResult allows one to determine whether the last input operation from a default input channel succeed. Text operations produce or consume data streams as a sequence of characters and line marks. The text input procedures (such as `ReadString` never remove a line mark from the input stream. The procedure `SkipLine` should be used to pass a line mark.

The `Copy` procedure reads strings from the input channel and copies them to the output channel.

    PROCEDURE Copy;
      VAR s: ARRAY [0..63] OF CHAR;
    BEGIN
      LOOP
        STextIO.ReadString(s);
        CASE SIOResult.ReadResult() OF
         |SIOResult.allRight:
            STextIO.WriteString(s);
         |SIOResult.endOfLine:
            STextIO.SkipLine;
            STextIO.WriteLn;
         |SIOResult.endOfInput:
            EXIT
        END;
      END;
    END Copy;

No procedure is provided to get the result of a `write' operation. Device errors are reported by raising an exception (See module IOChan).

### Reading and writing data

For all modules in this group a channel is specified by an actual parameter of the type IOChan.ChanId.

IOResult | Read results for specified channels
LongIO | LONGREAL numbers IO operations
RawIO | Raw IO operations (no conversion or interpretation)
RealIO | REAL numbers IO operations
TextIO | Character and string types IO operations
WholeIO | Whole numbers IO operations

The following procedure copies an input channel to an output channel byte by byte:

    PROCEDURE CopyChars(in,out: IOChan.ChanId);
      VAR ch: CHAR;
    BEGIN
      LOOP
        TextIO.ReadChar(in,ch);
        CASE IOResult.ReadResult(in) OF
         |IOResult.allRight:
            TextIO.WriteChar(out,ch);
         |IOResult.endOfLine:
            TextIO.SkipLine(in);
            TextIO.WriteLn(out);
         |IOResult.endOfInput:
            EXIT
        END;
      END;
    END CopyChars;

### Device modules

The device modules allows to get a channel connected to a stream, a file, program arguments and to default channels.

ChanConsts | Common types and values for channel open
| requests and results
ProgramArgs | Access to program arguments
RndFile | Random access files
SeqFile | Rewindable sequential files
StdChans | Access to standard and default channels
StreamFile | Independent sequential data streams

In the following example a channel connected to a rewindable file is opened:

    MODULE Example;

    IMPORT  SeqFile, STextIO, TextIO;

    CONST flags = SeqFile.text + SeqFile.old;

    VAR
      cid: SeqFile.ChanId;
      res: SeqFile.OpenResults;
      i  : CARDINAL;

    BEGIN
      SeqFile.OpenWrite(cid,"example.dat",flags,res);
      IF res = SeqFile.opened THEN
        FOR i:=0 TO 9 DO
          TextIO.WriteString(cid,"Hello");
          TextIO.WriteLn(cid);
        END;
        SeqFile.Close(cid);
      ELSE
        STextIO.WriteString("Open error");
        STextIO.WriteLn;
      END;
    END Example.

The module StdChans allows one to get channels already open to sources and destinations of standard input, standard output and standard error output. Default channels initially corresponds to the standard channels, but their values may be changed to redirect input or output.

    PROCEDURE RedirectOutput(cid: StdChans.ChanId);
    BEGIN
    (* writing to the current default channel: *)
      STextIO.WriteString("Redirecting output...");
      STextIO.WriteLn;
    (* redirecting output: *)
      StdChans.SetOutChan(cid);
    END RedirectOutput;

After the call of `RedirectOutput(cid)` all subsequent output via modules STextIO, SWholeIO, etc will be written to the channel `cid`. To restore output call

      StdChans.SetOutChan(StdChans.StdOutChan());

The module ProgramArgs provides a channel to access program's arguments. The following program prints all its arguments.

    MODULE Args;

    IMPORT ProgramArgs, TextIO, STextIO;

    VAR
      str: ARRAY [0..255] OF CHAR;
      cid: ProgramArgs.ChanId;

    BEGIN
      cid:=ProgramArgs.ArgChan();
      WHILE ProgramArgs.IsArgPresent() DO
        TextIO.ReadToken(cid,str);
        (* Note: read result test is omitted *)
        STextIO.WriteString(str); STextIO.WriteLn;
      END;
    END Args.

### Low-level IO modules

Two low-level modules are described in this section. The module IOChan defines the type `ChanId` that is used to identify channels and provides a set of procedures forming the channel's interface in a device-independent manner.

The module IOLink provides facilities that allow one to define new device modules. Let us implement an encryption channel, i.e. a channel that encrypts all information that is written to it. To make the encryption device-independent we need a channel for input/output operations.

In the following example a sketch of the encryption device module is shown.

    DEFINITION MODULE EncryptChan;

    IMPORT IOChan, ChanConsts;

    TYPE
      ChanId = IOChan.ChanId;
      OpenResults = ChanConsts.OpenResults;

    PROCEDURE Connect(VAR cid: ChanId;
                           io: ChanId;
                      VAR res: OpenResults);
    (* Attempts to open an encryption channel. All I/O
       operations will be made through "io" channel.
    *)

    PROCEDURE Close(VAR cid: ChanId);
    (* Closes the channel. *)

    END EncryptChan.

Values of the type `DeviceId` are used to identify device modules. By calling the procedure `DeviceTablePtrValue`, a device module can obtain a pointer to a device table for the channel. Each channel has it own copy of a device table. A device table contains a field in which the device module can store private data. In our example, the `io` channel will be stored in this field. The device table also serves as a method table (or virtual function table) in object-oriented languages. It contains the procedure variables for each device procedure. All fields are initialized by the call of `MakeChan` procedure. A device module has to assign its own device procedures to the fields of a device table. See the `Connect` procedure below.

    IMPLEMENTATION MODULE EncryptChan;

    IMPORT IOChan, IOLink, ChanConsts, SYSTEM;

    (* "did" is used to identify the channel's kind: *)
    VAR did: IOLink.DeviceId;

    PROCEDURE EncryptChar(from: SYSTEM.ADDRESS;
                             i: CARDINAL;
                        VAR ch: CHAR);
    BEGIN
      ch:='a'; (* very simple encryption :-) *)
    END EncryptChar;

    PROCEDURE TextWrite(x: IOLink.DeviceTablePtr;
                     from: SYSTEM.ADDRESS;
                      len: CARDINAL);
      VAR i: CARDINAL;
         ch: CHAR;
        cid: IOChan.ChanId;
    BEGIN
      (* get the channel id *)
      cid:=SYSTEM.CAST(IOChan.ChanId,x^.cd);
      FOR i:=0 TO len-1 DO
        (* encrypt i-th character *)
        EncryptChar(from,i,ch);
        (* write an encrypted character *)
        IOChan.TextWrite(cid,SYSTEM.ADR(ch),1);
      END;
    END TextWrite;

    PROCEDURE Connect(VAR cid: ChanId;
                           io: ChanId;
                      VAR res: OpenResults);
      VAR x: IOLink.DeviceTablePtr;
    BEGIN
      IOLink.MakeChan(did,cid);
      IF cid = IOChan.InvalidChan() THEN
        res:=ChanConsts.outOfChans
      ELSE
        (* get a pointer to the device table *)
        x:=IOLink.DeviceTablePtrValue(cid,did,
                           IOChan.notAvailable,"");
        (* store the channel id *)
        x^.cd:=SYSTEM.CAST(SYSTEM.ADDRESS,io);
        x^.doTextWrite:=TextWrite;
        (* ... *)
      END;
    END Connect;

    PROCEDURE Close(VAR cid: ChanId);
    BEGIN
      IOLink.UnMakeChan(did,cid);
    END Close;

    BEGIN
      IOLink.AllocateDeviceId(did);
    END EncryptChan.

The module EncryptChan can be used as any standard device module.

## String conversions

The string conversion library admits the conversion of the values of numeric data types to and from the character string representation. It contains the following modules:

ConvTypes | Common types used in the string conversion modules
LongConv | Low-level LONGREAL/string conversions
LongStr | LONGREAL/string conversions
RealConv | Low-level REAL/string conversions
RealStr | REAL/string conversions
WholeConv | Low-level whole number/string conversions
WholeStr | Whole number/string conversions

The module ConvTypes defines the enumeration type `ConvResults`. It also defines the types `ScanClass` and `ScanState` to use in the low-level conversion modules.

The low-level conversion modules allow to control lexical scanning of character sequences. For example, the WholeConv module implements procedures `ScanInt` and `ScanCard` representing the start state for a finite state scanner for signed and unsigned whole numbers. In the following example the procedure `ScanInt` is used to locate a position of the first character in a string which is not a part of an integer.

    PROCEDURE SkipInt(str: ARRAY OF CHAR;
                  VAR pos: CARDINAL);
      VAR len: CARDINAL;
        state: ConvTypes.ConvState;
        class: ConvTypes.ConvClass;
    BEGIN
      pos:=0; len:=LENGTH(str);
      state:=WholeConv.ScanInt;
      WHILE pos < len DO
        state(str[pos],class,state);
        IF   (class = WholeConv.invalid)
          OR (class = WholeConv.terminator)
        THEN
          RETURN
        END;
        INC(pos);
      END;
    END SkipInt;

## Mathematical libraries

The following modules constitute a mathematical library:

ComplexMath | `COMPLEX` mathematical functions
LongComplexMath | `LONGCOMPLEX` mathematical functions
LongMath | `LONGREAL` mathematical functions
RealMath | `REAL` mathematical functions

## Processes and Semaphores

The following modules allows concurrent algorithms to be expressed using processes:

Processes | Provides process creation and manipulation facilities.
Semaphores | Provides mutual exclusion facilities for use by processes.

##### Example

    MODULE Test;

    IMPORT Processes, Semaphores, STextIO;

    VAR
      sig : Semaphores.SEMAPHORE;
      prs : Processes.ProcessId;
      main: Processes.ProcessId;

    PROCEDURE Proc;
    BEGIN
      STextIO.WriteString('Proc 1'); STextIO.WriteLn;
      Semaphores.Claim(sig); (* suspend until released *)
      STextIO.WriteString('Proc 2'); STextIO.WriteLn;
      Processes.StopMe;
    END Proc;

    BEGIN
      STextIO.WriteString('Main 1'); STextIO.WriteLn;
      Semaphores.Create(sig,0);
      main:=Processes.Me();
      Processes.Start(Proc,40000,Processes.UrgencyOf(main)+1,NIL,prs);
      STextIO.WriteString('Main 2'); STextIO.WriteLn;
      Semaphores.Release(sig);
      STextIO.WriteString('Main 3'); STextIO.WriteLn;
      Processes.StopMe;
    END Test.

## Other libraries

In this section we list the ISO modules that do not belong to any of the above groups:

CharClass | provides predicates to test a value of a character type
Storage | Facilities for allocating and deallocating storage
Strings | Facilities for string manipulation
SysClock | Access to a system clock