implementation module EdProjectUtils;

import StdClass,StdInt,StdBool,StdChar,StdString,StdArray, StdEnum, StdList, StdFunc;
import deltaFileSelect,deltaDialog, deltaIOState;

import	EdProgramState, EdMyIO, EdCleanSystem, EdWindows, EdProject, EdFiles, EdPath,
		EdParse, EdLists, EdDialogs, EdDrawWindow, EdMenuItems, EdTextWindow, EdOptionsMenu2, EdInterrupt;
import UtilNewlinesFile;

::	SetMadeProjectFun
	:== Bool -> Bool -> Project -> ProgState -> *(IO -> ProgIO);
	// The continuation function for the MakeProject function:
	// arguments:	- boolean indicating whether compiling/code generation/linking has been performed
	//				- boolean indicating whether 'make' was successfull
	//				- the new project
	//				- the new program state
	//				- the new io state

::	SetLinkedProjectFun
	:==	Bool -> Bool -> Bool -> (List FileInfo) -> (List Pathname) -> Project -> Bool
		-> ProgState -> *(IO -> ProgIO);
	// The continuation function for the BringProjectModulesUpToDate functions:
	// arguments:	- boolean indicating whether 'make' was successfull
	//				- boolean indicating whether new defualt/project paths were set
	//				- boolean indicating whether linking has been performed
	//				- new list with modification dates and info read from ABC file
	//				- list of project module pathnames
	//				- the new project
	//				- boolean indicating a user break
	//				- the program state
	//				- the io state

::	FileInfo
	=	 {	path		:: !Pathname,
			abcpath		:: !Pathname,
			objpath		:: !Pathname,
			sys			:: !Bool,
			seq_stack	:: !Bool, 
			version		:: !Int,
			abcOptions	:: !ABCOptions,
			dcldate		:: !DATE,
			icldate		:: !DATE,
			abcdate		:: !DATE,
			objdate		:: !DATE };
		// path name, abc/obj path names, system file?, sequential code & stack info?, version,
		// compiler options (in abc file), .dcl date, .icl date, .abc date, .obj date


::	Compiled_and_Linked	:== Bool;

	IsModal			:== False; // @@@

	System			:== "_system";

(AP2) infixr;
(AP2) f g :== f e1 e2; { (e1,e2) = g };

//	Compile /Check Syntax of the designated module

CompileProjectModule ::	!CompileOrCheckSyntax !Pathname !Project !SetMadeProjectFun !ProgState !IO -> ProgIO;
CompileProjectModule compilerOrCheckSyntax path project setproject prog io
	=	(prog2,io3);
	{
//		(_,io3) = ClearCache io2;
		io3 = io2;
		(prog2,io2) = setproject ok newpaths project` prog1 io1;
		((prog1,io1),_,project`,ok,newpaths,_) = CompileTheProjectModule True compilerOrCheckSyntax ClearCache path Nil project prog io;
	};

/*	Auxiliary function used by 'MakeTheProject': Generated code for all the out of date
	abc files in the project.
*/
	
GenProjectModules :: !Bool !Bool !Bool !(List FileInfo) !(List Pathname) !(List Pathname) !Project
					!SetLinkedProjectFun !Bool !ProgState !IO -> ProgIO;
GenProjectModules ok newpaths linked fileinfo Nil modpaths project setproject intr prog=:{editor} io
	= setproject ok newpaths linked fileinfo modpaths project intr prog io;
GenProjectModules ok newpaths linked fileinfo (path:!rest) modpaths project setproject intr prog io
	| not ok || intr
		= setproject False newpaths False fileinfo modpaths project intr prog io;
	| not ok2
		= setproject ok2 newpaths False fileinfo2 modpaths project2 intr prog2 io2;
		= ContIntr gencodeprojectmodules prog2 io2;
	{
		gencodeprojectmodules :: !Bool !ProgState !IO -> ProgIO;					
		gencodeprojectmodules intr prog io
			= GenProjectModules True False (gen || linked) fileinfo2 rest modpaths project2 setproject intr prog io;
	}
	where {
		((prog1,io1),fileinfo1,gen,abcpath)
			= CheckObjectFileOutOfDate path fileinfo project prog io;
		((prog2,io2),fileinfo2,project2,ok2,_)
			= GenCodeTheProjectModule gen False CodeGeneration abcpath fileinfo1 project prog1 io1;
	};

//	Compiles and generates code for a module.

CompileAndGenCodeProjectModule :: !CodeGenerateAsmOrCode !Pathname !Project !SetMadeProjectFun !ProgState !IO
								-> ProgIO;
CompileAndGenCodeProjectModule genAsmOrCode path project setproject prog io
	| not compiledok || newpaths	= setproject True False projecta proga ioa;
									= setproject True codegenok projectb progb iob;
	where {
	(prioa,fileinfoa,projecta,compiledok,newpaths,abcpath)
					= CompileTheProjectModule True Compilation Don`tClearCache path Nil project prog io;
	(proga, ioa)	= prioa;
	(priob,_,projectb,codegenok,_)
					= GenCodeTheProjectModule True False genAsmOrCode abcpath fileinfoa projecta proga ioa;
	(progb,iob)		= priob;
	};
	
/*	Auxiliary function used by 'CompileAndGenCodeProjectModule' and 'CompileProjectModule':
	compile the designated module.
*/
CompileTheProjectModule ::	!Bool !CompileOrCheckSyntax !CompileClearCache !Pathname !(List FileInfo) !Project !ProgState !IO
							-> (!ProgIO, !List FileInfo, !Project, !Bool, !Bool, !Pathname);
CompileTheProjectModule outofdate compileOrCheckSyntax clearCache path fileinfo project
							prog=:{editor={defaults={paths=defpaths}}} io
	| not outofdate 
		# ((prog,fileinfo`,info), io)
			=	accFiles (GetFileInfo tp path fileinfo prog) io;
		= ((prog,io),fileinfo`,project,True,False,info.abcpath);
	// otherwise
		# (prio`,abcpath,res) = Compile verbfun errwin typewin compileOrCheckSyntax clearCache path paths applicationOptions.memoryProfiling applicationOptions.profiling modinfo.ModInfo.compilerOptions prog1 io1;
		# (prog`,io`) = prio`;
		= ProcessCompilerMsg compileOrCheckSyntax path abcpath res fileinfo project prog` io`;
	where {
	(prog1,io1)				= ShowInfo True IsModal line prog io;
	mn						= GetModuleName path;
	paths					= Concat prjpaths defpaths;
	(_, modinfo)			= PR_GetModuleInfo mn project;
	line					= [(if (compileOrCheckSyntax == Compilation) "Compiling '" "Checking '") +++ RemovePath path +++ "'"];
	applicationOptions		= PR_GetApplicationOptions project;
	prjpaths				= PR_GetPaths project;
	tp						= PR_GetProcessor project;
	errwin					= UpdateInfoWindow ErrorWdID;
	typewin					= UpdateInfoWindow TypeWdID;

	verbfun :: !String !ProgState !IO -> ProgIO;
	verbfun str prog io
		= ShowInfo True IsModal ["",str] prog io;
	};

