123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Input-Stream.SL (TOPS-20 Version) - File Input Stream Objects
- %
- % Author: Alan Snyder
- % Hewlett-Packard/CRC
- % Date: 29 July 1982
- %
- % This package is 6.6 times faster than the standard unbuffered I/O.
- % (Using message passing, it is only 1.7 times faster.)
- %
- % Note: this code will only run COMPILED.
- %
- % See TESTING code at the end of this file for examples of use.
- % Be sure to include "(CompileTime (load objects))" at the beginning
- % of any file that uses this package.
- %
- % Summary of public functions:
- %
- % (setf s (open-input "file name")) % generates error on failure
- % (setf s (attempt-to-open-input "file name")) % returns NIL on failure
- % (setf ch (=> s getc)) % read character (map CRLF to LF)
- % (setf ch (=> s getc-image)) % read character (don't map CRLF to LF)
- % (setf ch (=> s peekc)) % peek at next character
- % (setf ch (=> s peekc-image)) % peek at next character (don't map CRLF to LF)
- % (setf str (=> s getl)) % Read a line; return string without terminating LF.
- % (=> s empty?) % Are there no more characters?
- % (=> s close) % Close the file.
- % (setf fn (=> s file-name)) % Return "true" name of file.
- % (setf date (=> s read-date)) % Return date that file was last read.
- % (setf date (=> s write-date)) % Return date that file was last written.
- % (=> s delete-file) % Delete the associated file.
- % (=> s undelete-file) % Undelete the associated file.
- % (=> s delete-and-expunge) % Delete and expunge the associated file.
- % (setf name (=> s author)) % Return the name of the file's author.
- % (setf name (=> s original-author)) % Return the original author's name.
- % (setf count (=> s file-length)) % Return the byte count of the file.
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %
- % Changes:
- %
- % 9/29/82 Alan Snyder
- % Changed GETC to return stray CRs.
- % Now uses (=> self ...) form (produces same object code).
- % Added operations PEEKC-IMAGE, GETL, TELL-POSITION, SEEK-POSITION
- % (written by Nancy Kendzierski).
- %
- % 11/22/82 Alan Snyder
- % Changed SEEK-POSITION to work with large byte pointers (> 256K).
- %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (CompileTime (load fast-int fast-strings))
- (BothTimes (load objects jsys))
- (load directory file-support)
- (de attempt-to-open-input (file-name)
- (let ((p (ErrorSet (list 'open-input file-name) NIL NIL)))
- (and (PairP p) (car p))
- ))
- (de open-input (file-name)
- (let ((s (make-instance 'input-stream)))
- (=> s open file-name)
- s))
- (DefConst FILE-BUFFER-SIZE #.(* 5 512))
- (defflavor input-stream ((jfn NIL) % TOPS-20 file number
- ptr % "pointer" to next char in buffer
- count % number of valid chars in buffer
- eof-flag % T => this bufferfull is the last
- file-name % full name of actual file
- buffer % input buffer
- )
- ()
- (gettable-instance-variables file-name)
- )
- % Note: The JSYS function can't be used for the 'SIN' JSYS because the JSYS
- % function handles errors. The 'SIN' JSYS will report an error on end-of-file
- % if errors are being handled. We don't want that to happen!
- (CompileTime (progn
- (put 'SIN 'OpenCode '((jsys 8#52) (move (reg 1) (reg 3))))
- (put 'BIN 'OpenCode '((jsys 8#50) (move (reg 1) (reg 2))))
- (put 'CLOSF 'OpenCode '((jsys 8#22) (move (reg 1) (reg 1))))
- (put 'RFPTR 'OpenCode '((jsys 8#43) (jfcl) (move (reg 1) (reg 2))))
- (put 'SFPTR 'OpenCode '((jsys 8#27) (jfcl) (move (reg 1) (reg 1))))
- ))
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (defmethod (input-stream getc) ()
- % Return the next character from the file. Line termination is represented
- % by a single NEWLINE (LF) character. Returns NIL on end of file.
- % Implementation note: It was determined by experiment that the PSL
- % compiler produces much better code if there are no function calls other
- % than tail-recursive ones. That's why this function is written the way
- % it is.
- (if (< ptr count)
- (let ((ch (prog1
- (string-fetch buffer ptr)
- (setf ptr (+ ptr 1))
- )))
- % Ignore CR followed by LF
- (if (= ch #\CR)
- (=> self &getc-after-CR)
- ch
- ))
- (=> self &fill-buffer-and-getc)
- ))
- (defmethod (input-stream &getc-after-CR) () % Internal method.
- % We have just read a CR from the buffer. If the next character
- % is a LF, then we should ignore the CR and return the LF.
- % Otherwise, we should return the CR.
- (if (= (=> self peekc-image) #\LF)
- (=> self getc-image)
- #\CR
- ))
- (defmethod (input-stream &fill-buffer-and-getc) () % Internal method.
- (and (=> self &fill-buffer) (=> self getc)))
- (defmethod (input-stream getc-image) ()
- % Return the next character from the file. Do not perform any translation.
- % In particular, return all <CR>s. Returns NIL on end of file.
- (if (< ptr count)
- (prog1
- (string-fetch buffer ptr)
- (setf ptr (+ ptr 1))
- )
- (=> self &fill-buffer-and-getc-image)
- ))
- (defmethod (input-stream &fill-buffer-and-getc-image) () % Internal method.
- (and (=> self &fill-buffer) (=> self getc-image)))
- (defmethod (input-stream empty?) ()
- (null (=> self peekc-image)))
- (defmethod (input-stream peekc) ()
- % Return the next character from the file, but don't advance to the next
- % character. Returns NIL on end of file. Maps CRLF to LF.
- (if (< ptr count)
- (let ((ch (string-fetch buffer ptr)))
- % Ignore CR if followed by LF
- (if (and (= ch #\CR)
- (= (=> self &peek2) #\LF)
- )
- #\LF
- ch
- ))
- (=> self &fill-buffer-and-peekc)
- ))
- (defmethod (input-stream &fill-buffer-and-peekc) () % Internal method.
- (and (=> self &fill-buffer) (=> self peekc)))
- (defmethod (input-stream peekc-image) ()
- % Return the next character from the file, but don't advance to the next
- % character. Returns NIL on end of file.
- (if (< ptr count)
- (string-fetch buffer ptr)
- (=> self &fill-buffer-and-peekc-image)
- ))
- (defmethod (input-stream &fill-buffer-and-peekc-image) () % Internal method.
- (and (=> self &fill-buffer) (=> self peekc-image)))
- (defmethod (input-stream &peek2) () % Internal method.
- % Return the character after the next character in the file, but don't
- % advance. Does not map CRLF. Returns Ascii NUL on end of file. Requires
- % that the buffer contain at least one character. This is a hack required
- % to implement PEEKC.
- (let ((next-ptr (+ ptr 1)))
- (cond ((>= next-ptr count)
- % The next character has not yet been read into the buffer.
- (let* ((old-pos (RFPTR jfn))
- (ch (BIN jfn))
- )
- (SFPTR jfn old-pos)
- ch
- ))
- (t (string-fetch buffer next-ptr))
- )))
- (defmethod (input-stream &fill-buffer) () % Internal method.
- % Return NIL iff there are no more characters.
- (if eof-flag
- NIL
- (let ((n (SIN jfn (jconv buffer) (- (const FILE-BUFFER-SIZE)))))
- (if (~= n 0) (setf eof-flag T))
- (setf count (+ (const FILE-BUFFER-SIZE) n))
- (setf ptr 0)
- (~= count 0))))
- (defmethod (input-stream getl) ()
- % Read and return (the remainder of) the current input line.
- % Read, but don't return the terminating EOL (if any).
- % (EOL is interpreted as LF or CRLF)
- % Return NIL if no characters and end-of-file detected.
- (if (and (>= ptr count) (not (=> self &fill-buffer)))
- NIL
- % Else
- (let ((start ptr) (save-buffer NIL) (eof? NIL))
- (while (and (not eof?) (~= (string-fetch buffer ptr) #\LF))
- (setf ptr (+ ptr 1))
- (cond ((>= ptr count)
- (setf save-buffer
- (concat save-buffer (subseq buffer start ptr)))
- (setf eof? (not (=> self &fill-buffer)))
- (setf start ptr)
- ))
- )
- (if eof?
- save-buffer
- % Else
- (setf ptr (+ ptr 1))
- (if (= ptr 1)
- (if save-buffer
- (if (= (string-fetch save-buffer (size save-buffer)) #\CR)
- (subseq save-buffer 0 (size save-buffer))
- (sub save-buffer 0 (size save-buffer)))
- (subseq buffer start ptr))
- (if (= (string-fetch buffer (- ptr 2)) #\CR)
- (concat save-buffer (subseq buffer start (- ptr 2)))
- (concat save-buffer (subseq buffer start (- ptr 1)))
- )))
- )))
- (defmethod (input-stream tell-position) ()
- % Return an integer representing the current "position" of the stream. About
- % all we can guarantee about this integer is (1) it will be 0 at the
- % beginning of the file and (2) if you later SEEK-POSITION to this integer,
- % the stream will be reset to its current position. The reason for this
- % fuzziness is that the translation of CRLF into LF performed by the "normal"
- % input operations makes it impossible to predict the relationship between
- % the apparent file position and the actual file position.
- (- (RFPTR jfn) (- count ptr))
- )
- (defmethod (input-stream seek-position) (p)
- (setf p (int2sys p))
- (let* ((buffer-end (RFPTR jfn))
- (buffer-start (- buffer-end count)))
- (if (and (>= p buffer-start) (< p buffer-end))
- (setf ptr (- p buffer-start))
- % Else
- (SFPTR jfn p)
- (setf ptr 0)
- (setf count 0)
- (setf eof-flag NIL)
- )
- ))
- (defmethod (input-stream open) (name-of-file)
- % Open the specified file for input via SELF. If the file cannot be opened,
- % a Continuable Error is generated.
- (if jfn (=> self close))
- (setf buffer (MkString (const FILE-BUFFER-SIZE) #\space))
- (setf ptr 0)
- (setf count 0)
- (setf eof-flag NIL)
- (setf jfn (Dec20Open name-of-file
- (int2sys 2#001000000000000001000000000000000000)
- (int2sys 2#000111000000000000010000000000100000)
- ))
- (if (= jfn 0) (setf jfn NIL))
- (if (null jfn)
- (=> self open
- (ContinuableError
- 0
- (BldMsg "Unable to Open '%w' for Input." name-of-file)
- name-of-file))
- % Else
- (setf file-name (jfn-truename jfn))
- ))
- (defmethod (input-stream close) ()
- (when jfn
- (CLOSF jfn)
- (setf jfn NIL)
- (setf buffer NIL)
- (setf count 0)
- (setf ptr 0)
- (setf eof-flag T)
- ))
- (defmethod (input-stream read-date) ()
- (jfn-read-date jfn))
- (defmethod (input-stream write-date) ()
- (jfn-write-date jfn))
- (defmethod (input-stream delete-file) ()
- (jfn-delete jfn))
- (defmethod (input-stream undelete-file) ()
- (jfn-undelete jfn))
- (defmethod (input-stream delete-and-expunge-file) ()
- (jfn-delete-and-expunge jfn))
- (defmethod (input-stream author) ()
- (jfn-author jfn))
- (defmethod (input-stream original-author) ()
- (jfn-original-author jfn))
- (defmethod (input-stream file-length) ()
- (jfn-byte-count jfn))
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % TESTING CODE
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- (CommentOutCode (progn
- (de test-buffered-input (name-of-file)
- (setf s (open-input name-of-file))
- (while (setf ch (input-stream$getc s))
- (WriteChar ch)
- )
- (=> s close)
- (Prin2 "---EOF---")
- NIL
- )
- (de time-buffered-input (name-of-file)
- (setf start-time (time))
- (setf s (open-input name-of-file))
- (while (setf ch (input-stream$getc s))
- )
- (=> s close)
- (- (time) start-time)
- )
- (de time-buffered-input-1 (name-of-file)
- (setf start-time (time))
- (setf s (open-input name-of-file))
- (while (setf ch (=> s getc))
- )
- (=> s close)
- (- (time) start-time)
- )
- (de time-standard-input (name-of-file)
- (setf start-time (time))
- (setf chan (open name-of-file 'INPUT))
- (while (not (= (setf ch (ChannelReadChar chan)) $EOF$))
- )
- (close chan)
- (- (time) start-time)
- )
- (de time-input (name-of-file)
- (list
- (time-buffered-input name-of-file)
- (time-buffered-input-1 name-of-file)
- (time-standard-input name-of-file)
- ))
- )) % End CommentOutCode
|