PageRenderTime 20ms CodeModel.GetById 11ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/io/basic/text_file_read.e

http://github.com/tybor/Liberty
Specman e | 327 lines | 253 code | 28 blank | 46 comment | 22 complexity | ad6eee2a62669354b9ca039009f4134d MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class TEXT_FILE_READ
  5   --
  6   -- Basic input facilities to read a named file on the disc.
  7   --
  8   -- Note: most features are common with STD_INPUT so you can test your program on the
  9   -- screen first and then, just changing of instance (STD_INPUT/TEXT_FILE_READ), doing the
 10   -- same in a file.
 11   --
 12   -- Input stream usage is available in tutorial/io and Liberty Eiffel FAQ.
 13   --
 14
 15inherit
 16   FILE_STREAM
 17      redefine out_in_tagged_out_memory
 18      end
 19   TERMINAL_INPUT_STREAM
 20      redefine filtered_read_line_in, filtered_read_available_in, out_in_tagged_out_memory
 21      end
 22
 23insert
 24   STRING_HANDLER
 25      redefine out_in_tagged_out_memory
 26      end
 27
 28create {ANY}
 29   make, connect_to
 30
 31feature {ANY}
 32   connect_to (new_path: ABSTRACT_STRING)
 33         -- Open text file for reading. The stream is positioned at the
 34         -- beginning of the file.
 35      local
 36         p: POINTER
 37      do
 38         p := new_path.to_external
 39         input_stream := text_file_read_open(p)
 40         if input_stream.is_not_null then
 41            end_of_input := False
 42            set_path(new_path)
 43            if capacity = 0 then
 44               buffer := buffer.calloc(4096)
 45               capacity := 4096
 46            end
 47            end_reached := False
 48            buffer_position := 0
 49            buffer_size := 0
 50            filtered_last_character := '%U'
 51         end
 52      ensure then
 53         is_connected implies not end_of_input
 54      end
 55
 56   disconnect
 57      do
 58         io_fclose(input_stream)
 59         path := Void
 60         filter := Void
 61      end
 62
 63   can_unread_character: BOOLEAN
 64      do
 65         Result := buffer_position > 0
 66      end
 67
 68   end_of_input: BOOLEAN
 69
 70   out_in_tagged_out_memory
 71      do
 72         tagged_out_memory.append(once "{TEXT_FILE_READ ")
 73         tagged_out_memory.append(path)
 74         tagged_out_memory.extend('}')
 75      end
 76
 77feature {FILTER_INPUT_STREAM}
 78   filtered_read_character
 79      do
 80         if buffer_position >= buffer_size then
 81            fill_buffer
 82         end
 83         filtered_last_character := buffer.item(buffer_position)
 84         buffer_position := buffer_position + 1
 85         end_of_input := end_reached
 86         check
 87            valid_last_character
 88         end
 89      end
 90
 91   filtered_unread_character
 92      do
 93         end_of_input := False
 94         buffer_position := buffer_position - 1
 95         if valid_last_character then
 96            filtered_last_character := buffer.item(buffer_position - 1)
 97         end
 98      end
 99
