/*
	File:		clm.c
	Written by: John van Groningen
	At:			Radboud University Nijmegen
*/

#define CLM_VERSION "2.4"

#define VERSION 920

#if !defined (SYSTEM_LINKER) && !defined (MACH_O64)
# define OPTIMISE_LINK
#endif

#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n)

#ifdef OS2
# define OMF
# define NO_CLIB
#endif

#if defined (_WINDOWS_)
# undef USE_WLINK
# define USE_CLEANLINKER
# define NO_CLIB
#endif

#if (defined (_WINDOWS_) || defined (OMF) || defined (LINUX) || defined (SOLARIS)) && !defined (MACH_O64)
# define NO_ASSEMBLE
#endif

#define MARKING_GC

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#if defined(I486) || defined (SOLARIS) || defined (LINUX)
#	include <unistd.h>
#endif

#include <signal.h>

#ifdef A_64
# include <stdint.h>
# define Int32 int32_t
#else
# define Int32 long
#endif

#if defined (applec) || defined (__MWERKS__)
#	define MACINTOSH 1
#	if __MWERKS__
#		define POWER
#	endif
#else
#	define MACINTOSH 0
#endif

#if MACINTOSH
#	include <Files.h>
#	include <Strings.h>
#	ifdef applec
#		include <FCntl.h>
#	endif
#	define USE_PATH_CACHE 1
#else
# if !(defined (_WINDOWS_) || defined (OS2))
#	include <sys/file.h>
#	include <sys/types.h>
#	include <sys/wait.h>
# endif
# ifdef OS2
#	include <sys/types.h>
# endif
#	include <sys/stat.h>
#	define USE_PATH_CACHE 0
#endif

#if USE_PATH_CACHE
#	include "path_cache.h"
#endif

#ifdef _WINDOWS_
# ifdef __MWERKS__
#  include <x86_prefix.h>
# else
#  ifndef GNU_C
#   define _X86_
#  endif
#  include <stdarg.h>
# endif
# ifdef GNU_C
#  include <windows.h>
# else
#  include <windef.h>
#  include <winbase.h>
# endif
# include <process.h>
#endif

#ifdef OS2
# define INCL_ERRORS
# define INCL_DOSFILEMGR
# define INCL_DOSPROCESS
# include <os2.h>
#endif

#if !MACINTOSH
 extern char *getenv();
#endif

#define PATH_NAME_STRING_SIZE 256
#define PATH_LIST_STRING_SIZE 1024

/* file and directory names which may be patched using patchbin */
#if defined (I486) && !defined (LINUX)
#  ifdef OS2
	char clean_lib_directory[PATH_NAME_STRING_SIZE] = "\\clean\\lib";
	char gcc_lib_directory[PATH_NAME_STRING_SIZE] = "\\emx\\lib";
	char assembler_file_name[PATH_NAME_STRING_SIZE] = "as.exe";
#	ifdef OMF
	char linker_file_name[PATH_NAME_STRING_SIZE] = "link386.exe";
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "crt0.obj";
#	else
	char gcc_lib_directory_arg[PATH_NAME_STRING_SIZE+2];
	char linker_file_name[PATH_NAME_STRING_SIZE] = "ld.exe";
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "crt0.o";
#	endif
#  else
#   ifdef _WINDOWS_
	char clean_lib_directory[PATH_NAME_STRING_SIZE] = "d:\\john";
	char assembler_file_name[PATH_NAME_STRING_SIZE] = "as.exe";
#	 ifndef USE_WLINK
#     ifdef USE_CLEANLINKER
	char linker_file_name[PATH_NAME_STRING_SIZE] = "linker.exe";
#     else
	char linker_file_name[PATH_NAME_STRING_SIZE] = "ld.exe";
#     endif
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "c:\\gnu\\lib\\crt0.o";
#	 else
	char linker_file_name[PATH_NAME_STRING_SIZE] = "wlink";
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "crt0.o";
#	 endif
#   else
	char clean_lib_directory[PATH_NAME_STRING_SIZE] = "/usr/scratch/johnvg/clean";
	char assembler_file_name[PATH_NAME_STRING_SIZE] = "/usr/bin/as";
	char linker_file_name[PATH_NAME_STRING_SIZE] = "/usr/bin/ld";
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "/usr/lib/crt0.o";
#   endif
#  endif
#else
#  if defined (SOLARIS) || defined (LINUX)
	char _clean_lib_directory[PATH_NAME_STRING_SIZE] = "#$@CLEANLIB  %*&.";
	char _clean_directory_list[PATH_LIST_STRING_SIZE]= "#$@CLEANPATH %*&.";
	char _clean_include_library_directory[PATH_NAME_STRING_SIZE] = "#$@CLEANILIB %*&.";
#   ifdef SOLARIS
    char _assembler_file_name[PATH_NAME_STRING_SIZE] = "#$@ASSEMBLER %*&/usr/ccs/bin/as";
    char _linker_file_name[PATH_NAME_STRING_SIZE]    = "#$@LINKER    %*&/usr/ccs/bin/ld";
#   else
    char _assembler_file_name[PATH_NAME_STRING_SIZE] = "#$@ASSEMBLER %*&/usr/bin/as";
    char _linker_file_name[PATH_NAME_STRING_SIZE]    = "#$@LINKER    %*&/usr/bin/gcc";
#   endif
    char _crt0_file_name [PATH_NAME_STRING_SIZE]     = "#$@CRT       %*&crt1.o";
	char _ld_args [PATH_LIST_STRING_SIZE]            = "#$@LDARGS    %*&";
/* 	char _ld_args [PATH_LIST_STRING_SIZE]			 = "#$@LDARGS    %*& --dynamic /lib/ld-linux.so.1"; */
#	define clean_lib_directory (&_clean_lib_directory[16])
#	define clean_directory_list (&_clean_directory_list[16])
#	define clean_include_library_directory (&_clean_include_library_directory[16])
#   define assembler_file_name (&_assembler_file_name[16])
#   define linker_file_name (&_linker_file_name[16])
#   define crt0_file_name (&_crt0_file_name[16])
#   define ld_args (&_ld_args[16])
#  else
	char clean_lib_directory[PATH_NAME_STRING_SIZE] = ".";
	char assembler_file_name[PATH_NAME_STRING_SIZE] = "/bin/as";
	char linker_file_name[PATH_NAME_STRING_SIZE] = "/bin/ld";
	char crt0_file_name [PATH_NAME_STRING_SIZE] = "/lib/crt0.o";
#  endif
#endif

#ifdef M68000
char Mcrt1_file_name [PATH_NAME_STRING_SIZE] = "/lib/Mcrt1.o";
#endif

/* default options of cocl */

#define DEFAULT_WARNING 				1
#define DEFAULT_NO_REUSE_UNIQUE_NODES	1
#define DEFAULT_VERBOSE 				0
#define DEFAULT_DEBUG					0
#define DEFAULT_NO_TIME_PROFILE			1
#define DEFAULT_STRICTNESS_ANALYSIS 	1
#define DEFAULT_LIST_TYPES				0
#define DEFAULT_LIST_ALL_TYPES			0

#define DEBUG_MASK					1
#define NO_REUSE_UNIQUE_NODES_MASK	2
#define PARALLEL_MASK				4
#define STACK_LAYOUT_MASK			8
#define STRICTNESS_ANALYSIS_MASK	16
#define NO_TIME_PROFILE_MASK 		32
#define VERBOSE_MASK				64
#define WARNING_MASK				128
#define SYSTEM_MASK 				256
#define FUSION_MASK					512
#define A64_MASK					1024

#define LIST_TYPES_MASK 			2048
#define LIST_ALL_TYPES_MASK 		4096

#define MEMORY_PROFILE				8192
 
#define DEFAULT_OPTIONS \
	(DEFAULT_WARNING ? WARNING_MASK : 0)\
	| (DEFAULT_NO_REUSE_UNIQUE_NODES ? NO_REUSE_UNIQUE_NODES_MASK : 0)\
	| (DEFAULT_VERBOSE ? VERBOSE_MASK : 0)\
	| (DEFAULT_DEBUG ? DEBUG_MASK : 0)\
	| (DEFAULT_NO_TIME_PROFILE ? NO_TIME_PROFILE_MASK : 0)\
	| (DEFAULT_STRICTNESS_ANALYSIS ? STRICTNESS_ANALYSIS_MASK : 0)\
	| (DEFAULT_LIST_TYPES ? LIST_TYPES_MASK : 0)\
	| (DEFAULT_LIST_ALL_TYPES ? LIST_ALL_TYPES_MASK : 0)

static int clean_options=DEFAULT_OPTIONS;	
static int clean_options_mask=0;
static int remove_symbol_table;
static int	list_strict_export_types=0,funcmayfail_error=0,varnotused_error=0,funcnotused_error=0,
			nowarn=0,progress=0;

static char *cocl_redirect_stdout,*cocl_redirect_stdout_option;
static char *cocl_redirect_stderr,*cocl_redirect_stderr_option;

static int check_stack_overflow,check_indices,dynamics;

#ifdef OS2
static int window_application;
#endif

#ifdef _WINDOWS_
	typedef FILETIME FileTime;
#	define FILE_TIME_LE(t1,t2) ((unsigned)(t1.dwHighDateTime)<(unsigned)(t2.dwHighDateTime) \
		|| (t1.dwHighDateTime==t2.dwHighDateTime && (unsigned)(t1.dwLowDateTime)<=(unsigned)(t2.dwLowDateTime)))
#else
	typedef unsigned long FileTime;
#	define FILE_TIME_LE(t1,t2) (t1<=t2)
#endif

typedef struct project_node {
	struct project_node *		pro_next;
	char *						pro_fname;
	struct dep_list *			pro_depend;
	int 						pro_options;
	FileTime					pro_abc_time;
	FileTime					pro_dcl_time;
	unsigned int				pro_up_to_date:1,
								pro_valid_abc_time:1,
								pro_valid_dcl_time:1,
								pro_no_abc_file:1,
								pro_no_dcl_file:1,
								pro_valid_options:1,
								pro_ignore_o:1;
	struct object_file_list *	pro_imported_object_files;
} *P_NODE;

typedef struct dep_list {
	struct dep_list *		dep_next;
	P_NODE					dep_node;
} *DEP_LIST;

P_NODE first_project_node,last_project_node,main_project_node;

struct object_file_list {
	struct object_file_list *	object_file_next;
#if !defined (GNU_C)
	char						object_file_name[];
#else
	char						object_file_name[1];
#endif
};

struct library_list {
	struct library_list *	library_next;
#if !defined (GNU_C)
	char					library_file_name[];
#else
	char					library_file_name[1];
#endif
};

static struct library_list *first_library,*last_library;

struct export_list {
	struct export_list *	export_next;
#if !defined (GNU_C)
	char					export_name[];
#else
	char					export_name[1];
#endif
};

static struct export_list *first_export,*last_export;

struct export_file_list {
	struct export_file_list*export_file_next;
#if !defined (GNU_C)
	char					export_file_name[];
#else
	char					export_file_name[1];
#endif
};

static struct export_file_list *first_export_file,*last_export_file;

static void warning_s (char *warning_string,char *s)
{
	fprintf (stderr,warning_string,s);
	fputc ('\n',stderr);
}

static void warning_s_s (char *warning_string,char *s1,char *s2)
{
	fprintf (stderr,warning_string,s1,s2);
	fputc ('\n',stderr);
}

static void error (char *error_string)
{
	fprintf (stderr,"%s\n",error_string);
	exit (1);
}

static void error_s (char *error_string,char *s)
{
	fprintf (stderr,error_string,s);
	fputc ('\n',stderr);
	exit (1);
}

static void error_s_s (char *error_string,char *s1,char *s2)
{
	fprintf (stderr,error_string,s1,s2);
	fputc ('\n',stderr);
	exit (1);
}

static void *memory_allocate (int size)
{
	void *block;
	
	block=malloc (size);
	if (block==NULL)
		error ("Out of memory");
	return block;
}

#if defined (OS2) || defined (_WINDOWS_)
int dos_exec (char *file_name,char **args,int use_temp_file)
{
# ifdef OS2
	char command[8192];
# else
	char command[1024];
# endif

	if (!use_temp_file){
		int length;

		strcpy (command,file_name);
		strcat (command," ");

		++args;
		while (*args){
			strcat (command,*args);
			strcat (command," ");
			++args;
		}
	
		length=strlen (command);

		command[--length]='\0';

		return system (command);
	} else {
		char *temp_file_name;
		FILE *temp_file;	
		int r;

#if defined (_WINDOWS_) || defined (OS2)
		temp_file_name="param.$$$";
# ifdef OMF
		{
			char *p;
			
			for (p=temp_file_name; *p; ++p)
				if (*p=='/')
					*p='\\';
		}
# endif
		temp_file=fopen (temp_file_name,"w");
#else
		{
		static char param_tmp_file_name[]="/tmp/paramXXXXXX";
		int temp_file_fd;

		temp_file_fd=mkstemp (param_tmp_file_name);
		if (temp_file_fd<0)
			return 1;
	
		temp_file_name=param_tmp_file_name;	
		temp_file=fdopen (temp_file_fd,"w");
		}
# endif
		if (temp_file==NULL)
			return 1;

		++args;
		while (*args!=NULL){
#ifdef OMF
			if (*args!=NULL && **args==','){
				++args;
				fprintf (temp_file,"\n");
			} else {
				if (args[1]!=NULL && *args[1]=='/')
					fprintf (temp_file,"%s ",*args);
				else if (args[1]!=NULL && *args[1]!=',')
					fprintf (temp_file," %s +\n",*args);
				else
					fprintf (temp_file,"%s\n",*args);
				++args;
				if (*args!=NULL && **args==',')
					++args;
			}
#else
			fprintf (temp_file,"%s\n",*args);
			++args;
#endif
		}
			
	 	if (fclose (temp_file)!=0){
			return 1;
		}

		sprintf (command,"%s @%s",file_name,temp_file_name);
		r=system (command);

		unlink (temp_file_name);

		return r;
	}
}
#endif

static P_NODE add_project_node (char *module_name)
{
	P_NODE new_project_node;
	char *pro_fname;
	
	new_project_node=memory_allocate (sizeof (struct project_node));
	new_project_node->pro_next=NULL;
	
	pro_fname=memory_allocate (1+strlen (module_name));
	strcpy (pro_fname,module_name);

	new_project_node->pro_fname=pro_fname;
	new_project_node->pro_depend=NULL;
	new_project_node->pro_up_to_date=0;
	new_project_node->pro_valid_abc_time=0;
	new_project_node->pro_valid_dcl_time=0;
	new_project_node->pro_no_abc_file=0;
	new_project_node->pro_no_dcl_file=0;
	new_project_node->pro_ignore_o=0;
	new_project_node->pro_valid_options=0;
	new_project_node->pro_imported_object_files=NULL;
	
	if (first_project_node==NULL)
		first_project_node=new_project_node;
	else
		last_project_node->pro_next=new_project_node;
	last_project_node=new_project_node;
	
	return new_project_node;
}

static P_NODE add_dependency (DEP_LIST *dependency_list_p,char *dependent_module)
{
	DEP_LIST new_dependency,dependency;
	P_NODE project_node;

	for_l (dependency,*dependency_list_p,dep_next)
		if (!strcmp (dependent_module,dependency->dep_node->pro_fname))
			return NULL;
	
	new_dependency=memory_allocate (sizeof (struct dep_list));
	
	for_l (project_node,first_project_node,pro_next)
		if (!strcmp (dependent_module,project_node->pro_fname))
			break;

	if (project_node==NULL)
		project_node=add_project_node (dependent_module);
	
	new_dependency->dep_node=project_node;
	
	new_dependency->dep_next=*dependency_list_p;
	*dependency_list_p=new_dependency;
	
	return project_node;
}

static char *clean_path_list,clean_path_list_copy[PATH_LIST_STRING_SIZE];
static char *clean_lib_path,clean_lib_path_copy[PATH_NAME_STRING_SIZE];

static char *clean_abc_path,*clean_o_path;

#if defined (OS2) && !defined (OMF)
static char gcc_lib_path_copy[PATH_NAME_STRING_SIZE];
#endif

static int verbose=0;
static int silent=0;

#if MACINTOSH
#	define DIRECTORY_SEPARATOR_STRING ":"
#	define DIRECTORY_SEPARATOR_CHAR ':'
#	define PATH_SEPARATOR_CHAR ','
#else
# if defined (OS2) || defined (_WINDOWS_)
#	define DIRECTORY_SEPARATOR_STRING "\\"
#	define DIRECTORY_SEPARATOR_CHAR '\\'
#	define PATH_SEPARATOR_CHAR ';'
# else
#	define DIRECTORY_SEPARATOR_STRING "/"
#	define DIRECTORY_SEPARATOR_CHAR '/'
#	define PATH_SEPARATOR_CHAR ':'
# endif
#endif

#if MACINTOSH

#	undef TEST

#	ifdef TEST
		unsigned long f_get_f_info_time=0;
		int f_get_f_info_count=0;
