/*  artherr.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */

#include <stream.h>
#include <stdio.h>
#include "artherr.h"
#include "usercom.h"
#include "portable.h"
#include "arthtyp.h"
#include "hrdarth.h"
#include "yacintfc.h"
#ifdef INTERACTIVE
#include "dspe_app.h"
#include "cgidbg.h"
#endif
#include <float.h>


void ReportOverflows(int32 NumberOfOverflows, int32 SaveOverflows,
	const char * Where)
{
#ifdef INTERACTIVE
	int HowOften = DspApplication::overflow_check_limit();
#else
	const HowOften = 400 ;
#endif
	// Report overflows if this is the first or if we exceed
	// a multiple of HowOften
	char buf[32] ;
	sprintf(buf,"%d",NumberOfOverflows + SaveOverflows);
	if (!SaveOverflows) State.Warning(buf,
		" total overflows in `",Where,"'");
	 else if (NumberOfOverflows/HowOften > SaveOverflows/HowOften) {
		HelpOut << NumberOfOverflows + SaveOverflows << 
		" total overflows in `" << Where << "'.\n" ;
	}
#ifdef INTERACTIVE
	if (DspApplication::is_trace())
		TheLog << NumberOfOverflows << " new overflow with a total of "
			<< NumberOfOverflows + SaveOverflows << " in `" <<
			Where << "'.\n" ;
#endif
}

// These two routines do not give warnings and are used in
// static initializers.

MachWord NormToHardLimitMachWord(double v)
{ 
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < MachWord::min_negative) v = MachWord::min_negative;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > MachWord::max_positive) v = MachWord::max_positive;
	}
	return (MachWordCast) v ;
}

AccMachWord NormToHardLimitAccMachWord(double v)
{
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < AccMachWord::min_negative) v = AccMachWord::min_negative;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > AccMachWord::max_positive) v = AccMachWord::max_positive;
	}
	return (AccMachWordCast) v ;
}



MachWord NormToMachWord(double v)
{ 
	int warn = 0 ;
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < MachWord::min_negative) v = MachWord::min_negative,warn=1 ;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > MachWord::max_positive) v = MachWord::max_positive,warn=1 ;
	}
	if (warn) MachWord::hard_limit_warn();
	return (MachWordCast) v ;
}

AccMachWord NormToAccMachWord(double v)
{
	int warn = 0 ;
	v *= NormToOneMachWord ;
	if (v < 0) {
#ifdef INTEGER_MACH_WORD_TYPE
		v -= .5 ;
#endif
		if (v < AccMachWord::min_negative) v = AccMachWord::min_negative,warn=1 ;
	} else {
#ifdef INTEGER_MACH_WORD_TYPE
		v += .5 ;
#endif
		if (v > AccMachWord::max_positive) v = AccMachWord::max_positive,warn=1 ;
	}
	if (warn) MachWord::hard_limit_warn("AccMachWord");
	return (AccMachWordCast) v ;
}



void MachWord::hard_limit_warn(const char * type)
{
	State.Warning("`", type, "' overflow, value has been hard limited");
#ifdef INTERACTIVE
        if (DspApplication::is_trace()) TheLog << "`" << type <<
            "' overflow, value has been hard limited.\n"  ;
#endif

}


IntegerMachWord MachWord::convert_int_check(int32 v)
{
	int warn = 0 ;
	if (v > max_int_positive) v = max_int_positive,warn=1;
	else if (v < min_int_negative) v = min_int_negative,warn=1;
	if (warn) hard_limit_warn("IntegerMachWord");
	return v ;
}

UnsignedIntegerMachWord MachWord::convert_unsigned_int_check(int32 v)
{
    int warn = 0 ;
    if (v > max_unsigned_int) v = max_unsigned_int,warn=1;
    else if (v < 0) v = 0,warn=1;
    if (warn) hard_limit_warn("UsignedIntegerMachWord");
	return v ;
}

IntegerMachWord MachWord::convert_int_check(double v)
{
	int warn = 0 ;
	if (v > max_int_positive) v = max_int_positive,warn=1;
	else if (v < min_int_negative) v = min_int_negative,warn=1;
	if (warn) hard_limit_warn("IntegerMachWord");
	return (IntegerMachWord) v ;
}

UnsignedIntegerMachWord MachWord::convert_unsigned_int_check(double v)
{
    int warn = 0 ;
    if (v > max_unsigned_int) v = max_unsigned_int,warn=1;
    else if (v < 0) v = 0,warn=1;
    if (warn) hard_limit_warn("UsignedIntegerMachWord");
	return (UnsignedIntegerMachWord) v ;
}

int32 MachWord::convert_int32_check(MachWord vv)
{
	MachWordCast v = vv.val();
	int warn = 0 ;
	int32 val ;
	int32 min = -0x80000000 ;
	int32 max =  0x7fffffff;
	if (v < min) val = min, warn = 1 ;
	if (v > max) val = max, warn = 1 ;
	if (warn) hard_limit_warn("int32");
	else val = (int32) v ;
	return val ;
}

IntegerMachWord MachWord::convert_check(MachWord vv)
{
	MachWordCast v = vv.val() ;
	int warn = 0 ;
	IntegerMachWord val ;
	if (v < min_int_negative) val = min_int_negative,warn = 1 ;
	if (v > max_int_positive) val = max_int_positive,warn = 1 ;
	if (warn) hard_limit_warn("IntegerMachWord");
	else val = (IntegerMachWord) v ;
	return val ;
}

MachWordCast MachWord::convert_MachWord_check(IntegerMachWord v)
{
	int warn = 0 ;
	MachWordCast val ;
	if (v < min_negative) val = min_negative, warn = 1 ;
	if (v > max_positive) val = max_positive, warn = 1 ;
	if (warn) hard_limit_warn();
	else val = (MachWordCast) v ;
	return val ;
}


