implementation module SearchObject;

/*
	problem: (from the perspective of the dynamic linker)
	
	assume a running application uses object from module x. The application uses a dynamic which
	in turn uses also a module y. If x <> y then there is no problem. But if x == y then, we have
	a problem.
	
	Are the running application and the dynamic using the same (object) module or are there two
	different but equally named (object) modules?
	
	To answer this question more information is needed. We cannot conclude soley from the modules
	whether the object module is shared or not. Here the type system comes in. Based on the type
	information available in each (object) module, the type system can decide whether a module is
	usable for the application and/or dynamic.
	
	If it decides that the module x can be shared between the application and its dynamic then
	there is no problem. But if not, there is a serious problem: we have two *equally* named 
	(object) modules (e.g. both modules are named x) with differently typed objects. The linker
	can however not load two equally named object modules and consider them different. Somehow
	we have to load them both!

	Solution: for the moment it is assumed that all loaded modules have *different* names
*/

/*
import
	StdEnv;

import DebugUtilities;
	
import DLState;
import UnknownModuleOrSymbol;

// Extension to library 0.8.1
//import ExtFile_IO081;
from deltaIOState import FileEnv;
import deltaFileSelect;

import DynamicLink;

import ExtFile;
import ReadObject;


import SortSymbols;
import LinkerMessages;
//import lib;

import UtilStrictLists;
*/


// NEW ...
//from Redirections import RedirectionState;
//1.3
from ReadObject import read_library_file,ReadXcoffM, ExtFileSystem, read_library_file_new;
from SortSymbols import sort_modules;
from ExtFile import ExtractPathFileAndExtension, ExtractPathAndFile, path_separator, FileExists, strip_abc_and_o_extension;
//3.1
/*2.0
from ReadObject import read_library_file,ReadXcoffM, class ExtFileSystem, instance ExtFileSystem Files, read_library_file_new;
from SortSymbols import sort_modules;
from ExtFile import ExtractPathFileAndExtension, ExtractPathAndFile, path_separator, FileExists, strip_abc_and_o_extension;
from deltaIOState import instance FileEnv (IOState s);
0.2*/

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


//from ReadObject import read_library_file, ExtFileSystem, ;

// ... NEW




/*
load_object :: !String !Int !String !*State !*DLClientState !*DLServerState !(IOState s) -> !(!Bool,![(!String,!Int,!Int)],!*State,!*DLClientState,!*DLServerState,!(IOState s));
load_object object_path_name_ext _ symbol_name state=:{one_pass_link,n_xcoff_files} dl_client_state dl_server_state io
	
	
	| F object_path_name_ext ends object_path_name_ext ".lib"
		// check if symbol_name exists, if necessary
		#!(state,io)
			= case (symbol_name == "") of {
				True
					-> (state,io);
				False
					#! ((symbol_found,state),io)
						= accFiles (check_symbol state) io;
					#! (non_fatal_error,state)
						= IsErrorOccured state;
					| not non_fatal_error
						-> (state,io);
					
					// symbol defined as required
					#! state
						= case symbol_found of {
							True
								-> state;
							False
								#! msg
									= "static library file '" +++ object_path_name_ext +++ "' does not define symbol '" +++ symbol_name +++ "' as required.";
								-> AddMessage (LinkerError msg) state;
						};
					-> (state,io);
			};
			
		// fatal error?
		#! ((symbol_found,state),io)
			= accFiles (check_symbol state) io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			=  (False,[],state,dl_client_state,dl_server_state,io);
			
			
		// read static libraries
		#! (state,io)
			= accFiles (add_static_libraries object_path_name_ext state) io

		
		#! (errors,xcoff_list, _, names_table, n_xcoff_files, files)
			= read_static_lib_files [object_path_name_ext] [] names_table n_xcoff_files xcoff_list files;
			

			/*
			# linker_messages_state
			//AddMessage
				= setLinkerMessages [LinkerError e \\ e <- errors] DefaultLinkerMessages;
			= ({ EmptyState & linker_messages_state = linker_messages_state },files);
			
			*/

			
		//= abort "load object modules";
//= (True,[],state,dl_client_state,dl_server_state,io); 

		= load_module3 object_path_name_ext 0 symbol_name state dl_client_state dl_server_state io;

		
		//(True,[],state,dl_client_state,dl_server_state,io); 
where {
	add_static_libraries lib_file_name state files
		// select
		#! (names_table,state)
			= select_namestable state;
		#! (xcoff_a,state)
			= select_xcoff_a state;
		#! xcoff_list 
			= xcoff_array_to_list 0 xcoff_a;
			
		// load object module from library
		#! (errors,xcoff_list, _, names_table, n_xcoff_files, files)
			= read_static_lib_files [lib_file_name] [] names_table n_xcoff_files xcoff_list files;			
		#! state
			= { state &
				namestable = names_table
			};
		| not (isEmpty errors)
			
			
			= (False,[],SetLinkerMessages (LinkerError [LinkerError e \\ e <- errors]) state,dl_client_state,dl_server_state,io); 

			
// winos dependent
	check_symbol state files
		// open library
		#! (errors,lib_file,files)
			= StaticOpenLibraryFile object_path_name_ext files;
		
		// read library info
		#! (n_xcoff_files, xcoff_file_offsets, n_xcoff_symbols, indices, string_table, lib_file)
			= ReadSecondLinkerMember lib_file;
			
		// close library
		#! files 
			= CloseLibraryFile lib_file files;
			
		// search symbol
		#! (ok,state)
			= search_symbol 0 0 n_xcoff_symbols string_table state;	
		= ((ok,state),files);
	where {
		search_symbol i symbol_n n_xcoff_symbols s state
			| symbol_n == n_xcoff_symbols
				= (False,state);
				
			#! (found,i_zero_delimiter)
				= CharIndex s i '\0';
			| not found
				#! msg
					= "static library file '" +++ object_path_name_ext +++ "' is corrupt.";
				= (False,AddMessage (LinkerError msg) state);
				
				#! sn
					= (s % (i,dec i_zero_delimiter));
				| symbol_name == sn
					= (True,state);
					= search_symbol (inc i_zero_delimiter) (inc symbol_n) n_xcoff_symbols s state;
	}
} // load_object

/*
		// static library
		#! (ok,state,io)
			= case (symbol_name == "") of {
				True
					// static library needs not define symbol
					#! (errors,xcoff_list, _, names_table, n_xcoff_files, files)
						= read_static_lib_files static_libraries [] names_table n_xcoff_files xcoff_list files;
					| not (isEmpty errors)
						-> (False,SetLinkerMessages [LinkerError e \\ e <- errors],io);
			};
		= (ok,[],state,dl_client_state,dl_server_state,io);
*/
/*		
		// AddMessage
			
		= abort "load_object";
		
		= load_module3 object_path_name_ext 0 symbol_name state dl_client_state dl_server_state io;
*/		
*/


/*
** Loads a module in memory. If necessary e.g. (size symbol_name) > 0 then it is
** checked if the module is its defining module. Accordingly to the result, the
** returned bool is set. If it is false, the module is not loaded e.g. integrated
** with existing modules.
*/ 
load_object :: !String !Int !String !*State !*DLClientState !*DLServerState !(IOState s) -> !(!Bool,![(!String,!Int,!Int)],!*State,!*DLClientState,!*DLServerState,!(IOState s));
load_object object_path_name_ext object_fp_in_library symbol_name state=:{one_pass_link,n_xcoff_files} dl_client_state dl_server_state io
	
	/*
	** If symbol_name must be defined (length greater than zero), then create a
	** new, empty names_table because it is unknown if the specified module
	** actually defines the symbol.
	*/	
	#! (names_table,state)
		= case (size symbol_name) of {
			0 -> select_namestable state;
			_ -> (create_names_table,state);					
		}			

	// read object file	
	#! (redirection_state,state)	= get_redirection_state state;		
	#! ((any_extra_sections,errors,xcoff_list,names_table,redirection_state),io)
 		= accFiles (ReadXcoffM False object_path_name_ext object_fp_in_library names_table one_pass_link n_xcoff_files redirection_state) io;
 	#! state = put_redirection_state redirection_state state;
	| not (isEmpty errors)
		#! state
			= { state & namestable = names_table };
		#! messages
			= [LinkerError m \\ m <- errors];
		= (False,[],SetLinkerMessages messages state,dl_client_state,dl_server_state,io);
	
