/*
	File:	wcon.c
	Author:	John van Groningen
	At:		University of Nijmegen
*/

#include <float.h>

#define GC_FLAGS

#ifdef WINDOWS
# include <windows.h>
# define ULONG unsigned long
# define DosWrite(f,p,l,lp) WriteFile ((HANDLE)f,p,l,lp,NULL)
# define DosRead(f,p,l,lp) ReadFile ((HANDLE)f,p,l,lp,NULL)
# define OS(w,o) w
# define StdInput std_input_handle
# define StdOutput std_output_handle
# define StdError std_error_handle
# ifdef TIME_PROFILE
#  define TCHAR char
#  if 0
   typedef struct _WIN32_FIND_DATA {
		DWORD dwFileAttributes;
		FILETIME ftCreationTime;
		FILETIME ftLastAccessTime;
		FILETIME ftLastWriteTime;
		DWORD    nFileSizeHigh;
		DWORD    nFileSizeLow;
		DWORD    dwReserved0;
		DWORD    dwReserved1;
		TCHAR    cFileName[ MAX_PATH ];
		TCHAR    cAlternateFileName[ 14 ];
   } WIN32_FIND_DATA;
#  endif
# endif
#else
# define INCL_DOSFILEMGR
# include <os2.h>
# define OS(w,o) o
# define StdInput 0
# define StdOutput 1
# define StdError 2
#endif

#ifdef WINDOWS
HANDLE std_input_handle,std_output_handle,std_error_handle;
int console_window_visible,console_allocated,console_flag=0;
#endif

extern int c_entier (double);
extern double c_log10 (double);
extern double c_pow (double,double);

extern long ab_stack_size,heap_size,flags;

static void print_char (char c,OS(HANDLE,int) file_number)
{
	ULONG n_chars;

	if (c==10){
		c=13;
		DosWrite (file_number,&c,1,&n_chars);
		c=10;
	}
	DosWrite (file_number,&c,1,&n_chars);
}

static void print_text (char *s,unsigned long length,OS(HANDLE,int) file_number)
{
	ULONG n_chars;
	int n;

	n=0;
	while (n!=length)
		if (s[n]!=10)
			++n;
		else {
			char c;

			if (n>0)
				DosWrite (file_number,s,n,&n_chars);
			c=13;
			DosWrite (file_number,&c,1,&n_chars);

			s+=n;
			length-=n;
			n=1;
		}

	if (length>0)
		DosWrite (file_number,s,length,&n_chars);
}

#ifdef WINDOWS
static void make_console_window_visible ()
{
	if (!console_window_visible){
		if (console_flag==0 ||
			std_input_handle==INVALID_HANDLE_VALUE || std_input_handle==NULL ||
			std_output_handle==INVALID_HANDLE_VALUE || std_output_handle==NULL ||
			std_error_handle==INVALID_HANDLE_VALUE || std_error_handle==NULL)
		{
			console_allocated=AllocConsole();
	
			if (std_input_handle==INVALID_HANDLE_VALUE || std_input_handle==NULL)
				std_input_handle=GetStdHandle (STD_INPUT_HANDLE);
			if (std_output_handle==INVALID_HANDLE_VALUE || std_output_handle==NULL)
				std_output_handle=GetStdHandle (STD_OUTPUT_HANDLE);
			if (std_error_handle==INVALID_HANDLE_VALUE || std_error_handle==NULL)
				std_error_handle=GetStdHandle (STD_ERROR_HANDLE);
		}
		
		console_window_visible=1;
	}
}
#endif

void w_print_char (char c)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_char (c,StdOutput);
}

void w_print_text (char *s,unsigned long length)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_text (s,length,StdOutput);
}

void ew_print_char (char c)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_char (c,StdError);
}

void ew_print_text (char *s,unsigned long length)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_text (s,length,StdError);
}

static int next_stdin_character=-1;

int w_get_char (void)
{
	ULONG n_chars;
	char c;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	if (next_stdin_character==-1){
		do {
			DosRead (StdInput,&c,1,&n_chars);
			if (n_chars>0 && c!=13)
				return c;
		} while (n_chars>0);

		return -1;
	} else {
		c=next_stdin_character;
		next_stdin_character=-1;
		return c;
	}
}

