ANY FILTER_INPUT_STREAM FILTER_OUTPUT_STREAM NONE
class interface STD_INPUT_OUTPUT
   --
   -- Just a centralized access to std_input and std_output, because it's
   -- quite useful (good old io).
   --
   -- Note that it cannot be filtered itself (see invariant). Instead,
   -- use STANDARD_STREAMS features to modify std_input and std_output.
   --

creation
   make

feature(s) from INPUT_STREAM
   read_character
      -- If read_character fail, end_of_input is set and thus 
      -- any further read is forbidden. Else, use last_character.
      require
         is_connected;
         not end_of_input;
         not input_is_filtered and then can_read_character
      ensure
         is_connected

   read_line_in (buffer: STRING)
      -- Same job as read_line but storage is directly done in buffer.
      require
         is_connected;
         not end_of_input;
         not input_is_filtered and then can_read_line;
         buffer /= Void

   unread_character
      require
         is_connected;
         not input_is_filtered and then can_unread_character
      ensure
         not end_of_input

   last_character: CHARACTER
      require
         is_connected;
         not end_of_input;
         not input_is_filtered and then valid_last_character
      ensure
         is_connected;
         not end_of_input

   can_read_character: BOOLEAN

   can_read_line: BOOLEAN

   can_unread_character: BOOLEAN

   valid_last_character: BOOLEAN

   end_of_input: BOOLEAN
      -- end_of_input means the previous attempt in character 
      -- reading failed because the end has been reached. So
      -- last_character is not valid and you are not allowed to do
      -- any read attempt anymore. (NOTE: just after a successful
      -- connect, end_of_input is always false because you never read).
      --
      -- Please refer to SmartEiffel FAQ or tutorial/io examples.

   detach_input
      ensure
         not input_is_filtered

feature(s) from INPUT_STREAM
   filtered_read_character
      require
         is_connected;
         not end_of_input;
         can_read_character

   filtered_unread_character
      require
         is_connected;
         can_unread_character

   filtered_last_character: CHARACTER
      require
         is_connected;
         valid_last_character

   filtered_read_line_in (buffer: STRING)
      require
         is_connected;
         not end_of_input;
         buffer /= Void

feature(s) from INPUT_STREAM
   input_filter: FILTER_INPUT_STREAM

feature(s) from INPUT_STREAM
   -- Skipping separators:

   skip_separators
      -- Skip all separators (see is_separator of class CHARACTER) and
      -- make the first non-separator available in last_character. This
      -- non-separator character is pushed back into the stream (see
      -- unread_character) to be available one more time (the next
      -- read_character will consider this non-separator). When
      -- end_of_input occurs, this process is automatically stopped.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   skip_separators_using (separators: STRING)
      -- Same job as skip_separators using the separators set.
      require
         is_connected;
         not input_is_filtered;
         separators /= Void;
         not end_of_input

   skip_remainder_of_line
      -- Skip all the remainder of the line including the end of
      -- line delimiter itself.
      require
         is_connected;
         not input_is_filtered

feature(s) from INPUT_STREAM
   -- To read one number at a time:

   read_integer
      -- Read an integer according to the Eiffel syntax.
      -- Make result available in last_integer.
      -- Heading separators are automatically skipped using
      -- is_separator of class CHARACTER.
      -- Trailing separators are not skipped.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   last_integer: INTEGER
      -- Last integer read using read_integer.

   read_real
      -- Read a REAL and make the result available in last_real
      -- and in last_double.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   last_real: REAL
      -- Last real read with read_real.

   read_double
      -- Read a DOUBLE and make the result available in last_double.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   last_double: DOUBLE
      -- Last double read with read_double.

feature(s) from INPUT_STREAM
   -- To read one line or one word at a time:

   last_string: STRING
      -- Access to the unique common buffer to get for example the result
      -- computed by read_line, read_word, newline, etc. This is a
      -- once function (the same common buffer is used for all streams).

   read_line
      -- Read a complete line ended by '%N' or end_of_input. Make the
      -- result available in last_string common buffer. The end of line
      -- character (usually '%N') is not added in the last_string buffer.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   read_word
      -- Read a word using is_separator of class CHARACTER. The result is
      -- available in the last_string common buffer. Heading separators are
      -- automatically skipped. Trailing separators are not skipped
      -- (last_character is left on the first one). If end_of_input is
      -- encountered, Result can be the empty string.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input

   newline
      -- Consume input until newline ('%N') is found. The corresponding
      -- STRING is stored in last_string common buffer.
      require
         is_connected;
         not input_is_filtered

   reach_and_skip (keyword: STRING)
      -- Try to skip enough characters in order to reach the keyword
      -- which is skipped too. If the keyword is not in the remainder of
      -- this stream, the process is stopped as soon  as end_of_input
      -- occurs. As for skip_separators the following character of the
      -- keyword is available in last_character and not yet read.
      require
         is_connected;
         not input_is_filtered;
         not keyword.is_empty
      ensure
         not end_of_input implies last_string.is_equal(keyword)