/*	
	// TEST
	#! (names_table_element,names_table)
		= find_symbol_in_symbol_table "qd" names_table
	#! names_table
		= case names_table_element of {			
			NamesTableElement _ symbol_n file_n _
				-> abort ("gevonden: symbol_n=" +++ toString symbol_n +++ " - file_n=" +++ toString file_n);
			_
				-> abort "niet gevonden";
		};
*/
			

	// if necessary, check if symbol_name is defined in this module
	#! (symbol_found,names_table,state)
		= case (size symbol_name) of {
			0 
				// symbol_name needs not be defined
				-> (True,names_table,state);
			_
				// symbol_name must be defined
				#! (names_table_element,names_table)
					= find_symbol_in_symbol_table symbol_name names_table
				-> case names_table_element of {			
					NamesTableElement _ _ _ _
						#! (old_namestable,state)
							= select_namestable state;
						-> (True, (MergeNamesTables old_namestable names_table),state);
					_
						-> (False,names_table,state);
					}
			}
	| not symbol_found
		#! state
			= { state & namestable = names_table };
		#! message
			= "module '" +++ object_path_name_ext +++ "' requires symbol " +++ symbol_name +++ "to be defined";
		= (False,[],AddMessage (LinkerError message) state,dl_client_state,dl_server_state,io);
	
	// import as many symbols as can be resolved; sort on macos probably not needed
	#! map_function
		= sel_platform
			sort_modules																				// winos
			(\xcoff -> sort_modules (split_data_symbol_lists_without_removing_unmarked_symbols xcoff))	// macos
			;
	#!  (undefined_symbols,xcoff_list,names_table)
		=  import_symbols_in_xcoff_files /*[sort_modules xcoff]*/ (map map_function xcoff_list) n_xcoff_files [] names_table;
	#! state
		= update_namestable names_table state;
	= (True,undefined_symbols,/*add_module (hd xcoffs) state*/ foldl (\state xcoff -> add_module xcoff state) state xcoff_list,dl_client_state,dl_server_state,io);
// where {
	add_module :: !*Xcoff !State -> !State;
	add_module xcoff=:{n_symbols=n_new_xcoff_symbols} state=:{n_xcoff_files,n_xcoff_symbols,n_library_symbols}
		// HACK: see InitialLink2 in ObjectToMem.icl; it is a way to pass on the absolute address of the
		//       qd symbol.
//		#! (qd_address,state)
//				= acc_pd_state (\pd_state=:{qd_address} -> (qd_address,pd_state)) state;

		#! (marked_bool_a,state)
			= select_marked_bool_a state;
		#! (marked_offset_a,state)
			= select_marked_offset_a state;
		#! (module_offset_a,state)
			= select_module_offset_a state;
		#! n_xcoff_files_plus_libraries 
			= size marked_offset_a;
		#! n_symbols 
			= n_xcoff_symbols + n_new_xcoff_symbols + n_library_symbols;
			
		# marked_bool_a2 = createArray n_symbols False;
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i-n_new_xcoff_symbols] \\ i<-[n_xcoff_symbols+n_new_xcoff_symbols..n_symbols-1]};
		
		# marked_offset_a2 = createArray (n_xcoff_files_plus_libraries+1) 0;
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i] \\ i<-[0..n_xcoff_files-1]};
		  marked_offset_a2 = {marked_offset_a2 & [n_xcoff_files] = n_xcoff_symbols};
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i-1]+n_new_xcoff_symbols \\ i<-[n_xcoff_files+1..n_xcoff_files_plus_libraries]};
	
		# module_offset_a2 = createArray n_symbols 0; //qd_address; //0;
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i-n_new_xcoff_symbols] \\ i<-[n_xcoff_symbols+n_new_xcoff_symbols..n_symbols-1]};
	
		#! state 
			= update_state_with_xcoff xcoff state;
			
		= { state & 
			n_xcoff_files = n_xcoff_files + 1,
			n_xcoff_symbols = n_xcoff_symbols + n_new_xcoff_symbols,
			
			// n_library_symbols, library_list, one_pass_link and namestable remain unaltered
			
			marked_bool_a = marked_bool_a2,
			marked_offset_a = marked_offset_a2,
			module_offset_a = module_offset_a2
		  };
//} // load_module2
	add_module2 :: !*Xcoff !State -> !State;
	add_module2 xcoff=:{n_symbols=n_new_xcoff_symbols} state=:{n_xcoff_files,n_xcoff_symbols,n_library_symbols}
		// HACK: see InitialLink2 in ObjectToMem.icl; it is a way to pass on the absolute address of the
		//       qd symbol.
//		#! (qd_address,state)
//				= acc_pd_state (\pd_state=:{qd_address} -> (qd_address,pd_state)) state;

		#! (marked_bool_a,state)
			= select_marked_bool_a state;
		#! (marked_offset_a,state)
			= select_marked_offset_a state;
		#! (module_offset_a,state)
			= select_module_offset_a state;
		#! n_xcoff_files_plus_libraries 
			= size marked_offset_a;
		#! n_symbols 
			= n_xcoff_symbols + n_new_xcoff_symbols + n_library_symbols;
			
		# marked_bool_a2 = createArray n_symbols False;
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i-n_new_xcoff_symbols] \\ i<-[n_xcoff_symbols+n_new_xcoff_symbols..n_symbols-1]};
		
		# marked_offset_a2 = createArray (n_xcoff_files_plus_libraries+1) 0;
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i] \\ i<-[0..n_xcoff_files-1]};
		  marked_offset_a2 = {marked_offset_a2 & [n_xcoff_files] = n_xcoff_symbols};
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i-1]+n_new_xcoff_symbols \\ i<-[n_xcoff_files+1..n_xcoff_files_plus_libraries]};
	
		# module_offset_a2 = createArray n_symbols 0; //qd_address; //0;
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i-n_new_xcoff_symbols] \\ i<-[n_xcoff_symbols+n_new_xcoff_symbols..n_symbols-1]};
	
		#! state 
			= update_state_with_xcoff xcoff state;
			
		= { state & 
			n_xcoff_files = n_xcoff_files + 1,
			n_xcoff_symbols = n_xcoff_symbols + n_new_xcoff_symbols,
			
			// n_library_symbols, library_list, one_pass_link and namestable remain unaltered
			
			marked_bool_a = marked_bool_a2,
			marked_offset_a = marked_offset_a2,
			module_offset_a = module_offset_a2
		  };

	add_library2 :: !Int !Int !LibraryList !State -> !State;
	add_library2 n_new_libraries n_new_library_symbols library_list state=:{n_libraries,n_xcoff_files,n_xcoff_symbols,n_library_symbols}
		#! (marked_bool_a,state)
			= select_marked_bool_a state;
		#! (marked_offset_a,state)
			= select_marked_offset_a state;
		#! (module_offset_a,state)
			= select_module_offset_a state;
		#! n_xcoff_files_plus_libraries 
			= size marked_offset_a;
		#! n_symbols 
			= n_xcoff_symbols + n_new_library_symbols + n_library_symbols;
			
		# marked_bool_a2 = createArray n_symbols False;
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  marked_bool_a2 = {marked_bool_a2 & [i]=marked_bool_a.[i-n_new_library_symbols] \\ i<-[n_xcoff_symbols+n_new_library_symbols..n_symbols-1]};
		
		# marked_offset_a2 = createArray (n_xcoff_files_plus_libraries+ n_new_libraries) 0;
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i] \\ i<-[0..n_xcoff_files-1]};  // copy old xcoff offsets
		# marked_offset_a2 = fill_library_offsets library_list n_xcoff_files n_xcoff_symbols marked_offset_a2;
		  
		  