#define is_digit(n) ((unsigned)((n)-'0')<(unsigned)10)

int w_get_int (int *i_p)
{
	int c,negative;
	unsigned int i;
	
	c=w_get_char();
	while (c==' ' || c=='\t' || c=='\n')
		c=w_get_char();
	
	negative=0;
	if (c=='+')
		c=w_get_char();
	else
		if (c=='-'){
			c=w_get_char();
			negative=1;
		}
	
	if (!is_digit (c)){
		next_stdin_character=c;
		
		*i_p=0;
		return 0;
	}
	
	i=c-'0';
	while (c=w_get_char(),is_digit (c)){
		i+=i<<2;
		i+=i;
		i+=c-'0';
	};

	if (negative)
		i=-i;

	next_stdin_character=c;

	*i_p=i;
	return -1;
}

char *convert_string_to_real (char *string,double *r_p)
{
	int neg,has_digits,has_dot;
	char *s_p,*end_s;
	long scale;
	double d;

	s_p=string;

	neg=0;
	if (*s_p=='+')
		++s_p;
	else if (*s_p=='-'){
		neg = 1;
		++s_p;
    }

	has_digits=0;
	has_dot=0;
	scale=0;
	d=0.0;

	for (;;){
		if (*s_p== '.' && !has_dot){
			++s_p;
			has_dot=1;
		} else if ((unsigned)(*s_p-'0') < (unsigned)10){
			if (!has_digits){
				d=(double)(*s_p - '0');
				has_digits=1;
			} else {
				if (d >= 1e18)
					++scale;
				else
					d = d*10.0 + (double)(*s_p - '0');
			}
			++s_p;
			if (has_dot)
				--scale;
		} else
			break;
	}

	if (!has_digits){
		*r_p=0.0;
		return string;
	}

	end_s=s_p;

	if ((*s_p & ~0x20)=='E'){
		int neg_exponent;

		++s_p;

		neg_exponent=0;
		if (*s_p=='+')
			++s_p;
		else if (*s_p=='-'){
			neg_exponent=1;
			++s_p;
		}
		
		if ((unsigned)(*s_p-'0') < (unsigned)10){
			int exponent;
			
			exponent=*s_p++ - '0';
			while ((unsigned)(*s_p-'0') < (unsigned)10)
				exponent=exponent*10 + *s_p++ - '0';

			if (neg_exponent)
				scale -= exponent;
			else
				scale += exponent;
			
			end_s=s_p;
        }
    }

	if (scale!=0 && d!=0.0)
		d *= c_pow (10.0,(double)scale);

	if (neg)
		d=-d;

	*r_p=d;

	return end_s;
}

int w_get_real (double *r_p)
{
	char s[256+1];
	int c,dot,digits,result,n;
	
	n=0;
	
	c=w_get_char();
	while (c==' ' || c=='\t' || c=='\n')
		c=w_get_char();
	
	if (c=='+')
		c=w_get_char();
	else
		if (c=='-'){
			s[n++]=c;
			c=w_get_char();
		}
	
	dot=0;
	digits=0;
	
	while (is_digit (c) || c=='.'){
		if (c=='.'){
			if (dot){
				dot=2;
				break;
			}
			dot=1;
		} else
			digits=-1;
		if (n<256)
			s[n++]=c;
		c=w_get_char();
	}

	result=0;
	if (digits)
		if (dot==2 || ! (c=='e' || c=='E'))
			result=-1;
		else {
			if (n<256)
				s[n++]=c;
			c=w_get_char();
			
			if (c=='+')
				c=w_get_char();
			else
				if (c=='-'){
					if (n<256)
						s[n++]=c;
					c=w_get_char();
				}
			
			if (is_digit (c)){
				do {
					if (n<256)
						s[n++]=c;
					c=w_get_char();
				} while (is_digit (c));

				result=-1;
			}
		}

	if (n>=256)
		result=0;

	next_stdin_character=c;

	*r_p=0.0;
	
	if (result){
		s[n]='\0';
		result= convert_string_to_real (s,r_p)==&s[n];
	}
	
	return result;
}

