1470 lines
40 KiB
C
1470 lines
40 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2010, 2012 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_ctype.h"
|
|
#include "gtm_string.h"
|
|
#include "cli.h"
|
|
#include "gdsroot.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include <rtnhdr.h>
|
|
#include "gv_trigger.h"
|
|
#include "gtm_trigger.h"
|
|
#include "trigger.h"
|
|
#include "trigger_parse_protos.h"
|
|
#include "trigger_scan_string.h"
|
|
#include "zshow.h" /* for zwr2format() prototype */
|
|
#include "min_max.h"
|
|
#include "util.h"
|
|
#include "subscript.h"
|
|
#include "cli_parse.h"
|
|
#include "compiler.h"
|
|
#include "gtm_utf8.h"
|
|
#include "gtmctype.h"
|
|
|
|
GBLREF CLI_ENTRY *cmd_ary;
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF CLI_ENTRY trigger_cmd_ary[];
|
|
|
|
#define BITS_PER_INT (SIZEOF(uint4) * 8) /* Number of bits in an integer */
|
|
#define MAX_PIECE_VALUE (BITS_PER_INT * 1024) /* Largest value allowed in -pieces string */
|
|
#define MAX_PIECE_INT (MAX_PIECE_VALUE / 32) /* Number of integers it takes to hold MAX_PIECE_VALUE bits */
|
|
#define MAX_PIECE_CHARS (MAX_PIECE_INT * 4) /* Number of 8-bit bytes in MAX_PIECE_INT integers */
|
|
#define MAX_LVN_COUNT MAX_GVSUBSCRIPTS /* Maximum number of "lvn=" in trigger subscript */
|
|
#define MAX_OPTIONS_LEN 1024 /* Maximum size of the "options" string */
|
|
#define MAX_DCHAR_LEN 1024 /* Maximum size of $C or $ZCH string */
|
|
#define MAX_DELIM_LEN 1024 /* Maximum size of the string for a delimiter - $C, $ZCH, "x", ... */
|
|
#define MAX_ERROR_MSG_LEN 72
|
|
#define TRIGR_PRECOMP_RTNNAME "trigcomptest#"
|
|
|
|
#define CONV_CH(PTR, STR, LEN) \
|
|
{ \
|
|
if (PRINTABLE(*PTR)) \
|
|
{ \
|
|
STR[0] = '"'; \
|
|
STR[1] = *PTR; \
|
|
STR[2] = '"'; \
|
|
LEN = 3; \
|
|
} else \
|
|
format2zwr((sm_uc_ptr_t)PTR, 1, STR, &LEN); \
|
|
}
|
|
|
|
#define ERROR_MSG_RETURN(STR, LEN, PTR) \
|
|
{ \
|
|
CONV_STR_AND_PRINT(STR, LEN, PTR); \
|
|
return FALSE; \
|
|
}
|
|
|
|
#define ERROR_STR_RETURN(STR) \
|
|
{ \
|
|
util_out_print_gtmio(STR, FLUSH); \
|
|
return FALSE; \
|
|
}
|
|
|
|
#define CONV_CH_AND_PRINT(STR, PTR) \
|
|
{ \
|
|
int out_len; \
|
|
unsigned char out_str[64]; /* Plenty of room for $ZCH(xxx) */ \
|
|
\
|
|
CONV_CH(PTR, out_str, out_len); \
|
|
util_out_print_gtmio(STR, FLUSH, out_len, out_str); \
|
|
}
|
|
|
|
#define CONV_CH_AND_STR_AND_PRINT(STR, PTR1, LEN, PTR2) \
|
|
{ \
|
|
int out_len1, out_len2; \
|
|
unsigned char out_str1[64]; /* Plenty of room for $ZCH(xxx) */ \
|
|
unsigned char out_str2[MAX_ZWR_EXP_RATIO * OUT_BUFF_SIZE]; \
|
|
\
|
|
CONV_CH(PTR1, out_str1, out_len1); \
|
|
CONV_TO_ZWR(LEN, PTR2, out_len2, out_str2); \
|
|
util_out_print_gtmio(STR, FLUSH, out_len1, out_str1, out_len2, out_str2); \
|
|
}
|
|
|
|
#define CONV_NUM_AND_STR_AND_PRINT(STR, NUM, LEN, PTR) \
|
|
{ \
|
|
int out_len; \
|
|
unsigned char out_str[MAX_ZWR_EXP_RATIO * OUT_BUFF_SIZE]; \
|
|
\
|
|
CONV_TO_ZWR(LEN, PTR, out_len, out_str); \
|
|
util_out_print_gtmio(STR, FLUSH, NUM, out_len, out_str); \
|
|
}
|
|
|
|
#define UPDATE_DST(PTR, LEN, HAVE_STAR, DST_PTR, DST_LEN, MAX_LEN) \
|
|
{ \
|
|
if (!HAVE_STAR) \
|
|
{ \
|
|
if (MAX_LEN < ++DST_LEN) \
|
|
{ \
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
*DST_PTR++ = *PTR++; \
|
|
} \
|
|
else PTR++; \
|
|
LEN--; \
|
|
}
|
|
#define UPDATE_TRIG_PTRS(VAL, NEXT_VAL, LEN, MAX_OUTPUT_LEN) \
|
|
{ \
|
|
NEXT_VAL = VAL + LEN; \
|
|
if (0 > --MAX_OUTPUT_LEN) \
|
|
{ \
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
*NEXT_VAL++ = '\0'; \
|
|
}
|
|
|
|
#define PROCESS_NUMERIC(PTR, LEN, HAVE_STAR, DST_PTR, DST_LEN, MAX_LEN) \
|
|
{ \
|
|
UPDATE_DST(PTR, LEN, HAVE_STAR, DST_PTR, DST_LEN, MAX_LEN); \
|
|
while (ISDIGIT_ASCII(*PTR)) \
|
|
{ \
|
|
if (!HAVE_STAR) \
|
|
{ \
|
|
if (MAX_LEN < ++DST_LEN) \
|
|
{ \
|
|
util_out_print_gtmio("Subscript too long", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
*DST_PTR++ = *PTR++; \
|
|
} else \
|
|
PTR++; \
|
|
LEN--; \
|
|
} \
|
|
}
|
|
#define PROCESS_STRING(PTR, LEN, HAVE_STAR, DST_PTR, DST_LEN, MAX_LEN) \
|
|
{ \
|
|
char *ptr1; \
|
|
int add_len; \
|
|
\
|
|
ptr1 = scan_to_end_quote(PTR, LEN, MAX_LEN); \
|
|
if (NULL == ptr1) \
|
|
{ \
|
|
util_out_print_gtmio("Invalid string", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
add_len = (int)(ptr1 - PTR); \
|
|
LEN -= add_len; \
|
|
if (!HAVE_STAR) \
|
|
{ \
|
|
if (MAX_LEN < (DST_LEN + add_len)) \
|
|
{ \
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
memcpy(DST_PTR, PTR, add_len); \
|
|
DST_PTR += add_len; \
|
|
DST_LEN += add_len; \
|
|
} \
|
|
PTR = ptr1; \
|
|
}
|
|
#define PROCESS_AND_GET_NUMERIC(PTR, LEN, HAVE_STAR, DST_PTR, DST_LEN, NUM, MAX_LEN) \
|
|
{ \
|
|
char *ptr1; \
|
|
int add_len; \
|
|
\
|
|
ptr1 = PTR; \
|
|
A2I(ptr1, PTR + LEN, NUM); \
|
|
add_len = (int)(ptr1 - PTR); \
|
|
LEN -= add_len; \
|
|
if (!HAVE_STAR) \
|
|
{ \
|
|
if (MAX_LEN < (DST_LEN + add_len)) \
|
|
{ \
|
|
util_out_print_gtmio("Subscript too long", FLUSH); \
|
|
return FALSE; \
|
|
} \
|
|
memcpy(DST_PTR, PTR, add_len); \
|
|
DST_PTR += add_len; \
|
|
DST_LEN += add_len; \
|
|
} \
|
|
PTR = ptr1; \
|
|
}
|
|
|
|
#define GET_CLI_STR(QUAL, MAX_OUTPUT_LEN, VALUE, RES) \
|
|
{ \
|
|
unsigned short qual_len; \
|
|
\
|
|
qual_len = (unsigned short)MAX_OUTPUT_LEN; \
|
|
assert(MAX_OUTPUT_LEN == qual_len); /* make sure it fits in short */ \
|
|
if (FALSE == cli_get_str(QUAL, VALUE, &qual_len)) \
|
|
return FALSE; \
|
|
RES = qual_len; \
|
|
}
|
|
|
|
#define GET_CLI_STR_AND_CHECK(QUAL, QUAL_PRESENT, MAX_OUTPUT_LEN, CHECK_FN, VAL, VAL_LEN, NEXT_VAL, ERR_MSG) \
|
|
{ \
|
|
unsigned short qual_str_len; \
|
|
\
|
|
if (CLI_PRESENT == (QUAL_PRESENT = cli_present(QUAL))) \
|
|
{ \
|
|
GET_CLI_STR(QUAL, MAX_OUTPUT_LEN, VAL, qual_str_len); \
|
|
VAL_LEN = qual_str_len; \
|
|
if (!CHECK_FN(VAL, &VAL_LEN)) \
|
|
{ \
|
|
if (0 == STR_LIT_LEN(ERR_MSG)) \
|
|
return FALSE; \
|
|
else \
|
|
{ \
|
|
ERROR_MSG_RETURN(ERR_MSG, VAL_LEN, VAL); \
|
|
} \
|
|
} \
|
|
} else \
|
|
VAL_LEN = 0; \
|
|
/* cli_get_str() will put the string in the buffer (based on max_output_len) \
|
|
* but the check_*() function might take another pass over the string in the \
|
|
* output buffer and consolidate it -- for example piece can reduce 2;3;4;5 \
|
|
* to 2:5. So don't adjust max_output_len until we know the actual length. \
|
|
*/ \
|
|
MAX_OUTPUT_LEN -= VAL_LEN; \
|
|
UPDATE_TRIG_PTRS(VAL, NEXT_VAL, VAL_LEN, MAX_OUTPUT_LEN); \
|
|
}
|
|
|
|
GBLREF char cli_err_str[];
|
|
GBLREF boolean_t gtm_cli_interpret_string;
|
|
|
|
LITREF unsigned char lower_to_upper_table[];
|
|
LITREF mval gvtr_cmd_mval[GVTR_CMDTYPES];
|
|
|
|
error_def(ERR_INVSTRLEN);
|
|
|
|
STATICFNDEF char *scan_to_end_quote(char *ptr, int len, int max_len)
|
|
{
|
|
int str_len = 0;
|
|
|
|
if ((1 >= len) || ('"' != *ptr))
|
|
return NULL; /* Invalid string - it needs at least "" */
|
|
if (max_len < ++str_len)
|
|
{
|
|
util_out_print_gtmio("String too long", FLUSH);
|
|
return NULL;
|
|
}
|
|
ptr++;
|
|
len--;
|
|
for ( ; 0 < len; len--, ptr++)
|
|
{ /* Scan until the closing quote */
|
|
if ('"' == *ptr)
|
|
{
|
|
if (1 == len)
|
|
break;
|
|
if ('"' == *(ptr + 1))
|
|
{
|
|
if (max_len < ++str_len)
|
|
{
|
|
util_out_print_gtmio("String too long", FLUSH);
|
|
return NULL;
|
|
}
|
|
ptr++;
|
|
len--;
|
|
} else
|
|
break;
|
|
}
|
|
if (max_len < ++str_len)
|
|
{
|
|
util_out_print_gtmio("String too long", FLUSH);
|
|
return NULL;
|
|
}
|
|
}
|
|
return (('"' == *ptr) ? ptr + 1 : NULL);
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_dollar_char(char **src_ptr, int *src_len, boolean_t have_star, char **d_ptr, int *dst_len)
|
|
{
|
|
int char_count;
|
|
char *char_ptr;
|
|
int len;
|
|
char *dst_ptr;
|
|
char dst_string[MAX_DCHAR_LEN];
|
|
int lcl_dst_len;
|
|
mstr m_dst;
|
|
mstr m_src;
|
|
char *ptr;
|
|
int q_len;
|
|
char *tmp_dst_ptr;
|
|
|
|
tmp_dst_ptr = dst_ptr = *d_ptr;
|
|
ptr = *src_ptr;
|
|
len = *src_len;
|
|
lcl_dst_len = *dst_len;
|
|
assert('$' == *ptr);
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
|
|
if (0 == len)
|
|
return FALSE;
|
|
switch (*ptr)
|
|
{
|
|
case 'c':
|
|
case 'C':
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
|
|
if ((0 < len) && ('(' == *ptr))
|
|
break;
|
|
else if ((3 < len) && ('H' == lower_to_upper_table[*ptr])
|
|
&& ('A' == lower_to_upper_table[*(ptr + 1)])
|
|
&& ('R' == lower_to_upper_table[*(ptr + 2)]) && ('(' == *(ptr + 3)))
|
|
{
|
|
ptr += 3;
|
|
len -= 3;
|
|
break;
|
|
}
|
|
else
|
|
return FALSE;
|
|
break;
|
|
case 'z':
|
|
case 'Z':
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
|
|
if ((2 < len) && ('C' == lower_to_upper_table[*ptr])
|
|
&& ('H' == lower_to_upper_table[*(ptr + 1)]) && ('(' == *(ptr + 2)))
|
|
{
|
|
ptr += 2;
|
|
len -= 2;
|
|
}
|
|
else if ((4 < len) && ('C' == lower_to_upper_table[*ptr])
|
|
&& ('H' == lower_to_upper_table[*(ptr + 1)])
|
|
&& ('A' == lower_to_upper_table[*(ptr + 2)])
|
|
&& ('R' == lower_to_upper_table[*(ptr + 3)]) && ('(' == *(ptr + 4)))
|
|
{
|
|
ptr += 4;
|
|
len -= 4;
|
|
}
|
|
else
|
|
return FALSE;
|
|
if (MAX_GVSUBS_LEN < lcl_dst_len + 2)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
MEMCPY_LIT(dst_ptr, "CH");
|
|
dst_ptr += 2;
|
|
lcl_dst_len += 2;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
assert('(' == *ptr);
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
|
|
while ((0 < len) && (')' != *ptr))
|
|
{
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, lcl_dst_len, MAX_GVSUBS_LEN);
|
|
}
|
|
q_len = 0;
|
|
if (!have_star)
|
|
{
|
|
if (MAX_GVSUBS_LEN < ++lcl_dst_len)
|
|
{
|
|
util_out_print_gtmio("$[Z]CHAR expression too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = *ptr++;
|
|
*dst_ptr = '\0';
|
|
m_src.addr = tmp_dst_ptr;
|
|
m_src.len = (mstr_len_t)(dst_ptr - tmp_dst_ptr);
|
|
m_dst.addr = dst_string;
|
|
m_dst.len = 0;
|
|
if (!zwr2format(&m_src, &m_dst))
|
|
return FALSE;
|
|
lcl_dst_len = *dst_len; /* Reset length because we're creating the final version now */
|
|
if (MAX_GVSUBS_LEN < ++lcl_dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*tmp_dst_ptr++ = '"';
|
|
char_ptr = m_dst.addr;
|
|
if (MAX_GVSUBS_LEN < (lcl_dst_len + m_dst.len))
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
for (char_count = 0; m_dst.len > char_count; char_count++)
|
|
{
|
|
if ('"' == *char_ptr)
|
|
{
|
|
if (MAX_GVSUBS_LEN < ++lcl_dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*tmp_dst_ptr++ = '"';
|
|
q_len++;
|
|
}
|
|
*tmp_dst_ptr++ = *char_ptr++;
|
|
lcl_dst_len++;
|
|
}
|
|
if (MAX_GVSUBS_LEN < ++lcl_dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*tmp_dst_ptr++ = '"';
|
|
dst_ptr = tmp_dst_ptr;
|
|
}
|
|
else
|
|
ptr++;
|
|
assert(!have_star || ((dst_ptr == *d_ptr) && (lcl_dst_len == *dst_len)));
|
|
*src_ptr = ptr;
|
|
*src_len = len + 2 + q_len; /* Allow for the open and close quotes and any internal quotes */
|
|
*d_ptr = dst_ptr;
|
|
*dst_len = lcl_dst_len;
|
|
return TRUE;
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_delim(char *delim_str, uint4 *delim_len)
|
|
{
|
|
int char_count;
|
|
mstr dst;
|
|
int dst_len;
|
|
char *dst_ptr;
|
|
char dst_string[MAX_DELIM_LEN + 1];
|
|
uint4 len;
|
|
char *ptr;
|
|
char *ptr1;
|
|
int q_len;
|
|
char src_string[MAX_DELIM_LEN + 1];
|
|
mstr src;
|
|
char *src_ptr;
|
|
|
|
if (MAX_DELIM_LEN < *delim_len)
|
|
{
|
|
util_out_print_gtmio("Delimiter too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
ptr = delim_str;
|
|
len = *delim_len;
|
|
src_ptr = src_string;
|
|
dst_len = 0;
|
|
/* If ", scan to end quote
|
|
* If $, look for char --> c or zchar --> zch
|
|
* If _, leave it
|
|
*/
|
|
while (0 < len)
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case '"':
|
|
PROCESS_STRING(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
|
|
break;
|
|
case '$':
|
|
UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
|
|
if (0 == len)
|
|
{
|
|
util_out_print_gtmio("Invalid entry in delimiter", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if ((3 < len) && ('C' == lower_to_upper_table[*ptr])
|
|
&& ('H' == lower_to_upper_table[*(ptr + 1)])
|
|
&& ('A' == lower_to_upper_table[*(ptr + 2)])
|
|
&& ('R' == lower_to_upper_table[*(ptr + 3)]))
|
|
{
|
|
if (MAX_DELIM_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*src_ptr++ = 'C';
|
|
ptr += 4;
|
|
len -= 4;
|
|
} else if ((4 < len) && ('Z' == lower_to_upper_table[*ptr])
|
|
&& ('C' == lower_to_upper_table[*(ptr + 1)])
|
|
&& ('H' == lower_to_upper_table[*(ptr + 2)])
|
|
&& ('A' == lower_to_upper_table[*(ptr + 3)])
|
|
&& ('R' == lower_to_upper_table[*(ptr + 4)]))
|
|
{
|
|
if (MAX_DELIM_LEN < (dst_len + 3))
|
|
{
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
MEMCPY_LIT(src_ptr, "ZCH");
|
|
src_ptr += 3;
|
|
dst_len += 3;
|
|
ptr += 5;
|
|
len -= 5;
|
|
} else
|
|
{
|
|
UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
|
|
}
|
|
break;
|
|
default:
|
|
UPDATE_DST(ptr, len, FALSE, src_ptr, dst_len, MAX_DELIM_LEN);
|
|
break;
|
|
}
|
|
}
|
|
*src_ptr = '\0';
|
|
src.addr = src_string;
|
|
src.len = (mstr_len_t)(src_ptr - src_string);
|
|
dst.addr = dst_string;
|
|
dst.len = 0;
|
|
if (!zwr2format(&src, &dst))
|
|
{
|
|
util_out_print_gtmio("Invalid delimiter", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (MAX_DELIM_LEN < dst.len)
|
|
{
|
|
util_out_print_gtmio("Delimiter too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
memcpy(delim_str, dst_string, dst.len);
|
|
*delim_len = dst.len;
|
|
return TRUE;
|
|
}
|
|
|
|
boolean_t check_trigger_name(char *name_str, uint4 *name_len)
|
|
{
|
|
uint4 len, lcl_name_len;
|
|
unsigned char *ptr;
|
|
|
|
/* To conform to the other uses of the check_* functions and their use in the GET_CLI_STR_AND_CHECK macro
|
|
* name_len is passed in as a uint4 *, but in this case a uint4 would suffice. To mitigate the dereferencing
|
|
* issues, a local copy is used.
|
|
*/
|
|
lcl_name_len = *name_len;
|
|
if (MAX_USER_TRIGNAME_LEN < lcl_name_len)
|
|
return FALSE;
|
|
ptr = (unsigned char *)name_str;
|
|
if (('%' != *ptr) && !ISALPHA_ASCII(*ptr))
|
|
return FALSE;
|
|
for (len = lcl_name_len - 1, ptr++; (0 < len) && ISALNUM_ASCII(*ptr); ptr++, len--)
|
|
;
|
|
return (0 == len);
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_options(char *option_str, uint4 option_len, boolean_t *isolation, boolean_t *noisolation,
|
|
boolean_t *consistency, boolean_t *noconsistency)
|
|
{
|
|
char local_options[MAX_OPTIONS_LEN];
|
|
char *ptr;
|
|
|
|
if (MAX_OPTIONS_LEN < option_len)
|
|
{
|
|
util_out_print_gtmio("Too many options", FLUSH);
|
|
return FALSE;
|
|
}
|
|
memcpy(local_options, option_str, option_len);
|
|
*isolation = *noisolation = *consistency = *noconsistency = FALSE;
|
|
ptr = local_options;
|
|
for ( ; 0 < option_len; ptr++, option_len--)
|
|
*ptr = TOUPPER(*ptr);
|
|
ptr = strtok(local_options, ",");
|
|
do
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case 'C':
|
|
if (1 == STRLEN(ptr))
|
|
*consistency = TRUE;
|
|
else
|
|
{
|
|
assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_CONSISTENCY));
|
|
*consistency = TRUE;
|
|
}
|
|
break;
|
|
case 'I':
|
|
if (1 == STRLEN(ptr))
|
|
*isolation = TRUE;
|
|
else
|
|
{
|
|
assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_ISOLATION));
|
|
*isolation = TRUE;
|
|
}
|
|
break;
|
|
case 'N':
|
|
assert('O' == *(ptr + 1));
|
|
if ('C' == *(ptr + 2))
|
|
{
|
|
assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_NOCONSISTENCY));
|
|
*noconsistency = TRUE;
|
|
} else
|
|
{
|
|
assert('I' == *(ptr + 2));
|
|
assert(0 == MEMCMP_LIT(ptr, HASHT_OPT_NOISOLATION));
|
|
*noisolation = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
GTMASSERT; /* Parsing should have found invalid command */
|
|
break;
|
|
}
|
|
} while (ptr = strtok(NULL, ","));
|
|
return !((*isolation && *noisolation) || (*consistency && *noconsistency));
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str, char *out_str, int4 *out_max)
|
|
{
|
|
boolean_t alternation;
|
|
char dst[MAX_GVSUBS_LEN];
|
|
int dst_len;
|
|
char *dst_ptr;
|
|
int len;
|
|
boolean_t have_pattern;
|
|
boolean_t have_range;
|
|
boolean_t have_star;
|
|
boolean_t have_dot;
|
|
int i;
|
|
int lvn_count;
|
|
uint4 lvn_len[MAX_LVN_COUNT];
|
|
char *lvn_start;
|
|
char *lvn_str[MAX_LVN_COUNT];
|
|
int multiplier;
|
|
boolean_t newsub;
|
|
int num1;
|
|
int num2;
|
|
char *ptr;
|
|
char *ptr1;
|
|
char *save_dst_ptr;
|
|
int save_len;
|
|
char *start_dst_ptr;
|
|
uint4 start_len;
|
|
uint4 subsc_count;
|
|
uint4 tmp_len;
|
|
boolean_t valid_sub;
|
|
|
|
have_pattern = have_range = valid_sub = have_star = FALSE;
|
|
ptr = subscr_str;
|
|
start_len = len = *subscr_len;
|
|
dst_len = 0;
|
|
newsub = TRUE;
|
|
subsc_count = lvn_count = 0;
|
|
start_dst_ptr = dst_ptr = dst;
|
|
while ((0 < len) && (')' != *ptr))
|
|
{
|
|
if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
|
|
{
|
|
PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
newsub = FALSE;
|
|
valid_sub = TRUE;
|
|
}
|
|
else if (ISALPHA_ASCII(*ptr) || ('%' == *ptr))
|
|
{
|
|
if (!newsub)
|
|
{
|
|
util_out_print_gtmio("Invalid subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
lvn_start = ptr;
|
|
tmp_len = 0;
|
|
do
|
|
{
|
|
if (MAX_MIDENT_LEN < ++tmp_len)
|
|
{
|
|
util_out_print_gtmio("Variable name too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = *ptr++;
|
|
len--;
|
|
} while (ISALNUM_ASCII(*ptr));
|
|
if ('=' != *ptr)
|
|
{
|
|
util_out_print_gtmio("Invalid variable name in subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
for (i = 0; i < lvn_count; i++)
|
|
{
|
|
if ((lvn_len[i] == tmp_len) && (0 == strncmp(lvn_str[i], lvn_start, tmp_len)))
|
|
{
|
|
util_out_print_gtmio("Duplicate variable name in subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
}
|
|
lvn_str[lvn_count] = lvn_start;
|
|
lvn_len[lvn_count] = tmp_len;
|
|
lvn_count++;
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = *ptr++; /* move past = */
|
|
start_dst_ptr = dst_ptr;
|
|
len--;
|
|
if ((0 < len) && ((',' == *ptr) || (')' == *ptr)))
|
|
{
|
|
util_out_print_gtmio("Variable name not followed by valid subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
continue;
|
|
} else
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case '"':
|
|
PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
valid_sub = TRUE;
|
|
newsub = FALSE;
|
|
break;
|
|
case '$':
|
|
if (!process_dollar_char(&ptr, &len, have_star, &dst_ptr, &dst_len))
|
|
{
|
|
util_out_print_gtmio("Invalid subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
newsub = FALSE;
|
|
valid_sub = TRUE;
|
|
break;
|
|
case '?':
|
|
if (have_range)
|
|
{
|
|
util_out_print_gtmio("Range and pattern match not valid in same subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
ptr1 = ptr;
|
|
alternation = FALSE;
|
|
while ((0 < len) && ((',' != *ptr) || alternation) && ((')' != *ptr) || alternation)
|
|
&& (';' != *ptr))
|
|
{
|
|
num1 = num2 = -1;
|
|
have_dot = FALSE;
|
|
if (ISDIGIT_ASCII(*ptr))
|
|
{
|
|
PROCESS_AND_GET_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, num1,
|
|
MAX_GVSUBS_LEN);
|
|
}
|
|
if ('.' == *ptr)
|
|
{
|
|
have_dot = TRUE;
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = *ptr++;
|
|
len--;
|
|
if (ISDIGIT_ASCII(*ptr))
|
|
{
|
|
PROCESS_AND_GET_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, num2,
|
|
MAX_GVSUBS_LEN);
|
|
}
|
|
if (-1 == num1)
|
|
num1 = 0;
|
|
}
|
|
switch (*ptr)
|
|
{
|
|
case '(':
|
|
if (!alternation && (0 <= num1))
|
|
{
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
|
|
MAX_GVSUBS_LEN);
|
|
alternation = TRUE;
|
|
continue;
|
|
}
|
|
break;
|
|
case ',':
|
|
if (alternation && (-1 == num1) && (-1 == num2))
|
|
{
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
|
|
MAX_GVSUBS_LEN);
|
|
continue;
|
|
}
|
|
break;
|
|
case ')':
|
|
if (alternation && (-1 == num1) && (-1 == num2))
|
|
{
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len,
|
|
MAX_GVSUBS_LEN);
|
|
alternation = FALSE;
|
|
continue;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ((0 <= num1) && (0 <= num2) && (num2 < num1))
|
|
{
|
|
util_out_print_gtmio("Invalid pattern match range", FLUSH);
|
|
return FALSE;
|
|
}
|
|
switch (toupper(*ptr))
|
|
{
|
|
case 'E':
|
|
if (have_dot && (0 >= num1) && (-1 == num2))
|
|
{ /* Treat ?.E the same as * */
|
|
have_star = TRUE;
|
|
dst_ptr = start_dst_ptr;
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = '*';
|
|
}
|
|
/* Note: we're dropping into the following case */
|
|
case 'A':
|
|
case 'C':
|
|
case 'K':
|
|
case 'L':
|
|
case 'N':
|
|
case 'P':
|
|
case 'U':
|
|
case 'V':
|
|
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
break;
|
|
case '"':
|
|
PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len,
|
|
MAX_GVSUBS_LEN);
|
|
break;
|
|
/* Note: we're dropping into the default/error case */
|
|
default:
|
|
CONV_CH_AND_PRINT("Unexpected character !AD in pattern code", ptr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
have_pattern = TRUE;
|
|
valid_sub = TRUE;
|
|
newsub = FALSE;
|
|
break;
|
|
case ':':
|
|
if (have_range)
|
|
{
|
|
util_out_print_gtmio("Range within a range not allowed", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (have_pattern)
|
|
{
|
|
util_out_print_gtmio("Pattern not allowed as a range", FLUSH);
|
|
return FALSE;
|
|
}
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
|
|
{
|
|
PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
}
|
|
else if ('"' == *ptr)
|
|
{
|
|
PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
} else if ('$' == *ptr)
|
|
{
|
|
if (!process_dollar_char(&ptr, &len, have_star, &dst_ptr, &dst_len))
|
|
{
|
|
util_out_print_gtmio("Invalid range value", FLUSH);
|
|
return FALSE;
|
|
}
|
|
} else if ((0 < len) && (',' != *ptr) && (';' != *ptr) && (')' != *ptr))
|
|
{
|
|
util_out_print_gtmio("Invalid string range", FLUSH);
|
|
return FALSE;
|
|
} else
|
|
{ /* A range with no lower end - just scan the numeric or string */
|
|
ptr1 = ptr;
|
|
if (ISDIGIT_ASCII(*ptr) || ('-' == *ptr))
|
|
{
|
|
PROCESS_NUMERIC(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
} else if ('"' == *ptr1)
|
|
{
|
|
PROCESS_STRING(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
} else if ((0 < len) && ((',' != *ptr) && (';' != *ptr) && (')' != *ptr)))
|
|
{
|
|
util_out_print_gtmio("Range value must be integer or string", FLUSH);
|
|
return FALSE;
|
|
} else if (!valid_sub)
|
|
{ /* this is a single ":" - treat it just like a * */
|
|
have_star = TRUE;
|
|
dst_ptr = start_dst_ptr;
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = '*';
|
|
}
|
|
}
|
|
valid_sub = TRUE;
|
|
newsub = FALSE;
|
|
have_range = TRUE;
|
|
break;
|
|
case '*':
|
|
if (!have_star)
|
|
{
|
|
have_star = TRUE;
|
|
dst_ptr = start_dst_ptr;
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = '*';
|
|
}
|
|
ptr++;
|
|
len--;
|
|
if ((0 < len) && (',' != *ptr) && (';' != *ptr) && (')' != *ptr))
|
|
{
|
|
util_out_print_gtmio("Invalid use of *", FLUSH);
|
|
return FALSE;
|
|
} else
|
|
valid_sub = TRUE;
|
|
newsub = FALSE;
|
|
break;
|
|
case ';':
|
|
UPDATE_DST(ptr, len, have_star, dst_ptr, dst_len, MAX_GVSUBS_LEN);
|
|
/* Delete extraneous ; in the subscript */
|
|
if ((!have_star) && (newsub || ((0 < len)
|
|
&& ((',' == *ptr) || (';' == *ptr) || ISALPHA_ASCII(*ptr)
|
|
|| ('%' == *ptr) || (')' == *ptr)))))
|
|
dst_ptr--;
|
|
valid_sub = FALSE;
|
|
have_pattern = have_range = FALSE;
|
|
break;
|
|
case ',':
|
|
if (newsub)
|
|
{
|
|
util_out_print_gtmio("Empty subscript not allowed", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (MAX_GVSUBSCRIPTS <= ++subsc_count)
|
|
{
|
|
util_out_print_gtmio("Too many subscripts", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (MAX_GVSUBS_LEN < ++dst_len)
|
|
{
|
|
util_out_print_gtmio("Subscript too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
*dst_ptr++ = *ptr++;
|
|
len--;
|
|
start_dst_ptr = dst_ptr;
|
|
newsub = TRUE;
|
|
have_range = have_pattern = valid_sub = have_star = FALSE;
|
|
break;
|
|
default:
|
|
CONV_CH_AND_PRINT("Invalid character !AD in subscript", ptr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
if ((0 == len) && (')' != *ptr))
|
|
{
|
|
util_out_print_gtmio("Missing \")\" after global subscript", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if ((start_len == len) || newsub)
|
|
{
|
|
util_out_print_gtmio("Empty subscript not allowed", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if ((')' == *ptr) && (MAX_GVSUBSCRIPTS <= ++subsc_count))
|
|
{
|
|
util_out_print_gtmio("Too many subscripts", FLUSH);
|
|
return FALSE;
|
|
}
|
|
CHECK_FOR_ROOM_IN_OUTPUT_AND_COPY(dst, out_str, (int)(dst_ptr - dst), *out_max);
|
|
*subscr_len = (uint4)(dst_ptr - dst);
|
|
*next_str = ptr + 1;
|
|
return TRUE;
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_pieces(char *piece_str, uint4 *piece_len)
|
|
{
|
|
uint bit;
|
|
uint4 bitmap[MAX_PIECE_INT];
|
|
uint bitval;
|
|
uint bitword;
|
|
boolean_t have_low_num;
|
|
boolean_t have_num;
|
|
boolean_t have_num_in_str;
|
|
uint i;
|
|
uint4 len;
|
|
int low;
|
|
int num;
|
|
char *ptr;
|
|
char *ptr1;
|
|
boolean_t have_error = FALSE;
|
|
int num_len;
|
|
|
|
memset((void *)bitmap, 0, MAX_PIECE_CHARS);
|
|
ptr = piece_str;
|
|
len = *piece_len;
|
|
have_num = have_low_num = FALSE;
|
|
if ('"' == *ptr)
|
|
{
|
|
ptr++;
|
|
len--;
|
|
}
|
|
while ((0 < len) && !have_error)
|
|
{
|
|
switch (*ptr)
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
ptr1 = ptr;
|
|
A2I(ptr1, ptr + len, num);
|
|
if ((0 == num) || (MAX_PIECE_VALUE < num))
|
|
{
|
|
CONV_NUM_AND_STR_AND_PRINT("Invalid value !UL in PIECES - !AD", num, *piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
len -= (int)(ptr1 - ptr);
|
|
ptr = ptr1;
|
|
bitmap[num / BITS_PER_INT] |= 1 << (num % BITS_PER_INT);
|
|
have_num = TRUE;
|
|
have_low_num = TRUE;
|
|
break;
|
|
case ';':
|
|
if (!have_num)
|
|
{
|
|
CONV_STR_AND_PRINT("Expected an integer in PIECES - ", *piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
have_num = FALSE;
|
|
ptr++;
|
|
len--;
|
|
break;
|
|
case ':':
|
|
if (!have_low_num)
|
|
{
|
|
CONV_STR_AND_PRINT("Expected an integer for lower value in range in PIECES - ",
|
|
*piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
ptr++;
|
|
len--;
|
|
low = num;
|
|
if (!ISDIGIT_ASCII(*ptr))
|
|
{
|
|
CONV_STR_AND_PRINT("Expected an integer for upper value in range in PIECES - ",
|
|
*piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
ptr1 = ptr;
|
|
A2I(ptr1, ptr + len, num);
|
|
if (MAX_PIECE_VALUE < num)
|
|
{
|
|
CONV_NUM_AND_STR_AND_PRINT("Invalid value \"!UL\" in PIECES - !AD", num,
|
|
*piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
if (num <= low)
|
|
{
|
|
CONV_STR_AND_PRINT("Low value of range not less than high value in PIECES - ",
|
|
*piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
len -= (int)(ptr1 - ptr);
|
|
ptr = ptr1;
|
|
for (i = low + 1; i <= num; i++)
|
|
bitmap[i / BITS_PER_INT] |= 1 << (i % BITS_PER_INT);
|
|
have_num = TRUE;
|
|
have_low_num = FALSE;
|
|
break;
|
|
case '"':
|
|
if (1 == len)
|
|
{
|
|
len--;
|
|
break;
|
|
}
|
|
default:
|
|
CONV_CH_AND_STR_AND_PRINT("Invalid character !AD in PIECES - !AD", ptr, *piece_len, piece_str);
|
|
have_error = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if ((0 != len) || !have_num || have_error)
|
|
{
|
|
if (!have_error)
|
|
CONV_STR_AND_PRINT("Invalid PIECE entry - ", *piece_len, piece_str);
|
|
return FALSE;
|
|
}
|
|
have_num = have_low_num = have_num_in_str = FALSE;
|
|
ptr = piece_str;
|
|
len = 0;
|
|
for (i = 0; i < MAX_PIECE_INT; i++)
|
|
{
|
|
if ((0 == bitmap[i] && !have_low_num))
|
|
continue;
|
|
bitword = bitmap[i];
|
|
bit = 0;
|
|
while ((0 != bitword) || have_low_num)
|
|
{
|
|
bitval = bitword & 1;
|
|
if (!have_low_num)
|
|
{
|
|
if (0 == bitval)
|
|
{
|
|
bitword = bitword >> 1;
|
|
bit++;
|
|
continue;
|
|
}
|
|
have_num = TRUE;
|
|
have_low_num = TRUE;
|
|
low = i * BITS_PER_INT + bit;
|
|
if (have_num_in_str)
|
|
{
|
|
*ptr++ = ';';
|
|
len++;
|
|
}
|
|
num_len = 0;
|
|
I2A(ptr, num_len, low);
|
|
len += num_len;
|
|
ptr += num_len;
|
|
have_num_in_str = TRUE;
|
|
}
|
|
while ((1 == bitval) && (BITS_PER_INT > bit))
|
|
{
|
|
bitword = bitword >> 1;
|
|
bitval = bitword & 1;
|
|
bit++;
|
|
}
|
|
if (BITS_PER_INT == bit)
|
|
break;
|
|
num = (0 == bit) ? i * BITS_PER_INT - 1 : i * BITS_PER_INT + bit - 1;
|
|
have_low_num = FALSE;
|
|
if (num == low)
|
|
continue;
|
|
*ptr++ = ':';
|
|
len++;
|
|
num_len = 0;
|
|
I2A(ptr, num_len, num);
|
|
len += num_len;
|
|
ptr += num_len;
|
|
}
|
|
}
|
|
*ptr = '\0';
|
|
*piece_len = len;
|
|
return TRUE;
|
|
}
|
|
|
|
STATICFNDEF boolean_t process_xecute(char *xecute_str, uint4 *xecute_len, boolean_t multi_line)
|
|
{
|
|
uint4 dst_len;
|
|
char dst_string[MAX_SRCLINE];
|
|
uint4 src_len;
|
|
gv_trigger_t trigdsc;
|
|
|
|
src_len = *xecute_len;
|
|
if ((src_len == XTENDED_START_LEN) && (0 == memcmp(XTENDED_START, xecute_str, XTENDED_START_LEN)))
|
|
return TRUE;
|
|
if (!multi_line && (NULL != memchr(xecute_str, '\n', src_len)))
|
|
{
|
|
util_out_print_gtmio("Newline not allowed in XECUTE string", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (!multi_line && MAX_SRCLINE < src_len + 1) /* allow room for leading blank */
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (0 == src_len)
|
|
{
|
|
util_out_print_gtmio("Empty XECUTE string is invalid", FLUSH);
|
|
return FALSE;
|
|
}
|
|
if (!multi_line)
|
|
{
|
|
dst_string[0] = ' ';
|
|
if (!trigger_scan_string(xecute_str, &src_len, dst_string + 1, &dst_len) || (1 != src_len))
|
|
{
|
|
util_out_print_gtmio("Invalid XECUTE string", FLUSH);
|
|
return FALSE;
|
|
}
|
|
memcpy(xecute_str, dst_string, ++dst_len);
|
|
*xecute_len = dst_len;
|
|
trigdsc.xecute_str.str.addr = dst_string;
|
|
trigdsc.xecute_str.str.len = dst_len;
|
|
} else
|
|
{
|
|
trigdsc.xecute_str.str.addr = xecute_str;
|
|
trigdsc.xecute_str.str.len = src_len;
|
|
}
|
|
/* Test compile the string - first build up the parm list to trigger compile routine */
|
|
trigdsc.rtn_desc.rt_name.addr = TRIGR_PRECOMP_RTNNAME;
|
|
trigdsc.rtn_desc.rt_name.len = SIZEOF(TRIGR_PRECOMP_RTNNAME) - 1;
|
|
trigdsc.rtn_desc.rt_adr = NULL;
|
|
return (0 == gtm_trigger_complink(&trigdsc, FALSE));
|
|
}
|
|
|
|
boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **values, uint4 *value_len, int4 *max_len,
|
|
boolean_t *multi_line_xecute)
|
|
{
|
|
boolean_t cli_status;
|
|
int cmd_ind;
|
|
int count;
|
|
int eof;
|
|
int extra;
|
|
boolean_t found_zkill;
|
|
boolean_t found_kill;
|
|
uint4 len;
|
|
int4 max_output_len;
|
|
int parse_ret;
|
|
boolean_t delim_present, name_present, pieces_present, xecute_present, zdelim_present;
|
|
char *ptr;
|
|
char *ptr1;
|
|
char *ptr2;
|
|
int4 rec_num;
|
|
CLI_ENTRY *save_cmd_ary;
|
|
boolean_t set_present;
|
|
int trigvn_len;
|
|
boolean_t in_multi_line_xecute, out_multi_line_xecute;
|
|
|
|
max_output_len = *max_len;
|
|
in_multi_line_xecute = out_multi_line_xecute = *multi_line_xecute;
|
|
if (in_multi_line_xecute)
|
|
{
|
|
if ((XTENDED_STOP_LEN != input_len) || (0 != memcmp(XTENDED_STOP, input, XTENDED_STOP_LEN)))
|
|
{
|
|
ptr1 = values[XECUTE_SUB] + value_len[XECUTE_SUB];
|
|
if (0 < (max_output_len - input_len - 1))
|
|
{
|
|
memcpy(ptr1, input, input_len);
|
|
ptr1 += input_len;
|
|
*ptr1 = '\n';
|
|
max_output_len -= (input_len + 1);
|
|
value_len[XECUTE_SUB] += input_len + 1;
|
|
*max_len = max_output_len;
|
|
return TRIG_SUCCESS;
|
|
} else
|
|
{
|
|
*multi_line_xecute = FALSE;
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH);
|
|
return FALSE;
|
|
}
|
|
}
|
|
out_multi_line_xecute = FALSE;
|
|
if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], TRUE))
|
|
{
|
|
*multi_line_xecute = FALSE;
|
|
ERROR_MSG_RETURN("Error parsing XECUTE string: ", value_len[XECUTE_SUB], values[XECUTE_SUB]);
|
|
}
|
|
*multi_line_xecute = out_multi_line_xecute;
|
|
*max_len = max_output_len;
|
|
return TRIG_SUCCESS;
|
|
}
|
|
ptr1 = input;
|
|
len = (uint4)input_len;
|
|
if ('^' != *ptr1++)
|
|
{
|
|
ERROR_MSG_RETURN("Missing global name:\n", input_len, input);
|
|
}
|
|
ptr = ptr1;
|
|
len--;
|
|
if (('%' != *ptr1) && !ISALPHA_ASCII(*ptr1))
|
|
{
|
|
ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
|
|
}
|
|
ptr1++;
|
|
while (ISALNUM_ASCII(*ptr1))
|
|
ptr1++;
|
|
if (('(' != *ptr1) && !ISSPACE_ASCII(*ptr1))
|
|
{
|
|
ERROR_MSG_RETURN("Invalid global name:\n", input_len, input);
|
|
}
|
|
trigvn_len = (int)(ptr1 - ptr);
|
|
if (MAX_MIDENT_LEN < trigvn_len)
|
|
{
|
|
trigvn_len = MAX_MIDENT_LEN;
|
|
util_out_print_gtmio("Warning: global name truncated to ^!AD", FLUSH, trigvn_len, ptr);
|
|
}
|
|
memcpy(trigvn, ptr, trigvn_len);
|
|
trigvn[trigvn_len] = '\0';
|
|
/* lookup global to get collation info */
|
|
len -= (uint4)trigvn_len;
|
|
ptr2 = ptr1;
|
|
if ('(' == *ptr1)
|
|
{
|
|
ptr1++;
|
|
len--;
|
|
if (!process_subscripts(ptr1, &len, &ptr2, values[GVSUBS_SUB], &max_output_len))
|
|
{
|
|
ERROR_MSG_RETURN("", input_len, input);
|
|
}
|
|
} else
|
|
len = 0;
|
|
if (0 > --max_output_len)
|
|
{
|
|
util_out_print_gtmio("Trigger definition too long", FLUSH);
|
|
return TRIG_FAILURE;
|
|
}
|
|
values[GVSUBS_SUB][len] = '\0';
|
|
value_len[GVSUBS_SUB] = (uint4)len;
|
|
save_cmd_ary = cmd_ary;
|
|
cmd_ary = &trigger_cmd_ary[0];
|
|
gtm_cli_interpret_string = FALSE;
|
|
cli_str_setup(input_len - (uint4)(ptr2 - input), ptr2);
|
|
parse_ret = parse_triggerfile_cmd();
|
|
gtm_cli_interpret_string = TRUE;
|
|
cmd_ary = save_cmd_ary;
|
|
if (parse_ret)
|
|
{
|
|
ERROR_MSG_RETURN("Parse error in input:\n", input_len, input);
|
|
}
|
|
values[CMD_SUB] = values[GVSUBS_SUB] + value_len[GVSUBS_SUB] + 1;
|
|
if (CLI_PRESENT == cli_present("COMMANDS"))
|
|
{
|
|
GET_CLI_STR("COMMANDS", max_output_len, values[CMD_SUB], value_len[CMD_SUB]);
|
|
ptr = values[CMD_SUB];
|
|
count = 0;
|
|
found_zkill = found_kill = FALSE;
|
|
/* The following order (set, kill, zkill, ztkill) needs to be maintained to match
|
|
* the corresponding bit value orders in gv_trig_cmd_table.h
|
|
*/
|
|
if (CLI_PRESENT == (set_present = cli_present("COMMANDS.SET")))
|
|
{
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_SET].str.len, gvtr_cmd_mval[GVTR_CMDTYPE_SET].str.addr,
|
|
max_output_len);
|
|
}
|
|
if (CLI_PRESENT == cli_present("COMMANDS.KILL"))
|
|
{
|
|
found_kill = TRUE;
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_KILL].str.len, gvtr_cmd_mval[GVTR_CMDTYPE_KILL].str.addr,
|
|
max_output_len);
|
|
}
|
|
if (CLI_PRESENT == cli_present("COMMANDS.ZKILL"))
|
|
{
|
|
found_zkill = TRUE;
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZKILL].str.len,
|
|
gvtr_cmd_mval[GVTR_CMDTYPE_ZKILL].str.addr, max_output_len);
|
|
}
|
|
if (CLI_PRESENT == cli_present("COMMANDS.ZWITHDRAW") && !found_zkill)
|
|
{
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZKILL].str.len,
|
|
gvtr_cmd_mval[GVTR_CMDTYPE_ZKILL].str.addr, max_output_len);
|
|
}
|
|
if (CLI_PRESENT == cli_present("COMMANDS.ZTKILL"))
|
|
{
|
|
if (found_kill)
|
|
ERROR_MSG_RETURN("KILL and ZTKILL incompatible: ", value_len[CMD_SUB], values[CMD_SUB]);
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.len,
|
|
gvtr_cmd_mval[GVTR_CMDTYPE_ZTKILL].str.addr, max_output_len);
|
|
}
|
|
if (CLI_PRESENT == cli_present("COMMANDS.ZTRIGGER"))
|
|
{
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, gvtr_cmd_mval[GVTR_CMDTYPE_ZTRIGGER].str.len,
|
|
gvtr_cmd_mval[GVTR_CMDTYPE_ZTRIGGER].str.addr, max_output_len);
|
|
}
|
|
*ptr = '\0';
|
|
value_len[CMD_SUB] = STRLEN(values[CMD_SUB]);
|
|
} else
|
|
value_len[CMD_SUB] = 0;
|
|
UPDATE_TRIG_PTRS(values[CMD_SUB], values[DELIM_SUB], value_len[CMD_SUB], max_output_len);
|
|
GET_CLI_STR_AND_CHECK("DELIM", delim_present, max_output_len, process_delim, values[DELIM_SUB], value_len[DELIM_SUB],
|
|
values[TRIGNAME_SUB], "Error parsing DELIM string: ");
|
|
GET_CLI_STR_AND_CHECK("NAME", name_present, max_output_len, check_trigger_name, values[TRIGNAME_SUB],
|
|
value_len[TRIGNAME_SUB], values[OPTIONS_SUB], "Error parsing NAME string: ");
|
|
if (CLI_PRESENT == cli_present("OPTIONS"))
|
|
{
|
|
boolean_t isolation, noisolation, consistency, noconsistency;
|
|
|
|
GET_CLI_STR("OPTIONS", max_output_len, values[OPTIONS_SUB], value_len[OPTIONS_SUB]);
|
|
if (!process_options(values[OPTIONS_SUB], value_len[OPTIONS_SUB], &isolation, &noisolation, &consistency,
|
|
&noconsistency))
|
|
{
|
|
ERROR_MSG_RETURN("Inconsistent values in OPTIONS string: ", value_len[OPTIONS_SUB], values[OPTIONS_SUB]);
|
|
}
|
|
count = 0;
|
|
ptr = values[OPTIONS_SUB];
|
|
if (isolation)
|
|
{
|
|
ADD_STRING(count, ptr, STRLEN(HASHT_OPT_ISOLATION), HASHT_OPT_ISOLATION, max_output_len);
|
|
}
|
|
else if (noisolation)
|
|
{
|
|
ADD_STRING(count, ptr, STRLEN(HASHT_OPT_NOISOLATION), HASHT_OPT_NOISOLATION, max_output_len);
|
|
}
|
|
if (consistency)
|
|
{
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, STRLEN(HASHT_OPT_CONSISTENCY), HASHT_OPT_CONSISTENCY, max_output_len);
|
|
}
|
|
else if (noconsistency)
|
|
{
|
|
ADD_COMMA_IF_NEEDED(count, ptr, max_output_len);
|
|
ADD_STRING(count, ptr, STRLEN(HASHT_OPT_NOCONSISTENCY), HASHT_OPT_NOCONSISTENCY, max_output_len);
|
|
}
|
|
*ptr = '\0';
|
|
value_len[OPTIONS_SUB] = STRLEN(values[OPTIONS_SUB]);
|
|
} else
|
|
value_len[OPTIONS_SUB] = 0;
|
|
UPDATE_TRIG_PTRS(values[OPTIONS_SUB], values[PIECES_SUB], value_len[OPTIONS_SUB], max_output_len);
|
|
GET_CLI_STR_AND_CHECK("PIECES", pieces_present, max_output_len, process_pieces, values[PIECES_SUB], value_len[PIECES_SUB],
|
|
values[ZDELIM_SUB], "");
|
|
GET_CLI_STR_AND_CHECK("ZDELIM", zdelim_present, max_output_len, process_delim, values[ZDELIM_SUB], value_len[ZDELIM_SUB],
|
|
values[XECUTE_SUB], "Error parsing ZDELIM string: ");
|
|
/* Since process_xecute() does a test compile of the xecute string, it changes the parsing table from MUPIP TRIGGER
|
|
* to GT.M. To avoid problems with saving and restoring the parse state (which would have to be done with globals
|
|
* that are static in cli_parse.c), it is much easier to put process_xecute() last in the list of qualifiers to check -
|
|
* solving the problem. In other words, don't try to neaten things up by making the qualifiers alphabetical!
|
|
*/
|
|
if (CLI_PRESENT == (xecute_present = cli_present("XECUTE")))
|
|
{
|
|
GET_CLI_STR("XECUTE", max_output_len, values[XECUTE_SUB], value_len[XECUTE_SUB]);
|
|
out_multi_line_xecute |= (value_len[XECUTE_SUB] == XTENDED_START_LEN)
|
|
&& (0 == memcmp(XTENDED_START, values[XECUTE_SUB], XTENDED_START_LEN));
|
|
if (!process_xecute(values[XECUTE_SUB], &value_len[XECUTE_SUB], out_multi_line_xecute))
|
|
{
|
|
ptr = values[XECUTE_SUB];
|
|
len = value_len[XECUTE_SUB];
|
|
ERROR_MSG_RETURN("Error parsing XECUTE string: ", len, ptr);
|
|
}
|
|
} else
|
|
value_len[XECUTE_SUB] = 0;
|
|
if (!in_multi_line_xecute)
|
|
{
|
|
max_output_len -= value_len[XECUTE_SUB];
|
|
UPDATE_TRIG_PTRS(values[XECUTE_SUB], values[CHSET_SUB], value_len[XECUTE_SUB], max_output_len);
|
|
ptr = values[XECUTE_SUB] + value_len[XECUTE_SUB];
|
|
*ptr = '\0';
|
|
if (!xecute_present && !out_multi_line_xecute)
|
|
{
|
|
ERROR_STR_RETURN("XECUTE value missing");
|
|
}
|
|
if (0 == value_len[CMD_SUB])
|
|
{
|
|
ERROR_STR_RETURN("COMMANDS value missing");
|
|
}
|
|
if (delim_present && zdelim_present)
|
|
{
|
|
ERROR_STR_RETURN("Can't have both DELIM and ZDELIM in same entry");
|
|
}
|
|
if ((delim_present || zdelim_present) && !set_present)
|
|
{
|
|
ERROR_STR_RETURN("DELIM and ZDELIM need a commands=SET");
|
|
}
|
|
if (pieces_present && (!delim_present && !zdelim_present))
|
|
{
|
|
ERROR_STR_RETURN("PIECES need either DELIM or ZDELIM");
|
|
}
|
|
if (MAX_HASH_INDEX_LEN < (trigvn_len + 1 + value_len[GVSUBS_SUB] + 1 + value_len[DELIM_SUB] + 1
|
|
+ value_len[ZDELIM_SUB] + 1 + value_len[XECUTE_SUB] + 1))
|
|
{
|
|
ERROR_STR_RETURN("Entry too large to properly index");
|
|
}
|
|
}
|
|
|
|
*multi_line_xecute = out_multi_line_xecute;
|
|
*max_len = max_output_len;
|
|
return TRIG_SUCCESS;
|
|
}
|