100   filtered_last_character: CHARACTER
101
102   filtered_read_line_in (str: STRING)
103      local
104         i: INTEGER; stop: BOOLEAN; old_count, new_count: INTEGER; initial_count: INTEGER
105      do
106         from
107            initial_count := str.count
108         until
109            stop
110         loop
111            -- search %N in buffer
112            from
113               i := buffer_position
114            until
115               i >= buffer_size or else buffer.item(i) = '%N'
116            loop
117               i := i + 1
118            end
119            -- block copy (but slice_copy copies char by char...)
120            if i > buffer_position then
121               old_count := str.count
122               new_count := old_count + i - buffer_position
123               if str.capacity < new_count then
124                  str.resize((old_count * 2).max(new_count))
125               end
126               str.storage.slice_copy(old_count, buffer, buffer_position, i - 1)
127               str.set_count(new_count)
128            end
129            -- next buffer if needed
130            if i < buffer_size and then buffer.item(i) = '%N' then
131               stop := True
132               buffer_position := i + 1
133               if str.count > initial_count and then str.last = '%R' then
134                  str.remove_last
135                  -- UNIX uses the Linefeed character (ASCII character 10) to
136                  -- denote the end of a line. DOS uses the Carriage Return
137                  -- followed by the Linefeed character (ASCII character 13
138                  -- & ASCII character 10) to denote a new line.
139               end
140            else
141               if not end_reached then
142                  fill_buffer
143               end
144               stop := end_reached
145            end
146         end
147         end_of_input := end_reached
148      end
149
150   filtered_read_available_in (str: STRING; limit: INTEGER)
151         -- Limit reading to what the buffer contains. If the buffer is already exhausted, just fill it once.
152      local
153         old_count, new_count, i: INTEGER
154      do
155         if buffer_position >= buffer_size then
156            fill_buffer
157         end
158         old_count := str.count
159         i := limit.min(buffer_size - buffer_position)
160         new_count := old_count + i
161         if str.capacity < new_count then
162            str.resize((old_count * 2).max(new_count))
163         end
164         str.storage.slice_copy(old_count, buffer, buffer_position, buffer_position + i - 1)
165         str.set_count(new_count)
166         buffer_position := buffer_position + i
167      end
168
169feature {FILTER}
170   filtered_descriptor: INTEGER
171      do
172         Result := sequencer_descriptor(input_stream)
173      end
174
175   filtered_has_descriptor: BOOLEAN True
176
177   filtered_stream_pointer: POINTER
178      do
179         Result := input_stream
180      end
181
182   filtered_has_stream_pointer: BOOLEAN True
183
184feature {FILE_TOOLS}
185   same_as (other: like Current): BOOLEAN
186      require
187         is_connected
188         other.is_connected
189      local
190         b1, b2: NATIVE_ARRAY[CHARACTER]; i: INTEGER
191      do
192         from
193            fill_buffer
194            b1 := buffer
195            other.fill_buffer
196            b2 := other.buffer
197            Result := True
198         until
199            not Result or else end_reached or else other.end_reached
200         loop
201            if buffer_size = other.buffer_size then
202               if b1.item(0) /= b2.item(0) then
203                  Result := False
204               else
205                  -- make first character different for loop end
206                  b1.put('%R', 0)
207                  b2.put('%N', 0)
208                  from
209                     i := buffer_size - 1
210                  variant
211                     i
212                  until
213                     b1.item(i) /= b2.item(i)
214                  loop
215                     i := i - 1
216                  end
217                  Result := i = 0
218               end
219               if Result then
220                  fill_buffer
221                  other.fill_buffer
222               end
223            else
224               from
225                  read_character
226                  other.read_character
227               until
228                  not Result or else end_of_input or else other.end_of_input
229               loop
230                  Result := last_character = other.last_character
231                  read_character
232                  other.read_character
233               end
234            end
235         end
236         Result := Result and then end_reached and then other.end_reached
237         disconnect
238         other.disconnect
239      ensure
240         not is_connected
241         not other.is_connected
242      end
243
244feature {INPUT_STREAM}
245   input_stream: POINTER
246
247feature {TEXT_FILE_READ}
248   buffer: NATIVE_ARRAY[CHARACTER]
249
250   end_reached: BOOLEAN
251
252   buffer_position, buffer_size: INTEGER
253
254   capacity: INTEGER
255
256   fill_buffer
257      local
258         last: CHARACTER; more: BOOLEAN
259      do
260         more := buffer_size > 0
261         if more then
262            last := buffer.item(buffer_size - 1)
263         end
264         buffer_size := io_fread(buffer, capacity, input_stream)
265         buffer_position := 0
266         if buffer_size = 0 then
267            end_reached := True
268            if more then
269               -- needed for unread_character service
270               buffer.put(last, 0)
271               buffer_size := 1
272               buffer_position := 1
273            else
274               buffer_size := 0
275            end
276         elseif buffer_size < 0 then
277            -- ???
278         end
279      end
280
281feature {}
282   make
283         -- The new created object is not connected. (See also `connect_to'.)
284      do
285      ensure
286         not is_connected
287      end
288
289   text_file_read_open (path_pointer: POINTER): POINTER
290      external "plug_in"
291      alias "{
292         location: "${sys}/plugins"
293         module_name: "io"
294         feature_name: "text_file_read_open"
295         }"
296      end
297
298   io_fclose (stream: POINTER)
299      external "plug_in"
300      alias "{
301         location: "${sys}/plugins"
302         module_name: "io"
303         feature_name: "io_fclose"
304         }"
305      end
306
307end -- class TEXT_FILE_READ
308--
309-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
310--
311-- Permission is hereby granted, free of charge, to any person obtaining a copy
312-- of this software and associated documentation files (the "Software"), to deal
313-- in the Software without restriction, including without limitation the rights
314-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
315-- copies of the Software, and to permit persons to whom the Software is
316-- furnished to do so, subject to the following conditions:
317--
318-- The above copyright notice and this permission notice shall be included in
319-- all copies or substantial portions of the Software.
320--
321-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
322-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
323-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
324-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
325-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
326-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
327-- THE SOFTWARE.