//		  marked_offset_a2 = {marked_offset_a2 & [n_xcoff_files] = n_xcoff_symbols};
		  marked_offset_a2 = {marked_offset_a2 & [i]=marked_offset_a.[i-n_new_libraries]+n_new_library_symbols 
		  
//?		  \\ i<-[n_xcoff_files+n_new_libraries..n_xcoff_files_plus_libraries]};
		  \\ i<-[n_xcoff_files+n_new_libraries.. /* n_xcoff_files_plus_libraries */ n_xcoff_files_plus_libraries+n_new_libraries - 1 ]};

	
		# module_offset_a2 = createArray n_symbols 0; //qd_address; //0;
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i] \\ i<-[0..n_xcoff_symbols-1]};
		  module_offset_a2 = {module_offset_a2 & [i]=module_offset_a.[i-n_new_library_symbols] \\ i<-[n_xcoff_symbols+n_new_library_symbols..n_symbols-1]};
	
//		#! state 
//			= update_state_with_xcoff xcoff state;
			
		= { state & 
//			n_xcoff_files = n_xcoff_files + 1,
//			n_xcoff_symbols = n_xcoff_symbols + n_new_xcoff_symbols,
			n_libraries			= n_new_libraries + n_libraries,
			n_library_symbols	= n_new_library_symbols + n_library_symbols,

			
			// n_library_symbols, library_list, one_pass_link and namestable remain unaltered
			// State
			marked_bool_a = marked_bool_a2,
			marked_offset_a = marked_offset_a2,
			module_offset_a = module_offset_a2
		  };
	split_data_symbol_lists_without_removing_unmarked_symbols
		// The Clean 1.3 compiler does check only when they are fully expanded. The Clean 2.0 compiler checks
		// before expansion.
		= abort "split_data_symbol_lists_without_removing_unmarked_symbols; look in source";
		  
import ObjectToMem;

add_libraries [] state dl_client_state dl_server_state io
	= (state,dl_client_state,dl_server_state,io);
	
add_libraries new_library_file_names state=:{n_libraries,n_library_symbols,library_file_names} dl_client_state=:{initial_link} dl_server_state io
	| initial_link
		// IDE should already have put the required libraries in the list
		= (state,dl_client_state,dl_server_state,io);

	/*
		assumprtions:
		- 	dynamically loaded symbols have unique names
		-	library names can be prefixed with their paths
		-	library files can have different names but still refer to the same dll
		
		improvements:
		-	an initial link of a lazily linked client (during Init-function call) is guaranteed to already have	
			a list of required libraries. 
	*/
	// determine what libraries have not yet been loaded
	#! (libraries_to_be_loaded,library_file_names)
		= foldl f ([],library_file_names) new_library_file_names;
	| isEmpty libraries_to_be_loaded
		= (state,dl_client_state,dl_server_state,io);
		
	= load_libraries libraries_to_be_loaded state dl_client_state dl_server_state io;
where {
	load_libraries [] state dl_client_state dl_server_state io
		= (state,dl_client_state,dl_server_state,io);
	load_libraries [lib:libs] state dl_client_state dl_server_state io
		#! (/*ok*/ _,_,_,_,state,dl_client_state,dl_server_state,io)
			= SearchAndLoad2 (LibraryUnknown lib) state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (state,dl_client_state,dl_server_state,io);
		= load_libraries libs state dl_client_state dl_server_state io;

	f s=:(libraries_to_be_loaded,existing_libraries) new_library_file_name
		| isMember new_library_file_name existing_libraries
			= s;
			= ([new_library_file_name:libraries_to_be_loaded],[new_library_file_name:existing_libraries]);
}

// precondition
only_obj_and_lib_extensions_allowed s 
	#! (_,extension)
		= ExtractPathFileAndExtension s;
	| (extension == "") || (extension == "obj") || (extension == "lib")
		= False;
		
		= abort ("1 only_obj_extension_allowed: " +++ s +++ " - " +++ extension); 

import ExtArray;
import ExtString;
import target;
import UpdateObject;

/*
	UpdateAndLoadModule2
	
	The module_path_name can have the {.lib,.obj} extensions. Other extensions e.g. .abc or .o *are*
	not allowed.
*/
UpdateAndLoadModule2 :: !String !Int !String !*State !*DLClientState !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!String,[ModuleOrSymbolUnknown],[String],[(!String,!Int,!Int)],!*State,!*DLClientState,!*DLServerState,!(IOState !*DLServerState));
UpdateAndLoadModule2 module_path_name object_fp_in_library symbol_name state dl_client_state=:{client_window} dl_server_state io
	| only_obj_and_lib_extensions_allowed module_path_name
		= abort "SearchAndLoad2: only .obj or .lib-extension allowed";

	// attempt to generate object (.o) file
	#! (object_available,object_path_name_ext,extra_objs,extra_libs,state,dl_client_state,dl_server_state,io)
		= GenerateObject module_path_name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		=  (False,"",[],[],[],state,dl_client_state,dl_server_state,io);		
	| not object_available
//		= abort ("!object not available" +++ module_path_name +++ " - <" +++ object_path_name_ext +++ ">"); 
		= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);

//		= abort ("object available" +++ object_path_name_ext);

	// verbose
	#! state 
		= AddMessage (Verbose ("loaded " +++ object_path_name_ext)) state;

	// object available			
	#! (module_loaded,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= load_object object_path_name_ext object_fp_in_library symbol_name state dl_client_state dl_server_state io;
	= (module_loaded,object_path_name_ext,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);