#	endif

	static unsigned long get_file_time (char *fname,int wd_ref_num)
	{
		FileParam fpb;
		char fn[256];
		int err;
		
		strcpy (fn, fname);
	
		fpb.ioNamePtr=c2pstr (fn);
		fpb.ioFDirIndex=0;
		fpb.ioFVersNum=0;
		fpb.ioVRefNum=wd_ref_num;
	
#	ifdef TEST
		{
		unsigned long begin_time=TickCount();
#	endif
		
		err=PBGetFInfoSync ((ParmBlkPtr)&fpb);
	
#	ifdef TEST
		f_get_f_info_time+=TickCount()-begin_time;
		
		printf ("t=%d %d\n",f_get_f_info_time,++f_get_f_info_count);
		}
#	endif
	
		if (err)
			return 0;
		else
			return fpb.ioFlMdDat;
	}

	struct path_list {
		short				path_wd_ref_num;
		short				path_clean_system_files_wd_ref_num;
		struct path_list *	path_next;
#	ifdef __MWERKS__
		char				path_name[];
#	else
		char				path_name[0];
#	endif
	};

	static struct path_list *path_list;
	
	static unsigned char *copy_c_to_p_string (char *c_string,char *p_string)
	{
		char *s,*d,c;
		
		d=p_string+1;
		s=c_string;
		while (c=*s++, c!='\0')
			*d++=c;
		
		*p_string=s-1-c_string;
		
		return (unsigned char*) p_string;
	}

	static void add_directory_to_path_list (char *path_name)
	{
		short wd_ref_num,clean_system_files_wd_ref_num;
		struct path_list *new_path,**last_path_p;
		int path_name_length;
		char p_string [256];
		CInfoPBRec fpb;
		WDPBRec wd_pb;
		int err,root_path;
	
		root_path=0;
		
		if (path_name){
			char *p;
			
			for (p=path_name; *p!=DIRECTORY_SEPARATOR_CHAR && *p!='\0'; ++p)
				;
				
			if (*p=='\0'){
				root_path=1;
				p[0]=DIRECTORY_SEPARATOR_CHAR;
				p[1]='\0';
			}

			fpb.hFileInfo.ioNamePtr=copy_c_to_p_string (path_name,p_string);
		} else
			fpb.hFileInfo.ioNamePtr=(unsigned char*)"\001:";
		
		fpb.hFileInfo.ioVRefNum =0;
		fpb.hFileInfo.ioFDirIndex=0;
		fpb.hFileInfo.ioDirID=0;
	
		err = PBGetCatInfoSync (&fpb);
	
		if (err!=0){
			if (path_name)
				error_s ("folder '%s' does not exist",path_name);
			return;
		}
	
		wd_pb.ioNamePtr=fpb.hFileInfo.ioNamePtr;
		wd_pb.ioWDProcID='ClCo';

		wd_pb.ioVRefNum=0;
		wd_pb.ioWDDirID=0;
/*
		wd_pb.ioVRefNum=fpb.hFileInfo.ioVRefNum;
		wd_pb.ioWDDirID=fpb.hFileInfo.ioDirID;
*/

		err = PBOpenWD (&wd_pb,0);

		if (err!=0){
			if (path_name)
				error_s ("folder '%s' does not exist",path_name);
			return;
		}

		wd_ref_num=wd_pb.ioVRefNum;

# ifndef NO_CLEAN_SYSTEM_FILES_FOLDERS
		if (path_name)
			if (root_path)
				strcat (path_name,"Clean System Files");
			else
				strcat (path_name,":Clean System Files");
		else
			path_name="Clean System Files";
		
		fpb.hFileInfo.ioNamePtr=copy_c_to_p_string (path_name,p_string);
		fpb.hFileInfo.ioVRefNum =0;
		fpb.hFileInfo.ioFDirIndex=0;
		fpb.hFileInfo.ioDirID=0;
	
		err = PBGetCatInfoSync (&fpb);
	
		if (err!=0){
			if (path_name)
				error_s ("folder '%s' does not exist",path_name);
			return;
		}
	
		wd_pb.ioNamePtr=fpb.hFileInfo.ioNamePtr;
		wd_pb.ioWDProcID='ClCo';

		wd_pb.ioVRefNum=0;
		wd_pb.ioWDDirID=0;

		err = PBOpenWD (&wd_pb,0);
		
		if (err!=0){
			if (path_name)
				error_s ("folder '%s' does not exist",path_name);
			return;
		}

		clean_system_files_wd_ref_num=wd_pb.ioVRefNum;
	
		path_name_length=strlen (path_name)-strlen (":Clean System Files");
		if (path_name_length<0)
			path_name_length=0;
		path_name[path_name_length]='\0';
# else
		clean_system_files_wd_ref_num=0;
		
		if (path_name==NULL)
			path_name="";
		
		path_name_length=strlen (path_name);
# endif
	
		new_path=memory_allocate (sizeof (struct path_list)+1+path_name_length);
	
		last_path_p=&path_list;
		while (*last_path_p)
			last_path_p=&(*last_path_p)->path_next;
		
		new_path->path_wd_ref_num=wd_ref_num;
		new_path->path_clean_system_files_wd_ref_num=clean_system_files_wd_ref_num;
		strcpy (new_path->path_name,path_name);
		new_path->path_next=NULL;
	
		*last_path_p=new_path;
	}
	
	static void initialise_path_list (void)
	{
		char path[PATH_NAME_STRING_SIZE];
		char *s,*path_elem;
		int c;
		
		path_list=NULL;

		if (clean_abc_path)
			add_directory_to_path_list (clean_abc_path);

		add_directory_to_path_list (NULL);
		s = clean_path_list;
		
		if (s!=NULL){
			path_elem = s;
		
			for (c=*s; ; c=*s){
				if (c==PATH_SEPARATOR_CHAR || c == '\0'){
					char *s_p,*d_p;
					
					d_p=path;
					s_p=path_elem;
					while (s_p!=s)
						*d_p++ = *s_p++;
					*d_p='\0';
		
					add_directory_to_path_list (path);
								
					if (c == '\0')
						break;
					
					path_elem = ++s;
				} else
					++s;
			}
		}
	}
	
	static int last_path_clean_system_files_wd_ref_num_defined;
	static short last_path_clean_system_files_wd_ref_num;

	static unsigned long find_file (char *file_name,char *extension,char *complete_file_name)
	{
		unsigned long file_time;
	
		if (file_name[0]!=DIRECTORY_SEPARATOR_CHAR){
			struct path_list *path_elem;
# if USE_PATH_CACHE
			int dcl_file;
# endif
			strcpy (complete_file_name,file_name);
			strcat (complete_file_name,extension);
	
#	if USE_PATH_CACHE
			dcl_file=	extension[0]=='.' && extension[1]=='d' && extension[2]=='c' && 
						extension[3]=='l' && extension[4]=='\0';
	
			if (dcl_file){
				struct search_dcl_path_in_cache_result r;
				
				if (search_dcl_path_in_cache (file_name,&r)){
					short wd_ref_num;
				
					wd_ref_num=r.wd_ref_num;
					file_time=r.file_time;
	
					last_path_clean_system_files_wd_ref_num_defined=1;
					last_path_clean_system_files_wd_ref_num=r.clean_system_files_wd_ref_num;
	
					strcpy (complete_file_name,r.path);
					if (complete_file_name[0]!='\0' && complete_file_name[strlen (complete_file_name)-1]!=DIRECTORY_SEPARATOR_CHAR)
						strcat (complete_file_name,DIRECTORY_SEPARATOR_STRING);
					strcat (complete_file_name,file_name);
					strcat (complete_file_name,extension);
								
					return file_time;
				}
			}
#	endif

			for (path_elem=path_list; path_elem!=NULL;path_elem=path_elem->path_next)
			{
				short wd_ref_num;
				
				wd_ref_num=path_elem->path_wd_ref_num;
	
				file_time=get_file_time (complete_file_name,wd_ref_num);
				
				if (file_time){
					last_path_clean_system_files_wd_ref_num_defined=1;
					last_path_clean_system_files_wd_ref_num=path_elem->path_clean_system_files_wd_ref_num;
				
					strcpy (complete_file_name,path_elem->path_name);
					if (complete_file_name[0]!='\0' && complete_file_name[strlen (complete_file_name)-1]!=DIRECTORY_SEPARATOR_CHAR)
						strcat (complete_file_name,DIRECTORY_SEPARATOR_STRING);
					strcat (complete_file_name,file_name);
					strcat (complete_file_name,extension);
	
# if USE_PATH_CACHE
					if (dcl_file)
						cache_dcl_path
							(file_name,wd_ref_num,last_path_clean_system_files_wd_ref_num,file_time,path_elem->path_name);
# endif
								
					return file_time;
				}
			}
		}

		strcpy (complete_file_name,file_name);
		strcat (complete_file_name,extension);

		return get_file_time (complete_file_name,0);
	}

	static unsigned long find_clean_system_file (char *file_name,char *extension,char *complete_file_name)
	{
#ifdef NO_CLEAN_SYSTEM_FILES_FOLDERS
		return find_file (file_name,extension,complete_file_name);
#else
		unsigned long file_time;
		last_path_clean_system_files_wd_ref_num_defined=0;
		
		file_time=find_file (file_name,".dcl",complete_file_name);
		if (!file_time)
			file_time=find_file (file_name,".icl",complete_file_name);
		
		if (file_time){
			char *p,*last_colon;
			
			last_colon=complete_file_name;
			p=complete_file_name;
			while (*p){
				if (*p==DIRECTORY_SEPARATOR_CHAR)
					last_colon=p+1;
				++p;
			}
			
# ifndef NO_CLEAN_SYSTEM_FILES_FOLDERS
			strcpy (last_colon,"Clean System Files" DIRECTORY_SEPARATOR_STRING);
# else
			*last_colon='\0';
# endif
			strcat (last_colon,file_name);
			strcat (last_colon,extension);
			
			if (last_path_clean_system_files_wd_ref_num_defined){
				char file_name_with_extension[PATH_NAME_STRING_SIZE];
				
				strcpy (file_name_with_extension,file_name);
				strcat (file_name_with_extension,extension);
				
				file_time=get_file_time (file_name_with_extension,last_path_clean_system_files_wd_ref_num);
			} else
				file_time=get_file_time (complete_file_name,0);
		}
		
		return file_time;
#endif
	}

#else
# ifdef _WINDOWS_
	static int file_exists (char *file_name,FileTime *time_p)
	{
		HANDLE h;
#  ifdef GNU_C
		WIN32_FIND_DATAA find_data;

		h=FindFirstFileA (file_name,&find_data);
#  else
		WIN32_FIND_DATA find_data;

		h=FindFirstFile (file_name,&find_data);
#  endif
	
		if (h!=INVALID_HANDLE_VALUE){
			FindClose (h);
			*time_p=find_data.ftLastWriteTime;
			return 1;
		} else
			return 0;
	}
# endif

# ifdef OS2
	static int file_exists (char *file_name)
	{
		FILESTATUS3 fstatus;
		APIRET rc;
		
		rc = DosQueryPathInfo (file_name,FIL_STANDARD,&fstatus,sizeof (FILESTATUS3));
	
		return rc==NO_ERROR;
	}
# endif

	int find_file (char *file_name,char *extension,char *complete_file_name,char *first_path
#	ifdef _WINDOWS_
		,FileTime *file_time_p
#	endif
		)
	{
		if (file_name[0]!=DIRECTORY_SEPARATOR_CHAR){
			if (first_path!=NULL){
				strcpy (complete_file_name,first_path);
				strcat (complete_file_name,DIRECTORY_SEPARATOR_STRING);
				strcat (complete_file_name,file_name);
				strcat (complete_file_name,extension);
					
#	ifdef _WINDOWS_
				if (file_exists (complete_file_name,file_time_p))
#	else
#	 ifdef OS2
				if (file_exists (complete_file_name))
#	 else
				if (access (complete_file_name,F_OK)==0)
#	 endif
#	endif
					return 1;
			}
			
			if (clean_path_list!=NULL){
				char *s;
				int c;
				
				s=clean_path_list;
				c=*s++;
				while (c!='\0'){
					char *p;
					
					p=complete_file_name;
	
					while (c!=PATH_SEPARATOR_CHAR && c!='\0'){
						*p++=c;
						c=*s++;
					}
	
					*p++=DIRECTORY_SEPARATOR_CHAR;
	
					strcpy (p,file_name);
					strcat (p,extension);
					
#	ifdef _WINDOWS_
					if (file_exists (complete_file_name,file_time_p))
#	else
#	 ifdef OS2
					if (file_exists (complete_file_name))
#	 else
					if (access (complete_file_name,F_OK)==0)
#	 endif
#	endif
						return 1;
	
					if (c==PATH_SEPARATOR_CHAR)
						c=*s++;
				}
			}
#	if 0
			strcpy (complete_file_name,clean_lib_path);
			strcat (complete_file_name,DIRECTORY_SEPARATOR_STRING "stdenv" DIRECTORY_SEPARATOR_STRING);
			strcat (complete_file_name,file_name);
			strcat (complete_file_name,extension);

#	ifdef _WINDOWS_
			if (file_exists (complete_file_name,file_time_p))
#	else
#	 ifdef OS2
			if (file_exists (complete_file_name))
#	 else
			if (access (complete_file_name,F_OK)==0)
#	 endif
#	endif
				return 1;
#	endif

#ifdef OS2
			if (window_application){
				int length;
				char *lib_p;

				strcpy (complete_file_name,clean_lib_path);
				
				length=strlen (complete_file_name);
				lib_p=&complete_file_name[length-3];
				if (length>3 && (lib_p[0] & 0xdf)=='L' && (lib_p[1] & 0xdf)=='I' && (lib_p[2] & 0xdf)=='B'){
					strcpy (lib_p,"CleanIO\\");
					strcat (lib_p,file_name);
					strcat (lib_p,extension);
		
					if (file_exists (complete_file_name))
						return 1;
	
					strcpy (lib_p,"OsIO\\");
					strcat (lib_p,file_name);
					strcat (lib_p,extension);
		
					if (file_exists (complete_file_name))
						return 1;
				}
			}
#endif
		}
			
		strcpy (complete_file_name,file_name);
		strcat (complete_file_name,extension);
	
#	ifdef _WINDOWS_
		return file_exists (complete_file_name,file_time_p);
#	else
#	 ifdef OS2
		return file_exists (complete_file_name);
#	 else
		return access (complete_file_name,F_OK)==0;
#	 endif
#	endif
	 }

	static void replace_file_name_in_path (char *path,char *file_name,char *extension)
	{
		char *p,*last_colon;

		last_colon=path;
		p=path;
		while (*p){
			if (*p==DIRECTORY_SEPARATOR_CHAR)
				last_colon=p+1;
			++p;
		}
		strcpy (last_colon,file_name);
		strcat (last_colon,extension);
	}

	static void add_clean_system_files_and_replace_file_name_in_path (char *path,char *file_name,char *extension)
	{
		char *p,*last_colon;

		last_colon=path;
		p=path;
		while (*p){
			if (*p==DIRECTORY_SEPARATOR_CHAR)
				last_colon=p+1;
			++p;
		}
# ifndef NO_CLEAN_SYSTEM_FILES_FOLDERS
		strcpy (last_colon,"Clean System Files" DIRECTORY_SEPARATOR_STRING);
# else
		*last_colon='\0';
# endif
		strcat (last_colon,file_name);
		strcat (last_colon,extension);
	}

	int find_clean_system_file (char *file_name,char *extension,char *complete_file_name,char *first_path
#	ifdef _WINDOWS_
		,FileTime *file_time_p
#	endif
		)
	{
		int found;

		found=find_file (file_name,".dcl",complete_file_name,first_path
#	ifdef _WINDOWS_
					,file_time_p
#	endif
			);
		if (!found)
			found=find_file (file_name,".icl",complete_file_name,first_path
#	ifdef _WINDOWS_
					,file_time_p
#	endif
				);
		
		if (found){
			add_clean_system_files_and_replace_file_name_in_path (complete_file_name,file_name,extension);

#	ifdef _WINDOWS_
			return file_exists (complete_file_name,file_time_p);
#	else
#	 ifdef OS2
			return file_exists (complete_file_name);
#	 else
			return access (complete_file_name,F_OK)==0;
#	 endif
#	endif
		}
		
		return found;
	}
#endif

#ifdef OS2
static char *clm_file_name;
#endif

static void need_file(char *file_name,char *extension,char *complete_file_name)
{
	if (!find_clean_system_file (file_name, extension,complete_file_name,NULL)){
		fprintf (stderr,"Couldn't find %s%s\n", file_name, extension);
		exit (1);
	}
}

static void get_paths (void)
{
#if MACINTOSH
	clean_path_list = NULL;
	clean_lib_path = NULL;
#else
	clean_path_list=getenv ("CLEANPATH");		
	if (clean_path_list!=NULL)
		clean_path_list=strcpy (clean_path_list_copy,clean_path_list);
	else
		clean_path_list=clean_directory_list;

# ifdef OS2
	{
		int l;
		
		clean_lib_path=clean_lib_path_copy;

		l=strlen (clm_file_name);
		if (l<PATH_NAME_STRING_SIZE-1){
			int n;
			
			strcpy (clean_lib_path_copy,clm_file_name);
			
			for (n=l-1; n>=0; --n)
				if (clean_lib_path_copy[n]=='\\'){
					clean_lib_path_copy[n]='\0';
					l=n;
					break;
				}

			if (clean_lib_path_copy[l-4]=='\\'
				&& (clean_lib_path_copy[l-3] & 0xdf)=='B'
				&& (clean_lib_path_copy[l-2] & 0xdf)=='I'
				&& (clean_lib_path_copy[l-1] & 0xdf)=='N')
			{
				clean_lib_path_copy[l-3]+='l'-'b';
				clean_lib_path_copy[l-2]+='i'-'i';
				clean_lib_path_copy[l-1]+='b'-'n';
			}
		} else {
			clean_lib_path_copy[0]='.';
			clean_lib_path_copy[1]='\0';
		}
	}	
# else
	clean_lib_path=getenv ("CLEANLIB");
	if (clean_lib_path!=NULL)
		clean_lib_path=strcpy (clean_lib_path_copy,clean_lib_path);
	else
		clean_lib_path=clean_lib_directory;
# endif
#endif

#if MACINTOSH
	clean_abc_path=NULL;
	clean_o_path=NULL;
#else
	clean_abc_path=getenv ("CLEANABCPATH");
	clean_o_path=getenv ("CLEANOPATH");
#endif

#if defined (OS2) && !defined (OMF)
	{
		char *gcc_lib_path;
	
		gcc_lib_path=getenv ("GCCLIB");
		if (gcc_lib_path!=NULL)
			gcc_lib_path=strcpy (gcc_lib_path_copy,gcc_lib_path);
		else
			gcc_lib_path=gcc_lib_directory;
		
		gcc_lib_directory_arg[0]='-';
		gcc_lib_directory_arg[1]='L';
		strcpy (&gcc_lib_directory_arg[2], gcc_lib_path);
		sprintf (crt0_file_name,"%s\\crt0.o",&gcc_lib_directory_arg[2]);
	}
#endif
}