/*	Auxiliary function used by 'CompileTheProjectModule': Check whether compilation was successfull, update
	various info windows and mark this module as compiled in the project.
*/

ProcessCompilerMsg	:: 	!CompileOrCheckSyntax !Pathname !Pathname !CompilerMsg !(List FileInfo) !Project
							!ProgState !IO
						-> (!ProgIO,!List FileInfo,!Project,!Bool,Bool,!Pathname);

ProcessCompilerMsg compileOrCheckSyntax path abcpath (Patherror pathname) fileinfo project prog io
	| new	= CompileTheProjectModule True compileOrCheckSyntax Don`tClearCache path fileinfo project` prog` io`;
			= (prio`,fileinfo,project`,False,new,abcpath);
	where {
	(prio`,project`,new)	= NewPathsDialog (GetModuleName path) pathname project prog io;
	(prog`,io`)				= prio`;
	};

ProcessCompilerMsg compileOrCheckSyntax path abcpath SyntaxError fileinfo project prog io
	= ((prog, io), fileinfo, project, False, False, abcpath);
	
ProcessCompilerMsg compileOrCheckSyntax path abcpath CompilerOK fileinfo project prog io
	| compileOrCheckSyntax == SyntaxCheck
		= ((prog,io),fileinfo,project,True, False,EmptyPathname);
		= ((prog,io`),fileinfo`,project`,True, False, abcpath);
		{
			fileinfo`		= UpdateFileInfo path update fileinfo;
			mn				= GetModuleName path;
			project`		= PR_SetCompiled mn project;
			(abc,io1)	= accFiles (FModified abcpath) io;
			((sys,stack,version,abcOptions), io`)
				= accFiles (getABCInfo abcpath) io1
				where {
					getABCInfo path files
						= ((sys,stack,version,abcOptions), files`)
						where {
							(files`, sys,stack,version,abcOptions)
								= GetABCCompiledInfo abcpath files;
						}
				}
			update :: !FileInfo -> FileInfo;
			update finfo	= {finfo & abcpath=abcpath,abcdate=abc,sys=sys,seq_stack=stack,version=version,
										abcOptions = abcOptions }
		};

UpdateCompilerOptionsWithABCOptions :: CompilerOptions ABCOptions -> CompilerOptions;
UpdateCompilerOptionsWithABCOptions compilerOptions abcOptions
	=	{compilerOptions &	sa = abcOptions.abcStrictnessAnalysis,
							gw = abcOptions.abcGiveWarnings,
							bv = abcOptions.abcBeVerbose,
							gc = abcOptions.abcGenerateComments,
							reuseUniqueNodes = abcOptions.abcReuseUniqueNodes	};

UpdateAbcDate :: Pathname Pathname (List FileInfo) *Files -> (List FileInfo, *Files);
UpdateAbcDate path abcPath fileInfo files
	# (abcDate, files)
		=	FModified abcPath files;
	=	(UpdateFileInfo path (\info -> {info & abcpath=abcPath, abcdate=abcDate}) fileInfo, files);

RemoveNewlineChar :: *{#Char} -> *{#Char};
RemoveNewlineChar string
	| stringSize > 0 && string.[stringSize - 1] == '\n'
		=	string;
	// otherwise
		=	string;
		where
		{
			stringSize
				=	size string
		}

PatchSystemABC :: !Pathname !Bool !Bool !*Files -> (!Bool, !*Files);
PatchSystemABC abcPath memoryProfile timeProfile files
	# (opened, file, files)
		=	fopen abcPath FReadData files
	| not opened
		=	(False, files); // ->> abcPath +++ " not opened\n";
	# (patched, file)
		=	patchFile file;
	# (closed, files)
		=	fclose file files;
	= (patched && closed, files);
	where
	{
		patchFile :: *File -> (Bool, *File);
		patchFile file
			# (firstLine, file)
				=	readLine file
			# (patched, firstLine)
				=	patchLine (RemoveNewlineChar firstLine)
			| not patched
				=	(False, file); // ->> (abcPath +++ " not patched\n");
			# (reopened, file)
				=	freopen file FAppendText
			| not reopened
				=	(False, file); // ->> abcPath +++ " not reopened\n";

			# (sought, file)
				=	fseek file 0 FSeekSet;
			| not sought
				=	(False, file); // ->> abcPath +++ " not sought\n";
			# file
				=	fwrites firstLine file
			=	(True, file);

		patchLine :: {#Char} -> (Bool, {#Char});
		patchLine line
			| found
				/* sanity checks ...
				| abcNoMemoryProfile <> '0' && abcNoMemoryProfile <> '1'
					=	(False, line) ->> abcPath +++ " incorrect memory offset\n" 
				| abcNoTimeProfile <> '0' && abcNoTimeProfile <> '1'
					=	(False, line) ->> abcPath +++ " incorrect time offset\n" 
				| (abcNoMemoryProfile == '0') == memoryProfile && (abcNoTimeProfile == '0') == timeProfile
					=	(False, line) ->> abcPath +++ " unnecessary patch\n"
				... sanity checks */
				// otherwise
					=	(found, {copy line & [offset+NoMemoryProfileMask] = if memoryProfile '0' '1',
					                         [offset+NoTimeProfileMask] = if timeProfile '0' '1'});
			| otherwise
				=	(False, line);
			where {
				(found, offset)
					=	findOptionStringOffset line;
				abcNoMemoryProfile
					=	line.[offset+NoMemoryProfileMask];
				abcNoTimeProfile
					=	line.[offset+NoTimeProfileMask];
			}


		copy array
			=	{el \\ el <-: array};

		findOptionStringOffset :: {#Char} -> (Bool, Int);
		findOptionStringOffset string
			=	(offset+NrOfOptions < stringLength, offset);
			where
			{
				offset
					=	skipSpaces (match (toString Version) (skipSpaces (match ".comp" (skipSpaces 0))));
				stringLength
					=	size string;

				skipSpaces :: Int -> Int;
				skipSpaces offset
					| offset > stringLength || string.[offset] <> ' '
						=	offset;
					| otherwise
						=	skipSpaces (offset+1);

				match :: {#Char} Int -> Int;
				match matchString offset
					| offset + matchLength <= stringLength && string % (offset, offset+matchLength-1) == matchString
						=	offset + matchLength;
					| otherwise
						=	stringLength;
						where
						{
							matchLength
								=	size matchString;
						}
			}
	}

//	Auxiliary function used by 'BringProjectModuleUpToDate': Generate code for the designated module.

GenCodeTheProjectModule ::	!Bool !Bool !CodeGenerateAsmOrCode !Pathname !(List FileInfo) !Project !ProgState !IO
	-> (!ProgIO,!List FileInfo,!Project,!Bool,!Pathname);
GenCodeTheProjectModule outofdate sys genAsmOrCode abc_path fileinfo project prog io
	# ((prog,fileinfo1,info), io)
		=	accFiles (GetFileInfo cgo.tp abc_path fileinfo prog) io;
	| not outofdate
		=	((prog,io),fileinfo1,project,True,info.objpath);
	# (prog,io)
		=	ShowInfo True IsModal ["Generating code for '" +++ RemovePath abc_path +++ "'"] prog io;
	# ((prog, io), objpath,res)
		=	CodeGen (UpdateInfoWindow ErrorWdID) genAsmOrCode abc_path cgo ao prog io;
	| genAsmOrCode == CodeGeneration && res
		# (obj_file_date, io)
			=	accFiles (FModified objpath) io;
		=	((prog, io), UpdateFileInfo abc_path (update objpath obj_file_date) fileinfo, project`, res, objpath);
		{
			update objpath obj_file_date finfo = {finfo & objpath=objpath, objdate=obj_file_date};
		}
	// otherwise
		=	((prog, io), fileinfo1, project, res, info.objpath);
	where {
		project` | sys			= PR_SetSysCodeGenerated project;
								= PR_SetCodeGenerated mn project;
		cgo						= PR_GetCodeGenOptions project;
		ao						= PR_GetApplicationOptions project;
		mn						= GetModuleName abc_path;
	};
/*
GenCodeTheProjectModule ::	!Bool !Bool !CodeGenerateAsmOrCode !Pathname !(List FileInfo) !Project !ProgState !IO
							-> (!ProgIO,!List FileInfo,!Project,!Bool,!Pathname);
GenCodeTheProjectModule outofdate sys genAsmOrCode abc_path fileinfo project prog io
	| not outofdate
		=	((prog0,io1),fileinfo1,project,True,info.objpath);
	| genAsmOrCode == CodeGeneration && res
		=	((progb,io`),fileinfo2,project`, res,objpath);
		{
			progb			= {progc & world=world`};
			fileinfo2		= UpdateFileInfo abc_path update fileinfo1; // fileinfo;
			(progc,io`)		= prioc;
			(obj_file_date,world`) = accFiles (FModified objpath) progc.world;

			update :: !FileInfo -> FileInfo;
			update finfo = {finfo & objpath=objpath,objdate=obj_file_date};
		}
		=	(prioc, fileinfo1,project,res,info.objpath);
	where {
		((prog0,fileinfo1,info), io1	= accFiles (GetFileInfo cgo.tp abc_path fileinfo prog) io;
		(prog1,io2)				= ShowInfo True IsModal ["Generating code for '" +++ RemovePath abc_path +++ "'"] prog0 io1;
		(prioc, objpath,res)	= CodeGen (UpdateInfoWindow ErrorWdID) genAsmOrCode abc_path cgo ao prog1 io2;
		project` | sys			= PR_SetSysCodeGenerated project;
								= PR_SetCodeGenerated mn project;
		cgo						= PR_GetCodeGenOptions project;
		ao						= PR_GetApplicationOptions project;
		mn						= GetModuleName abc_path;
	};
*/

//	Brings the project up to date

MakeProject :: !Project !SetMadeProjectFun !ProgState !IO -> ProgIO;
MakeProject project setproject prog io
	=	StartIntr DInfoID maketheproject prog` io`;
	{
		(prog`,io`)	= ShowInfo True IsModal [""] prog io;
	
		maketheproject :: !Bool !ProgState !IO -> ProgIO;
		maketheproject intr prog io
			=  MakeTheProject Nil project setproject` prog io;

		setproject` :: !Bool !Bool !Bool !(List FileInfo) !(List Pathname) !Project !Bool !ProgState !IO -> ProgIO;
		setproject` ok newpaths linked fileinfo modpaths project intr prog io
			| newpaths && not intr
				# (_,io1) = ClearCompilerCache io;
				=	MakeTheProject fileinfo project setproject` prog io1;
				# (prog1,io1)	= StopIntr prog io;
				# (_,io2) = ClearCompilerCache io1;
				=	setproject linked ok project prog1 io2;
	};

MakeTheProject :: !(List FileInfo) !Project !SetLinkedProjectFun !ProgState !IO -> ProgIO;
MakeTheProject fileinfo project setproject prog io
		= CompileModules Nil root fileinfo project gencode False prog io;
	where {
		gencode :: !Bool !Bool !Bool !(List FileInfo) !(List Pathname) !Project !Bool !ProgState !IO -> ProgIO;				
		gencode ok newpaths linked fileinfo modpaths project intr prog io
			# (prog,io) = ExitCleanCompiler  prog io;
			= GenProjectModules ok newpaths False fileinfo modpaths modpaths project link intr prog io;
		
		link :: !Bool !Bool !Bool !(List FileInfo) !(List Pathname) !Project !Bool !ProgState !IO -> ProgIO;
		link ok newpaths linked fileinfo modpaths project intr prog io
			= LinkProjectModules ok newpaths False fileinfo modpaths project setproject intr prog io;
		
		root = PR_GetRootPathName project :! Nil;
	};
	
/*	Auxiliary function used by 'BringModulesUpToDate' for scanning and updating
	all modules of a project (using a scanfunction passed as parameter).
*/

CompileModules ::	!(List Pathname) !(List Pathname) !(List FileInfo) !Project !SetLinkedProjectFun !Bool !ProgState !IO
				-> ProgIO;
CompileModules done new fileinfo project cont True prog io
	= cont False False False fileinfo done project True prog io;
CompileModules done Nil 			fileinfo project cont intr prog io
	= RemoveUnreferencedModules True False False fileinfo done project cont intr prog io;
CompileModules done (new:!rest)	fileinfo project cont intr prog io
	| StringOccurs new done
		= CompileModules done rest fileinfo project cont intr prog io;
	| ok
		= ContIntr scanmods prog` io`;
		{
			scanmods :: !Bool !ProgState !IO -> ProgIO;
			scanmods intr prog io = CompileModules done` rest` fileinfo` project` cont intr prog io;
		}
		= cont ok newpaths False fileinfo` done project` intr prog` io`;
	where {
		((prog`,io`),fileinfo`,project`,ok,newpaths,rest`)
						= UpdateDependencies new rest fileinfo project prog io;
		done`			= new :! done;	
	};

//	Auxiliary function used by 'CompileModules': Scan modified modules and update the dependencies (recompile if necessary).

UpdateDependencies ::	!Pathname !(List Pathname) !(List FileInfo) !Project !ProgState !IO
						-> (!ProgIO, !List FileInfo, !Project, !Bool, !Bool, !List Pathname);
UpdateDependencies path paths fileinfo project prog io
	# (_,modinfo)	= PR_GetModuleInfo (GetModuleName path) project;
	  scanmod		= not modinfo.date.exists;
	  (prio,fileinfoa,project,found_dependent_dcls,newpathsa,pathsb) = ReadModuleDependencies scanmod path paths fileinfo project prog io;
	  (prio,fileinfo,project,scan,compile,isSystemModule,wrongVersion) = CheckABCFileOutOfDate path fileinfoa project AP2 prio;
/* RWS always recompile if some dependent dcl was not found, perhaps it is not needed any more ...
	| not found_dependent_dcls && not scan && not (isSystemModule && wrongVersion)
		= (prio,fileinfoa,project,False,newpathsa,pathsb);
*/
	# (compile, scan)
		=	if (not found_dependent_dcls)
				(True, True)
				(compile, scan);
/* ... RWS */
	| isSystemModule
		# 	(ok, fileinfo, prio)
			=	UpdateSystemModule wrongVersion compile path fileinfo project prio;
		=	(prio, fileinfo, project, ok, newpathsa, pathsb);
	# (prio2,fileinfob,projectb,ok2,newpathsb,_) = CompileTheProjectModule compile Compilation Don`tClearCache path fileinfo project AP2 prio;
	| ok2
		= ReadModuleDependencies scan path /* JVG pathsb */ paths fileinfob projectb AP2 prio2;
		= (prio2,fileinfob,projectb,ok2,newpathsb,pathsb);

UpdateSystemModule ::	Bool Bool Pathname (List FileInfo) Project (!ProgState, !IO)
						-> (!Bool, !List FileInfo, !ProgIO);
UpdateSystemModule wrongVersion compile path fileinfo project (programState, ioState)
	| wrongVersion
		#	(_, programState, ioState)
				= OpenNotice (Notice ["System file '" +++ GetModuleName path +++ "' has incorrect version number"]
		  		    	  (NoticeButton 1 "Ok") []) programState ioState;
		= (False, fileinfo, (programState,ioState));
	| compile
		# (abcPath, ioState)
			=	accFiles (MakeABCSystemPathname path) ioState;
		# (patched, ioState)
			=	accFiles (PatchSystemABC abcPath applicationOptions.memoryProfiling applicationOptions.profiling) ioState;
			with {
				applicationOptions
					=	PR_GetApplicationOptions project;
				}
		| patched
			#	(fileinfo, ioState)
					=	accFiles (UpdateAbcDate path abcPath fileinfo) ioState;
			=	(True, fileinfo, (programState, ioState));

		// otherwise
		#	(_, programState, ioState)
			=	OpenNotice (Notice ["System file '" +++ GetModuleName path +++ "' could not be patched"]
														  		    	  (NoticeButton 1 "Ok") []) programState ioState;
		= (False, fileinfo, (programState,ioState));
	// otherwise
		= (True, fileinfo, (programState,ioState));


/*	Auxiliary function for reading module dependencies out of '.dcl' and '.icl' or '.abc' files.
	Note that module dependencies are read from '.abc' files when this options is set in the project
	manager options dialog.
*/

ReadModuleDependencies ::	!Bool !Pathname !(List Pathname) !(List FileInfo) !Project !ProgState !IO
							-> (!ProgIO, !List FileInfo, !Project, !Bool, !Bool, !List Pathname);
ReadModuleDependencies scan path paths fileinfo project prog io
	# ((prog,io),fileinfo1,project1,ok,newpaths,paths`)
		= ModuleDependencies scan path paths fileinfo project prog io;
	| not ok
		= ((prog, io), fileinfo1, project1, ok, newpaths, paths`);
	| otherwise
	#	((prog,fileinfo2,project2), io)
			= accFiles (SetWindows_and_Dates scan path fileinfo1 project1 prog) io;
		= ((prog,io), fileinfo2, project2, True, False, paths`);

/*	Auxiliary function used by 'ReadModuleDependencies' for reading module dependencies out of
	'.dcl' and '.icl' or '.abc' files.
*/

ModuleDependencies ::	!Bool !Pathname !(List Pathname) !(List FileInfo) !Project !ProgState !IO
						-> (!ProgIO,!List FileInfo,!Project,!Bool,!Bool,!List Pathname);
ModuleDependencies scanmod path paths fileinfo project prog io
	| not scanmod
		= GetPaths modinfo.deps path fileinfo project prog io paths;
	#	(prog,io)	= ShowInfo verbose IsModal line prog io;
					with {
						line | verbose	= ["Scanning \'" +++  modname +++ ".abc\'"];
										= [];
						verbose			= (PR_GetProjectOptions project).ProjectOptions.verbose;
					};
	#	((prog,fileinfo1,info),io)	= accFiles (GetFileInfo tp path fileinfo prog) io;
	#	((ok,mods,linkObjFileNames,linkLibraryNames),io) = accFiles (ParseABCDependencies info.abcpath) io;
	| not ok
		= ((prog,io), fileinfo1, project, True, False, paths);
	#	((prog, io),fileinfo2,project1,get_paths_ok,newpaths,mods1)
								= GetPaths mods path fileinfo1 project prog io Nil;
		paths1					= Concat mods1 paths;
	| not get_paths_ok
		= ((prog, io),fileinfo2,project1,get_paths_ok,newpaths,paths1);
	// otherwise
		#	project2 = PR_AddABCLinkInfo path linkObjFileNames linkLibraryNames (PR_AddNewDependencies path mods1 project1);
		= ((prog, io),fileinfo2,project2,get_paths_ok,newpaths,paths1);
	where {
		modname					= GetModuleName path;
		(_,modinfo)				= PR_GetModuleInfo modname project;
		tp						= PR_GetProcessor project;
	};

/*	Auxiliary function used by 'ReadModuleDependencies' to register open	definition and implementation
	windows in the project and to set the scan dates of the .dcl and .icl modules.
*/
	
SetWindows_and_Dates :: !Bool !Pathname !(List FileInfo) !Project !ProgState !Files
						-> ((!ProgState, !List FileInfo, !Project), Files);
SetWindows_and_Dates scan path fileinfo project prog files
	| not scan
		= ((prog,fileinfo,project), files);
	// otherwise
		= (setwindows prog` fileinfo` project, files`);
	where {
	((prog`,fileinfo`,info), files`)	= GetFileInfo tp path fileinfo prog files;
	tp						= PR_GetProcessor project;
	
	setwindows ::	!ProgState !(List FileInfo) !Project
					-> (!ProgState, !List FileInfo, !Project);
	setwindows prog=:{editor=ed=:{editwindows}} fileinfo project
		= (prog`, fileinfo, project`);
	where {
	prog`			= {prog & editor={ed & editwindows=editwindows`}};
	project`		= PR_UpdateModule mn update project;
	(existsdef,id1)	= IsExistingPathname defpath editwindows;
	(existsimp,id2)	= IsExistingPathname path editwindows;
	defwd			= GetWindow id1 editwindows;
	impwd			= GetWindow id2 editwindows;
	editwindows`	= SetWindow id2 impwd` editwindows;
	mn				= GetModuleName path;
	defpath			= MakeDefPathname path;
	defeo`			= EW_GetEditOptions defwd;
	impeo`			= EW_GetEditOptions impwd;
	impwd`			= {impwd & wstate = {WinState | impwd.wstate & co = co`}};
	co`				= UpdateCompilerOptionsWithABCOptions compilerOptions info.abcOptions;
	compilerOptions	= impwd.wstate.WinState.co;

	update :: !ModInfo -> ModInfo;
	update minfo=:{ModInfo | date={exists},compilerOptions=c,defeo,impeo}
		= { ModInfo | minfo &
			defeo	= if existsdef {defeo & eo = defeo`} defeo,
			impeo	= if existsimp {defeo & eo = impeo`} impeo,
			compilerOptions
					= if exists c (UpdateCompilerOptionsWithABCOptions c info.abcOptions),
			defopen	= existsdef,
			impopen	= existsimp,
			date 	= info.abcdate }; };

	};