SearchAndLoad2 :: !ModuleOrSymbolUnknown !*State !*DLClientState !*DLServerState !*(IOState !*DLServerState) -> !*(!Bool,[ModuleOrSymbolUnknown],[{#Char}],[UndefinedSymbol],!*State,!*DLClientState,!*DLServerState,!*IOState !*DLServerState);
SearchAndLoad2 (SymbolUnknown referencing_module_name symbol_name ) state dl_client_state dl_server_state io
	| /*F ("SymbolUnknown% " +++ referencing_module_name +++ " - " +++ symbol_name)*/  only_obj_and_lib_extensions_allowed referencing_module_name
		= abort "foutje; SearchAndLoad2 (SymbolUnknown: only .obj or .lib-extension allowed";

	// attempt to search symbol in symboltable	
	#! (is_defined,file_n,symbol_n,state)
		= is_defined_symbol symbol_name state;
	| is_defined 
		= /*F ("symbol " +++ symbol_name +++ " is defined") */(True,[],[],[],state,dl_client_state,dl_server_state,io);
		
	// attempt with list of unknown symbols
	#! (symbol_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= try_unknown_symbols symbol_name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
	| symbol_loaded
		= (True,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
	
	// attempt with (static) libraries; SHOULD BE DONE!		
/*
		// 2.a  Try libraries
		#! (dynamic_linker_node,state)
			= state!dynamic_linker_node;	
		#! (symbol_found, library_name, module_offset, dynamic_linker_node)
			= LookUpStaticSymbol symbol_name dynamic_linker_node; 
		#! (module_loaded, client_cancelled, new_cgpath, undefined_symbols, state, files)
			= case symbol_found of {
				False
					-> (False, False, "", [], state, files);
				True
					-> UpdateAndLoadModule env "" "" library_name module_offset "" state files;
			}
		| module_loaded || client_cancelled
			= (not client_cancelled, new_cgpath, undefined_symbols, { state & dynamic_linker_node = dynamic_linker_node}, files);
*/
	#! (symbol_loaded,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= try_user symbol_name  state dl_client_state dl_server_state io;
	| not symbol_loaded
		#! msg
			= "(SearchAndLoad2;SymbolUnknown): symbol '" +++ symbol_name +++ "'" +++
				(if (symbol_name == "")
					("")
					(" in referencing module '" +++ referencing_module_name +++ "'")
				) +++
				"has not been found.";
/*	
		// test		
		#! (is_defined,file_n,symbol_n,state)
			= is_defined_symbol ("." +++ symbol_name) state;
		| is_defined
			= abort "found!";
*/		
	
		#! state
			= AddMessage (LinkerError msg) state;
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
		= abort "loaded";
where {
	// try_unknown_symbols
	try_unknown_symbols symbol_name state dl_client_state dl_server_state io
		#! (module_found,unknown_module,dl_client_state)
			= LookUpUnknownSymbol symbol_name dl_client_state;
		| not module_found
			= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);
			#! path_module
				= unknown_module.UndefSymbol.path;
			= UpdateAndLoadModule2 path_module 0 symbol_name  state dl_client_state dl_server_state io;
			
	// try user
	try_user module_name state dl_client_state dl_server_state io
		// referencing_module_name
		#! msg
			= "try_user: not yet implemented <" +++ symbol_name +++ ">; gui not yet implemented"
		#! state
			= AddMessage (LinkerError msg) state;
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
} // SearchAndLoad2 SymbolUnknown

SearchAndLoad2 (ModuleUnknown prefixed_module_name symbol_name) state=:{n_xcoff_files} dl_client_state dl_server_state io
	| F ("*** " +++ prefixed_module_name) only_obj_and_lib_extensions_allowed prefixed_module_name
		= abort "SearchAndLoad2: only .obj or .lib-extension allowed";
		
	#! (is_defined,file_n,symbol_n,state)
		= is_defined_symbol symbol_name state;
//	| True
//		= abort prefixed_module_name;
		
	| is_defined 
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
//		= abort ("undefined " +++ symbol_name);
	
	
	// symbol is *not* defined; is module already loaded?
	#! (module_path,module_name)
		= ExtractPathAndFile prefixed_module_name;
	#! (module_found,state)
		= loopAst (f module_name) (False,state) n_xcoff_files;
	| module_found
		// symbol is not defined but its defining module is present
		#! message
			= "SearchAndLoad2 (internal error): symbol is not defined but its defining module is present";
		//= abort (symbol_name +++ " " +++ prefixed_module_name +++ " " +++ message); //
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
	
	// attempt with prefixed path
	#! (module_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= F "!" try_module_with_path module_path prefixed_module_name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
	| module_loaded
		= (True,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
	
	// attempt with (static) libraries; SHOULD BE DONE!
/*		
		MUST BE INCLUDED:
		
		// 2.a. Try statically linked libraries
		#! (dynamic_linker_node,state)
			= state!dynamic_linker_node;
		#! (module_path, module_file_name)
			= ExtractPathAndFile prefixed_module_name;
			
		#! (module_found, library_name, module_offset, dynamic_linker_node)
			= LookUpStaticModule (module_file_name +++ ".o") dynamic_linker_node 
		#! (module_loaded, client_cancelled, new_cgpath, undefined_symbols, state, files)
			= case module_found of {
				False
					-> (False, False, "", [], state, files);
				True
					-> (UpdateAndLoadModule env "" "" library_name module_offset "" state files);
			}
		| module_loaded || client_cancelled
			= (not client_cancelled, new_cgpath, undefined_symbols, { state & dynamic_linker_node = dynamic_linker_node}, files);
*/
	
	// attempt with list of unknown modules
	#! (module_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= try_unknown_modules module_name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
	| module_loaded
		= (True,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
		
//		= abort ("<" +++ module_name +++ ">");
	

	// attempt with project and environment paths
	#! (module_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= try_project_and_env_paths module_name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| /* F "try_project_and_env_paths"*/ not non_fatal_error
		#! (ms,dl_client_state)
			= GetLinkerMessages dl_client_state;
		= abort (q ms);
		//= F "fatal_error" (False,[],[],[],state,dl_client_state,dl_server_state,io);
	| module_loaded
		= (True,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);


	// attemp user
	#! (module_loaded,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= try_user module_name state dl_client_state dl_server_state io;
	| module_loaded
		= (True,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);

/*
SearchAndLoad2 (ModuleUnknown prefixed_module_name symbol_name) state=:{n_xcoff_files} dl_client_state dl_server_state io

*/
		#! msg
			= "(!SearchAndLoad2;ModuleUnknown): module '" +++ module_name +++ "'" +++
				(if (symbol_name == "")
					("")
					(" defining symbol '" +++ symbol_name +++ "'")
				) +++
				"has not been found.";
		#! state
			= AddMessage (LinkerError msg) state;
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
where {
	q []
		= "niets";
	q [LinkerError msg:ls]
		= "Error: " +++ msg +++ (q ls);
	q [LinkerWarning msg:ls]
		= "Warning: " +++ msg +++ (q ls);
	q [Verbose msg:ls]
		= "Verbose: " +++ msg +++ (q ls);
		

	
	f :: !String !Int !(!Bool,!*State) -> !(!Bool,!*State);
	f _ _ s=:(True,state)
		= s;
	f searched_module_name file_n (_,state=:{n_xcoff_files})
	
		#! (module_name,state)
			= select_module_name file_n state;
		| F ("searched: " +++ searched_module_name +++ " - current: " +++ module_name) True
		= (module_name == searched_module_name,state);
		
		
		
		
		
		
	// try_module_with_path
	try_module_with_path module_path module_path_name state dl_client_state dl_server_state io
		| /*F "try_module_with_path"*/ module_path == ""
			= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);
			= UpdateAndLoadModule2 module_path_name 0 symbol_name state dl_client_state dl_server_state io;
			
	// try_unknown_modules
	try_unknown_modules module_name state dl_client_state dl_server_state io
		#! (module_found,unknown_module,dl_client_state)
			= LookUpUnknownModule module_name dl_client_state;
		| not module_found
			= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);
			#! path_module
				= unknown_module.UndefModule.path;
			= UpdateAndLoadModule2 path_module 0 symbol_name state dl_client_state dl_server_state io;
			
	// try_module_with_paths
	try_project_and_env_paths module_name state dl_client_state=:{project,target={target_path}} dl_server_state io
//		| F ("searching " +++ module_name) True
		#! module_name_in_clean_system_files
			= (toString path_separator) +++ "Clean System Files" +++ (toString path_separator) +++ module_name;

		// try (static) project paths
		#! (s=:(module_found_and_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io))
			= try_paths (fst (getStaticInfo project)).stat_paths module_name_in_clean_system_files state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (False,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
		| module_found_and_loaded
			= (module_found_and_loaded,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);

		// try (dynamic) project paths
		#! (s=:(module_found_and_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io))
			= try_paths (fst (getDynamicInfo project)).dyn_paths module_name_in_clean_system_files state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (False,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
		| module_found_and_loaded
			= (module_found_and_loaded,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
			
		// try environment paths
		#! (s=:(module_found_and_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io))
			= try_paths target_path module_name_in_clean_system_files state dl_client_state dl_server_state io;
		| /*F "try_project_and_env_paths"*/ module_found_and_loaded
			= /*F ("try_project_and_env_paths; found: " +++ module_name_in_clean_system_files)*/ (module_found_and_loaded,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);	
		
		// module not found
		= /*F ("try_project_and_env_paths; not found." +++ module_name_in_clean_system_files)*/ (False,"",[],[],[],state,dl_client_state,dl_server_state,io);
	where {
		try_paths Nil module_name_in_clean_system_files state dl_client_state dl_server_state io
			= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);
			
		try_paths (p:!ps) module_name_in_clean_system_files state dl_client_state dl_server_state io
			#! path_module
				= p +++ module_name_in_clean_system_files;
			#! (s=:(module_loaded,_,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io))
				= UpdateAndLoadModule2 path_module 0 "" state dl_client_state dl_server_state io;
			#! (non_fatal_error,state)
				= IsErrorOccured state;
			| F ("try_paths: " +++ path_module) not non_fatal_error
				= (False,"",[],[],[],state,dl_client_state,dl_server_state,io);

			| not module_loaded
				= try_paths ps module_name_in_clean_system_files state dl_client_state dl_server_state io;
				
				= (module_loaded,"",extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);
	} // try_project_and_env_paths
	
	// try_user; windows specific
	try_user module_name state dl_client_state=:{project} dl_server_state=:{application_path} io
		#! state
			= AddMessage (LinkerError "user-interface not implemented.") state;
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);

//		= abort ("try_user: not yet implemented" +++ module_name);
	
/*
		// macOs
		#! (open_button_pressed,module_path,dl_server_state,io)
			= SelectInputFile dl_server_state io;
		| not open_button_pressed
			= (False,[],[],[],state,dl_client_state,dl_server_state,io);
			
			#! 
			
			= abort "try user";
*/

/*
		// winOs; general
		#! (include_dir,module_path,cancelled)
			= GetModulePath title module_name 2 env_string;
		| cancelled
			= (False,[],[],[],state,dl_client_state,dl_server_state,io);
		
		#! path_module
			= if (ends module_name ".obj") module_name (fst (ExtractPathFileAndExtension module_path)); 
		#! (s=:(module_loaded,module_path,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io))
			= UpdateAndLoadModule2 path_module 0 "" state dl_client_state dl_server_state io;
		| not module_loaded
			= try_user module_name state dl_client_state dl_server_state io;

			// if necessary, update project			
			#! (path,name_extension)
				= ExtractPathAndFile module_path;
		
			#! dl_client_state
				= case include_dir of {
					True
						#! (stripped_clean_system_files_suffix,path)
							= strip_clean_system_files path;
						-> AddDynamicProjectPath path dl_client_state;
					False
						#! (name,extension)
							= ExtractPathFileAndExtension name_extension;
						#! (module_name,path)
							= case (extension == "obj") of {
								True
									-> (name +++ ".obj",path +++ toString path_separator +++ name +++ ".obj");
								False
									-> (name,path +++ toString path_separator +++ name);
							};
						#! dl_client_state
							= AddUnknownModule module_name path dl_client_state;
						-> dl_client_state;
				};
			= (module_loaded,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io);		
	where {
		env_string
			=	"project\0" +++ (fst (getStaticInfo project)).stat_prj_path +++ "\0" +++
			 	"application\0" +++ application_path +++ "\0\0";
			
		title
			= "Select module '" +++ module_name +++ "'";
	} // try_user
*/
	
} // SearchAndLoad2

SearchAndLoad2 (LibraryUnknown library_name) state=:{library_file_names} dl_client_state dl_server_state io
	#! (path,name)
		= ExtractPathAndFile library_name;
	
	// attempt with prefixed path
	#! (ok,state,dl_client_state,dl_server_state,io)
		= load_library library_name state dl_client_state dl_server_state io;
	| ok
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
		
	// attempt with already loaded libraries
	| isMember name library_file_names
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
		
	// attempt with list of unknown dynamic libraries
	#! (found,dlib,dl_client_state)
		= LookUpDynamicLibrary name dl_client_state;
	| found
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
		
	// attempt with project and environment paths
	#! (library_found,state,dl_client_state,dl_server_state,io)
		= try_project_and_env_paths name state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
	| library_found
		= (True,[],[],[],state,dl_client_state,dl_server_state,io);
		
		// error
		#! msg
			= "SearchAndLoad2 (LibraryUnknown: gui not yet implemented";
		#! state
			= AddMessage (LinkerError msg) state;
		= (False,[],[],[],state,dl_client_state,dl_server_state,io);
where {
	try_project_and_env_paths library_name state dl_client_state=:{project,target={target_path}} dl_server_state io
		#! library_name_in_clean_system_files
			= (toString path_separator) +++ "Clean System Files" +++ (toString path_separator) +++ library_name;

		// try (static) project paths
		#! (library_found_and_loaded,state,dl_client_state,dl_server_state,io)
			= try_paths (fst (getStaticInfo project)).stat_paths library_name_in_clean_system_files state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (False,state,dl_client_state,dl_server_state,io);	
		| library_found_and_loaded
			= (library_found_and_loaded,state,dl_client_state,dl_server_state,io);
			
		// try (dynamic) project paths
		#! (library_found_and_loaded,state,dl_client_state,dl_server_state,io)
			= try_paths (fst (getDynamicInfo project)).dyn_paths library_name_in_clean_system_files state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (False,state,dl_client_state,dl_server_state,io);
		| library_found_and_loaded
			= (library_found_and_loaded,state,dl_client_state,dl_server_state,io);
			
		// try environment paths
		#! (library_found_and_loaded,state,dl_client_state,dl_server_state,io)
			= try_paths (fst (getDynamicInfo project)).dyn_paths library_name_in_clean_system_files state dl_client_state dl_server_state io;
		#! (non_fatal_error,state)
			= IsErrorOccured state;
		| not non_fatal_error
			= (False,state,dl_client_state,dl_server_state,io);
		| library_found_and_loaded
			= (library_found_and_loaded,state,dl_client_state,dl_server_state,io);
			= (False,state,dl_client_state,dl_server_state,io);
	where {
		try_paths Nil library_name_in_clean_system_files state dl_client_state dl_server_state io
			= (False,state,dl_client_state,dl_server_state,io);
			
		try_paths (p:!ps) library_name_in_clean_system_files state dl_client_state dl_server_state io
			#! path_library
				= p +++ library_name_in_clean_system_files;
			#! (s=:(library_loaded,state,dl_client_state,dl_server_state,io))
				= load_library path_library state dl_client_state dl_server_state io;	
			| not library_loaded
				= try_paths ps library_name_in_clean_system_files state dl_client_state dl_server_state io;
				
				= (library_loaded,state,dl_client_state,dl_server_state,io);
	} // try_project_and_env_paths

	load_library :: !String !*State !*DLClientState !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!*State,!*DLClientState,!*DLServerState,!(IOState !*DLServerState));
	load_library library_name state=:{n_libraries,library_list} dl_client_state dl_server_state io
		#! (library_exists,io)
			= accFiles (/*file_exists*/ FileExists library_name) io;
		| not library_exists
			= (False,state,dl_client_state,dl_server_state,io);
			
			#! (namestable,state)
				= select_namestable state;
			#! ((ok,library_name2,library_symbols2,n_library_symbols2,namestable),io)
				= accFiles (read_library_file2 library_name (~ (inc n_libraries)) namestable) io
			#! state
				= { state & namestable = namestable};
			| not ok
				= (False,state,dl_client_state,dl_server_state,io);
	
		
			#! new_library_list
				= Library library_name2 /* mac */ 0 library_symbols2 n_library_symbols2 library_list;
//			| F library_name2 True 
		

			#! state
				= add_library library_name new_library_list n_library_symbols2 state;
			#! state 
				= {state & library_list = new_library_list};
			= /*F "voorbij"*/ (True,state,dl_client_state,dl_server_state,io);
	where {
		read_library_file2 file_name library_n names_table0 files0
			#! (ok1,library_name,library_symbols,n_library_symbols,files1,names_table1)
				= read_library_file file_name library_n files0 names_table0;
			= ((ok1,library_name,library_symbols,n_library_symbols,names_table1),files1);

		add_library library_name new_library_list n_new_library_symbols state=:{n_libraries,library_file_names,n_xcoff_symbols,n_library_symbols,n_xcoff_files}
			#! (marked_bool_a,state)
				= select_marked_bool_a state;
			#! (marked_offset_a,state)
				= select_marked_offset_a state;
			#! (module_offset_a,state)
				= select_module_offset_a state;
			#! n_symbols2
				= n_xcoff_symbols + n_new_library_symbols + n_library_symbols;
			#! n_symbols
				= n_xcoff_symbols + n_library_symbols;

			//
			#! n_new_xcoff_symbols 
				= n_new_library_symbols;
			#! n_xcoff_files_plus_libraries
				= size marked_offset_a;

			// marked_bool_a2
			#! marked_bool_a2
				= createArray n_symbols2 False;
			#! (i,marked_bool_a,j,marked_bool_a2)
				= copy 0 n_xcoff_symbols marked_bool_a 0 marked_bool_a2;
			#! (_,marked_bool_a,j,marked_bool_a2)
				= copy n_xcoff_symbols n_symbols marked_bool_a (n_xcoff_symbols + n_new_library_symbols) marked_bool_a2;
				
			// marked_offset_a2
			#! s_marked_offset_a2
				= n_xcoff_files + n_libraries + 1;
			#! marked_offset_a2
				= createArray s_marked_offset_a2 0;
				
			#! (i,marked_offset_a,j,marked_offset_a2)
				= copy 0 n_xcoff_files marked_offset_a 0 marked_offset_a2;
			#! marked_offset_a2
				= { marked_offset_a2 & [n_xcoff_files] = n_xcoff_symbols };
			#! (_,marked_offset_a,j,marked_offset_a2)
				= copy_and_add n_xcoff_files (n_xcoff_files + n_libraries) marked_offset_a (inc n_xcoff_files) marked_offset_a2 n_new_library_symbols;
				
			// module_offset		
			#! module_offset_a2
				= createArray n_symbols2 0;
			#! (i,module_offset_a,j,module_offset_a2)
				= copy 0 n_xcoff_symbols module_offset_a 0 module_offset_a2;
			#! (_,module_offset_a,j,module_offset_a2)
				= copy n_xcoff_symbols n_symbols module_offset_a (n_xcoff_symbols + n_new_library_symbols) module_offset_a2;
					
			// update state
			#! state
				= { state &
					n_libraries			= inc n_libraries
				,	n_library_symbols	= n_new_library_symbols + n_library_symbols
				,	marked_bool_a		= marked_bool_a2
				,	marked_offset_a		= marked_offset_a2
				,	module_offset_a		= module_offset_a2
				
				// dynamic libraries
				,	library_list 		= new_library_list
				,	library_file_names	= [library_name:library_file_names]
				};
			= state;	
		where {
			// copies from i to limit. s[limit] is *not* copied. 
			copy i limit s j d
				| i == limit
					= (i,s,j,d);
					
					#! (e,s)
						= s![i];
					= copy (inc i) limit s (inc j) {d & [j] = e};
					
			copy_and_add i limit s j d c
				| i == limit
					= (i,s,j,d);
					
					#! (e,s)
						= s![i];
					= copy_and_add (inc i) limit s (inc j) {d & [j] = e + c} c;
		
		};	
	}
} // SearchAndLoad2 (LibraryUnknown

/*
	OPERATIONS ON MODULES

	list with unknown modules contains module names *without* extension. One exception
	modules with extension .obj. Each module occurs only once in this list.
	
	An unknown module is a record:
		- module_name
		  In case of an .obj-file the extension is included. In any other case the extension
		  is omitted, which means it is a clean object module. 
		- path
		  Contains the full path. The filename at the very right has the above described
		  format.
*/
LookUpUnknownModule :: !String !*DLClientState -> (!Bool,!UndefModule,!*DLClientState);
LookUpUnknownModule module_name1 dl_client_state=:{project}
	#! (pdi,project)
		= getDynamicInfo project;
	#! modules
		= Filter (\um -> um.UndefModule.module_name == module_name1) pdi.dyn_mods;
	= (LLength modules <> 0, if (LLength modules == 0) EmptyUndefModule (Head modules),dl_client_state);
		
AddUnknownModule :: !String !String !*DLClientState -> !*DLClientState;
AddUnknownModule module_name path_and_file dl_client_state=:{project}
	#! (found,_,dl_client_state)
		= LookUpUnknownModule module_name dl_client_state;
	| found
		= dl_client_state;

		#! new_unknown_module
			= { UndefModule | EmptyUndefModule &
				module_name = module_name,
				path = strip_abc_and_o_extension path_and_file
			};
		#! (pdi,project)
			= getDynamicInfo project;
		#! pdi
			= { pdi &
				dyn_mods = Append pdi.dyn_mods new_unknown_module
			};	

		#! dl_client_state 
			= { dl_client_state &
				updated 	= True
			,	project		= setDynamicInfo pdi project
			};
		= dl_client_state;

/*
	OPERATIONS ON SYMBOLS
	
	An unknown symbol is a record:
		- symbol_name
		- path
		  Contains the full path. The filename has the same format as described in the
		  path-field for modules
*/

strip_clean_system_files s
	| ends s clean_system_files
		= (True,s % (0, size s - s_clean_system_files - 1));
		= (False,"");		
where {
	clean_system_files
		= toString path_separator +++ "Clean System Files";
		
	s_clean_system_files
		= size clean_system_files;
} // strip_clean_system_files
		
LookUpUnknownSymbol :: !String !*DLClientState -> (!Bool,!UndefSymbol,!*DLClientState);
LookUpUnknownSymbol symbol_name dl_client_state=:{project}
	#! (pdi,project)
		= getDynamicInfo project;
	#! symbols 
		= Filter (\us -> us.UndefSymbol.symbol_name == symbol_name) pdi.dyn_syms;
	= (LLength symbols <> 0, if (LLength symbols == 0) EmptyUndefSymbol (Head symbols),dl_client_state);
			
AddUnknownSymbol :: !String !String !*DLClientState -> !*DLClientState;
AddUnknownSymbol symbol_name path_and_file dl_client_state=:{project}
	#! (found,_,dl_client_state)
		= LookUpUnknownSymbol symbol_name dl_client_state;
	| found
		= dl_client_state;
		
		#! new_unknown_symbol
			= { UndefSymbol | EmptyUndefSymbol &
				symbol_name = symbol_name,
				path = strip_abc_and_o_extension path_and_file
			};
		#! (pdi,project)
			= getDynamicInfo project;
		#! pdi
			= { pdi &
				dyn_syms = Append pdi.dyn_syms new_unknown_symbol
			};
		#! dl_client_state 
			= { dl_client_state &
				updated 	= True
			,	project		= setDynamicInfo pdi project
			};
		= dl_client_state;
		
// Dynamic project paths
LookUpDynamicProjectPath :: !String !*DLClientState -> !(!Bool,!*DLClientState);
LookUpDynamicProjectPath dynamic_project_path1 dl_client_state=:{project}
	#! (pdi,project)
		= getDynamicInfo project;
	#! dynamic_project_paths
		= Filter (\dynamic_project_path	-> dynamic_project_path == dynamic_project_path1) pdi.dyn_paths;
	= (LLength dynamic_project_paths <> 0, dl_client_state);
	
AddDynamicProjectPath :: !String !*DLClientState -> !*DLClientState;
AddDynamicProjectPath dynamic_project_path dl_client_state=:{project}
	#! (found,dl_client_state)
		= LookUpDynamicProjectPath dynamic_project_path dl_client_state;
	| found
		= dl_client_state;

		#! (pdi,project)
			= getDynamicInfo project;
		#! pdi
			= { pdi &
				dyn_paths = Append pdi.dyn_paths dynamic_project_path
			};
		#! dl_client_state 
			= { dl_client_state &
				updated 	= True
			,	project		= setDynamicInfo pdi project
			};
		= dl_client_state;
		
// dynamic libraries
LookUpDynamicLibrary :: !String !*DLClientState -> !(!Bool,!String,!*DLClientState);
LookUpDynamicLibrary dynamic_library_name dl_client_state=:{project}
	#! (pdi,project)
		= getDynamicInfo project;
	#! dyn_libs
		= Filter (\dyn_dlib -> ends dyn_dlib dynamic_library_name) pdi.dyn_dlibs;
	= (LLength dyn_libs <> 0, if (LLength dyn_libs == 0) "" (Head dyn_libs),dl_client_state);
			
/*
** Loads a module and the modules it depends upon. If necessary the additional 
** restriction is imposed that it must be the defining module of the specified 
** symbol. The restriction is only valid during the first invocation of the 
** function.
** It is guaranteed that at return, that all modules are loaded having without
** having unresolved references.
*/	
load_modules2 :: [ModuleOrSymbolUnknown] !*State !*DLClientState !*DLServerState !(IOState !*DLServerState) -> !(!Bool,!*State,!*DLClientState,!*DLServerState,!(IOState !*DLServerState));
load_modules2 [] state dl_client_state dl_server_state io
	= (True,state,dl_client_state,dl_server_state,io);

load_modules2 [module_or_symbol_unknown:module_or_symbol_unknowns] state dl_client_state dl_server_state=:{application_path} io
	// attempt to load the module module_name
	#! (module_loaded,extra_objs,extra_libs,undefined_symbols,state,dl_client_state,dl_server_state,io)
		= SearchAndLoad2 module_or_symbol_unknown state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,state,dl_client_state,dl_server_state,io);
	| not module_loaded
		= (False,state,dl_client_state,dl_server_state,io);
		
	// load extra libraries
	#! (state,dl_client_state,dl_server_state,io)
		= add_libraries extra_libs state dl_client_state dl_server_state io;
	#! (non_fatal_error,state)
		= IsErrorOccured state;
	| not non_fatal_error
		= (False,state,dl_client_state,dl_server_state,io);
		
	// extract module names
	#! module_or_symbol_unknowns
		= extract_and_add_module_names undefined_symbols (extra_objs ++ module_or_symbol_unknowns);
		
	// load module dependencies of the recently loaded module
	#! (modules_loaded,state,dl_client_state,dl_server_state,io)
		= load_modules2 module_or_symbol_unknowns state dl_client_state dl_server_state io;
	| not modules_loaded
		= (False,state,dl_client_state,dl_server_state,io);
		
	// all module dependencies have been loaded; import remaining undefined symbols
	= import_undefined_symbols undefined_symbols state dl_client_state dl_server_state io;
where {
	import_undefined_symbols :: [UndefinedSymbol] !*State !*DLClientState !*DLServerState !*(IOState !*DLServerState) -> !*(!Bool,!*State,!*DLClientState,!*DLServerState,!*IOState !*DLServerState);
	import_undefined_symbols [] state dl_client_state dl_server_state io
		= (True,state,dl_client_state,dl_server_state,io);
		
	import_undefined_symbols [undefined_symbol=:(label_name,xcoff_n,_):undefined_symbols] state dl_client_state dl_server_state io
		// import undefined symbol
		#! (is_defined_symbol,state) 
			= import_undefined_symbol undefined_symbol state
		| is_defined_symbol
		 	= import_undefined_symbols undefined_symbols state dl_client_state dl_server_state io;
		 	
			// undefined symbol
			#! (name_of_referencing_module,state)
		 		= select_file_name xcoff_n state;
		 	#! (ok,state,dl_client_state,dl_server_state,io)
		 		= load_modules2 [(SymbolUnknown (strip_abc_and_o_extension name_of_referencing_module) label_name)] state dl_client_state dl_server_state io;
		 		
		 	// import undefined symbol		 	
		 	#! (is_defined_symbol,state)
		 		= import_undefined_symbol undefined_symbol state;	
		 	| is_defined_symbol == True
				= import_undefined_symbols undefined_symbols state dl_client_state dl_server_state io;
				
				= (False,state,dl_client_state,dl_server_state,io);
	{}
	{
		/*
		** If an assumed undefined symbol appears to be defined somewhere, its
		** symbolic reference by label_name is converted into a file_n and 
		** symbol_n--pair. Otherwise, false is returned.
		*/ 
		import_undefined_symbol :: !UndefinedSymbol !State -> (!Bool,!State);
		import_undefined_symbol (label_name,xcoff_n,index) state
			# (namestable,state)
				= select_namestable state;
			# (names_table_element,namestable)
				= find_symbol_in_symbol_table label_name namestable
			# state
				= update_namestable namestable state;
		
			= case names_table_element of {
				NamesTableElement _ symbol_n file_n symbol_list
					# state
						= update_symbol (CreateImportedLabel file_n symbol_n) xcoff_n index state;
					-> (True,state);	
				_
					-> (False,state);
			}
	}

	extract_and_add_module_names :: ![UndefinedSymbol] [ModuleOrSymbolUnknown] -> [ModuleOrSymbolUnknown];
	extract_and_add_module_names [] module_or_symbol_unknowns
		= module_or_symbol_unknowns;	
	
	extract_and_add_module_names [(symbol_name,_,_):symbol_names] module_or_symbol_unknowns
		#! (module_name_extracted,module_name)
			= extract_module_name symbol_name;
//		| module_name == "clCrossCall"
//			= abort ("stop " +++ symbol_name);
		
		#! module_name 
			= case module_name of {
				"system"	-> "_system";
				_			-> module_name
			}
		| not module_name_extracted
			= extract_and_add_module_names symbol_names module_or_symbol_unknowns;
	
			/*
			** Module name extracted
			*/
			#! module_name_already_in_unknown_modules
				= isEmpty (filter (f module_name) module_or_symbol_unknowns);
			| module_name_already_in_unknown_modules
				= extract_and_add_module_names symbol_names (module_or_symbol_unknowns ++ [ModuleUnknown module_name ""]);
			
				= extract_and_add_module_names symbol_names module_or_symbol_unknowns;
	where
	{
		extract_module_name :: !String -> !(!Bool,!String);
		extract_module_name ""
			= (False,"");
			
		extract_module_name symbol_name
			#! (e__prefixed, index)
				= starts "e__" symbol_name;
			| e__prefixed
				#! (non_underscore_found, non_underscore_index)
					= CharIndexFunc symbol_name index (\c -> c <> '_');
				| not non_underscore_found
					= (False,"");
					
	//			#! (underscore_found, underscore_index)
	//				= find_rightmost_underscores symbol_name non_underscore_index;		
			
					#! (underscore_found, underscore_index)
						= CharIndexFunc symbol_name non_underscore_index (\c -> c == '_');

					| not underscore_found
						= (False,"");
						
						/*
						** e____SystemEnum__symbool
						**    ^ ^         ^
						**    | |         | 
						** non_underscore |
						**    |  _index   |
						**  index         |
						**          underscore_index
						*/
						#! module_name
							= case (index == non_underscore_index) of {
								True
									#! module_name
										= symbol_name % (index,underscore_index - 1);						
									-> if (module_name == "system") "_system" module_name;
									
								False
									#! module_name
										= symbol_name % (non_underscore_index - 1, underscore_index - 1)
									-> module_name;
							
							}
						
						
						= (True,module_name);
		
				/*
				** no 'e__' prefix, no modulename to be extracted
				*/
				= (False,"");
		where {
		/*
			find_rightmost_underscores symbol_name non_underscore_index /* previous underscores: */ prev_underscore_index_found prev_underscore_index
					#! (underscore_found, underscore_index)
						= CharIndexFunc symbol_name non_underscore_index (\c -> c == '_');						
					| not underscore_found
						= abort "hallo"; //(underscore_found, underscore_index);
						
					= find_rightmost_underscores symbol_name (underscore_index + 2) 
					
					
					= abort ("found" +++ symbol_name % (underscore_index,size symbol_name -1) +++ "original: <"+++ symbol_name +++ ">");
		*/
					
				
					/*

				#! (non_underscore_found, non_underscore_index)
					= find_rightmost_underscores symbol_name index;		
/*
				#! (non_underscore_found, non_underscore_index)
					= CharIndexFunc symbol_name index (\c -> c <> '_');
*/*/
		
		} // extract_module_name
	
				
		 f :: !String !ModuleOrSymbolUnknown -> !Bool;
		 f module_name1 (ModuleUnknown module_name2 _)
		 	#! (module_name2,_)
		 		= ExtractPathFileAndExtension module_name2
		 	= ends module_name2 module_name1;
		 f _ _
		 	= False;
	}

} // load_modules2	

		
/*		
LookUpStaticSymbol :: !String !DynamicLinkerNode -> (!Bool,!String,!Int,!DynamicLinkerNode);
LookUpStaticSymbol symbol_name dynamic_linker_node /*=:{staticlibraries}*/
	= (False, "", 0, dynamic_linker_node); //= abort "LookUpStaticSymbol";
/* 		
	#! (symbol_found, library_name, module_offset, new_staticlibraries)
		= look_up_static_module staticlibraries symbol_name [];
	| not symbol_found
		= (False, "", 0, dynamic_linker_node);
		= (True, library_name, module_offset, {dynamic_linker_node & staticlibraries = new_staticlibraries});
*/
/*
where
{
	E :: !a !b -> !b;
	E a b = b;
	
	look_up_static_module [] symbol_name new_static_libraries
		= (False, "",  0, []);
		
	look_up_static_module [static_library=:{static_library_name,static_symbols,static_modules}:static_libraries] symbol_name new_static_libraries
		#! (symbol_found, module_offset)
			= bin_search symbol_name 0 (size static_symbols - 1) static_symbols;
		| symbol_found
			#! (found, new_static_modules)
				= look_up_within_static_library static_modules module_offset [];
			| not found
				= abort "LookUpStaticSymbol: error, library file is corrupted";
						
			#! new_static_library
				= case (isEmpty new_static_modules) of {
					True
						/*
						** All modules within the library have been used. Therefore the complete
						** library is removed from the list.
						*/
						-> [];
					False
						/*
						** Only a single object module of the library needs to be removed. The 
						** rest of the modules contained in that library remains.
						*/
						-> [{static_library &
							 static_modules = new_static_modules
							}];	
				
				}
			= (True, static_library_name, module_offset,new_static_libraries ++ new_static_library ++ static_libraries);
			
				
			
			//= abort "gevonden";
			
			= look_up_static_module static_libraries symbol_name (new_static_libraries ++ [static_library]);
	where
	{
		bin_search symbol_name start end static_library_symbols
		/*
			| start == size static_library_symbols
				= (False, 0);
				
				
				| symbol_name == (fst static_library_symbols.[start])
					= (True, (snd static_library_symbols.[start]));
					
					= bin_search symbol_name (inc start) end static_library_symbols;
		*/	
		
			| symbol_name == center_symbol_name
				/*
				** Symbol found
				*/
				= (True, center_module_offset);
				
				| start == end 
					/*
					** Symbol name has not been found
					*/
					= (False,  0);
					
					| symbol_name < center_symbol_name
						/*
						** Try the left of the array
						*/
						= bin_search symbol_name start (dec center) static_library_symbols;
					
						/*
						** Try the right of the array 
						*/
						= bin_search symbol_name (inc center) end static_library_symbols;
		where
		{
			center = /*E 1*/ /*(fwrites s stderr)*/ (start + ((end - start + 1) / 2));
			
			(center_symbol_name,center_module_offset)
				 = static_library_symbols.[center];
				 
			s	= (toString start) +++ " - " +++ (toString end) +++ "\n";
				 
			E :: !a !b -> !b;
			E a b = b
		}
		
		look_up_within_static_library [] module_file_offset new_static_modules
			= (False, []);
		look_up_within_static_library [(module_name,module_offset):modules] module_file_offset new_static_modules
			| module_offset == module_file_offset
				= (True, new_static_modules ++ modules); 
				
				= look_up_within_static_library	modules module_file_offset (new_static_modules ++ [(module_name,module_offset)]);

	
	}
}
*/