static int get_abc_time (P_NODE project_node,FileTime *time_p)
{
	char file_name[PATH_NAME_STRING_SIZE];
	FileTime time;
	
	if (project_node->pro_valid_abc_time)
		time=project_node->pro_abc_time;
	else {
		if (project_node->pro_no_abc_file)
			return 0;

#if MACINTOSH
		time=find_clean_system_file (project_node->pro_fname,".abc",file_name);

		if (time==0){
			project_node->pro_no_abc_file=1;
			return 0;
		}
#else
# ifdef _WINDOWS_
		if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path,&time))
			return 0;
# else
		{
		struct stat stat_buffer;
		
		if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path))
			return 0;
	
		if (stat (file_name,&stat_buffer)<0){
			project_node->pro_no_abc_file=1;
			return 0;
		}
		time=stat_buffer.st_mtime;
		}
# endif
#endif		
		project_node->pro_abc_time=time;
		project_node->pro_valid_abc_time=1;
	}
	
	*time_p=time;
	return 1;
}

static int get_dcl_time (P_NODE project_node,FileTime *time_p)
{
	char file_name[PATH_NAME_STRING_SIZE];
	FileTime time;
	
	if (project_node->pro_valid_dcl_time)
		time=project_node->pro_dcl_time;
	else {
		if (project_node->pro_no_dcl_file)
			return 0;
#if MACINTOSH
		time=find_file (project_node->pro_fname,".dcl",file_name);

		if (time==0){
			project_node->pro_no_dcl_file=1;
			return 0;
		}
#else
# ifdef _WINDOWS_
		if (!find_file (project_node->pro_fname,".dcl",file_name,NULL,&time))
			return 0;
# else
		{	
		struct stat stat_buffer;

		if (!find_file (project_node->pro_fname,".dcl",file_name,NULL))
			return 0;
	
		if (stat (file_name,&stat_buffer)<0){
			project_node->pro_no_dcl_file=1;
			return 0;
		}
	
		time=stat_buffer.st_mtime;
		}
# endif
#endif
		project_node->pro_dcl_time=time;
		project_node->pro_valid_dcl_time=1;
	}
	
	*time_p=time;
	return 1;
}

#if MACINTOSH
	static int get_time (P_NODE project_node,char *extension,FileTime *time_p)
	{
		char file_name[PATH_NAME_STRING_SIZE];
		unsigned long time;
	
		time=find_file (project_node->pro_fname,extension,file_name);
	
		if (time==0)
			return 0;
		
		*time_p=time;
	
		return 1;
	}

	static int get_clean_system_time (P_NODE project_node,char *extension,FileTime *time_p)
	{
		char file_name[PATH_NAME_STRING_SIZE];
		unsigned long time;
	
		time=find_clean_system_file (project_node->pro_fname,extension,file_name);
	
		if (time==0)
			return 0;
		
		*time_p=time;
	
		return 1;
	}

#else
	static int get_time (P_NODE project_node,char *extension,FileTime *time_p,char *first_path)
	{
		char file_name[PATH_NAME_STRING_SIZE];
# ifdef _WINDOWS_
		return find_file (project_node->pro_fname,extension,file_name,first_path,time_p);
# else
		struct stat stat_buffer;
		
		if (!find_file (project_node->pro_fname,extension,file_name,first_path))
			return 0;
		
		if (stat (file_name,&stat_buffer)<0)
			return 0;
	
		*time_p=stat_buffer.st_mtime;
	
		return 1;
# endif
	}

	static int get_clean_system_time (P_NODE project_node,char *extension,FileTime *time_p,char *first_path)
	{
		char file_name[PATH_NAME_STRING_SIZE];
# ifdef _WINDOWS_
		return find_clean_system_file (project_node->pro_fname,extension,file_name,first_path,time_p);
# else
		struct stat stat_buffer;
		
		if (!find_clean_system_file (project_node->pro_fname,extension,file_name,first_path))
			return 0;
		
		if (stat (file_name,&stat_buffer)<0)
			return 0;
	
		*time_p=stat_buffer.st_mtime;
	
		return 1;
# endif
	}
#endif

FILE *abc_file;
int last_char;

static int open_abc_file2 (P_NODE project_node,char file_name[])
{
	FILE *f;
	
#if MACINTOSH
	if (!find_clean_system_file (project_node->pro_fname,".abc",file_name))
		return 0;
#else
# ifdef _WINDOWS_
	{
	FileTime time;
	
	if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path,&time))
		return 0;
	}
# else
	if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path))
		return 0;
# endif
#endif
	
	f=fopen (file_name,"r");
	if (f==NULL)
		return 0;
	
	setvbuf (f,NULL,_IOFBF,2048);
	
	last_char=getc (f);
	abc_file=f;
	return 1;
}

static int open_abc_file (P_NODE project_node)
{
	char file_name [PATH_NAME_STRING_SIZE];

	return open_abc_file2 (project_node,file_name);
}

static void skip_spaces (void)
{
	while (last_char==' ' || last_char=='\t')
		last_char=getc (abc_file);
}

static void skip_to_next_line (void)
{
	while (last_char!='\n' && last_char!=EOF)
		last_char=getc (abc_file);
	if (last_char=='\n')
		last_char=getc (abc_file);
}

static int last_char_was (int c)
{
	if (last_char==c){
		last_char=getc (abc_file);
		return 1;
	} else
		return 0;
}

static int last_char_was_digit (void)
{
	if (last_char<='9' && last_char>='0'){
		last_char=getc (abc_file);
		return 1;
	} else
		return 0;
}

static int get_version_and_options_of_abc_file (P_NODE project_node,int *version_p,long *comp_options_position_p)
{
	int version,options;
	
	*comp_options_position_p = -1;

	while (last_char!=EOF){
		skip_spaces();
		if (last_char!='.')
			return 0;
		last_char=getc (abc_file);
		if (last_char_was ('c')){
			if (last_char_was ('o') && last_char_was ('m') && last_char_was ('p')){
				int digit_1,digit_2,digit_3;
				
				skip_spaces();
				
				if ((digit_1=last_char,last_char_was_digit())
					&& (digit_2=last_char,last_char_was_digit())
					&& (digit_3=last_char,last_char_was_digit()))
				{
					int digit_n;
					
					version=(digit_1-'0')*100 + (digit_2-'0')*10 + (digit_3-'0');
					
					skip_spaces();
					
					options=0;
					if (last_char!='\n'){
						long comp_options_position;

						comp_options_position=ftell (abc_file)-1;

						for (digit_n=0; digit_n<9; ++digit_n){
							if (last_char=='0')
								;
							else if (last_char=='1')
								options |= (1<<digit_n);
							else
								return 0;
							last_char=getc (abc_file);
						}

						while (digit_n<11 && (last_char & 0xfe)=='0'){
							options |= ((last_char & 1)<<digit_n);
							last_char=getc (abc_file);
							++digit_n;
						}

						*comp_options_position_p=comp_options_position;
					}
					skip_to_next_line();
					
					project_node->pro_options=options;
					project_node->pro_valid_options=1;
					
					*version_p=version;
					return 1;
				}
			}
		} else if (last_char_was ('e') && last_char_was ('n') && last_char_was ('d')
			&& last_char_was ('i') && last_char_was ('n') && last_char_was ('f')
			&& last_char_was ('o'))
		{
			return 0;
		}
		skip_to_next_line();
	}
	return 0;
}

static int get_dependency_or_imported_object_file_of_abc_file (char *file_name,int max_length)
{
	int depend_or_impobj;

	depend_or_impobj=1;
	while (last_char!=EOF){
		skip_spaces();
		if (last_char!='.')
			return 0;
		last_char=getc (abc_file);
		if (last_char_was ('d')){
			if (last_char_was ('e') && last_char_was ('p') && last_char_was ('e')
				&& last_char_was ('n') && last_char_was ('d'))
			{
				depend_or_impobj=1;
				break;
			}
		} else if (last_char_was ('i')){
			if (last_char_was ('m') && last_char_was ('p') && last_char_was ('o')
				&& last_char_was ('b') && last_char_was ('j'))
			{
				depend_or_impobj=2;
				break;
			}
		} else if (last_char_was ('e') && last_char_was ('n') && last_char_was ('d')
			&& last_char_was ('i') && last_char_was ('n') && last_char_was ('f')
			&& last_char_was ('o'))
		{
			return 0;
		} else
			skip_to_next_line();
	}

   	if (depend_or_impobj==0)
   		return 0;

	skip_spaces();
				
	if (last_char=='\"'){
		int n;

		last_char=getc (abc_file);
		n=0;
		while (last_char!='\"' && last_char!='\n' && last_char!=EOF
		   && n<max_length)
		{
			*file_name++=last_char;
			last_char=getc (abc_file);
			++n;
		}
		if (n<max_length && last_char=='\"'){
			*file_name='\0';
			skip_to_next_line();
			return depend_or_impobj;
		}
	}

	return 0;
}

static void close_abc_file (void)
{
	fclose (abc_file);
}

static void add_imported_object_file_to_project_node (char *object_file_name,P_NODE project_node)
{
	int object_file_name_size;
	struct object_file_list *new_imported_object_file,**object_file_h;
	int add_object_file_extension;

	object_file_name_size=strlen (object_file_name);
	
	add_object_file_extension=0;
	if (object_file_name_size>0 && object_file_name[object_file_name_size-1]=='.'){
		add_object_file_extension=1;
		++object_file_name_size;
	}
	
	new_imported_object_file=memory_allocate (sizeof (struct object_file_list)+object_file_name_size+1);

	strcpy (new_imported_object_file->object_file_name,object_file_name);	
	if (add_object_file_extension){
		new_imported_object_file->object_file_name[object_file_name_size-1]='o';
		new_imported_object_file->object_file_name[object_file_name_size]='\0';
	}
	
	new_imported_object_file->object_file_next=NULL;

	object_file_h=&project_node->pro_imported_object_files;
	while (*object_file_h!=NULL)
		object_file_h=&(*object_file_h)->object_file_next;
	*object_file_h=new_imported_object_file;
}

static int single_module=0;
static int syntax_check=0;
static int only_abc_files=0;
static int only_s_files=0;
static int only_o_files=0;