unsigned long w_get_text (char *string,unsigned long max_length)
{
	ULONG length;

	length=0;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif
	
	if (max_length==0)
		return length;
	
	if (next_stdin_character!=-1){
		*string++=next_stdin_character;
		next_stdin_character=-1;
		--max_length;
		++length;
	}
	
	while (max_length>0){
		ULONG r_length;
		int s,d;
		
		DosRead (StdInput,string,max_length,&r_length);
		
		s=0;
		d=0;
		while (s<r_length){
			char c;
			
			c=string[s];
			++s;
			
			if (c!=13){
				string[d]=c;
				++d;
			}
		}
		length += d;

		if (r_length!=max_length)
			break;
		
		string += d;
		max_length -= d;
	}

	return length;
}

void w_print_string (char *s)
{
	char *p;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	for (p=s; *p!=0; ++p)
		;

	print_text (s,p-s,StdOutput);
}

void ew_print_string (char *s)
{
	char *p;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	for (p=s; *p!=0; ++p)
		;

	print_text (s,p-s,StdError);
}

static void print_integer (int n,OS(HANDLE,int) file_number)
{
	char s[16];
	int length;
	unsigned int m;
	ULONG n_chars;

	if (n<0)
		m=-n;
	else
		m=n;

	length=16;

	while (m>=10){
		unsigned int r;

		r=m/10;
		s[--length]=48+m-r*10;
		m=r;
	}

	s[--length]=48+m;
	if (n<0)
		s[--length]='-';

	DosWrite (file_number,&s[length],16-length,&n_chars);
}

void w_print_int (int n)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_integer (n,StdOutput);
}

void ew_print_int (int n)
{
#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif

	print_integer (n,StdError);
}

int xam_and_fstsw (double d)
{
	int i;
	
	asm ("fxam ; fstsw %%ax" : : "f" (d) : "%ax");
	asm ("movzwl %%ax,%0" : "=g" (i) : );

	return i;
}

int fbstp (double d,char *buffer)
{
	asm ("movl %0,%%eax ; fbstp (%%eax) ; fld1" : : "g" (buffer) , "f" (d) : "%eax");
}

#define N_DIGITS 15

