As has already been observed, in ISO standard Modula-2, the modules SWholeIO, SRealIO, SLongIO, and STextIO operate on the standard channels. These are defined in the Module StdChans:
DEFINITION MODULE StdChans; IMPORT IOChan; TYPE ChanId = IOChan.ChanId; (* Values of this type are used to identify channels *) (* The following functions return the standard channel values. These channels cannot be closed. *) PROCEDURE StdInChan (): ChanId; (* Returns the identity of the implementation-defined standard source for program input. *) PROCEDURE StdOutChan (): ChanId; (* Returns the identity of the implementation-defined standard source for program output. *) PROCEDURE StdErrChan (): ChanId; (* Returns the identity of the implementation-defined standard destination for program error messages. *) PROCEDURE NullChan (): ChanId; (* Returns the identity of a channel open to the null device. *) (* The following functions return the default channel values *) PROCEDURE InChan (): ChanId; (* Returns the identity of the current default input channel. *) PROCEDURE OutChan (): ChanId; (* Returns the identity of the current default output channel. *) PROCEDURE ErrChan (): ChanId; (* Returns the identity of the current default error message channel. *) (* The following procedures allow for redirection of default channels *) PROCEDURE SetInChan (cid: ChanId); (* Sets the current default input channel to that identified by cid. *) PROCEDURE SetOutChan (cid: ChanId); (* Sets the current default output channel to that identified by cid. *) PROCEDURE SetErrChan (cid: ChanId); (* Sets the current default error channel to that identified by cid. *) END StdChans.
Observe that there is a third channel besides that for input and output. The error channel may be the same as the standard output, or it may be a file that logs errors. This channel is available to the programmer as well:
IF Error THEN TextIO.WriteString (StdChans.ErrChan(), theMessage) END;
It is also easy to see how the non-standard module RedirStdIO that was employed earlier in the text can be written on top of this standard one. It is only necessary to open new channels through StreamFile and then employ the procedures of StdChans to redirect the current default channel. The definition, and an implementation for the Macintosh operating system follow. Of course, the specific details that relate to the manner in which the file name is obtained before being passed to be opened will differ on other operating systems.
DEFINITION MODULE RedirStdIO; (* ========================================= Definition and Implementation © 1993-1997 by R. Sutcliffe Trinity Western University 7600 Glover Rd., Langley, BC Canada V3A 6H4 e-mail: rsutc@twu.ca Last modification date 1997 07 02 =========================================== *) IMPORT ChanConsts; TYPE OpenResults = ChanConsts.OpenResults; PROCEDURE OpenResult () : OpenResults; (* returns the result of the last attempt to open a file for redirection *) PROCEDURE OpenOutput; (* engages the user in a dialog to obtain a file for redirection of standard Output and attempts to open the file so obtained *) PROCEDURE OpenOutputFile (VAR fileName: ARRAY OF CHAR); (* opens the file specified by fileName for redirection of output. If the name supplied is the empty string or the file could not be opened, control passes to OpenOutput and the filename eventually used is returned in the parameter. *) PROCEDURE CloseOutput; (* returns the standard output channel to the default value *) PROCEDURE OpenInput; (* engages the user in a dialog to obtain a file for redirection of standard Input and attempts to open the file so obtained *) PROCEDURE OpenInputFile (VAR fileName: ARRAY OF CHAR); (* Opens the file specified by fileName for redirection of input. If the name supplied is the empty string or is not found, control passes to OpenInput and the filename eventually used is returned in the parameter. *) PROCEDURE CloseInput; (* returns the standard input channel to the default value *) END RedirStdIO. IMPLEMENTATION MODULE RedirStdIO; (* ========================================= Definition and Implementation © 1993-1997 by R. Sutcliffe Trinity Western University 7600 Glover Rd., Langley, BC Canada V3A 6H4 e-mail: rsutc@twu.ca Last modification date 1999 07 22 =========================================== *) (* First cut was October 1993 1994 05 21 modified to p1 version change some type imports use put get File rather than File0 change string handling accordingly change to proper name "Strings" 1996 08 08 removed extraneous local var from OpenOutput 1997 07 08 added OpenOutputFile and OpenInputFile *) (* Mac Specific *) FROM StandardFile IMPORT SFReply, SFTypeList, SFPutFile, SFGetFile; FROM MacTypes IMPORT Str255, Str63, Point; FROM Strings IMPORT Assign; FROM StdChans IMPORT SetOutChan, StdOutChan, SetInChan, StdInChan; IMPORT ChanConsts; FROM ChanConsts IMPORT read, write, old; FROM StreamFile IMPORT ChanId, Open, Close; FROM SYSTEM IMPORT TOSTR255, FROMSTR255; FROM MacString IMPORT MacToModString; TYPE ModStr255 = ARRAY [0..255] OF CHAR; VAR out, in : ChanId ; count : CARDINAL; lastOpenResult : OpenResults; inRedir, outRedir : BOOLEAN; (*--------------------------------------------------------------------------------*) PROCEDURE InternalOpenOutput (VAR fileName : ARRAY OF CHAR); (* engages the user in a dialog to obtain a file for redirection of standard Output and attempts to open the file so obtained *) VAR result : OpenResults; defFileName, thePrompt : Str255; p : Point; sfreply : SFReply; mTempStr : ModStr255; gottaAsk : BOOLEAN; BEGIN gottaAsk:=TRUE; IF fileName[0] <> "" (* file name non-empty? *) THEN (* go try it *) Open (out, fileName, write+old, result); gottaAsk:= NOT (result = ChanConsts.opened) END; (* if *) IF gottaAsk (* true if filename was empty or not found *) THEN thePrompt := TOSTR255 ("Output File?"); (* get dialog box prompt ready *) defFileName := TOSTR255 ("output"); (* and default file name *) SFPutFile (p, thePrompt, defFileName, NIL,sfreply); (* and go try with dialog box *) IF sfreply.good (* got it OK *) THEN (* convert filename returned to Modula string *) MacToModString (sfreply.fName, mTempStr); Assign (mTempStr,fileName); Open (out, mTempStr, write+old, result); END; END; lastOpenResult := result; IF result = ChanConsts.opened THEN SetOutChan (out); outRedir := TRUE; ELSE fileName[0]:= ""; END; (* if didn't work, nothing is done *) END InternalOpenOutput; (*--------------------------------------------------------------------------------*) PROCEDURE OpenResult () : OpenResults; (* returns the result of the last attempt to open a file for redirection *) BEGIN RETURN lastOpenResult; END OpenResult; (*--------------------------------------------------------------------------------*) PROCEDURE OpenOutput; (* engages the user in a dialog to obtain a file for redirection of standard Output and attempts to open the file so obtained *) VAR DummyFile : ARRAY [0..1] OF CHAR; BEGIN DummyFile[0]:= ""; InternalOpenOutput (DummyFile); END OpenOutput; (*--------------------------------------------------------------------------------*) PROCEDURE OpenOutputFile (VAR fileName : ARRAY OF CHAR); (* opens the file specified by FileName for redirection of output. If the name supplied is the empty string or the file could not be opened, control passes to OpenOutput and the filename eventually used is returned in the parameter. *) BEGIN InternalOpenOutput (fileName); END OpenOutputFile; (*--------------------------------------------------------------------------------*) PROCEDURE CloseOutput; (* returns the standard output channel to the default value *) BEGIN IF outRedir THEN Close (out); SetOutChan (StdOutChan () ); outRedir := FALSE; END; END CloseOutput; (*--------------------------------------------------------------------------------*) PROCEDURE InternalOpenInput (VAR fileName : ARRAY OF CHAR); (* This procedure is where all the work gets done. Engages the user in a dialog to obtain a file for redirection of standard Output and attempts to open the file so obtained *) VAR result : OpenResults; p : Point; sfreply : SFReply; mTempStr : ModStr255; gottaAsk : BOOLEAN; SFt: SFTypeList; BEGIN gottaAsk:=TRUE; IF fileName[0] <> "" (* file name non-empty? *) THEN (* go try it *) Open (in, fileName, old+read, result); gottaAsk:= NOT (result = ChanConsts.opened) END; (* if *) IF gottaAsk (* true if filename was empty or not found *) THEN SFGetFile (p, "", NIL, -1, SFt, NIL, sfreply); (* go try with dialog box *) IF sfreply.good (* got it OK *) THEN (* convert filename returned to Modula string *) MacToModString (sfreply.fName, mTempStr); Assign (mTempStr,fileName); Open (in, mTempStr, old+read, result); END; END; lastOpenResult := result; (* from one or the other *) IF result = ChanConsts.opened THEN SetInChan(in); inRedir := TRUE; ELSE fileName[0]:= ""; END; (* if didn't work, nothing is done *) END InternalOpenInput; (*--------------------------------------------------------------------------------*) PROCEDURE OpenInput; (* engages the user in a dialog to obtain a file for redirection of standard Input and attempts to open the file so obtained *) VAR DummyFile : ARRAY [0..1] OF CHAR; BEGIN DummyFile[0]:= ""; InternalOpenInput (DummyFile); END OpenInput; (*--------------------------------------------------------------------------------*) PROCEDURE OpenInputFile (VAR fileName : ARRAY OF CHAR); (* This is the procedure that does all the work. Opens the file specified by fileName for redirection of input. If the name supplied is the empty string or is not found, control passes to OpenInput and the filename eventually used is returned in the parameter. *) BEGIN InternalOpenInput (fileName); END OpenInputFile; (*--------------------------------------------------------------------------------*) PROCEDURE CloseInput; (* returns the standard input channel to the default value *) BEGIN IF inRedir THEN Close (in); SetInChan (StdInChan () ); inRedir := FALSE; END; END CloseInput; BEGIN (* main program *) lastOpenResult := ChanConsts.otherProblem; inRedir := FALSE; outRedir := FALSE; END RedirStdIO.
In this system, the dialog boxes that are standard to the Macintosh operating system are presented to the user so that folders can be navigated in the usual way to obtain the file name. In a text based operating system, these sections would have to be replaced with a dialog to the interactive terminal where the user types in a file name.