static int project_node_is_abc_up_to_date (P_NODE project_node)
{
	FileTime abc_time,dcl_time,icl_time;
	int version,abc_options;
	DEP_LIST dependency_list;
	long comp_options_position;
	char abc_file_name [PATH_NAME_STRING_SIZE];
	char dependent_module [PATH_NAME_STRING_SIZE];

	if (!get_abc_time (project_node,&abc_time)){
		if (verbose)
			warning_s ("(%s.abc doesn't exist)",project_node->pro_fname);
		return 0;
	}
	
	if (!open_abc_file2 (project_node,abc_file_name))
		return 0;
	
	if (!get_version_and_options_of_abc_file (project_node,&version,&comp_options_position)){
		close_abc_file();
		return 0;
	}
	abc_options=project_node->pro_options;
	
	if (version!=VERSION){
		close_abc_file();
		warning_s ("Warning: %s.abc is generated with another compiler version",
				   project_node->pro_fname);
		return 0;
	}
	
	if (!(abc_options & SYSTEM_MASK)){
		if ((abc_options & PARALLEL_MASK) || !(abc_options & STACK_LAYOUT_MASK)){
			if (verbose)
				warning_s ("(%s.abc is not sequential abc code with stack information)",
						   project_node->pro_fname);
			close_abc_file();
			return 0;
		}

		if ((NO_TIME_PROFILE_MASK & (clean_options ^ abc_options))!=0){
			if (verbose)
 				warning_s ("(%s.icl is compiled with different time profile options)",project_node->pro_fname);
			close_abc_file();
			return 0;
		}

#if MACINTOSH
		if (get_time (project_node,".icl",&icl_time) && abc_time<=icl_time){
#else
		if (get_time (project_node,".icl",&icl_time,NULL) && FILE_TIME_LE (abc_time,icl_time)){
#endif
			if (verbose)
				warning_s ("(%s.abc is older than corresponding icl file)",
						   project_node->pro_fname);
			close_abc_file();
			return 0;
		}
		
		if (get_dcl_time (project_node,&dcl_time) && FILE_TIME_LE (abc_time,dcl_time)){
			if (verbose)
				warning_s ("(%s.abc is older than corresponding dcl file)",
						   project_node->pro_fname);
			return 0;
		}
	} else {
		if ((NO_TIME_PROFILE_MASK & (clean_options ^ abc_options))!=0){
			if (verbose)
 				warning_s ("(%s.icl is compiled with different time profile options)",project_node->pro_fname);
			close_abc_file();

			if (comp_options_position>=0){
				FILE *f;

				f=fopen (abc_file_name,"r+");
				if (f==NULL)
					error_s ("Could not write to file %s\n",abc_file_name);
		
				if (fseek (f,comp_options_position+5,SEEK_SET)!=0)
					error_s ("Could not write to file %s\n",abc_file_name);

				if ((clean_options & NO_TIME_PROFILE_MASK)==0)
					fputc ('0',f);
				else
					fputc ('1',f);
	
				if (fclose (f)!=0)
					error_s ("Could not write to file %s\n",abc_file_name);
			
				project_node->pro_options &= ~NO_TIME_PROFILE_MASK;
				project_node->pro_options |= clean_options & NO_TIME_PROFILE_MASK;

				return 1;
			}
	
			return 0;
		}
	}
	
	if (project_node==main_project_node &&
		((DEBUG_MASK | STRICTNESS_ANALYSIS_MASK | FUSION_MASK | NO_REUSE_UNIQUE_NODES_MASK) & clean_options_mask & (clean_options ^ abc_options))!=0)
	{
		if (verbose)
			warning_s ("(%s.icl is compiled with different options)", project_node->pro_fname);

		close_abc_file();
		return 0;
	}	

	{
	int depend_or_impobj;

	dependency_list=NULL;
	while (
		depend_or_impobj=get_dependency_or_imported_object_file_of_abc_file (dependent_module,PATH_NAME_STRING_SIZE-1),
		depend_or_impobj!=0
	){
		if (depend_or_impobj==1){
			FileTime dcl_time;
			P_NODE dependency_node;
		
			dependency_node=add_dependency (&dependency_list,dependent_module);
		
			if (dependency_node==NULL)
				continue;
		
			if (!(abc_options & SYSTEM_MASK)){
				if (get_dcl_time (dependency_node,&dcl_time) && FILE_TIME_LE(abc_time,dcl_time)){
					if (verbose)
						warning_s_s ("(%s.icl conflicts with %s.dcl)",project_node->pro_fname,
									 dependent_module);
					close_abc_file();
					return 0;
				}
			
				/*
				if (is_system_file (dependency_node)){
					long dcl_abc_time;
				
					if (get_abc_time (dependency_node,&dcl_abc_time) && abc_time<=dcl_abc_time){
						if (verbose)
							warning_s_s ("(%s.icl conflicts with %s.abc)",
										 project_node->pro_fname,dependency_node->pro_fname);
						close_abc_file();
						return 0;
					}
				}
				*/
			}
		} else if (depend_or_impobj==2)
			add_imported_object_file_to_project_node (dependent_module,project_node);
	}

	}

	close_abc_file();
	
	project_node->pro_depend=dependency_list;
	
	if (verbose)
		warning_s ("(%s.abc is up to date)",project_node->pro_fname);
	return 1;
}

static int is_system_file (P_NODE project_node)
{
	if (project_node->pro_no_abc_file)
		return 0;
	
	if (!project_node->pro_valid_options){
		int version;
		long comp_options_position;
		FILE *old_file;
		
		old_file=abc_file;
		
		if (!open_abc_file (project_node)){
			abc_file=old_file;
			return 0;
		}
	
		if (!get_version_and_options_of_abc_file (project_node,&version,&comp_options_position)){
			close_abc_file();
			abc_file=old_file;
			return 0;
		}
		close_abc_file();
		abc_file=old_file;
	}
	
	return (project_node->pro_options & SYSTEM_MASK)!=0;
}

#if defined(_WINDOWS_) && defined (GNU_C)
extern int wait (int*);
#endif

#include <errno.h>

static int wait_for_child (pid_t pid, char *child_name, int *status_p)
{
    int result;

   	result=waitpid (pid, status_p, 0);

    if (*status_p & 255)
        fprintf (stderr,"%s exited abnormally\n",child_name);

    return result;
}

#if MACINTOSH
extern int CallCompiler (int argc,char **argv);
#endif

#ifdef OS2
static char *arg_v_to_arguments (char **argv)
{
	int arguments_length;
	char **argv_p,*arguments,*arg_p;
	
	arguments_length=2;
	for (argv_p=argv; *argv_p!=NULL; ++argv_p)
		arguments_length += strlen (*argv_p)+1;
	
	arguments=memory_allocate (arguments_length);
	
	if (arguments!=NULL){
		arg_p=arguments;
		argv_p=argv;
		
		strcpy (arg_p,*argv_p);
		arg_p += strlen (arg_p)+1;

		if (*++argv_p!=NULL){
			strcpy (arg_p,*argv_p);
			arg_p += strlen (arg_p);

			while (*++argv_p!=NULL){
				*arg_p++ =' ';
				strcpy (arg_p,*argv_p);
				arg_p += strlen (arg_p);
			}
		}
		*arg_p++ = '\0';
		*arg_p++ = '\0';
	}
	
	return arguments;
}
#endif

#define CACHING_COMPILER

#ifdef CACHING_COMPILER

#include "Clean.h"
#include "cachingcompiler.h"

static int compiler_started=0;

static void start_compiler (void)
{
	int r;
	char cocl_file_name[PATH_NAME_STRING_SIZE];

	strcpy (cocl_file_name,clean_lib_path); 
	strcat (cocl_file_name,"/cocl");

	r=start_caching_compiler ((unsigned char *)cocl_file_name);
	if (r < 0)
		exit(r);	
}

static void stop_compiler (void)
{
	int r;

	r=stop_caching_compiler();
	if (r < 0)
		exit(r);
}

static char *concatenate_args (char **argv)
{
	int size;
	char **argv2, *p, *args;

	if (*argv == NULL)
		error ("concatenate_args: no args\n");

	size=0;
	for (argv2=argv; *argv2!=NULL; argv2++){
		char *arg;

		size += 1; /* '"' */
		for (arg=*argv2; *arg!='\0'; arg++)
			if (*arg=='"')
				size += 2; /* '\' and '"' */
			else
				size += 1; /* c */
		size += 2; /* '"' and (' ' or '\0') */
	}

	args=malloc(size);
	if (args==NULL)
		return NULL;

	p=args;
	for (argv2=argv; *argv2!=NULL; argv2++){
		char *arg;

		*p++='"';
		for (arg=*argv2; *arg!='\0'; arg++)
			if (*arg=='"')
			{
				*p++='\\';
				*p++='"';
			}
			else
				*p++=*arg;
		*p++='"';
		*p++=' ';
	}
	*(p-1)='\0';

	if (p-args!=size)
		error ("concatenate_args: fatal programming error\n");

	return args;
}	
#endif

static int call_compiler (char *cocl_file_name, char **argv)
{
#ifdef CACHING_COMPILER
	int r;
	char *args;

	if (!compiler_started){
		start_compiler();
		compiler_started=1;
	}

	args=concatenate_args(argv);
	if (args != NULL)
	{
		r=call_caching_compiler ((unsigned char *)args);
		free (args);
	}
	else
		r=-1;

	return r>=0;
#else /* ifndef CACHING_COMPILER */
	int pid,r,status;

	pid=fork();
	if (pid<0)
		error ("Fork failed");
	
	if (!pid){
		strcat (cocl_file_name,"/cocl");
		execv (cocl_file_name,argv);
		
		error ("Can't execute the clean compiler");
	}
	
	r=wait_for_child (pid, "Clean compiler",&status);
	
	return r>=0 && status==0;
#endif
}

static int compile_project_node (P_NODE project_node)
{
	char file_name[PATH_NAME_STRING_SIZE];
	char *abc_file_name,abc_file_name_s[PATH_NAME_STRING_SIZE];
	char cocl_file_name[PATH_NAME_STRING_SIZE];
	char *argv[16],**arg;
	int options;

	if (!silent)
		printf ("Compiling %s\n",project_node->pro_fname);
	
	project_node->pro_no_abc_file=0;
	project_node->pro_valid_abc_time=0;

#if MACINTOSH
	if (!find_file (project_node->pro_fname,".icl",file_name))
		error_s ("Can't find %s.icl",project_node->pro_fname);
#else
# ifdef _WINDOWS_
	{
	FileTime time;
	
	if (!find_file (project_node->pro_fname,".icl",file_name,NULL,&time))
		error_s ("Can't find %s.icl",project_node->pro_fname);
	}
# else
	if (!find_file (project_node->pro_fname,".icl",file_name,NULL))
		error_s ("Can't find %s.icl",project_node->pro_fname);
# endif
#endif

	if (clean_abc_path==NULL){
#ifdef NO_CLEAN_SYSTEM_FILES
		int length;
#endif

		abc_file_name=abc_file_name_s;
		strcpy (abc_file_name_s,file_name);
#ifdef NO_CLEAN_SYSTEM_FILES
		length=strlen (abc_file_name_s);
		abc_file_name_s[length-3]='a';
		abc_file_name_s[length-2]='b';
		abc_file_name_s[length-1]='c';
#else
		{
			char *p,*last_colon;
			
			last_colon=abc_file_name_s;
			p=abc_file_name_s;
			while (*p){
				if (*p==DIRECTORY_SEPARATOR_CHAR)
					last_colon=p+1;
				++p;
			}
			strcpy (last_colon,"Clean System Files");
		
			if (access (abc_file_name,F_OK)!=0){
				if (mkdir (abc_file_name,0777)!=0)
					error_s ("Could not create directory %s\n",abc_file_name);
			}

			strcat (last_colon,DIRECTORY_SEPARATOR_STRING);
			strcat (last_colon,project_node->pro_fname);
			strcat (last_colon,".abc");
		}
#endif
	} else {
		abc_file_name=abc_file_name_s;
		strcpy (abc_file_name,clean_abc_path);
#if MACINTOSH
		if (clean_abc_path[0]!='\0' && clean_abc_path[strlen (clean_abc_path)-1]!=DIRECTORY_SEPARATOR_CHAR)
#endif
		strcat (abc_file_name,DIRECTORY_SEPARATOR_STRING);
		strcat (abc_file_name,project_node->pro_fname);
		strcat (abc_file_name,".abc");
	}

	arg=argv;
	*arg++="cocl";

    if (cocl_redirect_stdout!=NULL){
        *arg++ = cocl_redirect_stdout_option;
        *arg++ = cocl_redirect_stdout;
    }

    if (cocl_redirect_stderr!=NULL){
        *arg++ = cocl_redirect_stderr_option;
        *arg++ = cocl_redirect_stderr;
    }

	*arg++="-sl";

#ifndef NO_CLEAN_SYSTEM_FILES
	*arg++="-csf";
#endif
	
	*arg++="-P";
	
	if (clean_path_list!=NULL) {
		int path_list_length;
		char *cocl_path_list;

		path_list_length=strlen (clean_path_list)+3;
		cocl_path_list=memory_allocate (path_list_length);
		cocl_path_list[0]='\0';
		strcat (cocl_path_list,clean_path_list);
		strcat (cocl_path_list,":.");

		*arg++=cocl_path_list;
	} else
		*arg++=".";
	
	if (syntax_check)
		*arg++="-c";
	
	if (progress || ((clean_options & VERBOSE_MASK)!=0)!=DEFAULT_VERBOSE)
		*arg++="-v";
	if (((clean_options & LIST_TYPES_MASK)!=0)!=DEFAULT_LIST_TYPES)
		*arg++="-lt";
	if (((clean_options & LIST_ALL_TYPES_MASK)!=0)!=DEFAULT_LIST_ALL_TYPES)
		*arg++="-lat";

	if ((clean_options & NO_REUSE_UNIQUE_NODES_MASK)==0)
		*arg++="-ou";
	if ((clean_options & MEMORY_PROFILE)!=0)
		*arg++="-pm";
	if ((clean_options & NO_TIME_PROFILE_MASK)==0)
		*arg++="-pt";
	if ((clean_options & FUSION_MASK)!=0)
		*arg++="-fusion";
	if (dynamics)
		*arg++="-dynamics";

	if (project_node->pro_valid_options)
		options=project_node->pro_options;
	else
		options=DEFAULT_OPTIONS;

	project_node->pro_valid_options=0;
		
	if (project_node==main_project_node)
		options=(options & ~clean_options_mask) 
				| (clean_options & clean_options_mask);
	
	if (nowarn || ((options & WARNING_MASK)!=0)!=DEFAULT_WARNING)
		*arg++="-w";
	if (((options & DEBUG_MASK)!=0)!=DEFAULT_DEBUG)
		*arg++="-d";
	if (((options & STRICTNESS_ANALYSIS_MASK)!=0)!=DEFAULT_STRICTNESS_ANALYSIS)
		*arg++="-sa";

	if (list_strict_export_types)
		*arg++="-lset";

#ifdef OS2
	if (window_application)
		*arg++="-p";
#endif

	if (funcmayfail_error)
		*arg++="-emf";
	if (varnotused_error)
		*arg++="-enu";
	if (funcnotused_error)
		*arg++="-efnu";

	*arg++="-o";
	*arg++=abc_file_name;

	*arg++=file_name;
	*arg=NULL;

#if MACINTOSH
	r=CallCompiler (arg-argv-1,argv+1);
	if (r)
		return 1;
	else
		return 0;
#else
	strcpy (cocl_file_name,clean_lib_path);
# if defined (OS2) || defined (_WINDOWS_)
	strcat (cocl_file_name,"\\cocl.exe");
	argv[0]=cocl_file_name;
#  if defined (_WINDOWS_)
#   ifdef GNU_C
	r=spawnvp (P_WAIT,cocl_file_name,argv);
	if (r>=0)
		r=wait (&status);
	return r>=0 && status==0;
#   else
	return spawnv (P_WAIT,cocl_file_name,argv)==0;
#   endif
#  else
	{
		CHAR load_error [17];
		RESULTCODES return_codes;
		APIRET rc;
		char *arguments;

		arguments=arg_v_to_arguments (argv);

		if (arguments!=NULL){					
			rc=DosExecPgm (load_error,sizeof (load_error),EXEC_SYNC,arguments,NULL,&return_codes,cocl_file_name);
					
			free (arguments);
			
			if (rc==0 && return_codes.codeTerminate==0)
				return return_codes.codeResult==0;
		}
		
		error ("Can't execute the clean compiler");
		return 0;
	}
#  endif
# else
	return call_compiler (cocl_file_name, argv);
# endif
#endif
}

#if MACINTOSH && !defined (G_POWER)
static char *OBJECT_FILE_EXTENSION;
/* #	define OBJECT_FILE_EXTENSION ".obj1" */
#else
# if (defined (_WINDOWS_) && (defined (USE_WLINK)) || defined (OMF))
#	define OBJECT_FILE_EXTENSION ".obj"
# else
#	define OBJECT_FILE_EXTENSION ".o"
# endif
#endif

#if MACINTOSH
extern int generate_code (int,char **);
#endif

static int generate_code_for_project_node (P_NODE project_node,char *file_name)
{
	char *argv[16],**arg;

	if (!silent)
		printf ("Generating code for %s\n",project_node->pro_fname);
		
	arg=argv;
	*arg++="cg";

#if MACINTOSH || defined (NO_ASSEMBLE)
	if (only_s_files)
		*arg++="-a";
#endif
	if (check_stack_overflow)
		*arg++="-os";

	if (check_indices)
		*arg++="-ci";

	*arg++=file_name;
	*arg=NULL;

#if MACINTOSH
	return generate_code (arg-argv,argv)==0;
#else
	{
	char cg_file_name[PATH_NAME_STRING_SIZE];

	strcpy (cg_file_name,clean_lib_path);
# if defined (OS2) || defined (_WINDOWS_)
	strcat (cg_file_name,"\\cg.exe");
	argv[0]=cg_file_name;
#  ifdef _WINDOWS_
#   ifdef GNU_C
	{
		int r,status;
	
		argv[0]=cg_file_name;
		r=spawnvp (P_WAIT,cg_file_name,argv);
		if (r>=0)
			r=wait (&status);
		return r>=0 && status==0;
	}
#   else
	return spawnv (P_WAIT,cg_file_name,argv)==0;
#   endif
#  else
	{
		CHAR load_error [17];
		RESULTCODES return_codes;
		APIRET rc;
		char *arguments;

		arguments=arg_v_to_arguments (argv);

		if (arguments!=NULL){					
			rc=DosExecPgm (load_error,sizeof (load_error),EXEC_SYNC,arguments,NULL,&return_codes,cg_file_name);
					
			free (arguments);
			
			if (rc==0 && return_codes.codeTerminate==0)
				return return_codes.codeResult==0;
		}
		
		error ("Can't execute the code generator");
		return 0;
	}
#  endif
# else
	{
		int pid,r,status;
	
		pid=fork();
		if (pid<0)
			error ("Fork failed");
		
		if (!pid){
			strcat (cg_file_name,"/cg");

			execv (cg_file_name,argv);
			
			error ("Can't execute the code generator");
		}
	
		r=wait_for_child (pid, "Code generator",&status);
		return r>=0 && status==0;
	}
# endif
	}
#endif
}

static int assemble (P_NODE project_node,char *file_name)
{
	int pid,r,status;
	char s_file_name[PATH_NAME_STRING_SIZE],o_file_name[PATH_NAME_STRING_SIZE];
	
	if (!silent)
		printf ("Assembling %s\n",project_node->pro_fname);

	strcpy (s_file_name,file_name);
	strcat (s_file_name,".s");

#if ! MACINTOSH
	if (clean_o_path==NULL)
#endif
		strcpy (o_file_name,file_name);
#if ! MACINTOSH
	else {
		strcpy (o_file_name,clean_o_path);
		strcat (o_file_name,DIRECTORY_SEPARATOR_STRING);
		strcat (o_file_name,project_node->pro_fname);
	}
#endif
	strcat (o_file_name,OBJECT_FILE_EXTENSION);

#if !(defined (OS2) || defined (_WINDOWS_)) && ! MACINTOSH
	pid=fork();
	if (pid<0)
		error ("Fork failed");
	
	if (!pid)
#endif
	{
		char *argv[16],**arg;
		
		arg=argv;
		*arg++="as";

#if defined (OS2) && defined (OMF)
		*arg++="-Zomf";
#endif

		*arg++=s_file_name;
		*arg++="-o";
		*arg++=o_file_name;
		*arg=0;
#if defined (OS2) || defined (_WINDOWS_)
# if defined (OS2)
		r=dos_exec (assembler_file_name,argv,0);
# else
#  ifdef _WINDOWS_
#   ifdef GNU_C
		{
			int status;
		
			argv[0]=assembler_file_name;
			r=spawnvp (P_WAIT,assembler_file_name,argv);
			if (r>=0)
				r=wait (&status);
			return r>=0 && status==0;
		}
#   else
		return spawnvp (P_WAIT,assembler_file_name,argv)==0;
#   endif
#  else
		r=dos_exec (assembler_file_name,argv,1);
#  endif
# endif

		return r==0;
	}
#else
#	if MACINTOSH
	}
	return 1;
#	else
		execv (assembler_file_name,argv);

		error ("Can't execute the assembler");
	}
	
	r=wait_for_child (pid, "Assembler",&status);
	return r>=0 && status==0;
#	endif
#endif
}

static void get_dependencies (P_NODE project_node)
{
	DEP_LIST dependency_list;
	char dependent_module [PATH_NAME_STRING_SIZE];
	long comp_options_position;
	int depend_or_impobj,version;

	if (!open_abc_file (project_node))
		return;

	if (!get_version_and_options_of_abc_file (project_node,&version,&comp_options_position)){
		close_abc_file();
		return;
	}

	dependency_list=NULL;
	do {
		depend_or_impobj=get_dependency_or_imported_object_file_of_abc_file (dependent_module,PATH_NAME_STRING_SIZE-1);

		if (depend_or_impobj==1)
			add_dependency (&dependency_list,dependent_module);
		else if (depend_or_impobj==2)
			add_imported_object_file_to_project_node (dependent_module,project_node);
	} while (depend_or_impobj!=0);

	close_abc_file();

	project_node->pro_depend=dependency_list;
}

static int make_project_to_abc_files (P_NODE project_node)
{
	DEP_LIST dependency;
	
	if (project_node->pro_up_to_date)
		return 1;
	
	project_node->pro_up_to_date=1;
	
	if (!project_node->pro_ignore_o && !project_node_is_abc_up_to_date (project_node)){
		if (is_system_file (project_node))
			return 0;
		if (!compile_project_node (project_node))
			return 0;
		if (!single_module)
			get_dependencies (project_node);
	}
	
	if (!single_module)
		for_l (dependency,project_node->pro_depend,dep_next)
			if (!make_project_to_abc_files (dependency->dep_node))
				return 0;
	
	return 1;
}

static int project_node_is_o_up_to_date (P_NODE project_node)
{
	FileTime abc_time,o_time;

	if (!get_clean_system_time (project_node,OBJECT_FILE_EXTENSION,&o_time
#if ! MACINTOSH
				   ,clean_o_path!=NULL ? clean_o_path : clean_abc_path
#endif
		))
	{
		if (verbose)
			warning_s ("(%s.o doesn't exist)",project_node->pro_fname);
		return 0;
	}
	
	if (get_abc_time (project_node,&abc_time) && FILE_TIME_LE (o_time,abc_time)){
		if (verbose)
			warning_s ("(%s.o is older than corresponding abc file)",
					   project_node->pro_fname);
		return 0;
	}
	
	if (verbose)
		warning_s ("(%s.o is up to date)",project_node->pro_fname);
	
	return 1;
}