// lookup module in *.lib	
LookUpStaticModule :: !String !DynamicLinkerNode -> (!Bool,!String,!Int,!DynamicLinkerNode);
LookUpStaticModule module_file_name dynamic_linker_node=:{project}
	= (False,"",0,dynamic_linker_node);

//	| True // tellertje & weggooien van libs
//		= abort ("LookUpStaticModule: " +++ module_file_name); //= (False,"",0,dynamic_linker_node);	
	

/*	
LookUpStaticModule :: !String !DynamicLinkerNode -> (!Bool,!String,!Int,!DynamicLinkerNode);
LookUpStaticModule module_file_name dynamic_linker_node //=:{staticlibraries}
	#! (module_found,library_name,module_offset,new_staticlibraries)
		= look_up_static_module staticlibraries module_file_name [];
	| not module_found
		= (False, "", 0, dynamic_linker_node);
	
		= (True, library_name, module_offset, dynamic_linker_node); //{dynamic_linker_node & staticlibraries = new_staticlibraries});
where	 
{
	look_up_static_module [] module_file_name new_static_libraries
		= (False, "", 0, []);
		 
	look_up_static_module [static_library=:{static_library_name,static_modules}:static_libraries] module_file_name new_static_libraries
		#! (module_found, offset, new_static_modules)
			= look_up_within_static_library static_modules module_file_name [];
		| not module_found
			= look_up_static_module static_libraries module_file_name (new_static_libraries ++ [static_library])
			
			#! new_static_library
				= case (isEmpty new_static_modules) of {
					True
						/*
						** All modules within the library have been used. Therefore the complete
						** library is removed from the list.
						*/
						-> [];
					False
						/*
						** Only a single object module of the library needs to be removed. The 
						** rest of the modules contained in that library remains.
						*/
						-> [{static_library &
							 static_modules = new_static_modules
							}];	
				
				}
			
				= (True, static_library_name, offset,new_static_libraries ++ new_static_library ++ static_libraries);
			
			// volgorde van libraries, geen lege libraries, als of module geladen of een symbool 
			// geladen, dan kan de hele module weg.	 
			
	where	
	{
		look_up_within_static_library [] module_file_name new_static_modules
			= (False, 0, []);
		look_up_within_static_library [(module_name,module_offset):modules] module_file_name new_static_modules
			| module_file_name == module_name
				= (True, module_offset, new_static_modules ++ modules); 
				
				= look_up_within_static_library	modules module_file_name (new_static_modules ++ [(module_name,module_offset)]);
	} 
}
*/