char *convert_real_to_string (double d,char *s_p)
{
	double scale_factor;
	int exponent,n;
	unsigned int fpu_status;
	unsigned char bcd_buffer[16];
	int i,j;

	fpu_status = xam_and_fstsw (d);

	switch (fpu_status & 0x4500){
		case 0x500:
			if (fpu_status & 0x200)
				*s_p++='-';
			s_p[0]='#';
			s_p[1]='I';
			s_p[2]='N';
			s_p[3]='F';
			s_p[4]='\0';
			return s_p+4;
		case 0x100:
			s_p[0]='#';
			s_p[1]='N';
			s_p[2]='A';
			s_p[3]='N';
			s_p[4]='\0';
			return s_p+4;
		case 0x4100:
			if (fpu_status & 0x200)
				*s_p++='-';
			s_p[0]='#';
			s_p[1]='E';
			s_p[2]='M';
			s_p[3]='P';
			s_p[4]='\0';
			return s_p+4;
	}

	if (d<0){
		d=-d;
		*s_p++ = '-';
	}

	if (d==0){
		*s_p++ = '0';
		*s_p = '\0';
		return s_p;
	}

	if (d<1e4){
		if (d<1e0){
			if (d<1e-4){
				exponent=c_entier (c_log10 (d));
				if (N_DIGITS-exponent>=308){
					d=d*1e20;
					scale_factor=c_pow (10.0,N_DIGITS-1-20-exponent);
				} else {
					scale_factor=c_pow (10.0,N_DIGITS-1-exponent);
				}
			} else {
				if (d<1e-2){
					if (d<1e-3){
						exponent=-4;
						scale_factor=1e18;
					} else {
						exponent=-3;
						scale_factor=1e17;
					}
				} else {
					if (d<1e-1){
						exponent=-2;
						scale_factor=1e16;
					} else {
						exponent=-1;
						scale_factor=1e15;
					}
				}
			}
		} else {
			if (d<1e2){
				if (d<1e1){
					exponent=0;
					scale_factor=1e14;
				} else {
					exponent=1;
					scale_factor=1e13;
				}				
			} else {
				if (d<1e3){
					exponent=2;
					scale_factor=1e12;
				} else {
					exponent=3;
					scale_factor=1e11;
				}			
			}
		}		
	} else {
		if (d<1e8){
			if (d<1e6){
				if (d<1e5){
					exponent=4;
					scale_factor=1e10;
				} else {
					exponent=5;
					scale_factor=1e9;
				}
			} else {
				if (d<1e7){
					exponent=6;
					scale_factor=1e8;
				} else {
					exponent=7;
					scale_factor=1e7;			
				} 
			}
		} else if (d<1e12){
			if (d<1e10){
				if (d<1e9){
					exponent=8;
					scale_factor=1e6;
				} else {
					exponent=9;
					scale_factor=1e5;
				}
			} else {
				if (d<1e11){
					exponent=10;
					scale_factor=1e4;
				} else {
					exponent=11;
					scale_factor=1e3;
				}
			}						
		} else {
			exponent=c_entier (c_log10 (d));
			scale_factor=c_pow (10.0,N_DIGITS-1-exponent);
		}
	}

	d *= scale_factor;

	if (d<1e14){
		d *= 10.0;
		--exponent;
	}

	fbstp (d,bcd_buffer);

	j=14;
	for (i=0; i<7; ++i){
		unsigned char bcd_byte;
		
		bcd_byte=bcd_buffer[i];
		s_p[j] ='0'+(bcd_byte & 0xf);
		s_p[j-1]='0'+((bcd_byte & 0xf0)>>4);
		j-=2;
	}
	s_p[j] ='0'+(bcd_buffer[i] & 0xf);
	
	s_p+=15;

	if (exponent>(N_DIGITS-1) || exponent<-4){
		int exponent_d10;
		
		for (n=-1; n>=-(N_DIGITS-1); --n)
			s_p[n+1]=s_p[n];
		s_p[-(N_DIGITS-1)]='.';

		++s_p;
		while (s_p[-1]=='0')
			--s_p;

		if (s_p[-1]=='.')
			--s_p;
		
		*s_p++ = 'e';
		
		if (exponent>=0)
			*s_p++ = '+';
		else {
			*s_p++ = '-';
			exponent= -exponent;
		}
		
		if (exponent>=100){
			int exponent_d100;
			
			exponent_d100=exponent/100;
			*s_p++ = '0'+exponent_d100;
			exponent -= 100*exponent_d100;
		}
		
		exponent_d10=exponent/10;
		*s_p++ = '0'+exponent_d10;
		*s_p++ = '0'+exponent-10*exponent_d10;
	} else {
		if (exponent>=-1){
			for (n=-1; n>=exponent-(N_DIGITS-1); --n)
				s_p[n+1]=s_p[n];
			s_p[exponent-(N_DIGITS-1)]='.';
			++s_p;
		} else {
			for (n=-1; n>=-N_DIGITS; --n)
				s_p[n-exponent]=s_p[n];		
			s_p[-N_DIGITS] = '.';
			
			for (n=exponent; n<-1; ++n)
				s_p[-(N_DIGITS-1)+(n-exponent)] = '0';
			s_p+= -exponent;			
		}

		while (s_p[-1]=='0')
			--s_p;

		if (s_p[-1]=='.')
			--s_p;
	}

	*s_p='\0';
	return s_p;	
}

void w_print_real (double r)
{
	char s[32],*end_s;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif
	
	end_s=convert_real_to_string (r,s);
	print_text (s,end_s-s,StdOutput);
}

void ew_print_real (double r)
{
	char s[32],*end_s;

#ifdef WINDOWS
	if (!console_window_visible)
		make_console_window_visible();
#endif
	
	end_s=convert_real_to_string (r,s);
	print_text (s,end_s-s,StdError);
}