static int make_project_to_o_files (void)
{
	P_NODE project_node;
	
	for_l (project_node,first_project_node,pro_next){
		if (project_node->pro_up_to_date && !project_node->pro_ignore_o && !project_node_is_o_up_to_date (project_node)){
			char file_name[PATH_NAME_STRING_SIZE];
			
#if MACINTOSH
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name))
				error_s ("Can't find %s.abc",project_node->pro_fname);
#else
# ifdef _WINDOWS_
			{
			FileTime time;
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path,&time))
				error_s ("Can't find %s.abc",project_node->pro_fname);
			}
# else
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path))
				error_s ("Can't find %s.abc",project_node->pro_fname);
# endif
#endif
			
			file_name[strlen (file_name)-4]='\0';
			
			if (!generate_code_for_project_node (project_node,file_name))
				return 0;
#if ! MACINTOSH && !defined (NO_ASSEMBLE)
			if (!assemble (project_node,file_name))
				return 0;

			strcat (file_name,".s");
			unlink (file_name);
#endif
		}
	}
	return 1;
}

static int project_node_is_s_up_to_date (P_NODE project_node)
{
	FileTime abc_time,s_time;
	
	if (!get_clean_system_time (project_node,".s",&s_time
#if ! MACINTOSH
					,clean_abc_path
#endif
	)){
		if (verbose)
			warning_s ("(%s.s doesn't exist)",project_node->pro_fname);
		return 0;
	}
	
	if (get_abc_time (project_node,&abc_time) && FILE_TIME_LE (s_time,abc_time)){
		if (verbose)
			warning_s ("(%s.s is older than corresponding abc file)",
					   project_node->pro_fname);
		return 0;
	}
	
	if (verbose)
		warning_s ("(%s.s is up to date)",project_node->pro_fname);
	return 1;
}

static int make_project_to_s_files (void)
{
	P_NODE project_node;
	
	for_l (project_node,first_project_node,pro_next){
		if (project_node->pro_up_to_date && !project_node_is_s_up_to_date (project_node)){
			char file_name[PATH_NAME_STRING_SIZE];

#if MACINTOSH
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name))
				error_s ("Can't find %s.abc",project_node->pro_fname);
#else
# ifdef _WINDOWS_
			{
			FileTime time;
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path,&time))
				error_s ("Can't find %s.abc",project_node->pro_fname);
			}
# else
			if (!find_clean_system_file (project_node->pro_fname,".abc",file_name,clean_abc_path))
				error_s ("Can't find %s.abc",project_node->pro_fname);
# endif
#endif
			
			file_name[strlen (file_name)-4]='\0';
			
			if (!generate_code_for_project_node (project_node,file_name))
				return 0;
		}
	}
	return 1;
}

int data [] =
{
#ifdef M68000
	0x00020107, 0x00000000, 0x00000010, 0x00000000,
	0x0000003c, 0x00000000, 0x00000000, 0x00000000,
	0x00200000, 0x00080000, 0x00080000, 0x00000008,
	0x00000004, 0x07000000, 0x0000000c, 0x0000000b,
	0x07000000, 0x00000010, 0x00000014, 0x07000000,
	0x00000000, 0x0000001f, 0x07000000, 0x00000008,
	0x0000002d, 0x07000000, 0x00000004, 0x0000003c,
	0x5f666c61, 0x67730064, 0x6174615f, 0x656e6400,
	0x5f686561, 0x705f7369, 0x7a65005f, 0x635f7374,
	0x61636b5f, 0x73697a65, 0x005f6162, 0x5f737461,
	0x636b5f73, 0x697a6500
#else
# ifdef I486
#  ifdef _WINDOWS_
#   if 0 /* without _ */
      196940,   814507665,         152,          11,
    17104896,  2019914798,         116,           0,
           0,           0,           0,           0,
           0,           0,          32,  1952539694,
          97,           0,           0,          12,
         140,           0,           0,           0,
          64,  1936941614,           0,          12,
          12,           0,           0,           0,
           0,           0,         128,          11,
          21,          31,  1818846766,         101,
           0,       65534,  1634074983,       25963,
           0,           0,           0,           0,
           4,           0,           2,           2,
      917504,      262144,      131072,      131072,
  1734437990,         115,           8,           2,
  1949171714,     7632997,           0,       65536,
    16973824,           0,           0,           0,
           0,  1680736256,     6386785,           0,
      131072,    16973824,          12,           0,
           0,           0,  1647181824,       29555,
           0,      196608,    16973824,           0,
           0,           0,           0,     1835008,
  1701314560,  1935634529,     6650473,  1935630945,
  1801675124,  2053731167,         101
#   else /* with _ */
      196940,   817729185,         152,          11,
    17039360,  2019914798,         116,           0,
           0,           0,           0,           0,
           0,           0,  1610612768,  1952539694,
          97,           0,           0,          12,
         140,           0,           0,           0,
 -1073741760,  1936941614,           0,           0,
          12,           0,           0,           0,
           0,           0, -1073741696,          11,
          21,          31,  1818846766,         101,
           0,       65534,  1634074983,       25963,
           0,           0,           0,  2019914798,
         116,           0,           1,         259,
           0,           0,           0,           0,
  1952539694,          97,           0,           2,
      786691,           0,           0,           0,
           0,  1936941614,           0,          12,
           3,         259,           0,           0,
           0,           0,           0,           4,
           0,           2,           2,      983040,
      262144,      131072,      131072,  1634494047,
       29543,           8,           2,     1966082,
  1751056384,  1601200485,  1702521203,  1650548480,
  1635021663,  1935633251,     6650473
#   endif
#  else
#   ifdef OMF
	 0x0b000d80,0x6974706f,0x2e736e6f,0xf36a626f
	,0x80000688,0x4c4803a1,0x005096ba,0x45540600
	,0x32335458,0x54414406,0x05323341,0x33535342
	,0x24240932,0x424d5953,0x07534c4f,0x59542424
	,0x04534550,0x45444f43,0x54414404,0x53420341
	,0x45440653,0x4d595342,0x42454406,0x04505954
	,0x54414c46,0x52474406,0x7350554f,0xa9000798
	,0x07020000,0x0798ae01,0x000ca900,0xa0010803
	,0xa9000798,0x09040000,0x0798aa01,0x0017a900
	,0x91010a05,0xa9000798,0x0b060000,0x029aa601
	,0x9a580c00,0xff0d0006,0x5002ff03,0x01002a90
	,0x65680902,0x735f7061,0x00657a69,0x610d0000
	,0x74735f62,0x5f6b6361,0x657a6973,0x05000004
	,0x67616c66,0x00000873,0x00048805,0x9101a240
	,0x020010a0,0x00010000,0x00020000,0x00030000
	,0xa0480000,0x00040015,0x01401000,0x20202004
	,0x35100020,0x01170017,0xa02b07cc,0x1104000a
	,0x00110500,0x2b000000,0x4400089d,0xc8011001
	,0x95af8c02,0x01000027,0x00000000,0x00000000
	,0x00000018,0x00000000,0x00000000,0x00000001
	,0x74706f0b,0x736e6f69,0x6a626f2e,0x00028baa
	,0x00007300
#   else
#	 ifdef LINUX_ELF
#     ifdef A_64
	0x464c457f,0x00010102,0x00000000,0x00000000,
	0x003e0001,0x00000001,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000094,0x00000000,
	0x00000000,0x00000040,0x00400000,0x00040007,
	
	0x00000001,0x00000000,0x00000004,0x00000000,
	0x00000005,0x00000000,0x00000002,0x00000000,
	0x00000003,0x00000000,
						  0x79732e00,0x6261746d,
	0x74732e00,0x62617472,0x68732e00,0x74727473,
	0x2e006261,0x74786574,0x61642e00,0x2e006174,
	0x00737362,
			   0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,
			   0x0000001b,0x00000001,0x00000006,
	0x00000000,0x00000000,0x00000000,0x00000040,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000004,0x00000000,0x00000000,
	0x00000000,
			   0x00000021,0x00000001,0x00000003,
	0x00000000,0x00000000,0x00000000,0x00000040,
	0x00000000,0x00000028,0x00000000,0x00000000,
	0x00000000,0x00000004,0x00000000,0x00000000,
	0x00000000,
			   0x00000027,0x00000008,0x00000003,
	0x00000000,0x00000000,0x00000000,0x00000068,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000004,0x00000000,0x00000000,
	0x00000000,
			   0x00000011,0x00000003,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000068,
	0x00000000,0x0000002c,0x00000000,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000000,
	0x00000000,
			   0x00000001,0x00000002,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000254,
	0x00000000,0x000000d8,0x00000000,0x00000006,
	0x00000004,0x00000004,0x00000000,0x00000018,
	0x00000000,
			   0x00000009,0x00000003,0x00000000,
	0x00000000,0x00000000,0x00000000,0x0000032c,
	0x00000000,0x00000044,0x00000000,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000000,
	0x00000000,
			   0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,
									 0x00000000,
	0x00010003,0x00000000,0x00000000,0x00000000,
	0x00000000,
	           0x00000000,0x00020003,0x00000000,
	0x00000000,0x00000000,0x00000000,
		 	 				         0x00000000,
	0x00030003,0x00000000,0x00000000,0x00000000,
	0x00000000,
	           0x00000001,0x00020011,0x00000000,
	0x00000000,0x00000000,0x00000000,
									 0x0000000b,
	0x00020011,0x00000008,0x00000000,0x00000000,
	0x00000000,
	           0x00000019,0x00020011,0x00000010,
	0x00000000,0x00000000,0x00000000,
						     		 0x0000001f,
	0x00020011,0x00000018,0x00000000,0x00000000,
	0x00000000,
	           0x00000032,0x00020011,0x00000020,
	0x00000000,0x00000000,0x00000000,
									 0x61656800,
	0x69735f70,0x6100657a,0x74735f62,0x5f6b6361,
	0x657a6973,0x616c6600,0x68007367,0x5f706165,
	0x657a6973,0x6c756d5f,0x6c706974,0x6e690065,
	0x61697469,0x65685f6c,0x735f7061,0x00657a69
#     else
	0x464c457f,0x00010101,0x00000000,0x00000000,
	0x00030001,0x00000001,0x00000000,0x00000000,
	0x00000074,0x00000000,0x00000034,0x00280000,
	0x00040007,0x00000001,0x00000004,0x00000005,
	0x00000002,0x00000003,0x79732e00,0x6261746d,
	0x74732e00,0x62617472,0x68732e00,0x74727473,
	0x2e006261,0x74786574,0x61642e00,0x2e006174,
	0x00737362,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x0000001b,
	0x00000001,0x00000006,0x00000000,0x00000034,
	0x00000000,0x00000000,0x00000000,0x00000004,
	0x00000000,0x00000021,0x00000001,0x00000003,
	0x00000000,0x00000034,0x00000014,0x00000000,
	0x00000000,0x00000004,0x00000000,0x00000027,
	0x00000008,0x00000003,0x00000000,0x00000048,
	0x00000000,0x00000000,0x00000000,0x00000004,
	0x00000000,0x00000011,0x00000003,0x00000000,
	0x00000000,0x00000048,0x0000002c,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000001,
	0x00000002,0x00000000,0x00000000,0x0000018c,
	0x00000090,0x00000006,0x00000004,0x00000004,
	0x00000010,0x00000009,0x00000003,0x00000000,
	0x00000000,0x0000021c,0x00000044,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00010003,0x00000000,
	0x00000000,0x00000000,0x00020003,0x00000000,
	0x00000000,0x00000000,0x00030003,0x00000001,
#      if 0
	0x00000000,0x00000000,0x00020011,0x0000000b,
	0x00000004,0x00000000,0x00020011,0x00000019,
	0x00000008,0x00000000,0x00020011,0x0000001f,
	0x0000000c,0x00000000,0x00020011,0x00000032,
	0x00000010,0x00000000,0x00020011,0x61656800,
#      else
	/* st_other = STV_HIDDEN */
	0x00000000,0x00000000,0x00020211,0x0000000b,
	0x00000004,0x00000000,0x00020211,0x00000019,
	0x00000008,0x00000000,0x00020211,0x0000001f,
	0x0000000c,0x00000000,0x00020211,0x00000032,
	0x00000010,0x00000000,0x00020211,0x61656800,
#      endif
	0x69735f70,0x6100657a,0x74735f62,0x5f6b6361,
	0x657a6973,0x616c6600,0x68007367,0x5f706165,
	0x657a6973,0x6c756d5f,0x6c706974,0x6e690065,
	0x61697469,0x65685f6c,0x735f7061,0x00657a69
#     endif
#	 else
#     ifdef MACH_O64
	0xfeedfacf,0x01000007,0x00000003,0x00000001,
	0x00000003,0x00000150,0x00000000,0x00000000,
	0x00000019,0x000000e8,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000028,0x00000000,0x00000170,0x00000000,
	0x00000028,0x00000000,0x00000007,0x00000007,
	0x00000002,0x00000000,0x65745f5f,0x00007478,
	0x00000000,0x00000000,0x45545f5f,0x00005458,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000170,0x00000000,
	0x00000000,0x00000000,0x80000000,0x00000000,
	0x00000000,0x00000000,0x61645f5f,0x00006174,
	0x00000000,0x00000000,0x41445f5f,0x00004154,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000028,0x00000000,0x00000170,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000002,0x00000018,
	0x00000198,0x00000005,0x000001e8,0x0000004c,
	0x0000000b,0x00000050,0x00000000,0x00000000,
	0x00000000,0x00000005,0x00000005,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000001,0x00000000,0x00000002,0x00000000,
	0x00000003,0x00000000,0x00000004,0x00000000,
	0x00000005,0x00000000,0x00000026,0x0000020f,
	0x00000018,0x00000000,0x00000001,0x0000020f,
	0x00000000,0x00000000,0x0000001b,0x0000020f,
	0x00000010,0x00000000,0x00000035,0x0000020f,
	0x00000020,0x00000000,0x00000008,0x0000020f,
	0x00000008,0x00000000,0x6c665f00,0x00736761,
	0x696e695f,0x6c616974,0x6165685f,0x69735f70,
	0x5f00657a,0x70616568,0x7a69735f,0x615f0065,
	0x74735f62,0x5f6b6361,0x657a6973,0x65685f00,
	0x735f7061,0x5f657a69,0x746c756d,0x656c7069,
	0x00000000
#     else
	0x00640107,0x00000000,0x0000000c,0x00000000,
	0x00000024,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000004,
	0x00000007,0x00000000,0x0000000f,0x00000007,
	0x00000004,0x0000001e,0x00000007,0x00000008,
	0x00000025,0x6165685f,0x69735f70,0x5f00657a,
	0x735f6261,0x6b636174,0x7a69735f,0x665f0065,
	0x7367616c,0x00000000
#     endif
#    endif
#   endif
#  endif
# else
#  if defined (SOLARIS)
	0x7f454c46,0x01020100,0x00000000,0x00000000,
	0x00010002,0x00000001,0x00000000,0x00000000,
	0x000000ec,0x00000000,0x00340000,0x00000028,
	0x00050001,0x002e7368,0x73747274,0x6162002e,
	0x64617461,0x002e7379,0x6d746162,0x002e7374,
	0x72746162,0x00000000,0x00000001,0x00000002,
	0x00000003,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000001,0x0000000c,0x00000000,
	0x00000002,0x00000000,0x00000000,0x00000000,
	0x03000002,0x0000000a,0x00000000,0x00000000,
	0x10000002,0x00000014,0x00000004,0x00000000,
	0x10000002,0x00000022,0x00000008,0x00000000,
	0x10000002,0x00646174,0x615f656e,0x64006865,
	0x61705f73,0x697a6500,0x61625f73,0x7461636b,
	0x5f73697a,0x6500666c,0x61677300,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000001,0x00000003,0x00000000,
	0x00000000,0x00000034,0x00000021,0x00000000,
	0x00000000,0x00000001,0x00000000,0x0000000b,
	0x00000001,0x00000003,0x00000000,0x00000058,
	0x0000000c,0x00000000,0x00000000,0x00000004,
	0x00000000,0x00000011,0x00000002,0x00000002,
	0x00000000,0x00000064,0x00000060,0x00000004,
	0x00000003,0x00000004,0x00000010,0x00000019,
	0x00000003,0x00000002,0x00000000,0x000000c4,
	0x00000028,0x00000000,0x00000000,0x00000001,
	0x00000000
#  else
#   ifdef LINUX
	0x7f454c46,0x01020100,0x00000000,0x00000000,
	0x00010014,0x00000001,0x00000000,0x00000000,
	0x00000074,0x00000000,0x00340000,0x00000028,
	0x00070004,0x00000008,0x00200000,0x00080000,
	0x00001400,0x00019000,0x002e7379,0x6d746162,
	0x002e7374,0x72746162,0x002e7368,0x73747274,
	0x6162002e,0x74657874,0x002e6461,0x7461002e,
	0x62737300,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x0000001b,
	0x00000001,0x00000006,0x00000000,0x00000034,
	0x00000000,0x00000000,0x00000000,0x00000001,
	0x00000000,0x00000021,0x00000001,0x00000003,
	0x00000000,0x00000034,0x00000014,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000027,
	0x00000008,0x00000003,0x00000000,0x00000048,
	0x00000000,0x00000000,0x00000000,0x00000001,
	0x00000000,0x00000011,0x00000003,0x00000000,
	0x00000000,0x00000048,0x0000002c,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000001,
	0x00000002,0x00000000,0x00000000,0x0000018c,
	0x00000090,0x00000006,0x00000004,0x00000004,
	0x00000010,0x00000009,0x00000003,0x00000000,
	0x00000000,0x0000021c,0x00000041,0x00000000,
	0x00000000,0x00000001,0x00000000,0x00000000,
	0x00000000,0x00000000,0x00000000,0x00000000,
	0x00000000,0x00000000,0x03000001,0x00000000,
	0x00000000,0x00000000,0x03000002,0x00000000,
	0x00000000,0x00000000,0x03000003,0x00000001,
	0x00000000,0x00000000,0x11000002,0x00000007,
	0x00000004,0x00000000,0x11000002,0x00000011,
	0x00000008,0x00000000,0x11000002,0x0000001c,
	0x0000000c,0x00000000,0x11000002,0x0000002f,
	0x00000010,0x00000000,0x11000002,0x00666c61,
	0x67730068,0x6561705f,0x73697a65,0x00737461,
	0x636b5f73,0x697a6500,0x68656170,0x5f73697a,
	0x655f6d75,0x6c746970,0x6c650069,0x6e697469,
	0x616c5f68,0x6561705f,0x73697a65,0x00
#   else
	0x01030107,0x00000000,0x00000010,0x00000000,
	0x0000003c,0x00000000,0x00000000,0x00000000,
	0x00200000,0x00080000,0x00080000,0x00000008,
	0x00000004,0x07000000,0x00000008,0x00000012,
	0x07000000,0x0000000c,0x00000019,0x07000000,
	0x00000004,0x00000028,0x07000000,0x00000000,
	0x00000033,0x07000000,0x00000010,0x0000003c,
	0x5f635f73,0x7461636b,0x5f73697a,0x65005f66,
	0x6c616773,0x005f6162,0x5f737461,0x636b5f73,
	0x697a6500,0x5f686561,0x705f7369,0x7a650064,
	0x6174615f,0x656e6400
#   endif
#  endif
# endif
#endif
};

