/* This file is part of Cloudy and is copyright (C)1978-2006 by Gary J. Ferland
 * For conditions of distribution and use see copyright notice in license.txt */
/*ParseCrashDo any of several tests to check that the code can crash */
#include "cddefines.h"
#include "physconst.h"
#include "parse.h"
#include "cpu.h"
/* disable warning about undefined vars being used - one of the tests shall do exactly that */
#ifdef _MSC_VER
#pragma warning( disable : 4700 )
#endif
#ifdef __INTEL_COMPILER
#pragma warning( disable : 592 )
#endif
/* disable warning about division by zero */
#ifdef _MSC_VER
#pragma warning( disable : 4756 )
#endif

#define ARR_SIZE 10

static double ar2[ARR_SIZE];

void ParseCrashDo(char *chCard)
{
	float ar1, br1;
	long int i;

	int lgCrash = FALSE;
	/* div by 0 to get crash as check on FP environment */
	if( lgMatch("ZERO",chCard) )
	{
		fprintf(ioQQQ," I will now div by 0 to get crash.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		ar1 = (float)(1. / ZeroNum);
		fprintf(ioQQQ," I am still alive - something is wrong, result is %e\n",
			ar1);
		lgCrash = TRUE;
	}

	/* use some undefined numbers */
	else if( lgMatch("UNDE",chCard) )
	{
		if( lgMatch("STAT",chCard) )
		{
			fprintf(ioQQQ," Now I will now use an undefined static variable.  Hold on.\n");
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
			fflush(ioQQQ);
			/*lint -e530 ar2 not initialized */
			ar2[0] *= 1e-10;
			/*lint +e530 ar2 not initialized */

			fprintf(ioQQQ," I am still alive - something is wrong, the result of the mult of undef by 1e-10 is %e\n", ar2[0] );
			fflush(ioQQQ);
		}
		else if( lgMatch("STAC",chCard) || lgMatch("AUTO",chCard) )
		{
			float a;
			fprintf(ioQQQ," Now I will now use an undefined variable off the stack.  Hold on.\n");
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
			fflush(ioQQQ);
			/*lint -e530 a not initialized */
			a *= 1e-10f;
			/*lint +e530 a not initialized */

			fprintf(ioQQQ," I am still alive - something is wrong, the result of the mult of undef by 1e-10 is %e\n", a );
			fflush(ioQQQ);
		}
		else /* if( lgMatch("HEAP",chCard) */
		{
			float *aa;
			fprintf(ioQQQ," I will now use an undefined variable off the heap obtained with malloc.  Hold on.\n");
#			if defined(NDEBUG) || defined(NOINIT)
			fprintf(ioQQQ," The malloc'ed memory was NOT initialized by MyMalloc.\n" );
#			else
			fprintf(ioQQQ," The malloc'ed memory was set to NaN.\n" );
#			endif
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
			fflush(ioQQQ);
			/* the array size must be odd to guarantee that MyMalloc will fill with float SNaN, PvH */
			if( ( aa = (float*)MALLOC(3*sizeof(float)) ) == NULL )
				BadMalloc();
			/*lint -e530 aa[1] not initialized */
			aa[1] *= 1e-10f;
			/*lint +e530 aa[1] not initialized */
			fprintf(ioQQQ," I am still alive - something is wrong, the result of the mult of undef by 1e-10 is %e\n", aa[1] );
			fflush(ioQQQ);
			free( aa );
		}
		
		lgCrash = TRUE;
	}

	/* make overflow to get crash as check on FP environment */
	else if( lgMatch("OVER",chCard) && lgMatch("LONG",chCard) )
	{ 
		long lng;
		fprintf(ioQQQ," I will now make long overflow to get crash.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		lng = (long)(LONG_MAX*sqrt(1e6) );
		fprintf(ioQQQ," I am still alive - something is wrong, the result was %li\n",
			lng);
		lgCrash = TRUE;
	}

	/* make overflow to get crash as check on FP environment */
	else if( lgMatch("OVER",chCard) )
	{ 
		ar1 = 1e-20f; 
		fprintf(ioQQQ," I will now make float overflow to get crash.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		br1 = (float)(DBL_MAX / ar1);
		fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
			br1);
		lgCrash = TRUE;
	}

	/* assert impossible to get crash as check on environment */
	else if( lgMatch("ASSE",chCard) )
	{ 
		fprintf(ioQQQ," I will now assert that a false statement is true to get a crash.\n\n");
		fprintf(ioQQQ," The correct behavior is for the statement \"PROBLEM An assert has been thrown, this is bad\" to be printed,\n     followed by a request to show the output to Gary Ferland.\n\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n\n");
		fflush(ioQQQ);
		ASSERT( DBL_MAX <  ZerO );
		fprintf(ioQQQ," I am still alive - the assert macro is not working in this executable.\n");
		lgCrash = TRUE;
	}

	/* assert ratios of zeros (NaN) to get crash as check on environment */
	else if( lgMatch(" NAN",chCard) )
	{ 
		ar1 = 0.;
		fprintf(ioQQQ," I will now make invalid operation (div 0 by 0) to get crash.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		br1 = (float)(ar1 / ZeroNum);
		fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
			br1);
		lgCrash = TRUE;
	}

	/* assert that the SET_FLT_SNAN macro works properly */
	else if( lgMatch("SETN",chCard) && lgMatch("FLOA",chCard) )
	{
		float f;
		fprintf(ioQQQ," I will now initialize a float to a signaling NaN. This should never crash!\n");
		SET_FLT_SNAN(f);
		fprintf(ioQQQ," Initialization finished. I will now perform an operation on this variable.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		f *= 2.f;
		fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
			f);
		lgCrash = TRUE;
	}

	/* assert that the SET_DBL_SNAN macro works properly */
	else if( lgMatch("SETN",chCard) )
	{
		double d;
		fprintf(ioQQQ," I will now initialize a double to a signaling NaN. This should never crash!\n");
		SET_DBL_SNAN(d);
		fprintf(ioQQQ," Initialization finished. I will now perform an operation on this variable.  Hold on.\n");
		fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong ....\" then there are problems.\n");
		fflush(ioQQQ);
		d *= 2.;
		fprintf(ioQQQ," I am still alive - something is wrong, the result was %e\n",
			d);
		lgCrash = TRUE;
	}

	/* array index out of bounds, two options, low and high */
	else if( lgMatch("BOUN",chCard) )
	{
		int lgEOL;
		double x;
		i = 5;
		/* read offset */
		x = FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL && lgMatch(" LOW", chCard ) )
			x = -2.;
		if( lgEOL && lgMatch("HIGH", chCard ) )
			x = 2.;
		i = ( x >= 0. ) ? (long)(x+0.5) + ARR_SIZE : (long)(x-0.5);
		/* must turn off pclint detection of logical errors in this block */
		/*lint -e662 out of bounds*/
		/*lint -e661 out of bounds*/
		if( lgMatch("STAT",chCard) )
		{
			fprintf(ioQQQ," I will now access static array element ar2[%ld].  Hold on.\n", i );
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then there are problems.\n");
			fflush(ioQQQ);
			ar2[i] = 1e-10;

			fprintf(ioQQQ," I am still alive - something is wrong\n" );
			fflush(ioQQQ);
		}
		else if( lgMatch("STAC",chCard) || lgMatch("AUTO",chCard) )
		{
			float a[ARR_SIZE];
			fprintf(ioQQQ," I will now access automatic array element a[%ld].  Hold on.\n", i );
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then there are problems.\n");
			fflush(ioQQQ);
			a[i] = 1e-10f;

			fprintf(ioQQQ," I am still alive - something is wrong, return value was %.2e\n" ,a[i] );
			fflush(ioQQQ);
		}
		else /* if( lgMatch("HEAP",chCard) */
		{
			int *ibound;		
			if( (ibound = ((int *)MALLOC( ARR_SIZE*sizeof(int) ))) == NULL )
				BadMalloc();
			fprintf(ioQQQ," I will now access heap array element ibound[%ld].  Hold on.\n", i );
			fprintf(ioQQQ," If the next line says \"I am still alive - something is wrong\" then there are problems.\n");
			fflush(ioQQQ);
			ibound[i] = 1;
			fprintf(ioQQQ," I am still alive - something is wrong, return value is %i\n" , ibound[i] );
			fflush(ioQQQ);
			free(ibound);
		}
		/*lint +e662 out of bounds*/
		/*lint +e661 out of bounds*/

		lgCrash = TRUE;
	}

	else
	{
		fprintf(ioQQQ,
			" crash options are ZERO, UNDEfined, OVERflow, ASSErt, _NAN, SETNAN, and BOUNds.\n");
		lgCrash = TRUE;
	}
	if( lgCrash )
	{
		puts( "[Stop in ParseCrashDo]" );
		cdEXIT(EXIT_FAILURE);
	}
}
/* turn this back on */
#ifdef _MSC_VER
#pragma warning( default : 4700 )/* disable warning that conditional expression*/
#endif
