textfile.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand        --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute  and/or modify it under the terms of the GNU Library General --
-- Public  License (LGPL)  as published  by the  Free  Software  Foundation; --
-- either version 2 of the license, or (at your option) any later version.   --
-- This  library  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details.       --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------


class TEXT_FILE < $FILES,$OSTREAM

class TEXT_FILE < $FILES,$OSTREAM is -- This class specifies the text file specific operations on file -- objects. It treats a file as a simple stream for which no positioning -- operations are provided. See also the $FILE_CURSORS class. -- Version 1.3 Nov 2000. Copright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 5 Apr 96 kh Original -- 5 Apr 97 kh Modified for INT to CARD -- 26 Oct 98 kh Revised, added pre/post conditions -- 17 Nov 00 kh Added size to give chars not octets include FILE{TEXT_FILE} size -> private octet_size ; size( lib : LIBCHARS ) : CARD pre ~void(self) and ~void(fyle) post true -- or an exception has been raised. is -- This routine returns the current size of the file as the number of -- CHARs contained in the given culture encoding. If the contents have been -- written and not flushed then the value returned may not reflect the -- actual contents of the file when flushed and closed. If the attempt to -- obtain the size is not accepted by the underlying file system then an -- exception is raised for external handling. return octet_size / lib.my_size end ; size : CARD pre ~void(self) and ~void(fyle) post true -- or an exception has been raised. is -- This routine returns the current size of the file as the number of -- CHARs contained using the default culture encoding. See also the above -- definition. return size(LIBCHARS::default) end ; cursor( buff_size : CARD, lib : LIBCHARS ) : TEXT_FILE_CURSOR pre ~void(fyle) and ((buff_size % 4) = 0) post ~void(result) is -- This routine provides for buffered I/O using the file cursor -- returned. This permits the use of large files where reading all of -- file contents at once would be impractical. return TEXT_FILE_CURSOR::create(fyle,buff_size,lib,readable,writable) end ; cursor( buff_size : CARD ) : TEXT_FILE_CURSOR pre ~void(fyle) and ((buff_size % 4) = 0) post ~void(result) is -- This routine provides for buffered I/O using the file cursor -- returned. This permits the use of large files where reading all of -- file contents at once would be impractical. return cursor(buff_size,LIBCHARS::default) end ; plus( item : $STR ) pre ~void(self) and ~void(fyle) and writable post (size >= initial(size)) is -- This routine appends the given item to the current channel at its -- present position. Note the special handling of the void string at the -- beginning! if void(item) then -- nothing to do! return end ; dummy : BOOL ; count : CARD ; loc_lib : LIBCHARS ; loc_octs : BINSTR ; typecase item when CHAR then count := 1 ; loc_octs := item.binstr ; loc_lib := LIBCHARS::default ; loc_octs := loc_octs.tail(loc_lib.my_size) when FSTR then count := item.size ; loc_octs := item.binstr ; loc_lib := item.index_lib when STR then count := item.size ; loc_octs := item.binstr ; loc_lib := item.index_lib else SYS_ERROR::create.error(self,SYS_EXCEPT::Bad_Type,my_name) end ; dummy := FILE_SYS::file_write(loc_octs,loc_lib.my_size,inout count,fyle) end ; plus( item : $STR ) : SAME pre ~void(self) and ~void(fyle) and writable post (size >= initial(size)) is -- This routine appends the given item to the current channel. It -- returns self. plus(item) ; return self end ; fstr( lib : LIBCHARS ) : FSTR pre ~void(self) and ~void(fyle) and readable post void(result) or (result.loc <= size) is -- This routine returns a string buffer containing the entire -- contents of the file. Note that some operating systems carry out -- conversions on input and the number of characters contained may, -- therefore, not be the same as reported by the filing system. -- file_size : CARD ; if ~FILE_SYS::size(fyle,out file_size) then return void end ; if file_size = 0 then -- Nothing to read! return FSTR::create(1,lib) -- an empty buffer! end ; res : FSTR := FSTR::create(file_size,lib) ; buffer_cnt : CARD := file_size ; -- in octets!! if ~FILE_SYS::seek(fyle,0.int,FILE_LOCS::Beginning) then return void end ; if ~FILE_SYS::file_read(res,1,inout buffer_cnt,fyle) then return void -- probably not readable! end ; res.loc := buffer_cnt ; return res end ; fstr : FSTR pre ~void(self) and ~void(fyle) and readable post void(result) or (result.loc <= size) is -- This routine returns a string buffer containing the entire -- contents of the file. Note that some operating systems carry out -- conversions on input and the number of characters contained may, -- therefore, not be the same as reported by the filing system. return fstr(LIBCHARS::default) end ; frunes( lib : LIBCHARS ) : FRUNES pre ~void(self) and ~void(fyle) and readable post (result.loc = size) is -- This routine returns a text buffer containing the entire contents of -- the file if no error was detected (otherwise an empty text string). This -- contents is organised as a sequence of runes each of which in general have -- more encodings than one. The string is organised into runes on the -- assumption that it uses the given repertoire and encoding. file_size : CARD ; if ~FILE_SYS::size(fyle,out file_size) then return void end ; if file_size = 0 then -- Nothing to read! return FRUNES::create(1,lib) -- an empty buffer! end ; res : FRUNES := FRUNES::create(file_size,lib) ; buffer_cnt : CARD := file_size ; -- in octets!! if ~FILE_SYS::seek(fyle,0.int,FILE_LOCS::Beginning) then return void end ; if ~FILE_SYS::file_read(res,1,inout buffer_cnt,fyle) then return void -- probably not readable! end ; res.loc := buffer_cnt ; res.buffer_scan ; return res end ; frunes : FRUNES pre ~void(self) and ~void(fyle) and readable post (result.loc = size) is -- This routine returns a text buffer containing the entire contents of -- the file if no error was detected (otherwise an empty text string). This -- contents is organised as a sequence of runes each of which in general have -- more encodings than one. The string is organised into runes on the -- assumption that it is in the program environment repertoire and encoding. return frunes(LIBCHARS::default) end ; end ; -- TEXT_FILE