#define COMMENT_CHAR '#'

static char *parse_word (char **line_h)
{
    char *begin,*end;
	int c;

    begin=*line_h;
	while ((c = (*begin=='\\' && *(begin+1)!='\0') ? * ++begin : *begin),isspace (c))
		++begin;

    if (*begin==COMMENT_CHAR || *begin=='\0')
        return NULL;

    for (end=begin; !isspace ((int) *end) && *end!='\0'; ++end)
        if (*end=='\\' && *(end+1)!='\0')
            ++end;

    if (*end=='\0')
        *line_h = end;
    else {
        *line_h = end+1;
        *end = '\0';
    }

    return begin;
}

long ab_stack_size,heap_size,flags;

#ifdef MARKING_GC
long heap_size_multiple=20<<8,initial_heap_size=100<<10;
#endif

#if ! MACINTOSH
int create_options_file (char **options_file_name_p)
{
	char *options_file_name;
	FILE *f;
	unsigned int data_size;

#if defined (_WINDOWS_) || defined (OS2)
	options_file_name="cgopt.$$$";

# ifdef OMF
	{
		char *p;
		
		for (p=options_file_name; *p; ++p)
			if (*p=='/')
				*p='\\';
	}
# endif

	f=fopen (options_file_name,"wb");
#else
	{
	static char cgopt_file_name[]="/tmp/cgoptXXXXXX";
	int options_fd;

	options_fd=mkstemp (cgopt_file_name);
	if (options_fd<0)
		return 0;

	options_file_name=cgopt_file_name;
	
	f=fdopen (options_fd,"wb");
	}
#endif
	if (f==NULL)
		error_s ("Can't create options file %s",options_file_name);

#if defined (SOLARIS)
	data[22]=heap_size;
	data[23]=ab_stack_size;
	data[24]=flags;
	data_size=sizeof (data);
#else
# if defined (LINUX_ELF)
#  ifdef A_64
	data[16]=heap_size;
	data[18]=ab_stack_size;
	data[20]=flags;
	data[22]=heap_size_multiple;
	data[24]=initial_heap_size;
#  else
	data[13]=heap_size;
	data[14]=ab_stack_size;
	data[15]=flags;
	data[16]=heap_size_multiple;
	data[17]=initial_heap_size;
#  endif
	data_size=sizeof (data);
# elif defined (LINUX) && defined (POWERPC)
	data[13]=flags;
	data[14]=heap_size;
	data[15]=ab_stack_size;
	data[16]=heap_size_multiple;
	data[17]=initial_heap_size;
	data_size=sizeof (data);
# else
#  ifdef _WINDOWS_
	data[35]=heap_size;
	data[36]=ab_stack_size;
	data[37]=flags;
#   if 0 /* without _ */
	data_size=sizeof (data)-2;
#   else /* with _ */
	data_size=sizeof (data);
#   endif
#  else
#   ifdef MACH_O64
	data[92]=flags;
	data[94]=initial_heap_size;
	data[96]=heap_size;
	data[98]=ab_stack_size;
	data[100]=heap_size_multiple;
	data_size=sizeof (data);
#   else
#    ifdef OMF
	*(long*)((char*)data+230)=heap_size;
	*(long*)((char*)data+234)=ab_stack_size;
	*(long*)((char*)data+238)=flags;
	data_size=sizeof (data)-2;
#    else
	data[8]=heap_size;
	data[9]=ab_stack_size;
#     ifdef I486
	data[10]=flags;
	data_size=sizeof (data)-3;
#     else
	data[10]=512<<10;
	data[11]=flags;
	data_size=sizeof (data);
#     endif
#    endif
#   endif
#  endif
# endif
#endif
	
	if (fwrite (data,1,data_size,f)!=data_size){
		fclose (f);
		unlink (options_file_name);
		error ("Error writing options file");
	}
	
	if (fclose (f)!=0){
		unlink (options_file_name);
		error ("Error writing options file");
	}
	
	*options_file_name_p=options_file_name;
	return 1;
}
#else

#include <Resources.h>

static void remove_resources (ResType resource_type)
{
	SetResLoad (0);
	while (Count1Resources (resource_type)>0){
		Handle resource;
		
		resource=Get1IndResource (resource_type,1);
		if (resource==NULL || ResError()){
			SetResLoad (1);
			error ("Error while removing resources from application file");
		}
		
		RmveResource (resource);
		if (ResError()){
			SetResLoad (1);
			error ("Error while removing resources from application file");
		}
	}
	SetResLoad (1);
}

static int add_stack_and_size_resource_to_resource_file (void)
{
	Handle size_handle;
	unsigned short *size_p;
	Handle stack_handle;
	unsigned long *stack_p;
	unsigned long size;

	remove_resources ('SIZE');
	remove_resources ('STCK');

	stack_handle=NewHandle (16);
	if (stack_handle==NULL)
		return 0;
	
	size_handle=NewHandle (10);
	if (size_handle==NULL){
		DisposeHandle (stack_handle);
		return 0;
	}
	
	stack_p=(unsigned long*)*stack_handle;
	*stack_p++=ab_stack_size;
	*stack_p++=0;
	*stack_p++=heap_size;
	*stack_p=flags;

	size_p=(unsigned short*)*size_handle;
	*size_p++=0;
	size = ab_stack_size + heap_size + 160*1024;
	size = (size+3l) & ~3l;
	*(*(unsigned long**)&size_p)++= size;
	*(*(unsigned long**)&size_p)++= size;

	AddResource (stack_handle,'STCK',0,(ConstStr255Param)"\p");
	if (ResError()){
		DisposeHandle (stack_handle);
		DisposeHandle (size_handle);
		return 0;
	}
	
	AddResource (size_handle,'SIZE',-1,(ConstStr255Param)"\p");
	if (ResError()){
		ReleaseResource (stack_handle);
		DisposeHandle (size_handle);
		return 0;
	}

	ReleaseResource (stack_handle);
	if (ResError()){
		ReleaseResource (size_handle);
		return 0;
	}

	ReleaseResource (size_handle);
	if (ResError())
		return 0;
	
	return 1;
}

static int add_stack_and_size_resource_to_application (char *application_file_name)
{
	int resource_file_n,error;
	char resource_file_name[256];

	if (application_file_name!=NULL)
		copy_c_to_p_string (application_file_name,resource_file_name);
	else
		copy_c_to_p_string ("hd:desktop folder:a",resource_file_name);

	resource_file_n=HOpenResFile (0,0,(ConstStr255Param)resource_file_name,fsRdWrPerm);
	if (resource_file_n==-1)
		return 0;

	error=add_stack_and_size_resource_to_resource_file();

	CloseResFile (resource_file_n);
	if (ResError())
		return 0;
	
	return error;	
}
#endif

#if MACINTOSH && !defined (G_POWER)
extern int link_application_argc_argv (int,char **);
#endif

#ifdef OPTIMISE_LINK
static char *linker_output_object_file_name;
static int no_optimise_link;
#endif

static int stack_trace;

static char **add_imported_object_files (P_NODE first_project_node,char *o_file_name,char **arg)
{
	P_NODE project_node;

	for_l (project_node,first_project_node,pro_next){
		struct object_file_list *imported_object_file;
		char *file_name;

		for_l (imported_object_file,project_node->pro_imported_object_files,object_file_next){
# ifdef _WINDOWS_
			FileTime time;
# endif

			/* use "Clean System Files/" as file name and the object file name as extension: */
			if (!find_file ("Clean System Files" DIRECTORY_SEPARATOR_STRING,imported_object_file->object_file_name,
# if MACINTOSH
							o_file_name
# else
							o_file_name,clean_o_path!=NULL ? clean_o_path : clean_abc_path
#  ifdef _WINDOWS_
				,&time
#  endif
# endif
			))
			{
				error_s_s ("Can't find object file %s imported from %s",
							imported_object_file->object_file_name,project_node->pro_fname);
			}

			file_name=memory_allocate (strlen (o_file_name)+1);

			strcpy (file_name,o_file_name);
			*arg++=file_name;
		}
	}
	return arg;
}