//	Auxiliary function used by 'UpdateDependencies' which checks whether source files in the project are out of date.

CheckABCFileOutOfDate ::	!Pathname !(List FileInfo) !Project !ProgState !IO -> (!ProgIO, !List FileInfo,!Project, !Bool,!Bool,!Bool,!Bool);
CheckABCFileOutOfDate path fileinfo project prog io
	= (ShowInfo verbose IsModal lines prog` io`,fileinfo`,project`,scanabc,compile,sys,wrong_version);
	where {
	project`		| c_opt && sys && not wrong_version
					= PR_SetCompiled mn project;
					= project;
	verbose			= (PR_GetProjectOptions project).ProjectOptions.verbose;
	compile			= if sys patchSystemModule compileIclModule;
					  where {
					  	compileIclModule
							= dcl || icl || imports  || c_opt || options || stack || wrong_version || not abcexists;
						patchSystemModule
							= projectMemoryProfiling <> info.abcOptions.abcMemoryProfile || projectTimeProfiling <>  info.abcOptions.abcTimeProfile;
						}
	scanabc			= not modinfo.date.exists || compile || (abcexists && Older_Date modinfo.date info.abcdate);
	abcexists		= info.abcdate.exists;
	objexists		= info.objdate.exists;
	abc_obj_date | abcexists
					= info.abcdate;
					= info.objdate;
	tp				= PR_GetProcessor project;
	projectTimeProfiling = (PR_GetApplicationOptions project).profiling;
	projectMemoryProfiling = (PR_GetApplicationOptions project).memoryProfiling;
	((prog`,fileinfo`,younger_import), io`) = f;
	f	| /* JVG: imports is only used when !(dcl || icl) */ dcl || icl || /**/ not abc_obj_date.exists
			=	((prog1,fileinfo1,False), io1);
		// otherwise
			=	accFiles (YoungerImportedDcl tp getpath fileinfo1 modinfo.deps abc_obj_date prog1) io1;

	((prog1,fileinfo1,info), io1)
					= accFiles (GetFileInfo tp (MakeImpPathname path) fileinfo prog) io;

	dcl				= info.dcldate.exists && (not abc_obj_date.exists || Older_Date abc_obj_date info.dcldate);
	icl				= info.icldate.exists && (not abc_obj_date.exists || Older_Date abc_obj_date info.icldate);
	imports			= not abc_obj_date.exists || younger_import;
	
	c_opt			= not (PR_SrcUpToDate mn project);
	(_,modinfo)		= PR_GetModuleInfo mn project;
	mn				= GetModuleName path;

	stack			= abcexists && not info.seq_stack;
	sys				= abcexists && info.sys;
	wrong_version	= abcexists && info.version <> Version;
	options			= abcexists && NECompilerOptions projectMemoryProfiling projectTimeProfiling modinfo.compilerOptions info.abcOptions && modinfo.ModInfo.date.exists;

	getpath :: !Modulename -> Pathname;
	getpath mn
		| size dir>0
			= MakeFullPathname dir (MakeImpPathname mn);
			= "";
		where {
			dir=modinfo.dir;
		 	(_,modinfo)	= PR_GetModuleInfo mn project;
		 };
		
	lines | verbose	= MakeSourceOutOfDateMessage mn dcl icl imports abcexists objexists c_opt
													sys stack options wrong_version;
					= [];
	};

