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; } } }
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; }