2 Additional Library Modules

The additional library modules provide modules for the handling of the p1 Modula-2 specific data type "BCD", access to the Modula-2 runtime system, and some special services.

2.1 Extensions to the Standard Library

As the type "BCD" is a speciality of p1 Modula-2, there are no modules in the standard library to deal with this data type. The additional modules described in this chapter correspond in names and functionality with the modules of the standard library for the other numerical types.

For the data type "BCD" the following modules analogous to the standard library are provided: "BcdConv" / "BcdStr" and "BcdIO" / "SBcdIO".

"LineFile" is an additional device module to use the serial lines of the Apple Macintosh via the standard library modules.

"NetFile" is an additional device module to use network (TCP) connections via the standard library modules.

"ByteArrayFile" is an additional device module access data stored in memory via the standard library modules.

"LogStd" implements the possibility to log standardOut to a secondary output stream. This module is embedded into the internal structure of the library and cannot be added to the standard library with the predefined modules (in contrary to the other modules of this chapter). This restriction should be kept in mind while writing portable programs.

The module "FNames" is a useful auxiliary module to add default parts to file names.

2.1.1 BcdConv

DEFINITION MODULE BcdConv;
 
IMPORT
  ConvTypes;

FROM SYSTEM IMPORT BCD;
 
TYPE
  ConvResults = ConvTypes.ConvResults; (* strAllRight, strOutOfRange, strWrongFormat, strEmpty *)

  BcdFormat = (
    formatOk,                (* correct conversion format *)
    decMarker,               (* none or more than one marker for the position
                                of the decimal point specified  *)
    missingChar,             (* missing characters after "=" or "\" *)
    illegalValue             (* a value that is too great to be represented
                                with this format *)
    );

(*
The format string accepted by the conversion routines has the following rules:

    Z : digit, leading " "
    # : digit, leading " "
    9 : digit, leading "0"
    = : sign, the two following characters represent "+" and "-"
    - : same as "= -"
    + : same as "=+-"
    ! : marks the position of the decimal point (no required representation)
    , : same as "!\,"
    . : same as "!\."
    \ : escape character, the follow character is printed without
         interpretation 
    other characters: copied to the result string as they are.

    Examples:
    format: " ###\.###\.###\.##9,999 =HS"
    23456.78    is converted to :    "    .   . 23.456,780 H"
    -0.123    is converted to :    "    .   .   .  0,123 S"

    "+999.99999"
    23456.78    formatResult becomes illegalValue
    -0.123    is converted to :    "-000.12300"

    "DM - ZZZZZZ,ZZ"
    23456.78    is converted to :    "DM    23456,78"
    -0.123    is converted to :    "DM -       ,12"

    "DM - #####9,99"
    23456.78    is converted to :    "DM    23456,78"
    -0.123    is converted to :    "DM -      0,12"


*)

PROCEDURE ScanBcd (inputCh: CHAR; VAR chClass: ConvTypes.ScanClass;
                   VAR nextState: ConvTypes.ScanState);
  (* Represents the start state of a finite state scanner for bcd numbers -
     assigns class of inputCh to chClass and a procedure representing the
     next state to nextState.
  *)
 
PROCEDURE FormatBcd (str: ARRAY OF CHAR): ConvResults;
  (* Returns the format of the string value for conversion to BCD *)
 
PROCEDURE ValueBcd (str: ARRAY OF CHAR): BCD;
  (* If str is well-formed, returns the value corresponding to the bcd number
     string value str, otherwise an exception is raised.
  *)
 
PROCEDURE LengthFixedBcd (bcd: BCD; place: INTEGER): CARDINAL;
  (* Returns the number of characters in the fixed-point string
     representation of bcd rounded to the given place relative to the decimal
     point.
  *)
 
PROCEDURE TestFreeFormat (format: ARRAY OF CHAR): BcdFormat ;
  (* Tests wether format is a format string accepted by conversion rouines,
     value checks cannot be done.
  *)

PROCEDURE LengthFreeBcd (bcd: BCD; format: ARRAY OF CHAR): CARDINAL;
  (* If format is a well-formed format string and bcd can be represented
     within this format, returns the number of characters in the given string
     representation of bcd, otherwise an exception is raised.
  *)
 
PROCEDURE IsBcdConvException (): BOOLEAN;
 
END BcdConv.
"BcdConv" provides the basic conversion procedures for type "BCD" analogous to the "...Conv" modules of the standard library.

"ScanBcd" is the start procedure of a finite state machine to test whether strings can be converted to type "BCD". "FormatBcd" tests a complete string whether it can be converted. "ValueBcd" converts a string to a value of type "BCD" or raises an exception, if the string does not represent a valid "BCD" number.

"LengthFixedBcd" calculates the number of characters necessary for the representation of "bcd" in fixed point notation, if the number is rounded to "place" digits.

"IsBcdConvException" allows to test, whether a exception has been raised by module "BcdConv".

A facility is provided for "BCD" numbers to define special formats for output. In particular, it is possible to define representation and position of the sign, the representation of leading zeros and the representation of decimal point and delimiter symbols. The following characters have a special meaning in the format definition string:
Zdigit, leading space
#digit, leading space (same as "Z")
9digit, leading zero
=sign is to be placed at this position, the following two format characters define the representation of "+" and "–" (e.g. "=HS" for the German "Soll / Haben")
sign is to place at this position, the representation for "+" is "  ", the representation for "–" is "–" (same as "=  –")
+sign is to be placed at this position, the representation for "+" is "+", the representation for "–" is "–" (same as "=+–")
!Defines the position of the decimal point without generation a representation (used to define a special representation)
.Defines the position of the decimal point, "." is used for representation (same as "!\.")
,Defines the position of the decimal point, "," is used for representation (same as "!\,")
\escape character to write special characters, the following character is output without any special interpretation.

All other characters are incorporated into the number at the position they occupy in the format string.

"TestFreeFormat" tests, whether "format" represents a valid format string.

"LengthFreeBcd" calculates the length of the result string when converting "bcd" to the format defined in "format".

2.1.2 BcdIO

DEFINITION MODULE BcdIO;
 
(* Input and output of bcd numbers in decimal text form *)
 
IMPORT
  IOChan;

FROM SYSTEM IMPORT BCD;
 
(* the text form of a signed bcd number is
     ["+" | "-"], decimal digit, {decimal digit},
     [".", {decimal digit}] ["$"]
*)
 
PROCEDURE ReadBcd (cid: IOChan.ChanId; VAR bcd: BCD);
  (* Skips leading spaces and removes any remaining characters
     that form part of a signed bcd number.  A corresponding value is
     assigned to the parameter bcd.  The read result is set to the
     value allRight, outOfRange, wrongFormat, endOfLine, or endOfInput.
  *)
 
PROCEDURE WriteFixed (cid: IOChan.ChanId; bcd: BCD; place: INTEGER;
                      width: CARDINAL);
  (* Writes the value of the parameter bcd in fixed-point text form,
     rounded to the given place relative to the decimal point,
     in a field of the given minimum width.
  *)
 
  (* Examples of fixed point output:
     value:     3923009   3.923009   0.0003923009
     places
     -5         3920000          0              0
     -2         3923010          0              0
     -1         3923009          4              0
      0        3923009.         4.             0.
      1       3923009.0        3.9            0.0
      4    3923009.0000     3.9230         0.0004
  *)
 
END BcdIO.
"BcdIO" provides the procedures "ReadBcd" and "WriteFixed" for input and output of values of type "BCD". The parameter "cid" has to specify a channel supporting text mode. The relationship of "BcdIO" to the standard library is that of all "...IO" modules.

2.1.3 BcdStr

DEFINITION MODULE BcdStr;
 
(* BCD/string conversions *)
 
IMPORT
  ConvTypes;
IMPORT
  BcdConv;

FROM SYSTEM IMPORT BCD;
 
TYPE
  ConvResults = ConvTypes.ConvResults; (* strAllRight, strOutOfRange,
                                          strWrongFormat, strEmpty *)
  BcdFormat = BcdConv.BcdFormat; (* formatOk, decMarker, missingChar,
                                    illegalValue *)
 
(* the string form of a signed bcd number is
     ["+" | "-"], decimal digit, {decimal digit},
     [".", {decimal digit}] ["$"]
*)
 
PROCEDURE StrToBcd (str: ARRAY OF CHAR; VAR bcd: BCD; VAR res: ConvResults);
  (* Ignores any leading spaces in str. If the subsequent characters in str
     are in the format of a signed bcd number, assigns a corresponding value
     to bcd. Assigns a value indicating the format of str to res.
  *)
 
 
PROCEDURE BcdToFixed (bcd: BCD; place: INTEGER; VAR str: ARRAY OF CHAR);
  (* Converts the value of bcd to fixed-point string form, rounded to the
     given place relative to the decimal point, and copies the possibly
     truncated result to str.
  *)
 
PROCEDURE BcdToFree (bcd: BCD; format: ARRAY OF CHAR; VAR str: ARRAY OF CHAR;
                     VAR formatResult: BcdFormat);
  (* If format is a well-format format string and bcd can be represented
     within this format, converts bcd to the given format, and assigns the
     possibly truncated result to str, and "formatOk" to formatResult.
     Otherwise assigns a value indicating the error to formatResult.
  *)
 
END BcdStr.
"Corresponding to the "...Str" modules of the standard library, "BcdStr" provides procedures for simple conversion of "BCD" to and from strings.

"StrToBcd" converts a string to a number of type "BCD" and returns the result of the format check in "res". "BcdToFixed" converts a number of type "BCD" into a string rounded to "places" digits.

"BcdToFree" converts the value "bcd" according to the format defined in "format" (cf. module "BcdConv", chapter 2.1.1). The result returned in "formatResult" indicates, whether the number could be converted.

2.1.4 ByteArrayFile

DEFINITION MODULE ByteArrayFile;
 
  (* File Data kept in memory *)
 
IMPORT IOChan, ChanConsts, SYSTEM;
 
TYPE
  ChanId = IOChan.ChanId;
  FlagSet = ChanConsts.FlagSet;
  OpenResults = ChanConsts.OpenResults;
 
  (* Accepted singleton values of FlagSet *)
 
CONST
  read = FlagSet{ChanConsts.readFlag};   (* input operations are requested/available *)
  write = FlagSet{ChanConsts.writeFlag}; (* output operations are requested/available *)
  text = FlagSet{ChanConsts.textFlag};   (* text operations are requested/available *)
  raw = FlagSet{ChanConsts.rawFlag};     (* raw operations are requested/available *)

TYPE
  DataInfo = RECORD
    start: SYSTEM. ADDRESS;              (* Start address of the memory block contaiming the written data*)
    length: CARDINAL;                    (* Length of the written data *)
    allocLength: CARDINAL;               (* Length of allocated memory block *);
  END(*RECORD*);
  DataInfoPtr = POINTER TO DataInfo;
 
PROCEDURE OpenWrite (VAR cid: ChanId; VAR info: DataInfoPtr; flags: FlagSet;
                     VAR res: OpenResults);
  (* Attempts to obtain and open a channel connected to memory data.
     The write flag is implied; without the raw flag, text is implied.
     If successful, assigns to cid the identity of the opened channel, assigns the value
     opened to res, assigns a pointer to the memory description to info, and selects output mode,
     with the write position at the start of the memory location (i.e. length ist zero at start).
     If a channel cannot be opened as required, the value of res indicates the reason, and
     cid identifies the invalid channel.
     The information referenced by info is valid only after close has been performed. The
     user is responsible to DEALLOCATE the memory identfied by info when no longer needed.
  *)

PROCEDURE OpenRead (VAR cid: ChanId; start: SYSTEM. ADDRESS; length: CARDINAL; flags: FlagSet;
                    VAR res: OpenResults);
  (* Attempts to obtain and open a channel connected to the given memory data.
     The read and old flags are implied; without the raw flag, text is implied.
     If successful, assigns to cid the identity of the opened channel, assigns the value
     opened to res, and selects input mode, with the read position corresponding to the
     start of the memory location.
     If a channel cannot be opened as required, the value of res indicates the reason, and
     cid identifies the invalid channel.
  *)
 
PROCEDURE IsByteArrayFile (cid: ChanId): BOOLEAN;
  (* Tests if the channel identified by cid is open to a memory location file. *)
 
PROCEDURE Reread (cid: ChanId);
  (* If the channel identified by cid is not open to a memory location file, the
     exception wrongDevice is raised; otherwise attempts to set the read position to the
     start of the file, and to select input mode.
     If the operation cannot be performed (perhaps because of insufficient permissions)
     neither input mode nor output mode is selected.
  *)
 
PROCEDURE Rewrite (cid: ChanId);
  (* If the channel identified by cid is not open to a memory location file, the
     exception wrongDevice is raised; otherwise, attempts to truncate the file to zero
     length, and to select output mode.
     If the operation cannot be performed (perhaps because of insufficient permissions)
     neither input mode nor output mode is selected.
  *)
 
PROCEDURE Close (VAR cid: ChanId);
  (* If the channel identified by cid is not open to a memory location file, the
     exception wrongDevice is raised; otherwise closes the channel, and assigns the value
     identifying the invalid channel to cid.
     If the file is open for writing, the data info structure is set to the appropriate values.
  *)
 
END ByteArrayFile.
The device module "ByteArrayFile" allows to treat data stored in memory like data stored in a sequential file. For write operations, memory is allocated as needed. After closing the file, information about the allocated memory is returned. An open channel is either in read or in write mode. Switching is not possible but data may be read serveral times by using "Reread" or writen again by using "Rewrite".

"OpenWrite" opens a new memory location. Write access is enabled automatically. If neither "text" nor "raw" is passed in "flags", only text access is allowed. After successful opening, "cid" contains the opened channel, the write position is at the start of the memorty location and "res" contains the value "opened". Otherwise, "res" indicates the error reason, and "cid" identifies the illegal channel.
The parameter "info" returns a pointer to an information record that is filled in only after "close" has been performed.

"OpenRead" opens a file for the memory location specified by "start" and "length". Read access is enabled automatically. If neither "text" nor "raw" is passed in "flags", only text access is allowed. After successful opening, "cid" contains the opened channel, the read position is at the start of the memory location, and "res" contains the value "opened". Otherwise, "res" indicates the error reason and "cid" identifies the illegal channel.

"IsByteArrayFile" tests whether a channel has been opened by "ByteArrayFile".

If read access is specified, "Reread" positions to the start of the memory location to read the data again. Analogous, if write access is specified, "Rewrite" positions to the start of the memory location to overwrite the data. The size of the actually allocated buffer remains unchanged.

"Close" closes the file, filles in the info data for files in write mode, and destroys the assigned channel.

2.1.5 FNames

DEFINITION MODULE FNames;
 
 
PROCEDURE DefaultName (VAR namestr: ARRAY OF CHAR;
                       defaultstr: ARRAY OF CHAR);
  (* Completes missing parts in namestr with pieces provided for in defaultstr. *)
 
END(*MODULE*) FNames.
The procedure "DefaultName" is designed to add missing parts of file names from "defaultstr" to "namestr". If "defaultstr" starts with "." (but not "./" or "..") and "namestr" does not contain a dot, then "defaultstr" is appended as extension to "namestr". If "defaultstr" ends with "/" and "namestr" does not contain a slash, then "defaultstr" is inserted as path name at the start of "namestr".

2.1.6 LineFile

DEFINITION MODULE LineFile;

(* serial lines *)

IMPORT IOChan, ChanConsts;

CONST
    B50 = 50;
    B75 = 75;
    B110 = 110;
    B134 = 134;
    B150 = 150;
    B200 = 200;
    B300 = 300;
    B600 = 600;
    B1200 = 1200;
    B1800 = 1800;
    B2400 = 2400;
    B4800 = 4800;
    B9600 = 9600;
    B19200 = 19200;
    B38400 = 38400;

TYPE
    StopBits = (stop1, stop2);
    Parity = (noParity, oddParity, evenParity);
    DataBits = (data5, data6, data7, data8);

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

(* Accepted singleton values of FlagSet: *)

CONST
    read = FlagSet{ChanConsts.readFlag};   (* input operations are requested/available *)
    write = FlagSet{ChanConsts.writeFlag}; (* output operations are requested/available *)
    old = FlagSet{ChanConsts.oldFlag};     (* a file may/must/did exist before the channel is opened *)
    text = FlagSet{ChanConsts.textFlag};   (* text operations are requested/available *)
    raw = FlagSet{ChanConsts.rawFlag};     (* raw operations are requested/available *)

PROCEDURE Open (VAR cid: ChanId; name: ARRAY OF CHAR; openFlags: FlagSet; VAR res: OpenResults);
  (* Attempts to obtain and open a channel connected to a serial line of the given name.
     old and interactive are always implied; without the binary flag, text is implied.
     If successful, assigns to the parameter cid the identity of a channel
     open to a source/destination of the given name and assigns the value
     opened to the parameter res.
     If a channel cannot be opened as required, the value of the parameter
     res indicates the reason and cid identifies the bad channel.
  *)

PROCEDURE IsLineFile(cid: ChanId): BOOLEAN;
  (* Tests if the channel is open to a serial line. *)

PROCEDURE Close(VAR cid: ChanId);
  (* If the channel is not open to a serial line, the exception wrongDevice
     is raised. Otherwise, the channel is closed and the value identifying
     the bad channel is assigned to the parameter cid.
  *)

PROCEDURE LineReset (cid: ChanId; rate: CARDINAL; stop: StopBits; data: DataBits; parity: Parity);
  (* The line connected to cid is set to the given values. *)

PROCEDURE LineHandShake (cid: ChanId; software, hardware: BOOLEAN);
  (* The line connected to cid is set to the given handshake modes. *)

PROCEDURE GetWindowSize (cid: ChanId; VAR rows, cols: CARDINAL);
  (* Returns the size of the connected window (if any) in rows and columns *)

PROCEDURE SetWindowSize (cid: ChanId; rows, cols: CARDINAL);
  (* Sets the size of the connected window (if any) in rows and columns *)

END LineFile.
The module "LineFile" supplements the standard library with a module for direct access to serial ports (including those emulated over USB).

The procedures "Open", "Close" and "IsLineFile" parallel the corresponding procedures in the standard device modules.

"LineReset" and "LineHandShake" allow to change the parameter settings of the ports. Constans resp. enumeration types support for conveniant parameter values for "LineReset".

"GetWindowSize" and "SetWindowSize" allow to enquire resp. set the size of the window associated with this terminal line.

2.1.7 LogStd

DEFINITION MODULE LogStd;

IMPORT
  IOChan;

PROCEDURE SetLogChan (cid: IOChan. ChanId);
  (* Output to StdChans.  OutChan is coppied to this channel.
     Text operations are coppied, iff 
       ChanConsts. textFlag IN CurrentFlags (cid).
     Raw operations are coppied, iff
       ChanConsts. rawFlag IN CurrentFlags (cid).
     Logging is started iff cid <> IOChan. InvalidChan
  *)

PROCEDURE SuspendLogging ();
  (* suspends logging, nop if no log channel is defined. *)

PROCEDURE ResumeLogging ();
  (* resumes logging, nop if no log channel is defined. *)

PROCEDURE IsLogging (): BOOLEAN;
  (* TRUE, iff logging is enabled. *)

END LogStd.
The procedures of "LogStd" provide a facility for copying output to the standard output channel to a secondary channel. This allows automatic file protocols of the program output.

"SetLogChan" defines the channel for the copy and starts logging. Only these parts of the output ("text" and / or "raw") are copied, that the given channel can deal with. A call to "SetLogChan" with "IOChan. InvalidChan" stops logging.

"SuspendLogging" suspends logging temporarily, "ResumeLogging" resumes logging again. "IsLogging" tests, whether logging is turned on.

Attention:
Logging has an effect on the channel active as output channel in the moment of the call to "SetLogChan" only. Logging remains established for this channel, even if the output channel is changed via "StdChans. SetOutChan".

2.1.10 NetFile

DEFINITION MODULE NetFile;

(* Independent sequential data streams *)

IMPORT IOChan, ChanConsts;

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

(* Accepted singleton values of FlagSet *)

CONST
  read = FlagSet{ChanConsts.readFlag};   (* input operations are requested/available *)
  write = FlagSet{ChanConsts.writeFlag}; (* output operations are requested/available *)
  text = FlagSet{ChanConsts.textFlag};   (* text operations are requested/available *)
  raw = FlagSet{ChanConsts.rawFlag};     (* raw operations are requested/available *)

TYPE
  ServerId;
  CreateResults = (			(* Possible results of creating a server socket *)
    created,				(* Serversocket was successfully established *)
    portInUse,				(* Given port is already in use *)
    otherError);			(* Other error occurred *)

PROCEDURE CreateServer (VAR sid: ServerId; port: CARDINAL; VAR res: CreateResults);
  (*
     Attempts to create a server socket ready to listen on the given port.
  *)

PROCEDURE Listen (VAR cid: ChanId; sid: ServerId; openFlags: FlagSet; VAR res: OpenResults);
  (*
     Listens on the given server socket for an incomming connection (blocking call).
     Returns the channel id of a net file as soon as a connection is made to this socket.
     openFlags describe the requested features for the channel.
     Without the raw flag, text is implied; without read and write both flags are implied.
     If the channel could not be established, the invalid channel is returned.
  *)

PROCEDURE CloseServer (sid: ServerId);
  (*
     Closes the listening port.
  *)

PROCEDURE Open (VAR cid: ChanId; servername: ARRAY OF CHAR; port: CARDINAL; openFlags: FlagSet; VAR res: OpenResults);
  (*
     Attempts to obtain and open a channel connected to a network stream to the given server and port.
     Without the raw flag, text is implied.
     If successful, assigns to cid the identity of the opened channel, and assigns the value
     opened to res.
     If a channel cannot be opened as required, the value of res indicates the reason, and
     cid identifies the invalid channel.
  *)

PROCEDURE IsNetFile (cid: ChanId): BOOLEAN;
  (* Tests if the channel identified by cid is open to a sequential stream. *)

PROCEDURE Close (VAR cid: ChanId);
  (* If the channel identified by cid is not open to a network stream, the exception
     wrongDevice is raised; otherwise closes the channel, and assigns the value identifying
     the invalid channel to cid.
  *)

END NetFile.
"NetFile" models sequential data streams over TCP connections. Parallel reading and writing is thus the default. Creation of a listening (server-)socket is also provided for.

"CreateServer" creates a TCP server socket bound to the given port and ready to listen on this port. If the socket cannot be created, either "portInUse" (if the port is not available) or "otherError" (for any other network problem) is returned.

"Listen" blocks until a connetion is made to the socket identified by "sid". On return, "cid" identifies a net file channel open for communication through the TCP stream with the requested features.

"CloseServer" releases the socket identified by "sid" and assigns the undefined server id to "sid".

"Open" opens a TCP connection to the requested server and port for reading and writing. The available operations may be restricted to read or write exclusively (specification necessary). If neither "text" nor "raw" is passed in "flags", only text access is allowed. After successful opening, "cid" contains the opened channel and "res" contains the value "opened". Otherwise, "res" indicates the error reason and "cid" identifies the illegal channel.

"IsNetFile" tests whether a channel has been opened by "NetFile".

"Close" writes buffered data if necessary, closes the TCP stream, and destroys the assigned channel.

"IOChan. Reset (cid)" does nothing.

2.1.11 SBcdIO

DEFINITION MODULE SBcdIO;

FROM SYSTEM IMPORT BCD;
 
(* Input and output of bcd numbers in decimal text form over default channels
*)
 
PROCEDURE ReadBcd (VAR bcd: BCD);
  (* Skips leading spaces and removes any remaining characters that
     form part of a signed bcd number.  A corresponding value is assigned
     to the parameter bcd.  The read result is set to the value
     allRight, outOfRange, wrongFormat, endOfLine, or endOfInput.
  *)
 
PROCEDURE WriteFixed (bcd: BCD; place: INTEGER; width: CARDINAL);
  (* Writes the value of the parameter bcd in fixed-point text form,
    rounded to the given place relative to the decimal point,
    in a field of the given minimum width.
  *)
 
END SBcdIO.
"SBcdIO" is the equivalent to "BcdIO" with predefined standard in- and outchannel.

2.2 Basic Modules of the Library

These modules are internal modules; the implementation of the standard library is based on it. For most of the users, these modules are only of theoretical interest, in special cases basic functionality of the library can be manipulated with these modules.

ATTENTION!

2.2.1 BasicRealConv

DEFINITION MODULE BasicRealConv;

CONST
    maxSigFigs = 16;
    defaultSigFigsReal = 8;
    defaultSigFigsLong = 16;

TYPE
    BasicRealType = LONGREAL;
    SyntaxFlags = (                     (* syntax properties *)
        leadingZero,                    (* at least one digit befor the decimal point is required *)
        decimalPoint,                   (* allow decimal point (e.g. "0.0") *)
        decimalComma,                   (* allow decimal comma (e.g. "0,0") *)
        lowercaseE);                    (* allow "e" for exponent *)
    SyntaxFlagSet = SET OF SyntaxFlags;
    ScanConvertClass = (                (* state of scanner *)
        empty,                          (* terminated before start of number *)
        continuing,                     (* scanning, number continues *)
        terminated,                     (* terminated by termination character "" *)
        stopped,                        (* terminated by other character *)
        error);                         (* terminated due to wrong syntax *)
    ScanConvertState = PROCEDURE (CHAR, VAR InputDescriptor, VAR ScanConvertClass, VAR ScanConvertState);
    InputDescriptor = RECORD
        float: BasicRealType;           (* value of already processed charachters *)
        negative: BOOLEAN;              (* sign of mantissa *)
        expNegative: BOOLEAN;           (* sign of exponent *)
        exponent: INTEGER;              (* from conversion of fraction *)
        exphi: INTEGER;                 (* converted from exponent behind "E" *)
        sigfigs: CARDINAL;              (* already processed significant characters *)
        idleState: ScanConvertClass;    (* scanner state at the end of the number *)
    END(*RECORD*);
    OutputDescriptor = RECORD
        mantissa: ARRAY [0 .. maxSigFigs - 1] OF CHAR;        (* mantissa trimmed to "m.fff..." *)
        exponent: INTEGER;                                    (* corresponding exponent *)
        negative: BOOLEAN;                                    (* sign of mantissa *)
    END(*RECORD*);

CONST                                    (* default syntax corresponds with standard *)
    defaultSyntax = SyntaxFlagSet {lowercaseE, decimalPoint};

PROCEDURE ScanConvertReal
  (inputCh: CHAR; VAR data: InputDescriptor; VAR chClass: ScanConvertClass; VAR nextState: ScanConvertState);
(* Start of a scanner that stores the scanned real number in a descriptor pointed to by "data" *)

PROCEDURE GetExponent (x: BasicRealType; sigFigs: CARDINAL): INTEGER;
(* calculates exponent for representation rounded to "sigFigs" digits *)

PROCEDURE FloatToDesc (x: BasicRealType; sigFigs: CARDINAL; VAR desc: OutputDescriptor);
(* converts "x" to string *)

PROCEDURE SetRealSyntax (flags: SyntaxFlagSet);
(* sets the properties of the scanner started with ScanConvertReal *)

PROCEDURE GetRealSyntax (VAR flags: SyntaxFlagSet);
(* returns the actual properties of the scanner started with ScanConvertReal *)

PROCEDURE GetSpecialStringReal (r: REAL; VAR str: ARRAY OF CHAR): BOOLEAN;
(* returns true iff r denotes one of the special values inf or nan and assign the text to str *)

PROCEDURE GetSpecialStringLong (r: LONGREAL; VAR str: ARRAY OF CHAR): BOOLEAN;
(* returns true iff r denotes one of the special values inf or nan and assign the text to str *)

END BasicRealConv.
All conversion and io modules for real numbers are based on "BasicRealConv". The type used for storing all internal data is determined by the this module.

The scanner starting with "ScanConvertReal" inserts the read string automatically into the record "data" for further processing. If the string is syntactically correct, it can be directly processed with "DescToFloat". The result type "ScanConvertClass" is designed in a form that allows to distinguish whether the scanning has stopped due to a syntax error ("error"), end of string at a correct point ("terminated") or a not fitting character after a correct string ("stopped"). In this situation, the user can do a test of its own, whether he treats the termination character as legal.

"DescToFloat" converts a number described in "Descriptor" into a number of type "BasicRealType".

"GetExponent" calculates the exponent of "x" after rounding to "sigFigs" significant figures.

"FloatToDesc" converts a number of type "BasicRealType" to a descriptor.

"SetRealSyntax" allows to change the behaviour of the universal scanner "ScanConvertReal". The elements of "SyntaxFlags" have the following meaning:

The default "SyntaxFlagSet {leadingZero, decimalPoint}" corresponds with the syntax for real numbers as defined in the standard.

"GetRealSyntax" returns the actual setting of the universal scanner "ScanConvertReal". This allows to reset the original state.

2.2.2 ChanDefs

DEFINITION MODULE ChanDefs;

FROM EXCEPTIONS IMPORT ExceptionSource;
FROM MacTypes IMPORT OSType;
FROM SYSTEM IMPORT ADDRESS, INT32;
IMPORT IOLink;


CONST
    illDevice = 0;
    stdInOutDevice = 1;
    streamDevice = 2;
    rewDevice = 3;
    rndDevice = 4;
    argDevice = 5;
    firstFreeDevice = 6;

    illChannel = 0;
    maxChans = 31;

TYPE
    DeviceTablePtr = IOLink. DeviceTablePtr;
    ChannIds = [0 .. maxChans];
    ChannelTable = ARRAY ChannIds OF DeviceTablePtr;
    ChanSet = SET OF ChannIds;

CONST
    allChannels = ChanSet {illChannel + 1 .. maxChans};

VAR
    openChans: ChanSet;
    channelTable: ChannelTable;
    libException: ExceptionSource;

PROCEDURE MakeChan
  (VAR cid: CARDINAL; VAR ptr: ADDRESS; tableSize: CARDINAL);
PROCEDURE UnMakeChan (cid: CARDINAL; tableSize: CARDINAL);

PROCEDURE SetTypeAndCreator (fileDescriptor: INT32; type, creator: OSType);
PROCEDURE GetFileName (fileDescriptor: INT32; VAR fname: ARRAY OF CHAR);

END ChanDefs.
The module "ChanDefs" is the basic module for the management of io channels. It provides some Mac specific functionality, which is used by other modules.

Variables of type "ChanId" (channels) are internally of type "CARDINAL" and represent a index into the array "ChanDefs. channelTable". The elements of this array are of type "IOLink. DeviceTablePtr". Manipulation of the pointers stored in this array generally cause program termination, as the various device modules store private data behind the part described by "IOLink. DeviceTable". For implementation of filter procedures the "device procedures" described in "IOLink. DeviceTable" may be overridden in the sense of the methods of an object.

The set "openChans" store all currently open channels. It is possible to test whether "cid" specifies an open channel by "CAST (CARDINAL, cid) IN openChans".

2.2.3 StdDevices

DEFINITION MODULE StdDevices;

FROM IOChan IMPORT ChanId;

VAR
    stdIn, stdOut, stdErr, stdNull: ChanId;

END StdDevices.
The modules "StdDevices" contains the actual implementation of the standard channels. Linking of "StdDevices" to an application generates and using one of the standard channels creates—indirect via "TermBase" (cf. section 2.2.4)—a terminal input / output window for this application. The functionality is described in chapter 1.3 (The Input / Output Library).

2.3 Miscellaneous

This chapter summarizes all services of the library of p1 Modula-2, that do not fit into any other context.

"QuickCopy" and "SysExtensions" provide well defined access to the runtime procedures of p1 Modula-2 where this access may be necessary for the user. The use is—if not mentioned otherwise—without any hidden influence in the program.

"MacMisc" and "MacString" provide auxiliary procedures for the connection of library modules with runtime procedures of other languages or with procedures of the operating system.

2.3.1 MacMisc

DEFINITION MODULE MacMisc;

FROM IOChan IMPORT ChanId;
IMPORT SYSTEM;

TYPE
	<* IF ARCH = a64 THEN *>
	OSType = SYSTEM. CARD32;
	<* ELSIF ARCH = x86 THEN *>
	OSType = SYSTEM. CARD32;
	<* END *>

PROCEDURE SetTypeAndCreator (cid: ChanId; type, creator: OSType);
(* if "cid" identifies an open channel to a disk file, type and creator are
   set according to the parameters. Otherwise the exception "notAChannel"
   or "notAvailable" is raised.
*)

PROCEDURE Remove (VAR cid: ChanId);
(* if "cid" identifies an open channel to a disk file, the file is removed.
   The channel is closed and the value identifying the invalid channel
   is assigned to cid.
*)
    
PROCEDURE GetFileDescriptor (cid: ChanId): INTEGER;							(*V9.2*)
(* if "cid" identifies an open channel associated with a Unix file descriptor (or socket),
   the according file descriptor is returned.
*)

END MacMisc.
The procedure "SetTypeAndCreator" allows to specify type and creator according to the conventions of the Macintosh OS for all files opened with the modules "StreamFile", "SeqFile", or "RndFile" of the standard library.
Attention: "SetTypeAndCreator" is based directly upon the kernel APIs. It does not check whether a file system does support the finder flags. If applied to a file system other than HFS(+), it will silently do nothing.

The procedure "Remove" closes a file and then removes it. Like "SetTypeAndCreator", "Remove" is only applicable to files opened with the modules "StreamFile", "SeqFile", or "RndFile" of the standard library.

The procedure "GetFileDescriptor" returnes the Unix file descriptor associated with the open channel. This is mainly inteded for access to features not mapped by the standard library (like unblocking reads, setting special serial line behaviour, using "select" to survey open conections, etc.).

2.3.2 MacString

DEFINITION MODULE MacString;
 
FROM MacTypes IMPORT Str255;
 
PROCEDURE MacToModString (macStr: ARRAY OF CHAR; VAR modStr: ARRAY OF CHAR);
 
PROCEDURE ModToMacString (modStr: ARRAY OF CHAR; VAR macStr: ARRAY OF CHAR);

PROCEDURE STR255 (modStr: ARRAY OF CHAR): Str255;
 
END MacString.
This module provides conversion procedures between Macintosh Pascal strings with length information in the first byte and Modula-2 strings with termination character.

All procedures truncate the source string without error report, if it does not fit into the destination string.

The procedure "STR255" is alike "ModToMacString", but the produced Pascal string is returned on the stack instead as a parameter. The name "STR255" is kept for compatibility to earlier releases; it should not be confused with the data type "STR255" of module "SYSTEM".

For Pascal strings of maximal size (255 bytes) it is more advantageous to use the procedures "SYSTEM. FROMSTR255" and "SYSTEM. TOSTR255".

2.3.3 QuickCopy

<* ASSIGN (Foreign, TRUE) *>
DEFINITION MODULE QuickCopy;

FROM SYSTEM IMPORT
    ADDRESS;
FROM SYSTEM IMPORT
    CARD16, CARD32;

PROCEDURE CopyB (src, dst: ADDRESS; count: CARD16);
(*  Bytewise copying of count bytes from src to dst.
    Overlapping (src < dst < src + count) generates
    multiple copies of the range src .. src+bytes-1.
*)

PROCEDURE CopyBytes (src, dst: ADDRESS; count: CARD32);
(*  Optimized copying of count bytes from src to dst.
    Overlapping is handled correctly.
    CopyBytes has more fixed overhead as CopyB but is
    faster for large numbers and has no overlap problems!
*)

END QuickCopy.
"QuickCopy" provides access to two assembler procedures for fast copying of byte arrays.

"CopyB" is a simple procedure, which copies a byte array of length "count" with byte move instructions from "src" to "dest" without checks or optimization. If the destination address is within the source, this procedure will cause copy errors.

"CopyBytes" is a more general copy procedure with range check and optimization. It has more starting overhead than "CopyB". But for large arrays, it is normally faster, as it uses long word instructions whenever possible.

2.3.4 SysExceptions

DEFINITION MODULE  SysExceptions;

FROM M2EXCEPTION IMPORT M2Exceptions;
FROM M2OOEXCEPTION IMPORT M2OOExceptions;


TYPE
    SYSEXCEPTIONS =
		(busError, segmentationError, illegalInstr, trapInstr,
		 stackOverflow,
		 bcdOverflow, bcdDivZero, bcdNobcd);
    ExceptionSet = SET OF M2Exceptions;
    SysExceptionSet = SET OF SYSEXCEPTIONS;
    OOExceptionSet = SET OF M2OOExceptions;
    CallErrorDialogInfo = RECORD
        onException: ExceptionSet;
        onOOException: OOExceptionSet;
        onSysException: SysExceptionSet;
        onUserDefined: BOOLEAN;
    END(*RECORD*);

PROCEDURE SysException (): SYSEXCEPTIONS;

PROCEDURE IsSysException (): BOOLEAN;

(* There are two sets of information to decide wether or not
   the error dialog is called if the debugger is not present.
   One set (OnHandled) is used, if an exception handler is installed.
   The other set (OnUnHandled) is used, if no exception handler is installed.
   The default is: no call, if an exception handler is present, call
   on all but user defined exceptions, if no handler is present.
*)
PROCEDURE SetCallOnHandled (info: CallErrorDialogInfo);
PROCEDURE SetCallOnUnhandled (info: CallErrorDialogInfo);
PROCEDURE GetCallOnHandled (VAR info: CallErrorDialogInfo);
PROCEDURE GetCallOnUnhandled (VAR info: CallErrorDialogInfo);

PROCEDURE SetTrapsCaught (catch: BOOLEAN);

END SysExceptions.
The module "SysExceptions" provides basic services for exception handling.

The Type "SYSEXCEPTIONS" defines all runtime errors of the Macintosh OS not predefined in the standard ("busError .. stackOverflow") and the exceptions possible by the use of the type "BCD" ("bcdOverflow .. bcdNobcd"). The meaning of the first group is clear from the name. The meaning of the second group is as follows:
bcdOverflow Arithmetic overflow in an operation with operands of type "BCD" or in a conversion to type "BCD".
bcdDivZero Division by 0 in BCD division.
bcdNobcd Access to variables / constants that do not contain a valid BCD value.

"IsSysException" allows to inform, whether an exception is defined in this module, "SysException" returns the according value from "SYSEXCEPTIONS" (cf. compiler manual, chapter 2.7 (Exception Handling) and 2.11 (The Module M2EXCEPTION)).

The procedures "SetCallOn..." allow to define the conditions, on which the error dialog of p1 Modula-2 shall be activated or on which the corresponding exception handler shall be activated at once. These values can also be changed from within the debugger (cf. utilities manual, chapter 1.5.4). The record "CallErrorDialogInfo" contains one set for the exceptions defined in "M2Exceptions" and one for those of "SysExceptions" and a boolean variable for all user defined exceptions. The error dialog is activated for all exceptions set in these sets. If "onUserDefined" has the value "true", the error dialog is (also) activated for user defined exceptions.

The error dialog may be raised in two situations:

The procedures "GetCallOnHandled" and "GetCallOnUnHandled" return the actual conditions for the activation of the error dialog. Thus, it is possible to do a local change without influence on the rest of the program.

The procedure "SetTrapsCaught" can be used to temporarily turn off the catching of all runtime errors of the Macintosh OS. With "SetTrapsCaught (false)" catching of those exceptions is turned off, with "SetTrapsCaught (true)" it is turned on again. If a system exception is raised while exception handling is turned off, the program is terminated immediately and a crash dump is produced This dump, which includes the register settings and the stack chain including procedure names and relative program counter values, can be viewed with the utility "Console". This can come in useful when the exact location of an exception has to be determined without the use of the debugger.

2.3.5 StackDump

DEFINITION MODULE StackDump;

PROCEDURE Dump (VAR text: ARRAY OF CHAR);

END StackDump.
The procedure "Dump" returns a textual representation of the procedure nesting at the point of call. For each stack frame module name, procedure or method number and program counter relative to the procedure start are given. The frames are separated by ", " so that the may be printed as returned or split e.g. into separate lines.
chapter 1 (library) start page chapter 3 (library)