/*	Auxiliary function used by 'DoRebuild' and 'MakeTheProject': Remove all modules not (indirectly)
	imported by the main module
*/

RemoveUnreferencedModules :: !Bool !Bool !Bool !(List FileInfo) !(List Pathname) !Project !SetLinkedProjectFun !Bool !ProgState !IO -> ProgIO;				
RemoveUnreferencedModules ok newpaths linked fileinfo modpaths project setproject intr prog io
	| no_remove
		=	setproject (ok && not intr) newpaths False fileinfo modpaths` project` intr prog io;
		= 	setproject ok newpaths False fileinfo modpaths` project` intr prog io;
	where {
		project` | no_remove	= project;
								= PR_SetBuilt project;
		built					= PR_Built project;
		modpaths` | no_remove	= modpaths;
								= PR_GetModulenames True IclMod project`;
		no_remove				= built || not ok || intr;
	};

/*	Auxiliary function used by 'MakeProject': Check whether executable is out of date and relink it	if required. */

LinkProjectModules ::	!Bool !Bool !Bool !(List FileInfo) !(List Pathname) !Project !SetLinkedProjectFun !Bool !ProgState !IO -> ProgIO;
LinkProjectModules ok newpaths linked fileinfo modpaths project setproject intr prog=:{editor={defaults={paths=defpaths}}} io
	| intr || not ok
		= setproject False newpaths False fileinfo modpaths project intr prog io;
	# ((systemFound,full_sys),io)	= accFiles (SearchABCFile System defpaths) io;
	| not systemFound
		# (_,prog,io) = OpenNotice (Notice ["The StdEnv directory was not found in the default paths"] (NoticeButton 1 "Ok") []) prog io;
		= setproject False newpaths False fileinfo modpaths project intr prog io;
	# full_system_path_name = MakeImpPathname full_sys;
	  (patch_abc_file,genabc,abcpath,fileinfo1_,prio) = CheckSystemObjectFileOutOfDate full_system_path_name fileinfo project prog io;
	  (patch_ok,fileinfo1,(prog,io)) = UpdateSystemModule False patch_abc_file abcpath fileinfo1_ project prio;
	| not patch_ok
		= setproject False newpaths False fileinfo1 modpaths project intr prog io;
	# ((prog,io),fileinfo2,project1,ok3,system_obj_path) = GenCodeTheProjectModule genabc True CodeGeneration abcpath fileinfo1 project prog io;
	| not ok3
		= setproject ok3 newpaths False fileinfo2 modpaths project intr prog io;
	# execpath				= MakeExecPathname (PR_GetRootPathName project);
	  ((prog,io),link)		= CheckExecOutOfDate (linked || genabc) execpath fileinfo2 project1 prog io;
	  objpaths					= GetObjPaths system_obj_path fileinfo2;
	  ((prog,io),project`,ok5)	= LinkModules link execpath system_obj_path objpaths project1 prog io;
	= setproject ok5 False (link && ok5) fileinfo2 modpaths project` intr prog io;

CheckExecOutOfDate ::	!Bool !Pathname !(List FileInfo) !Project !ProgState !IO
						-> (!ProgIO, !Bool);
CheckExecOutOfDate gen execpath fileinfo project prog io
	| gen	= ((prog,io),True);
	| a_opt
		= (ShowInfo verbose IsModal linesa prog io,True);
		{
			linesa | verbose= MakeExecOutOfDateMessage (RemovePath execpath) True True a_opt;
							= [];
		}
		= (ShowInfo verbose IsModal linesb prog io1,link);
		{
			linesb | verbose= MakeExecOutOfDateMessage (RemovePath execpath) link date.exists a_opt;
							= [];
		}
	where {
	link			= youngest.exists && (not date.exists || Older_Date date youngest);
	a_opt			= not (PR_ExecUpToDate project);
	(date, io1)		= accFiles (FModified execpath) io;
	youngest		= YoungestObj NoDate fileinfo;
	verbose			= (PR_GetProjectOptions project).ProjectOptions.verbose;
	};

/*	Auxilary function used by 'LinkProjectModules': Links the project modules and updates the info
	windows.
*/

/* MW was:
	LinkModules	:: !Bool !Pathname !Pathname !(List Pathname) !Project !ProgState !IO -> (!ProgIO, !Project, !Bool);
	LinkModules outofdate execpath sys_obj paths project prog=:{editor={defaults={paths=defpaths}}} io
		| not outofdate		= ((prog, io),project,True);
		| res				= (prio`, PR_SetLinked project,res);
							= (prio`, project, res);
		where {
		(prio`, res)		= Link (UpdateInfoWindow ErrorWdID) execpath sys_obj paths defpaths ao (PR_GetProcessor project) (PR_GetLinkOptions project) prog1 io1;
		(prog1,io1)			= ShowInfo True IsModal line prog io;
		ao					= PR_GetApplicationOptions project;
		line				= ["Linking '" +++ RemovePath execpath +++ "'"];
		};
