-- -- Author: Robert C. Shock, Dept of CS & CEG Wright State University -- In cooperation with: WRDC/ELED WPAFB Dayton, OH -- -- source: io_unit__.a with text_io; package body io_unit is type stack_element is record the_character: character := ' '; is_known: boolean := false; end record; g_stack: array ( 1 .. the_number_of_push_back_characters ) of stack_element; g_bypass_the_page_terminator: boolean := true; -- goal: instantiate the imported 'input_filter' generic type item is private; line_terminator : item; page_terminator : item; file_terminator : item; with procedure get (the_item : out item); with procedure skip_line; with procedure skip_page; with function is_end_of_line return boolean; with function is_end_of_page return boolean; with function is_end_of_file return boolean; package input_filter is procedure clear; procedure input (the_item : out item); end input_filter; --remarks: copied from Booch, Software Components With Ada p 449 generic type item is private; line_terminator : item; page_terminator : item; file_terminator : item; with procedure put ( the_item : in item ); with procedure new_line; with procedure new_page; with procedure end_file; package output_filter is procedure output ( the_item : in item ); end output_filter; --remark: code copied from Booch, Software Components With Ada pp 442-443 package body input_filter is lookahead : array ( 1 .. 2 ) of item; count : natural := 0; procedure clear is begin count := 0; end clear; procedure input ( the_item : out item ) is begin if count = 0 then if is_end_of_line then the_item := line_terminator; if is_end_of_page then lookahead ( 1 ) := page_terminator; count := 1; if is_end_of_file then lookahead ( 2 ) := file_terminator; count := 2; else skip_page; end if; else skip_line; end if; else get ( the_item ); end if; else the_item := lookahead ( 1 ); if lookahead ( 1 ) /= file_terminator then lookahead ( 1 ) := lookahead ( 2 ); count := count - 1; end if; end if; end input; end input_filter; --remarks: copied from Booch, Software Components With Ada p 449 package body output_filter is procedure output ( the_item : in item ) is begin if the_item = line_terminator then new_line; elsif the_item = page_terminator then new_page; elsif the_item = file_terminator then end_file; else put ( the_item ); end if; end output; end output_filter; procedure skip_line is begin text_io.skip_line; end skip_line; package input_stream is new input_filter ( item => character, line_terminator => the_end_line_character, page_terminator => the_end_page_character, file_terminator => the_end_file_character, get => text_io.get, skip_line => skip_line, skip_page => text_io.skip_page, is_end_of_line => text_io.end_of_line, is_end_of_page => text_io.end_of_page, is_end_of_file => text_io.end_of_file ); -- goal: to instantiate output_filter procedure new_line is begin text_io.new_line; end new_line; procedure new_page is begin text_io.new_page; end new_page; procedure end_file is begin null; end end_file; package output_stream is new output_filter ( item => character, line_terminator => the_end_line_character, page_terminator => the_end_page_character, file_terminator => the_end_file_character, put => text_io.put, new_line => new_line, new_page => new_page, end_file => end_file ); --------------------------------------------------------------------------- -- Code section build entirely from the above input output filters -- Text_io is never used in the code below procedure clear is begin g_stack := ( others => ( ' ', false ) ); end clear; procedure set_bypass_the_page_terminator is begin g_bypass_the_page_terminator := true; end set_bypass_the_page_terminator; procedure set_process_the_page_terminator is begin g_bypass_the_page_terminator := false; end set_process_the_page_terminator; function next_character_is return character is the_char: character; begin << repeat >> if not g_stack ( g_stack'first ).is_known then input_stream.input ( the_char ); else the_char := g_stack ( g_stack'first ).the_character; g_stack ( g_stack'first .. g_stack'last - 1 ) := g_stack ( g_stack'first + 1 .. g_stack'last ); g_stack ( g_stack'last ).is_known := false; end if; if g_bypass_the_page_terminator then if the_char = the_end_page_character then goto repeat; end if; end if; return the_char; end next_character_is; function next_line_is return string is the_char: character := next_character_is; begin if the_char = the_end_line_character or the_char = the_end_file_character then return ( 1 => the_char ); else return ( 1 => the_char ) & next_line_is; end if; end next_line_is; procedure get ( the_character: out character ) is begin the_character := next_character_is; end get; procedure push_back ( the_character: in character ) is begin g_stack ( g_stack'first + 1 .. g_stack'last ) := g_stack ( g_stack'first .. g_stack'last - 1 ); g_stack ( g_stack'first).is_known := true; g_stack ( g_stack'first).the_character := the_character; end push_back; -- output procedure put ( the_character: in character ) is begin output_stream.output ( the_character ); end put; procedure put ( the_string: in string ) is begin for index in the_string'range loop output_stream.output ( the_string ( index ) ); end loop; end put; ----- ITERATOR: passive procedure iterate_input_stream is continue: boolean := false; the_char: character := ' '; begin loop the_char := next_character_is; process ( the_char, continue ); exit when ( not continue ) or ( the_char = the_end_file_character ); end loop; end iterate_input_stream; -- ITERATOR: passive over lines procedure iterate_input_stream_with_lines is continue: boolean := false; procedure examine ( the_string: in string ) is -- examine the last character begin process ( the_string, continue ); if continue then continue := ( the_string ( the_string'last ) /= the_end_file_character ); end if; end examine; begin loop examine ( next_line_is ); exit when not continue; end loop; end iterate_input_stream_with_lines; begin -- PACKAGE CODE clear; set_bypass_the_page_terminator; end io_unit;