Most programs need to perform input (reading data), output (writing data), or both in order to be useful. The OOC library attempts to simplify these Input/Output (I/O) operations by providing several related abstractions that relate to I/O.
The two primary abstractions are channels and riders. The entire I/O Subsystem of the OOC library revolves around these two concepts.
In order to provide uniform access to different sorts of devices (files, program arguments, sockets, and so forth) the I/O subsystem consists of several interrelated class hierarchies of related abstractions. The two primary abstractions are channels and riders.
The intention of these abstractions is to allow similar handling of devices; even, potentially, to the level of such exotic devices as a screen pixelmap, a windowing system, or a speech output device.
The benefit of this unified I/O handling approach allows a programmer to
write procedures that operate on any kind of I/O channel. A program writing
to stdout
could be easily converted to allow writing into a file
instead. Or, similarly, it could serve as a remote telnet connection.
All channels can share the same operations for text based I/O
(ReadInt
, WriteInt
, and so forth). Riders (readers and
writers) can then be attached to the channel, allowing standard I/O,
regardless of the actual device used.
There are several conceptual layers to the I/O process that are modeled by various abstractions in the OOC library. Their relationships are shown here:
data locations - where data resides (raw data). | (e.g., hard disk, memory block, keyboard port, RS232 links) | | channels - connections to data locations in the form of byte streams. | (e.g., files - on disk and in memory, pipes, | TCP/IP connections) | basic riders - basic operations on bytes. | (e.g., SetPos, ReadByte, ReadBytes, WriteByte, WriteBytes) | | mappers - translations of high level data to and from a byte stream. (e.g., binary reader/writer, text reader/writer)
A data location (or simply location) is a source of input data or destination of output data. It it the physical or logical place where data exists; say a hard disk, or keyboard buffer.
A channel is a connection to a data location. A channel is envisioned as a contiguous sequence, or stream, of bytes. Channels may be sequential as in the case of terminal I/O, a TCP stream, pipes, and so forth; or positionable like Files and ProgramArgs.
Riders are associated with a channel and provide read and write access of a location; they operate directly on a stream of bytes (i.e., a channel). Multiple readers and writers can exist for a single channel.
A mapper is a high-level rider; it operates on a particular format of data, like textual or binary representation of elementary data types. Mappers rely on the primitive operations of basic riders to build more complex operations.
The benefit of differentiating these layers is allowing a way to distinguish between the simple access layer, that doesn't know a thing about the byte stream being read or written, and the interpretation layer that transforms bytes into useful data.
The term rider can be used to describe any operator that provides read or write operations on channels. However, there is a distinction between low-level (basic riders) and high-level operations (mappers).
Basic riders are associated directly with a particular channel type. Notice that the rider, not the channel, has a position property (the place where reading or writing occurs). Several riders can operate on the same channel at the same time. Riders may provide sequential or positionable (i.e., random) access depending on the type of channel.
In general, there are only two types of basic riders: readers and writers.
Mappers are similar to basic riders and, like riders, may be either readers or writers. They translate between a sequence of data items and an uninterpreted sequence of bytes. But mappers may also provide more sophisticated read/write operations; for instance, scanners are mappers that can distinguish between different types of data within a particular format, and then read in that data based on the type. See section Module TextRider, and See section Module BinaryRider, for descriptions of the simplest mappers.
Please note: a basic rider is dependent on the implementation of its channel, (e.g., a file rider must know how to position itself within a file). When a channel type is extended, usually the rider must be extended as well.
Mappers, on the other hand, are independent of a particular channel's implementation; mappers use riders in their implementation. This independence means that every mapper may be used on any compatible rider without the need to implement all combinations of mappers and riders individually.
Before reading or writing to a location, a connection must be created by opening a channel on the location. The operations for opening channels are collectively called locators. The primary function of locators is to resolve a data location (as specified by a file name, URL, etc.), and then open a channel to that location.
Locators may be simply a set of functions; for instance:
PROCEDURE New* (...): ChannelType; PROCEDURE Old* (...): ChannelType;
For channels that correspond to a location that can be both read and
changed, New()
will create a new channel for the given data location,
deleting all data previously contained in it. Old()
will open a
channel to existing data.
For channels representing a unidirectional byte stream (like output to/
input from terminal, or a TCP stream), only a procedure New()
is
provided. It will create a connection with the designated location.
The formal parameters of these procedures will normally include some kind of reference to the data being opened (e.g., a file name) and, optionally, flags that modify the way the channel is opened (e.g., read-only, write-only, etc). Their use (and therefore, interface) depends on the type of channel to be opened.
In more complex circumstances, actual locator types may be required; in that
case, the locator type might provide type-bound procedures Old
and
New
to create a new channel.
When finished reading to or writing from the location, the connection can be
terminated by closing the channel ((each channel provides a
Close
method for this purpose; locators do not supply any close
operations). This will free all resources allocated by the system for the
channel. Once a channel is closed, no further input or output operations
can be performed on it.
Please note: A channel implementation may limit the number of channels that can be open simultaneously. It's common for an OS to only support a limited number of open files or open sockets at the same time. See individual channel types for these limitations (if such limitations exist for that type).
This section describes the channel types provided by the OOC library. Each module contains both the channel and its associated basic riders. Constant values that are relevant to a particular channel type are also declared within the defining module.
Module Channel provides three abstract classes: Channel
,
Reader
, and Writer
.
All types and procedures declared in this module are considered abstract; they are never instanciated or called. Module Channel is of interest, however, because like all abstract classes, its types define the interface elements that are required for any concrete classes, which are derived from them.
Abstract class Channel
is the base for all channel types.
Abstract classes Reader
and Writer
are the required basic
rider types that must be declared for each channel. Notice that these
define only read and write operations for sequences of bytes
(see section Riders and Mappers).
See the various concrete channel classes for more detail and examples of usage (like section Module Files, section Module StdChannels, or section Module ProgramArgs). In particular, the chapter about Files can be read without any prior knowledge about channels.
Channel
contains the following fields:
Result
res
is the result (i.e., error flag) signalling failure of a call to
NewReader
, NewWriter
, Flush
, Close
, etc.
res
is initialized to done
when the channel is created.
Every operation sets this to done
if successful, or otherwise,
res.code
is set to an error value indicating the cause of the error
(use either res.GetLText()
or res.GetText()
to get a plain
text error description). See section Summary of Channel Constants, for a list of
applicable error codes.
BOOLEAN
readable
is set to TRUE
if, and only if, readers can be
attached to this channel with NewReader
.
BOOLEAN
writable
is set to TRUE
if, and only if, writers can be
attached to this channel with NewWriter
.
BOOLEAN
open
indicates the channel's status; that is, it is set to
TRUE
on channel creation, and set to FALSE
by a call to
Close
. Closing a channel prevents all further read or write
operations on it.
(ch: Channel)
Length (): LONGINT
Length
returns the number of bytes of data for the channel ch.
If ch represents a file, then this value is the file's size. If
ch has no fixed length (e.g., because it's interactive), it returns
noLength
.
(ch: Channel)
GetModTime (VAR mtime: Time.TimeStamp)
GetModTime
retrieves the modification time of the data location
accessed by channel ch.
If no such information is available, ch.res.code
is set to
noModTime
; otherwise ch.res
is set to done
.
(ch: Channel)
NewReader (): Reader
res
field is
initialized to done
.
ch.res
is set to done
on success and the new reader is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
Please note: if the channel does not support multiple reading
positions, the same reader is always returned.
(ch: Channel)
NewWriter (): Writer
res
field is
initialized to done
.
ch.res
is set to done
on success and the new writer is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
Please note: if the channel does not support multiple writing
positions, the same writer is always returned.
(ch: Channel)
Flush
ch.res.code
will be changed to writeError
, otherwise ch.res
is set
to done
.
Please note: you must check the channel's res
flag after an
explicit Flush
; none of the attached writers will indicate a write
error in this case.
(ch: Channel)
Close
ch
, closes the channel, and frees
all system resources allocated to it. This invalidates all riders attached
to ch
; they can't be used further. On success, if all read and write
operations (including Flush
) have completed successfully,
ch.res
is set to done
. An opened channel can only be
closed once, successive calls of Close
are undefined.
Please note: unlike the Oberon System all opened channels have to
be closed explicitly. Otherwise resources allocated to them will remain
blocked.
(ch: Channel)
ClearError
ch.res
to done
.
Reader
contains the following fields:
Channel
base
refers to the channel the reader is connected to.
Result
res
is a result (error) flag that signals failure of a call to
ReadByte
, ReadBytes
, or SetPos
. res
is
initialized to done
when creating a reader or by calling
ClearError
. The first failed read operation (or SetPos
)
changes this to indicate the error, all further calls to ReadByte
,
ReadBytes
, or SetPos
will be ignored until ClearError
resets this flag.
This means that the successful completion of an arbitrary complex sequence
of read operations can be ensured by asserting that res
equals
done
beforehand and also after the last operation.
If res
is not equal to done
, res.code
is set to the
applicable error code. Use either of the methods res.GetLText()
or
res.GetText()
to get a plain text error description of this error
code. See section Summary of Channel Constants, for a list of applicable error
codes.
LONGINT
bytesRead
is set by ReadByte
and ReadBytes
to indicate
the number of bytes that were successfully read.
BOOLEAN
positionable
is set to TRUE
if, and only if, the reader can be
moved to another position with SetPos
; for channels that can only be
read sequentially, like input from the keyboard, this is set to
FALSE
.
(r: Reader)
Pos (): LONGINT
r.base
, i.e., the index of the first byte that is read
by the next call to ReadByte
or ReadBytes
. This procedure
returns noPosition
if the reader has no concept of a reading position
(e.g., if it corresponds to input from keyboard), otherwise the result is
non-negative.
(r: Reader)
Available (): LONGINT
r.base
minus the current
reading position, for an sequential channel (or a channel designed to handle
slow transfer rates) this is the number of bytes that can be accessed
without additional waiting.
The result is -1
if Close()
was called for the channel (or
the channel has been otherwise disconnected), or no more bytes are
available.
Please note: the number returned may be an approximation of the
number of bytes that could be read at once; it could be lower than the
actual value. For some channels or systems, this value may be as low as 1
even if more bytes are waiting to be processed.
(r: Reader)
SetPos (newPos: LONGINT)
r.res.code
to outOfRange
. A value
larger than the channel's length is legal, but the next read operation will
most likely fail with an readAfterEnd
error (unless the channel has
grown beyond this position in the meantime).
Calls to this procedure while r.res # done
will be ignored; in
particular, a call with r.res.code = readAfterEnd
error will
not reset res
to done
.
(r: Reader)
ReadByte (VAR x: SYSTEM.BYTE)
r.base
at the reading
position associated with r and places it in x. The reading
position is moved forward by one byte on success, and r.res
is
set to done
. Otherwise, r.res.code
indicates the error
cause. Calling this procedure with the reader r placed at the end (or
beyond the end) of the channel will set r.res.code
to
readAfterEnd
.
r.bytesRead
will be 1
on success and 0
on
failure.
Calls to this procedure while r.res # done
will be ignored.
(r: Reader)
ReadBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
r.base
at the reading
position associated with r and places them in x beginning at
index start. The reading position is moved forward by n bytes
on success, and r.res
is set to done
. Otherwise,
r.res.code
indicates the error cause.
Calling this procedure with the reader r positioned less than n
bytes before the end of the channel will will set r.res.code
to
readAfterEnd
.
r.bytesRead
will hold the number of bytes that were actually
read (being equal to n on success). Calls to this procedure while
r.res # done
will be ignored.
Pre-condition: n and start are non-negative. Also,
there is enough space in array x, starting at index start, to
hold n bytes.
(r: Reader)
ClearError
r.res
to done
, re-enabling further
read operations on r.
Writer
contains the following fields:
Channel
Result
res
is a result (error) flag that signals failure of a call to
WriteByte
, WriteBytes
, or SetPos
. It is initialized to
done
when creating a writer or by calling ClearError
. The
first failed writing (or SetPos
) operation sets res.code
to
indicate the error; all further calls to WriteByte
,
WriteBytes
, or SetPos
will be ignored until ClearError
resets this flag.
This means that the successful completion of an arbitrary complex sequence
of write operations can be ensured by asserting that res
equals
done
beforehand and also after the last operation.
If res
is not equal to done
, res.code
is set to the
applicable error code. Use either of the methods res.GetLText()
or
res.GetText()
to get a plain text error description of this error
code. See section Summary of Channel Constants, for a list of applicable error
codes.
Please note: due to buffering, a write error may occur when
flushing or closing the underlying channel; you have to check the channel's
res
field after any Flush()
or the final Close()
because a writer's res
field may not indicate a write error in that
case.
LONGINT
WriteByte
and WriteBytes
to indicate the number of
bytes that were successfully written.
BOOLEAN
TRUE
if, and only if, the writer can be moved to another position
with SetPos
; for channels that can only be written sequentially, like
output to a terminal, this is FALSE
.
(w: Writer)
Pos (): LONGINT
w.base
, i.e., the index of the first byte that is
written by the next call to WriteByte
or WriteBytes
. This
procedure returns noPosition
if the writer has no concept of a
writing position (e.g., if it corresponds to output to terminal), otherwise
the result is non-negative.
(w: Writer)
SetPos (newPos: LONGINT)
w.res.code
to outOfRange
. A value
larger than the channel's length is legal, however, the next write operation
zero fills the intervening space. That is, the gap from the previous
end of the channel to newPos are filled with 0X
bytes.
Calls to this procedure while w.res # done
are ignored.
(w: Writer)
WriteByte (x: SYSTEM.BYTE)
w.base
at the
writing position associated with w. The writing position is moved
forward by one byte on success, and r.res
is set to
done
. Otherwise, w.res.code
is set to indicate the
error cause.
w.bytesWritten
will be 1
on success and 0
on
failure.
Calls to this procedure while w.res # done
are ignored.
(w: Writer)
WriteBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
w.base
at the writing position associated with w.
The writing position is moved forward by n bytes on success, and
r.res
is set to done
. Otherwise,
w.res.code
is set to indicate the error cause.
w.bytesWritten
will hold the number of bytes that were actually
written (being equal to n on success).
Calls to this procedure while w.res # done
are ignored.
Pre-condition: n and start are non-negative. Also,
this method requires that accessing n bytes in array x, starting
from index start, will not go past the end of the array.
(w: Writer)
ClearError
w.res
to done
, re-enabling further
write operations on w.
Channel.Length
.
Reader.Pos()
or Writer.Pos()
meaning that the reader or writer has no concept of a position (e.g., if it
corresponds to input from keyboard or output to a terminal).
A specific channel implementation (e.g., see section Module Files) defines its own list
of codes, containing aliases for the codes below (where appropriate) plus
error codes of its own. These values are compared against the
res.code
field of the corresponding object (of types Channel
,
Reader
, or Writer
).
The methods res.GetLText()
or res.GetText()
can be used to
translate any error code into a human readable message.
The following constant applies to the res
field, and may be compared
to it. (i.e., ch.res = done
or ch.res # done
.)
If res
is not equal to done
, the following values may appear
in res.code
. These values apply to Channel
, Reader
, or
Writer
. Please note: These codes only cover the most
typical errors.
Flush
or a
Close
.
Flush
or a Close
.
The following constants apply only to Reader.res.code
and
Writer.res.code
:
SetPos
has been called with a negative argument or it has been called
on a rider that doesn't support positioning.
ReadByte
or ReadBytes
has tried to access a byte
beyond the end of the channel. This means that there weren't enough bytes
left or the read operation started at (or after) the end.
Channel.Close()
(in which
case, you probably made a programming error), or the channel has been
otherwise disconnected (e.g., the process at the other end of the channel,
say a pipe or TCP stream, closed the connection).
The following constants apply only to Channel.res.code
:
NewReader
was called to create a reader on a channel that doesn't
allow read access.
NewWriter
was called to create a writer on a channel that doesn't
allow write access.
Most computer systems provide some way of storing persistent data--- information that exists between one program activation and the next. The most common way of accessing persistent data is through a file system. A file is generally a collection of data that is held on some physical medium like a hard disk or magnetic tape. A file system provides a means to manage files; grouping them logically into entities called directories, and otherwise accessing them through file names. As these are typical, basic computer concepts, this document will assume some familiarity with file systems.
Module Files provides facilities for accessing files using channel and rider
abstractions. Files provides three related classes: File
,
Reader
, and Writer
. These classes are concrete subclasses of
their conterparts in module Channel (see section Module Channel).
Class File
is derived from the base channel type and adds additional
methods for file specific operations. Files are probably the most
frequently used channel implementation and, at the same time, the first
channel to be used by a novice user. Therefore the description below
incorporates all the relevant parts from the chapter about the abstract base
type Channel
.
As with all basic riders, Reader
and Writer
operate on
sequences of bytes. Consequently, most of the time, after a file is opened,
a mapper would be attached to provide more useful read/write operations
(see section Module BinaryRider and section Module TextRider).
Please note: Most Unix systems only allow a fixed number of files (and sockets) to be open simultaneously. If this limit is reached, no new file can be opened or socket be created until an old file/socket is closed. For any POSIX compliant system at least 16 open files are supported, most implementations provide a much larger number.
Class File
allows access to files as contiguous sequences of bytes.
Example:
VAR f: Files.File; f := Files.Old ("example.dat", {Files.read, Files.write}, res); IF (res # Files.done) THEN (* Error processing: failed to open "old" file. *) END; ... f.Close; (* Be sure to close the file so that resources are freed. *)
Channel
that corresponds to actual
files. File
inherits the following fields:
INTEGER
res
is the result (i.e., error flag) signalling failure of a call to
NewReader
, NewWriter
, Flush
, Close
, etc.
res
is initialized to done
when the file is created.
Every operation sets this to done
if successful, or otherwise,
res.code
is set to an error value to indicate the cause of the error
(use either res.GetLText()
or res.GetText()
to get a plain
text error description). See section Summary of File Constants, for a list of
applicable error codes.
BOOLEAN
readable
is set to TRUE
if, and only if, readers can be
attached to this file with NewReader
.
BOOLEAN
writable
is set to TRUE
if, and only if, writers can be
attached to this file with NewWriter
.
BOOLEAN
open
indicates the file's status; that is, it is set to TRUE
on file creation, and set to FALSE
by a call to Close
.
Closing a file prevents all further read or write operations on it.
File
inherits the following methods from the abstract class
Channel
:
(f: File)
Length (): LONGINT
Length
returns the number of bytes of data for the file f. If
f represents a genuine file, this value is the file's size. If
f has no fixed length (e.g., because it's a FIFO special file), it
returns noLength
.
Example:
(* For file, -rw-rw-r-- 1 nikitin 8641 Jun 6 08:14 misc.txt *) VAR len: LONGINT; len := f.Length(); => len = 8641
(f: File)
GetModTime (VAR mtime: Time.TimeStamp)
GetModTime
retrieves the modification time of the data location
accessed by file f.
If no such information is available, f.res.code
is set to
noModTime
; otherwise, f.res
is set to done
. For
more on time stamps See section Module Time.
Example:
(* For file, -rw-rw-r-- 1 nikitin 8641 Jun 6 08:14 misc.txt *) VAR fTime: Time.TimeStamp; f.GetModTime(fTime); => fTime.days = 50605 => fTime.msecs = 44064000
(f: File)
NewReader (): Reader
res
field is initialized to done
.
f.res
is set to done
on success and the new reader is
returned. Otherwise, it returns NIL
and f.res.code
is
set to indicate the error cause.
Please note: if the file does not support multiple reading
positions (e.g., because it's a FIFO special file), the same reader is
always returned.
Example:
VAR r: Files.Reader; r := f.NewReader(); IF (f. res # Files.done) THEN (* Error processing: failed to attach a new reader. *) END;
(f: File)
NewWriter (): Writer
res
field is initialized to done
.
f.res
is set to done
on success and the new writer is
returned. Otherwise, it returns NIL
and f.res.code
is
set to indicate the error cause.
Please note: if the file does not support multiple writing
positions (e.g., because it's a FIFO special file), the same writer is
always returned.
Example:
VAR w: Files.Writer; w := f.NewWriter(); IF (f. res # Files.done) THEN (* Error processing: failed to attach a new writer. *) END;
(f: File)
Flush
f.res.code
will
be set to writeError
, otherwise, f.res
is set to
done
.
Please note: you must check the file's res
flag after an
explicit Flush
; none of the attached writers will indicate a write
error in this case.
Example:
f.Flush; IF (f.res # Files.done) THEN (* Error processing: write error when flushing buffers. *) END;
(f: File)
Close
Flush
) have completed successfully,
f.res
is set to done
. An opened file can only be closed
once, successive calls of Close
are undefined.
Please note: unlike the Oberon System all opened Files have to be
closed explicitly. Otherwise resources allocated to them will remain
blocked.
Example:
f.Close; IF (f. res # Files.done) THEN (* Error processing: error occured as file was closed. *) END;
(f: File)
ClearError
f.res
to done
.
Example:
f.ClearError; => f.res = done
Besides its inherited methods, File
has the following additional
method:
(f: File)
Register
Tmp
procedure (see section File Locators). Registration happens
atomically, i.e., it is guaranteed that any previously existing file is
replaced by the newly registered one without any "in between" state. If the
operation is interrupted, then either the old file still exists on the file
system, or it has been replaced completely by the new one.
Calling Tmp
and Register
successively has the same effect as
calling New
. Calling this procedure has no effect if the file
f has been created with New
or has been registered previously.
Registration fails with an anonymousFile
error if it was created by
calling Tmp
with an empty file name, and with a channelClosed
error if f is closed.
Example:
(* open named temporary file *) f := Files.Tmp ("temp.fil", {Files.write}, res); f.Close; f.Register; => f.res.code = channelClosed res.GetText (str); => str = "File has been closed" (* open anonymous temporary file *) f := Files.Tmp ("", {Files.write}, res); f.Register; => f.res.code = anonymousFile res.GetText (str); => str = "Can't register anonymous file"
Class Reader provides primitive read operations on Files; that is, reading
of bytes from a file. Most programmers would not use this class directly; a
mapper class like BinaryRider.Reader
or TextRider.Reader
would
be used instead (see section Module BinaryRider and section Module TextRider)
Reader
inherits the following fields from the base reader type:
Channel.Channel
base
refers to the file the reader is connected to.
INTEGER
res
is a result (error) flag that signals failure of a call to
ReadByte
, ReadBytes
, or SetPos
. res
is
initialized to done
when creating a reader or by calling
ClearError
. The first failed read operation (or SetPos
)
changes this to indicate the error, all further calls to ReadByte
,
ReadBytes
, or SetPos
will be ignored until ClearError
resets this flag.
This means that the successful completion of an arbitrary complex sequence
of read operations can be ensured by asserting that res
equals
done
beforehand and also after the last operation.
If res
is not equal to done
, res.code
is set to the
applicable error code. Use either of the methods res.GetLText()
or
res.GetText()
to get a plain text error description of this error
code. See section Summary of File Constants, for a list of applicable error
codes.
LONGINT
bytesRead
is set by ReadByte
and ReadBytes
to indicate
the number of bytes that were successfully read.
BOOLEAN
positionable
is set to TRUE
if, and only if, the reader can be
moved to another position with SetPos
; for files that can only be
read sequentially, this is set to FALSE
.
Reader
inherits the following methods from the abstract reader class:
(r: Reader)
Pos (): LONGINT
r.base
, i.e., the index of the first byte that is read by
the next call to ReadByte
or ReadBytes
. This procedure
returns a non-negative result.
(r: Reader)
Available (): LONGINT
r.base
minus the current
reading position.
The result is -1
if Close()
was called for the file (or the
file has been otherwise closed), or no more bytes are available.
(r: Reader)
SetPos (newPos: LONGINT)
r.res.code
to outOfRange
. A value
larger than the file's length is legal, but the following read operation
will most likely fail with an readAfterEnd
error (unless the file has
grown beyond this position in the meantime).
Calls to this procedure while r.res # done
will be ignored, in
particular a call with r.res.code = readAfterEnd
error will not
reset res
to done
.
Example:
(* For file, -r--r--r-- 1 nikitin 12265 Jun 9 11:16 test.dat *) VAR pos, avail: LONGINT; r: Files.Reader; f: Files.File; f := Files.Old("test.dat", {Files.read}, res); r := f. NewReader(); pos := r.Pos(); => pos = 0 avail := r.Available(); => avail = 12265 r.SetPos(6000); pos := r.Pos(); => pos = 6000 avail := r.Available(); => avail = 6265
(r: Reader)
ReadByte (VAR x: SYSTEM.BYTE)
r.base
at the reading
position associated with r and places it in x. The reading
position is moved forward by one byte on success, and r.res
is
set to done
. Otherwise r.res.code
indicates the error
cause. Calling this procedure with the reader r placed at the end (or
beyond the end) of the file will set r.res.code
to
readAfterEnd
.
r.bytesRead
will be 1
on success and 0
on
failure.
Calls to this procedure while r.res # done
will be ignored.
Example:
(* OOC assumes that SIZE(SYSTEM.BYTE) = SIZE(SHORTINT)
*)
VAR byte: SHORTINT;
ch : CHAR;
r.ReadByte(byte);
r.ReadByte(ch);
(r: Reader)
ReadBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
r.base
at the reading
position associated with r and places them in x, beginning at
index start. The reading position is moved forward by n bytes
on success, and r.res
is set to done
. Otherwise,
r.res.code
indicates the error cause.
Calling this procedure with the reader r positioned less than n
bytes before the end of the file will will set r.res.code
to
readAfterEnd
.
r.bytesRead
will hold the number of bytes that were actually
read (being equal to n on success). Calls to this procedure while
r.res # done
will be ignored.
Pre-condition: n and start are non-negative. Also,
there is enough space in array x, starting at index start, to
hold n bytes.
Example:
VAR byteArr: ARRAY 256 OF SHORTINT; r.ReadBytes(byteArr, 0, 16); => reads the next 16 bytes from r.base into byteArr[0..15] r.ReadBytes(byteArr, 16, 100); => reads the next 100 bytes from r.base into byteArr[16..115]
(r: Reader)
ClearError
r.res
to done
, re-enabling further
read operations on r.
Example:
r.ClearError => r.res = done
Class Writer provides primitive write operations on Files; that is, writing
of bytes to a file. Most programmers would not use this class directly; a
mapper class like BinaryRider.Writer
or TextRider.Writer
would
be used instead (see section Module BinaryRider and see section Module TextRider)
Writer
inherits the following fields from the base writer type:
Channel.Channel
INTEGER
res
is a result (error) flag that signals failure of a call to
WriteByte
, WriteBytes
, or SetPos
. It is initialized to
done
when creating a writer or by calling ClearError
. The
first failed writing (or SetPos
) operation sets res.code
to
indicate the error; all further calls to WriteByte
,
WriteBytes
, or SetPos
will be ignored until ClearError
resets this flag.
This means that the successful completion of an arbitrary complex sequence
of write operations can be ensured by asserting that res
equals
done
beforehand and also after the last operation.
If res
is not equal to done
, res.code
is set to the
applicable error code. Use either of the methods res.GetLText()
or
res.GetText()
to get a plain text error description of this error
code. See section Summary of File Constants, for a list of applicable error
codes.
Please note: due to buffering, a write error may occur when
flushing or closing the underlying file; you have to check the file's
res
field after any Flush()
or the final Close()
.
LONGINT
WriteByte
and WriteBytes
to indicate the number of
bytes that were successfully written.
BOOLEAN
TRUE
if, and only if, the writer can be moved to another position
with SetPos
; for files that can only be written sequentially, this is
FALSE
.
Writer
inherits the following methods from the abstract writer class:
(w: Writer)
Pos (): LONGINT
w.base
, i.e., the index of the first byte that is written
by the next call to WriteByte
or WriteBytes
. This procedure
returns a non-negative result.
(w: Writer)
SetPos (newPos: LONGINT)
w.res.code
to outOfRange
. A value
larger than the file's length is legal, however, the next write operation
zero fills the intervening space. That is, the gap from the previous
end of the file to newPos are filled with 0X
bytes.
Calls to this procedure while w.res # done
are ignored.
Example:
(* For file, -r--r--r-- 1 nikitin 12265 Jun 9 11:16 test.dat *) VAR pos, LONGINT; w: Channel.Writer; f: Files.File; f := Files.Old("test.dat", {Files.write}, res); w := f. NewWriter(); pos := w.Pos(); => pos = 0 w.SetPos(6000); pos := w.Pos(); => pos = 6000
(w: Writer)
WriteByte (x: SYSTEM.BYTE)
w.base
at the writing
position associated with w. The writing position is moved forward by
one byte on success, and r.res
is set to done
.
Otherwise, w.res.code
is set to indicate the error cause.
w.bytesWritten
will be 1
on success and 0
on
failure.
Calls to this procedure while w.res # done
are ignored.
Example:
(* OOC assumes that SIZE(SYSTEM.BYTE) = SIZE(SHORTINT) *) VAR byte: SHORTINT; byte = ODH; w.WriteByte(byte); w.WriteByte("A");
(w: Writer)
WriteBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
w.base
at the writing position associated with
w. The writing position is moved forward by n bytes on success,
and r.res
is set to done
. Otherwise,
w.res.code
is set to indicate the error cause.
w.bytesWritten
will hold the number of bytes that were actually
written (being equal to n on success).
Calls to this procedure while w.res # done
are ignored.
Pre-condition: n and start are non-negative. Also,
this method requires that accessing n bytes in array x, starting
from index start, will not go past the end of the array.
Example:
(* OOC assumes that SIZE(SYSTEM.BYTE) = SIZE(CHAR). *) VAR charArr: ARRAY 256 OF CHAR; charArr := "abcdefghijklmnopqrstuvwxyz"; (* Note charArr[26] = 0X *) w.WriteBytes(charArr, 0, 16); => writes exactly 16 values (i.e., 0X is not automatically written) => abcdefghijklmnop w.WriteBytes(charArr, 16, 11); => writes exactly 11 values (i.e., 0X is written from charArr[26]) => qrstuvwxyz0X
(w: Writer)
ClearError
w.res
to done
, re-enabling further
write operations on w.
Example:
w.ClearError => w.res = done
Besides its inherited methods, Writer
has the following additional
methods:
(VAR w: Writer)
Truncate (VAR newLength: LONGINT)
0X
bytes). The writer's position is not
modified in either case.
Please note: On systems that do not support shortening files
directly it is implemented as a partial file copy.
The following locator procedures are provided for opening files. Possible
values for the flags parameter are read
, write
,
tryRead
, tryWrite
(see section Summary of File Constants).
(VAR file: ARRAY OF CHAR; VAR flags: SET; VAR res: Result): File
done
. Otherwise, it
returns NIL
and res.code and will indicate the problem.
If res
is not equal to done
, use either of the methods
res.GetLText()
or res.GetText()
to get a plain text error
description of this error code. See section Summary of File Constants, for a
list of applicable error codes.
Please note: In terms of the Oberon System, this procedure combines the procedures New and Register.
(VAR file: ARRAY OF CHAR; VAR flags: SET; VAR res: Result): File
done
. Otherwise, it returns NIL
and
res.code will indicate the problem.
If res
is not equal to done
, use either of the methods
res.GetLText()
or res.GetText()
to get a plain text error
description of this error code. See section Summary of File Constants, for a
list of applicable error codes.
(VAR file: ARRAY OF CHAR; VAR flags: SET; VAR res: Result): File
done
. Otherwise,
it returns NIL
and res.code will indicate the problem.
If res
is not equal to done
, use either of the methods
res.GetLText()
or res.GetText()
to get a plain text error
description of this error code. See section Summary of File Constants, for a
list of applicable error codes.
Temporary files are created with only the user's write bit set, and the permissions are extended upon registration. The files are deleted if they haven't been registered and are closed, or the program terminates.
An unique temporary file name is created if the given file name is the empty string. Such a file can't be registered later. Note that some systems may have a low limit for the number of temporary file names. The limit is never less than 25. To be safe, you should never have more than 25 anonymous temporary files open simultaneously, or check that the TMP_MAX macro in /usr/include/stdio.h is large enough for your purposes.
With oo2c if file isn't empty, the new name is derived from the old
one by appending "^", "^1", "^2", etc. in turn, until a file name is found
that doesn't exist already. If such call to Tmp
returns
nameTooLong
, then this refers to the constructed temporary name, not
the one in file.
This function corresponds to Oberon System's New.
It isn't always desirable to have to open a file before performing certain operations on it. You may not be interested in a file's contents; but rather some property of the file itself (for instance, does the named file even exist). As such, module Files provides some free-standing procedures:
(VAR file: ARRAY OF CHAR; VAR mtime: Time.TimeStamp; VAR res: Result)
done
. Otherwise, res.code
holds an error code that indicates the problem.
Please note: under Unix this procedure will also change the access time to the value of mtime.
(VAR file: ARRAY OF CHAR; VAR mtime: Time.TimeStamp; VAR res: Result)
done
. Otherwise, res.code
holds an error code that indicates the problem.
(VAR file: ARRAY OF CHAR): BOOLEAN
TRUE
if file file exists, FALSE
otherwise. This
procedure may be changed in future revisions to give more useful information
on failure.
Example:
(* Attempting to open a "read-only" file for writing *) f := Files.Old ("example.dat", {Files.write}, res); => res.code = accessDenied res.GetText (str); => str = "Failed to open file with requested access rights"
For constant values that are common to all channel types (see section Summary of Channel Constants), local names have been provided:
File.Length
.
Reader.Pos()
or Writer.Pos()
meaning that the reader or writer has no concept of a position.
The following constant applies to the res
field, and may be compared
to it. (i.e., ch.res = done
or ch.res # done
.)
The following values are compared against the res.code
field of the
corresponding object (of types Channel
, Reader
, or
Writer
).
The methods res.GetLText()
or res.GetText()
can be used to
translate any error code into a human readable message.
Flush
or a Close
.
Flush
or a Close
.
The following constants only apply to Reader.res.code
and
Writer.res.code
:
SetPos
has been called with a negative argument or it has been called
on a rider that doesn't support positioning.
ReadByte
or ReadBytes
has tried to access a byte
beyond the end of the file. This means that there weren't enough bytes left
or the read operation started at (or after) the end.
File.Close()
(in which case, you probably made a programming error),
or the channel has been otherwise closed.
The following constants only apply to File.res.code
:
NewReader
was called to create a reader on a file that doesn't allow
read access.
NewWriter
was called to create a writer on a file that doesn't allow
write access.
The following values report problems when opening or modifying a file:
flags
argument specified write access, and the file is a
directory.
Old()
does not exist. Or the directory
part of a file name passed to New()
or Tmp()
does not exist.
SetModTime
is not a valid time stamp;
either the millisecond part isn't valid, or the time value is too large or
too small to be mapped to the time value of the underlying OS.
Tmp()
.
The following are possible elements for the flags parameter of
New
, Old
, or Tmp
.
Please note: at least one of the following flags has to be set; otherwise you will get an "access denied" error:
noReadAccess
.
noWriteAccess
.
readable
is set to FALSE
.
writable
is set to FALSE
.
Module StdChannels defines the standard I/O channels, which are predefined channels for input (typically the keyboard) and output (typically the computer screen).
Standard channels do not have to be opened by a client program because they
are already open and ready for use. Their attributes and operations are
described by the class Channel.Channel
.
The standard channels (stdin
, stdout
, and stderr
)
should never be closed. You can close the standard channels (e.g.,
to detach a program from its terminal), but StdChannels
does not
provide a way to reopen them. Notice that the modules In
,
Out
, Err
, OakIn
, and OakOut
are all affected by
such operations on standard channels. If, for example, you call
stdout.Close
, then the procedures in module Out will no longer
function (unless you use Out.SetWriter
to set another channel).
A fourth standard channel, null
, is also provided.
Mappers may be attached to any of these channels to provide read and
write operations for them. Mappers from module TextRider
are
most often used.
Also, be aware that modules In
, Out
, and Err
provide
simple interfaces to the standard channels (see section Standard I/O). So that,
in many cases, you may not have to use module StdChannels
directly.
Example:
VAR stringVar: ARRAY 256 OF CHAR; rdr: TextRider.Reader; rdr := TextRider.ConnectReader(StdChannels.stdin); rdr.ReadLine(stringVar);
Example:
VAR wrtr: TextRider.Writer; wrtr := TextRider.ConnectWriter(StdChannels.stdout); wrtr.WriteString("A string to write"); wrtr.WriteLn;
Example:
VAR wrtr: TextRider.Writer; wrtr := TextRider.ConnectWriter(StdChannels.stderr); wrtr.WriteString("An error has occured"); wrtr.WriteLn;
This module provides access to the command line arguments passed to the
program's invocation. They are mapped onto a standard channel args
,
with each argument transformed into a single line of text. Interpreting the
list of arguments is usually done by applying an instance of
TextRider.Reader
or TextRider.Scanner
to the argument channel.
The number of arguments is determined by calling args.ArgNumber()
.
If the invocation were, for example, foo bar 42
, where foo
is
the name of the program itself, then the channel's contents would look like
this:
foo bar 42
For the above example, args.ArgNumber()
would return 2
; that
is, the program name is not counted by ArgNumber
even though it is
present in args
.
Note that any end-of-line characters within command line arguments are
mapped to space (20X
) characters. This ensures, that a single
argument is always mapped onto a single line of text, even if it has
embedded end-of-line characters.
Also, be careful with settings for TextRider.Reader
and especially
TextRider.Scanner
: end-of-line characters are treated as whitespace
by many of the read operations, which means, for a program foo
, the
reader or scanner has no way of distinguishing between
foo 123 bar for "123 bar"
You would normally consider the first invocation as having two arguments,
and the second as having one; which is also how ProgramArgs would interpret
them. For foo 123 bar
, args
would contain
foo 123 bar
whereas, for foo "123 bar"
, args
would contain
foo 123 bar
But a text reader or scanner, if set to treat end-of-line as whitespace, would treat both of these invocations as equivalent.
Please note: In cases where separate arguments need to be considered as a whole, the reader method
ReadLine
should be used. Unlike other read operations, such asReadInt
orReadIdentifier
, leading whitespace is not skipped and, after completion, the reading position is just behind the end-of-line character.So
ReadLine
should be used to read, for example, file name arguments because operating systems like Unix typically allow arbitrary characters in file names, including blanks and control codes.
Module ProgramArgs
provides local equivalents for the following
constants from module Channels
: done
, outOfRange
,
readAfterEnd
, channelClosed
, noWriteAccess
, and
noModTime
.
(VAR ch: Channel)
ArgNumber (): LONGINT
As a further example, suppose a program foo
required exactly two
(positional) command line arguments. The first is an integer value and the
second is an identifier. Also, suppose that all of the following
invocations are to be considered equivalent:
foo 123 bar foo +123 bar foo " +123" " bar"
Note that, the following module would not consider `foo 123 " bar "' or `foo 123+ bar' to be equivalent to the above invocations.
Example:
VAR r: TextRider.Reader; str: ARRAY 256 OF CHAR; int: LONGINT; r := TextRider.ConnectReader(ProgramArgs.args); IF r = NIL THEN (* Error processing: failed to connect to `args' *) END; IF ProgramArgs.args.ArgNumber() # 2 THEN (* Error processing: wrong number of arguments *) END; (* skip past the line containing the program name `foo' *) r.ReadLn; r.ReadLInt(int); IF r.res # TextRider.done THEN (* Error processing: can't read an integer *) ELSIF ~r.Eol() THEN (* Error processing: this argument has other stuff after the integer just read *) END; r.ReadLn; (* skip to the next line *) r.ReadIdentifier(str); IF r.res # TextRider.done THEN (* Error processing: can't read an identifier *) ELSIF ~r.Eol() THEN (* Error processing: extra stuff after the identifier *) END;
Module `Msg' provides a framework for messages, which are used as a
level of indirection between simple error codes and human readable error
messages. Unlike numeric error codes, an instance of Msg
carries its
own interpretation context. Using this context, plus the error code stored
in the message, and possibly additional data, the message can be converted
into a description. The additional data can be text fragments, numbers, or
other messages, and it can be inserted anywhere into the message's text.
There is no need to determine the message text at the place the message is
created. A message can be converted to text anywhere in the program.
This module actually combines several concepts: messages, message attributes, message contexts, and message lists. Although this may seem a bit complicated, the actual mechanism is very simple.
A message is an object that can be converted to human readable text and presented to a program's user. Within the OOC Library, messages are used to store errors in the I/O modules. Another example is an XML parser, which uses messages to create an error list when parsing an XML document.
Contexts and attributes are primarily of interest for modules
that generate messages. These determine the content of the message, and how
it can be translated into readable text. A typical user will mostly be in
the position of message consumer, and will be handed filled in message
objects. For a user, the typical operation will be to convert a message
into descriptive text (see methods Message.GetText()
and
Message.GetLText()
).
Message lists are a convenience feature for modules like parsers, which normally do not abort after a single error message. Usually, they try to continue their work after an error, looking for more problems and possibly emitting more error messages. Using message lists, errors can be collected together (e.g., within a compiler) to be presented to the user in a single batch.
Msg
Msg
NIL
, and are used by
MsgList
.
Code
Context
Attribute
Attribute.nextAttrib
to traverse the list.
The following function is a constructor for a message object:
(context: Context; code: Code): Msg
Users of messages will be most interested in the following methods, which are used to retrieve the textual representation of a message:
(msg: Msg)
GetLText (VAR text: LString)
msg.context.GetTemplate
. Then the
attributes are inserted into the template string; the placeholder string
`${foo}' is replaced with the textual representation of each
attribute (see Context.GetTemplate
).
Pre-condition: LEN(text)<2^15
Please note: Behaviour is undefined if replacement text of
an attribute contains an attribute reference.
(msg: Msg)
GetText (VAR text: String)
GetLText
, but the message text is
truncated to ISO-Latin-1 characters. All characters that are not part of
ISO-Latin-1 are mapped to question marks `?'.
Example:
VAR r: TextRider.Reader; f: Files.File; str: ARRAY 256 OF CHAR; res: Files.Result; (* `Result' is an alias for `Msg.Msg'. *) f := Files.Old("Sample.txt", {Files.read}, res); IF (f = NIL) THEN res.GetText(str); Err.String(str); Err.Ln; ELSE r := TextRider.ConnectReader(f); IF (r # NIL) THEN r.ReadLine(str); (* Read the lines of a file. *) WHILE r.res=Files.done DO Out.String(str); Out.Ln; (* And output them to the screen. *) r.ReadLine(str); END; (* Check to see if it stopped reading because it reached * end-of-file. If not, then print the error string. *) IF (r.res.code#Files.readAfterEnd) THEN r.res.GetText(str); Err.String(str); Err.Ln; END; END; END;
A programmer who is creating a library module can use the following methods to manage the attributes of a message:
(msg: Msg)
GetAttribute (name: String): Attribute
NIL
is returned.
(msg: Msg)
SetAttribute (attr: Attribute)
Length(attr.name^)<=sizeAttrName
and
attr has not been attached to any other message.
(msg: Msg)
SetIntAttrib (name: String; value: LONGINT)
Length(name)<=sizeAttrName
Example:
VAR lineVal, colVal: LONGINT; attrib1, attrib2: Msg.Attribute; msg.SetIntAttrib ("line", lineVal); msg.SetIntAttrib ("column", colVal); ... attrib1 := GetAttribute("line"); attrib2 := GetAttribute("column");
(msg: Msg)
SetStringAttrib (name: String; value: StringPtr)
Length(name)<=sizeAttrName
(msg: Msg)
SetLStringAttrib (name: String; value: LStringPtr)
Length(name)<=sizeAttrName
(msg: Msg)
SetMsgAttrib (name: String; value: Msg)
Length(name)<=sizeAttrName
When writing a library module (or perhaps a set of related library modules),
a Context
is defined, which may specify message formats and handle
generation of messages. Specific Attributes
that directly relate to
a Context
, and its related messages, are defined to go along with
that Context
.
The basic steps are
Context
.
Context
class (and be sure to initialize it
in the module body).
GetTemplate
method so that it supplies messages in the
desired format (using GetAttribute
to retrieve attribute information,
if necessary).
The following is an example showing how a Context
can be set up. (In
this case, for a command line parser). Note that use of Attributes
is not required (and not shown in this example), and that this example has
only a single error message.
MODULE CmdLine; IMPORT Msg; (* Context and template infrastructure *) CONST connectFailed = 1; TYPE ErrorContext = POINTER TO ErrorContextDesc; ErrorContextDesc = RECORD (Msg.ContextDesc) END; VAR cmdLineContext: ErrorContext; PROCEDURE (context: ErrorContext) GetTemplate* (msg: Msg.Msg; VAR templ: Msg.LString); VAR t: ARRAY 128 OF Msg.LChar; BEGIN CASE msg. code OF | connectFailed: t := "Failed to connect reader to program arguments" END; COPY (t, templ) END GetTemplate; PROCEDURE Error (code: Msg.Code): Msg.Msg; (* Create error message for context `cmdLineContext', using the error code `code'. *) VAR err: Msg.Msg; BEGIN err := Msg.New (cmdLineContext, code); RETURN err END Error; BEGIN (* initialize error context *) NEW (cmdLineContext); Msg.InitContext (cmdLineContext, "CmdLine") END CmdLine.
StringPtr
InitContext
).
The following is an initialization procedure for Context
s:
(context: Context; id: String)
Context
. The string
argument id should describe the message context to the programmer. It
should not appear in output generated for a program's user, or at least, it
should not be necessary for a user to interpret this string to understand the
message. Generally, it is a good idea to use the module name of the context
variable for the identifier. If this is not sufficient to identify the
variable, add the variable name to the string.
(context: Context)
GetTemplate (msg: Msg; VAR templ: LString)
GetText
. Typically, the string is derived from the message code, and
it contains attribute references. Instead of the reference `${foo}',
the procedure GetText
(see below) will insert the textual
representation of the attribute with the name `foo'. The special
reference `${MSG_CONTEXT}' is replaced by the value of
context.id
, and `${MSG_CODE}' with msg.code
.
The default implementation returns this string:
MSG_CONTEXT: ${MSG_CONTEXT} MSG_CODE: ${MSG_CODE} attribute_name: ${attribute_name}The last item is repeated for every attribute name. The lines are separated by
CharClass.eol
.
Pre-condition: msg # NIL
Example:
PROCEDURE (context: aContext) GetTemplate* (msg: Msg.Msg; VAR templ: Msg.LString); VAR t: ARRAY 128 OF Msg.LChar; BEGIN CASE msg. code OF ... (* set the value of `t' with appropriate message *) END; COPY (t, templ); (* then append the line and column numbers --- * note that attribute values are later substituted by * `Msg.GetLText' or `Msg.GetText'. *) LongStrings.Append (" line=${line}, column=${column}", templ); END GetTemplate;
InitAttribute
,
NewIntAttrib
, NewStringAttrib
, NewLStringAttrib
, or
NewMsgAttrib
.
GetText
function, the value part of each attribute can be converted
to some textual representation, and then inserted into the message's text.
Within a message, an attribute is uniquely identified by its name.
Attribute
StringPtr
Attribute
is restricted to sizeAttrName
characters.
The following is an initialization procedure for Attribute
s:
(attr: Attribute; name: String)
(attr: Attribute)
ReplacementText (VAR text: LString)
sizeAttrReplacement
characters. Note that GetLText()
calls
this procedure with a text buffer of `sizeAttrReplacement+1' bytes.
The following are default implementations for some commonly used message
attributes and their corresponding constructors and ReplacementText
methods:
LONGINT
(name: String; value: LONGINT): IntAttribute
IntAttribute
)
object.
Pre-condition: Length(name)<=sizeAttrName
(attr: IntAttribute)
ReplacementText (VAR text: LString)
StringPtr
(name: String; value: StringPtr): StringAttribute
StringAttribute
)
object.
Pre-condition: Length(name)<=sizeAttrName
(attr: StringAttribute)
ReplacementText (VAR text: LString)
LStringPtr
(name: String; value: LStringPtr): LStringAttribute
LStringAttribute
)
object.
Pre-condition: Length(name)<=sizeAttrName
(attr: LStringAttribute)
ReplacementText (VAR text: LString)
Msg
(name: String; value: Msg): MsgAttribute
MsgAttribute
)
object.
Pre-condition: Length(name)<=sizeAttrName
(attr: MsgAttribute)
ReplacementText (VAR text: LString)
LONGINT
Msg
Msg.nextMsg
and Msg.prevMsg
.
The following are for construction and initialization of MsgList
s:
(l: MsgList)
(): MsgList
The following methods are used to add messages to a message list:
(l: MsgList)
Append (msg: Msg)
(l: MsgList)
AppendList (source: MsgList)
Mappers are high-level riders, which are used to translate between a sequence of data items and an uninterpreted sequence of bytes (see section Riders and Mappers). Thus, the reader and writer types in BinaryRider and TextRider are considered mappers.
The standard mappers, defined in this section, use the basic riders associated with a particular channel type for reading and writing bytes. You'll notice that there are very few error code constants defined within either of these modules; error codes are dependant on the channel being read, and so you'll have to use the constant values for readers and writers that are declared within each particular channel module.
Because OOC has both CHAR
and LONGCHAR
character types,
mappers for textual data have been set up as a class hierarchy, with base
classes in module `Rider' from which all other text mappers derive.
The text mapper modules (`Rider', `LongRider', `TextRider', and `UnicodeRider') provide facilities for reading and writing values in text format. Text format is delimited, or otherwise formatted, sequences of character values that can be interpreted as words, numbers, symbols, and so forth. This corresponds to the way human beings read text, or perhaps how an Oberon-2 source file is parsed by a compiler. Data in text format are generally refered to simply as text.
Text can usually be interpreted in a limited number of ways. For example,
the number 2
can be read as an INTEGER
value or as a
REAL
. It could be an element of a SET
, or perhaps even be
part of an identifier such as oo2c
. The interpretation is based on
context and the format of the characters rather than as a fixed number of
bytes.
Because the corresponding classes from the text mapper modules provide related facilities, they form a class hierarchy as follows:
Rider [ABSTRACT] / \ / \ / \ TextRider LongRider [ABSTRACT] | | | UnicodeRider
Module `Rider' encapsulates the base classes for all other text mapper
classes. These base classes (Reader
, Writer
, and
Scanner
) are abstract classes that define the interface elements
required for concrete classes derived from them.
See the concrete text mapper classes for more detail and examples of usage (section Module TextRider and section Module UnicodeRider).
Reader.eol
.
Also note that, after any failed read operation, all further attempts to
read will be ignored until the error is cleared using ClearError
.
See section Class Reader (TextRider), for examples of usage.
SET
Msg.Msg
ReadLine
, ReadInt
, SetPos
, etc.).
Error codes (for res.code
) are highly dependent on the channel being
read, and therefore on the basic riders provided by that channel, so you
must look at the result codes for a particular channel's reader type (e.g.,
Files.Reader
error codes). See the various channel types for details
of these error codes (i.e., section Module Files, section Module StdChannels, or
section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
Channel.Channel
The following fields determine how the reader interprets end-of-line
markers. Note that the end-of-line marker may contain the character
`0X', which means its length must be stored in a separate field. The
eol
marker cannot be empty, and all characters must be an ASCII code
in the range 00X..1FX
.
ARRAY maxLengthEol OF CHAR
INTEGER
eol
. The default value for this is
`-1', which means that end-of-line is auto detected (see SetEol
below). Otherwise, this value is in the range 1 <= eolLen <=
maxLengthEol
.
The following methods can be used to check the status of a reader or, in some cases, change its state. Some methods are fully described in the abstract reader section (see section Abstract Class Reader), so only brief descriptions of those are given here.
(r: Reader)
Available () : LONGINT
(r: Reader)
ClearError
(r: Reader)
Eol (): BOOLEAN
TRUE
if the reader is currently positioned at an
end-of-line marker (see SetEol
below). This will also return
TRUE
if r.res # done
. Otherwise, FALSE
is
returned.
(r: Reader)
Pos (): LONGINT
r.base
.
(r: Reader)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
eol
, or if it contains a character >= ` ', then
r.res.code
is set to invalidFormat
.
A marker length markerLen=-1
enables auto detection of the
end-of-line convention used by the channel. For auto detection to work, the
channel is required to use one of the following eol
markers:
ReadChar
is unaffected by the current
eol
setting. That is, if the end-of-line marker consists of more
than one character (like `CR/LF'), each character is read separately.
All other read operations view an end-of-line marker at an atomic entity
when the channel is read sequentially.
If auto detection is enabled, and the eol
convention of the file is
`CR/LF', then the first end-of-line marker is not skipped completely
when reached by the reader (r.Pos()
is at the `LF'). This
is transparent to all reading procedures except ReadChar
and
Pos
; the `LF' will be skipped automatically on the next read.
This positioning inconsistency only applies for the very first eol
encountered.
Pre-condition: All of the following apply:
r.res = done
, and
(markerLen = -1) OR (1 <= markerLen < LEN (marker))
, and
markerLen <= maxLengthEol
, and
i
: marker[i] < 20X
(r: Reader)
SetOpts (opts: SET)
r.opt
.
(r: Reader)
SetPos (newPos: LONGINT)
The following methods read a value of the given type from the current
position of the reader. Most read operations skip leading whitespace before
reading a token; there are only three methods that do not skip whitespace:
ReadChar
, ReadLn
, and ReadLine
.
When attempting to read, and if the value is not properly formatted for its
type, r.res.code
is set to invalidFormat
. The reader remains
positioned at the character which caused the invalidFormat
error, but
further reading can not take place until the error is cleared.
If a number, or potential set element, is properly formatted, but has a
value that is out of range of the target type, then a valueOutOfRange
error occurs. In this case, the reader is positioned after the last
character that was read. Again, further reading can not take place until
the error is cleared.
A valueOutOfRange
error also occurs for methods reading into an
ARRAY OF CHAR
(i.e., ReadLine
, ReadIdentifier
, and
ReadString
) if the character array is not large enough to hold the
entire input.
Otherwise, for any operation attempting to read when there are no characters
left to be read, a read-after-end error occurs and Reader.res.code
is
set to readAfterEnd
.
In any case, whenever an error occurs, it is safest to assume that no value has been read. That is, the variable being read into is left with an undefined value.
All further calls of these read methods will be ignored if
r.res#done
. That is, no new characters will be read if an
error has occurred previously.
(r: Reader)
ReadBool (VAR bool: BOOLEAN)
ReadIdentifier
below), and if it is
either of the tokens TRUE
or FALSE
, it is converted to a
BOOLEAN
value. If this method encounters any other token, an
invalidFormat
error occurs and the value of bool is undefined.
(r: Reader)
ReadChar (VAR ch: CHAR)
(r: Reader)
ReadHex (VAR lint: LONGINT)
LONGINT
value.
The first character must be a decimal digit (i.e., `0..9') and
subsequent characters must be valid hexadecimal digits (i.e., `0..9' or
`A..F'). If the first non-whitespace character is not a digit, then an
invalidFormat
error occurs.
If the input is properly formatted as an unsigned hex number, but the value
is out of range for a LONGINT
, then a valueOutOfRange
error
occurs.
Upon encountering an error, the value of lint is undefined.
Please note: Because LONGINT
values are signed, hex numbers
in the range `80000000H..FFFFFFFFH' are interpreted as negative
LONGINT
values.
(r: Reader)
ReadIdentifier (VAR s: ARRAY OF CHAR)
invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
(r: Reader)
ReadInt (VAR int: INTEGER)
INTEGER
value.
If the first character is not a digit, a "+
" sign, or a "-
"
sign, then an invalidFormat
error occurs.
If the input is properly formatted as a signed whole number, but the value
is out of range for an INTEGER
, then a valueOutOfRange
error
occurs.
Upon encountering an error, the value of int is undefined.
(r: Reader)
ReadLInt (VAR lint: LONGINT)
ReadInt
, except that it
deals with LONGINT
values.
(r: Reader)
ReadSInt (VAR sint: SHORTINT)
ReadInt
, except that it
deals with SHORTINT
values.
(r: Reader)
ReadLine (VAR s: ARRAY OF CHAR)
0X
.
If r is already positioned at an end-of-line character, s
returns as an empty string.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs; s returns with the sequence of
characters that have been read so far (terminated by 0X
).
If r has already reached the end of the channel (i.e., there are no
more characters left to read), a readAfterEnd
error occurs and
s returns as an empty string.
(r: Reader)
ReadLn
readAfterEnd
error occurs.
(r: Reader)
ReadString (VAR s: ARRAY OF CHAR)
'
) or double
("
) quote marks. The opening quote must be the same as the closing
quote and must not occur within the string.
Characters will be read until the terminating quote mark is encountered, an
invalid character is read (end-of-line is always considered invalid), there
are no more characters available in the channel, or the string s is
full. s is always terminated with 0X
.
Unquoted strings produce an invalidFormat
error. Strings with no
terminating quote mark also result in an invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
(r: Reader)
ReadReal (VAR real: REAL)
REAL
value.
If the first character is not a digit, a "+
" sign, or a "-
"
sign, then an invalidFormat
error occurs.
If the input is properly formatted as a signed fixed or floating-point
number, but the value is out of range for a REAL
, then a
valueOutOfRange
error occurs.
Upon encountering an error, the value of real is undefined.
(r: Reader)
ReadLReal (VAR lreal: LONGREAL)
ReadReal
, except that it
deals with LONGREAL
values.
(r: Reader)
ReadSet (VAR s: SET)
SET
.
If the sequence of characters does not form a valid set constructor, then an
invalidFormat
error occurs.
If the input is properly formatted as a set constructor, but a set element
has a value out of the range 0..MAX(SET)
, then a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
See section Class Writer (TextRider), for examples of usage.
SET
Msg.Msg
WriteBytes
, WriteInt
, SetPos
, etc.).
Error codes are highly dependent on the channel being written to (and
therefore on the basic riders provided for that channel), so you must look
at the result codes for the basic writer that is associated with that
particular channel (e.g., Files.Writer
error codes). See the various
channel types for details of these error codes (i.e., section Module Files,
section Module StdChannels, or section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
Channel.Channel
The following methods can be used to check the status of a writer or, in some cases, change its state. Some methods are fully described in the abstract writer section (see section Abstract Class Writer), so only brief descriptions of those are given here.
(w: Writer)
ClearError
(w: Writer)
Pos () : LONGINT
w
in
channel w.base
.
(w: Writer)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
eol
, then w.res.code
is set to
invalidFormat
. The empty marker is permitted. The default value for
a newly created writer is CharClass.systemEol
.
Pre-condition: All of the following apply:
w.res = done
, and
0 <= markerLen < LEN (marker)
, and
markerLen <= maxLengthEol
.
(w: Writer)
SetOpts (opts: SET)
w.opt
.
(w: Writer)
SetPos (newPos: LONGINT)
The following writer methods are used to write values in text format to the underlying channel. In some situations, it is possible for only part of the value to be actually written.
(w: Writer)
WriteBool (bool: BOOLEAN)
TRUE
or
FALSE
.
(w: Writer)
WriteChar (ch: CHAR)
(w: Writer)
WriteHex (lint: LONGINT; d: LONGINT)
(w: Writer)
WriteInt (int: INTEGER; n: LONGINT)
(w: Writer)
WriteLInt (lint: LONGINT; n: LONGINT)
WriteInt
, except that it
deals with LONGINT
values.
(w: Writer)
WriteSInt (sint: SHORTINT; n: LONGINT)
WriteInt
, except that it
deals with SHORTINT
values.
(w: Writer)
WriteReal (real: REAL; n, k: LONGINT)
(w: Writer)
WriteLReal (lreal: LONGREAL; n, k: LONGINT)
WriteReal
, except that it
deals with LONGREAL
values.
(w: Writer)
WriteRealEng (real: REAL; n, k: LONGINT)
(w: Writer)
WriteLRealEng (lreal: LONGREAL; n, k: LONGINT)
WriteRealEng
, except that
it deals with LONGREAL
values.
(w: Writer)
WriteRealFix (real: REAL; n, k: LONGINT)
(w: Writer)
WriteLRealFix (lreal: LONGREAL; n, k: LONGINT)
WriteRealFix
, except that
it deals with LONGREAL
values.
(w: Writer)
WriteSet (s: SET)
..
") where appropriate.
(w: Writer)
WriteString (s: ARRAY OF CHAR)
0X
character. The behaviour of this method is undefined if s is an
unterminated character array.
Please note: ReadString
and WriteString
are
not symmetric. That is, WriteString
does not enclose the written
string in quote marks; only the actual character values contained in s
are written.
(w: Writer)
WriteLn
CharClass.systemEol
(see SetEol
above).
A text scanner is a special type of reader, which is used to parse
text for different kinds of tokens. Integers, reals, strings, identifiers,
set constructors, the boolean tokens TRUE
and FALSE
, and other
special symbols are all tokens recognized by this kind of scanner.
These tokens are scanned sequentially, converted to an appropriate type, and
then returned in one of the scanner's fields. The scanner's type
field is then used to determine the type of token which has been scanned.
Along with some typical reader methods, such as SetPos
, the primary
method of a scanner is Scan
, which simply scans the next token based
on the scanner's current options setting.
See section Class Scanner (TextRider), for examples of usage.
Please note: LEN()
can be used on a variable of type
String
to determine the maximum size that can be held by a scanner
string.
type
field (section Summary of TextRider Constants).
Note that a scanner will not continue to read (via calls to Scan
) if
it has scanned an invalid token or an error occurs; ClearError
must
be called explicitly before scanning can continue. The difference is that
invalid
means that the token could not be interpreted; a sequence of
characters was read, but could not be interpreted as a valid token. An
error
occurs when there is a problem with the underlying
Reader
; so, error
is used to determine when you have reached
end-of-text.
Channel.Channel
LONGINT
Scan
.
SET
LONGINT
Pos()
method.
This value may be useful when an invalid
token is scanned, as it will
point to the start of the invalid
token (whereas Pos()
would
be positioned after the invalid token). You could, for example,
reset the scanner options and re-position the scanner back at the invalid
token to attempt a re-scan.
Msg.Msg
Scan
, SetPos
, etc.).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
INTEGER
bool
, char
, error
, int
, invalid
,
line
, ident
, real
, set
, string
,
tab
, and undefined
are possible values for type
. See
also the related output fields listed below.
The following are the output fields within a scanner. Before the first call
to the Scan
method, the values of these fields are undefined. After
each successive call to Scan
, type
is set and the matching
output field contains the value of the scanned token. The value of output
fields not corresponding to type
are undefined.
BOOLEAN
interpretBools
option is set and one of the tokens TRUE
or FALSE
is scanned.
CHAR
type
is char
, line
, or tab
.
LONGINT
type
is int
.
Please note: Valid integers are in either signed decimal or
unsigned hexadecimal formats (hexadecimal tokens must be terminated
with an "H
" character).
LONGREAL
type
is real
.
type
is set
.
type
is string
or ident
.
The following scanner methods are equivalent to the corresponding reader methods described in section Class Reader (TextRider), so only brief descriptions are given here.
(s: Scanner)
Available () : LONGINT
(s: Scanner)
ClearError
(s: Scanner)
Pos (): LONGINT
s.base
. Note that the value returned by this method is
different from the position indicated by the scanner's pos
field.
(s: Scanner)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
Reader.SetEol
. A marker length markerLen=-1
enables auto
detection of the end-of-line convention used by the channel.
(s: Scanner)
SetOpts (opts: SET)
s.opt
. See
section Summary of TextRider Constants for possible option values.
(s: Scanner)
SetPos (newPos: LONGINT)
(s: Scanner)
Scan
s.type
is set and the matching output field is assigned a
value.
If the end of the valid text is reached, s.type
is set to
error
. (Note that error
is set when the last available valid
token is read, not necessarily by a readAfterEnd
condition.)
Valid tokens are described as follows:
bool
interpretBools
is set as a scanner option, the text tokens
TRUE
or FALSE
are read as bool
. (Otherwise, these
tokens are read as type ident
.)
char
char
:
interpretSets
is not set, elements of a set constructor,
"{
", "}
", ",
", are read as char
(and the
associated integer constants are read as separate tokens).
interpretStrings
is not set, quote characters are read as
char
(and string contents are then read as separate tokens).
useSignedNumbers
is not set, "+
" and "-
" are
read as char
. (Otherwise, they are always considered part of a
number.)
int
H
". Also, lower-case letters,
`a..f', are not valid hex digits.)
line
returnCtrlChars
is set, an end-of-line character is read as
s.type = line
. Otherwise, it is counted as whitespace.
ident
_
" is not considered as part of
an identifier, nor is a selector ".
".)
real
set
string
tab
returnCtrlChars
is set, a tab character is read as
s.type = tab
. Otherwise, it is counted as whitespace.
Module `LongRider' extends the classes of `Rider' to provide
support for types LONGCHAR
and LongString
. The classes of
`LongRider' (Reader
, Writer
, and Scanner
) are also
abstract, and only extensions are described in this section; see section Module Rider
for descriptions of other facilities.
Also, see the concrete text mapper classes for more detail and examples of usage (see section Module TextRider and section Module UnicodeRider).
Please note: Care should be taken when using the method
SetPos
for classes based on `LongRider'. Recall that
SetPos
operates just like the corresponding method from class
Channel
; that is, position is set directly within the byte stream.
Setting the position is based on byte position rather than character
position.
Because `LongRider' based classes deal with multi-byte character
encodings, which may be of variable width, and because SetPos
positions a reader on a byte level, a user cannot necessarily set a rider to
an arbitrary character position within a channel. For practical purposes,
variable width encodings may limit usage to saving the position of a reader
based on a call like pos := reader.Pos()
, which can later be restored
via reader.SetPos(pos)
.
However, even in such a case, moving to a previously saved position might fail for encodings that use different states during decoding. For example, if the encoding uses special byte sequences to switch between different mappings while decoding, the actual mapping in use at file position `x' will not be reinstated correctly when calling `SetPos(x)'.
Rider.Reader
that provides support
for LONGCHAR
and LongString
.
The specification for ReadChar
is changed for LongRider.Reader
in that it actually reads a LONGCHAR
value (2 bytes) from the channel
and then attempts to map it to a CHAR
value (ISO-Latin-1). If the
value cannot be mapped, a valueOutOfRange
error occurs. Consequently
for `LongRider', ReadLine
, ReadIdentifier
, and
ReadString
produce the same error in similar situations.
Also note that a valueOutOfRange
error occurs for methods reading
into an ARRAY OF LONGCHAR
(i.e., ReadLLine
,
ReadLIdentifier
, and ReadLString
) if the (long) character
array is not large enough to hold the entire input.
Reader
adds the following methods:
(r: Reader)
ReadLChar (VAR ch: LONGCHAR)
LONGCHAR
) character value and places it in
ch.
(r: Reader)
ReadLIdentifier (VAR s: ARRAY OF LONGCHAR)
invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
(r: Reader)
ReadLLine (VAR s: ARRAY OF LONGCHAR)
LONGCHAR
) characters into s; reading
continues until an end-of-line character is encountered, the array s
is full, or r reaches the end of the channel. The end-of-line
character is discarded and s is always terminated with 0X
.
If r is already positioned at an end-of-line character, s
returns as an empty string.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs; s returns with the sequence of
characters that have been read so far (terminated by 0X
).
If r has already reached the end of the channel (i.e., there are no
more characters left to read), a readAfterEnd
error occurs and
s returns as an empty string.
(r: Reader)
ReadLString (VAR s: ARRAY OF CHAR)
LONGCHAR
) characters enclosed in single
('
) or double ("
) quote marks. The opening quote must be the
same as the closing quote and must not occur within the string.
Characters will be read until the terminating quote mark is encountered, an
invalid character is read (end-of-line is always considered invalid), there
are no more characters available in the channel, or the string s is
full. s is always terminated with 0X
.
Unquoted strings produce an invalidFormat
error. Strings with no
terminating quote mark also result in an invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
Rider.Writer
that provides support
for LONGCHAR
and LongString
.
Note that the specification for WriteChar
is changed for
LongRider.Writer
in that it actually writes 2 bytes at a time to the
channel (i.e., CHAR
values are actually written as Unicode values).
ReadLine
, ReadIdentifier
, and ReadString
behave
similarly for `LongRider'.
LongRider.Writer
adds the following methods:
(w: Writer)
WriteLChar (ch: LONGCHAR)
LONGCHAR
) character value ch.
(w: Writer)
WriteLString (s: ARRAY OF LONGCHAR)
0X
character. The behaviour of this method is undefined if s
is an unterminated (LONGCHAR
) character array.
Please note: ReadLString
and WriteLString
are
not symmetric. That is, WriteLString
does not enclose the written
string in quote marks; only the actual (LONGCHAR
) character values
contained in s are written.
Rider.Scanner
that provides support
for LONGCHAR
and LongString
.
Please note: LEN()
can be used on a variable of type
LongString
to determine the maximum size that can be held by a
scanner string.
INTEGER
lchar
, lident
, lline
, lstring
,
ltab
.
LONGCHAR
type
is lchar
, lline
, or ltab
.
type
is lstring
or lident
.
Module `TextRider' provides concrete classes derived from the abstract
base classes of module `Rider'. `TextRider' is used for reading
and writing data as character type CHAR
(i.e., interpreting byte
streams as ISO-Latin-1 characters). The descriptions below include details
of the `TextRider' facilities (much of which is repeated from the
section on module `Rider') as well as many examples of use.
The following program fragment gives an example of how you could use `TextRider' facilities to read the entire contents of a file, one line at a time, and echo each line to the screen (note that no error checking is done):
VAR r: TextRider.Reader; f: Files.File; str: ARRAY 256 OF CHAR; res: Result; f := Files.Old("Sample.txt", {Files.read}, res); r := TextRider.ConnectReader(f); r.ReadLine(str); WHILE r.res=Files.done DO Out.String(str); Out.Ln; r.ReadLine(str); END;
Reader.eol
.
Rider.Reader
that provides
facilities for reading various kinds of text. Note that this type does not
inherit properties from any basic reader type; rather it uses the basic
reader type associated with the channel it is attached to.
Also note that, after any failed read operation, all further attempts to
read will be ignored until the error is cleared using ClearError
.
SET
Msg.Msg
ReadLine
, ReadInt
, SetPos
, etc.).
Error codes (for res.code
) are highly dependent on the channel being
read, and therefore on the basic riders provided by that channel, so you
must look at the result codes for a particular channel's reader type (e.g.,
Files.Reader
error codes). See the various channel types for details
of these error codes (i.e., section Module Files, section Module StdChannels, or
section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
Channel.Channel
The following fields determine how the reader interprets end-of-line
markers. Note that the end-of-line marker may contain the character
`0X', which means its length must be stored in a separate field. The
eol
marker cannot be empty, and all characters must be an ASCII code
in the range 00X..1FX
.
ARRAY maxLengthEol OF CHAR
INTEGER
eol
. The default value for this is
`-1', which means that end-of-line is auto detected (see SetEol
below). Otherwise, this value is in the range 1 <= eolLen <=
maxLengthEol
.
The following methods can be used to check the status of a reader or, in some cases, change its state. Some methods are fully described in the abstract reader section (see section Abstract Class Reader), so only brief descriptions of those are given here.
(r: Reader)
Available () : LONGINT
(r: Reader)
ClearError
(r: Reader)
Eol (): BOOLEAN
TRUE
if the reader is currently positioned at an
end-of-line marker (see SetEol
below). This will also return
TRUE
if r.res # done
. Otherwise, FALSE
is
returned.
(r: Reader)
Pos (): LONGINT
r.base
.
(r: Reader)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
eol
, or if it contains a character >= ` ', then
r.res.code
is set to invalidFormat
.
A marker length markerLen=-1
enables auto detection of the
end-of-line convention used by the channel. For auto detection to work, the
channel is required to use one of the following eol
markers:
ReadChar
is unaffected by the current
eol
setting. That is, if the end-of-line marker consists of more
than one character (like `CR/LF'), each character is read separately.
All other read operations view an end-of-line marker at an atomic entity
when the channel is read sequentially.
If auto detection is enabled, and the eol
convention of the file is
`CR/LF', then the first end-of-line marker is not skipped completely
when reached by the reader (r.Pos()
is at the `LF'). This
is transparent to all reading procedures except ReadChar
and
Pos
; the `LF' will be skipped automatically on the next read.
This positioning inconsistency only applies for the very first eol
encountered.
Pre-condition: All of the following apply:
r.res = done
, and
(markerLen = -1) OR (1 <= markerLen < LEN (marker))
, and
markerLen <= maxLengthEol
, and
i
: marker[i] < 20X
(r: Reader)
SetOpts (opts: SET)
r.opt
. See
section Summary of TextRider Constants for possible option values.
Example:
r.SetOpts({TextRider.returnCtrlChars}); => read operations using r do not treat EOL and TAB characters as whitespace. r.SetOpts(TextRider.defReaderOptions); => reader options set to default values.
(r: Reader)
SetPos (newPos: LONGINT)
The following methods read a value of the given type from the current
position of the reader. Most read operations skip leading whitespace before
reading a token; there are only three methods that do not skip whitespace:
ReadChar
, ReadLn
, and ReadLine
.
When attempting to read, and if the value is not properly formatted for its
type, r.res.code
is set to invalidFormat
. The reader remains
positioned at the character which caused the invalidFormat
error, but
further reading can not take place until the error is cleared.
If a number, or potential set element, is properly formatted, but has a
value that is out of range of the target type, then a valueOutOfRange
error occurs. In this case, the reader is positioned after the last
character that was read. Again, further reading can not take place until
the error is cleared.
A valueOutOfRange
error also occurs for methods reading into an
ARRAY OF CHAR
(i.e., ReadLine
, ReadIdentifier
, and
ReadString
) if the character array is not large enough to hold the
entire input.
Otherwise, for any operation attempting to read when there are no characters
left to be read, a read-after-end error occurs and Reader.res.code
is set to readAfterEnd
.
In any case, whenever an error occurs, it is safest to assume that no value has been read. That is, the variable being read into is left with an undefined value.
All further calls of these read methods will be ignored if
r.res#done
. That is, no new characters will be read if an
error has occurred previously.
(r: Reader)
ReadBool (VAR bool: BOOLEAN)
ReadIdentifier
below), and if it is
either of the tokens TRUE
or FALSE
, it is converted to a
BOOLEAN
value. If this method encounters any other token, an
invalidFormat
error occurs and the value of bool is undefined.
(r: Reader)
ReadChar (VAR ch: CHAR)
(r: Reader)
ReadHex (VAR lint: LONGINT)
LONGINT
value.
The first character must be a decimal digit (i.e., `0..9') and
subsequent characters must be valid hexadecimal digits (i.e., `0..9' or
`A..F'). If the first non-whitespace character is not a digit, then an
invalidFormat
error occurs.
If the input is properly formatted as an unsigned hex number, but the value
is out of range for a LONGINT
, then a valueOutOfRange
error
occurs.
Upon encountering an error, the value of lint is undefined.
Please note: Because LONGINT
values are signed, hex numbers
in the range `80000000H..FFFFFFFFH' are interpreted as negative
LONGINT
values.
(r: Reader)
ReadIdentifier (VAR s: ARRAY OF CHAR)
invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
Example:
(* Input is as follows: myIdentifier x y2 3z *) VAR str: ARRAY 256 OF CHAR; r.ReadIdentifier(str) => str = "myIdentifier" r.ReadIdentifier(str) => str = "x" r.ReadIdentifier(str) => str = "y2" r.ReadIdentifier(str) => r.res.code = invalidFormat, str = undefined
(r: Reader)
ReadInt (VAR int: INTEGER)
INTEGER
value.
If the first character is not a digit, a "+
" sign, or a "-
"
sign, then an invalidFormat
error occurs.
If the input is properly formatted as a signed whole number, but the value
is out of range for an INTEGER
, then a valueOutOfRange
error
occurs.
Upon encountering an error, the value of int is undefined.
Example:
(* Input is as follows: 12345 999999999999999 forty-two *) VAR intVar: INTEGER; r.ReadInt(intVar); => intVar = 12345 r.ReadInt(intVar); => r.res.code = valueOutOfRange, intVar = undefined r.ClearError; r.ReadInt(intVar); (* attempting to read `forty-two' *) => r.res.code = invalidFormat, intVar = undefined (* r.Pos() is still at the `f' in `forty-two' *)
(r: Reader)
ReadLInt (VAR lint: LONGINT)
ReadInt
, except that it
deals with LONGINT
values.
(r: Reader)
ReadSInt (VAR sint: SHORTINT)
ReadInt
, except that it
deals with SHORTINT
values.
(r: Reader)
ReadLine (VAR s: ARRAY OF CHAR)
0X
.
If r is already positioned at an end-of-line character, s
returns as an empty string.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs; s returns with the sequence of
characters that have been read so far (terminated by 0X
).
If r has already reached the end of the channel (i.e., there are no
more characters left to read), a readAfterEnd
error occurs and
s returns as an empty string.
(r: Reader)
ReadLn
readAfterEnd
error occurs.
(r: Reader)
ReadString (VAR s: ARRAY OF CHAR)
'
) or double
("
) quote marks. The opening quote must be the same as the closing
quote and must not occur within the string.
Characters will be read until the terminating quote mark is encountered, an
invalid character is read (end-of-line is always considered invalid), there
are no more characters available in the channel, or the string s is
full. s is always terminated with 0X
.
Unquoted strings produce an invalidFormat
error. Strings with no
terminating quote mark also result in an invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
Example:
(* Input is as follows: "A well-formed string" 'This is well-formed too' "Not well-formed because of line break" *) VAR str: ARRAY 256 OF CHAR; r.ReadString(str); => str = "A well-formed string" r.ReadString(str); => str = "This is well-formed too" r.ReadString(str); => r.res.code = invalidFormat, str = undefined (* r.Pos() is now at the end of this line *) r.ClearError; r.ReadString(str); (* attempting to read `because of line break"' *) => r.res.code = invalidFormat, str = undefined
(r: Reader)
ReadReal (VAR real: REAL)
REAL
value.
If the first character is not a digit, a "+
" sign, or a "-
"
sign, then an invalidFormat
error occurs.
If the input is properly formatted as a signed fixed or floating-point
number, but the value is out of range for a REAL
, then a
valueOutOfRange
error occurs.
Upon encountering an error, the value of real is undefined.
Example:
(* Input is as follows: -42 3.1415 +54321E+30 2.34E+56 +A _34.56 *) VAR realVar: REAL; r.ReadReal(realVar); => realVar = -4.200000E+1 r.ReadReal(realVar); => realVar = 3.141500 r.ReadReal(realVar); => realVar = 5.432100E+34 r.ReadReal(realVar); => r.res.code = valueOutOfRange, realVar = undefined r.ReadReal(realVar); => r.res = done, realVar = 0.000000 (* r.Pos() is now at `A' *) r.ClearError; r.ReadLn; => Clear error and skip to the beginning of the next line r.ReadReal(realVar); => r.res.code = invalidFormat, realVar = undefined (* r.Pos() is still at the `_' in `_34.56' *)
(r: Reader)
ReadLReal (VAR lreal: LONGREAL)
ReadReal
, except that it
deals with LONGREAL
values.
(r: Reader)
ReadSet (VAR s: SET)
SET
.
If the sequence of characters does not form a valid set constructor, then an
invalidFormat
error occurs.
If the input is properly formatted as a set constructor, but a set element
has a value out of the range 0..MAX(SET)
, then a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
Example:
(* Input is as follows: {0, 1, 2, 3, 4, 5} { 0..5 } {6, 7, 1024} {6, 7, W} 9..11 {13..12} *) VAR setVar: SET; r.ReadSet(setVar); => setVar = {0..5} r.ReadSet(setVar); => setVar = {0..5} r.ReadSet(setVar); => r.res.code = valueOutOfRange, setVar = undefined (* r.Pos() is now at the `}' after the `1024' *) r.ClearError; r.ReadLn; => Clear error and skip to the beginning of the next line r.ReadSet(setVar); (* attempt to read `{6, 7, W}' *) => r.res.code = invalidFormat, setVar = undefined (* r.Pos() is now at `W' *) r.ClearError; r.ReadLn; => Clear error and skip to the beginning of the next line r.ReadSet(setVar); (* attempt to read `9..11' *) => r.res.code = invalidFormat, setVar = undefined (* r.Pos() is now at `9' *) r.ClearError; r.ReadLn; => Clear error and skip to the beginning of the next line r.ReadSet(setVar); (* attempt to read `{13..12}' *) => r.res.code = invalidFormat, setVar = undefined (* r.Pos() is now at the `}' after the `12' *)
SET
Msg.Msg
WriteBytes
, WriteInt
, SetPos
, etc.).
Error codes are highly dependent on the channel being written to (and
therefore on the basic riders provided for that channel), so you must look
at the result codes for the basic writer that is associated with that
particular channel (e.g., Files.Writer
error codes). See the various
channel types for details of these error codes (i.e., section Module Files,
section Module StdChannels, or section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
Channel.Channel
The following methods can be used to check the status of a writer or, in some cases, change its state. Some methods are fully described in the abstract writer section (see section Abstract Class Writer), so only brief descriptions of those are given here.
(w: Writer)
ClearError
(w: Writer)
Pos () : LONGINT
w
in
channel w.base
.
(w: Writer)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
eol
, then w.res.code
is set to
invalidFormat
. The empty marker is permitted. The default value for
a newly created writer is CharClass.systemEol
.
Pre-condition: All of the following apply:
w.res = done
, and
0 <= markerLen < LEN (marker)
, and
markerLen <= maxLengthEol
.
(w: Writer)
SetOpts (opts: SET)
w.opt
. See
section Summary of TextRider Constants for possible option values.
Example:
w.SetOpts({TextRider.noBuffering}); => output is not buffered. w.SetOpts(TextRider.defWriterOptions); => writer options set to default values.
(w: Writer)
SetPos (newPos: LONGINT)
The following writer methods are used to write values in text format to the underlying channel. In some situations, it is possible for only part of the value to be actually written.
(w: Writer)
WriteBool (bool: BOOLEAN)
TRUE
or
FALSE
.
(w: Writer)
WriteChar (ch: CHAR)
w.WriteChar("A"); => writes one character = "A"
(w: Writer)
WriteHex (lint: LONGINT; d: LONGINT)
w.WriteHex(127, 3); => writes "07F" w.WriteHex(127, 0); => writes "0000007F" w.WriteHex(-128, 0); => writes "FFFFFF80"
(w: Writer)
WriteInt (int: INTEGER; n: LONGINT)
w.WriteInt(54321, 0); => writes "54321" w.WriteInt(54321, 10); => writes " 54321"
(w: Writer)
WriteLInt (lint: LONGINT; n: LONGINT)
WriteInt
, except that it
deals with LONGINT
values.
(w: Writer)
WriteSInt (sint: SHORTINT; n: LONGINT)
WriteInt
, except that it
deals with SHORTINT
values.
(w: Writer)
WriteReal (real: REAL; n, k: LONGINT)
w.WriteReal(3923009, 0, 0); => writes "3.923009E+6" w.WriteReal(3923009, 0, 1); => writes "4E+6" w.WriteReal(3923009, 0, 4); => writes "3.923E+6" w.WriteReal(3923009, 10, 1); => writes " 4E+6" w.WriteReal(-39.23009, 12, 2); => writes " -3.9E+1" w.WriteReal(-39.23009, 1, 5); => writes "-3.9230E+1" w.WriteReal(0.0003923009, 6, 1); => writes " 4E-4"
(w: Writer)
WriteLReal (lreal: LONGREAL; n, k: LONGINT)
WriteReal
, except that it
deals with LONGREAL
values.
(w: Writer)
WriteRealEng (real: REAL; n, k: LONGINT)
w.WriteRealEng(39.23009, 0, 1); => writes "40" w.WriteRealEng(39.23009, 5, 2); => writes " 39" w.WriteRealEng(39.23009, 10, 5); => writes " 39.230" w.WriteRealEng(-3923009, 13, 1); => writes " -4E+6" w.WriteRealEng(-3923009, 7, 3); => writes " -3.92E+6" w.WriteRealEng(-3923009, 0, 6); => writes "-3.92301E+6" w.WriteRealEng(0.0003923009, 1, 1); => writes "400E-6" w.WriteRealEng(0.0003923009, 4, 2); => writes " 390E-6" w.WriteRealEng(0.0003923009, 16, 5); => writes " 392.30E-6"
(w: Writer)
WriteLRealEng (lreal: LONGREAL; n, k: LONGINT)
WriteRealEng
, except that
it deals with LONGREAL
values.
(w: Writer)
WriteRealFix (real: REAL; n, k: LONGINT)
w.WriteRealFix(3923009, 0, -5); => writes "3920000" (* rounded to the ten-thousands place *) w.WriteRealFix(3923009, 0, 4); => writes "3923009.0000" w.WriteRealFix(3923.5, 0, -1); => writes "3924" (* rounded to the "ones" place *) w.WriteRealFix(3923.5, 0, 0); => writes "3924." (* same as above, but writes a decimal point *) w.WriteRealFix(-39.23009, 10, 1); => writes " -39.2" w.WriteRealFix(-39.23009, 20, 4); => writes " -39.2301" w.WriteRealFix(0.0003923009, 5, 1); => writes " 0.0" w.WriteRealFix(0.0003923009, 11, 4); => writes " 0.0004"
(w: Writer)
WriteLRealFix (lreal: LONGREAL; n, k: LONGINT)
WriteRealFix
, except that
it deals with LONGREAL
values.
(w: Writer)
WriteSet (s: SET)
..
") where appropriate.
Example:
w.WriteSet({}); => writes "{}" w.WriteSet({1,6,10}); => writes "{1, 6, 10}" w.WriteSet({0, 1, 2, 3, 4, 5}); => writes "{0..5}" w.WriteSet({0, 2, 3, 4, 8}); => writes "{0, 2..4, 8}" w.WriteSet({0, 2..7, 8}); => writes "{0, 2..8}" w.WriteSet({0, 2, 4, 6} + {1, 3, 5, 7}); => writes "{0..7}"
(w: Writer)
WriteString (s: ARRAY OF CHAR)
0X
character. The behaviour of this method is undefined if s is an
unterminated character array.
Please note: ReadString
and WriteString
are
not symmetric. That is, WriteString
does not enclose the written
string in quote marks; only the actual character values contained in s
are written.
(w: Writer)
WriteLn
CharClass.systemEol
(see SetEol
above).
A text scanner is a special type of reader, which is used to parse
text for different kinds of tokens. Integers, reals, strings, identifiers,
set constructors, the boolean tokens TRUE
and FALSE
, and other
special symbols are all tokens recognized by this kind of scanner.
These tokens are scanned sequentially, converted to an appropriate type, and
then returned in one of the scanner's fields. The scanner's type
field is then used to determine the type of token which has been scanned.
Along with some typical reader methods, such as SetPos
, the primary
method of a scanner is Scan
, which simply scans the next token based
on the scanner's current options setting. A typical use of a scanner might
look similar the following program fragment:
Example:
VAR s: TextRider.Scanner; f: Files.File; res: Files.Result; f := Files.Old("Sample.txt", {Files.read}, res); s := TextRider.ConnectScanner(f); s.Scan; WHILE s.type # TextRider.error DO IF s.type = TextRider.string THEN ... (* Process string tokens *) ELSIF s.type = TextRider.ident THEN ... (* Process identifier tokens *) ELSIF s.type = TextRider.int THEN ... (* Process integer tokens *) ELSIF ... ... (* Process other token types *) END; s.Scan; END; Out.String("Total lines scanned="); Out.LongInt(s.lines, 0); Out.Ln;
Please note: LEN()
can be used on a variable of type
String
to determine the maximum size that can be held by a scanner
string.
type
field (section Summary of TextRider Constants).
Note that a scanner will not continue to read (via calls to Scan
) if
it has scanned an invalid token or an error occurs; ClearError
must
be called explicitly before scanning can continue. The difference is that
invalid
means that the token could not be interpreted; a sequence of
characters was read, but could not be interpreted as a valid token. An
error
occurs when there is a problem with the underlying
Reader
; so, error
is used to determine when you have reached
end-of-text.
Channel.Channel
LONGINT
Scan
.
SET
LONGINT
Pos()
method.
This value may be useful when an invalid
token is scanned, as it will
point to the start of the invalid
token (whereas Pos()
would
be positioned after the invalid token). You could, for example,
reset the scanner options and re-position the scanner back at the invalid
token to attempt a re-scan.
Msg.Msg
Scan
, SetPos
, etc.).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
INTEGER
bool
, char
, error
, int
, invalid
,
line
, ident
, real
, set
, string
,
tab
, and undefined
are possible values for type
. See
also the related output fields listed below.
The following are the output fields within a scanner. Before the first call
to the Scan
method, the values of these fields are undefined. After
each successive call to Scan
, type
is set and the matching
output field contains the value of the scanned token. The value of output
fields not corresponding to type
are undefined.
BOOLEAN
interpretBools
option is set and one of the tokens TRUE
or FALSE
is scanned.
CHAR
type
is char
, line
, or tab
.
LONGINT
type
is int
.
Please note: Valid integers are in either signed decimal or
unsigned hexadecimal formats (hexadecimal tokens must be terminated
with an "H
" character).
LONGREAL
type
is real
.
type
is set
.
type
is string
or ident
.
The following scanner methods are equivalent to the corresponding reader methods described in section Class Reader (TextRider), so only brief descriptions are given here.
Please note: Normally when scanning text, a program will monitor a scanner's
type
field and check forinvalid
tokens and the occurance oferror
. Theres.code
needs to be checked only to find out error details (and then, possibly, theClearError
method can be used to clear the error).Example:
VAR s: TextRider.Scanner; f: Files.File; res: Files.Result; str: ARRAY 256 OF CHAR; f := Files.Old("Sample.txt", {Files.read}, res); s := TextRider.ConnectScanner(f); f.Close; s.Scan; => s.type = error s.res.GetText(str); => str = "File has been closed"
(s: Scanner)
Available () : LONGINT
(s: Scanner)
ClearError
(s: Scanner)
Pos (): LONGINT
s.base
. Note that the value returned by this method is
different from the position indicated by the scanner's pos
field.
(s: Scanner)
SetEol (marker: ARRAY OF CHAR; markerLen: INTEGER)
Reader.SetEol
. A marker length markerLen=-1
enables auto
detection of the end-of-line convention used by the channel.
(s: Scanner)
SetOpts (opts: SET)
s.opt
. See
section Summary of TextRider Constants for possible option values.
Example:
s.SetOpts({TextRider.returnCtrlChars, TextRider.useSignedNumbers}); => s.opt = {returnCtrlChars, useSignedNumbers} s.SetOpts(s.opt + {TextRider.interpretBools}); => s.opt = {interpretBools, returnCtrlChars, useSignedNumbers} s.SetOpts(TextRider.defScannerOptions); => scanner options set to default values.
(s: Scanner)
SetPos (newPos: LONGINT)
(s: Scanner)
Scan
s.type
is set and the matching output field is assigned a
value.
If the end of the valid text is reached, s.type
is set to
error
. (Note that error
is set when the last available valid
token is read, not necessarily by a readAfterEnd
condition.)
Valid tokens are described as follows:
bool
interpretBools
is set as a scanner option, the text tokens
TRUE
or FALSE
are read as bool
. (Otherwise, these
tokens are read as type ident
.)
char
char
:
interpretSets
is not set, elements of a set constructor,
"{
", "}
", ",
", are read as char
(and the
associated integer constants are read as separate tokens).
interpretStrings
is not set, quote characters are read as
char
(and string contents are then read as separate tokens).
useSignedNumbers
is not set, "+
" and "-
" are
read as char
. (Otherwise, they are always considered part of a
number.)
int
H
". Also, lower-case letters,
`a..f', are not valid hex digits.)
line
returnCtrlChars
is set, an end-of-line character is read as
s.type = line
. Otherwise, it is counted as whitespace.
ident
_
" is not considered as part of
an identifier, nor is a selector ".
".)
real
set
string
tab
returnCtrlChars
is set, a tab character is read as
s.type = tab
. Otherwise, it is counted as whitespace.
The following procedures are provided for creating instances of
`TextRider' objects and connecting them to a channel. If the channel
being passed as an argument to any of these functions has a value of
NIL
, behavior is undefined.
Also, for any of these functions, the returned rider is positioned at the beginning of the channel for positionable channels and at the current position for non-positionable channels.
(ch: Channel.Channel): Reader
ch.res
is set to done
on success and the new reader is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
(ch: Channel.Channel): Writer
ch.res
is set to done
on success and the new writer is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
(ch: Channel.Channel): Scanner
ch.res
is set to done
on success and the new scanner is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
Example:
VAR r: TextRider.Reader; f: Files.File; res: Files.Result; f := Files.Old("test.dat", {Files.read}, res); IF (res # Files.done) THEN (* error processing *) END; r := TextRider.ConnectReader(f); IF (r = NIL) THEN (* error processing *) END;
Reader.eol
.
For other constant values that may be applicable when using module `TextRider', see the specific channel implementation that you are reading to or writing from, such as section Module Files, section Module StdChannels, or section Module ProgramArgs.
The following constant applies to the res
field, and may be compared
to it. (i.e., rider.res = done
or rider.res # done
.)
The following are possible values for res.code
:
The following are all possible values for a scanner's type
field:
interpretBools
.
Scan
when the scanner has reached the end of available
text), or a result of a lower level error (say, an error occured in the
underlying channel).
type =
invalid
, the contents of all of the scanner's output fields are undefined.
returnCtrlChars
.
interpretSets
.
interpretStrings
.
returnCtrlChars
.
Scanner.type
after ConnectScanner
or ClearError
(before any calls to Scan
).
The following is a possible writer option (i.e., a valid setting for the
writer's opt
field):
The following is a possible reader or scanner option (i.e., a valid setting
for the opt
field):
TRUE
or FALSE
are
read as boolean values (i.e., scanner.type = bool
). Otherwise, these
tokens are read as identifiers (i.e., scanner.type = ident
.)
{
", "}
",
",
", and associated integer constants) are read as SET
values.
Otherwise, these are read as separate tokens.
+
" and "-
" characters are always considered part of
a number. Otherwise, they are read as separate characters.
{}
).
{}
).
interpretBools
, interpretSets
,
interpretStrings
, and useSignedNumbers
.
Module `UnicodeRider' provides concrete classes derived from the
abstract base classes of module `LongRider'. `UnicodeRider' is
used for reading and writing data as (long) character type LONGCHAR
(i.e., interpreting byte streams as Unicode characters). The following
sections describe only `UnicodeRider' specific facilities; see
section Module TextRider for examples of usage and descriptions of facilities
inherited from section Module Rider.
LongRider.Reader
that provides
facilities for reading various kinds of unicode text.
Note that, in UnicodeRider.Reader
, ReadChar
actually reads a
LONGCHAR
value (2 bytes) from the channel and then attempts to map it
to a CHAR
value (ISO-Latin-1). If the value cannot be mapped, a
valueOutOfRange
error occurs. Consequently for `UnicodeRider',
ReadLine
, ReadIdentifier
, and ReadString
produce the
same error in similar situations.
Also note that a valueOutOfRange
error occurs for methods reading
into an ARRAY OF LONGCHAR
(i.e., ReadLLine
,
ReadLIdentifier
, and ReadLString
) if the (long) character
array is not large enough to hold the entire input.
UnicodeRider.Reader
adds the following methods:
(r: Reader)
ReadLChar (VAR ch: LONGCHAR)
LONGCHAR
) character value and places it in
ch.
(r: Reader)
ReadLIdentifier (VAR s: ARRAY OF LONGCHAR)
invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
(r: Reader)
ReadLLine (VAR s: ARRAY OF LONGCHAR)
LONGCHAR
) characters into s; reading
continues until an end-of-line character is encountered, the array s
is full, or r reaches the end of the channel. The end-of-line
character is discarded and s is always terminated with 0X
.
If r is already positioned at an end-of-line character, s
returns as an empty string.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs; s returns with the sequence of
characters that have been read so far (terminated by 0X
).
If r has already reached the end of the channel (i.e., there are no
more characters left to read), a readAfterEnd
error occurs and
s returns as an empty string.
(r: Reader)
ReadLString (VAR s: ARRAY OF CHAR)
LONGCHAR
) characters enclosed in single
('
) or double ("
) quote marks. The opening quote must be the
same as the closing quote and must not occur within the string.
Characters will be read until the terminating quote mark is encountered, an
invalid character is read (end-of-line is always considered invalid), there
are no more characters available in the channel, or the string s is
full. s is always terminated with 0X
.
Unquoted strings produce an invalidFormat
error. Strings with no
terminating quote mark also result in an invalidFormat
error.
If s is not large enough to hold the entire input, a
valueOutOfRange
error occurs.
Upon encountering an error, the value of s is undefined.
LongRider.Writer
that provides
facilities for writing various kinds of unicode text.
For UnicodeRider.Writer
, note that WriteChar
actually writes 2
bytes at a time to the channel (i.e., CHAR
values are actually
written as Unicode values). ReadLine
, ReadIdentifier
, and
ReadString
behave similarly for `LongRider'.
UnicodeRider.Writer
adds the following methods:
(w: Writer)
WriteLChar (ch: LONGCHAR)
LONGCHAR
) character value ch.
(w: Writer)
WriteLString (s: ARRAY OF LONGCHAR)
0X
character. The behaviour of this method is undefined if s
is an unterminated (LONGCHAR
) character array.
Please note: ReadLString
and WriteLString
are
not symmetric. That is, WriteLString
does not enclose the written
string in quote marks; only the actual (LONGCHAR
) character values
contained in s are written.
LongRider.Scanner
that provides
facilities for scanning sequences of (long) characters from a channel and
parsing those characters into various tokens. The tokens a scanner can
recognize are defined by the constants provided for its type
field
(section Summary of UnicodeRider Constants).
Please note: LEN()
can be used on a variable of type
LongString
to determine the maximum size that can be held by a
scanner string.
INTEGER
lchar
, lident
, lline
, lstring
,
ltab
.
LONGCHAR
type
is lchar
, lline
, or ltab
.
type
is lstring
or lident
.
Please note: After a call to Scan
, the type
field of
UnicodeRider.Scanner
is never expected to contain any of the
following values: char
, ident
, line
, string
,
tab
. But rather, the "long" versions of these type values are set
as appropriate.
The following procedures are provided for creating instances of
`UnicodeRider' objects and connecting them to a channel. If the
channel being passed as an argument to any of these functions has a value of
NIL
, behavior is undefined.
Also, for any of these functions, the returned rider is positioned at the beginning of the channel for positionable channels and at the current position for non-positionable channels.
(ch: Channel.Channel): Reader
ch.res
is set to done
on success and the new reader is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
(ch: Channel.Channel): Writer
ch.res
is set to done
on success and the new writer is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
(ch: Channel.Channel): Scanner
ch.res
is set to done
on success and the new scanner is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
Reader.eol
.
For other constant values that may be applicable when using module `UnicodeRider', see the specific channel implementation that you are reading to or writing from, such as section Module Files, section Module StdChannels, or section Module ProgramArgs.
The following constant applies to the res
field, and may be compared
to it. (i.e., rider.res = done
or rider.res # done
.)
The following are possible values for res.code
:
The following are all possible values for a scanner's type
field:
interpretBools
.
(For `UnicodeRider', type
is never expected to contain this
value. But rather, the "long" version is set when appropriate.)
Scan
when the scanner has reached the end of available
text), or a result of a lower level error (say, an error occured in the
underlying channel).
(For `UnicodeRider', type
is never expected to contain this
value. But rather, the "long" version is set when appropriate.)
LongString
).
type =
invalid
, the contents of all of the scanner's output fields are undefined.
returnCtrlChars
.
(For `UnicodeRider', type
is never expected to contain this
value. But rather, the "long" version is set when appropriate.)
returnCtrlChars
.
interpretSets
.
interpretStrings
.
(For `UnicodeRider', type
is never expected to contain this
value. But rather, the "long" version is set when appropriate.)
interpretStrings
.
returnCtrlChars
.
(For `UnicodeRider', type
is never expected to contain this
value. But rather, the "long" version is set when appropriate.)
returnCtrlChars
.
Scanner.type
after ConnectScanner
or ClearError
(before any calls to Scan
).
The following is a possible writer option (i.e., a valid setting for the
writer's opt
field):
The following is a possible reader or scanner option (i.e., a valid setting
for the opt
field):
TRUE
or FALSE
are
read as boolean values (i.e., scanner.type = bool
). Otherwise, these
tokens are read as identifiers (i.e., scanner.type = ident
.)
{
", "}
",
",
", and associated integer constants) are read as SET
values.
Otherwise, these are read as separate tokens.
+
" and "-
" characters are always considered part of
a number. Otherwise, they are read as separate characters.
{}
).
{}
).
interpretBools
, interpretSets
,
interpretStrings
, and useSignedNumbers
.
Module BinaryRider provides facilities for reading and writing binary
data. Binary data are simple sequences of byte values that may be
interpreted in any number of ways. This corresponds closely to the way
information is stored within a running program. Values are stored as a
fixed number of bytes rather than as a delimited sequence of characters.
For example, if SIZE(INTEGER) = 2
, then an INTEGER
value is
always stored as 2 bytes. If SIZE(LONGINT) = 4
, then a
LONGINT
is stored as 4 bytes.
The following program fragment gives an example of how you could read the entire contents of a file and echo each character to the screen (note that no error checking is done):
VAR r: BinaryRider.Reader; f: Files.File; ch: CHAR; res: Files.Result; f := Files.Old("Sample.txt", {Files.read}, res); r := BinaryRider.ConnectReader(f); r.ReadChar(ch); WHILE r.res=Files.done DO Out.Char(ch); r.ReadChar(ch); END;
Please note: Different kinds of computers use different conventions for the ordering of bytes within a word. Some computers put the most significant byte within a word first (this is called big-endian order), and others put it last (little-endian order). A small number of systems use different byte order schemes; they aren't supported by this module (yet). Operations provided by BinaryRider default to the little-endian byte order. However, byte order can be specified using the
SetByteOrder
methods provided by classesReader
andWriter
.Thus, programs can be written that produce files that are portable to machines with different byte orderings. It should be noted, however, that file I/O using the native byte order provides better speed efficiency.
Please note: Many of the methods for
BinaryRider.Reader
perform typicalReader
operations. Rather than duplicate descriptions of those methods here, a reference to the abstract reader type is provided instead.
Msg.Msg
ReadLine
, ReadInt
, SetPos
, etc.).
Error codes (for res.code
) are highly dependent on the channel being
read, and therefore on the basic riders provided by that channel, so you
must look at the result codes for a particular channel's reader type (e.g.,
Files.Reader
error codes). See the various channel types for details
of these error codes (i.e., section Module Files, section Module StdChannels, or
section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
SHORTINT
Channel.Channel
The following methods are all fully described in the section on abstract readers (see section Abstract Class Reader), so only brief descriptions are given here.
(r: Reader)
Available () : LONGINT
(r: Reader)
ClearError
(r: Reader)
Pos () : LONGINT
r.base
.
(r: Reader)
SetByteOrder (order: SHORTINT)
byteOrder
in reader r to order. This affects the
interpretation of byte values for applicable read operations.
Pre-condition: order is one of nativeEndian
,
littleEndian
, or bigEndian
.
Example:
VAR rBig, rLittle, r: BinaryRider.Reader; f: Files.File; f := Files.Old("test.dat", {Files.read}, res); r := BinaryRider.ConnectReader(f); => r reads from f using the default byte order (i.e., little endian) rBig := BinaryRider.ConnectReader(f); rBig.SetByteOrder(BinaryRider.bigEndian); => rBig reads from f using big endian byte order rLittle := BinaryRider.ConnectReader(f); rLittle.SetByteOrder(BinaryRider.littleEndian); => rLittle reads from f using little endian byte order
(r: Reader)
SetPos (newPos: LONGINT)
The following methods read a value of the given type from the current
position of the Reader. If the value is invalid for its type,
Reader.res.code
is set to invalidFormat
.
Otherwise, if there aren't enough bytes to satisfy the request,
Reader.res.code
is set to readAfterEnd
.
(r: Reader)
ReadBool (VAR bool: BOOLEAN)
BOOLEAN
value. Zero
values are read as FALSE
and non-zero values are read as TRUE
.
Example:
VAR bool: BOOLEAN; r.ReadBool(bool); => if byte read = 0, then bool = FALSE; otherwise, bool = TRUE
(r: Reader)
ReadBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
r.base
according to the
native machine byte order. That is, ReadBytes
is not affected by
calls to SetByteOrder
. Thus this method is equivalent to any basic
rider Reader.ReadBytes
method (see section Abstract Class Reader)
Example:
VAR byteArr: ARRAY 256 OF CHAR; r.ReadBytes(byteArr, 0, 16); => reads the next 16 bytes from r.base into byteArr[0..15] r.ReadBytes(byteArr, 16, 100); => reads the next 100 bytes from r.base into byteArr[16..115]
(r: Reader)
ReadChar (VAR ch: CHAR)
SIZE(SYSTEM.BYTE) =
SIZE(CHAR)
.
Example:
VAR ch: CHAR; r.ReadChar(ch); => reads one byte and assigns it to ch
(r: Reader)
ReadLChar (VAR ch: LONGCHAR)
SIZE(LONGCHAR)
bytes are read and interpreted based on the current
byte order setting for reader r (see SetByteOrder
).
(r: Reader)
ReadInt (VAR int: INTEGER)
INTEGER
value. SIZE(INTEGER)
bytes are read and
interpreted based on the current byte order setting for reader r (see
SetByteOrder
).
(r: Reader)
ReadLInt (VAR lint: LONGINT)
LONGINT
value. SIZE(LONGINT)
bytes are read and
interpreted based on the current byte order setting for reader r.
(r: Reader)
ReadLReal (VAR lreal: LONGREAL)
LONGREAL
value. SIZE(LONGREAL)
bytes are read and
interpreted based on the current byte order setting for reader r.
(r: Reader)
ReadNum (VAR num: LONGINT)
byteOrder
setting. Therefore,
ReadNum
is not affected by calls to SetByteOrder
.
(r: Reader)
ReadReal (VAR real: REAL)
REAL
value. SIZE(REAL)
bytes are read and
interpreted based on the current byte order setting for reader r.
(r: Reader)
ReadSet (VAR s: SET)
SET
value. SIZE(SET)
bytes are read and
interpreted based on the current byte order setting for reader r.
(r: Reader)
ReadSInt (VAR sint: SHORTINT)
SHORTINT
value.
Please note: OOC assumes that SIZE(SYSTEM.BYTE) =
SIZE(SHORTINT)
so that the current byte order setting for reader r
(see SetByteOrder
) does not matter for calls to ReadSInt
.
(r: Reader)
ReadString (VAR s: ARRAY OF CHAR)
0X
is encountered, there are no more characters available in the
channel, or the string s is full. s is always terminated with
0X
.
Example:
VAR str: ARRAY 256 OF CHAR; r.ReadString(str); => reads up to 256 characters, stops when encounters 0X
(r: Reader)
ReadLString (VAR s: ARRAY OF LONGCHAR)
0X
is encountered, there are no more characters available in the
channel, or the string s is full. s is always terminated with
0X
. For each character, SIZE(LONGCHAR)
bytes are read and
interpreted based on the current byte order setting for reader r (see
SetByteOrder
).
Please note: Many of the methods for
BinaryRider.Writer
perform typicalWriter
operations. Rather than duplicate descriptions of those methods here, a reference to the abstract writer type is provided instead.
Msg.Msg
WriteBytes
, WriteInt
, SetPos
, etc.).
Error codes are highly dependent on the channel being written to (and
therefore on the basic riders provided for that channel), so you must look
at the result codes for the basic writer that is associated with that
particular channel (e.g., Files.Writer
error codes). See the various
channel types for details of these error codes (i.e., section Module Files,
section Module StdChannels, or section Module ProgramArgs).
If res#done
, use either res.GetLText()
or res.GetText()
to get a plain text error description corresponding to the error code.
Channel.Channel
SHORTINT
The following methods are all fully described in the section on abstract writers (see section Abstract Class Writer), so only brief descriptions are given here.
(w: Writer)
ClearError
(w: Writer)
Pos () : LONGINT
w
in
channel w.base
.
(w: Writer)
SetPos (newPos: LONGINT)
The following writer methods are used to write values to the underlying channel. In some situations, it is possible for only part of the value to be written.
(w: Writer)
WriteBytes (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT)
w.base
according to the
native machine byte order (i.e., WriteBytes
is not affected by calls
to SetByteOrder
). Thus this method is equivalent to any basic rider
Writer.WriteBytes
method (see section Abstract Class Writer)
Example:
VAR byteArr: ARRAY 256 OF CHAR; w.WriteBytes(byteArr, 0, 16); => writes the values of byteArr[0..15] to the current writing position of w w.WriteBytes(byteArr, 16, 100); => writes the values of byteArr[16..115] to the current writing position of w
(w: Writer)
WriteBool (bool: BOOLEAN)
BOOLEAN
value as a single byte. FALSE
is written as
0
and TRUE
is written as 1.
Example:
w.WriteBool(TRUE); => writes one byte = 01H w.WriteBool(FALSE); => writes one byte = 00H
(w: Writer)
WriteChar (ch: CHAR)
SIZE(SYSTEM.BYTE) =
SIZE(CHAR)
.
Example:
VAR ch: CHAR: w.WriteChar("A"); => writes one byte = "A" ch := 41X; w.WriteChar(ch); => writes one byte = 41X (i.e., "A" in ASCII)
(w: Writer)
WriteLChar (ch: LONGCHAR)
SIZE(LONGCHAR)
bytes
based on the current byte order setting for writer w (see
SetByteOrder
).
(w: Writer)
WriteString (s: ARRAY OF CHAR)
0X
as an embedded terminator). The terminating
0X
is also written.
Example:
VAR str: ARRAY 256 OF CHAR; w.WriteString("abcdefg"); => writes a total of 8 characters including 0X str := "hijkl"; w.WriteString(str); => writes a total of 6 characters including 0X
(w: Writer)
WriteLString (s: ARRAY OF LONGCHAR)
0X
character. Each character is written as SIZE(LONGCHAR)
bytes based
on the current byte order setting for writer w (see
SetByteOrder
).
(w: Writer)
WriteSInt (sint: SHORTINT)
SHORTINT
value.
Please note: OOC assumes that SIZE(SYSTEM.BYTE) =
SIZE(SHORTINT)
so that the current byte order setting for writer w
(see SetByteOrder
) does not matter for calls to WriteSInt
.
(w: Writer)
WriteInt (int: INTEGER)
INTEGER
value. SIZE(INTEGER)
bytes are written
based on the current byte order setting for writer w (see
SetByteOrder
).
(w: Writer)
WriteLInt (lint: LONGINT)
LONGINT
value. SIZE(LONGINT)
bytes are written based
on the current byte order setting for writer w.
(w: Writer)
WriteNum (lint: LONGINT)
byteOrder
setting. Therefore,
WriteNum
is not affected by calls to SetByteOrder
.
(w: Writer)
WriteReal (real: REAL)
REAL
value. SIZE(REAL)
bytes are written based on
the current byte order setting for writer w.
(VAR w: Writer)
WriteLReal (VAR lreal: LONGREAL)
LONGREAL
value. SIZE(LONGREAL)
bytes are written
based on the current byte order setting for writer w.
(VAR w: Writer)
WriteSet (VAR s: SET)
SET
value. SIZE(SET)
bytes are written based on the
current byte order setting for writer w.
(VAR w: Writer)
SetByteOrder (VAR order: SHORTINT)
byteOrder
in writer w to order. This affects the
interpretation of byte values for applicable write operations.
Pre-condition: order is one of nativeEndian
,
littleEndian
, or bigEndian
.
Example:
VAR wBig, wLittle, w: BinaryRider.Writer; f: Files.File; f := Files.Old("test.dat", {Files.write}, res); w := BinaryRider.ConnectWriter(f); => w writes to f using native byte order wBig := BinaryRider.ConnectWriter(f); wBig.SetByteOrder(BinaryRider.bigEndian); => wBig writes to f using big endian byte order wLittle := BinaryRider.ConnectWriter(f); wLittle.SetByteOrder(BinaryRider.littleEndian); => wLittle writes to f using little endian byte order
Functions are provided by module BinaryRider to connect readers and writers
to open channels. If the channel being passed as an argument to either of
these functions has a value of NIL
, behavior is undefined.
Also, for either of these functions, the returned rider is positioned at the beginning of the channel for positionable channels and at the current position for non-positionable channels.
(VAR ch: Channel.Channel): Reader
ch.res
is set to done
on success and the new reader is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
(VAR ch: Channel.Channel): Writer
ch.res
is set to done
on success and the new writer is
returned. Otherwise, it returns NIL
and ch.res.code
is
set to indicate the error cause.
Example:
VAR f: Files.File; r: BinaryRider.Reader; res: Files.Result; f := Files.Old("test.dat", {Files.read, Files.write}, res); IF (res # Files.done) THEN (* error processing *) END; r := BinaryRider.ConnectReader(f); IF (r = NIL) THEN (* error processing *) END;
For other constant values that may be applicable when using module `BinaryRider', see the specific channel implementation that you are reading to or writing from.
The following constant applies to the res
field, and may be compared
to it. (i.e., rider.res = done
or rider.res # done
.)
The following are possible values for res.code
:
The following are possible endian (byte order) settings:
Modules In
, Out
, and Err
provide simple interfaces to
the standard channels (see section Module StdChannels) These modules can be used to
read from predefined input (typically the keyboard) and write to predefined
output (typically the computer screen) locations.
Historically, the various Oberon systems/ compilers have furnished modules
called In
and Out
, which were intended primarily as aids for
learning the Oberon(-2) programming language. These modules were often
over-simplified to such a degree that they were of limited use beyond the
initial learning stage. The intention was that, after learning the
language, a programmer would learn other, more sophisticated methods for
I/O.
Although the modules In
, Out
, and Err
in the OOC
library are simple enough to be used by novices, they are not nearly as
limited as the corresponding modules from the original Oberon system.
Hence, they are still useful to programmers well beyond the beginning
stages.
These modules give simplified facilities similar to module TextRider applied to the standard channels; they allow reading and writing of data as text. If these prove to be insufficient for your needs, then modules TextRider or BinaryRider may be used instead (see section Standard Mappers)
Module In
provides a set of basic read operations for text. It is
initially set to read from the standard input channel
StdChannels.stdin
(see section Module StdChannels), but this may be changed with
the SetReader
procedure.
Each of the procedures in this module is designed to interpret a specific
type of text token. That is, Char
will read in a single CHAR
value, Int
will read in an INTEGER
value, and so forth. For
exact syntax of each of these tokens see section Syntax of Text Tokens.
The following program fragment gives an example of how you could read input a single line at a time (input stops after reading a blank line):
VAR str: ARRAY 256 OF CHAR; In.Line(str); WHILE In.Done() & (str # "") DO (* process each line *) In.Line(str); END;
In
. The type of
reader
is TextRider.Reader
, and it is initialized to refer to
a text reader connected to the channel StdChannels.stdin
.
The SetReader
procedure may be used to change this to refer to
another TextRider.Reader
.
(): BOOLEAN
FALSE
after an unsuccessful read operation.
This may be caused by attempting to read improperly formatted text (e.g.,
attempting to read non-numeric text using Int
), or if the underlying
reader has encountered an error. Further reading is not possible until the
error is cleared using the ClearError
procedure.
(r: TextRider.Reader)
In
. Refer to section Module TextRider for details on how to open other
readers. If r=NIL, the reader is set to read from
StdChannels.stdin
.
All of the following read operations require that Done()
=>
TRUE
; that is, they will not read anything else after an unsuccessful
read operation has occured. Further reading cannot take place until the
error is cleared using ClearError
.
Most of these read operations skip leading whitespace (i.e., spaces, tabs,
end-of-line characters, etc.) before reading a token; the only procedures
that do not skip whitespace are Char
and Line
.
A read error will occur, not only for improperly formatted text, but for
numbers (i.e., reading using Int
, Real
, and so forth) and set
elements that have values out of range of the target type. For example,
attempting to read `999999999999999999' using Int
will give
Done()
=> FALSE
.
An error will also occur for procedures that read into an ARRAY
OF
CHAR
, when the array is not large enough to hold the entire
input.
(VAR bool: BOOLEAN)
(VAR ch: CHAR)
(VAR lint: LONGINT)
LONGINT
.
Upon encountering an error, the value of lint is undefined.
Please note: Because LONGINT
values are signed, hex numbers
in the range `80000000H..FFFFFFFFH' are interpreted as negative
LONGINT
values.
(VAR s: ARRAY OF CHAR)
Upon encountering an error, the value of s is undefined. Example:
(* Input is as follows: myIdentifier 3isBad *) VAR str: ARRAY 256 OF CHAR; In.Identifier(str) => Done() = TRUE, str = "myIdentifier" In.Identifier(str) => Done() = FALSE, str = undefined
(VAR int: INTEGER)
+
" sign, or a "-
" sign. The value read
must be in the valid range for an INTEGER
.
Upon encountering an error, the value of int is undefined.
Example:
(* Input is as follows: 12345 999999999999999 forty-two *) VAR intVar: INTEGER; In.Int(intVar); => Done() = TRUE, intVar = 12345 In.Int(intVar); => Done() = FALSE, intVar = undefined In.ClearError; In.Int(intVar); (* attempting to read `forty-two' *) => Done() = FALSE, intVar = undefined (* reading position is still at the `f' in `forty-two' *)
(VAR lint: LONGINT)
Int
, except that it
deals with LONGINT
values.
(VAR int: SHORTINT)
Int
, except that it
deals with SHORTINT
values.
(VAR s: ARRAY OF CHAR)
0X
. An
error will occur if s is not large enough to hold the entire input.
Upon encountering an error, the value of s is undefined.
Please note: This procedure returns an empty string if already at at the end-of-line.
(VAR s: ARRAY OF CHAR)
'
) or double ("
) quote
marks. The opening quote must be the same as the closing quote and must not
occur within the string. Reading will continue until the terminating quote
mark is encountered, an invalid character is read (end-of-line is always
considered invalid), or there are no more characters available to be read.
s is always terminated with 0X
.
Unquoted strings or strings with no terminating quote mark result in an error. An error will also occur if s is not large enough to hold the entire input.
Upon encountering an error, the value of s is undefined.
Example:
(* Input is as follows: "A well-formed string" "No end quote *) VAR str: ARRAY 256 OF CHAR; In.String(str); => Done() = TRUE, str = "A well-formed string" In.String(str); => Done() = FALSE, str = undefined (* reading position is now at the end of this line *)
(VAR real: REAL)
+
" sign, or a "-
" sign.
The value read must be in the valid range for a REAL
.
Upon encountering an error, the value of real is undefined.
Example:
(* Input is as follows: 3.1415 +54321E+30 2.34E+56 *) VAR realVar: REAL; In.Real(realVar); => Done() = TRUE, realVar = 3.141500 In.Real(realVar); => Done() = TRUE, realVar = 5.432100E+34 In.Real(realVar); => Done() = FALSE, realVar = undefined (* value is out of range for REAL *)
(VAR lreal: LONGREAL)
Real
, except that it
deals with LONGREAL
values.
(VAR s: SET)
Upon encountering an error, the value of s is undefined.
Example:
(* Input is as follows: {0, 1, 2, 3, 4, 5} {6, 7, 1024} *) VAR setVar: SET; In.Set(setVar); => Done() = TRUE, setVar = {0..5} In.Set(setVar); => Done() = FALSE, setVar = undefined (* reading position is now at the `}' after the `1024' *)
Module Out
provides a set of basic write operations for text. It is
initially set to write to the standard output channel
StdChannels.stdout
(see section Module StdChannels), but this may be changed
with the SetWriter
procedure.
Out
. The type of
writer
is TextRider.Writer
, and it is initialized to refer to
a text reader connected to the channel StdChannels.stdout
.
The SetWriter
procedure may be used to change this to refer to
another TextRider.Writer
.
(): BOOLEAN
FALSE
after an unsuccessful write operation.
This may happen when underlying writer has encountered an error. Further
writing is not possible until the error is cleared using the
ClearError
procedure.
(w: TextRider.Writer)
Out
. Refer to section Module TextRider for details on how to open
other writers. If w=NIL, the writer is set to write to
StdChannels.stdout
.
Out.writer
. Any pending write
operations are passed to the underlying system. If a writing error occurs
while flushing buffers, Out.Done()
will subsequently return
FALSE
. Otherwise, Out.Done()
will return TRUE
.
(bool: BOOLEAN)
(ch: CHAR)
Example:
Out.Char("A"); => writes one character = "A"
(lint: LONGINT; n: LONGINT)
Example:
Out.Hex(127, 4); => writes "007F" Out.Hex(-128, 0); => writes "FFFFFF80"
(int: INTEGER; n: LONGINT)
Example:
Out.Int(54321, 0); => writes "54321" Out.Int(54321, 10); => writes " 54321"
(lint: LONGINT; n: LONGINT)
Int
, except that it
deals with LONGINT
values.
(sint: SHORTINT; n: LONGINT)
Int
, except that it
deals with SHORTINT
values.
(real: REAL; n, k: LONGINT)
If the value of k is greater than 0, that number of significant digits is included. Otherwise, an implementation-defined number of significant digits is included. The decimal point is not included if there are no significant digits in the fractional part.
The number is scaled with one digit in the whole number part. A sign is included only for negative values.
Example:
Out.Real(3923009, 0, 0); => writes "3.923009E+6" Out.Real(3923009, 10, 1); => writes " 4E+6" Out.Real(-39.23009, 12, 2); => writes " -3.9E+1" Out.Real(0.0003923009, 6, 1); => writes " 4E-4"
(lreal: LONGREAL; n, k: LONGINT)
Real
, except that it
deals with LONGREAL
values.
(real: REAL; n, k: LONGINT)
Real
, except that the
number is scaled with one to three digits in the whole number part and has
an exponent that is a multiple of three.
Example:
Out.RealEng(39.23009, 10, 5); => writes " 39.230" Out.RealEng(-3923009, 7, 3); => writes " -3.92E+6" Out.RealEng(0.0003923009, 1, 1); => writes "400E-6" Out.RealEng(0.0003923009, 4, 2); => writes " 390E-6"
(lreal: LONGREAL; n, k: LONGINT)
RealEng
, except that it
deals with LONGREAL
values.
(real: REAL; n, k: LONGINT)
The value is rounded to the given value of k relative to the decimal point. The decimal point is suppressed if k is less than 0.
The number will have at least one digit in the whole number part. A sign is included only for negative values.
Example:
Out.RealFix(3923009, 0, -5); => writes "3920000" (* rounded to the ten-thousands place *) Out.RealFix(3923.5, 0, -1); => writes "3924" (* rounded to the "ones" place *) Out.RealFix(-39.23009, 10, 1); => writes " -39.2" Out.RealFix(0.0003923009, 11, 4); => writes " 0.0004"
(lreal: LONGREAL; n, k: LONGINT)
RealFix
, except that it
deals with LONGREAL
values.
(s: SET)
Example:
Out.Set({1,6,10}); => writes "{1, 6, 10}" Out.Set({0, 1, 2, 3, 4, 5}); => writes "{0..5}" Out.Set({0, 2, 4, 6} + {1, 3, 5, 7}); => writes "{0..7}"
(s: ARRAY OF CHAR)
0X
character. The behaviour of this procedure is undefined if s is an
unterminated character array.
Please note: In.String
and Out.String
are not
symmetric. That is, Out.String
does not enclose the written string
in quote marks; only the actual character values contained in s are
written.
Module Err
provides a set of basic write operations for text, which
exactly mirror those in module Out
. The difference is that
Err
is initially set to write to the standard error channel
StdChannels.stderr
(see section Module StdChannels). Also note that the call
Err.SetWriter(NIL)
will reset the writer for Err
to
StdChannels.stderr
.
Because the interfaces of Out
and Err
are identical,
decriptions of facilities are not duplicated here.
Go to the first, previous, next, last section, table of contents.