*/

LinkModules	:: !Bool !Pathname !Pathname !(List Pathname) !Project !ProgState !IO -> (!ProgIO, !Project, !Bool);
LinkModules outofdate execpath sys_obj paths project prog=:{editor={defaults={paths=defpaths}}} io
	|	not outofdate
		= ((prog, io),project,True);
	#	abcLinkInfo			= PR_GetABCLinkInfo project;
		abcLinkPathsCache	= PR_GetABCLinkPathsCache project;
		projectPaths		= PR_GetPaths project;
		((allObjFilesFound,objFilePathNames,abcLinkPathsCache),io)
							= accFiles (GetPathNames abcLinkInfo.linkObjFileNames Nil
													abcLinkPathsCache defpaths projectPaths) io;
		((allLibrariesFound,libraryPathNames,abcLinkPathsCache),io)
							= accFiles (GetPathNames abcLinkInfo.linkLibraryNames Nil
													abcLinkPathsCache defpaths projectPaths) io;
		abcLinkPathsCache	= removeUnusedEntries abcLinkInfo abcLinkPathsCache;
	|	not allObjFilesFound || not allLibrariesFound
		# (prog,io)		= warning (if (not allObjFilesFound) (Head objFilePathNames) (Head libraryPathNames))
									prog io;
		= ((prog, io), PR_SetABCLinkPathsCache [] project, False);
	#	line				= ["Linking '" +++ RemovePath execpath +++ "'"];
		(prog,io)			= ShowInfo True IsModal line prog io;
		ao					= PR_GetApplicationOptions project;
		((prog,io), res)	= Link	(UpdateInfoWindow ErrorWdID) execpath sys_obj paths defpaths ao 
									(PR_GetProcessor project) (PR_GetLinkOptions project)
									objFilePathNames libraryPathNames prog io;
	| res				= ((prog,io), PR_SetLinked (PR_SetABCLinkPathsCache abcLinkPathsCache project),res);
						= ((prog,io), PR_SetABCLinkPathsCache [] project, res);
	where {
		warning name_of_missing_file prog io
			# (_,prog,io)	= OpenNotice (Notice [	"Can't link: The object file \""
													 +++name_of_missing_file+++"\"was not found in the path.",
													"The CleanIDE searches only in the \"Clean System Files\" subfolders in",
													"the project and default paths."]
												 (NoticeButton 0 "Ok") []) prog io;
			= (prog, io);
	};

