Subject: Converting to Cedar 5.0 -- RefText, IO, FileIO, CedarScanner, and Convert interfaces
To: CedarUsers^
Reply-To: MBrown
1. Introduction
Purpose
The purpose of this memo is to help a Cedar programmer convert programs from Cedar 4.4 to Cedar 5.0, assuming that these programs use one or more of the RefText, IO, FileIO, CedarScanner, and Convert interfaces.
A separate document, /indigo/precedar/documentation/IODoc.tioga, describes the Cedar 5.0 IO facilities in complete detail. This memo just describes how to translate Cedar 4.4 constructs into Cedar 5.0, and leaves out many details of how the 5.0 version works, so when questions arise you should consult IODoc.tioga (and let me know if you find it to be confusing or wrong).
The interfaces involving streams
In Cedar 4.4, the interfaces IO, FileIO, Convert, and CedarScanner contained stream I/O procedures and string-to-value and value-to-string conversions. In Cedar 5.0 most of the same functions, and some new ones, are contained in the IO, Convert, FS, IOClasses, EditedStream, and IOUtils interfaces:
IO: the generic stream procs and errors, the most rudimentary stream classes (ROPE and REF TEXT streams), printing to a stream, scanning and input conversion from a stream (including scanning according to Cedar token structure), and primitives for constructing new stream classes.
Convert: conversion from ROPE and REF TEXT to various Cedar values (INT, time, etc) and from various Cedar values to ROPE and REF TEXT.
FS: creation of file streams, and special operations on file streams.
IOClasses: a collection of stream classes: "pipes", "comment filter input", and so on. Each is relatively simple and does not seem to require its own interface.
EditedStream: the edited stream class. This class is relatively complicated and the interface contains many procedures that are specialized to edited streams. It also contains SetEcho, which has a generic implementation but is used principally with edited streams.
IOUtils: procedures that are only of interest to more advanced clients ("ambitious" stream class implementations).
2. RefText
In Cedar 5.0, the RefText interface has changed in the following way: all procs that append to a REF TEXT return a REF TEXT value, as in AppendChar: PROC [to: REF TEXT, from: CHAR] RETURNS [REF TEXT]. The result TEXT is the same REF as the parameter to, unless to.length = to.maxLength when AppendChar is called. In this case, a longer TEXT is allocated and the current contents of to are copied into it. It is considered an error to pass NIL as the value of to (PointerFault will be raised). The same convention is followed by all procs that append to a REF TEXT in the RefText interface.
The IO and Convert interfaces follow the same conventions.
3. IO, FileIO
The IO interface no longer assigns two names to a single type or procedure
Handle -> STREAM
CreateInputStreamFromRope -> RIS
CreateOutputStreamToRope -> ROS
PutList -> PutL
PutFList -> PutFL
PutFToRope -> PutFR
The following have been renamed (mostly moved out of IO)
CreateInputStreamFromText -> TIS
IsACR -> EditedStream.IsACR
CreateFilterCommentsStream -> IOClasses.CreateFilterCommentsStream
CreateProcsStream -> CreateStream
StoreData -> IOUtils.StoreData
LookupData -> IOUtils.LookupData
RemoveData -> IOUtils.RemoveData
AmbushProcsStream -> IOUtils.AmbushStream
UnAmbushProcsStream -> IOUtils.UnAmbushStream
LookupProc -> IOUtils.LookupProc
The following have been changed in a way that requires thought in conversion
FileIO.Open -> FS.StreamOpen
The AccessOptions and CreateOptions have been replaced by a new type AccessOptions = {read, create, append, write}. Most clients who write files want accessOptions ~ $create; see comments in FS interface.
Note that the generic stream operations on a file do not raise FS errors directly, but instead raise IO.Error[$Failure, self], and require the client to call FS.ErrorFromStream[self] to get more information if it is needed.
FileIO.StreamFromCapability, FileIO.StreamFromOpenFile -> FS.StreamFromOpenFile
In place of AccessOptions, this proc takes accessRights ($read or $write) and an initialPosition ($start or $end). Note that the default is to close the open file when the stream is closed; this can be overridden by specifying streamOptions ~ [$closeFSOpenFileOnClose: FALSE].
FileIO.CapabilityFromStream -> FS.OpenFileFromStream
Note that an FS.OpenFile is volatile state (unlike Pilot's File.Capability), so to store it in a permanent structure requires obtaining a File.FP from the FS.OpenFile.
CreateOutputStreamToText -> TOS
Be sure to use TextFromTOS to get the result TEXT, because the original TEXT may overflow.
CreateEditedStream -> EditedStream.Create
DeliverWhenProc -> EditedStream.DeliverWhenProc
GetBufferContents -> EditedStream.DeliverWhenProc
If you use deliverWhen = IsACR then no other changes are necessary. Otherwise, read the documentation contained in EditedStream.mesa. Control-R is no longer an editing character (it retypes the current line, intended for non-erasing displays.)
SetEcho -> EditedStream.SetEcho, EditedStream.GetEcho
The functions of reading and writing the echo stream are now separate.
CreateDribbleStream -> IOClasses.CreateDribbleOutputStream
IO.CreateDribbleStream created an input/output stream; the new version creates an output-only stream. See documentation in IOClasses.mesa.
AppendStreams -> IOClasses.CreateCatInputStream
IO.AppendStreams appended to an existing stream by "ambusing" it; the new version leaves stores the existing streams in the data of a new stream, and returns the new stream.
CharsAvail
IS NOT RELATED TO EndOf! Returns an estimate of the number of characters from the input sequence that can be delivered very quickly (without waiting for user input or for network transmission.) A stream class that never waits may return a large constant value (INT.LAST), while a stream class that does wait should either return an exact value or an underestimate (it is acceptable to return 1 representing "some bytes are available" and 0 representing "no bytes are available"; 0 should not be returned if the stream detects end of input sequence). If wait, then does not return until a nonzero value can be returned (perhaps because end of input sequence has been detected). CharsAvail allows a single process to consume a byte stream efficiently, without being suspended for reading past the available input.
UnsafeBlock, GetBlock, UnsafeGetBlock, PutBlock, UnsafePutBlock
We have converted from [startIndex, stopIndexPlusOne] style to [startIndex, count] style. This is not a substantial change, but all programs that use block operations should examine these calls carefully. Calls made without keyword notation will not be flagged by the compiler, so EXAMINE ALL CALLS on the block operations.
GetOutputStreamRope -> RopeFromROS (but default is to Close the stream during this operation, so in this case a later call to Close should be removed.)
GetCedarToken, GetToken, ... (all formatted input procedures)
Scanning routines that return a result are generally provided in two versions. The first version takes a REF TEXT buffer as a parameter, and may return its result in this buffer, but will allocate a larger one if the buffer fills up. Hence if each token is smaller than the buffer, only a single allocation is required to scan a sequence of tokens. The second version returns its result in a ROPE; hence at least one byte of storage is allocated for each byte of token scanned. In either case, a token cannot exceed NAT.LAST bytes in length.
Most scanning routines raise IO.EndOfStream to signal end of input. The exception is GetCedarToken, which returns a special "tokenKind".
PutF
'* is no longer an escape character in format strings, the only PutF-specific escape in %. Use "\n" for "*n" in a format string.
CreateRefStreamProcs -> CreateStreamProcs
Default implementations have changed in some cases. If you implement a stream class you should read IODoc.tioga Sections 2 and 7 carefully.
UncheckedImplements -> IOUtils.StoreProc
If you are implementing a proc P of type T, pass key: ${name of operation implemented by P}, procRef: NEW[T ← P]. If you and IO disagree about the type T, you will get an error the first time IO attempts to call P.
SetPFCodeProc -> IOUtils.CopyPFProcs, SetPFProcs, SetPFCodeProc
SetPFCodeProc operates on a set of pf code procs that can later be bound to a stream, rather than operating directly on a stream. This means, for instance, that a stream class can supply a special pf code proc for each of its instances by sharing the code procs among all the instances, instead of creating the set from scratch each time. See IODoc.tioga Section 5.
The following have been converted by Paul Rovner; see him for documentation
CreateViewerStreams -> ViewerIO.CreateViewerStreams
PutTV -> PrintTV.Print
PutType -> PrintTV.PrintType
PutSignal -> AMIO.PutSignal
AttachRefPrintProc -> AMIO.AttachRefPrintProc
AttachTVPrintProc -> AMIO.AttachTVPrintProc
The following have been eliminated from the IO interface, but might find a home elsewhere (I don't plan to work on them)
CreateBufferedOutputStream
CurrentPosition, NewLine, SpaceTo
The following have been eliminated
GetBufferContents
This function is provided by the buffer: REF TEXT parm to DeliverWhenProc.
UserAborted, UserAbort, SetUserAbort, ResetUserAbort
To stop a process, call Process.Abort (replaces IO.SetUserAbort), passing it a PROCESS value (not a STREAM). ERROR ABORTED (replaces IO.UserAborted) is then raised in the target process the next time it waits on a condition variable that is enabled for aborts, or the next time the target process explicitly checks for aborts using Process.CheckForAborts (may be called ProcessExtras.CheckForAborts if you look too soon, replaces IO.UserAbort). The act of raising ABORTED clears the "aborted" flag of the process (replaces IO.ResetUserAbort). ABORTED is a normal ERROR and can be caught by client code; most command procs will wish to ignore ABORTED and catch UNWIND to finalize themselves (close files, etc). A condition variable becomes enabled for aborts by calling Process.EnableAborts.
string: PROC [LONG STRING] RETURNS [Value]
STRING is being banished from Cedar.
tv, type: PROC [...] RETURNS [Value]
These created an interface dependency on AMTypes.
AddData: PROC [self: STREAM, key: ATOM, data: REF ANY]
Implements: PROC [self: STREAM, operation, via: PROC ANY RETURNS ANY]
Use IOUtils.StoreProc (see "UncheckedImplements -> IOUtils.StoreProc" above).
SetPFStarCodeProc PROC [self: STREAM, operation, via: PROC ANY RETURNS ANY]
If you implement your own PFStarCodeProcs, you can either convert the function to a PFCodeProc (passing a corresponding dummy value like IO.rope[NIL], NOT [null[]], in your call to PutF), or implement the function outside of PutF.
Signal: SIGNAL [ec: SignalCode, stream: STREAM]
IO.Error is raised in most cases. PutF has plug-in error handler, similar in spirit to PFCodeProcs, and the default is for PutF to print "#####" and press on in spite of an error.
BufferOverFlow: SIGNAL [text: REF TEXT] RETURNS [REF TEXT]
RefText.Append* and RefText.InlineAppend* now expand the REF TEXT when it becomes full. These primitives are used throughout the IO package.
StreamProperty: TYPE = REF StreamPropertyRecord
The StreamProcs property list is now a standard property list, not a LIST OF StreamProperty.
BackSlashChar: PROC [char: CHAR, stream: STREAM]
Use Convert.CharFromLiteral or Convert.RealFromLiteral as appropriate.
Zone: PRIVATE ZONE
4. CedarScanner
The functions provided by the CedarScanner interface are now provided in the IO and Convert interfaces.
IO.GetCedarToken has changed in a manner analogous to the way GetToken et. al. have changed (see above); the types Token, GetProc, and GetClosure are no longer used. The type TokenKind has been expanded, with $tokenINT replaced by $tokenDECIMAL, $tokenOCTAL, $tokenHEX. The conversion procs in the CedarScanner interface (RealFromToken, IntFromToken, ... ) are replaced by corresponding procs in the Convert interface.
5. Convert
The Cedar 4.4 Convert interface has two functions: input conversion (Convert.Parse, Convert.IntFromRope) and output conversion (Convert.ValueToRope, Convert.ValueToRefText, Convert.MapValue).
The Cedar 5.0 Convert interface contains individual procedures per value type, instead a small number of procedures with parameters and results encoded in a variant record. Hence "NARROW[Convert.Parse[[rope[rope]]].value, Convert.Value.real].real" becomes "Convert.RealFromRope[rope]". For input conversion, the procs take ROPE as the character source; the client can pass REF TEXT to the same procs using RefText.TrustTextAsRope. For output conversion, two forms are provided for each value type: a form that appends characters to an existing REF TEXT, and a form that produces a ROPE. Convert.ValueToRefText allocates a TEXT on each call, while Convert.AppendReal (for instance) allocates one only if the one you pass it is too small to hold the result.