mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-25 00:43:03 +01:00
1663 lines
39 KiB
C++
1663 lines
39 KiB
C++
|
/*
|
||
|
* PROGRAM: JRD Command Oriented Query Language
|
||
|
* MODULE: eval.c
|
||
|
* DESCRIPTION: Value and boolean expression evaluator
|
||
|
*
|
||
|
* The contents of this file are subject to the Interbase Public
|
||
|
* License Version 1.0 (the "License"); you may not use this file
|
||
|
* except in compliance with the License. You may obtain a copy
|
||
|
* of the License at http://www.Inprise.com/IPL.html
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an
|
||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||
|
* or implied. See the License for the specific language governing
|
||
|
* rights and limitations under the License.
|
||
|
*
|
||
|
* The Original Code was created by Inprise Corporation
|
||
|
* and its predecessors. Portions created by Inprise Corporation are
|
||
|
* Copyright (C) Inprise Corporation.
|
||
|
*
|
||
|
* All Rights Reserved.
|
||
|
* Contributor(s): ______________________________________.
|
||
|
*/
|
||
|
|
||
|
#include "../jrd/ib_stdio.h"
|
||
|
#include <string.h>
|
||
|
#include "../include/jrd/gds.h"
|
||
|
#include "../jrd/common.h"
|
||
|
#include "../qli/dtr.h"
|
||
|
#include "../qli/exe.h"
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
#include "../jrd/kanji.h"
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
#include "../qli/err_proto.h"
|
||
|
#include "../qli/eval_proto.h"
|
||
|
#include "../qli/exe_proto.h"
|
||
|
#include "../qli/form_proto.h"
|
||
|
#include "../qli/lex_proto.h"
|
||
|
#include "../qli/mov_proto.h"
|
||
|
#include "../qli/picst_proto.h"
|
||
|
#include "../jrd/gds_proto.h"
|
||
|
#include "../jrd/utl_proto.h"
|
||
|
|
||
|
typedef struct vary {
|
||
|
USHORT vary_length;
|
||
|
TEXT vary_string[1];
|
||
|
} VARY;
|
||
|
|
||
|
extern USHORT QLI_prompt_count, QLI_reprompt;
|
||
|
extern USHORT sw_forms;
|
||
|
|
||
|
static SLONG execute_any(NOD);
|
||
|
static DSC *execute_concatenate(NOD, DSC *, DSC *);
|
||
|
static DSC *execute_edit(NOD);
|
||
|
static DSC *execute_function(NOD);
|
||
|
static DSC *execute_prompt(NOD);
|
||
|
static DSC *execute_statistical(NOD);
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int like(USHORT *, SSHORT, USHORT *, SSHORT, USHORT);
|
||
|
static int like2(UCHAR *, SSHORT, UCHAR *, SSHORT, UCHAR);
|
||
|
#else
|
||
|
static int like(UCHAR *, SSHORT, UCHAR *, SSHORT, UCHAR);
|
||
|
#endif
|
||
|
static TEXT *make_blob_buffer(SLONG *, USHORT *);
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int matches(USHORT *, SSHORT, USHORT *, SSHORT);
|
||
|
static int matches2(UCHAR *, SSHORT, UCHAR *, SSHORT);
|
||
|
#else
|
||
|
static int matches(TEXT *, SSHORT, TEXT *, SSHORT);
|
||
|
#endif
|
||
|
static int sleuth(NOD, DSC *, DSC *, DSC *);
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int sleuth_check(USHORT, USHORT *, USHORT *, USHORT *, USHORT *);
|
||
|
static int sleuth_check2(USHORT, TEXT *, TEXT *, TEXT *, TEXT *);
|
||
|
static int sleuth_class(USHORT, USHORT *, USHORT *, USHORT);
|
||
|
#else
|
||
|
static int sleuth_check(USHORT, UCHAR *, UCHAR *, UCHAR *, UCHAR *);
|
||
|
static int sleuth_class(USHORT, UCHAR *, UCHAR *, UCHAR);
|
||
|
#endif
|
||
|
static int sleuth_merge(UCHAR *, UCHAR *, UCHAR *, UCHAR *, UCHAR *);
|
||
|
static int string_boolean(NOD);
|
||
|
static int string_function(NOD, SSHORT, TEXT *, SSHORT, TEXT *);
|
||
|
|
||
|
#define TEMP_LENGTH 128
|
||
|
#define SLEUTH_insensitive 1
|
||
|
#define COND_UPPER(c) ((flags & SLEUTH_insensitive) ? UPPER(c) : c)
|
||
|
|
||
|
static UCHAR special[127] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||
|
0, 1, 1, 0, 1,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||
|
};
|
||
|
|
||
|
static TEXT prompt[2][128] = { "", "" };
|
||
|
|
||
|
|
||
|
int EVAL_boolean( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E V A L _ b o o l e a n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Evaluate a boolean expression.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *value1, *value2, *value3;
|
||
|
TEXT *p;
|
||
|
int result;
|
||
|
|
||
|
switch (node->nod_type) {
|
||
|
case nod_eql:
|
||
|
case nod_neq:
|
||
|
case nod_gtr:
|
||
|
case nod_geq:
|
||
|
case nod_leq:
|
||
|
case nod_lss:
|
||
|
case nod_between:
|
||
|
if (!(value1 = EVAL_value(node->nod_arg[0])) ||
|
||
|
(value1->dsc_missing & DSC_missing) ||
|
||
|
!(value2 = EVAL_value(node->nod_arg[1])) ||
|
||
|
(value2->dsc_missing & DSC_missing)) return FALSE;
|
||
|
if (node->nod_flags & nod_comparison)
|
||
|
result = MOVQ_compare(value1, value2);
|
||
|
break;
|
||
|
|
||
|
case nod_and:
|
||
|
case nod_or:
|
||
|
case nod_not:
|
||
|
result = EVAL_boolean(node->nod_arg[0]);
|
||
|
break;
|
||
|
|
||
|
case nod_containing:
|
||
|
case nod_matches:
|
||
|
case nod_like:
|
||
|
case nod_starts:
|
||
|
case nod_sleuth:
|
||
|
result = string_boolean(node);
|
||
|
}
|
||
|
|
||
|
switch (node->nod_type) {
|
||
|
case nod_eql:
|
||
|
return (result == 0);
|
||
|
case nod_neq:
|
||
|
return (result != 0);
|
||
|
case nod_gtr:
|
||
|
return (result > 0);
|
||
|
case nod_geq:
|
||
|
return (result >= 0);
|
||
|
case nod_leq:
|
||
|
return (result <= 0);
|
||
|
case nod_lss:
|
||
|
return (result < 0);
|
||
|
|
||
|
case nod_between:
|
||
|
if (result < 0)
|
||
|
return FALSE;
|
||
|
if (!(value2 = EVAL_value(node->nod_arg[2])) ||
|
||
|
(value2->dsc_missing & DSC_missing)) return FALSE;
|
||
|
result = MOVQ_compare(value1, value2);
|
||
|
if (result > 0)
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
|
||
|
case nod_missing:
|
||
|
value1 = EVAL_value(node->nod_arg[0]);
|
||
|
if (value1)
|
||
|
return (value1->dsc_missing & DSC_missing);
|
||
|
return TRUE;
|
||
|
|
||
|
case nod_and:
|
||
|
if (!result)
|
||
|
return FALSE;
|
||
|
return EVAL_boolean(node->nod_arg[1]);
|
||
|
|
||
|
case nod_or:
|
||
|
if (result)
|
||
|
return TRUE;
|
||
|
return EVAL_boolean(node->nod_arg[1]);
|
||
|
|
||
|
case nod_not:
|
||
|
return !result;
|
||
|
|
||
|
case nod_any:
|
||
|
case nod_unique:
|
||
|
return execute_any(node);
|
||
|
|
||
|
case nod_sleuth:
|
||
|
case nod_containing:
|
||
|
case nod_matches:
|
||
|
case nod_like:
|
||
|
case nod_starts:
|
||
|
return result;
|
||
|
|
||
|
default:
|
||
|
BUGCHECK(28); /* Msg28 EVAL_boolean: not finished */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void EVAL_break_compute( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E V A L _ b r e a k _ c o m p u t e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Compute the value of a statistical expression at control
|
||
|
* break. The only function that needs any work is average.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *desc1;
|
||
|
|
||
|
if (node->nod_type == nod_rpt_average && node->nod_arg[e_stt_default])
|
||
|
if (node->nod_desc.dsc_dtype == dtype_long)
|
||
|
*(SLONG *) node->nod_desc.dsc_address /= (SLONG) node->
|
||
|
nod_arg[e_stt_default];
|
||
|
else
|
||
|
*(double *) node->nod_desc.dsc_address /= (SLONG) node->
|
||
|
nod_arg[e_stt_default];
|
||
|
}
|
||
|
|
||
|
|
||
|
void EVAL_break_increment( 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, *desc2;
|
||
|
SLONG count;
|
||
|
SSHORT comparison;
|
||
|
|
||
|
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 */
|
||
|
|
||
|
if (!(desc2 = EVAL_value(node->nod_arg[e_stt_value])))
|
||
|
return;
|
||
|
|
||
|
/* If this is the first value, just move it in. */
|
||
|
|
||
|
count = (SLONG) 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] = (NOD) (SLONG) count;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
else if (desc2->dsc_missing)
|
||
|
return;
|
||
|
|
||
|
node->nod_arg[e_stt_default] = (NOD) (SLONG) count;
|
||
|
desc1->dsc_missing = FALSE;
|
||
|
|
||
|
/* Finish off as per operator */
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void EVAL_break_init( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E V A L _ b r e a k _ i n i t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Initialize a report-local statistical function.
|
||
|
*
|
||
|
**************************************/
|
||
|
|
||
|
node->nod_arg[e_stt_default] = 0;
|
||
|
node->nod_desc.dsc_missing = FALSE;
|
||
|
|
||
|
if (node->nod_type == nod_rpt_count)
|
||
|
*(SLONG *) (node->nod_desc.dsc_address) = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
DSC *EVAL_parameter(PAR parameter)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E V A L _ p a r a m e t e r
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Compute the descriptor for a parameter.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *desc;
|
||
|
MSG message;
|
||
|
PAR missing_parameter;
|
||
|
USHORT *missing_flag;
|
||
|
|
||
|
desc = ¶meter->par_desc;
|
||
|
desc->dsc_missing = FALSE;
|
||
|
message = parameter->par_message;
|
||
|
|
||
|
if (missing_parameter = parameter->par_missing) {
|
||
|
missing_flag =
|
||
|
(USHORT *) (message->msg_buffer + missing_parameter->par_offset);
|
||
|
desc->dsc_missing = (*missing_flag) ? DSC_missing : 0;
|
||
|
}
|
||
|
|
||
|
desc->dsc_address = message->msg_buffer + parameter->par_offset;
|
||
|
|
||
|
return desc;
|
||
|
}
|
||
|
|
||
|
|
||
|
DSC *EVAL_value(NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* E V A L _ v a l u e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Evaluate a value node.
|
||
|
*
|
||
|
**************************************/
|
||
|
NOD *ptr, *end_ptr;
|
||
|
FLD field;
|
||
|
DSC *values[4], **value, *desc, *desc2;
|
||
|
UCHAR *p;
|
||
|
double d1;
|
||
|
|
||
|
/* Start by evaluating sub-expressions (where appropriate) */
|
||
|
|
||
|
desc = &node->nod_desc;
|
||
|
ptr = node->nod_arg;
|
||
|
end_ptr = ptr + node->nod_count;
|
||
|
|
||
|
for (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 (!(SLONG) node->nod_arg[e_stt_default])
|
||
|
desc->dsc_missing = DSC_missing;
|
||
|
|
||
|
case nod_rpt_count:
|
||
|
case nod_constant:
|
||
|
return desc;
|
||
|
|
||
|
case nod_variable:
|
||
|
field = (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) {
|
||
|
d1 = MOVQ_date_to_double(values[0]) + MOVQ_get_double(values[1]);
|
||
|
MOVQ_double_to_date(d1, 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;
|
||
|
|
||
|
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]); /* Msg499 Re-enter */
|
||
|
ERRQ_msg_get(500, 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:
|
||
|
if (desc2 = EVAL_value(node->nod_arg[e_stt_value])) {
|
||
|
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:
|
||
|
p = desc->dsc_address;
|
||
|
PIC_edit(values[0], node->nod_arg[e_fmt_picture], &p,
|
||
|
desc->dsc_length);
|
||
|
desc->dsc_length = p - desc->dsc_address;
|
||
|
return desc;
|
||
|
|
||
|
case nod_form_field:
|
||
|
return FORM_get_field(node);
|
||
|
|
||
|
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:
|
||
|
BUGCHECK(29); /* Msg29 EVAL_value: not finished */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static SLONG execute_any( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ a n y
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Execute an ANY expression. This may require that a request get
|
||
|
* started, a message sent, and a message received for each
|
||
|
* record. At the other end of the spectrum, there may be
|
||
|
* absolutely nothing to do.
|
||
|
*
|
||
|
**************************************/
|
||
|
REQ request;
|
||
|
MSG message;
|
||
|
USHORT *flag;
|
||
|
|
||
|
/* If there is a request associated with the node, start it and possibly
|
||
|
send a message along with it. */
|
||
|
|
||
|
if (request = (REQ) node->nod_arg[e_any_request])
|
||
|
EXEC_start_request(request, node->nod_arg[e_any_send]);
|
||
|
else if (message = (MSG) node->nod_arg[e_any_send])
|
||
|
EXEC_send(message);
|
||
|
|
||
|
message = (MSG) node->nod_arg[e_any_receive];
|
||
|
EXEC_receive(message, 0);
|
||
|
|
||
|
return MOVQ_get_long(EVAL_parameter(node->nod_import), 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
static DSC *execute_concatenate( NOD node, DSC * value1, DSC * value2)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ c o n c a t e n a t e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Concatenate two strings.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *desc;
|
||
|
VARY *vary;
|
||
|
TEXT *p, temp1[32], temp2[32], *address1, *address2;
|
||
|
USHORT length1, length2;
|
||
|
|
||
|
length1 = MOVQ_get_string(value1, &address1, temp1, sizeof(temp1));
|
||
|
length2 = MOVQ_get_string(value2, &address2, temp2, sizeof(temp2));
|
||
|
desc = &node->nod_desc;
|
||
|
vary = (VARY *) desc->dsc_address;
|
||
|
p = vary->vary_string;
|
||
|
length1 = MIN(length1, desc->dsc_length - 2);
|
||
|
length2 = MAX(MIN(length2, desc->dsc_length - 2 - length1), 0);
|
||
|
|
||
|
if (length1)
|
||
|
do
|
||
|
*p++ = *address1++;
|
||
|
while (--length1);
|
||
|
|
||
|
if (length2)
|
||
|
do
|
||
|
*p++ = *address2++;
|
||
|
while (--length2);
|
||
|
|
||
|
vary->vary_length = p - vary->vary_string;
|
||
|
|
||
|
return desc;
|
||
|
}
|
||
|
|
||
|
|
||
|
static DSC *execute_edit( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ e d i t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Edit a blob. If there's an existing
|
||
|
* blob for input, force the descriptor
|
||
|
* to quad to get move the id.
|
||
|
*
|
||
|
**************************************/
|
||
|
SLONG *id;
|
||
|
DSC *desc;
|
||
|
DBB dbb;
|
||
|
TEXT *field_name;
|
||
|
|
||
|
dbb = (DBB) node->nod_arg[e_edt_dbb];
|
||
|
id = (SLONG *) & node->nod_arg[e_edt_id1];
|
||
|
|
||
|
desc = NULL;
|
||
|
|
||
|
if (node->nod_arg[e_edt_input]) {
|
||
|
desc = EVAL_value(node->nod_arg[e_edt_input]);
|
||
|
if (desc && (desc->dsc_dtype == dtype_blob)) {
|
||
|
desc->dsc_dtype = dtype_quad;
|
||
|
MOVQ_move(desc, &node->nod_desc);
|
||
|
desc->dsc_dtype = dtype_blob;
|
||
|
}
|
||
|
}
|
||
|
if (!desc)
|
||
|
id[0] = id[1] = NULL;
|
||
|
|
||
|
field_name = (TEXT *) node->nod_arg[e_edt_name];
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
BLOB_edit2(id, dbb->dbb_handle, dbb->dbb_transaction, field_name,
|
||
|
node->nod_desc.dsc_sub_type);
|
||
|
#else
|
||
|
BLOB_edit(id, dbb->dbb_handle, dbb->dbb_transaction, field_name);
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
node->nod_desc.dsc_missing = (id[0] || id[1]) ? 0 : DSC_missing;
|
||
|
|
||
|
return &node->nod_desc;
|
||
|
}
|
||
|
|
||
|
|
||
|
static DSC *execute_function( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ f u n c t i o n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Execute a statistical expression.
|
||
|
*
|
||
|
**************************************/
|
||
|
REQ request;
|
||
|
MSG message;
|
||
|
PAR parameter;
|
||
|
|
||
|
/* If there is a request associated with the node, start it and possibly
|
||
|
send a message along with it. */
|
||
|
|
||
|
if (request = (REQ) node->nod_arg[e_fun_request])
|
||
|
EXEC_start_request(request, node->nod_arg[e_fun_send]);
|
||
|
else if (message = (MSG) node->nod_arg[e_fun_send])
|
||
|
EXEC_send(message);
|
||
|
|
||
|
return EXEC_receive(node->nod_arg[e_fun_receive], node->nod_import);
|
||
|
}
|
||
|
|
||
|
|
||
|
static DSC *execute_prompt( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ p r o m p t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Execute a prompt and return a descriptor. If end of file,
|
||
|
* abort request; if a singleton tab, return the previous value,
|
||
|
* and if a null string, return MISSING.
|
||
|
*
|
||
|
**************************************/
|
||
|
TEXT *p, string[128], *value, buffer[256];
|
||
|
DSC *desc;
|
||
|
USHORT reprompt;
|
||
|
VARY *data;
|
||
|
int length, l;
|
||
|
|
||
|
if (sw_forms)
|
||
|
FORM_reset();
|
||
|
|
||
|
ERRQ_pending();
|
||
|
reprompt = QLI_reprompt;
|
||
|
desc = &node->nod_desc;
|
||
|
data = (VARY *) desc->dsc_address;
|
||
|
|
||
|
value =
|
||
|
(desc->dsc_length - 2 <= sizeof(buffer)) ? buffer : data->vary_string;
|
||
|
length =
|
||
|
(desc->dsc_length - 2 <=
|
||
|
sizeof(buffer)) ? sizeof(buffer) : desc->dsc_length - 2;
|
||
|
|
||
|
for (;;) {
|
||
|
++QLI_prompt_count;
|
||
|
if (node->nod_arg[e_prm_prompt]) {
|
||
|
if (reprompt)
|
||
|
sprintf(string, "\07%s %s: ", prompt[0],
|
||
|
node->nod_arg[e_prm_prompt]);
|
||
|
else
|
||
|
sprintf(string, "%s %s: ", prompt[1],
|
||
|
node->nod_arg[e_prm_prompt]);
|
||
|
}
|
||
|
else {
|
||
|
if (reprompt)
|
||
|
sprintf(string, "\07%s: ", prompt[0]); /* Msg497 Re-enter */
|
||
|
else
|
||
|
sprintf(string, "%s: ", prompt[1]); /* Msg498 Enter */
|
||
|
}
|
||
|
|
||
|
if (!LEX_get_line(string, value, length)) {
|
||
|
QLI_abort = TRUE;
|
||
|
EXEC_poll_abort();
|
||
|
}
|
||
|
|
||
|
if (value[0] == '\t' && value[1] == '\n')
|
||
|
return desc;
|
||
|
|
||
|
p = value + strlen(value);
|
||
|
if (p > value && p[-1] == '\n')
|
||
|
*--p = 0;
|
||
|
|
||
|
/* Get rid of trailing blanks on non-text data types */
|
||
|
|
||
|
if (desc->dsc_dtype > dtype_varying) {
|
||
|
while (p > value && p[-1] == ' ')
|
||
|
--p;
|
||
|
*p = 0;
|
||
|
}
|
||
|
|
||
|
if ((l = p - value) <= desc->dsc_length - 2) {
|
||
|
if (value != data->vary_string)
|
||
|
memcpy(data->vary_string, value, l);
|
||
|
desc->dsc_missing = (data->vary_length = l) ? 0 : DSC_missing;
|
||
|
return desc;
|
||
|
}
|
||
|
|
||
|
ERRQ_msg_put(32, NULL, NULL, NULL, NULL, NULL); /* Msg32 Input value is too long */
|
||
|
reprompt = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static DSC *execute_statistical( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* e x e c u t e _ s t a t i s t i c a l
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Execute a statistical expression.
|
||
|
*
|
||
|
**************************************/
|
||
|
REQ request;
|
||
|
MSG message;
|
||
|
PAR parameter;
|
||
|
|
||
|
/* If there is a request associated with the node, start it and possibly
|
||
|
send a message along with it. */
|
||
|
|
||
|
if (request = (REQ) node->nod_arg[e_stt_request])
|
||
|
EXEC_start_request(request, node->nod_arg[e_stt_send]);
|
||
|
else if (message = (MSG) node->nod_arg[e_stt_send])
|
||
|
EXEC_send(message);
|
||
|
|
||
|
return EXEC_receive(node->nod_arg[e_stt_receive], node->nod_import);
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int like2(
|
||
|
UCHAR * p1,
|
||
|
SSHORT l1, UCHAR * p2, SSHORT l2, UCHAR escape_char)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i k e 2
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Front-end of like() in Japanese version.
|
||
|
* Prepare buffer of short, then "copy" char-based data
|
||
|
* into the new short-based buffer. Use the new buffer for
|
||
|
* later processing with like().
|
||
|
*
|
||
|
**************************************/
|
||
|
USHORT *buf1, *buf2;
|
||
|
int ret_val;
|
||
|
|
||
|
buf1 = (USHORT *) gds__alloc((l1 + 1) * sizeof(SSHORT));
|
||
|
buf2 = (USHORT *) gds__alloc((l2 + 1) * sizeof(SSHORT));
|
||
|
|
||
|
l1 = KANJI_byte2short(p1, buf1, l1);
|
||
|
l2 = KANJI_byte2short(p2, buf2, l2);
|
||
|
|
||
|
*(buf1 + l1) = 0;
|
||
|
*(buf2 + l2) = 0;
|
||
|
|
||
|
ret_val = like(buf1, l1, buf2, l2, (USHORT) escape_char);
|
||
|
|
||
|
gds__free(buf1);
|
||
|
gds__free(buf2);
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
|
||
|
static int like(
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT * p1,
|
||
|
SSHORT l1, USHORT * p2, SSHORT l2, USHORT escape_char)
|
||
|
#else
|
||
|
UCHAR * p1,
|
||
|
SSHORT l1, UCHAR * p2, SSHORT l2, UCHAR escape_char)
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* l i k e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Return true if a string (p1, l1) matches a given pattern (p2, l2).
|
||
|
* The character '_' in the pattern may match any single character
|
||
|
* in the the string, and the character '%' may match any sequence
|
||
|
* of characters.
|
||
|
* Japanese version operates on short-based buffer,
|
||
|
* instead of char-based.
|
||
|
*
|
||
|
**************************************/
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT c;
|
||
|
#else
|
||
|
UCHAR c;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
int escape;
|
||
|
|
||
|
escape = FALSE;
|
||
|
|
||
|
while (--l2 >= 0) {
|
||
|
c = *p2++;
|
||
|
if (escape_char && !escape && c == escape_char) {
|
||
|
escape = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
if (!escape && c == '%') {
|
||
|
if (l2 == 0)
|
||
|
return TRUE;
|
||
|
while (l1)
|
||
|
if (like(p1++, l1--, p2, l2, escape_char))
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (--l1 < 0)
|
||
|
return FALSE;
|
||
|
if ((escape || c != '_') && c != *p1)
|
||
|
return FALSE;
|
||
|
escape = FALSE;
|
||
|
p1++;
|
||
|
}
|
||
|
|
||
|
return (l1) ? FALSE : TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static TEXT *make_blob_buffer( SLONG * blob, USHORT * length)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* m a k e _ b l o b _ b u f f e r
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* For a blob, get the max segment length,
|
||
|
* check that the buffer allocated is at least
|
||
|
* that length, and, if not, allocate a bigger one.
|
||
|
*
|
||
|
**************************************/
|
||
|
SLONG size, segment_count, max_segment;
|
||
|
|
||
|
gds__blob_size(&blob, &size, &segment_count, &max_segment);
|
||
|
|
||
|
#ifdef JPN_EUC
|
||
|
max_segment = MIN(max_segment * 2, 32768); /* prepare for SJIS->EUC expansion */
|
||
|
#endif /* JPN_EUC */
|
||
|
|
||
|
if (max_segment >= *length) {
|
||
|
TEXT *buffer;
|
||
|
*length = max_segment;
|
||
|
buffer = (TEXT *) gds__alloc((SLONG) * length);
|
||
|
#ifdef DEBUG_GDS_ALLOC
|
||
|
/* We don't care about QLI specific memory leaks for V4.0 */
|
||
|
gds_alloc_flag_unfreed((void *) buffer); /* QLI: don't care */
|
||
|
#endif
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int matches2( UCHAR * p1, SSHORT l1, UCHAR * p2, SSHORT l2)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* m a t c h e s 2
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Front-end of matches() in Japanese version.
|
||
|
* Prepare buffer of short, then "copy" char-based data
|
||
|
* into the new short-based buffer. Use the new buffer for
|
||
|
* later processing with matches().
|
||
|
*
|
||
|
**************************************/
|
||
|
USHORT *buf1, *buf2;
|
||
|
int ret_val;
|
||
|
|
||
|
buf1 = (USHORT *) gds__alloc((l1 + 1) * sizeof(SSHORT));
|
||
|
buf2 = (USHORT *) gds__alloc((l2 + 1) * sizeof(SSHORT));
|
||
|
|
||
|
l1 = KANJI_byte2short(p1, buf1, l1);
|
||
|
l2 = KANJI_byte2short(p2, buf2, l2);
|
||
|
|
||
|
*(buf1 + l1) = 0;
|
||
|
*(buf2 + l2) = 0;
|
||
|
|
||
|
ret_val = matches(buf1, l1, buf2, l2);
|
||
|
|
||
|
gds__free(buf1);
|
||
|
gds__free(buf2);
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
|
||
|
static int matches(
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT * p1, SSHORT l1, USHORT * p2, SSHORT l2)
|
||
|
#else
|
||
|
TEXT * p1, SSHORT l1, TEXT * p2, SSHORT l2)
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* m a t c h e s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Return true if a string (p1, l1) matches a given pattern (p2, l2).
|
||
|
* The character '?' in the pattern may match any single character
|
||
|
* in the the string, and the character '*' may match any sequence
|
||
|
* of characters.
|
||
|
*
|
||
|
**************************************/
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT c;
|
||
|
#else
|
||
|
TEXT c;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
while (--l2 >= 0) {
|
||
|
c = *p2++;
|
||
|
if (c == '*') {
|
||
|
if (l2 == 0)
|
||
|
return TRUE;
|
||
|
while (l1)
|
||
|
if (matches(p1++, l1--, p2, l2))
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (--l1 < 0 || (c != '?' && UPPER(c) != UPPER(*p1)))
|
||
|
return FALSE;
|
||
|
p1++;
|
||
|
}
|
||
|
|
||
|
return (l1) ? FALSE : TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int sleuth( NOD node, DSC * desc1, DSC * desc2, DSC * desc3)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s l e u t h
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Return true if a string (p1, l1) matches a given pattern (p2, l2),
|
||
|
* using a pattern language defined in p3, l3.
|
||
|
*
|
||
|
**************************************/
|
||
|
TEXT *p1, *p2, *buffer, temp1[TEMP_LENGTH], temp2[TEMP_LENGTH],
|
||
|
fixed_buffer[512], control[256];
|
||
|
int *blob;
|
||
|
USHORT buffer_length;
|
||
|
STATUS status_vector[20];
|
||
|
SSHORT l1, l2, result;
|
||
|
CTX context;
|
||
|
REQ request;
|
||
|
DBB dbb;
|
||
|
|
||
|
/* Get operator definition string (control string) */
|
||
|
|
||
|
l1 = MOVQ_get_string(desc3, &p1, temp1, TEMP_LENGTH);
|
||
|
|
||
|
/* Get address and length of search string */
|
||
|
|
||
|
l2 = MOVQ_get_string(desc2, &p2, temp2, TEMP_LENGTH);
|
||
|
|
||
|
/* Merge search and control strings */
|
||
|
|
||
|
l2 = sleuth_merge(p2, p2 + l2, p1, p1 + l1, control);
|
||
|
|
||
|
/* If source is not a blob, do a simple search */
|
||
|
|
||
|
if (desc1->dsc_dtype != dtype_blob) {
|
||
|
l1 = MOVQ_get_string(desc1, &p1, temp1, TEMP_LENGTH);
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
return sleuth_check2(0, p1, p1 + l1, control, control + l2);
|
||
|
#else
|
||
|
return sleuth_check(0, p1, p1 + l1, control, control + l2);
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
}
|
||
|
|
||
|
/* Source string is a blob, things get interesting */
|
||
|
|
||
|
result = FALSE;
|
||
|
|
||
|
blob = EXEC_open_blob(node->nod_arg[0]);
|
||
|
|
||
|
buffer_length = sizeof(fixed_buffer);
|
||
|
|
||
|
if (!(buffer = make_blob_buffer(blob, &buffer_length)))
|
||
|
buffer = fixed_buffer;
|
||
|
|
||
|
while (!gds__get_segment(status_vector,
|
||
|
GDS_REF(blob),
|
||
|
GDS_REF(l1), buffer_length, GDS_VAL(buffer)))
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
if (sleuth_check2(0, buffer, buffer + l1, control, control + l2))
|
||
|
#else
|
||
|
if (sleuth_check(0, buffer, buffer + l1, control, control + l2))
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
result = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (buffer != fixed_buffer)
|
||
|
gds__free(buffer);
|
||
|
|
||
|
if (gds__close_blob(status_vector, GDS_REF(blob))) {
|
||
|
context = (CTX) node->nod_arg[e_fld_context];
|
||
|
request = context->ctx_request;
|
||
|
dbb = request->req_database;
|
||
|
ERRQ_database_error(dbb, status_vector);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
static int sleuth_check2(
|
||
|
USHORT flags,
|
||
|
TEXT * search,
|
||
|
TEXT * end_search, TEXT * match, TEXT * end_match)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s l e u t h _ c h e c k 2
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Front-end of sleuth_check() in Japanese version.
|
||
|
* Prepare buffer of short, then "copy" char-based data
|
||
|
* into the new short-based buffer. Use the new buffer for
|
||
|
* later processing with sleuth_check().
|
||
|
*
|
||
|
**************************************/
|
||
|
USHORT l1, l2, *buf1, *buf2;
|
||
|
int ret_val;
|
||
|
|
||
|
l1 = end_search - search;
|
||
|
l2 = end_match - match;
|
||
|
|
||
|
buf1 = (USHORT *) gds__alloc((l1 + 1) * sizeof(SSHORT));
|
||
|
buf2 = (USHORT *) gds__alloc((l2 + 1) * sizeof(SSHORT));
|
||
|
|
||
|
l1 = KANJI_byte2short(search, buf1, l1);
|
||
|
l2 = KANJI_byte2short(match, buf2, l2);
|
||
|
|
||
|
*(buf1 + l1) = 0;
|
||
|
*(buf2 + l2) = 0;
|
||
|
|
||
|
ret_val = sleuth_check(flags, buf1, buf1 + l1, buf2, buf2 + l2);
|
||
|
|
||
|
gds__free(buf1);
|
||
|
gds__free(buf2);
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
|
||
|
static int sleuth_check(
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT flags,
|
||
|
USHORT * search,
|
||
|
USHORT * end_search,
|
||
|
USHORT * match, USHORT * end_match)
|
||
|
#else
|
||
|
USHORT flags,
|
||
|
UCHAR * search,
|
||
|
UCHAR * end_search,
|
||
|
UCHAR * match, UCHAR * end_match)
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s l e u t h _ c h e c k
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Evaluate the "sleuth" search operator.
|
||
|
*
|
||
|
**************************************/
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT c, d, *class_, *p, *end_class;
|
||
|
#else
|
||
|
UCHAR c, d, *class_, *p, *end_class;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
while (match < end_match) {
|
||
|
c = *match++;
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
if ((c == '@' && (c = *match++)) || KANJISHORT(c) || !special[c])
|
||
|
#else
|
||
|
if ((c == '@' && (c = *match++)) || !special[c])
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
c = COND_UPPER(c);
|
||
|
if (match >= end_match || *match != '*') {
|
||
|
if (search >= end_search)
|
||
|
return FALSE;
|
||
|
d = *search++;
|
||
|
if (c != COND_UPPER(d))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
++match;
|
||
|
for (;;)
|
||
|
if (sleuth_check
|
||
|
(flags, search, end_search, match,
|
||
|
end_match)) return TRUE;
|
||
|
else if (search < end_search) {
|
||
|
d = *search++;
|
||
|
if (c != COND_UPPER(d))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else if (c == '?')
|
||
|
if (match >= end_match || *match != '*') {
|
||
|
if (search >= end_search)
|
||
|
return FALSE;
|
||
|
search++;
|
||
|
}
|
||
|
else {
|
||
|
if (++match >= end_match)
|
||
|
return TRUE;
|
||
|
for (;;)
|
||
|
if (sleuth_check
|
||
|
(flags, search, end_search, match,
|
||
|
end_match)) return TRUE;
|
||
|
else if (++search >= end_search)
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (c == '[') {
|
||
|
class_ = match;
|
||
|
while (*match++ != ']')
|
||
|
if (match >= end_match)
|
||
|
return FALSE;
|
||
|
end_class = match - 1;
|
||
|
if (match >= end_match || *match != '*') {
|
||
|
if (!sleuth_class(flags, class_, end_class, *search++))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
++match;
|
||
|
for (;;)
|
||
|
if (sleuth_check
|
||
|
(flags, search, end_search, match,
|
||
|
end_match)) return TRUE;
|
||
|
else if (search < end_search) {
|
||
|
if (!sleuth_class
|
||
|
(flags, class_, end_class,
|
||
|
*search++)) return FALSE;
|
||
|
}
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
else if (c == '+') {
|
||
|
c = *match++;
|
||
|
if (c == 'S' || c == 's')
|
||
|
flags &= ~SLEUTH_insensitive;
|
||
|
}
|
||
|
else if (c == '-') {
|
||
|
c = *match++;
|
||
|
if (c == 'S' || c == 's')
|
||
|
flags |= SLEUTH_insensitive;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (search < end_search)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int sleuth_class( USHORT flags,
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT * class_, USHORT * end_class, USHORT character)
|
||
|
#else
|
||
|
UCHAR * class_, UCHAR * end_class, UCHAR character)
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s l e u t h _ c l a s s
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* See if a character is a member of a class.
|
||
|
*
|
||
|
**************************************/
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT c, d;
|
||
|
#else
|
||
|
UCHAR c, d;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
USHORT result;
|
||
|
|
||
|
result = TRUE;
|
||
|
character = COND_UPPER(character);
|
||
|
|
||
|
if (*class_ == '~') {
|
||
|
++class_;
|
||
|
result = FALSE;
|
||
|
}
|
||
|
|
||
|
while (class_ < end_class) {
|
||
|
c = *class_++;
|
||
|
if (c == '@') {
|
||
|
if (*class_++ == character)
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (*class_ == '-') {
|
||
|
class_ += 2;
|
||
|
if (character >= c && character <= class_[-1])
|
||
|
return result;
|
||
|
}
|
||
|
else if (character == c)
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
return (result) ? FALSE : TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int sleuth_merge(
|
||
|
UCHAR * match,
|
||
|
UCHAR * end_match,
|
||
|
UCHAR * control,
|
||
|
UCHAR * end_control, UCHAR * combined)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s l e u t h _ m e r g e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Merge the matching pattern and control strings to give a cannonical
|
||
|
* matching pattern. Return the length of the combined string.
|
||
|
*
|
||
|
* What this routine does is to take the language template, strip off
|
||
|
* the prefix and put it in the output string, then parse the definitions
|
||
|
* into an array of character pointers. The index array is the defined
|
||
|
* character. The routine then takes the actual match pattern and uses
|
||
|
* the characters in it to index into the definitions to produce an equivalent
|
||
|
* pattern in the cannonical language.
|
||
|
*
|
||
|
* The silly loop setting *v++ to zero initializes the array up to the
|
||
|
* highest character defined (also max_op). Believe it or not, that part
|
||
|
* is not a bug.
|
||
|
*
|
||
|
**************************************/
|
||
|
UCHAR c, *comb, **v, *vector[128], **end_vector, *p, max_op, temp[256],
|
||
|
*t;
|
||
|
SSHORT n;
|
||
|
|
||
|
comb = combined;
|
||
|
v = vector;
|
||
|
t = temp;
|
||
|
|
||
|
/* Parse control string into substitution strings and initializing string */
|
||
|
|
||
|
while (control < end_control) {
|
||
|
c = *control++;
|
||
|
if (*control == '=') {
|
||
|
end_vector = vector + c;
|
||
|
while (v <= end_vector)
|
||
|
*v++ = 0;
|
||
|
*end_vector = t;
|
||
|
++control;
|
||
|
while (control < end_control) {
|
||
|
c = *control++;
|
||
|
if ((t[-1] == '@') || ((c != ',') && (c != ')')))
|
||
|
*t++ = c;
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
*t++ = 0;
|
||
|
}
|
||
|
else if (c == '@' && control < end_control)
|
||
|
*comb++ = *control++;
|
||
|
else if (c == ')')
|
||
|
break;
|
||
|
else if (c != '(')
|
||
|
*comb++ = c;
|
||
|
}
|
||
|
|
||
|
max_op = v - vector;
|
||
|
|
||
|
/* Interpret matching string, substituting where appropriate */
|
||
|
|
||
|
while (c = *match++) {
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
if (KANJI1(c)) {
|
||
|
|
||
|
/* it is a kanji, copy the 2 bytes */
|
||
|
|
||
|
*comb++ = c;
|
||
|
*comb++ = *match++;;
|
||
|
continue;
|
||
|
}
|
||
|
#ifdef JPN_SJIS
|
||
|
else if (SJIS_SINGLE(c)) {
|
||
|
|
||
|
/* it is an SJIS half-width kana, copy the 1 byte */
|
||
|
|
||
|
*comb++ = c;
|
||
|
continue;
|
||
|
}
|
||
|
#endif /* JPN_SJIS */
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
/* if we've got a defined character, slurp the definition */
|
||
|
if (c <= max_op && (p = vector[c])) {
|
||
|
while (*p)
|
||
|
*comb++ = *p++;
|
||
|
/* if we've got the definition of a quote character, slurp the next character too */
|
||
|
if (comb[-1] == '@' && *match)
|
||
|
*comb++ = *match++;
|
||
|
}
|
||
|
/* at this point we've got a non-match, but as it might be one of ours, quote it. */
|
||
|
else {
|
||
|
if (special[c] && comb[-1] != '@')
|
||
|
*comb++ = '@';
|
||
|
*comb++ = c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Put in trailing stuff */
|
||
|
|
||
|
while (control < end_control)
|
||
|
*comb++ = *control++;
|
||
|
|
||
|
return comb - combined;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int string_boolean( NOD node)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s t r i n g _ b o o l e a n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Perform one of the complex string functions CONTAINING, MATCHES,
|
||
|
* or STARTS WITH.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *desc1, *desc2, *desc3;
|
||
|
TEXT *p1, *p2, *p3, *buffer, fixed_buffer[512];
|
||
|
TEXT temp1[TEMP_LENGTH], temp2[TEMP_LENGTH];
|
||
|
int *blob;
|
||
|
SSHORT l1, l2, l3, l, result;
|
||
|
USHORT buffer_length;
|
||
|
STATUS status_vector[20];
|
||
|
CTX context;
|
||
|
REQ request;
|
||
|
DBB dbb;
|
||
|
|
||
|
if (!(desc1 = EVAL_value(node->nod_arg[0])) ||
|
||
|
(desc1->dsc_missing & DSC_missing) ||
|
||
|
!(desc2 = EVAL_value(node->nod_arg[1])) ||
|
||
|
(desc2->dsc_missing & DSC_missing) ||
|
||
|
(node->nod_arg[2] && (!(desc3 = EVAL_value(node->nod_arg[2])) ||
|
||
|
(desc3->dsc_missing & DSC_missing))))
|
||
|
return FALSE;
|
||
|
|
||
|
if (node->nod_type == nod_sleuth)
|
||
|
return sleuth(node, desc1, desc2, desc3);
|
||
|
|
||
|
/* Get address and length of strings */
|
||
|
|
||
|
l2 = MOVQ_get_string(desc2, &p2, temp2, TEMP_LENGTH);
|
||
|
|
||
|
/* If source is not a blob, do a simple search */
|
||
|
|
||
|
if (desc1->dsc_dtype != dtype_blob) {
|
||
|
l1 = MOVQ_get_string(desc1, &p1, temp1, TEMP_LENGTH);
|
||
|
return string_function(node, l1, p1, l2, p2);
|
||
|
}
|
||
|
|
||
|
/* Source string is a blob, things get interesting */
|
||
|
|
||
|
result = FALSE;
|
||
|
blob = EXEC_open_blob(node->nod_arg[0]);
|
||
|
|
||
|
buffer_length = sizeof(fixed_buffer);
|
||
|
|
||
|
if (!(buffer = make_blob_buffer(blob, &buffer_length)))
|
||
|
buffer = fixed_buffer;
|
||
|
|
||
|
while (!gds__get_segment(status_vector,
|
||
|
GDS_REF(blob),
|
||
|
GDS_REF(l1),
|
||
|
buffer_length,
|
||
|
GDS_VAL(buffer)))
|
||
|
if (string_function(node, l1, buffer, l2, p2)) {
|
||
|
result = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (buffer != fixed_buffer)
|
||
|
gds__free(buffer);
|
||
|
|
||
|
if (gds__close_blob(status_vector, GDS_REF(blob))) {
|
||
|
context = (CTX) node->nod_arg[e_fld_context];
|
||
|
request = context->ctx_request;
|
||
|
dbb = request->req_database;
|
||
|
ERRQ_database_error(dbb, status_vector);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int string_function(
|
||
|
NOD node,
|
||
|
SSHORT l1, TEXT * p1, SSHORT l2, TEXT * p2)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s t r i n g _ f u n c t i o n
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Perform one of the complex string functions CONTAINING, MATCHES,
|
||
|
* or STARTS WITH.
|
||
|
*
|
||
|
**************************************/
|
||
|
DSC *desc;
|
||
|
TEXT *q1, *q2, *q3, c1, c2, c3, temp[16];
|
||
|
SSHORT l;
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
TEXT *p1_orig = p1;
|
||
|
TEXT *p2_orig = p2;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
|
||
|
|
||
|
/* Handle "STARTS WITH" */
|
||
|
|
||
|
if (node->nod_type == nod_starts) {
|
||
|
if (l1 < l2)
|
||
|
return FALSE;
|
||
|
while (--l2 >= 0)
|
||
|
if (*p1++ != *p2++)
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Handle CONTAINS */
|
||
|
|
||
|
if (node->nod_type == nod_containing) {
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
USHORT c1, c2, *p1, *p2, *q1, *q2, *buf1, *buf2;
|
||
|
|
||
|
buf1 = (USHORT *) gds__alloc((l1 + 1) * sizeof(SSHORT));
|
||
|
buf2 = (USHORT *) gds__alloc((l2 + 1) * sizeof(SSHORT));
|
||
|
|
||
|
l1 = KANJI_byte2short(p1_orig, buf1, l1);
|
||
|
l2 = KANJI_byte2short(p2_orig, buf2, l2);
|
||
|
|
||
|
*(buf1 + l1) = 0;
|
||
|
*(buf2 + l2) = 0;
|
||
|
|
||
|
p1 = buf1;
|
||
|
p2 = buf2;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
while (l1 >= l2) {
|
||
|
--l1;
|
||
|
q1 = p1++;
|
||
|
q2 = p2;
|
||
|
l = l2;
|
||
|
do {
|
||
|
if (--l < 0)
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
{
|
||
|
gds__free(buf1);
|
||
|
gds__free(buf2);
|
||
|
return TRUE;
|
||
|
}
|
||
|
#else
|
||
|
return TRUE;
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
c1 = *q1++;
|
||
|
c2 = *q2++;
|
||
|
} while (UPPER(c1) == UPPER(c2));
|
||
|
}
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
gds__free(buf1);
|
||
|
gds__free(buf2);
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* Handle LIKE */
|
||
|
|
||
|
if (node->nod_type == nod_like) {
|
||
|
c1 = 0;
|
||
|
if (node->nod_count > 2 &&
|
||
|
MOVQ_get_string(EVAL_value(node->nod_arg[2]), &q1, temp,
|
||
|
sizeof(temp))) c1 = *q1;
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
if (like2(p1, l1, p2, l2, c1))
|
||
|
#else
|
||
|
if (like(p1, l1, p2, l2, c1))
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/* Handle MATCHES */
|
||
|
|
||
|
if (node->nod_type == nod_matches)
|
||
|
#if (defined JPN_EUC || defined JPN_SJIS)
|
||
|
if (matches2(p1, l1, p2, l2))
|
||
|
#else
|
||
|
if (matches(p1, l1, p2, l2))
|
||
|
#endif /* (defined JPN_EUC || defined JPN_SJIS) */
|
||
|
return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|