// MW..
// iff the returned Bool is True, all filenames were found in the path and the list contains the paths.
// otherwise the list contains one element: the first filename which was not found.
// The returned ABCLinkPathsCache will be updated, when a path is found via SearchDisk
GetPathNames	::	!(List Filename) !(List Pathname)
					!ABCLinkPathsCache !(List Pathname) !(List Pathname) !*Files
				->	(!(!Bool, !List Pathname, !ABCLinkPathsCache), !*Files);
GetPathNames Nil akku abcLinkPathsCache _ _ disk
	= ((True, akku, abcLinkPathsCache), disk);
GetPathNames (fileName :! fileNames) akku abcLinkPathsCache defdirs projectDirs disk
	// first check, whether the path exists in the ABCLinkPathsCache
	#	fileNameCSF			= "Clean System Files"+++DirSeparatorString+++fileName;
		firstPathMatches	= dropWhile (\pathInCache -> (RemovePath pathInCache)<>fileName) abcLinkPathsCache;
	|	not (isEmpty firstPathMatches)	// the path is in the cache
		= GetPathNames fileNames (hd firstPathMatches:!akku) abcLinkPathsCache defdirs projectDirs disk;
	// otherwise search it in the default and project paths
	#	((found, pathname), disk)	= SearchDisk False fileNameCSF defdirs projectDirs disk;
	|	found
		= GetPathNames fileNames (pathname:!akku) [pathname:abcLinkPathsCache] defdirs projectDirs disk;
	= ((False, fileNameCSF:!Nil, abcLinkPathsCache), disk);
 