static int link_project (P_NODE first_project_node,char *options_file_name,char *application_file_name)
{
	P_NODE project_node;
	char o_file_name[PATH_NAME_STRING_SIZE],system_file_name[PATH_NAME_STRING_SIZE];
	char *argv[1024],**arg;
	struct library_list *library;
	struct export_list *export;
	struct export_file_list *export_file;

# if (defined (_WINDOWS_) && !defined (USE_WLINK)) || defined (OMF)
#  if defined (NO_CLIB)
	char startup0_file_name[PATH_NAME_STRING_SIZE];
#  endif
	char startup1_file_name[PATH_NAME_STRING_SIZE],startup2_file_name[PATH_NAME_STRING_SIZE];
# else
	char start_up_file_name[PATH_NAME_STRING_SIZE];
# endif
# ifdef sparc
	char reals_file_name[PATH_NAME_STRING_SIZE];
# endif
# ifdef OS2
	char clean_resources_file_name[PATH_NAME_STRING_SIZE], clean_def_file_name[PATH_NAME_STRING_SIZE],appl_file_name[PATH_NAME_STRING_SIZE];
#  ifndef OMF
	char os2_interface_file_name[PATH_NAME_STRING_SIZE];
#  endif
#  ifdef NO_CLIB
	char os2lib_file_name[PATH_NAME_STRING_SIZE];
#  endif
	int l;
# endif
# if defined (_WINDOWS_) && defined (USE_WLINK)
	char w_crt0_file_name[PATH_NAME_STRING_SIZE];
# endif
# if defined (_WINDOWS_) || defined (OS2)
	char stack_option[32];
# endif	
# if defined (USE_CLEANLINKER)
	char kernel32_file_name[PATH_NAME_STRING_SIZE];
	char user32_file_name[PATH_NAME_STRING_SIZE];
	char gdi32_file_name[PATH_NAME_STRING_SIZE];
# endif
# ifdef SOLARIS
        char crt [128], crti [128], crtn [128];
# endif
 
	if (!silent)
		printf ("Linking %s\n",main_project_node->pro_fname);

# ifdef OPTIMISE_LINK
	if (!no_optimise_link){
	{
	static char linker_output_file_name[]="/tmp/linkerXXXXXX";
	int linker_output_fd;

	linker_output_fd=mkstemp (linker_output_file_name);
	if (linker_output_fd<0){
		error_s ("Can't create %s",linker_output_file_name);
		return 0;
	}
	close (linker_output_fd);
	linker_output_object_file_name=linker_output_file_name;
	}

	arg=argv;

	*arg++="linker";

	*arg++=linker_output_object_file_name;

	if ((clean_options & NO_TIME_PROFILE_MASK)!=0)
		need_file ("_startup",OBJECT_FILE_EXTENSION,start_up_file_name);
	else if (stack_trace)
		need_file ("_startupTrace",OBJECT_FILE_EXTENSION,start_up_file_name);
	else
		need_file ("_startupProfile",OBJECT_FILE_EXTENSION,start_up_file_name);
	*arg++=start_up_file_name;

	need_file ("_system",OBJECT_FILE_EXTENSION,system_file_name);
	*arg++=system_file_name;

	for_l (project_node,first_project_node,pro_next){
		if (project_node->pro_up_to_date && !project_node->pro_ignore_o){
			char *file_name;

			if (!find_clean_system_file (project_node->pro_fname,OBJECT_FILE_EXTENSION,o_file_name,
							clean_o_path!=NULL ? clean_o_path : clean_abc_path
			))
			{
				error_s ("Can't find %s.o",project_node->pro_fname);
			}

			file_name=memory_allocate (strlen (o_file_name)+1);
		
			strcpy (file_name,o_file_name);
			*arg++=file_name;
		}
	}

	arg = add_imported_object_files (first_project_node,o_file_name,arg);
	
	for_l (library,first_library,library_next){
		int s;

		s=strlen (library->library_file_name);
		if (s>=2 && library->library_file_name[0]!=':' && library->library_file_name[s-2]=='.' && library->library_file_name[s-1]=='o')
			*arg++=library->library_file_name;
	}

	for_l (export,first_export,export_next){
		*arg++="-e";
		*arg++=export->export_name;
	}

	for_l (export_file,first_export_file,export_file_next){
		*arg++="-E";
		*arg++=export_file->export_file_name;
	}

	*arg=NULL;

	{
	int pid,r,status;

# if 0
	char **a;

	a=argv;
	while (*a){
		printf ("%s\n",*a);
		++a;
	}
# endif

	pid=fork();
	if (pid<0)
		error ("Fork failed");
	
	if (!pid){
		char linker_file_name_[PATH_NAME_STRING_SIZE];

		strcpy (linker_file_name_,clean_lib_path);
		strcat (linker_file_name_,"/linker");

		execv (linker_file_name_,argv);
		
		error ("Can't execute the linker");
	}
	
	r=wait_for_child (pid, "Linker",&status);

	if (!(r>=0 && status==0))
		return 0;
	}
	}
#endif
	
	arg=argv;

# ifdef USE_WLINK
	*arg++="wlink";
	*arg++="sys";
	*arg++="nt";
	*arg++="op";
	*arg++="c";
	*arg++="op";
	*arg++="q";
	*arg++="op";
	sprintf (stack_option,"stack=%dk",(ab_stack_size+1023) >> 10);
	*arg++=stack_option;
# else
#  ifdef OMF
	*arg++="link386";
	*arg++="/bat";
	*arg++="/nol";
	*arg++="/noe";
	*arg++="/noi";
	*arg++="/nod";
	*arg++="/base:0x10000";
	sprintf (stack_option,"/st:%ld",(long)ab_stack_size);
	*arg++=stack_option;
#  else
#   ifdef USE_CLEANLINKER
	*arg++="linker";
#   else
	*arg++=linker_file_name;
#   endif
#  endif
# endif

    {
        static char ld_args_copy[PATH_LIST_STRING_SIZE];
        char *rest,*ld_arg;

        rest = strcpy (ld_args_copy,ld_args);
        while ((ld_arg=parse_word (&rest))!=NULL)
            *arg++=ld_arg;
    }

# ifdef M68000
	*arg++="-N";
# endif

# if !defined (I486) && !MACINTOSH && !defined (SOLARIS) && !defined (LINUX)
	*arg++="-e";
	*arg++="start";
	*arg++="-dc";
	*arg++="-dp";
# endif

# if !MACINTOSH
#  if !(defined (USE_WLINK) || defined (OMF) || defined (USE_CLEANLINKER))
	if (remove_symbol_table)
		*arg++="-s";
#  endif
#  ifdef OS2
#   ifndef OMF
	*arg++ = "-o";
	l=strlen (application_file_name);

	if (l > 4 && strcmp (&application_file_name[l-4],".exe")==0)
		*arg++=application_file_name;
	else {
		strcpy (appl_file_name,application_file_name);
		strcat (appl_file_name,".exe");
		*arg++=appl_file_name;
	}
#   endif
#  else
	if (application_file_name!=NULL){
#   ifdef USE_WLINK
		*arg++="name";
#   else
		*arg++="-o";
#   endif
		*arg++=application_file_name;
	}
#   if defined (_WINDOWS_) && !defined (USE_CLEANLINKER)
	else {
#    ifdef USE_WLINK
		*arg++="name";
		*arg++="a";
#    else 
		*arg++="-o";
		*arg++="a.exe";
#    endif
	}
#   endif
#  endif
#  if defined (OS2) && !defined (OMF)
	*arg++=gcc_lib_directory_arg;
#  endif

#  ifndef NO_CLIB
#   ifdef USE_WLINK
	*arg++="file";
	strcpy (w_crt0_file_name,clean_lib_path);
	strcat (w_crt0_file_name,"\\crt0.obj");
	*arg++=w_crt0_file_name;
#   else
#    ifdef OMF
	*arg++="e:\\emx\\lib\\crt0.obj";
#    else
#     ifndef LINUX
#      ifdef SOLARIS
		if ((clean_options & NO_TIME_PROFILE_MASK)!=0)
			need_file ("_startup",OBJECT_FILE_EXTENSION,start_up_file_name);
		else if (stack_trace)
			need_file ("_startupTrace",OBJECT_FILE_EXTENSION,start_up_file_name);
		else		
			need_file ("_startupProfile",OBJECT_FILE_EXTENSION,start_up_file_name);

		strcpy (crt,start_up_file_name);
		replace_file_name_in_path (crt,"crt",OBJECT_FILE_EXTENSION);
		*arg++=crt;

		strcpy (crti,start_up_file_name);
		replace_file_name_in_path (crti,"crti",OBJECT_FILE_EXTENSION);
		*arg++=crti;
#      else
	*arg++=crt0_file_name;
#      endif
#     endif
#    endif
#   endif
#  endif

#  ifdef M68000
	*arg++=Mcrt1_file_name;
#  endif
# endif

# ifdef OPTIMISE_LINK
	if (!no_optimise_link)
		*arg++ = linker_output_object_file_name;
	else {
# endif

# if (defined (_WINDOWS_) && !defined (USE_WLINK)) || defined (OMF)
#  ifdef NO_CLIB
	strcpy (startup0_file_name,clean_lib_path);
	strcat (startup0_file_name,"\\_startup0" OBJECT_FILE_EXTENSION);
	*arg++=startup0_file_name;
#  endif
#  ifdef OS2
	{
		P_NODE project_node;

		for_l (project_node,first_project_node,pro_next)
			if (!strcmp (project_node->pro_fname,"_startup1"))
				break;
		if (project_node==NULL){
#  endif
	strcpy (startup1_file_name,clean_lib_path);
	strcat (startup1_file_name,"\\_startup1" OBJECT_FILE_EXTENSION);
	*arg++=startup1_file_name;
#  ifdef OS2
		}
	}
	{
		P_NODE project_node;

		for_l (project_node,first_project_node,pro_next)
			if (!strcmp (project_node->pro_fname,"_startup2"))
				break;
		if (project_node==NULL){
#  endif
	strcpy (startup2_file_name,clean_lib_path);
	strcat (startup2_file_name,"\\_startup2" OBJECT_FILE_EXTENSION);
	*arg++=startup2_file_name;
#  ifdef OS2
		}
	}
#  endif
# else
#  if !(!defined (LINUX) && defined (SOLARIS))
	if ((clean_options & NO_TIME_PROFILE_MASK)!=0)
		need_file ("_startup",OBJECT_FILE_EXTENSION,start_up_file_name);
	else if (stack_trace)
		need_file ("_startupTrace",OBJECT_FILE_EXTENSION,start_up_file_name);
	else
		need_file ("_startupProfile",OBJECT_FILE_EXTENSION,start_up_file_name);
#  endif
	*arg++=start_up_file_name;
# endif	

# ifdef OS2
	{
		P_NODE project_node;

		for_l (project_node,first_project_node,pro_next)
			if (!strcmp (project_node->pro_fname,"_system"))
				break;
		if (project_node==NULL){
# endif
	need_file ("_system",OBJECT_FILE_EXTENSION,system_file_name);
	*arg++=system_file_name;
# ifdef OS2
		}
	}
# endif

	for_l (project_node,first_project_node,pro_next){
		if (project_node->pro_up_to_date && !project_node->pro_ignore_o){
			char *file_name;
# ifdef _WINDOWS_
			FileTime time;
# endif

# if ! MACINTOSH
			if (!find_clean_system_file (project_node->pro_fname,OBJECT_FILE_EXTENSION,o_file_name,
							clean_o_path!=NULL ? clean_o_path : clean_abc_path
#  ifdef _WINDOWS_
				,&time
#  endif
			))
			{
				error_s ("Can't find %s.o",project_node->pro_fname);
			}
# else
			if (!find_clean_system_file (project_node->pro_fname,OBJECT_FILE_EXTENSION,o_file_name))
				error_s ("Can't find %s" OBJECT_FILE_EXTENSION,project_node->pro_fname);
# endif
				
			file_name=memory_allocate (strlen (o_file_name)+1);
		
			strcpy (file_name,o_file_name);
# ifdef USE_WLINK
			*arg++="file";
# endif
			*arg++=file_name;
		}
	}

	arg = add_imported_object_files (first_project_node,o_file_name,arg);

# ifdef OPTIMISE_LINK
	}
# endif

#ifndef OS2
	for_l (library,first_library,library_next){
# ifdef OPTIMISE_LINK
		if (!no_optimise_link){
			int s;

			if (library->library_file_name[0]==':')
				*arg++=&library->library_file_name[1];
			else
				if (s=strlen (library->library_file_name), ! (s>=2 && library->library_file_name[s-2]=='.' && library->library_file_name[s-1]=='o'))
					*arg++=library->library_file_name;
		} else
# endif
		*arg++=library->library_file_name;
	}
#endif

# if MACINTOSH
#  if 1
	{
	char library_obj_file_name[PATH_NAME_STRING_SIZE];

	strcpy (library_obj_file_name,clean_lib_path);
	strcat (library_obj_file_name,":Clean System Files:_library" OBJECT_FILE_EXTENSION);
	*arg++=library_obj_file_name;
	*arg=NULL;

	return link_application_argc_argv (arg-argv,argv)==0;
	}
#  else
	{
	char **argument;
	
	if (application_file_name!=NULL)
		printf ("linker %s ",application_file_name);
	else
		printf ("linker a.out");
	
	for (argument=argv; argument!=arg; ++argument)
		printf ("[partial]\n \'%s\'",*argument);

	printf ("[partial]\n \'%s:Clean System Files:_library.obj2\'\n",clean_lib_path);

	return 1;
	}
#  endif
# else
#  if defined (OS2) && !defined (OMF)
	if (window_application){
		strcpy (clean_resources_file_name,clean_lib_path);
		strcat (clean_resources_file_name,"\\clean.res");
		*arg++ = clean_resources_file_name;
		strcpy (clean_def_file_name,clean_lib_path);
		strcat (clean_def_file_name,"\\clean.def");
		*arg++ = clean_def_file_name;
		strcpy (os2_interface_file_name,clean_lib_path);
		strcat (os2_interface_file_name,"\\os2interface.lib");
		*arg++ = os2_interface_file_name;
	}
#  endif

#  ifdef USE_WLINK
	*arg++="file";
#  endif
	*arg++=options_file_name;

#  ifdef sparc
	strcpy (reals_file_name,start_up_file_name);\
	replace_file_name_in_path (reals_file_name,"_reals",OBJECT_FILE_EXTENSION);
	*arg++=reals_file_name;
#  endif

#  if defined(_WINDOWS_) && !defined (USE_WLINK) && !defined (USE_CLEANLINKER)
	*arg++="-Lc:\\Gnu\\lib";
#  endif

#  if defined (sparc) || (defined (I486) || defined (LINUX) && !defined (USE_WLINK) && !defined (OMF) && !defined (USE_CLEANLINKER))
	*arg++="-lm";
#  endif

#  ifdef OS2
#   ifdef OMF
	*arg++=",";
	*arg++=application_file_name;
	*arg++=",";
	*arg++=",";
#    ifndef NO_CLIB
	*arg++="e:\\emx\\lib\\gcc.lib";
	*arg++="e:\\emx\\lib\\st\\c.lib";
	*arg++="e:\\emx\\lib\\st\\c_app.lib";
	*arg++="e:\\emx\\lib\\st\\sys.lib";
#    endif

#    ifdef OS2
	for_l (library,first_library,library_next)
		*arg++=library->library_file_name;
#    endif

#    ifdef NO_CLIB
	strcpy (os2lib_file_name,clean_lib_path);
	strcat (os2lib_file_name,"\\os2.lib");
	*arg++=os2lib_file_name;
#    else
	*arg++="e:\\emx\\lib\\os2.lib";
#    endif

	*arg++=",";
	strcpy (clean_def_file_name,clean_lib_path);
	if (!window_application)
		strcat (clean_def_file_name,"\\text.def");
	else
		strcat (clean_def_file_name,"\\clean.def");
	*arg++ = clean_def_file_name;
	*arg++=",";
#   else
	*arg++="-lgcc";
	*arg++="-lst/c";
	*arg++="-lst/c_app";
	*arg++="-lst/c_import";
	*arg++="-lst/emx";
	*arg++="-lemx2";
	*arg++="-los2";
#   endif
#  else
#   ifndef USE_WLINK
#    if defined (_WINDOWS_) && !defined (USE_WLINK)
#     ifndef NO_CLIB
	*arg++="-lgcc";
	*arg++="-lc";
#     endif
#     if defined (USE_CLEANLINKER)
	strcpy (kernel32_file_name,"-l");
	strcat (kernel32_file_name,clean_lib_path);
	strcat (kernel32_file_name,"\\kernel_library");
	*arg++ = kernel32_file_name;
	strcpy (user32_file_name,"-l");
	strcat (user32_file_name,clean_lib_path);
	strcat (user32_file_name,"\\user_library");
	*arg++ = user32_file_name;
	strcpy (gdi32_file_name,"-l");
	strcat (gdi32_file_name,clean_lib_path);
	strcat (gdi32_file_name,"\\gdi_library");
	*arg++ = gdi32_file_name;
#     else
	*arg++="-lkernel32";
#     endif
#     ifndef NO_CLIB
	*arg++="-ladvapi32";
	*arg++="-luser32";
	*arg++="-lgcc";
#     endif
#    else	
	*arg++="-lc";
#     ifdef SOLARIS
	strcpy (crtn,start_up_file_name);
	replace_file_name_in_path (crtn,"crtn",OBJECT_FILE_EXTENSION);
	*arg++=crtn;
#     endif
#    endif
#   endif
#  endif

	*arg=NULL;

#  if defined (OS2) || defined (_WINDOWS_)
	{
	int r;

#   ifdef _WINDOWS_
#    ifdef GNU_C
	{
		int status;

		argv[0]=linker_file_name;
		r=spawnvp (P_WAIT,linker_file_name,argv);
		if (r>=0)
			r=wait (&status);

		return r>=0 && status==0;
	}
#    else
	r=spawnvp (P_WAIT,linker_file_name,argv);
#    endif
#   else
	r=dos_exec (linker_file_name,argv,1);
#   endif

	return r==0;
	}
#  else
	{
	int pid,r,status;

	pid=fork();
	if (pid<0)
		error ("Fork failed");
	
	if (!pid){
		execv (linker_file_name,argv);
		
		error ("Can't execute the linker");
	}
	
	r=wait_for_child (pid, "Linker",&status);

#   ifdef OPTIMISE_LINK
	if (!no_optimise_link)
		unlink (linker_output_object_file_name);
#   endif

	return r>=0 && status==0;
	}
#  endif
# endif
}

static void print_version (void)
{
	printf (
		"Clean Compiler 1.2.6/0.%03d/1.2\n"
		"Copyright (C) 1987-1997 University of Nijmegen and HILT - High Level Software Tools B.V.\n"
		,VERSION
	);
}

static void print_version_and_variables (void)
{
    fprintf (stderr, "clm - Clean make - version %s\n\n", CLM_VERSION);
#if defined (I486) && defined (DOS)
    fprintf (stderr,"\tclean_lib_directory = \n\t\t%s\n", clean_lib_directory);
    fprintf (stderr,"\tassembler_file_name =\n\t\t%s\n", assembler_file_name);
    fprintf (stderr,"\tlinker_file_name =\n\t\t%s\n", linker_file_name);
    fprintf (stderr,"\tcrt0_file_name =\n\t\t%s\n", crt0_file_name);
    fprintf (stderr,"\tgcc_lib_directory_arg =\n\t\t%s\n", gcc_lib_directory_arg);
#else
    fprintf (stderr,"\tclean_lib_directory =\n\t\t%s\n", clean_lib_directory);
    fprintf (stderr,"\tclean_default_path_list =\n\t\t%s\n", clean_directory_list);
    fprintf (stderr,"\tclean_include_library_directory =\n\t\t%s\n", clean_include_library_directory);
	fprintf (stderr,"\tassembler_file_name =\n\t\t%s\n", assembler_file_name);
    fprintf (stderr,"\tlinker_file_name =\n\t\t%s\n", linker_file_name);
    fprintf (stderr,"\tcrt0_file_name =\n\t\t%s\n", crt0_file_name);
    fprintf (stderr,"\tld_args =\n\t\t%s\n", ld_args);
#endif

#ifdef M68000
    fprintf (stderr, "\tMcrt1_file_name =\n\t\t%s\n", Mcrt1_file_namee);
#endif
}

static void argument_error (void)
{
	fprintf (stderr, "clm - Clean make - version %s\n", CLM_VERSION);
	printf ("\nUsage:\n");
	printf ("  clm [options] module_name [-o application_name]\n");
	printf ("\nPath options:\n");
	printf ("  -I <path>     Append <path> to the search path\n");
	printf ("  -IL <path>    Prepend the library path to <path> and append to the search path\n");
	printf ("  -P <path>     Replace the complete search path with <path>\n");
	printf ("\nMain module options:\n");
	printf ("  -v -nv        Enable/disable verbose output\n");
	printf ("                (default: -nv)\n");
	printf ("  -w -nw        Enable/disable warnings\n");
	printf ("                (default: -w)\n");
	printf ("  -d -nd        Enable/disable the generation of readable label names\n");
	printf ("                (default: -nd)\n");
	printf ("  -sa -nsa      Enable/disable strictness analysis\n");
	printf ("                (default: -sa)\n");
	printf ("\nProject options:\n");
	printf ("  -mv           Verbose output of the make process\n");
	printf ("  -ms           Silent make process\n");
	printf ("  -O            Only generate the object file of the main module\n");
	printf ("  -PO           Only generate object files of the project modules\n");
	printf ("  -S            Only generate the assembly file of the main module\n");
	printf ("  -PS           Only generate assembly files of the project modules\n");
	printf ("  -ABC          Only generate the ABC file of the main module\n");
	printf ("  -PABC         Only generate ABC files of the project modules\n");
	printf ("  -c            Only check the syntax\n");
	printf ("                (note: compilation only considers the main module)\n");
	printf ("  -lt -nlt      Enable/disable listing only the inferred types\n");
	printf ("                (note: strictness information is never included)\n");
	printf ("                (default: -nlt)\n");
	printf ("  -lat -nlat    Enable/disable listing all the types\n");
	printf ("                (default: -nlat)\n");
	printf ("  -lset         List the types of functions for which not all strictness\n");
	printf ("                information has been exported\n");
	printf ("  -ci -nci      Enable/disable array indices checking\n");
	printf ("                (default: -nci)\n");
	printf ("  -ou -nou      Enable/disable optimizing uniqueness typing\n");
	printf ("                (default: -ou)\n");
	printf ("  -fusion -nfusion\n");
	printf ("                Enable/disable optimizing by fusion transformation\n");
	printf ("                (default: -nfusion)\n");
	printf ("  -pt -npt      Enable/disable the generation of code for time profiling\n");
	printf ("                (default: -npt)\n");
	printf ("  -tst          Generate code for stack tracing\n");
	printf ("\nLinker options:\n");
	printf ("  -ns           Disable stripping the application\n");
	printf ("  -no-opt-link  Disable the optimizing linker\n");
	printf ("  -l <file>     Include the object file <file>\n");
	printf ("  -sl <file>    Include the shared library file <file>\n");
	printf ("  -e <symbol>   Export the label name <symbol> for shared libraries\n");
	printf ("  -E <file>     Same as -e, but the exported label names are specified in the\n");
	printf ("                file <file>, separated by newlines\n");
	printf ("\nApplication options:\n");
	printf ("  -h <size>     Set the heap size to <size> in bytes\n");
	printf ("                (note: append k, K, m, or M to denote kilobytes or megabytes)\n");
	printf ("                (default: 2M)\n");
	printf ("  -s <size>     Set the stack size to <size> in bytes\n");
	printf ("                (note: append k, K, m, or M to denote kilobytes or megabytes)\n");
	printf ("                (default: 512K)\n");
	printf ("  -b -sc        Display the basic values or the constructors\n");
	printf ("                (default: -sc)\n");
	printf ("  -t -nt        Enable/disable displaying the execution times\n");
	printf ("                (default: -t)\n");
	printf ("  -gc -ngc      Enable/disable displaying heap size after garbage collection\n");
	printf ("                (default: -ngc)\n");
	printf ("  -st -nst      Enable/disable displaying stack size before garbage collection\n");
	printf ("                (default: -nst)\n");
	printf ("  -nr           Disable displaying the result of the application\n"); 
#ifdef MARKING_GC
	printf ("  -gcm          Use marking/compacting garbage collection\n");
	printf ("  -gcc          Use copy/compacting garbage collection\n");
	printf ("  -gcf <n>      Multiply the heap size with <n> after garbage collection\n");
	printf ("                (default: 20)\n");
	printf ("  -gci <size>   Set the initial heap size to <size> in bytes\n");
	printf ("                (note: append k, K, m, or M to denote kilobytes or megabytes)\n");
	printf ("                (default: 100K)\n");
#endif	
	exit (1);
}

