Exemple #1
0
dsc* EVAL_value(qli_nod* node)
{
/**************************************
 *
 *	E V A L _ v a l u e
 *
 **************************************
 *
 * Functional description
 *	Evaluate a value node.
 *
 **************************************/
	DSC *values[4];

	// Start by evaluating sub-expressions (where appropriate)

	dsc* desc = &node->nod_desc;
	fb_assert(node->nod_count < 5);
	qli_nod** ptr = node->nod_arg;
	const qli_nod* const* const end_ptr = ptr + node->nod_count;

	for (dsc** value = values; ptr < end_ptr; ptr++, value++)
	{
		*value = EVAL_value(*ptr);
		if (node->nod_flags & nod_partial)
			break;
	}

	switch (node->nod_type)
	{
	case nod_edit_blob:
		return execute_edit(node);

	case nod_rpt_max:
	case nod_rpt_min:
	case nod_rpt_total:
	case nod_rpt_average:
		if (!(IPTR) node->nod_arg[e_stt_default])
			desc->dsc_missing = DSC_missing;

	case nod_rpt_count:
	case nod_constant:
		return desc;

	case nod_variable:
		{
			qli_fld* field = (qli_fld*) node->nod_arg[e_fld_field];
			desc->dsc_missing = (field->fld_flags & FLD_missing) ? DSC_missing : 0;
		}
		return desc;

	case nod_field:
		return EVAL_value(node->nod_arg[e_fld_reference]);

	case nod_reference:
		return EVAL_parameter(node->nod_import);

	case nod_null:
		return desc;

	case nod_add:
		if ((values[0]->dsc_missing & DSC_missing) || (values[1]->dsc_missing & DSC_missing))
		{
			desc->dsc_missing = DSC_missing;
			return desc;
		}
		desc->dsc_missing = FALSE;
		if (node->nod_flags & nod_date)
		{
			double d1 = MOVQ_date_to_double(values[0]) + MOVQ_get_double(values[1]);
			MOVQ_double_to_date(d1, (SLONG*) desc->dsc_address);
		}
		else if (desc->dsc_dtype == dtype_long)
		{
			*((SLONG*) desc->dsc_address) =
				MOVQ_get_long(values[0], desc->dsc_scale) + MOVQ_get_long(values[1], desc->dsc_scale);
		}
		else
			*((double*) desc->dsc_address) = MOVQ_get_double(values[0]) + MOVQ_get_double(values[1]);
		return desc;

	case nod_subtract:
		if ((values[0]->dsc_missing & DSC_missing) || (values[1]->dsc_missing & DSC_missing))
		{
			desc->dsc_missing = DSC_missing;
			return desc;
		}
		desc->dsc_missing = FALSE;
		if (node->nod_flags & nod_date)
		{
			*((double*) desc->dsc_address) =
				MOVQ_date_to_double(values[0]) - MOVQ_date_to_double(values[1]);
		}
		else if (desc->dsc_dtype == dtype_long)
		{
			*((SLONG*) desc->dsc_address) =
				MOVQ_get_long(values[0], desc->dsc_scale) - MOVQ_get_long(values[1], desc->dsc_scale);
		}
		else
			*((double*) desc->dsc_address) = MOVQ_get_double(values[0]) - MOVQ_get_double(values[1]);
		return desc;

	case nod_divide:
		if ((values[0]->dsc_missing & DSC_missing) || (values[1]->dsc_missing & DSC_missing))
		{
			desc->dsc_missing = DSC_missing;
			return desc;
		}
		desc->dsc_missing = FALSE;
		*((double*) desc->dsc_address) = MOVQ_get_double(values[0]) / MOVQ_get_double(values[1]);
		return desc;

	case nod_multiply:
		if ((values[0]->dsc_missing & DSC_missing) || (values[1]->dsc_missing & DSC_missing))
		{
			desc->dsc_missing = DSC_missing;
			return desc;
		}
		desc->dsc_missing = FALSE;
		if (desc->dsc_dtype == dtype_long)
		{
			*((SLONG*) desc->dsc_address) =
				MOVQ_get_long(values[0], values[0]->dsc_scale) *
				MOVQ_get_long(values[1], values[1]->dsc_scale);
		}
		else
			*((double*) desc->dsc_address) = MOVQ_get_double(values[0]) * MOVQ_get_double(values[1]);
		return desc;

	case nod_negate:
		if (values[0]->dsc_missing & DSC_missing)
		{
			desc->dsc_missing = DSC_missing;
			return desc;
		}
		desc->dsc_missing = FALSE;
		switch (desc->dsc_dtype)
		{
		case dtype_short:
			*((SSHORT*) desc->dsc_address) = -MOVQ_get_long(values[0], desc->dsc_scale);
			break;

		case dtype_long:
			*((SLONG*) desc->dsc_address) = -MOVQ_get_long(values[0], desc->dsc_scale);
			break;

		// lets throw arithmetic not supported until fixed
        //case dtype_int64:
		//	*((SINT64*) desc->dsc_address) = -MOVQ_get_long(values[0], desc->dsc_scale);
		//	break;

		case dtype_real:
			*((float*) desc->dsc_address) = -MOVQ_get_double(values[0]);
			break;

		case dtype_double:
			*((double*) desc->dsc_address) = -MOVQ_get_double(values[0]);
			break;

		default:
			IBERROR(30);		// Msg30 data type not supported for arithmetic
		}
		return desc;

	case nod_prompt:
		if (!prompt[0][0])
		{
			ERRQ_msg_get(499, prompt[0], sizeof(prompt[0]));	// Msg499 Re-enter
			ERRQ_msg_get(500, prompt[1], sizeof(prompt[1]));	// Msg500 Enter
		}
		return execute_prompt(node);

	case nod_concatenate:
		return execute_concatenate(node, values[0], values[1]);

	case nod_function:
		return execute_function(node);

	case nod_max:
	case nod_min:
	case nod_count:
	case nod_average:
	case nod_total:
	case nod_from:
		return execute_statistical(node);

	case nod_running_count:
		*(SLONG*) (desc->dsc_address) += 1;
		return desc;

	case nod_running_total:
		{
			dsc* desc2 = EVAL_value(node->nod_arg[e_stt_value]);
			if (desc2)
			{
				if (desc2->dsc_missing & DSC_missing)
					return desc;
				if (desc->dsc_dtype == dtype_long)
					*(SLONG*) desc->dsc_address += MOVQ_get_long(desc2, desc->dsc_scale);
				else
					*(double*) desc->dsc_address += MOVQ_get_double(desc2);
			}
		}
		return desc;

	case nod_format:
		{
			UCHAR* p = desc->dsc_address;
			PIC_edit(values[0], (pics*) node->nod_arg[e_fmt_picture], (TEXT**) &p, desc->dsc_length);
			desc->dsc_length = p - desc->dsc_address;
		}
		return desc;

	case nod_user_name:
		IBERROR(31);			// Msg31 user name is supported only in RSEs temporarily

	case nod_parameter:
	case nod_position:
	case nod_substr:
	case nod_via:

	default:
		ERRQ_bugcheck(29);			// Msg29 EVAL_value: not finished
		return NULL;
	}
}
static void edit_numeric(const dsc* desc, pics* picture, TEXT** output)
{
/**************************************
 *
 *	e d i t _ n u m e r i c
 *
 **************************************
 *
 * Functional description
 *	Edit data from a descriptor through an edit string to a running
 *	output pointer.
 *
 **************************************/
	bool overflow = false;

	TEXT* out = *output;

	double number = MOVQ_get_double(desc);
	const bool negative = (number < 0);
	if (negative)
	{
		number = -number;
		if (!(picture->pic_flags & PIC_signed))
			overflow = true;
	}

    SSHORT scale = picture->pic_fractions;
	if (scale)
	{
		if (scale < 0)
		{
			do {
				number /= 10.;
			} while (++scale);
		}
		else if (scale > 0)
		{
			do {
				number *= 10.;
			} while (--scale);
		}
	}

	TEXT temp[512];
	TEXT* p = temp;
	TEXT* digits = p;

	double check;
	USHORT power;
	if (picture->pic_digits && !overflow)
	{
		for (check = number, power = picture->pic_digits; power; --power)
			check /= 10.0;
		if (check >= 1)
			overflow = true;
		else
		{
			sprintf(digits, "%0*.0f", picture->pic_digits, number);
			p = digits + strlen(digits);
		}
	}

	picture->pic_pointer = picture->pic_string;
	bool hex_overflow = false;
	const TEXT* hex = 0;
	if (picture->pic_hex_digits)
	{
		hex = p;
		p += picture->pic_hex_digits;
		for (check = number, power = picture->pic_hex_digits; power; --power)
			check /= 16.0;
		if (check >= 1)
			hex_overflow = true;
		else
		{
			SLONG nh = static_cast<SLONG>(number);
			while (p-- > hex)
			{
				*p = "0123456789abcdef"[nh & 15];
				nh >>= 4;
			}
		}
	}
Exemple #3
0
void EVAL_break_increment( qli_nod* node)
{
/**************************************
 *
 *	E V A L _ b r e a k _ i n c r e m e n t
 *
 **************************************
 *
 * Functional description
 *	Initialize a report-local statistical function.
 *
 **************************************/
	DSC* desc1 = &node->nod_desc;

	// Knock off count as trivial

	if (node->nod_type == nod_rpt_count)
	{
		*(SLONG *) node->nod_desc.dsc_address += 1;
		return;
	}

	// Evaluate the sub-expression.  If null, don't bother to do anything
	// more.  If not, bump the number of records involved

	dsc* desc2 = EVAL_value(node->nod_arg[e_stt_value]);
	if (!desc2)
		return;

	// If this is the first value, just move it in.

	const SLONG count = (IPTR) node->nod_arg[e_stt_default] + 1;
	if (count == 1)
	{
		if (desc2->dsc_missing)
			desc1->dsc_missing = DSC_missing;
		else
		{
			desc1->dsc_missing = FALSE;
			MOVQ_move(desc2, desc1);
			node->nod_arg[e_stt_default] = (qli_nod*) (IPTR) count;
		}
		return;
	}
	if (desc2->dsc_missing)
		return;

	node->nod_arg[e_stt_default] = (qli_nod*) (IPTR) count;
	desc1->dsc_missing = FALSE;

	// Finish off as per operator

	SSHORT comparison;

	switch (node->nod_type)
	{
	case nod_rpt_min:
	case nod_rpt_max:
		if (!(comparison = MOVQ_compare(desc2, desc1)))
			break;
		if ((comparison > 0 && node->nod_type == nod_rpt_max) ||
			(comparison < 0 && node->nod_type == nod_rpt_min))
		{
			MOVQ_move(desc2, desc1);
		}
		break;

	case nod_rpt_total:
	case nod_rpt_average:
		if (desc1->dsc_dtype == dtype_long)
			*(SLONG *) desc1->dsc_address += MOVQ_get_long(desc2, desc1->dsc_scale);
		else
			*(double *) desc1->dsc_address += MOVQ_get_double(desc2);
		break;
	}
}
static void edit_float( const dsc* desc, pics* picture, TEXT** output)
{
/**************************************
 *
 *	e d i t _ f l o a t
 *
 **************************************
 *
 * Functional description
 *	Edit data from a descriptor through an edit string to a running
 *	output pointer.
 *
 **************************************/
	TEXT temp[512];
	USHORT l, width, decimal_digits, w_digits, f_digits;

	double number = MOVQ_get_double(desc);
	const bool negative = (number < 0);
	if (negative)
		number = -number;

	// If exponents are explicitly requested (E-format edit_string), generate them.
	// Otherwise, the rules are: if the number in f-format will fit into the allotted
	// space, print it in f-format; otherwise print it in e-format.
	// (G-format is untrustworthy.)

	if (isnan(number))
		sprintf(temp, "NaN");
	else if (isinf(number))
		sprintf(temp, "Infinity");
	else if (picture->pic_exponents)
	{
		width = picture->pic_print_length - picture->pic_floats - picture->pic_literals;
		decimal_digits = picture->pic_fractions;
		sprintf(temp, "%*.*e", width, decimal_digits, number);
	}
	else if (number == 0)
		sprintf(temp, "%.0f", number);
	else
	{
		width = picture->pic_float_digits - 1 + picture->pic_floats;
		f_digits = (width > 2) ? width - 2 : 0;
		sprintf(temp, "%.*f", f_digits, number);
		w_digits = strlen(temp);
		if (f_digits)
		{
			TEXT* p = temp + w_digits;	// find the end
			w_digits = w_digits - (f_digits + 1);
			while (*--p == '0')
				--f_digits;
			if (*p != '.')
				++p;
			*p = 0;				// move the end
		}
		if ((w_digits > width) || (!f_digits && w_digits == 1 && temp[0] == '0'))
		{
			// if the number doesn't fit in the default window, revert
			// to exponential notation; displaying the maximum number of
			// mantissa digits.

			if (number < 1e100)
				decimal_digits = (width > 6) ? width - 6 : 0;
			else
				decimal_digits = (width > 7) ? width - 7 : 0;
			sprintf(temp, "%.*e", decimal_digits, number);
		}
	}

	TEXT* p = temp;
	picture->pic_pointer = picture->pic_string;
	picture->pic_count = 0;
	TEXT* out = *output;

	for (l = picture->pic_length - picture->pic_print_length; l > 0; --l)
		*out++ = ' ';

	bool is_signed = false;

	for (;;)
	{
		const TEXT e = generate(picture);
		TEXT c = e;
		if (!c || c == '?')
			break;
		c = UPPER(c);

		switch (c)
		{
		case 'G':
			if (!is_signed)
			{
				if (negative)
					*out++ = '-';
				else
					*out++ = ' ';
				is_signed = true;
			}
			else if (*p)
				*out++ = *p++;
			break;

		case 'B':
			*out++ = ' ';
			break;

		case '"':
		case '\'':
		case '\\':
			literal(picture, c, &out);
			break;

		case '9':
		case 'Z':
			{
				if (!(*p) || *p > '9' || *p < '0')
					break;
				TEXT d = *p++;
				if (c == '9' && d == ' ')
					d = '0';
				else if (c == 'Z' && d == '0')
					d = ' ';
				*out++ = d;
			}
			break;

		case '.':
			*out++ = (*p == c) ? *p++ : c;
			break;

		case 'E':
			if (!*p)
				break;
			*out++ = e;
			if (UPPER(*p) == c)
				++p;
			break;

		case '+':
		case '-':
			if (!*p)
				break;
			if (*p != '+' && *p != '-')
			{
				if (is_signed)
					*out++ = c;
				else if (c == '-' && !negative)
					*out++ = ' ';
				else if (c == '+' && negative)
					*out++ = '-';
				else
					*out++ = c;
				is_signed = true;
			}
			else if (*p == '-' || c == '+')
				*out++ = *p++;
			else
			{
				*out++ = ' ';
				p++;
			}
			break;

		default:
			*out++ = c;
			break;
		}
	}

	*output = out;
}