dubois@uwmacc.UUCP (Paul DuBois) (03/17/86)
__StreamLib: A Rascal Library for Stream Input Introduction ----------------------------------------------------------------------- __StreamLib comprises a set of routines which allow programs to read TEXT and/or WORD (MacWrite) files as a stream of characters, without having to know or care about which type of file is being read. A stream can be opened and then read by operations that return either a character at a time or a line at a time. There are also sets of operations that work exclusively on each type of file, should the user wish to restrict program operation to TEXT files only or to WORD files only. Explicit use of a single stream type reduces the amount of code linked in (although the amount is small). Use of the routines that work on both kinds of files incurs a small penalty in code size but increases the generality of the program: any program that operates on simple text files can be made to operate on MacWrite files as well. To use the library, one first initializes it, then opens a stream and reads its contents. Streams are closed automatically when the end of the stream is reached. The stream can be read a character or a line at a time. Two small programs to read a file and display it follow. Proc CharReadStream (); (* read stream a character at a time *) Var c: Integer; { InitStream (); if OpenStream () <> noErr then { loop (,,,) { c := StreamGetC (); if c = -1 then break; (* end of stream *) WriteChar (c); if c = ' then WriteChar ('); }; }; }; Proc LineReadStream (); (* read stream a line at a time *) Var buf: Byte[512]; (* should be big enough! *) { InitStream (); if OpenStream () <> noErr then { loop (,,,) { if StreamGetS (buf) = nil then break; (* end of stream *) WriteString (buf); WriteLn (); }; }; }; If one wishes to know something about the stream, the procedure GetStreamInfo is available. This returns a copy of the SFReply used to open the stream (i.e., it contains the file name, file type, and volume reference number. Most of the routines in __StreamLib are described below. Routines with names beginning with an underscore are primarily intended for internal use, but they might be useful in certain contexts. Stream Initialization, Opening and Closing ----------------------------------------------------------------------- Procedure InitStream (); This procedure must be called to set up the library before any other stream operations are done. Function OpenStream (): OSErr; Open a stream. Closes any currently open stream, then displays a GetFile dialog listing both TEXT and WORD files. Function OpenTextStream (): OSErr; Like OpenStream, but for TEXT files only. Function OpenWordStream (): OSErr; Like OpenStream, but for WORD files only. OpenStream, OpenTextStream and OpenWordStream return: noErr stream opened successfully fnOpnErr stream not opened successfully mFulErr (occurs for WORD files only) stream could be opened, but there was not enough memory to read in initialization information (the stream is closed before returning) Procedure CloseStream (); Close the currently open stream. The character and line input routines (described below) close the stream automatically upon reaching end of stream, but CloseStream may be called safely any time after InitStream is called (even before the first stream is opened!). Character Input Routines ----------------------------------------------------------------------- Function StreamGetC (): Integer; Determine the type of the stream and get the next character appropriately. Function TextStreamGetC (): Integer; Get the next character from the currently open TEXT stream. Results meaningless if the stream is a WORD stream. Function WordStreamGetC (): Integer; Get the next character from the currently open WORD stream. Results meaningless if the stream is a TEXT stream. StreamGetC, TextStreamGetC and WordStreamGetC return: -1 end of stream otherwise next character of stream Note that the result must be assigned to an integer variable, since -1 is not a legal byte value. When the end of the stream is reached, these routines close the stream. Further calls return -1 repeatedly until another stream is opened. Line Input Routines ----------------------------------------------------------------------- Function StreamGetS (str: StringPtr): StringPtr; Determine the type of the stream and get the next line appropriately. Place the line in the given string. Function TextStreamGetS (str: StringPtr): StringPtr; Get the next line (all characters up to the next carriage return or end of stream) from the currently open TEXT stream. Place the line in the given string. The carriage return is not placed in the string. Results meaningless if the stream is a WORD stream. Function WordStreamGetS (str: StringPtr): StringPtr; Get the next line from the currently open WORD stream. A "line" is defined as a string of characters up to the next carriage return or end of stream, or up to the first space past the current linewrap length. Lines must be broken at some point, since WORD files contain carriage returns only at the ends of paragraphs, and it cannot be assumed that paragraphs will be less than any reasonable length. Therefore, once a certain number of characters have been read without a carriage return being found, the next space causes the call to terminate. (If you really need to read in a whole paragraph, use WordStreamGetC until it returns a carriage return.) The line is placed in the given string. The carriage return (or space if the line is broken) is not placed in the string. Results meaningless if the stream is a TEXT stream. StreamGetS, TextStreamGetS and WordStreamGetS return: nil end of stream otherwise pointer to the argument When the end of the stream is reached, these routines close the stream. Further calls return nil repeatedly until another stream is opened. Miscellaneous Routines ----------------------------------------------------------------------- Procedure GetStreamInfo (streamInfo: SFReply); Returns, in the argument, a copy of the SFReply record used to open the stream (from which the file name, file type and file volume reference number can be determined). This information is meaningless unless a stream is actually open. Procedure SetLineLen (len: Integer); Sets the line wrap length for WordStreamGetS. Function _FSOpen (fName: PtrB; vRefNum: Integer; refNum: ^Integer; mode: Integer): OSErr; This function is similar to FSOpen (in Inside Macintosh) except that it allows an open mode to be specified. Procedure _ffRead (f: Integer; b: PtrB; amount: LongInt); Reads amount bytes from the file f into the buffer pointed to by b. Procedure _fMoveTo (f: Integer; pos: LongInt); Moves to position pos in file f. Limitations ----------------------------------------------------------------------- Only one file at a time can be streamed. Acknowledgments ----------------------------------------------------------------------- The code which extracts the text from WORD files is modelled after the programs ReadMacWrite and Index, by Scott Gillespie (Reed College). Scott is of course not responsible for any glaring ugliness in my code. The main differences between his code and mine are: In ReadMacWrite the text extractor is a high-level routine that repeatedly passes characters to subsidiary routines, while in __SteamLib the extractor is a subsidiary routine repeatedly called by higher-level operations in the host program. Also, I used a Handle rather than a Ptr for reading in each paragraph. I found that DA's using the library would not execute properly when they were run inside of other programs not created with Rascal - SetPtrSize always failed. I don't know why. -- | Paul DuBois {allegra,ihnp4,seismo}!uwvax!uwmacc!dubois --+-- | |