//	This function removes items from the ABCLinkPathsCache, which are not in the project anymore
removeUnusedEntries	::	!ABCLinkInfo !ABCLinkPathsCache -> ABCLinkPathsCache;
removeUnusedEntries {linkObjFileNames,linkLibraryNames} abcLinkPathsCache 
	= filter used abcLinkPathsCache;
	where {
	used pathname
		#	filenameInCache	= RemovePath pathname;
		= isMember filenameInCache linkObjFileNames` || isMember filenameInCache linkLibraryNames`;
	linkObjFileNames`	= StrictListToList linkObjFileNames;
	linkLibraryNames`	= StrictListToList linkLibraryNames;
	};
// ..MW

//	Auxiliary function used by 'GenCodeProjectModules' which checks whether .abc files in the project are out of date.

CheckObjectFileOutOfDate :: !Pathname !(List FileInfo) !Project !ProgState !IO -> (!ProgIO, !List FileInfo,!Bool,!Pathname);
CheckObjectFileOutOfDate path fileinfo project prog io
	= (ShowInfo verbose IsModal lines prog` io`, fileinfo`,gencode,modinfo.abcpath);
	where {
		verbose			= (PR_GetProjectOptions project).ProjectOptions.verbose;
		gencode			= cg_opt || abc;
		((prog`,fileinfo`,modinfo), io`)
					= accFiles (GetFileInfo tp path fileinfo prog) io;
		abcexists		= modinfo.abcdate.exists;
		objexists		= modinfo.objdate.exists; 
		abc				= abcexists && (Older_Date modinfo.objdate modinfo.abcdate || not objexists);
		cg_opt = not (PR_ABCUpToDate mn project);
		tp				= PR_GetProcessor project;
		mn				= GetModuleName path;
		lines | verbose	= MakeABCOutOfDateMessage mn abc abcexists objexists cg_opt;
						= [];
	};

CheckSystemObjectFileOutOfDate :: !Pathname !(List FileInfo) !Project !ProgState !IO -> (!Bool,!Bool,!Pathname,!List FileInfo,!ProgIO);
CheckSystemObjectFileOutOfDate path fileinfo project prog io
	= (patch_abc_file,gencode,modinfo.abcpath, fileinfo`,ShowInfo verbose IsModal lines prog` io`);
	where {
		((prog`,fileinfo`,modinfo), io`) = accFiles (GetFileInfo (PR_GetProcessor project) path fileinfo prog) io;

		({profiling,memoryProfiling}) = PR_GetApplicationOptions project;
		patch_abc_file = memoryProfiling<>modinfo.abcOptions.abcMemoryProfile || profiling<> modinfo.abcOptions.abcTimeProfile;

		abcexists		= modinfo.abcdate.exists;
		objexists		= modinfo.objdate.exists; 
		abc				= abcexists && (Older_Date modinfo.objdate modinfo.abcdate || not objexists);
		cg_opt			= not (PR_SysUptoDate project);

		gencode		= cg_opt || abc || patch_abc_file;

		mn				= GetModuleName path;
		verbose			= (PR_GetProjectOptions project).ProjectOptions.verbose;
		lines
			| verbose
				= MakeABCOutOfDateMessage mn abc abcexists objexists cg_opt;
				= [];
	};
	
/*	Auxiliary function used by 'CheckModuleOutOfDate' which compares compiler options for the root
	module and compiler options read from the old .abc file.
*/

NECompilerOptions :: !Bool !Bool !CompilerOptions !ABCOptions -> Bool;
NECompilerOptions projectMemoryProfile projectProfile moduleInfo abcInfo
	= (((projectMemoryProfile && not moduleInfo.neverMemoryProfile) <> abcInfo.abcMemoryProfile) ||
			((projectProfile && not moduleInfo.neverTimeProfile) <> abcInfo.abcTimeProfile)
			|| moduleInfo.sa <> abcInfo.abcStrictnessAnalysis || moduleInfo.gc <> abcInfo.abcGenerateComments
			|| moduleInfo.reuseUniqueNodes <> abcInfo.abcReuseUniqueNodes);

//	Auxiliary function used by 'CheckModuleOutOfDate' which finds the most recently modified imported .dcl file.

::	PathFun	:== Pathname -> Pathname;

YoungerImportedDcl :: !Processor !PathFun !(List FileInfo) !(List Pathname) !DATE !ProgState !Files
					-> ((!ProgState,!List FileInfo,!Bool), Files);