static long parse_size (register char *s)
{
	register int c;
	register long n;
	
	c=*s++;
	if (c<'0' || c>'9')
		error ("Digit expected in argument\n");
	
	n=c-'0';
	
	while (c=*s++,c>='0' && c<='9')
		n=n*10+(c-'0');
	
	if (c=='k' || c=='K'){
		c=*s++;
		n<<=10;
	} else if (c=='m' || c=='M'){
		c=*s++;
		n<<=20;
	}
	
	if (c!='\0')
		error ("Error in size");
	
	return n;
}

#ifdef MARKING_GC
static long parse_integer (register char *s)
{
	register int c;
	register long n;

	c=*s++;
	if (c<'0' || c>'9')
		error ("Digit expected in argument\n");

	n=c-'0';

	while (c=*s++,c>='0' && c<='9')
		n=n*10+(c-'0');

	if (c!='\0')
		error ("Error in integer");

	return n;
}
#endif

static void add_library (char *library_file_name)
{
	int file_name_length;
	struct library_list *new_library_file;
	
	file_name_length=strlen (library_file_name);
	new_library_file=memory_allocate (sizeof (struct library_list)+file_name_length+1);

	strcpy (new_library_file->library_file_name,library_file_name);
	new_library_file->library_next=NULL;
	
	if (first_library==NULL)
		first_library=new_library_file;
	else
		last_library->library_next=new_library_file;
	last_library=new_library_file;
}

static void add_export (char *export_name)
{
	int export_name_length;
	struct export_list *new_export;
	
	export_name_length=strlen (export_name);
	new_export=memory_allocate (sizeof (struct export_list)+export_name_length+1);

	strcpy (new_export->export_name,export_name);
	new_export->export_next=NULL;
	
	if (first_export==NULL)
		first_export=new_export;
	else
		last_export->export_next=new_export;
	last_export=new_export;
}

static void add_export_file (char *export_file_name)
{
	int export_file_name_length;
	struct export_file_list *new_export_file;
	
	export_file_name_length=strlen (export_file_name);
	new_export_file=memory_allocate (sizeof (struct export_file_list)+export_file_name_length+1);

	strcpy (new_export_file->export_file_name,export_file_name);
	new_export_file->export_file_next=NULL;
	
	if (first_export_file==NULL)
		first_export_file=new_export_file;
	else
		last_export_file->export_file_next=new_export_file;
	last_export_file=new_export_file;
}

static P_NODE add_ignored (char *ignored_name)
{
    P_NODE ignored_module;

    for_l (ignored_module,first_project_node,pro_next)
        if (!strcmp (ignored_name,ignored_module->pro_fname))
            break;
    
	if (ignored_module==NULL)
        ignored_module=add_project_node(ignored_name);

    ignored_module->pro_ignore_o=1;

    return ignored_module;
}

static void read_shared_library (char *shared_script_name)
{
	char script_file_name[PATH_NAME_STRING_SIZE];
	char file_name[PATH_NAME_STRING_SIZE];
	FILE *fp;
#ifdef _WINDOWS_
	FileTime time;
#endif

#if MACINTOSH
	if (!find_file (shared_script_name,".lo",script_file_name))
#else
	if (!find_file (shared_script_name,".lo",script_file_name,clean_lib_path
# ifdef _WINDOWS_
		,&time
# endif
	))
#endif
		error_s ("Can't find %s.lo",shared_script_name);

	if (!(fp=fopen (script_file_name,"r")))
		error_s ("Can't open %s.lo",shared_script_name);

	while (fgets (file_name,PATH_NAME_STRING_SIZE,fp)!=NULL && file_name[0]!='='){
		char *rest,*parsed_file_name;

		rest=file_name;
		while ((parsed_file_name=parse_word (&rest))!=NULL)
			add_library (parsed_file_name);
	}
	{
	P_NODE ignored_module;
	int adding_dependencies;
	
	ignored_module=NULL;
	adding_dependencies=0;
	
	while (fgets (file_name,PATH_NAME_STRING_SIZE,fp)!=NULL){
		char *rest,*parsed_file_name;

		rest=file_name;
		while ((parsed_file_name=parse_word (&rest))!=NULL){
			if (parsed_file_name[0]=='('){
				++parsed_file_name;
				adding_dependencies=1;
			}

			if (adding_dependencies){
				int length;

				length=strlen (parsed_file_name);
				if (parsed_file_name[length-1]==')'){
					--length;
					parsed_file_name[length]='\0';
					adding_dependencies=0;
				}

				if (length>0){
				    if (ignored_module==NULL)
						fprintf (stderr,"no ignored module specified for %s\n",parsed_file_name);
					else
						add_dependency (&ignored_module->pro_depend,parsed_file_name);
				}
			} else 
				ignored_module=add_ignored (file_name);
		}
	}
	}
}

#define option_on(mask)  clean_options|=(mask);  clean_options_mask|=(mask);
#define option_off(mask) clean_options&=~(mask); clean_options_mask|=(mask);

#ifdef __MWERKS__
#	include <SIOUX.h>
extern int ccommand(char ***);
#	include <Memory.h>
#endif

#ifdef applec
#	include <Memory.h>
#endif

#if defined (OS2) && defined (OMF)
static int add_resource_to_application (char *application_file_name)
{
	char *argv[8],**arg;
	char clean_resources_file_name[PATH_NAME_STRING_SIZE];
	int r;

	strcpy (clean_resources_file_name,clean_lib_path);
	strcat (clean_resources_file_name,"\\clean.res");

	arg=argv;
	*arg++="rc.exe";
	*arg++=clean_resources_file_name;
	*arg++=application_file_name;
	*arg=NULL;
	
	r=dos_exec ("rc.exe",argv,0);

	return r==0;
}
#endif

#if defined (__MWERKS__)
int main (void)
{

	int argc;
	char *(arg_vector[32]),**argv;
#else
int main (int argc,char **argv)
{
#endif
	int arg_n;
	char *application_file_name,*main_module_name;

#if MACINTOSH || defined (POWER)
# if defined (__MWERKS__)
	SetApplLimit (GetApplLimit() - 200*1024);
	argv=arg_vector;
	argc = ccommand (&argv);
# else
#  ifdef applec
			SetApplLimit (GetApplLimit() - 200*1024);
#  endif
#  ifdef _LBFSIZ
	setvbuf (stdout,NULL,_IOLBF,_LBFSIZ);
#  else
	setvbuf (stdout,NULL,_IOLBF,256);
#  endif
# endif
#endif

#if defined (__MWERKS__)
	SIOUXSettings.showstatusline=0;
#endif

#ifdef OS2
	clm_file_name=argv[0];
#endif

#if MACINTOSH && !defined (G_POWER)
	OBJECT_FILE_EXTENSION=".obj0";
#endif

#ifdef DOS
	{
		int length;
	
		strcpy (clean_lib_directory,argv[0]);

		length=strlen (clean_lib_directory);
		while (length>0){
			--length;
			if (clean_lib_directory[length]=='/' ||
				clean_lib_directory[length]=='\\')
			{
				clean_lib_directory[length]=0;
				break;
			}
		}
		
		if (length==0)
			error ("argv[0] doesn't contain path name");
		strcat (clean_lib_directory,"/lib");
	}	
#endif

    if (argc==2 && strcmp (argv[1],"-V")==0){
        print_version_and_variables();
        exit (0);
    }

	if (argc<2 || argv[argc-1][0]=='-')
		argument_error();
	
	heap_size=2048<<10;
	ab_stack_size=512<<10;
	flags=8;
#ifdef MARKING_GC
	initial_heap_size=100<<10;
	heap_size_multiple=20<<8;
#endif
 	
	remove_symbol_table=1;
	check_stack_overflow=0;
	check_indices=0;
	dynamics=0;
#ifdef OPTIMISE_LINK
	no_optimise_link=0;
#endif
	stack_trace=0;

#ifdef OS2
	window_application=0;
#endif

	cocl_redirect_stdout=NULL;
	cocl_redirect_stderr=NULL;
 
	first_library=NULL;
	last_library=NULL;
	first_export=NULL;
	last_export=NULL;
	first_export_file=NULL;
	last_export_file=NULL;

	get_paths();
	
	for (arg_n=1; arg_n<argc && argv[arg_n][0]=='-'; ++arg_n){
		char *argument,*s;
		
		argument=argv[arg_n];		
		s=argument+1;
		
		/* driver options */
		
		if (!strcmp (s,"mv"))
			verbose=1;
		else if (!strcmp (s,"ms"))
			silent=1;
		else if (!strcmp (s,"c")){
			single_module=1;
			syntax_check=1;
		} else if (!strcmp (s,"ABC")){
			single_module=1;
			only_abc_files=1;
		} else if (!strcmp (s,"S")){
			single_module=1;
			only_s_files=1;
		} else if (!strcmp (s,"O")){
			single_module=1;
			only_o_files=1;
		} else if (!strcmp (s,"PABC"))
			only_abc_files=1;
		else if (!strcmp (s,"PS"))
			only_s_files=1;
		else if (!strcmp (s,"PO"))
			only_o_files=1;
		else if (!strcmp (s,"ns"))
			remove_symbol_table=0;
#ifdef OPTIMISE_LINK
		else if (!strcmp (s,"no-opt-link"))
			no_optimise_link=1;
#endif
		/* application options */
		else if (!strcmp (s,"h")){
			++arg_n;
			if (arg_n>=argc)
				error ("Heap size missing\n");
			heap_size=parse_size (argv[arg_n]);
		} else if (!strcmp (s,"s")){
			++arg_n;
			if (arg_n>=argc)
				error ("Stack size missing\n");
			ab_stack_size=parse_size (argv[arg_n]);
		} else if (!strcmp (s,"b"))
			flags |= 1;
		else if (!strcmp (s,"sc"))
			flags &= ~1;
		else if (!strcmp (s,"t"))
			flags |= 8;
		else if (!strcmp (s,"nt"))
			flags &= ~8;
		else if (!strcmp (s,"gc"))
			flags |= 2;
		else if (!strcmp (s,"ngc"))
			flags &= ~2;
		else if (!strcmp (s,"st"))
			flags |= 4;
		else if (!strcmp (s,"nst"))
			flags &= ~4;
		else if (!strcmp (s,"nr"))
			flags |= 16;
#ifdef MARKING_GC
		else if (!strcmp (s,"gcm"))
			flags |= 64;
		else if (!strcmp (s,"gcc"))
			flags &= ~64;
		else if (!strcmp (s,"gci")){
			++arg_n;
			if (arg_n>=argc)
				error ("Initial heap size missing\n");
			initial_heap_size=parse_size (argv[arg_n]);
		} else if (!strcmp (s,"gcf")){
			++arg_n;
			if (arg_n>=argc)
				error ("Next heap size factor missing\n");
			heap_size_multiple=parse_integer (argv[arg_n])<<8;
		}
#endif
		/* clean options */
		
		else if (!strcmp (s,"v")){
			option_on (VERBOSE_MASK);
		} else if (!strcmp (s,"nv")){
			option_off (VERBOSE_MASK);
		} else if (!strcmp (s,"w")){
			option_on (WARNING_MASK);
		} else if (!strcmp (s,"nw")){
			option_off (WARNING_MASK);
		} else if (!strcmp (s,"d")){
			option_on (DEBUG_MASK);
		} else if (!strcmp (s,"nd")){
			option_off (DEBUG_MASK);
		} else if (!strcmp (s,"sa")){
			option_on (STRICTNESS_ANALYSIS_MASK);
		} else if (!strcmp (s,"nsa")){
			option_off (STRICTNESS_ANALYSIS_MASK);
		} else if (!strcmp (s,"lt")){
			option_on (LIST_TYPES_MASK);
		} else if (!strcmp (s,"nlt")){
			option_off (LIST_TYPES_MASK);
		} else if (!strcmp (s,"lat")){
			option_on (LIST_ALL_TYPES_MASK);
		} else if (!strcmp (s,"nlat")){
			option_off (LIST_ALL_TYPES_MASK);
		} else if (!strcmp (s,"lset")){
			list_strict_export_types=1;
        } else if (!strcmp (s,"ou")){
            option_off (NO_REUSE_UNIQUE_NODES_MASK);
        } else if (!strcmp (s,"nou")){
            option_on (NO_REUSE_UNIQUE_NODES_MASK);
/*
        } else if (!strcmp (s,"pm")){
            option_on (MEMORY_PROFILE);
        } else if (!strcmp (s,"npm")){
            option_off (MEMORY_PROFILE);
*/
        } else if (!strcmp (s,"pt")){
            option_off (NO_TIME_PROFILE_MASK);
			stack_trace=0;
        } else if (!strcmp (s,"npt")){
            option_on (NO_TIME_PROFILE_MASK);
        } else if (!strcmp (s,"tst")){
            option_off (NO_TIME_PROFILE_MASK);
			stack_trace=1;
        } else if (!strcmp (s,"fusion")){
            option_on (FUSION_MASK);
        } else if (!strcmp (s,"nfusion")){
            option_off (FUSION_MASK);
		} else if (!strcmp (s,"dynamics")){
			dynamics=1;
        } else if (strcmp (s, "RE") == 0 || strcmp (s, "RAE") == 0){
            cocl_redirect_stderr_option = argument;
            if (++arg_n < argc)
                cocl_redirect_stderr = argv [arg_n];
            else
                error ("file name expected after -RE");
        } else if (strcmp (s, "RO") == 0 || strcmp (s, "RAO") == 0){
            cocl_redirect_stdout_option = argument;
            if (++arg_n < argc)
                cocl_redirect_stdout = argv [arg_n];
            else
                error ("file name expected after -RO");
		} else if (!strcmp (s,"funcmayfail")){
			funcmayfail_error=1;
		} else if (!strcmp (s,"varnotused")){
			varnotused_error=1;
		} else if (!strcmp (s,"funcnotused")){
			funcnotused_error=1;
		} else if (!strcmp (s,"nowarn")){
			nowarn=1;
#ifndef OS2
		} else if (!strcmp (s,"p")){
			progress=1;
#endif
		/* code generator options */
		} else if (!strcmp (s,"ci")){
			check_indices=1;
		} else if (!strcmp (s,"nci")){
			check_indices=0;
		} else if (!strcmp (s,"l")){
			++arg_n;
			if (arg_n>=argc)
				error ("Library name missing\n");
			add_library (argv[arg_n]);
		} else if (!strcmp (s,"sl")){
			++arg_n;
			if (arg_n>=argc)
			   error ("Shared library name missing\n");
			read_shared_library (argv[arg_n]);
		} else if (!strcmp (s,"e")){
			++arg_n;
			if (arg_n>=argc)
				error ("Exported label name missing\n");
			add_export (argv[arg_n]);
		} else if (!strcmp (s,"E")){
			++arg_n;
			if (arg_n>=argc)
				error ("File name with exported label names missing\n");
			add_export_file (argv[arg_n]);
#ifdef OS2
		} else if (!strcmp (s,"p")) {
			window_application=1;
#endif
		} else if (!strcmp (s,"P")){
			++arg_n;
			if (arg_n>=argc)
			   error ("Path list missing\n");
			clean_path_list=strcpy (clean_path_list_copy,argv[arg_n]);
		} else if (!strcmp (s,"I")){
			++arg_n;
			if (arg_n>=argc)
			   error ("Path missing\n");
			if (clean_path_list[0]!='\0')
				strcat (clean_path_list,":");
			strcat (clean_path_list,argv[arg_n]);
		} else if (!strcmp (s,"IL")){
			++arg_n;
			if (arg_n>=argc)
			   error ("Path missing\n");
			if (clean_path_list[0]!='\0')
				strcat (clean_path_list,":");
			strcat (clean_path_list,clean_include_library_directory);
			strcat (clean_path_list,"/");
			strcat (clean_path_list,argv[arg_n]);
		} else
			error_s ("Unknown option: %s",argument);
	}

	main_module_name=argv[arg_n];

	if (arg_n==argc-3){
		if (strcmp (argv[arg_n+1],"-o")!=0)
			argument_error();
		application_file_name=argv[arg_n+2];
	} else {
#ifdef OS2
		int length;
		
		length=strlen (main_module_name);
		
		application_file_name=memory_allocate (length+5);
		
		strcpy (application_file_name,main_module_name);
		strcat (application_file_name,".exe");
#else
		application_file_name=NULL;
#endif
		if (arg_n!=argc-1)
			argument_error();
	}

#if MACINTOSH
	initialise_path_list();
#endif

	if (progress)
		print_version();

	if (first_project_node==NULL)
		main_project_node=add_project_node (main_module_name);
	else {
		P_NODE old_first_project_node,old_last_project_node;
		
		old_first_project_node=first_project_node;
		old_last_project_node=last_project_node;

		first_project_node=NULL;

		main_project_node=add_project_node (main_module_name);

		main_project_node->pro_next=old_first_project_node;
		last_project_node=old_last_project_node;
	}

	if (make_project_to_abc_files (first_project_node)){
#ifdef CACHING_COMPILER
		if (compiler_started){
			stop_compiler();
			compiler_started=0;
		}
#endif

		if (only_abc_files || syntax_check)
			return 0;
		
		if (only_s_files)
			return make_project_to_s_files();
		
		if (make_project_to_o_files()){
#if ! MACINTOSH
			char *options_file_name;
#endif
			if (only_o_files)
				return 0;

			if (create_options_file (&options_file_name)){
				if (!link_project (first_project_node,options_file_name,application_file_name)){
					unlink (options_file_name);
					return 1;
				}
 				unlink (options_file_name);
#if defined (OS2) && defined (OMF)
				if (window_application && !add_resource_to_application (application_file_name))
					return 1;
#endif
				return 0;
			}
		}
	}
	
#ifdef CACHING_COMPILER
	stop_compiler ();
#endif

	return 1;
}

