709 lines
20 KiB
C
709 lines
20 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 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 <stdarg.h>
|
|
#include "gtm_string.h"
|
|
|
|
#include "gtmio.h"
|
|
#include "have_crit.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "filestruct.h"
|
|
#include "cmd_qlf.h"
|
|
#include "collseq.h"
|
|
#include "error.h"
|
|
#include "iosp.h"
|
|
#include "jnl.h"
|
|
#include "lv_val.h"
|
|
#include "view.h"
|
|
#include "send_msg.h"
|
|
#include "op.h"
|
|
#include "change_reg.h"
|
|
#include "patcode.h"
|
|
#include "mprof.h"
|
|
#include "cmidef.h"
|
|
#include "gvcmz.h"
|
|
#include "testpt.h"
|
|
#include "mvalconv.h"
|
|
#include "dpgbldir.h" /* for get_next_gdr() prototype */
|
|
#include "ast.h"
|
|
#include "wcs_flu.h"
|
|
#include "stringpool.h"
|
|
#include "gtmdbglvl.h"
|
|
#include "gtm_malloc.h"
|
|
#include "alias.h"
|
|
#include "fullbool.h"
|
|
#ifdef GTM_TRIGGER
|
|
#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */
|
|
#include "gv_trigger.h"
|
|
#include "gtm_trigger.h"
|
|
#endif
|
|
|
|
GBLREF boolean_t certify_all_blocks;
|
|
GBLREF bool undef_inhibit, jobpid;
|
|
GBLREF bool view_debug1, view_debug2, view_debug3, view_debug4;
|
|
GBLREF bool zdefactive;
|
|
GBLREF unsigned short zdefbufsiz;
|
|
GBLREF int4 break_message_mask;
|
|
GBLREF command_qualifier cmd_qlf, glb_cmd_qlf;
|
|
GBLREF gd_addr *gd_header;
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF gv_namehead *gv_target, *gv_target_list;
|
|
GBLREF gv_namehead *reset_gv_target;
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
GBLREF sgmnt_data_ptr_t cs_data;
|
|
GBLREF symval *curr_symval;
|
|
GBLREF trans_num local_tn; /* transaction number for THIS PROCESS */
|
|
GBLREF int4 zdir_form;
|
|
GBLREF boolean_t gvdupsetnoop; /* if TRUE, duplicate SETs update journal but not database (except for curr_tn++) */
|
|
GBLREF boolean_t badchar_inhibit;
|
|
GBLREF int gv_fillfactor;
|
|
GBLREF symval *curr_symval;
|
|
GBLREF uint4 gtmDebugLevel;
|
|
GBLREF boolean_t lvmon_enabled;
|
|
GBLREF spdesc stringpool;
|
|
GBLREF boolean_t is_updproc;
|
|
|
|
error_def(ERR_ACTRANGE);
|
|
error_def(ERR_COLLATIONUNDEF);
|
|
error_def(ERR_COLLDATAEXISTS);
|
|
error_def(ERR_INVZDIRFORM);
|
|
error_def(ERR_ISOLATIONSTSCHN);
|
|
error_def(ERR_JNLFLUSH);
|
|
error_def(ERR_PATLOAD);
|
|
error_def(ERR_PATTABNOTFND);
|
|
error_def(ERR_REQDVIEWPARM);
|
|
error_def(ERR_TEXT);
|
|
error_def(ERR_TRACEON);
|
|
error_def(ERR_VIEWCMD);
|
|
error_def(ERR_YDIRTSZ);
|
|
error_def(ERR_ZDEFACTIVE);
|
|
|
|
#define MAX_YDIRTSTR 32
|
|
#define ZDEFMIN 1024
|
|
#define ZDEFDEF 32767
|
|
#define ZDEFMAX 65535
|
|
|
|
#define WRITE_LITERAL(x) (outval.str.len = SIZEOF(x) - 1, outval.str.addr = (x), op_write(&outval))
|
|
|
|
/* if changing noisolation status within TP and already referenced the global, then error */
|
|
#define SET_GVNH_NOISOLATION_STATUS(gvnh, status) \
|
|
{ \
|
|
GBLREF uint4 dollar_tlevel; \
|
|
\
|
|
if (!dollar_tlevel || gvnh->read_local_tn != local_tn || status == gvnh->noisolation) \
|
|
gvnh->noisolation = status; \
|
|
else \
|
|
rts_error(VARLSTCNT(6) ERR_ISOLATIONSTSCHN, 4, gvnh->gvname.var_name.len, \
|
|
gvnh->gvname.var_name.addr, gvnh->noisolation, status); \
|
|
}
|
|
|
|
void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
|
|
{
|
|
int4 testvalue, tmpzdefbufsiz;
|
|
uint4 jnl_status, dummy_errno;
|
|
int status;
|
|
gd_region *reg, *r_top, *save_reg;
|
|
gv_namehead *gvnh;
|
|
mval *arg, *nextarg, outval;
|
|
mstr tmpstr;
|
|
va_list var;
|
|
viewparm parmblk;
|
|
viewtab_entry *vtp;
|
|
gd_addr *addr_ptr;
|
|
noisolation_element *gvnh_entry;
|
|
int lct, ncol;
|
|
collseq *new_lcl_collseq;
|
|
ht_ent_mname *tabent, *topent;
|
|
lv_val *lv;
|
|
symval *cstab;
|
|
sgmnt_addrs *csa;
|
|
sgmnt_data_ptr_t csd;
|
|
jnl_buffer_ptr_t jb;
|
|
int table_size_orig;
|
|
ht_ent_mname *table_base_orig;
|
|
hash_table_mname *table;
|
|
boolean_t dbgdmpenabled, was_crit;
|
|
symval *lvlsymtab;
|
|
lv_blk *lvbp;
|
|
lv_val *lvp, *lvp_top;
|
|
VMS_ONLY(int numarg;)
|
|
|
|
static readonly char msg1[] = "Caution: Database Block Certification Has Been ";
|
|
static readonly char msg2[] = "Disabled";
|
|
static readonly char msg3[] = "Enabled";
|
|
static readonly char lv_msg1[] =
|
|
"Caution: GT.M reserved local variable string pointer duplicate check diagnostic has been";
|
|
static readonly char upper[] = "UPPER";
|
|
static readonly char lower[] = "LOWER";
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
VAR_START(var, keyword);
|
|
VMS_ONLY(va_count(numarg));
|
|
jnl_status = 0;
|
|
if (numarg < 1)
|
|
GTMASSERT;
|
|
MV_FORCE_STR(keyword);
|
|
numarg--; /* remove keyword from count */
|
|
if (0 < numarg)
|
|
{
|
|
arg = va_arg(var, mval *);
|
|
MV_FORCE_STR(arg);
|
|
} else
|
|
arg = (mval *)NULL;
|
|
vtp = viewkeys(&keyword->str);
|
|
view_arg_convert(vtp, arg, &parmblk);
|
|
switch(vtp->keycode)
|
|
{
|
|
# ifdef UNICODE_SUPPORTED
|
|
case VTK_BADCHAR:
|
|
badchar_inhibit = FALSE;
|
|
break;
|
|
case VTK_NOBADCHAR:
|
|
badchar_inhibit = TRUE;
|
|
break;
|
|
# endif
|
|
case VTK_BREAKMSG:
|
|
break_message_mask = MV_FORCE_INT(parmblk.value);
|
|
break;
|
|
case VTK_DEBUG1:
|
|
outval.mvtype = MV_STR;
|
|
view_debug1 = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_DEBUG2:
|
|
outval.mvtype = MV_STR;
|
|
view_debug2 = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_DEBUG3:
|
|
outval.mvtype = MV_STR;
|
|
view_debug3 = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_DEBUG4:
|
|
outval.mvtype = MV_STR;
|
|
view_debug4 = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_FLUSH:
|
|
if (NULL == gd_header) /* open gbldir */
|
|
gvinit();
|
|
save_reg = gv_cur_region;
|
|
if (NULL == parmblk.gv_ptr)
|
|
{ /* flush all regions */
|
|
reg = gd_header->regions;
|
|
r_top = reg + gd_header->n_regions - 1;
|
|
} else /* flush selected region */
|
|
r_top = reg = parmblk.gv_ptr;
|
|
for (; reg <= r_top; reg++)
|
|
{
|
|
if (!reg->open)
|
|
gv_init_reg(reg);
|
|
if (!reg->read_only)
|
|
{
|
|
gv_cur_region = reg;
|
|
change_reg(); /* for jnl_ensure_open */
|
|
ENSURE_JNL_OPEN(cs_addrs, gv_cur_region);
|
|
wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH);
|
|
}
|
|
}
|
|
gv_cur_region = save_reg;
|
|
change_reg();
|
|
break;
|
|
case VTK_FULLBOOL:
|
|
TREF(gtm_fullbool) = FULL_BOOL;
|
|
break;
|
|
case VTK_FULLBOOLWARN:
|
|
TREF(gtm_fullbool) = FULL_BOOL_WARN;
|
|
break;
|
|
case VTK_NOFULLBOOL:
|
|
TREF(gtm_fullbool) = GTM_BOOL;
|
|
break;
|
|
case VTK_GDSCERT0:
|
|
outval.mvtype = MV_STR;
|
|
op_wteol(1);
|
|
WRITE_LITERAL(msg1);
|
|
certify_all_blocks = FALSE;
|
|
WRITE_LITERAL(msg2);
|
|
op_wteol(1);
|
|
break;
|
|
case VTK_GDSCERT1:
|
|
outval.mvtype = MV_STR;
|
|
op_wteol(1);
|
|
WRITE_LITERAL(msg1);
|
|
certify_all_blocks = TRUE;
|
|
WRITE_LITERAL(msg3);
|
|
op_wteol(1);
|
|
break;
|
|
case VTK_GDSCERT:
|
|
outval.mvtype = MV_STR;
|
|
op_wteol(1);
|
|
WRITE_LITERAL(msg1);
|
|
certify_all_blocks = (0 != MV_FORCE_INT(parmblk.value));
|
|
if (certify_all_blocks)
|
|
WRITE_LITERAL(msg3);
|
|
else
|
|
WRITE_LITERAL(msg2);
|
|
op_wteol(1);
|
|
break;
|
|
case VTK_GVDUPSETNOOP:
|
|
gvdupsetnoop = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_LVDUPCHECK:
|
|
/* This feature is not needed any more. This is a noop now */
|
|
break;
|
|
case VTK_LVNULLSUBS:
|
|
TREF(lv_null_subs) = LVNULLSUBS_OK;
|
|
break;
|
|
case VTK_NOLVNULLSUBS:
|
|
TREF(lv_null_subs) = LVNULLSUBS_NO;
|
|
break;
|
|
case VTK_NEVERLVNULLSUBS:
|
|
TREF(lv_null_subs) = LVNULLSUBS_NEVER;
|
|
break;
|
|
# ifndef VMS
|
|
case VTK_JNLERROR:
|
|
/* In case of update process, dont let this variable be user-controlled. We always want to error out
|
|
* if we are about to invoke "jnl_file_lost". This way we will force the operator to fix whatever
|
|
* caused the jnl_file_lost invocation (e.g. permissions, disk space issues etc.) and restart
|
|
* the receiver server so replication can resume from wherever we last left. On the other hand,
|
|
* automatically turning off journaling (and hence replication) (like is a choice for GT.M)
|
|
* would make resumption of replication much more effort for the user.
|
|
*/
|
|
assert(!is_updproc || (JNL_FILE_LOST_ERRORS == TREF(error_on_jnl_file_lost)));
|
|
if (!is_updproc)
|
|
{
|
|
TREF(error_on_jnl_file_lost) = MV_FORCE_INT(parmblk.value);
|
|
if (MAX_JNL_FILE_LOST_OPT < TREF(error_on_jnl_file_lost))
|
|
TREF(error_on_jnl_file_lost) = JNL_FILE_LOST_TURN_OFF;
|
|
if (NULL == gd_header) /* open gbldir */
|
|
gvinit();
|
|
save_reg = gv_cur_region;
|
|
/* change all regions */
|
|
reg = gd_header->regions;
|
|
r_top = reg + gd_header->n_regions - 1;
|
|
for (; reg <= r_top; reg++)
|
|
{
|
|
if (!reg->open)
|
|
gv_init_reg(reg);
|
|
if (!reg->read_only)
|
|
{
|
|
gv_cur_region = reg;
|
|
change_reg();
|
|
csa = cs_addrs;
|
|
csd = csa->hdr;
|
|
if (JNL_ENABLED(csd))
|
|
{
|
|
was_crit = csa->now_crit;
|
|
if (!was_crit)
|
|
grab_crit(reg);
|
|
if (JNL_ENABLED(csd))
|
|
csa->jnl->error_reported = FALSE;
|
|
if (!was_crit)
|
|
rel_crit(reg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
# endif
|
|
case VTK_JNLFLUSH:
|
|
if (NULL == gd_header) /* open gbldir */
|
|
gvinit();
|
|
save_reg = gv_cur_region;
|
|
if (NULL == parmblk.gv_ptr)
|
|
{ /* flush all journal files */
|
|
reg = gd_header->regions;
|
|
r_top = reg + gd_header->n_regions - 1;
|
|
} else /* flush journal for selected region */
|
|
r_top = reg = parmblk.gv_ptr;
|
|
for (; reg <= r_top; reg++)
|
|
{
|
|
if (!reg->open)
|
|
gv_init_reg(reg);
|
|
gv_cur_region = reg;
|
|
change_reg();
|
|
csa = cs_addrs;
|
|
csd = csa->hdr;
|
|
if (JNL_ENABLED(csd))
|
|
{
|
|
was_crit = csa->now_crit;
|
|
if (!was_crit)
|
|
grab_crit(reg);
|
|
if (JNL_ENABLED(csd))
|
|
{
|
|
jnl_status = jnl_ensure_open();
|
|
if (0 == jnl_status)
|
|
{
|
|
jb = csa->jnl->jnl_buff;
|
|
if (SS_NORMAL == (jnl_status = jnl_flush(reg)))
|
|
{
|
|
assert(jb->dskaddr == jb->freeaddr);
|
|
UNIX_ONLY(jnl_fsync(reg, jb->dskaddr));
|
|
UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr));
|
|
} else
|
|
{
|
|
send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
|
|
ERR_TEXT, 2,
|
|
RTS_ERROR_TEXT("Error with journal flush during op_view"),
|
|
jnl_status);
|
|
assert(FALSE);
|
|
}
|
|
} else
|
|
send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg));
|
|
}
|
|
if (!was_crit)
|
|
rel_crit(reg);
|
|
}
|
|
}
|
|
gv_cur_region = save_reg;
|
|
change_reg();
|
|
break;
|
|
case VTK_JNLWAIT:
|
|
/* go through all regions that could have possibly been open across all global directories */
|
|
for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
|
|
for (reg = addr_ptr->regions, r_top = reg + addr_ptr->n_regions; reg < r_top; reg++)
|
|
jnl_wait(reg);
|
|
break;
|
|
case VTK_JOBPID:
|
|
outval.mvtype = MV_STR;
|
|
jobpid = (0 != MV_FORCE_INT(parmblk.value));
|
|
break;
|
|
case VTK_LABELS:
|
|
if ((SIZEOF(upper) - 1) == parmblk.value->str.len)
|
|
{
|
|
if (!memcmp(upper, parmblk.value->str.addr, SIZEOF(upper) - 1))
|
|
glb_cmd_qlf.qlf &= ~CQ_LOWER_LABELS;
|
|
else if (!memcmp(lower, parmblk.value->str.addr, SIZEOF(lower) - 1))
|
|
glb_cmd_qlf.qlf |= CQ_LOWER_LABELS;
|
|
cmd_qlf.qlf = glb_cmd_qlf.qlf;
|
|
}
|
|
break;
|
|
case VTK_NOISOLATION:
|
|
if (NOISOLATION_NULL == parmblk.ni_list.type)
|
|
{
|
|
for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh)
|
|
SET_GVNH_NOISOLATION_STATUS(gvnh, FALSE);
|
|
parmblk.ni_list.type = NOISOLATION_PLUS;
|
|
}
|
|
assert((NOISOLATION_PLUS == parmblk.ni_list.type) || (NOISOLATION_MINUS == parmblk.ni_list.type));
|
|
if (NOISOLATION_PLUS == parmblk.ni_list.type)
|
|
{
|
|
for (gvnh_entry = parmblk.ni_list.gvnh_list; gvnh_entry; gvnh_entry = gvnh_entry->next)
|
|
SET_GVNH_NOISOLATION_STATUS(gvnh_entry->gvnh, TRUE);
|
|
} else
|
|
{
|
|
for (gvnh_entry = parmblk.ni_list.gvnh_list; gvnh_entry; gvnh_entry = gvnh_entry->next)
|
|
SET_GVNH_NOISOLATION_STATUS(gvnh_entry->gvnh, FALSE);
|
|
}
|
|
break;
|
|
case VTK_PATCODE:
|
|
if (arg)
|
|
tmpstr = parmblk.value->str;
|
|
else
|
|
tmpstr.len = 0;
|
|
status = setpattab(&tmpstr);
|
|
if (0 == status)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(4) ERR_PATTABNOTFND, 2, parmblk.value->str.len, parmblk.value->str.addr);
|
|
}
|
|
break;
|
|
case VTK_RESETGVSTATS:
|
|
for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
|
|
{
|
|
for (reg = addr_ptr->regions, r_top = reg + addr_ptr->n_regions; reg < r_top; reg++)
|
|
{
|
|
if (!reg->open)
|
|
continue;
|
|
switch(reg->dyn.addr->acc_meth)
|
|
{
|
|
case dba_mm:
|
|
case dba_bg:
|
|
csa = &FILE_INFO(reg)->s_addrs;
|
|
memset(&csa->gvstats_rec, 0, SIZEOF(gvstats_rec_t));
|
|
break;
|
|
case dba_cm:
|
|
case dba_usr:
|
|
break;
|
|
default:
|
|
GTMASSERT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case VTK_YDIRTVAL:
|
|
/* This is an internal use only call to VIEW which is used to modify directory
|
|
* tree entries. It places a string in in the static array view_ydirt_str. A subsequent
|
|
* view to YDIRTREE causes the value to be put in the directory tree.
|
|
* For example VIEW "YDIRTVAL":$C(55,0,0,0),"YDIRTREE":XYZ would cause global ^XYZ
|
|
* to have a root block of 0x00000055, on a little-endian computer.
|
|
* NOTE: it is easy to corrupt a database with these calls.
|
|
* The use of the "Y" sentinal character indicates that the VIEW keyword is interal
|
|
* FIS use only, and that FIS will not provide upward compatibility to the user.
|
|
* These keywords should NOT be used outside of FIS software
|
|
*/
|
|
if (NULL == TREF(view_ydirt_str))
|
|
TREF(view_ydirt_str) = (char *)malloc(MAX_YDIRTSTR + 1);
|
|
TREF(view_ydirt_str_len) = parmblk.value->str.len;
|
|
if (TREF(view_ydirt_str_len) > MAX_YDIRTSTR)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_YDIRTSZ);
|
|
}
|
|
if (TREF(view_ydirt_str_len) > 0)
|
|
memcpy(TREF(view_ydirt_str), parmblk.value->str.addr, TREF(view_ydirt_str_len));
|
|
break;
|
|
case VTK_YDIRTREE:
|
|
/* See comment under YDIRTVAL above
|
|
* Restriction: This program will update an existing entry in a directory tree but
|
|
* will fail if the entry is not present. So make sure that the global exists before
|
|
* a YDIRTREE update is performed
|
|
*/
|
|
op_gvname(VARLSTCNT(1) parmblk.value);
|
|
assert(INVALID_GV_TARGET == reset_gv_target);
|
|
reset_gv_target = gv_target;
|
|
gv_target = cs_addrs->dir_tree; /* Trick the put program into using the directory tree */
|
|
outval.mvtype = MV_STR;
|
|
outval.str.len = TREF(view_ydirt_str_len);
|
|
outval.str.addr = (char *)TREF(view_ydirt_str);
|
|
op_gvput(&outval);
|
|
RESET_GV_TARGET(DO_GVT_GVKEY_CHECK);
|
|
gv_target->root = 0;
|
|
/* Now that root is set to 0, the next access to this global will go through gvcst_root_search which will
|
|
* re-initialize "nct", "act" and "ver" accordingly and also initialize "collseq" ONLY IF "act" is non-zero.
|
|
* Since we do not know if "act" will be 0 or not in gvcst_root_search, let us reset "collseq" to NULL here.
|
|
*/
|
|
gv_target->collseq = NULL;
|
|
break;
|
|
case VTK_YLCT:
|
|
if (arg)
|
|
lct = MV_FORCE_INT(parmblk.value);
|
|
else
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_REQDVIEWPARM);
|
|
}
|
|
nextarg = NULL;
|
|
ncol = -1;
|
|
if (numarg > 1)
|
|
{
|
|
nextarg = va_arg(var, mval *);
|
|
ncol = MV_FORCE_INT(nextarg);
|
|
}
|
|
if ((-1 == lct) && (-1 == ncol))
|
|
break;
|
|
/* lct = -1 indicates user wants to change only ncol, not lct */
|
|
if (-1 != lct)
|
|
{
|
|
if ((lct < MIN_COLLTYPE) || (lct > MAX_COLLTYPE))
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(3) ERR_ACTRANGE, 1, lct);
|
|
}
|
|
}
|
|
/* at this point, verify that there is no local data with subscripts */
|
|
for (cstab = curr_symval; cstab; cstab = cstab->last_tab)
|
|
{
|
|
assert(cstab->h_symtab.top == cstab->h_symtab.base + cstab->h_symtab.size);
|
|
for (tabent = cstab->h_symtab.base, topent = cstab->h_symtab.top; tabent < topent; tabent++)
|
|
{
|
|
if (HTENT_VALID_MNAME(tabent, lv_val, lv))
|
|
{
|
|
assert(LV_IS_BASE_VAR(lv));
|
|
if (lv && LV_HAS_CHILD(lv))
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_COLLDATAEXISTS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (-1 != lct)
|
|
{
|
|
if (0 != lct)
|
|
{
|
|
new_lcl_collseq = ready_collseq(lct);
|
|
if (0 == new_lcl_collseq)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct);
|
|
}
|
|
TREF(local_collseq) = new_lcl_collseq;
|
|
} else
|
|
{
|
|
TREF(local_collseq) = 0;
|
|
if (NULL != TREF(lcl_coll_xform_buff))
|
|
{
|
|
assert(0 < TREF(max_lcl_coll_xform_bufsiz));
|
|
free(TREF(lcl_coll_xform_buff));
|
|
TREF(lcl_coll_xform_buff) = NULL;
|
|
TREF(max_lcl_coll_xform_bufsiz) = 0;
|
|
}
|
|
}
|
|
}
|
|
if (-1 != ncol)
|
|
TREF(local_collseq_stdnull) = (ncol ? TRUE: FALSE);
|
|
break;
|
|
case VTK_PATLOAD:
|
|
if (!load_pattern_table(parmblk.value->str.len, parmblk.value->str.addr))
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(4) ERR_PATLOAD, 2, parmblk.value->str.len, parmblk.value->str.addr);
|
|
}
|
|
break;
|
|
case VTK_NOUNDEF:
|
|
undef_inhibit = TRUE;
|
|
break;
|
|
case VTK_UNDEF:
|
|
undef_inhibit = FALSE;
|
|
break;
|
|
case VTK_TESTPOINT:
|
|
testvalue = MV_FORCE_INT(parmblk.value);
|
|
set_testpoint(testvalue);
|
|
break;
|
|
case VTK_ZDEFER:
|
|
if (zdefactive)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_ZDEFACTIVE);
|
|
}
|
|
zdefactive = TRUE;
|
|
tmpzdefbufsiz = MV_FORCE_INT(parmblk.value);
|
|
if (1 == tmpzdefbufsiz)
|
|
tmpzdefbufsiz = ZDEFDEF;
|
|
else if (tmpzdefbufsiz < ZDEFMIN)
|
|
tmpzdefbufsiz = ZDEFMIN;
|
|
else if (tmpzdefbufsiz > ZDEFMAX)
|
|
tmpzdefbufsiz = ZDEFMAX;
|
|
zdefbufsiz = (unsigned short)tmpzdefbufsiz;
|
|
break;
|
|
case VTK_ZFLUSH:
|
|
gvcmz_zflush();
|
|
break;
|
|
case VTK_TRACE :
|
|
testvalue = MV_FORCE_INT(parmblk.value);
|
|
if (testvalue)
|
|
{
|
|
if (2 > numarg)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_TRACEON);
|
|
}
|
|
arg = va_arg(var, mval *);
|
|
MV_FORCE_STR(arg);
|
|
turn_tracing_on(arg, FALSE, TRUE);
|
|
} else
|
|
{
|
|
if (2 == numarg)
|
|
{
|
|
arg = va_arg(var, mval *);
|
|
MV_FORCE_STR(arg);
|
|
turn_tracing_off(arg);
|
|
} else
|
|
turn_tracing_off(NULL);
|
|
}
|
|
break;
|
|
case VTK_ZDIR_FORM:
|
|
VMS_ONLY(
|
|
if (NULL != arg)
|
|
{
|
|
testvalue = MV_FORCE_INT(parmblk.value);
|
|
if (!IS_VALID_ZDIR_FORM(testvalue))
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(3) ERR_INVZDIRFORM, 1, testvalue);
|
|
}
|
|
} else
|
|
testvalue = ZDIR_FORM_FULLPATH;
|
|
zdir_form = testvalue;
|
|
)
|
|
break;
|
|
case VTK_FILLFACTOR:
|
|
testvalue = MV_FORCE_INT(parmblk.value);
|
|
if (MAX_FILLFACTOR < testvalue)
|
|
testvalue = MAX_FILLFACTOR;
|
|
else if (MIN_FILLFACTOR > testvalue)
|
|
testvalue = MIN_FILLFACTOR;
|
|
gv_fillfactor = testvalue;
|
|
break;
|
|
case VTK_STPGCOL:
|
|
INVOKE_STP_GCOL(INTCAST(stringpool.top - stringpool.free) + 1);/* computation to avoid assert in stp_gcol */
|
|
break;
|
|
case VTK_LVGCOL:
|
|
als_lvval_gc();
|
|
break;
|
|
case VTK_LVREHASH:
|
|
/* This doesn't actually expand or contract the local variable hash table but does cause it to be
|
|
* rebuilt. Then we need to do the same sort of cleanup that add_hashtab_mname_symval does. */
|
|
/* Step 1: remember table we started with */
|
|
table = &curr_symval->h_symtab;
|
|
table_base_orig = table->base;
|
|
table_size_orig = table->size;
|
|
/* Step 2 - rebuild the local variable hash table */
|
|
/* We'll do the base release once we do the reparations */
|
|
DEFER_BASE_REL_HASHTAB(table, TRUE);
|
|
expand_hashtab_mname(&curr_symval->h_symtab, curr_symval->h_symtab.size);
|
|
/* Step 3 - repair the l_symtab entries on the stack from the rebuilt hash table */
|
|
if (table_base_orig != curr_symval->h_symtab.base)
|
|
{ /* Only needed if expansion was successful */
|
|
als_lsymtab_repair(table, table_base_orig, table_size_orig);
|
|
FREE_BASE_HASHTAB(table, table_base_orig);
|
|
}
|
|
DEFER_BASE_REL_HASHTAB(table, FALSE);
|
|
break;
|
|
case VTK_STORDUMP:
|
|
if (gtmDebugLevel)
|
|
{ /* gtmdbglvl must be non-zero to have hope of printing a storage dump */
|
|
dbgdmpenabled = (GDL_SmDump & gtmDebugLevel);
|
|
gtmDebugLevel |= GDL_SmDump; /* Turn on indicator to force print */
|
|
printMallocDump();
|
|
if (!dbgdmpenabled)
|
|
gtmDebugLevel &= (~GDL_SmDump); /* Shut indicator back off */
|
|
}
|
|
break;
|
|
# ifdef DEBUG_ALIAS
|
|
case VTK_LVMONOUT:
|
|
als_lvmon_output();
|
|
break;
|
|
case VTK_LVMONSTART:
|
|
lvmon_enabled = TRUE; /* Enable lv_val monitoring */
|
|
/* Clear any existing marks on all lv_vals */
|
|
for (lvlsymtab = curr_symval; lvlsymtab; lvlsymtab = lvlsymtab->last_tab)
|
|
{
|
|
for (lvbp = curr_symval->lv_first_block; lvbp; lvbp = lvbp->next)
|
|
{
|
|
for (lvp = (lv_val *)LV_BLK_GET_BASE(lvbp), lvp_top = LV_BLK_GET_FREE(lvbp, lvp);
|
|
lvp < lvp_top; lvp++)
|
|
{
|
|
assert(LV_IS_BASE_VAR(lv));
|
|
lvp->lvmon_mark = FALSE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case VTK_LVMONSTOP:
|
|
als_lvmon_output();
|
|
lvmon_enabled = FALSE;
|
|
break;
|
|
# endif
|
|
default:
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_VIEWCMD);
|
|
}
|
|
va_end(var);
|
|
return;
|
|
}
|