YoungerImportedDcl tp getpath_function fileinfo Nil abc_obj_date prog files
	= ((prog,fileinfo,False), files);
YoungerImportedDcl tp getpath_function fileinfo (path:!rest) abc_obj_date prog files
	# getpath = getpath_function path;
	| size getpath==0
		= YoungerImportedDcl tp getpath_function fileinfo rest abc_obj_date prog files;
	# ((prog,fileinfo,info),files) = GetFileInfo tp getpath fileinfo prog files;
	| info.dcldate.exists && Older_Date abc_obj_date info.dcldate
		= ((prog,fileinfo,True), files);
		= YoungerImportedDcl tp getpath_function fileinfo rest abc_obj_date prog files;

//	Auxiliary function used by 'CheckExecOutOfDate' which finds the most recently modified .obj file.

YoungestObj :: !DATE !(List FileInfo) -> DATE;
YoungestObj youngest Nil = youngest;
YoungestObj youngest ({objdate}:!rest)
	= YoungestObj youngest` rest;
	where {
	youngest`	| not youngest.exists			= objdate;
				| not objdate.exists			= youngest;
				| Older_Date youngest objdate	= objdate;
												= youngest;
	};

GetFileInfo tp path fileinfo prog
	:== GetFileInfo1 tp path fileinfo fileinfo prog;

GetFileInfo1 ::	!Processor !Pathname !(List FileInfo) !(List FileInfo) !ProgState !Files
				-> ((!ProgState, !List FileInfo, !FileInfo), Files);
GetFileInfo1 tp this_path fileinfo=:((info=:{path,abcpath,objpath}):!rest) acc prog files
	| this_path==path || this_path==abcpath || this_path==objpath
		= ((prog, acc, info), files);
		= GetFileInfo1 tp this_path rest acc prog files;
GetFileInfo1 tp path Nil acc prog files
	#	(abcpath, files)	= MakeABCSystemPathname path files;
	#	(objpath, files)	= MakeObjSystemPathname tp path files;
	#	(dcldate, files)	= FModified dclpath files;
	#	(icldate, files)	= FModified iclpath files;
	#	(abcdate, files)	= FModified abcpath files;
	#	(objdate, files)	= FModified objpath files;
	| not abcdate.exists
		= ((prog, finfo:!acc, finfo), files);
		{
			finfo	= { path		= iclpath,
						abcpath		= abcpath,	objpath		= objpath,
						dcldate		= dcldate,	icldate		= icldate,
						abcdate		= abcdate,	objdate		= objdate,
						sys			= False,	seq_stack	= False,
						version		= -1,		abcOptions	= DefaultABCOptions };
		}
	// otherwise
		#	(files, sys,seq_stack,version,abcOptions)
								= GetABCCompiledInfo abcpath files;
			finfo	= { path		= iclpath,
						abcpath		= abcpath,	objpath		= objpath,
						dcldate		= dcldate,	icldate		= icldate,
						abcdate		= abcdate,	objdate		= objdate,
						sys			= sys,		seq_stack	= seq_stack,
						version		= version,	abcOptions	= abcOptions };
		= ((prog, finfo:!acc, finfo), files);
	where
	{
		dclpath					= MakeDefPathname path;
		iclpath					= MakeImpPathname path;
	}

//	GetObjPaths :: !String !(List FileInfo) -> !List PathName;
	GetObjPaths sys_obj fileinfo :== GetObjPaths1 sys_obj fileinfo Nil;

GetObjPaths1 :: !Pathname !(List FileInfo) !(List Pathname) -> List Pathname;
GetObjPaths1 sys_obj Nil paths
	= paths;
GetObjPaths1 sys_obj ({objpath}:!rest) paths
	| sys_obj == objpath
		= GetObjPaths1 sys_obj rest paths;
		= GetObjPaths1 sys_obj rest (objpath:!paths);

//	UpdateFileInfo :: !Pathname (FileInfo -> FileInfo) !(List FileInfo) -> List FileInfo;
	UpdateFileInfo key update list :== UpdateFileInfo1 key update list Nil;

UpdateFileInfo1 :: !Pathname (FileInfo -> FileInfo) !(List FileInfo) !(List FileInfo) -> List FileInfo;
UpdateFileInfo1 key update_function Nil acc
	= acc;
UpdateFileInfo1 key update_function ((first=:{path,abcpath,objpath}):!rest) acc
	| key == path || key == abcpath || key == objpath
		= Reverse2 (update_function first:!rest) acc;
		= UpdateFileInfo1 key update_function rest (first:!acc);
						
/*	Auxiliary function used by 'ReadModuleDependencies' to create the full pathnames out of the
	module names read from the '.dcl', '.icl' and '.abc' files.
*/

GetPaths ::	!(List Modulename) !Pathname !(List FileInfo) !Project !ProgState !IO !(List Pathname)
			-> (!ProgIO, !List FileInfo, !Project, !Bool, !Bool, !List Pathname);
GetPaths Nil path fileinfo project prog io modpaths
	=  ((prog,io), fileinfo, project, True, False, modpaths);
GetPaths (modname:!modnames) path fileinfo project prog=:{editor={defaults={paths=defpaths}}} io modpaths
	| StringOccurs dir defpaths || StringOccurs dir prjpaths
		= GetPaths modnames path fileinfo project prog io (InclString (MakeFullPathname dir iclmodname) modpaths);
/* RWS, never ask where the dcl file is, it may not be needed any more ...
	| ondisk
		= GetPaths modnames path fileinfo project prog1 io (InclString modpathb modpaths);
		= (prio2, fileinfo, project1, False, newpaths, modpaths);
		{
			(prio2,project1,newpaths)	= NewPathsDialog (GetModuleName path) iclmodname project prog1 io;
		}
*/
	| ondisk
		= GetPaths modnames path fileinfo project prog io1 (InclString modpathb modpaths);
	// otherwise
		= GetPaths modnames path fileinfo project prog io1 modpaths;
/* ... RWS */
	where {
		dir						= modinfo.dir;
		(_,modinfo)				= PR_GetModuleInfo modname project;
		prjpaths				= PR_GetPaths project;
		iclmodname				= MakeImpPathname modname;
		((ondisk,modpathb),io1)	= accFiles (SearchDisk True iclmodname defpaths prjpaths) io;
	};

/* Misc. functions */

InclString :: !String !(List String) -> List String;
InclString new strs | StringOccurs new strs	= strs;
											= new:!strs;