// -------------------------------------------------------------------------------------------------------



// LOADING OF MODULES
	  
			
*/
/*
LookUpUnknownModule :: !String !*DLClientState -> (!Bool,!UndefModule,!*DLClientState);
*/
// EXTRA PROJECT FUNCTIONS

		




		
/*
RemoveUnknownModule :: !String !DynamicLinkerNode -> !DynamicLinkerNode;
RemoveUnknownModule module_file_name dynamic_linker_node=:{project} 
	#! module_name
		= if (ends module_file_name ".obj") module_file_name (fst (ExtractPathFileAndExtension module_file_name))
	#! (pdi,project)
		= getDynamicInfo project;
	#! modules
		= Filter (\um -> um.module_name <> module_name) pdi.dyn_mods;
	= { dynamic_linker_node & 
		updated = (LLength modules) <> (LLength pdi.dyn_mods)
	  , project = setDynamicInfo pdi project
	 };

RemoveUnknownSymbol :: !String !DynamicLinkerNode ->  !DynamicLinkerNode;
RemoveUnknownSymbol symbol_name dynamic_linker_node=:{project}
	#! (pdi,project)
		= getDynamicInfo project;
	#! symbols
		= Filter (\us -> us.symbol_name <> symbol_name) pdi.dyn_syms;
	= { dynamic_linker_node &
		updated = (LLength symbols) <> (LLength pdi.dyn_syms)
	  , project = setDynamicInfo pdi project
	 };
*/