class TEXT_FILE_CURSOR < $FILE_CURSORS{CHAR,STR}

class TEXT_FILE_CURSOR < $FILE_CURSORS{CHAR,STR} is -- This class implements the detailed buffered I/O operations for -- a text file. Note that the majority of these make use of the underlying -- STR_CURSOR operations. -- Version 1.1 Apr 97. Copright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 5 Apr 96 kh Original -- 5 Apr 97 kh Modified for portability include FILE_CURSOR{TEXT_FILE_CURSOR, FSTR} ; create( handle : REFERENCE, buff_size : CARD, lib : LIBCHARS, rd, wr : BOOL ) : SAME pre ~void(handle) and (buff_size % 4 = 0) -- to avoid character code across boundary! post ~void(result) is -- THIS ROUTINE IS NOT FOR DIRECT USE -- IT IS ONLY FOR USE BY AN -- OBJECT OF THE TEXT_FILE CLASS!!! -- -- This routine establishes a new buffer for the specified file. It -- does NOT fill the buffer until an actual input/output operation is -- required! me : SAME := new ; me.fyle := handle ; me.buffer := FSTR::create(buff_size,lib) ; me.position := 0 ; me.buff_position := 0 ; me.buff_length := buff_size ; me.buff_valid := false ; me.buff_altered := false ; me.index := 0 ; me.writable := wr ; me.readable := rd ; return me end ; getch : CHAR pre ~void(self) and readable post ((result.code = CHAR_CODE::null) and at_end) or ~(result.code = CHAR_CODE::null) is -- This procedure returns a single character from the current line of -- text (providing that there is one), moving the cursor forward by one. loop -- needed to use next_ch! return next_ch! end end ; retract : SAME pre ~void(self) and (position >= buffer.index_lib.my_size) post ((result.position + result.buffer.index_lib.my_size) = initial(self.position)) is -- This routine moves the cursor backwards one character position. This -- is done by using backup. back_up ; return self end ; get_upto( ch : CHAR ) : STR pre ~void(self) and readable post result.index_lib = buffer.index_lib is -- This routine returns the string up to the next occurrence of -- ch -- or the end of the current line, whichever occurs first. res : FSTR := FSTR::create(buffer.index_lib) ; loc_line : STR := STR::create(buffer.index_lib).line_mark ; loop loc_ch : CHAR := next_ch! ; if (loc_ch.code = CHAR_CODE::null) then return res.str elsif (loc_ch = ch) or loc_line.contains(loc_ch) then dummy : SAME := retract ; return res.str else res := res + loc_ch end end ; return res.str end ; get_line : STR pre ~void(self) and readable post buffer.index_lib = result.index_lib is -- This routine returns all of the characters remaining on the current -- text line, advancing the cursor by as many places. It does NOT -- include any end of line mark! loc_mark : STR := STR::create(buffer.index_lib).line_mark ; res : FSTR := FSTR::create(buffer.index_lib) ; loc_ch : CHAR ; loop if at_end then return res.str end ; loc_ch := next_ch! ; if loc_mark.contains(loc_ch) then back_up ; return res.str else res := res + loc_ch end end end ; skip_to( ch : CHAR ) pre ~void(self) and readable post true is -- This routine skips up to the next occurrence of ch wherever it may -- occur in the remainder of the file -- or to the end of file, whichever -- occurs first. loop if at_end then break! elsif ch = next_ch! then dummy : SAME := retract ; break! end end end ; skip_over( ch : CHAR ) pre ~void(self) and readable post true is -- This routine skips up to the position one character beyond the next -- occurrence of ch wherever it may occur in the remainder of the file -- -- or to the end of file, whichever occurs first. loop if at_end then break! elsif ch = next_ch! then break! end end end ; skip_line pre ~void(self) and readable post true is -- This routine advances the cursor past the next end of line mark, -- or to the end of file -- whichever occurs first. loc_mark : STR := STR::create(buffer.index_lib).line_mark ; first_ch : CHAR ; loop if at_end then return end ; first_ch := next_ch! ; until!(loc_mark.contains(first_ch)) ; end ; loop if at_end then return end ; second_ch : CHAR := next_ch! ; if first_ch = second_ch or ~loc_mark.contains(second_ch) then back_up end ; return end end ; plus( item : CHAR ) pre ~void(self) and writable and ((buff_contents % buffer.index_lib.my_size) = 0) post (buffer[(index - 1) / buffer.index_lib.my_size] = item) is -- This routine appends item at the current position of the cursor. ch_size : CARD := buffer.index_lib.my_size ; if position < buff_position then emptybuff ; fillbuff else index := position - buff_position end ; if index = buff_contents then emptybuff ; if ~at_end then -- refill to over-write! fillbuff end end ; ch_index : CARD := index / ch_size ; buffer[ch_index] := item ; buff_altered := true ; -- needs writing after this! index := index + ch_size ; position := position + ch_size end ; plus( item : CHAR ) : SAME pre ~void(self) and writable post (buffer[(index - 1) / buffer.index_lib.my_size] = item) is -- This routine appends the given character to the file, returning -- the cursor. plus(item) ; return self end ; plus( str : STR ) pre ~void(self) and (str.size > 0) and writable and (str.index_lib = buffer.index_lib) post (position = (initial(position) + (str.size * str.index_lib.my_size))) is -- This routine appends str as a sequence of characters, using the -- routine above, to the file, starting at the current position of the cursor. todo : CARD := str.size ; -- characters - NOT octets cnt : CARD := 0 ; ch_index : CARD ; -- character index ch_size : CARD := buffer.index_lib.my_size ; -- octets! loop if position >= buff_position then index := position - buff_position ; buff_valid := (index < buff_length) else -- buffer needs filling! buff_valid := false end ; if ~buff_valid then -- simple! going forward! emptybuff ; if ~at_end then fillbuff else buff_position := position ; index := 0 end end ; todo := todo - cnt ; if todo = 0 then break! elsif todo > cnt then cnt := todo.min((buff_length - index) / ch_size) end ; loop cnt.times! ; ch_index := (index / ch_size).up! ; buffer.aset(ch_index,str.elt!) end ; buff_altered := true ; position := position + (cnt * ch_size) end end ; plus( str : STR ) : SAME pre ~void(self) and (str.size > 0) and writable and (str.index_lib = buffer.index_lib) post (position = (initial(position) + (str.size * str.index_lib.my_size))) is -- This routine appends str to the file, returning the cursor. plus(str) ; return self end ; skip( cnt : CARD ) : SAME pre ~void(self) and (cnt > 0) post (position > initial(position)) is -- This routine skips forward the given number of string items. It is -- NOT merely a renaming of forward above. loop cnt.times! ; dummy : CHAR := next_ch! end ; return self end ; private back_up pre ~void(self) and (position >= buffer.index_lib.my_size) post ((position + buffer.index_lib.my_size) = initial(position)) is -- This routine backs up one character code length. ch_size : CARD := buffer.index_lib.my_size ; position := position - ch_size end ; private next_ch! : CHAR pre ~void(self) post ~(result.code = CHAR_CODE::null) -- or has quit! is -- This iter 'hides' all of the buffer filling and emptying needed -- for file reading. Note that the attribute position is always considered -- to be the file position which may or may not be in the buffer on -- entry. Note that there is no readable pre-condition since all of the -- routines which may call this make a readability test! ch_size : CARD := buffer.index_lib.my_size ; loop if position = size then quit elsif position >= buff_position then index := position - buff_position ; buff_valid := (index < buff_contents) else -- buffer needs filling! buff_valid := false end ; if ~buff_valid then -- simple! going forward! fillbuff ; if buff_contents = 0 then -- reached the end quit end end ; position := position + ch_size ; -- after the yield yield buffer[index / ch_size] ; end end ; end ; -- TEXT_FILE_CURSOR