2012-02-05 11:35:58 -05:00
|
|
|
/****************************************************************
|
|
|
|
* *
|
2012-10-29 18:54:31 -04:00
|
|
|
* Copyright 2001, 2012 Fidelity Information Services, Inc *
|
2012-02-05 11:35:58 -05:00
|
|
|
* *
|
|
|
|
* 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_string.h"
|
|
|
|
|
|
|
|
#include "error.h"
|
|
|
|
#include "lv_val.h"
|
|
|
|
#include "subscript.h"
|
2012-10-29 18:54:31 -04:00
|
|
|
#include <rtnhdr.h>
|
2012-02-05 11:35:58 -05:00
|
|
|
#include "mv_stent.h"
|
|
|
|
#include "mlkdef.h"
|
|
|
|
#include "zshow.h"
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "stringpool.h"
|
|
|
|
#include "gdsroot.h"
|
|
|
|
#include "gdsblk.h"
|
|
|
|
#include "gtm_facility.h"
|
|
|
|
#include "fileinfo.h"
|
|
|
|
#include "gdsbt.h"
|
|
|
|
#include "gdsfhead.h"
|
|
|
|
#include "op.h"
|
|
|
|
#include "mvalconv.h"
|
|
|
|
#include "format_targ_key.h"
|
|
|
|
#include "gtm_maxstr.h"
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
#include "gtm_utf8.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define F_SUBSC_LEN 3
|
|
|
|
#define N_SUBSC_LEN 5
|
|
|
|
#define MIN_DATASIZE 40
|
|
|
|
#define ZSHOW_SPACE_INDENT 10 /* # of spaces every following line of zshow output is indented with */
|
|
|
|
|
|
|
|
GBLREF io_pair io_curr_device;
|
|
|
|
GBLREF spdesc stringpool;
|
|
|
|
GBLREF gv_key *gv_currkey;
|
|
|
|
GBLREF gd_region *gv_cur_region;
|
|
|
|
GBLREF mv_stent *mv_chain;
|
|
|
|
GBLREF unsigned char *msp, *stackwarn, *stacktop;
|
|
|
|
GBLREF int process_exiting;
|
|
|
|
|
|
|
|
error_def(ERR_ZSHOWGLOSMALL);
|
|
|
|
error_def(ERR_STACKOFLOW);
|
|
|
|
error_def(ERR_STACKCRIT);
|
|
|
|
error_def(ERR_MAXNRSUBSCRIPTS);
|
|
|
|
|
|
|
|
void zshow_output(zshow_out *out, const mstr *str)
|
|
|
|
{
|
|
|
|
mval *mv, lmv;
|
|
|
|
lv_val *lv, *lv_child;
|
|
|
|
char buff, *strptr, *strnext, *strtop, *strbase, *leadptr;
|
|
|
|
int key_ovrhd, str_processed, n_spaces, sbs_depth, dbg_sbs_depth;
|
|
|
|
ssize_t len, outlen, chcnt, char_len, disp_len ;
|
|
|
|
int buff_len;
|
|
|
|
int device_width, inchar_width, cumul_width;
|
|
|
|
boolean_t is_base_var, lvundef, utf8_active;
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
wint_t codepoint;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (NULL != str)
|
|
|
|
{
|
|
|
|
buff_len = (int)(out->ptr - out->buff);
|
|
|
|
out->size = MAXSTR_BUFF_ALLOC(str->len, out->buff, buff_len);
|
|
|
|
out->ptr = out->buff + buff_len;
|
|
|
|
}
|
2012-10-29 18:54:31 -04:00
|
|
|
if (!process_exiting)
|
|
|
|
{ /* Only if not exiting in case we are called from mdb_condition_handler
|
|
|
|
* with stack overflow */
|
|
|
|
PUSH_MV_STENT(MVST_MVAL);
|
|
|
|
mv = &mv_chain->mv_st_cont.mvs_mval;
|
|
|
|
} else
|
|
|
|
mv = &lmv;
|
|
|
|
mv->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before value gets initialized below */
|
2012-02-05 11:35:58 -05:00
|
|
|
switch (out->type)
|
|
|
|
{
|
|
|
|
case ZSHOW_DEVICE:
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
len = str->len;
|
|
|
|
strptr = str->addr;
|
|
|
|
char_len = UNICODE_ONLY((gtm_utf8_mode) ? (ssize_t)UTF8_LEN_STRICT(strptr, (int)len) :) len;
|
|
|
|
disp_len = UNICODE_ONLY((gtm_utf8_mode) ?
|
|
|
|
(ssize_t)gtm_wcswidth((unsigned char *)strptr, (int)len, FALSE, 1) :) len;
|
|
|
|
str_processed = 0;
|
|
|
|
}
|
|
|
|
device_width = io_curr_device.out->width;
|
|
|
|
/* Do not indent if width is < the indentation length or if remaining width cannot accommodate one character */
|
|
|
|
n_spaces = (device_width > (ZSHOW_SPACE_INDENT UNICODE_ONLY(+ (gtm_utf8_mode ? GTM_MB_DISP_LEN_MAX : 0)))
|
|
|
|
? ZSHOW_SPACE_INDENT : 0);
|
|
|
|
if (str && (disp_len + out->displen > device_width))
|
|
|
|
{
|
|
|
|
for (; (len > 0) && (disp_len + out->displen > device_width); )
|
|
|
|
{
|
|
|
|
assert(len <= out->size - (out->ptr - out->buff));
|
|
|
|
strbase = strptr = str->addr + str_processed;
|
|
|
|
strtop = str->addr + str->len;
|
|
|
|
if (!gtm_utf8_mode)
|
|
|
|
{
|
|
|
|
outlen = device_width - out->len;
|
|
|
|
chcnt = outlen;
|
|
|
|
strptr += outlen;
|
|
|
|
disp_len -= outlen;
|
|
|
|
}
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
else
|
|
|
|
{
|
|
|
|
utf8_active = (CHSET_M != io_curr_device.out->ichset); /* needed by GTM_IO_WCWIDTH macro */
|
|
|
|
cumul_width = out->displen;
|
|
|
|
for (chcnt = 0; chcnt < char_len; ++chcnt)
|
|
|
|
{
|
|
|
|
strnext = (char *)UTF8_MBTOWC(strptr, strtop, codepoint);
|
|
|
|
GTM_IO_WCWIDTH(codepoint, inchar_width);
|
|
|
|
if ((cumul_width + inchar_width) > device_width)
|
|
|
|
break;
|
|
|
|
cumul_width += inchar_width;
|
|
|
|
disp_len -= inchar_width;
|
|
|
|
strptr = strnext;
|
|
|
|
}
|
|
|
|
outlen = (ssize_t)(strptr - strbase);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
memcpy(out->ptr, strbase, outlen);
|
|
|
|
out->ptr += outlen;
|
|
|
|
str_processed += (int)outlen;
|
|
|
|
len = (ssize_t)(strtop - strptr);
|
|
|
|
char_len -= chcnt;
|
|
|
|
assert((UNICODE_ONLY((gtm_utf8_mode) ?
|
|
|
|
(ssize_t)UTF8_LEN_STRICT(strptr, (int)len) :) len) == char_len);
|
|
|
|
mv->str.addr = out->buff;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
op_write(mv);
|
|
|
|
op_wteol(1);
|
|
|
|
out->ptr = out->buff + n_spaces;
|
|
|
|
memset(out->buff, ' ', n_spaces);
|
|
|
|
out->len = n_spaces;
|
|
|
|
out->displen = n_spaces;
|
|
|
|
out->line_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
memcpy(out->ptr, str->addr + str_processed, len);
|
|
|
|
out->ptr += len;
|
|
|
|
out->len += (int)char_len;
|
|
|
|
out->displen += (int)disp_len;
|
|
|
|
}
|
|
|
|
if (out->flush && out->ptr != out->buff)
|
|
|
|
{
|
|
|
|
mv->str.addr = out->buff;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
op_write(mv);
|
|
|
|
op_wteol(1);
|
|
|
|
out->ptr = out->buff;
|
|
|
|
out->len = 0;
|
|
|
|
out->displen = 0;
|
|
|
|
out->line_num++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZSHOW_LOCAL:
|
|
|
|
if (out->code)
|
|
|
|
{
|
|
|
|
if (out->code != out->curr_code)
|
|
|
|
{
|
|
|
|
ENSURE_STP_FREE_SPACE(1);
|
|
|
|
mv->str.addr = (char *)stringpool.free;
|
|
|
|
mv->str.len = 1;
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
*mv->str.addr = out->code;
|
|
|
|
stringpool.free++;
|
|
|
|
lv = out->out_var.lv.lvar;
|
|
|
|
out->out_var.lv.child = lv_child = op_srchindx(VARLSTCNT(2) lv, mv);
|
|
|
|
if (NULL != lv_child)
|
|
|
|
{
|
|
|
|
lvundef = FALSE;
|
|
|
|
if (!LV_IS_VAL_DEFINED(lv))
|
|
|
|
{
|
|
|
|
lv->v.mvtype = MV_STR;
|
|
|
|
lv->v.str.len = 0;
|
|
|
|
lvundef = TRUE;
|
|
|
|
}
|
|
|
|
op_kill(lv_child);
|
|
|
|
if (lvundef)
|
|
|
|
lv->v.mvtype = 0;
|
|
|
|
}
|
|
|
|
/* Check if we can add two more subscripts 1) out->code & 2) out->line_num */
|
|
|
|
is_base_var = LV_IS_BASE_VAR(lv);
|
|
|
|
LV_SBS_DEPTH(lv, is_base_var, sbs_depth);
|
|
|
|
if (MAX_LVSUBSCRIPTS <= (sbs_depth + 2))
|
|
|
|
rts_error(VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS);
|
|
|
|
out->out_var.lv.child = op_putindx(VARLSTCNT(2) lv, mv);
|
|
|
|
DEBUG_ONLY(LV_SBS_DEPTH(out->out_var.lv.child, FALSE, dbg_sbs_depth);)
|
|
|
|
assert(MAX_LVSUBSCRIPTS > (dbg_sbs_depth + 1));
|
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
len = str->len;
|
|
|
|
strptr = str->addr;
|
|
|
|
str_processed = 0;
|
|
|
|
if (str->len + (out->ptr - out->buff) > MAX_SRCLINE)
|
|
|
|
{
|
|
|
|
strtop = str->addr + str->len;
|
|
|
|
lv_child = out->out_var.lv.child;
|
|
|
|
assert(NULL != lv_child);
|
|
|
|
for (; strptr != strtop; )
|
|
|
|
{
|
|
|
|
len = (ssize_t)(strtop - strptr);
|
|
|
|
if (len <= MAX_SRCLINE - (out->ptr - out->buff))
|
|
|
|
break;
|
|
|
|
len = MAX_SRCLINE - (ssize_t)(out->ptr - out->buff);
|
|
|
|
strbase = str->addr + str_processed;
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
if (gtm_utf8_mode)
|
|
|
|
{ /* terminate at the proper character boundary within MAX_SRCLINE bytes */
|
|
|
|
UTF8_LEADING_BYTE(strbase + len, strbase, leadptr);
|
|
|
|
len = (ssize_t)(leadptr - strbase);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
memcpy(out->ptr, strbase, len);
|
|
|
|
strptr += len;
|
|
|
|
out->ptr += len;
|
|
|
|
str_processed += (int)len;
|
|
|
|
mv->str.addr = 0;
|
|
|
|
mv->str.len = 0;
|
|
|
|
MV_FORCE_MVAL(mv, out->line_num);
|
|
|
|
/* It is safe to add the second subscript here since the check for this
|
|
|
|
* is already done in the previous if block (MAX_LVSUBSCRIPTS error)
|
|
|
|
*/
|
|
|
|
DEBUG_ONLY(LV_SBS_DEPTH(lv_child, FALSE, dbg_sbs_depth);)
|
|
|
|
assert(MAX_LVSUBSCRIPTS > (dbg_sbs_depth + 1));
|
|
|
|
lv = op_putindx(VARLSTCNT(2) lv_child, mv);
|
|
|
|
ENSURE_STP_FREE_SPACE((int)(out->ptr - out->buff));
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
mv->str.addr = (char *)stringpool.free;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
|
|
|
|
stringpool.free += mv->str.len;
|
|
|
|
lv->v = *mv;
|
|
|
|
out->ptr = out->buff + 10;
|
|
|
|
memset(out->buff, ' ', 10);
|
|
|
|
out->line_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memcpy(out->ptr, str->addr + str_processed, len);
|
|
|
|
out->ptr += len;
|
|
|
|
}
|
|
|
|
if (out->flush && (out->ptr != out->buff))
|
|
|
|
{
|
|
|
|
mv->str.addr = 0;
|
|
|
|
mv->str.len = 0;
|
|
|
|
MV_FORCE_MVAL(mv, out->line_num);
|
|
|
|
/* Check for if it is ok to add this second subscript is already done above (MAX_LVSUBSCRIPTS) */
|
|
|
|
lv_child = out->out_var.lv.child;
|
|
|
|
assert(NULL != lv_child);
|
|
|
|
DEBUG_ONLY(LV_SBS_DEPTH(lv_child, FALSE, dbg_sbs_depth);)
|
|
|
|
assert(MAX_LVSUBSCRIPTS > (dbg_sbs_depth + 1));
|
|
|
|
lv = op_putindx(VARLSTCNT(2) lv_child, mv);
|
|
|
|
ENSURE_STP_FREE_SPACE((int)(out->ptr - out->buff));
|
|
|
|
mv->str.addr = (char *)stringpool.free;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
|
|
|
|
stringpool.free += mv->str.len;
|
|
|
|
lv->v = *mv;
|
|
|
|
out->ptr = out->buff;
|
|
|
|
out->line_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZSHOW_GLOBAL:
|
|
|
|
if (!out->len)
|
|
|
|
{
|
|
|
|
key_ovrhd = gv_currkey->end + 1 + F_SUBSC_LEN + N_SUBSC_LEN;
|
|
|
|
out->len = (int)(gv_cur_region->max_rec_size - key_ovrhd - SIZEOF(rec_hdr));
|
|
|
|
if (out->len < MIN_DATASIZE)
|
|
|
|
rts_error(VARLSTCNT(1) ERR_ZSHOWGLOSMALL);
|
|
|
|
}
|
|
|
|
if (out->code && out->code != out->curr_code)
|
|
|
|
{
|
|
|
|
gv_currkey->end = out->out_var.gv.end;
|
|
|
|
gv_currkey->prev = out->out_var.gv.prev;
|
|
|
|
gv_currkey->base[gv_currkey->end] = 0;
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
mv->str.len = 1;
|
|
|
|
mv->str.addr = &buff;
|
|
|
|
*mv->str.addr = out->code;
|
|
|
|
mval2subsc(mv, gv_currkey);
|
|
|
|
if (gv_currkey->end >= gv_cur_region->max_key_size)
|
|
|
|
ISSUE_GVSUBOFLOW_ERROR(gv_currkey);
|
|
|
|
op_gvkill();
|
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
len = str->len;
|
|
|
|
strptr = str->addr;
|
|
|
|
str_processed = 0;
|
|
|
|
}
|
|
|
|
if (str && ((int)str->len + (out->ptr - out->buff) > out->len))
|
|
|
|
{
|
|
|
|
strtop = str->addr + str->len;
|
|
|
|
for (; strptr != strtop; )
|
|
|
|
{
|
|
|
|
len = (ssize_t)(strtop - strptr);
|
|
|
|
if (len <= out->len - (out->ptr - out->buff))
|
|
|
|
break;
|
|
|
|
len = out->len - (ssize_t)(out->ptr - out->buff);
|
|
|
|
strbase = str->addr + str_processed;
|
|
|
|
#ifdef UNICODE_SUPPORTED
|
|
|
|
if (gtm_utf8_mode)
|
|
|
|
{ /* terminate at the proper character boundary within out->len bytes */
|
|
|
|
UTF8_LEADING_BYTE(strbase + len, strbase, leadptr);
|
|
|
|
len = (ssize_t)(leadptr - strbase);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
memcpy(out->ptr, strbase, len);
|
|
|
|
strptr += len;
|
|
|
|
out->ptr += len;
|
|
|
|
str_processed += (int)len;
|
|
|
|
MV_FORCE_MVAL(mv, out->line_num);
|
|
|
|
if (FIRST_LINE_OF_ZSHOW_OUTPUT(out))
|
|
|
|
op_gvnaked(VARLSTCNT(1) mv);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mval2subsc(mv, gv_currkey);
|
|
|
|
if (gv_currkey->end >= gv_cur_region->max_key_size)
|
|
|
|
ISSUE_GVSUBOFLOW_ERROR(gv_currkey);
|
|
|
|
}
|
|
|
|
ENSURE_STP_FREE_SPACE((int)(out->ptr - out->buff));
|
|
|
|
mv->str.addr = (char *)stringpool.free;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
|
|
|
|
stringpool.free += mv->str.len;
|
|
|
|
op_gvput(mv);
|
|
|
|
out->ptr = out->buff + 10;
|
|
|
|
memset(out->buff, ' ', 10);
|
|
|
|
out->line_num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (str)
|
|
|
|
{
|
|
|
|
memcpy(out->ptr, str->addr + str_processed, len);
|
|
|
|
out->ptr += len;
|
|
|
|
}
|
|
|
|
if (out->flush && out->ptr != out->buff)
|
|
|
|
{
|
|
|
|
MV_FORCE_MVAL(mv, out->line_num);
|
|
|
|
if (FIRST_LINE_OF_ZSHOW_OUTPUT(out))
|
|
|
|
op_gvnaked(VARLSTCNT(1) mv);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mval2subsc(mv, gv_currkey);
|
|
|
|
if (gv_currkey->end >= gv_cur_region->max_key_size)
|
|
|
|
ISSUE_GVSUBOFLOW_ERROR(gv_currkey);
|
|
|
|
}
|
|
|
|
ENSURE_STP_FREE_SPACE((int)(out->ptr - out->buff));
|
|
|
|
mv->str.addr = (char *)stringpool.free;
|
|
|
|
mv->str.len = INTCAST(out->ptr - out->buff);
|
|
|
|
mv->mvtype = MV_STR;
|
|
|
|
memcpy(mv->str.addr, &out->buff[0], mv->str.len);
|
|
|
|
stringpool.free += mv->str.len;
|
|
|
|
op_gvput(mv);
|
|
|
|
out->ptr = out->buff;
|
|
|
|
out->line_num++;
|
|
|
|
}
|
2012-10-29 18:54:31 -04:00
|
|
|
break;
|
|
|
|
case ZSHOW_BUFF_ONLY:
|
|
|
|
/* This code is meant to print to a buffer so it DOES NOT bother setting the other fields of output.
|
|
|
|
* Only beginning and ending pointers because those are the only fields we need
|
|
|
|
*/
|
|
|
|
if (str)
|
2012-02-05 11:35:58 -05:00
|
|
|
{
|
2012-10-29 18:54:31 -04:00
|
|
|
len = str->len;
|
|
|
|
strptr = str->addr;
|
|
|
|
memcpy(out->ptr, str->addr, len);
|
|
|
|
out->ptr += len;
|
2012-02-05 11:35:58 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GTMASSERT;
|
|
|
|
break;
|
|
|
|
}
|
2012-10-29 18:54:31 -04:00
|
|
|
if (!process_exiting)
|
|
|
|
{
|
|
|
|
POP_MV_STENT();
|
|
|
|
}
|
2012-02-05 11:35:58 -05:00
|
|
|
out->curr_code = out->code;
|
|
|
|
out->flush = 0;
|
|
|
|
}
|