#ifdef WINDOWS
void wait_for_key_press (VOID)
{
	DWORD console_mode;
		
	SetConsoleTitleA ("press any key to exit");
		
	GetConsoleMode (std_input_handle,&console_mode);
	SetConsoleMode (std_input_handle,console_mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));		
	{
		ULONG n_chars;
		char c;

		n_chars=1;
		DosRead (StdInput,&c,1,&n_chars);
	}
	SetConsoleMode (std_input_handle,console_mode);
}
#endif

int free_memory (void *p)
{
#ifdef WINDOWS
	if (GlobalFree (p)==NULL)
		return 0;
	else
		return GetLastError();
#else
	return DosFreeMem (p);
#endif
}

void *allocate_memory (int size)
{
#ifdef WINDOWS
	return GlobalAlloc (GMEM_FIXED,size);
#else
	APIRET rc;
	void *pb;

	rc=DosAllocMem (&pb,size,fALLOC);
	if (rc!=0)
		return NULL;
	else
		return pb;
#endif
}

static long parse_size (char *s)
{
	int c;
	long n;
	
	c=*s++;
	if (c<'0' || c>'9'){
		w_print_string ("Digit expected in argument\n");
		return -1;
	}
	
	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'){
		w_print_string ("Error in argument\n");
		return -1;
	}
	
	return n;
}

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

	c=*s++;
	if (c<'0' || c>'9'){
		w_print_string ("Digit expected in argument\n");
		return (-1);
	}

	n=c-'0';

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

	if (c!='\0'){
		w_print_string ("Error in integer");
		return (-1);
	}
	
	return n;
}
#endif

int global_argc;
char **global_argv;

#ifdef DLL
extern void abc_main (void *);
#else
extern void abc_main (void);
#endif

#define EQ_STRING1(s,c1) ((s)[0]==(c1) && (s)[1]=='\0')
#define EQ_STRING2(s,c1,c2) ((s)[0]==(c1) && (s)[1]==(c2) &&(s)[2]=='\0')
#define EQ_STRING3(s,c1,c2,c3) ((s)[0]==(c1) && (s)[1]==(c2) && (s)[2]==(c3) && (s)[3]=='\0')

#ifdef WINDOWS
extern long heap_size_multiple;
extern long initial_heap_size;

# define MINIMUM_HEAP_SIZE_MULTIPLE ((2*256)+128)
# define MAXIMUM_HEAP_SIZE_MULTIPLE (100*256)
#endif

void (*exit_tcpip_function) (void);
#ifdef WINDOWS
int execution_aborted;
int return_code;
#endif

