implementation module ReadState

import
	StdEnv,
	State,
	ReadWriteState,
	pdReadState

//import DebugUtilities;
F a b :== b;
import ExtFile;

// expected is the file of the executable
ReadState :: !String !*State !*Files -> (!*State,!*Files)
ReadState application_name state files
//	#! state
//		= EmptyState;		
	#! (path, file_name_with_extension)
		= ExtractPathAndFile application_name
	#! (file_name, _)
		= ExtractPathFileAndExtension file_name_with_extension

	#! state_file_name
		= construct_path path (file_name +++ ".dat")
	#! (ok, input, files)
		= fopen state_file_name FReadData files
	| not ok
		#! state 
			= AddMessage (LinkerWarning ("could not read complement " +++ state_file_name)) state
		= (state,files)
		
	// check if complement is up-to-date		
	#! (exists_dat_file,is_it_up_to_date,state)
		= isComplementUpToDate state_file_name state
	| exists_dat_file && (not is_it_up_to_date) 
		#! state
			= AddMessage (LinkerError ("complement " +++ state_file_name +++ " is not up-to-date")) state
		#! (_,files)
			= fclose input files;
		= (state,files)
		
	// check if complement exists
	| not exists_dat_file
		#! state
			= AddMessage (LinkerError ("complement " +++ state_file_name +++ " doesn't exists")) state
		#! (_,files)
			= fclose input files;
		= (state,files)
		
	// check header
	#! (read_minor,input,state)
		= ReadComplementVersion state_file_name ComplementVersion input state;
	#! (ok,state)
		= IsErrorOccured state;
	| not ok
		= (state,files);
		
	// skip raw data within complement
	#! (ok_freadi,object_size,input)
		= freadi input	
	#! (ok_fseek, input)
		= fseek input object_size FSeekSet
	| not (ok_freadi || ok_fseek)
		#! state
			= AddMessage (LinkerError ("error reading complement " +++ state_file_name)) state
		#! (_,files)
			= fclose input files;
		= (state,files)

	// read counters	
	#! (_,n_libraries,input)
		= freadi input
	#! (_,n_xcoff_files,input)
		= freadi input 
	#! (_,n_xcoff_symbols,input)
		= freadi input
	#! (_,n_library_symbols,input)
		= freadi input
		
	// read libraries
	#! (library_list,input)
		= ReadLibraryList n_libraries EmptyLibraryList input
	#! (library_file_names,input)
		= ReadLibraryFileNames n_libraries input;
		
	// read marked_bool_a
	#! (marked_bool_a,input)
		= loopAfillOnInput read_bool input
			
	// read_marked_offset_a
	#! (marked_offset_a,input)
		= loopAfillOnInput read_int input
	
	// read module_offset_a
	#! (module_offset_a,input)
		= loopAfillOnInput read_int input
		
	// read xcoff_a
	#! (xcoff_a,input)
		= loopAurfillOnInput (read_xcoff state_file_name) input
		
	// read namestable
	#! (namestable,input)
		= ReadNamesTable create_names_table input	

	// update state
	#! state
		= { state &
		// linker tables
			n_libraries			= n_libraries
		,	n_xcoff_files 		= n_xcoff_files
		,	n_xcoff_symbols		= n_xcoff_symbols
		,	n_library_symbols	= n_library_symbols

		,	marked_bool_a		= marked_bool_a
		,	marked_offset_a		= marked_offset_a
		,	module_offset_a		= module_offset_a
		,	xcoff_a 			= xcoff_a
		,	namestable			= namestable

		// dynamic libraries		
		,	library_list 		= library_list
		,	library_file_names	= library_file_names

		};


	#! (_,files)
		= fclose input files;
	= (state,files);
where		
	read_bool :: !Int !*{#Bool} !*File -> !(!*{#Bool},!*File)
	read_bool i marked_bool_a input
		#! (_,c,input)
			= freadc input;
		= ({ marked_bool_a & [i] = c == 'T' }, input);
		
isComplementUpToDate :: !String !*State -> (!Bool,!Bool,!*State);
isComplementUpToDate file_name state
	#! msg
		= "isComplementUpToDate (ReadState): not yet implemented";
		
	= (True,True,AddMessage (LinkerWarning msg) state);
	
//	= F "isComplementUpToDate: not yet implemented" (True,True);
/*
	# file_name_without_extension
		= fst (ExtractPathFileAndExtension file_name);
	# (found,time_low,time_high)
		= FetchFileTime (file_name_without_extension +++ ".exe");
	# (found2,time_low2,time_high2)
		= FetchFileTime (file_name_without_extension +++ ".dat");
	#! result
		= CompareFileTimes time_low2 time_high2 time_low time_high;
				
	// .dat: just as old or newer as .exe 
	= (found2,result >  (-1));
*/

// ReadNamesTable
ReadNamesTable :: !*NamesTable !*File -> (!*NamesTable,!*File)
ReadNamesTable namestable input 
	= read_names_table_elements 0 /* n_names_table_elements*/ 1 namestable input	
	where 
		read_names_table_elements i limit namestable input
			#! (end,input)
				= fend input
			| end
				= (namestable,input)
				
				/*
				** Read NamesTableElement from input
				*/
				#! (s,input)
					= freadline input
				#! (_,i0,input)
					= freadi input
				#! (_,i1,input)
					= freadi input
				#! namestable
					= insert_symbol_in_symbol_table (s % (0, size s - 2)) i0 i1 namestable
				
				= read_names_table_elements (inc i) limit namestable input

ReadLibraryList :: !Int !LibraryList !*File -> (!LibraryList,!*File)
ReadLibraryList n_libraries ll input
	| n_libraries == 0
		= (ll,input)
	
		#! (s,input)
			= freadline input


		//pc
		#! (_,i0,input)
			= freadi input



		#! (lsl,input)
			= ReadLibrarySymbolsList input
		#! (_,i1,input)
			= freadi input
		= ReadLibraryList (dec n_libraries) (Library (s % (0, size s - 2)) /* mac */ i0 lsl i1 ll) input
where
	ReadLibrarySymbolsList input
		#! (_,n_library_symbols,input)
			= freadi input
		#! (lsl,input)
			= read_library_symbols_list n_library_symbols EmptyLibrarySymbolsList input
		= (lsl,input)
	where
		read_library_symbols_list n_library_symbols lsl input
			| n_library_symbols == 0
				= (lsl,input)
	
				#! (s,input)
					= freadline input 
				= read_library_symbols_list (dec n_library_symbols) (LibrarySymbol (s % (0, size s - 2)) lsl) input
				
ReadLibraryFileNames :: !Int !*File -> !([String],!*File)	
ReadLibraryFileNames n_libraries input
	| n_libraries == 0
		= ([],input)
		
		#! (_,s_lib_name,input)
			= freadi input
		#! (lib_name,input)
			= freads input s_lib_name
		#! (libs,input)
			= ReadLibraryFileNames (dec n_libraries) input
		= F lib_name ([lib_name:libs],input)