feature(s) from INPUT_STREAM
   -- Other features:

   read_word_using (separators: STRING)
      -- Same job as read_word using separators.
      require
         is_connected;
         not input_is_filtered;
         not end_of_input;
         separators /= Void

   read_tail_in (str: STRING)
      -- Read all remaining character of the stream in str.
      require
         is_connected;
         not input_is_filtered;
         str /= Void
      ensure
         end_of_input

feature(s) from INPUT_STREAM
   io_getc (stream_pointer: POINTER): INTEGER

   io_fread (buf: NATIVE_ARRAY[CHARACTER]; size: INTEGER; stream_pointer: POINTER): INTEGER
      -- return size read or 0 if end of input (-1 on error => exception ?)

   eof: INTEGER

feature(s) from STREAM
   is_connected: BOOLEAN

   disconnect
      require
         is_connected
      ensure
         output_filter = Void

   input_is_filtered: BOOLEAN

feature(s) from STREAM
   set_input_filter (a_filter: FILTER_OUTPUT_STREAM)
      require
         a_filter /= Void
      ensure
         input_filter = a_filter

feature(s) from OUTPUT_STREAM
   put_character (c: CHARACTER)
      require
         is_connected;
         not output_is_filtered and then can_put_character(c)

   flush
      -- Flushes the pipe. If is_filtered, calls the filter's
      -- flush instead.
      require
         is_connected

   can_put_character (c: CHARACTER): BOOLEAN

   detach_output
      ensure
         not output_is_filtered

feature(s) from OUTPUT_STREAM
   filtered_put_character (c: CHARACTER)
      require
         is_connected;
         can_put_character(c)

   filtered_flush
      require
         is_connected

feature(s) from OUTPUT_STREAM
   output_filter: FILTER_OUTPUT_STREAM

feature(s) from OUTPUT_STREAM
   put_string (s: STRING)
      -- Output s to current output device.
      require
         is_connected;
         not output_is_filtered;
         s /= Void

   put_unicode_string (unicode_string: UNICODE_STRING)
      -- Output the UTF-8 encoding of the unicode_string.
      require
         is_connected;
         not output_is_filtered;
         unicode_string /= Void

feature(s) from OUTPUT_STREAM
   -- To write a number:

   put_integer (i: INTEGER_64)
      -- Output i to current output device.
      require
         is_connected;
         not output_is_filtered

   put_integer_format (i: INTEGER_64; s: INTEGER)
      -- Output i to current output device using at most s character.
      require
         is_connected;
         not output_is_filtered

   put_real (r: REAL)
      -- Output r to current output device.
      require
         is_connected;
         not output_is_filtered

   put_real_format (r: REAL; f: INTEGER)
      -- Output r with only f digit for the fractionnal part.
      -- Examples:
      --    put_real(3.519,2) print "3.51".
      require
         is_connected;
         not output_is_filtered;
         f >= 0

   put_double (d: DOUBLE)
      -- Output d to current output device.
      require
         is_connected;
         not output_is_filtered

   put_double_format (d: DOUBLE; f: INTEGER)
      -- Output d with only f digit for the fractionnal part.
      -- Examples:
      --    put_double(3.519,2) print "3.51".
      require
         is_connected;
         not output_is_filtered;
         f >= 0

   put_number (number: NUMBER)
      -- Output the number.
      require
         is_connected;
         not output_is_filtered;
         number /= Void

feature(s) from OUTPUT_STREAM
   -- Other features:

   put_boolean (b: BOOLEAN)
      -- Output b to current output device according
      -- to the Eiffel format.
      require
         is_connected;
         not output_is_filtered

   put_pointer (p: POINTER)
      -- Output a viewable version of p.
      require
         is_connected;
         not output_is_filtered

   put_new_line
      -- Output a newline character.
      require
         is_connected;
         not output_is_filtered

   put_spaces (nb: INTEGER)
      -- Output nb spaces character.
      require
         is_connected;
         not output_is_filtered;
         nb >= 0

   append_file (file_name: STRING)
      require
         is_connected;
         not output_is_filtered;
         file_exists(file_name)

feature(s) from OUTPUT_STREAM
   io_putc (byte: CHARACTER; stream: POINTER)

   io_fwrite (buf: NATIVE_ARRAY[CHARACTER]; size: INTEGER; stream: POINTER)

   io_flush (stream_pointer: POINTER)

   tmp_file_read: TEXT_FILE_READ

   tmp_string: STRING

feature(s) from STD_INPUT_OUTPUT
   make

feature(s) from STD_INPUT_OUTPUT
   singleton: STD_INPUT_OUTPUT


invariant

    is_singleton: singleton = Current;

    not_filtered: not input_is_filtered and not output_is_filtered;

end of STD_INPUT_OUTPUT