#ifdef DLL
int clean_main (int heap_size_param,int flags_param,int ab_stack_size_param,void *start_address,int argc,char **argv)
#else
# ifdef CLIB
int main (int argc,char **argv)
# else
int clean_main (void)
# endif
#endif
{
	int arg_n;
#ifndef CLIB
	char **argv,*arg_p,*arg_p_copy,*command_p;
	int argc;
	
	argc=0;
	command_p=GetCommandLineA();
	if (command_p==NULL || *command_p=='\0')
		command_p="?";

	{
		char c;
	
		arg_p=command_p;

		while ((c=*arg_p)!=0){
			while (c==' ' || c=='\t' || c=='\n' || c=='\r')
				c = * ++arg_p;
			
			if (c=='\0')
				break;
			
			++argc;

			if (c=='\"'){
				do {
					c = * ++arg_p;
				} while (!(c=='\0' || c=='\"'));
				
				if (c=='\"')
					c = * ++arg_p;
			} else {
				while (!(c=='\0' || c==' ' || c=='\t' || c=='\n' || c=='\r'))
					c = * ++arg_p;
			}
			
			if (c=='\0')
				break;
			
			++arg_p;		
		}
	}
	
	argv=GlobalAlloc (GMEM_FIXED,argc*sizeof (char*));
	arg_p_copy=GlobalAlloc (GMEM_FIXED,(1+arg_p-command_p)*sizeof (char));

	argc=0;
	arg_p=command_p;

	if (argv==NULL || arg_p_copy==NULL){
		argv=&arg_p;
		argc=1;
	} else {
		char c;
		
		while ((c=*arg_p)!='\0'){
			while (c==' ' || c=='\t' || c=='\n' || c=='\r')
				c=* ++arg_p;
			
			if (c=='\0')
				break;
	
			argv[argc++]=arg_p_copy;

			if (c=='\"'){
				c = * ++arg_p;
				
				while (!(c=='\0' || c=='\"')){
					*arg_p_copy++ = c;
					c = * ++arg_p;
				}
			
				if (c=='\"')
					c = * ++arg_p;
			} else {
				while (!(c=='\0' || c==' ' || c=='\t' || c=='\n' || c=='\r')){
					*arg_p_copy++ = c;
					c = * ++arg_p;
				}
			}
	
			*arg_p_copy++ = '\0';

			if (c=='\0')
				break;
			
			++arg_p;		
		}
	}
#endif

	exit_tcpip_function=NULL;
#ifdef WINDOWS
	execution_aborted=0;
	return_code=0;
#endif

#ifdef DLL
	heap_size=heap_size_param;
	flags=flags_param;
	ab_stack_size=ab_stack_size_param;
#endif

#ifdef WINDOWS
	std_input_handle=GetStdHandle (STD_INPUT_HANDLE);
	std_output_handle=GetStdHandle (STD_OUTPUT_HANDLE);

	if (flags & 128)
		std_error_handle=CreateFileA ("Messages",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	else
		std_error_handle=GetStdHandle (STD_ERROR_HANDLE);

	console_window_visible=flags & 16 ? 0 : 1;

	if (heap_size_multiple<MINIMUM_HEAP_SIZE_MULTIPLE)
		heap_size_multiple=MINIMUM_HEAP_SIZE_MULTIPLE;
	if (heap_size_multiple>MAXIMUM_HEAP_SIZE_MULTIPLE)
		heap_size_multiple=MAXIMUM_HEAP_SIZE_MULTIPLE;
#endif

	for (arg_n=1; arg_n<argc; ++arg_n){
		char *s;
		
		s=argv[arg_n];
		if (*s!='-')
			break;

		++s;
		if (EQ_STRING1 (s,'h')){
   			long s;

			++arg_n;
			if (arg_n>=argc){
				w_print_string ("Heapsize missing\n");
				return -1;
			}
			s=parse_size (argv[arg_n]);
			if (s<0)
				return -1;
			heap_size=s;
		} else if (EQ_STRING1 (s,'s')){
   			long s;

			++arg_n;
			if (arg_n>=argc){
				w_print_string ("Stacksize missing\n");
				return -1;
			}
			s=parse_size (argv[arg_n]);
			if (s<0)
				return -1;
			ab_stack_size=s;
		} else if (EQ_STRING1 (s,'b'))
			flags |= 1;
		else if (EQ_STRING2 (s,'s','c'))
			flags &= ~1;
		else if (EQ_STRING1 (s,'t'))
			flags |= 8;
		else if (EQ_STRING2 (s,'n','t'))
			flags &= ~8;
		else if (EQ_STRING2 (s,'g','c'))
			flags |= 2;
		else if (EQ_STRING3 (s,'n','g','c'))
			flags &= ~2;
		else if (EQ_STRING2 (s,'s','t'))
			flags |= 4;
		else if (EQ_STRING3 (s,'n','s','t'))
			flags &= ~4;
		else if (EQ_STRING2 (s,'n','r'))
			flags |= 16;
#ifdef GC_FLAGS
		else if (EQ_STRING3 (s,'g','c','m'))
			flags |= 64;
		else if (EQ_STRING3 (s,'g','c','c'))
			flags &= ~64;
		else if (EQ_STRING3 (s,'g','c','i')){
			int s;
			
			++arg_n;
			if (arg_n>=argc){
				w_print_string ("Initial heap size missing\n");
				return -1;
			}
			s=parse_size (argv[arg_n]);
			if (s<0)
				return -1;
			initial_heap_size=s;
		} else if (EQ_STRING3 (s,'g','c','f')){
			int i;
			
			++arg_n;
			if (arg_n>=argc){
				w_print_string ("Next heap size factor missing\n");
				return -1;
			}
			i=parse_integer (argv[arg_n]);
			if (i<0)
				return -1;
			heap_size_multiple=i<<8;
		}
#endif
#ifdef WINDOWS
		else if (EQ_STRING3 (s,'c','o','n'))
			console_flag=1;
#endif
		else
			break;
	}

	--arg_n;
	argv[arg_n]=argv[0];
	global_argv=&argv[arg_n];
	global_argc=argc-arg_n;

#ifdef DLL
	abc_main (start_address);
#else
	abc_main();
#endif

	if (exit_tcpip_function!=NULL)
		exit_tcpip_function();

#ifdef WINDOWS
	if ( (!(flags & 16) || (flags & 8) || execution_aborted) && !console_flag)
		wait_for_key_press();

	if (return_code==0 && execution_aborted)
		return_code= -1;
#endif

#ifndef CLIB
	ExitProcess (return_code);
#endif

#ifdef WINDOWS
	return return_code;
#else
	return 0;
#endif
}

#ifdef TIME_PROFILE
char time_profile_file_name_suffix[]=" Time Profile.pcl";

#define MAX_PATH_LENGTH 256

void create_profile_file_name (unsigned char *profile_file_name_string)
{
	char *time_profile_file_name_p,*time_profile_file_name_suffix_p,*profile_file_name,*p;
	int length_time_profile_file_name,time_profile_file_name_suffix_length,i;

	time_profile_file_name_p=global_argv[0];
	profile_file_name=&profile_file_name_string[8];
	
	for (p=time_profile_file_name_p; *p!='\0'; ++p)
		;
	length_time_profile_file_name=p-time_profile_file_name_p;
	
	if (time_profile_file_name_p[0]=='\"' && length_time_profile_file_name>1 && time_profile_file_name_p[length_time_profile_file_name-1]=='\"'){
		++time_profile_file_name_p;
		length_time_profile_file_name-=2;
	}
	
	for (i=0; i<length_time_profile_file_name; ++i)
		profile_file_name[i]=time_profile_file_name_p[i];
	profile_file_name[length_time_profile_file_name]='\0';
	
	if (length_time_profile_file_name<=MAX_PATH_LENGTH){
		WIN32_FIND_DATA find_data;
		HANDLE find_first_file_handle;

		find_first_file_handle=FindFirstFileA (profile_file_name,&find_data);
		if (find_first_file_handle!=INVALID_HANDLE_VALUE){
			char *file_name_p,*p;
			int file_name_length;
			
			file_name_p=find_data.cFileName;
			for (p=file_name_p; *p!='\0'; ++p)
				;
			file_name_length=p-file_name_p;
			
			for (p=profile_file_name+length_time_profile_file_name; p>profile_file_name && p[-1]!='\\' && p[-1]!='/'; --p)
				;
			
			if ((p-profile_file_name)+file_name_length<=MAX_PATH_LENGTH){				
				for (i=0; i<file_name_length; ++i)
					p[i]=file_name_p[i];
				p[i]='\0';
				
				length_time_profile_file_name=&p[i]-profile_file_name;
			}
			
			FindClose (find_first_file_handle);
		}
	}

	p=&profile_file_name[length_time_profile_file_name];
	if (length_time_profile_file_name>3 && p[-4]=='.' && p[-3]=='e' && p[-2]=='x' && p[-1]=='e')
		length_time_profile_file_name-=4;
	
	time_profile_file_name_suffix_p=time_profile_file_name_suffix;
	time_profile_file_name_suffix_length=sizeof (time_profile_file_name_suffix);	
	if (length_time_profile_file_name+time_profile_file_name_suffix_length>MAX_PATH_LENGTH){
		time_profile_file_name_suffix_length=MAX_PATH_LENGTH-length_time_profile_file_name;
		time_profile_file_name_suffix_p=&time_profile_file_name_suffix_p[sizeof (time_profile_file_name_suffix)-time_profile_file_name_suffix_length];
	}
	
	p=profile_file_name+length_time_profile_file_name;
	for (i=0; i<=time_profile_file_name_suffix_length; ++i)
		p[i]=time_profile_file_name_suffix_p[i];
	
	*(unsigned int*)(&profile_file_name_string[4])=length_time_profile_file_name+time_profile_file_name_suffix_length;
}
#endif

#ifdef WRITE_HEAP
# include "iwrite_heap.c"
#endif
