Example #1
0
int op_readfl(mval *v, int4 length, int4 timeout)
{
	int4		stat;		/* status */
	size_t		cnt, insize, outsize;
	char		*start_ptr, *save_ptr;
	unsigned char	*temp_ch;
	int		b_length;

	if (timeout < 0)
		timeout = 0;
	/* Length is in units of characters, MAX_STRLEN and allocation unit in stp is bytes. Compute the worst case need in bytes.
	 * Worst case, every Unicode char is 4 bytes
	 */
	b_length = (!IS_UTF_CHSET(io_curr_device.in->ichset)) ? length : (length * 4);
	if (0 >= length)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RDFLTOOSHORT);
	/* This check is more useful in "M" mode. For UTF-8 mode, checks have to be done while reading */
	if (MAX_STRLEN < length)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RDFLTOOLONG);
	assert(stringpool.free >= stringpool.base);
	assert(stringpool.free <= stringpool.top);
	v->mvtype = MV_STR;
	v->str.len = 0;		/* Nothing kept from any old value */
	ENSURE_STP_FREE_SPACE(b_length + ESC_LEN);
	v->str.addr = (char *)stringpool.free;
	active_device = io_curr_device.in;
	stat = (io_curr_device.in->disp_ptr->readfl)(v, length, timeout);
	if (IS_AT_END_OF_STRINGPOOL(v->str.addr, 0))
		stringpool.free += v->str.len;	/* see UNIX iott_readfl */
	assert((int4)v->str.len <= b_length);
	assert(stringpool.free <= stringpool.top);
#	if defined(KEEP_zOS_EBCDIC) || defined(VMS)
	if (DEFAULT_CODE_SET != active_device->in_code_set)
	{
		cnt = insize = outsize = v->str.len;
		assert(stringpool.free >= stringpool.base);
		ENSURE_STP_FREE_SPACE(cnt);
		temp_ch = stringpool.free;
		save_ptr = v->str.addr;
		start_ptr = (char *)temp_ch;
		stringpool.free += cnt;
		assert(stringpool.free >= stringpool.base);
		assert(stringpool.free <= stringpool.top);
		ICONVERT(active_device->input_conv_cd, (unsigned char **)&(v->str.addr), &insize, &temp_ch, &outsize);
		v->str.addr = start_ptr;
	}
#	endif
	active_device = 0;
	if (NO_M_TIMEOUT != timeout)
		return (stat);
	return FALSE;
}
Example #2
0
void gvcmx_unlock(unsigned char rmv_locks, bool specific, char incr)
{
	struct CLB	*p;
	unsigned char	operation1,operation2,*ptr;

	if (!ntd_root || !ntd_root->cqh.fl || (specific && !remlkreq))
		return;

	if (rmv_locks == CM_ZALLOCATES)
	{
		operation1 = CM_ZALLOCATES;
		operation2 = REMOTE_ZALLOCATES;
	} else
	{
		operation1 = CM_LOCKS;
		operation2 = REMOTE_LOCKS;
	}
	operation1 |= incr;
	for (p = (struct CLB *)RELQUE2PTR(ntd_root->cqh.fl); p != (struct CLB *)ntd_root; p = (struct CLB *)RELQUE2PTR(p->cqe.fl))
	{
		p->ast = 0;
		ENSURE_STP_FREE_SPACE(p->mbl);
		p->mbf = stringpool.free;
		if (remlkreq)
		{
			if (((link_info*)(p->usr))->lck_info & REQUEST_PENDING)
				gvcmz_sndlkremove(p, operation1, CMMS_L_LKDELETE);
		} else if (((link_info*)(p->usr))->lck_info & (REMOTE_LOCKS | REMOTE_ZALLOCATES))
		{
			gvcmz_sndlkremove(p, operation1, CMMS_L_LKCANALL);
			((link_info*)(p->usr))->lck_info &= ~operation2;
		}
	}
}
Example #3
0
/* This function does the bulk of the conversion for i82mval and ui82mval. The primary routines set the sgn flag and pass the
 * absolute value to xi82mval(). In the case of a >18 digit number, xi82mval() examines the sgn flag to determine whether to
 * switch back to a signed value before string conversion.
 */
void xi82mval(mval *v, gtm_uint64_t i)
{
	int	exp;
	uint4	low;
	uint4	high;
	char    buf[21];	/* [possible] sign, [up to] 19L/20UL digits, and terminator. */
	int	len;

	if (i < INT_HI)
	{
		v->mvtype |= MV_INT;
		v->m[1] = MV_BIAS * (v->sgn ? -(int4)i : (uint4)i);
	} else
	{
		if (i < MANT_HI)
		{
			low = 0;
			high = i;
			exp = EXP_IDX_BIAL;
			while (high < MANT_LO)
			{
				high *= 10;
				exp--;
			}
			v->e = exp;
			v->m[0] = low;
			v->m[1] = high;
		} else if (i < (gtm_uint64_t)MANT_HI * MANT_HI)
		{
			low = i % MANT_HI;
			high = i / MANT_HI;
			exp = EXP_IDX_BIAL + 9;
			while (high < MANT_LO)
			{
				high = (high * 10) + (low / MANT_LO);
				low = (low % MANT_LO) * 10;
				exp--;
			}
			v->e = exp;
			v->m[0] = low;
			v->m[1] = high;
		} else
		{	/* The value won't fit in 18 digits, so return a string. */
			if (v->sgn)
				len = SPRINTF(buf, "%lld", -(gtm_int64_t)i);
			else
				len = SPRINTF(buf, "%llu", i);
			assert(18 < len);
			ENSURE_STP_FREE_SPACE(len);
			memcpy(stringpool.free, buf, len);
			v->mvtype = MV_STR;
			v->str.len = len;
			v->str.addr = (char *)stringpool.free;
			stringpool.free += len;
		}
		assert((v->mvtype != MV_NM) || (v->m[1] < MANT_HI));
		assert((v->mvtype != MV_NM) || (v->m[1] >= MANT_LO));
	}
}
Example #4
0
int gtm_conv(UConverter* from, UConverter* to, mstr *src, char* dstbuff, int* bufflen)
{
	char		*dstptr, *dstbase, *srcptr;
	const char	*ichset;
	int		dstlen, src_charlen, srclen;
	UErrorCode	status, status1;

	if (0 == src->len)
		return 0;
	if (NULL == dstbuff)
	{
		/* Compute the stringpool buffer space needed for conversion given that source
		 * is encoded in the ichset representation.  The ICU functions ucnv_getMinCharSize()
		 * and ucnv_getMaxCharSize() are used to compute the minimum and maximum number of
		 * bytes required per UChar if converted from/to ichset/ochset respectively
		 */
		src_charlen = (src->len / ucnv_getMinCharSize(from)) + 1; /* number of UChar's from ichset */
		dstlen = UCNV_GET_MAX_BYTES_FOR_STRING(src_charlen, ucnv_getMaxCharSize(to));
		dstlen = (dstlen > MAX_STRLEN) ? MAX_STRLEN : dstlen;
		ENSURE_STP_FREE_SPACE(dstlen);
		dstbase = (char *)stringpool.free;
	} else
	{
		dstbase = dstbuff;
		dstlen = *bufflen;
	}
	srcptr = src->addr;
	srclen = (int)src->len;
	dstptr = dstbase;
	status = U_ZERO_ERROR; /* initialization to "success" is required by ICU */
	ucnv_convertEx(to, from, &dstptr, dstptr + dstlen, (const char**)&srcptr, srcptr + srclen,
		NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
	if (U_FAILURE(status))
	{
		if (U_BUFFER_OVERFLOW_ERROR == status)
		{	/* translation requires more space than the maximum allowed GT.M string size */
			if (NULL == dstbuff)
				rts_error_csa(NULL, VARLSTCNT(1) ERR_MAXSTRLEN);
			else
			{
				/* Insufficient buffer passed. Return the required buffer length */
				src_charlen = (srclen / ucnv_getMinCharSize(from)) + 1;
				*bufflen = UCNV_GET_MAX_BYTES_FOR_STRING(src_charlen, ucnv_getMaxCharSize(to));
				return -1;
			}
		}
		status1 = U_ZERO_ERROR;
		ichset = ucnv_getName(from, &status1);
		assert(U_SUCCESS(status1));
		UTF8_BADCHAR(1,(unsigned char *) (srcptr - 1), NULL,STRLEN(ichset), ichset);
	}
	return (int) (dstptr - dstbase);
}
Example #5
0
void fgn_glopref(mval *v)
{
	unsigned char *p;

	ENSURE_STP_FREE_SPACE(v->str.len + 1);
	p = stringpool.free;
	*stringpool.free++ = '^';
	memcpy(stringpool.free,v->str.addr,v->str.len);
	stringpool.free += v->str.len ;
	v->str.addr = (char *)p;
	v->str.len++;
}
Example #6
0
oprtype put_str(char *pt, mstr_len_t n)
{
    mval p;

    ENSURE_STP_FREE_SPACE(n);
    memcpy(stringpool.free, pt, n);
    memset(&p, 0, SIZEOF(mval));
    p.mvtype = MV_STR;
    p.str.len = n;
    p.str.addr = (char *) stringpool.free;
    stringpool.free += n;
    /* The line below should be removed as part of GTM-8540; but I can't find a negative test case */
    s2n(&p);
    return put_lit(&p);
}
Example #7
0
void op_fnzbitxor(mval *dst, mval *bitstr1, mval *bitstr2)
{
	int 		n, str_len1, str_len2, new_str_len;
	unsigned char	*byte_1, *byte_n;
	unsigned char	*byte1_1, *byte1_n, byte1_len;
	unsigned char	*byte2_1, *byte2_n, byte2_len;

	error_def(ERR_INVBITSTR);

	MV_FORCE_STR(bitstr1);
	MV_FORCE_STR(bitstr2);

	if (!bitstr1->str.len || !bitstr2->str.len)
		rts_error(VARLSTCNT(1) ERR_INVBITSTR);

	byte1_len = *(unsigned char *)bitstr1->str.addr;
	str_len1 = (bitstr1->str.len - 1) * 8;
	if (7 < byte1_len)
		rts_error(VARLSTCNT(1) ERR_INVBITSTR);

	byte2_len = *(unsigned char *)bitstr2->str.addr;
	str_len2 = (bitstr2->str.len -1) * 8;
	if (7 < byte2_len)
		rts_error(VARLSTCNT(1) ERR_INVBITSTR);

	if (str_len1 - byte1_len > str_len2 - byte2_len)
		new_str_len = str_len2 - byte2_len;
	else
		new_str_len = str_len1 - byte1_len;
	n = (new_str_len + 7)/8 ;
	ENSURE_STP_FREE_SPACE(n + 1);
	byte_1 = (unsigned char *)stringpool.free;
	*byte_1 = n * 8 - new_str_len;
	byte1_1 = (unsigned char *)bitstr1->str.addr;
	byte2_1 = (unsigned char *)bitstr2->str.addr;

	for(byte_n = byte_1 + 1, byte1_n = byte1_1 + 1, byte2_n = byte2_1 + 1 ;
		 byte_n <= (byte_1 + n); byte_n++, byte1_n++, byte2_n++)
	{
		*byte_n = *byte1_n ^ *byte2_n;
	}

	*--byte_n &= mask[*byte_1];
	dst->mvtype = MV_STR;
	dst->str.addr = (char *)stringpool.free;
	dst->str.len = n + 1;
	stringpool.free += n + 1;
}
Example #8
0
void
s2pool(mstr *a)
{
    GBLREF spdesc stringpool;
    int al;

    if ((al = a->len) == 0)
        return;
    assert(stringpool.free >= stringpool.base);
    assert(stringpool.free <= stringpool.top);
    ENSURE_STP_FREE_SPACE(al);
    memcpy(stringpool.free,a->addr,al);
    a->addr = (char *)stringpool.free;
    stringpool.free += al;
    assert(stringpool.free >= stringpool.base);
    assert(stringpool.free <= stringpool.top);
}
Example #9
0
/* WARNING!!! - the it is left to the caller of this routine to protect the stringpool if appropriate */
void mval_lex(mval *v, mstr *output)
{
	int space_needed, des_len;

	MV_FORCE_STR(v);
	if (MV_IS_CANONICAL(v))
		*output = v->str;
	else
	{
		space_needed = ZWR_EXP_RATIO(v->str.len);
		ENSURE_STP_FREE_SPACE(space_needed);
		output->addr = (char *)stringpool.free;
		format2zwr((sm_uc_ptr_t)v->str.addr, v->str.len, (unsigned char *)output->addr, &des_len);
		output->len = des_len; /* need a temporary des_len since output->len is short on the VAX
					* and format2zwr expects an (int *) as the last parameter */
		assert(space_needed >= output->len);
	}
}
Example #10
0
oprtype make_gvsubsc(mval *v)
{
	mval	w;
	gv_key	*gp;

	ENSURE_STP_FREE_SPACE(MAX_SRCLINE + SIZEOF(gv_key));
	if ((INTPTR_T)stringpool.free & 1)
		stringpool.free++;	/* word align key for structure refs */
	gp = (gv_key *) stringpool.free;
	gp->top = MAX_SRCLINE;
	gp->end = gp->prev = 0;
	mval2subsc(v,gp);
	w.mvtype = MV_STR | MV_SUBLIT;
	w.str.addr = (char *) gp->base;
	w.str.len = gp->end + 1;
	stringpool.free = &gp->base[gp->end + 1];
	assert(stringpool.free <= stringpool.top);
	return put_lit(&w);
}
Example #11
0
void op_write(mval *v)
{
	GBLREF spdesc stringpool;
	size_t insize, outsize;
	int cnt;
	unsigned char *temp_ch;
	char *start_ptr, *save_ptr;

	MV_FORCE_STR(v);
	active_device = io_curr_device.out;

#if defined(KEEP_zOS_EBCDIC) || defined(VMS)
	if (DEFAULT_CODE_SET != active_device->out_code_set)
	{
		cnt = insize = outsize = v->str.len;
		assert(stringpool.free >= stringpool.base);
		assert(stringpool.free <= stringpool.top);
		ENSURE_STP_FREE_SPACE(cnt);
		temp_ch = stringpool.free;

		save_ptr = v->str.addr;
		start_ptr = (char *)temp_ch;
		stringpool.free += cnt;
		assert(stringpool.free >= stringpool.base);
		assert(stringpool.free <= stringpool.top);

		ICONVERT(active_device->output_conv_cd, (unsigned char **)&v->str.addr, &insize, &temp_ch, &outsize);

		v->str.addr = start_ptr;
	}
#endif

	(io_curr_device.out->disp_ptr->write)(&v->str);

#if defined(KEEP_zOS_EBCDIC) || defined(VMS)
	if (DEFAULT_CODE_SET != active_device->out_code_set)
		v->str.addr = save_ptr;
#endif

	active_device = 0;
	return;
}
Example #12
0
void get_reference(mval *var)
{
	char	*end, *start;
	char	extnamdelim[] = "^|\"\"|";
	char	*extnamsrc, *extnamtop;
	int	maxlen;

	/* you need to return a double-quote for every single-quote. assume worst case. */
	maxlen = MAX_ZWR_KEY_SZ + (!extnam_str.len ? 0 : ((extnam_str.len * 2) + SIZEOF(extnamdelim)));
	ENSURE_STP_FREE_SPACE(maxlen);
	var->mvtype = MV_STR;
	start = var->str.addr = (char *)stringpool.free;
	var->str.len = 0;
	if (gv_currkey && gv_currkey->end)
	{
		if (extnam_str.len)
		{
			*start++ = extnamdelim[0];
			*start++ = extnamdelim[1];
			*start++ = extnamdelim[2];
			extnamsrc = &extnam_str.addr[0];
			extnamtop = extnamsrc + extnam_str.len;
			for ( ; extnamsrc < extnamtop; )
			{
				*start++ = *extnamsrc;
				if ('"' == *extnamsrc++)	/* caution : pointer increment side-effect */
					*start++ = '"';
			}
			*start++ = extnamdelim[3];
		}
		end = (char *)format_targ_key((unsigned char *)start, MAX_ZWR_KEY_SZ, gv_currkey, TRUE);
		if (extnam_str.len)
			/* Note: the next vertical bar overwrites the caret that
			 * was part of he original name of the global variable
			 */
			*start = extnamdelim[4];
		var->str.len = INTCAST(end - var->str.addr);
		stringpool.free += var->str.len;
	}
}
Example #13
0
int op_read(mval *v, int4 timeout)
{
	int stat;
	mval val;
	size_t cnt, insize, outsize;
	unsigned char *temp_ch;
	char *start_ptr, *save_ptr;
	error_def(ERR_TEXT);

	if (timeout < 0)
		timeout = 0;
	active_device = io_curr_device.in;
	v->mvtype = MV_STR;
	v->str.len = 0;
	stat = (io_curr_device.in->disp_ptr->read)(v, timeout);
	if (stringpool.free == (unsigned char *)v->str.addr)
		stringpool.free += v->str.len;	/* see UNIX iott_readfl */
	assert(stringpool.free <= stringpool.top);
#ifdef KEEP_zOS_EBCDIC
	if (DEFAULT_CODE_SET != io_curr_device.in->in_code_set)
	{
		cnt = insize = outsize = v->str.len;
		assert(stringpool.free >= stringpool.base);
		ENSURE_STP_FREE_SPACE(cnt);
		temp_ch = stringpool.free;
		save_ptr = v->str.addr;
		start_ptr = (char *)temp_ch;
		stringpool.free += cnt;
		assert(stringpool.free >= stringpool.base);
		assert(stringpool.free <= stringpool.top);
		ICONVERT(io_curr_device.in->input_conv_cd, (unsigned char **)&v->str.addr, &insize, &temp_ch, &outsize);
		v->str.addr = start_ptr;
	}
#endif
	active_device = 0;
	if (NO_M_TIMEOUT != timeout)
		return(stat);
	return FALSE;
}
Example #14
0
/* This function is the equivalent of invoking gvcst_data & gvcst_get at the same time.
 * One crucial difference is that this function does NOT handle restarts by automatically invoking t_retry.
 * Instead, it returns the restart code to the caller so that it can handle the restart accordingly.
 * This is important in the case of triggers because we do NOT want to call t_retry in case of a implicit tstart
 * wrapped gvcst_put or gvcst_kill trigger-invoking update transaction. Additionally, this function assumes
 * that it is called always inside of TP (i.e. dollar_tlevel is non-zero).
 */
enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val)
{
	blk_hdr_ptr_t	bp;
	boolean_t	do_rtsib;
	enum cdb_sc	status;
	mint		dlr_data;
	rec_hdr_ptr_t	rp;
	unsigned short	match, rsiz;
	srch_blk_status *bh;
	srch_hist	*rt_history;
	sm_uc_ptr_t	b_top;
	int		key_size, data_len;
	uint4		save_t_err;

	error_def(ERR_GVDATAGETFAIL);
	error_def(ERR_GVKILLFAIL);

	/* The following code is lifted from gvcst_data. Any changes here might need to be reflected there as well */
	assert(dollar_tlevel);
	assert((CDB_STAGNATE > t_tries) || cs_addrs->now_crit);	/* we better hold crit in the final retry (TP & non-TP) */
	save_t_err = t_err;
	assert(ERR_GVKILLFAIL == save_t_err);	/* this function should currently be called only from gvcst_kill */
	t_err = ERR_GVDATAGETFAIL;	/* switch t_err to reflect dataget sub-operation (under the KILL operation) */
	/* In case of a failure return, it is ok to return with t_err set to ERR_GVDATAGETFAIL as that gives a better
	 * picture of exactly where in the transaction the failure occurred.
	 */
	rt_history = gv_target->alt_hist;
	rt_history->h[0].blk_num = 0;
	if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL)))
		return status;
	bh = gv_target->hist.h;
	bp = (blk_hdr_ptr_t)bh->buffaddr;
	rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset);
	b_top = bh->buffaddr + bp->bsiz;
	match = bh->curr_rec.match;
	key_size = gv_currkey->end + 1;
	do_rtsib = FALSE;
	/* Even if key does not exist, return null string in "val". Caller can use dollar_data to distinguish
	 * whether the key is undefined or defined and set to the null string.
	 */
	val->mvtype = MV_STR;
	val->str.len = 0;
	if (key_size == match)
	{
		dlr_data = 1;
		/* the following code is lifted from gvcst_get. any changes here might need to be reflected there as well */
		GET_USHORT(rsiz, &rp->rsiz);
		data_len = rsiz + rp->cmpc - SIZEOF(rec_hdr) - key_size;
		if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top))
		{
			assert(CDB_STAGNATE > t_tries);
			status = cdb_sc_rmisalign1;
			return status;
		} else
		{
			ENSURE_STP_FREE_SPACE(data_len);
			memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len);
			val->str.addr = (char *)stringpool.free;
			val->str.len = data_len;
			stringpool.free += data_len;
		}
		/* --------------------- end code lifted from gvcst_get ---------------------------- */
		rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rsiz);
		if ((sm_uc_ptr_t)rp > b_top)
		{
			status = cdb_sc_rmisalign;
			return status;
		} else if ((sm_uc_ptr_t)rp == b_top)
			do_rtsib = TRUE;
		else if (rp->cmpc >= gv_currkey->end)
			dlr_data += 10;
	} else if (match >= gv_currkey->end)
		dlr_data = 10;
	else
	{
		dlr_data = 0;
		if (rp == (rec_hdr_ptr_t)b_top)
			do_rtsib = TRUE;
	}
	if (do_rtsib && (cdb_sc_endtree != (status = gvcst_rtsib(rt_history, 0))))
	{
		if ((cdb_sc_normal != status) || (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, rt_history->h))))
			return status;
		if (rt_history->h[0].curr_rec.match >= gv_currkey->end)
		{
			assert(1 >= dlr_data);
			dlr_data += 10;
		}
	}
	status = tp_hist(0 == rt_history->h[0].blk_num ? NULL : rt_history);
	if (cdb_sc_normal != status)
		return status;
	*dollar_data = dlr_data;
	t_err = save_t_err;	/* restore t_err to what it was at function entry */
	return status;
}
Example #15
0
unsigned char *n2s(mval *mv_ptr)
{
	unsigned char	*start, *cp, *cp1;
	int4		exp, n0, m1, m0, tmp;
	unsigned char	lcl_buf[MAX_DIGITS_IN_INT];

	if (!MV_DEFINED(mv_ptr))
		GTMASSERT;
	ENSURE_STP_FREE_SPACE(MAX_NUM_SIZE);
	start = stringpool.free;
	cp = start;
	m1 = mv_ptr->m[1];
	if (m1 == 0)	/* SHOULD THIS BE UNDER THE MV_INT TEST? */
		*cp++ = '0';
	else  if (mv_ptr->mvtype & MV_INT)
	{
		if (m1 < 0)
		{
			*cp++ = '-';
			m1 = -m1;
		}
		cp1 = ARRAYTOP(lcl_buf);
		/* m0 is the integer part */
		m0 = m1 / MV_BIAS;
		/* m1 will become the fractional part */
		m1 = m1 - (m0 * MV_BIAS);
		if (m1 > 0)
		{
			for (n0 = 0;  n0 < MV_BIAS_PWR;  n0++)
			{
				tmp = m1;
				m1 /= 10;
				tmp -= (m1 * 10);
				if (tmp)
					break;
			}
			*--cp1 = tmp + '0';
			for (n0++;  n0 < MV_BIAS_PWR;  n0++)
			{
				tmp = m1;
				m1 /= 10;
				*--cp1 = tmp - (m1 * 10) + '0';
			}
			*--cp1 = '.';
		}
		while (m0 > 0)
		{
			tmp = m0;
			m0 /= 10;
			*--cp1 = tmp - (m0 * 10) + '0';
		}
		n0 = (int4)(ARRAYTOP(lcl_buf) - cp1);
		memcpy(cp, cp1, n0);
		cp += n0;
	} else
	{
		exp = (int4)mv_ptr->e - MV_XBIAS;
		if (mv_ptr->sgn)
			*cp++ = '-';
		m0 = mv_ptr->m[0];
		if (exp < 0)
		{
			*cp++ = '.';
			for (n0 = exp;  n0 < 0;  n0++)
				*cp++ = '0';
		}
		for (;  m1;  m1 = m0, m0 = 0)
		{
			for (n0 = 0;  n0 < PACKED_DIGITS;  n0++)
			{
				if (exp-- == 0)
				{
					if (m0 == 0 && m1 == 0)
						break;
					*cp++ = '.';
				} else  if (exp < 0 && m0 == 0 && m1 == 0)
					break;
				tmp = m1 / MANT_LO;
				m1 = (m1 - tmp * MANT_LO) * 10;
				*cp++ = tmp + '0';
			}
		}
		while (exp-- > 0)
			*cp++ = '0';
	}
	mv_ptr->mvtype |= MV_STR;
	mv_ptr->mvtype &= ~MV_NUM_APPROX;
	mv_ptr->str.addr = (char *)start;
	NON_UNICODE_ONLY(mv_ptr->str.len = cp - start);
#ifdef UNICODE_SUPPORTED
	/* Numerics are not unicode so cheaply set "unicode" length same as ascii length */
	mv_ptr->str.len = mv_ptr->str.char_len = INTCAST(cp - start);
	mv_ptr->mvtype |= MV_UTF_LEN;
#endif
	stringpool.free = cp;
	assert(mv_ptr->str.len);
	return cp;
}
Example #16
0
int f_char(oprtype *a, opctype op)
{
	boolean_t 	all_lits;
	unsigned char 	*base, *outptr, *tmpptr;
	int 		argc, ch, char_len, size;
	mval		v;
	oprtype 	*argp, argv[CHARMAXARGS];
	triple 		*curr, *last, *root;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	/* If we are not in UTF8 mode, we need to reroute to the $ZCHAR function to handle things correctly */
	if (!gtm_utf8_mode)
		return f_zchar(a, op);
	all_lits = TRUE;
	argp = &argv[0];
	argc = 0;
	for (;;)
	{
		if (EXPR_FAIL == expr(argp, MUMPS_INT))
			return FALSE;
		assert(TRIP_REF == argp->oprclass);
		if (OC_ILIT != argp->oprval.tref->opcode)
			all_lits = FALSE;
		argc++;
		argp++;
		if (TK_COMMA != TREF(window_token))
			break;
		advancewindow();
		if (CHARMAXARGS <= argc)
		{
			stx_error(ERR_FCHARMAXARGS);
			return FALSE;
		}
	}
	if (all_lits)
	{	/* All literals, build the function inline */
		size = argc * GTM_MB_LEN_MAX;
		ENSURE_STP_FREE_SPACE(size);
		base = stringpool.free;
		argp = &argv[0];
		for (outptr = base, char_len = 0; argc > 0; --argc, argp++)
		{	/* For each wide char value, convert to unicode chars in stringpool buffer */
			ch = argp->oprval.tref->operand[0].oprval.ilit;
			if (0 <= ch)
			{ /* As per the M standard, negative code points should map to no characters */
				tmpptr = UTF8_WCTOMB(ch, outptr);
				assert(tmpptr - outptr <= 4);
				if (tmpptr != outptr)
					++char_len; /* yet another valid character. update the character length */
				else if (!badchar_inhibit)
					stx_error(ERR_INVDLRCVAL, 1, ch);
				outptr = tmpptr;
			}
		}
		stringpool.free = outptr;
		MV_INIT_STRING(&v, outptr - base, base);
		v.str.char_len = char_len;
		v.mvtype |= MV_UTF_LEN;
		CLEAR_MVAL_BITS(&v);
		s2n(&v);
		*a = put_lit(&v);
		return TRUE;
	}
	root = maketriple(op);
	root->operand[0] = put_ilit(argc + 1);
	last = root;
	argp = &argv[0];
	for (; argc > 0 ;argc--, argp++)
	{
		curr = newtriple(OC_PARAMETER);
		curr->operand[0] = *argp;
		last->operand[1] = put_tref(curr);
		last = curr;
	}
	ins_triple(root);
	*a = put_tref(root);
	return TRUE;
}
Example #17
0
void op_fnj3(mval *src,int width,int fract,mval *dst)
{
	int4 n, n1, m;
	int w, digs, digs_used;
	int sign;
	static readonly int4 fives_table[9] =
	{ 500000000, 50000000, 5000000, 500000, 50000, 5000, 500, 50, 5};
	unsigned char *cp;
	error_def(ERR_JUSTFRACT);
	error_def(ERR_MAXSTRLEN);

	if (width < 0)
		width = 0;
	else	if (width > MAX_STRLEN)
			rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
	if (fract < 0)
		rts_error(VARLSTCNT(1) ERR_JUSTFRACT);
	w = width + MAX_NUM_SIZE + 2 + fract;
	/* the literal two above accounts for the possibility
	of inserting a zero and/or a minus with a width of zero */
	if  (w > MAX_STRLEN)
		rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
	MV_FORCE_NUM(src);
	/* need to guarantee that the n2s call will not cause string pool overflow */
	ENSURE_STP_FREE_SPACE(w);
	sign = 0;
	cp = stringpool.free;
	if (src->mvtype & MV_INT)
	{
		n = src->m[1];
                if (n < 0)
                {
			sign = 1;
			n = -n;
		}
		/* Round if necessary */
		if (fract < 3)
			n += fives_table[fract + 6];
		/* Compute digs, the number of non-zero leading digits */
		if (n < 1000)
		{
			digs = 0;
			/* if we have something like $j(-.01,0,1), the answer should be 0.0, not -0.0
			   so lets check for that here */
			if (sign && fract < 4 && n / ten_pwr[3 - fract] == 0)
			{
				sign = 0;
				n = 0;
			} else
				n *= 1000000;
		} else if (n >= 1000000000)
		{
			digs = 7;
		} else
		{
			for (digs = 6; n < 100000000 ; n *= 10 , digs--)
				;
		}
		/* Do we need leading spaces? */
		w = width - sign - (fract != 0) - fract - digs;
		if (digs == 0)
			w--;
		if (w > 0)
		{
			memset(cp, ' ', w);
			cp += w;
		}
		if (sign)
			*cp++ = '-';
		if (digs == 0)
			*cp++ = '0';
		else
		{
			/* It is possible that when rounding, that
			   we overflowed by one digit.  In this case,
			   the left-most digit must be a "1".
			   Take care of this case first.
			*/
			if (digs == 7)
			{
				*cp++ = '1';
				n -= 1000000000;
				digs = 6;
			}
			for ( ; digs > 0 ; digs--)
			{
				n1 = n / 100000000;
				*cp++ = n1 + '0';
				n = (n - n1 * 100000000) * 10;
			}
		}
		if (fract)
		{
			*cp++ = '.';
			for (digs = fract ; digs > 0 && n != 0; digs--)
			{
				n1 = n / 100000000;
				*cp++ = n1 + '0';
				n = (n - n1 * 100000000) * 10;
			}
			if (digs)
			{
				memset(cp, '0', digs);
				cp += digs;
			}
		}
	} else
	{
		digs = src->e - MV_XBIAS;
		m = src->m[0];
		n = src->m[1];
		sign = src->sgn;
		w = digs + fract;
		if (w < 18 && w >= 0)
		{
			if (w < 9)
			{
				n += fives_table[w];
				if (n >= MANT_HI)
				{
					n1 = n / 10;
					m = m / 10 + ((n - n1 * 10) * MANT_LO);
					n = n1;
					digs++;
				}
			}
			else
			{
				m += fives_table[w - 9];
				if (m >= MANT_HI)
				{
					m -= MANT_HI;
					n++;
					if (n >= MANT_HI)
					{
						n1 = n / 10;
						m = m / 10 + ((n - n1 * 10) * MANT_LO);
						n = n1;
						digs++;
					}
				}
			}
		}
		/* if we have something like $j(-.0001,0,1), the answer should be 0.0, not -0.0 */
		if (digs <= - fract)
		{
			sign = 0;
			n = m = 0;
		}
		w = width - fract - (fract != 0) - sign - (digs < 1 ? 1 : digs);
		if (w > 0)
		{
			memset(cp, ' ', w);
			cp += w;
		}
		if (sign)
			*cp++ = '-';
		digs_used = 0;
		if (digs < 1)
			*cp++ = '0';
		else
		{
			for ( ; digs > 0 && (n != 0 || m != 0); digs--)
			{
				n1 = n / 100000000;
				*cp++ = n1 + '0';
				digs_used++;
				if (digs_used == 9)
				{
					n = m;
					m = 0;
				} else
					n = (n - n1 * 100000000) * 10;
			}
			if (digs > 0)
			{
				memset(cp, '0', digs);
				cp += digs;
			}
		}
		if (fract)
		{
			*cp++ = '.';
			if (digs < 0)
			{
				digs = - digs;
				if (digs > fract)
					digs = fract;
				memset(cp, '0', digs);
				cp += digs;
				fract -= digs;
			}
			for (digs = fract ; digs > 0 && (n != 0 || m != 0); digs--)
			{
				n1 = n / 100000000;
				*cp++ = n1 + '0';
				digs_used++;
				if (digs_used == 9)
				{
					n = m;
					m = 0;
				} else
					n = (n - n1 * 100000000) * 10;
			}
			if (digs)
			{
				memset(cp, '0', digs);
				cp += digs;
			}
		}
	}
	dst->mvtype = MV_STR;
	dst->str.addr = (char *)stringpool.free;
	dst->str.len = INTCAST((char *)cp - dst->str.addr);
	stringpool.free = cp;
	return;
}
Example #18
0
void op_fnztrnlnm(mval *name,mval *table,int4 ind,mval *mode,mval *case_blind,mval *item,mval *ret)
{
	struct dsc$descriptor	lname, ltable;
	uint4		attribute, status, retlen, mask, full_mask;
	char			acmode;
	short int		*item_code, pass, index;
	bool			full;
	char			buff[256], result[MAX_RESULT_SIZE];
	char			i, slot, last_slot;
	char			def_table[] = "LNM$DCL_LOGICAL";

	struct
	{
		item_list_3	item[3];
		int4		terminator;
	} item_list;
	error_def(ERR_BADTRNPARAM);

	if(!name->str.len || MAX_LOGNAM_LENGTH < name->str.len || MAX_LOGNAM_LENGTH < table->str.len)
		rts_error(VARLSTCNT(1) SS$_IVLOGNAM);
	memset(&item_list,0,SIZEOF(item_list));
	item_list.item[0].item_code = 0;
	item_list.item[0].buffer_address = result;
	item_list.item[0].buffer_length = MAX_RESULT_SIZE;
	item_list.item[0].return_length_address = &retlen;
	item_code = &item_list.item[0].item_code;

	lname.dsc$w_length = name->str.len;
	lname.dsc$a_pointer = name->str.addr;
	lname.dsc$b_dtype = DSC$K_DTYPE_T;
	lname.dsc$b_class = DSC$K_CLASS_S;

	if (table->str.len)
	{	ltable.dsc$w_length = table->str.len;
		ltable.dsc$a_pointer = table->str.addr;
	}else
	{	ltable.dsc$a_pointer = def_table;
		ltable.dsc$w_length = strlen(def_table);
	}
	ltable.dsc$b_dtype = DSC$K_DTYPE_T;
	ltable.dsc$b_class = DSC$K_CLASS_S;

	if(ind)
	{	item_list.item[0].item_code = LNM$_INDEX;
		item_list.item[0].buffer_address = &ind;
		item_list.item[1].item_code = 0;
		item_list.item[1].buffer_address = result;
		item_list.item[1].buffer_length = MAX_RESULT_SIZE;
		item_list.item[1].return_length_address = &retlen;
		item_code = &item_list.item[1].item_code;
	}

	attribute = LNM$M_CASE_BLIND;
	if (case_blind->str.len)
	{
		if (case_blind->str.len > 14)
			rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
				MIN(SHRT_MAX, case_blind->str.len), case_blind->str.addr);
		lower_to_upper(buff,case_blind->str.addr,case_blind->str.len);
		if (case_blind->str.len == 14 && !memcmp(buff,"CASE_SENSITIVE",14))
			attribute = 0;
		else if (case_blind->str.len != 10 || memcmp(buff,"CASE_BLIND",10))
			rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,case_blind->str.len,case_blind->str.addr);
	}

	acmode = NOVALUE;
	if (mode->str.len)
	{
		if (mode->str.len > 14)
			rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
				MIN(SHRT_MAX, mode->str.len), mode->str.addr);
		lower_to_upper(buff,mode->str.addr,mode->str.len);
		switch (buff[0])
		{
		case 'U':
			if ( mode->str.len = 4 && !memcmp(buff, "USER", 4))
				acmode = PSL$C_USER;
		case 'S':
			if ( mode->str.len = 10 && !memcmp(buff, "SUPERVISOR", 10))
				acmode = PSL$C_SUPER;
		case 'K':
			if ( mode->str.len = 6 && !memcmp(buff, "KERNEL", 6))
				acmode = PSL$C_KERNEL;
		case 'E':
			if ( mode->str.len = 9 && !memcmp(buff, "EXECUTIVE", 9))
				acmode = PSL$C_EXEC;
		}
		if (acmode == NOVALUE)
			rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,mode->str.len,mode->str.addr);
	}

	full = FALSE;
	*item_code = NOVALUE;
	if (item->str.len)
	{	if (item->str.len > 12)
			rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
				MIN(SHRT_MAX, item->str.len), item->str.addr);
		lower_to_upper(buff,item->str.addr,item->str.len);
		if ((i = buff[0] - 'A') < MIN_INDEX || i > MAX_INDEX)
		{	rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2, item->str.len, item->str.addr);
		}
		if ( trnlnm_index[i].len)
		{	slot = trnlnm_index[i].index;
			last_slot = trnlnm_index[i].len;
			for (; slot < last_slot; slot++)
			{	if (item->str.len == trnlnm_table[slot].len &&
					!memcmp(trnlnm_table[slot].name, buff, item->str.len))
				{	if (trnlnm_table[slot].item_code == FULL_VALUE)
					{	if (ind)
							index = 2;
						else
							index = 1;
						*item_code = LNM$_STRING;
						item_list.item[index].buffer_address = &full_mask;
						item_list.item[index].buffer_length = SIZEOF(full_mask);
						item_list.item[index].item_code = LNM$_ATTRIBUTES;
						item_code = &item_list.item[index].item_code;
						full = TRUE;
					}else
					{	*item_code = trnlnm_table[slot].item_code;
					}
					break;
				}
			}
		}
		if (*item_code == NOVALUE)
		{	rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,item->str.len,item->str.addr);
		}
	}else
	{	*item_code = LNM$_STRING;
	}
	for ( pass = 0 ; ; pass++ )
	{	retlen = 0;
		status = sys$trnlnm(&attribute, &ltable, &lname, acmode == NOVALUE ? 0 : &acmode, &item_list);
		if (status & 1)
		{	if (*item_code == LNM$_STRING || *item_code == LNM$_TABLE)
			{	ret->mvtype = MV_STR;
				ENSURE_STP_FREE_SPACE(retlen);
				ret->str.addr = stringpool.free;
				ret->str.len = retlen;
				memcpy(ret->str.addr, result, retlen);
				stringpool.free += retlen;
				return;
			}else if (*item_code == LNM$_LENGTH || *item_code == LNM$_MAX_INDEX)
			{
				MV_FORCE_MVAL(ret,*(int4 *)result) ;
				n2s(ret);
				return;
			}else if (*item_code == LNM$_ACMODE)
			{	ret->mvtype = MV_STR;
				switch(*result)
				{	case PSL$C_USER:
						ENSURE_STP_FREE_SPACE(4);
						ret->str.addr = stringpool.free;
						ret->str.len = 4;
						memcpy(ret->str.addr, "USER", 4);
						stringpool.free += 4;
						return;
					case PSL$C_SUPER:
						ENSURE_STP_FREE_SPACE(5);
						ret->str.addr = stringpool.free;
						ret->str.len = 5;
						memcpy(ret->str.addr, "SUPER", 5);
						stringpool.free += 5;
						return;
					case PSL$C_EXEC:
						ENSURE_STP_FREE_SPACE(9);
						ret->str.addr = stringpool.free;
						ret->str.len = 9;
						memcpy(ret->str.addr, "EXECUTIVE", 9);
						stringpool.free += 9;
						return;
					case PSL$C_KERNEL:
						ENSURE_STP_FREE_SPACE(6);
						ret->str.addr = stringpool.free;
						ret->str.len = 6;
						memcpy(ret->str.addr, "KERNEL", 6);
						stringpool.free += 6;
						return;
					default:
						GTMASSERT;
				}
			}else
			{	assert(*item_code == LNM$_ATTRIBUTES);
				if (full)
				{	if (!retlen)	/* If the logical name exists, but has no entry for the specified index, */
					{		/* then the return status will be normal as the TERMINAL attribute will  */
							/* be filled in, but there will be no equivalence name, thus retlen == 0 */
						ret->mvtype = MV_STR;
						if (!pass)
						{	ret->str.len = 0;
							return;
						}
						ENSURE_STP_FREE_SPACE(lname.dsc$w_length);
						ret->str.addr = stringpool.free;
						ret->str.len = lname.dsc$w_length;
						memcpy(ret->str.addr, lname.dsc$a_pointer, lname.dsc$w_length);
						stringpool.free += lname.dsc$w_length;
						return;
					}
					if(full_mask & LNM$M_TERMINAL)
					{	ret->mvtype = MV_STR;
						ENSURE_STP_FREE_SPACE(retlen);
						ret->str.addr = stringpool.free;
						ret->str.len = retlen;
						memcpy(ret->str.addr, result, retlen);
						stringpool.free += retlen;
						return;
					}
					memcpy(buff,result,retlen);
					lname.dsc$w_length = retlen;
					lname.dsc$a_pointer = buff;
				}else
				{	mask = attr_tab[slot];
					if (mask == NOVALUE)
						GTMASSERT;
					MV_FORCE_MVAL(ret,( *((int4*)result) & mask ? 1 : 0 )) ;
					n2s(ret);
					return;
				}
			}
		}else if (status == SS$_NOLOGNAM)
		{	ret->mvtype = MV_STR;
			if (full && pass > 0)
			{
				ENSURE_STP_FREE_SPACE(lname.dsc$w_length);
				ret->str.addr = stringpool.free;
				ret->str.len = lname.dsc$w_length;
				memcpy(ret->str.addr, lname.dsc$a_pointer, lname.dsc$w_length);
				stringpool.free += lname.dsc$w_length;
			}else
			{	ret->str.len = 0;
			}
			return;
		}else
		{	rts_error(VARLSTCNT(1) status);
		}
	}
	MV_FORCE_MVAL(ret, 0) ;
	return;
}
Example #19
0
void op_indtext(mval *lab, mint offset, mval *rtn, mval *dst)
{
	bool		rval;
	mstr		*obj, object;
	mval		mv_off;
	oprtype		opt;
	triple		*ref;
	icode_str	indir_src;

	error_def(ERR_INDMAXNEST);
	error_def(ERR_STACKOFLOW);
	error_def(ERR_STACKCRIT);

	MV_FORCE_STR(lab);
	indir_src.str.len = lab->str.len;
	indir_src.str.len += SIZEOF("+^") - 1;
	indir_src.str.len += MAX_NUM_SIZE;
	indir_src.str.len += rtn->str.len;
	ENSURE_STP_FREE_SPACE(indir_src.str.len);
	DBG_MARK_STRINGPOOL_UNEXPANDABLE; /* Now that we have ensured enough space in the stringpool, we dont expect any more
					   * garbage collections or expansions until we are done with the below initialization.
					   */
	/* Push an mval pointing to the complete entry ref on to the stack so the string is valid even
	 * if garbage collection occurs before cache_put() */
	PUSH_MV_STENT(MVST_MVAL);
	mv_chain->mv_st_cont.mvs_mval.mvtype = 0;	/* so stp_gcol (if invoked below) does not get confused by this otherwise
							 * incompletely initialized mval in the M-stack */
	mv_chain->mv_st_cont.mvs_mval.str.addr = (char *)stringpool.free;
	memcpy(stringpool.free, lab->str.addr, lab->str.len);
	stringpool.free += lab->str.len;
	*stringpool.free++ = '+';
	MV_FORCE_MVAL(&mv_off, offset);
	MV_FORCE_STRD(&mv_off); /* goes at stringpool.free. we already made enough space in the stp_gcol() call */
	*stringpool.free++ = '^';
	memcpy(stringpool.free, rtn->str.addr, rtn->str.len);
	stringpool.free += rtn->str.len;
	mv_chain->mv_st_cont.mvs_mval.str.len = INTCAST(stringpool.free - (unsigned char*)mv_chain->mv_st_cont.mvs_mval.str.addr);
	mv_chain->mv_st_cont.mvs_mval.mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
	DBG_MARK_STRINGPOOL_EXPANDABLE;	/* Now that we are done with stringpool.free initializations, mark as free for expansion */

	indir_src.str = mv_chain->mv_st_cont.mvs_mval.str;
	indir_src.code = indir_text;
	if (NULL == (obj = cache_get(&indir_src)))
	{
		comp_init(&indir_src.str);
		rval = f_text(&opt, OC_FNTEXT);
		if (!comp_fini(rval, &object, OC_IRETMVAL, &opt, indir_src.str.len))
		{
			assert(mv_chain->mv_st_type == MVST_MVAL);
			POP_MV_STENT();
			return;
		}
		indir_src.str.addr = mv_chain->mv_st_cont.mvs_mval.str.addr;
		cache_put(&indir_src, &object);
		*ind_result_sp++ = dst;
		if (ind_result_sp >= ind_result_top)
			rts_error(VARLSTCNT(1) ERR_INDMAXNEST);
		assert(mv_chain->mv_st_type == MVST_MVAL);
		POP_MV_STENT(); /* unwind the mval entry before the new frame gets added by comp_indir below */
		comp_indr(&object);
		return;
	}
	*ind_result_sp++ = dst;
	if (ind_result_sp >= ind_result_top)
		rts_error(VARLSTCNT(1) ERR_INDMAXNEST);
	assert(mv_chain->mv_st_type == MVST_MVAL);
	POP_MV_STENT(); /* unwind the mval entry before the new frame gets added by comp_indir below */
	comp_indr(obj);
	return;
}
Example #20
0
/*
 * ----------------------------------------------------------
 * Set $zpiece procedure.
 * Set pieces first through last to expr.
 *
 * Arguments:
 *	src	- source mval
 *	del	- delimiter string mval
 *	expr	- expression string mval
 *	first	- starting index in source mval to be set
 *	last	- last index
 *	dst	- destination mval where the result is saved.
 *
 * Return:
 *	none
 * ----------------------------------------------------------
 */
void op_setzpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval *dst)
{
	size_t		str_len, delim_cnt;
	int 		match_res, len, src_len, first_src_ind, second_src_ind, numpcs;
	unsigned char 	*match_ptr, *src_str, *str_addr, *tmp_str;
	delimfmt	unichar;

	if (0 > --first)
		first = 0;
	assert(last >= first);
	second_src_ind = last - first;
	MV_FORCE_STR(del);
	/* Null delimiter */
	if (0 == del->str.len)
	{
		if (first && src->mvtype)
		{
			/* concat src & expr to dst */
			op_cat(VARLSTCNT(3) dst, src, expr);
			return;
		}
		MV_FORCE_STR(expr);
		*dst = *expr;
		return;
	}
	MV_FORCE_STR(expr);
	if (!MV_DEFINED(src))
	{
		first_src_ind = 0;
		second_src_ind = -1;
	} else
	{
		/* Valid delimiter -  See if we can take a short cut to op_fnzp1. If so, delimiter value needs to be reformated */
		if ((1 == second_src_ind) && (1 == del->str.len))
		{	/* Count of pieces to retrieve is 1 so see what we can do quickly */
			unichar.unichar_val = 0;
			unichar.unibytes_val[0] = *del->str.addr;
			op_setzp1(src, unichar.unichar_val, expr, last, dst);	/* Use "last" since it has not been modified */
			return;
		}
		/* We have a valid src with something in it */
		MV_FORCE_STR(src);
		src_str = (unsigned char *)src->str.addr;
		src_len = src->str.len;
		/* skip all pieces until start one */
		if (first)
		{
			numpcs = first;	/* copy int4 type "first" into "int" type numpcs for passing to matchc */
			match_ptr = matchb(del->str.len, (uchar_ptr_t)del->str.addr, src_len, src_str, &match_res, &numpcs);
			/* Note: "numpcs" is modified above by the function "matchb" to reflect the # of unmatched pieces */
			first = numpcs;	/* copy updated "numpcs" value back into "first" */
		} else
		{
			match_ptr = src_str;
			match_res = 1;
		}
		first_src_ind = INTCAST(match_ptr - (unsigned char *)src->str.addr);
		if (0 == match_res) /* if match not found */
			second_src_ind = -1;
		else
		{
			src_len -= INTCAST(match_ptr - src_str);
			src_str = match_ptr;
			/* skip # delimiters this piece will replace, e.g. if we are setting
			 * pieces 2 - 4, then the pieces 2-4 will be replaced by one piece - expr.
			 */
			match_ptr = matchb(del->str.len, (uchar_ptr_t)del->str.addr, src_len, src_str, &match_res, &second_src_ind);
			second_src_ind = (0 == match_res) ? -1 : INTCAST(match_ptr - (unsigned char *)src->str.addr - del->str.len);
		}
	}
	delim_cnt = (size_t)first;
	/* Calculate total string len. */
	str_len = (size_t)expr->str.len + ((size_t)first_src_ind + ((size_t)del->str.len * delim_cnt));
	/* add len. of trailing chars past insertion point */
	if (0 <= second_src_ind)
		str_len += (size_t)(src->str.len - second_src_ind);
	if (MAX_STRLEN < str_len)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
		return;
	}
	ENSURE_STP_FREE_SPACE((int)str_len);
	str_addr = stringpool.free;
	/* copy prefix */
	if (first_src_ind)
	{
		memcpy(str_addr, src->str.addr, first_src_ind);
		str_addr += first_src_ind;
	}
	/* copy delimiters */
	while (0 < delim_cnt--)
	{
		memcpy(str_addr, del->str.addr, del->str.len);
		str_addr += del->str.len;
	}
	/* copy expression */
	memcpy(str_addr, expr->str.addr, expr->str.len);
	str_addr += expr->str.len;
	/* copy trailing pieces */
	if (0 <= second_src_ind)
	{
		len = src->str.len - second_src_ind;
		tmp_str = (unsigned char *)src->str.addr + second_src_ind;
		memcpy(str_addr, tmp_str, len);
		str_addr += len;
	}
	assert(IS_AT_END_OF_STRINGPOOL(str_addr, -str_len));
	dst->mvtype = MV_STR;
	dst->str.len = INTCAST(str_addr - stringpool.free);
	dst->str.addr = (char *)stringpool.free;
	stringpool.free = str_addr;
	return;
}
Example #21
0
void gvcmx_susremlk(unsigned char rmv_locks)
{
	uint4		status,count,buffer;
	unsigned char	*ptr;
	struct CLB	*p;

	error_def(ERR_BADSRVRNETMSG);

	if (!ntd_root)
		return;
	buffer = lksusp_sent = lksusp_rec = 0;
	for (p = (struct CLB *)RELQUE2PTR(ntd_root->cqh.fl); p != (struct CLB *)ntd_root; p = (struct CLB *)RELQUE2PTR(p->cqe.fl))
	{
		if (((link_info*)(p->usr))->lck_info & REQUEST_PENDING)
			buffer += p->mbl;
	}
	ENSURE_STP_FREE_SPACE(buffer);
	ptr = stringpool.free;
	for (p = (struct CLB *)RELQUE2PTR(ntd_root->cqh.fl); p != (struct CLB *)ntd_root; p = (struct CLB *)RELQUE2PTR(p->cqe.fl))
	{
		if (((link_info *)(p->usr))->lck_info & REQUEST_PENDING)
		{
			p->mbf = ptr;
			*ptr++ = CMMS_L_LKSUSPEND;
			*ptr++ = rmv_locks;
			p->cbl = 2;
			p->ast = 0;
			status = cmi_write(p);
			if (CMI_ERROR(status))
			{
				((link_info *)(p->usr))->neterr = TRUE;
				gvcmz_error(CMMS_M_LKSUSPENDED, status);
				return;
			}
			p->ast = gvcmz_lksuspend_ast;
			status = cmi_read(p);
			if (CMI_ERROR(status))
			{
				((link_info *)(p->usr))->neterr = TRUE;
				gvcmz_error(CMMS_M_LKSUSPENDED, status);
				return;
			}
			lksusp_sent++;
			ptr = p->mbf + p->mbl;
		}
	}
	while (lksusp_sent != lksusp_rec && !lkerror)
		CMI_IDLE(CM_LKSUSPEND_TIME);
	if (lkerror)
	{
		if (CMI_CLB_ERROR(lkerrlnk))
			gvcmz_error(lkerror, CMI_CLB_IOSTATUS(lkerrlnk));
		else
		{
			if (*(lkerrlnk->mbf) != CMMS_E_ERROR)
				rts_error(VARLSTCNT(1) ERR_BADSRVRNETMSG);
			else
				gvcmz_errmsg(lkerrlnk, FALSE);
		}
	}
}
Example #22
0
void dm_read(mval *v)
{
	boolean_t	done;
	unsigned short	iosb[4];
	int		cl, index;
	uint4		max_width, save_modifiers, save_term_msk, status;
	read_iosb	stat_blk;
	io_desc		*io_ptr;
	t_cap		s_mode;
	d_tt_struct	*tt_ptr;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (tt == io_curr_device.out->type)
		iott_flush(io_curr_device.out);
	if (!comline_base)
	{
		comline_base = malloc(MAX_RECALL * SIZEOF(mstr));
		memset(comline_base, 0, (MAX_RECALL * SIZEOF(mstr)));
	}
	io_ptr = io_curr_device.in;
	assert(tt == io_ptr->type);
	assert(dev_open == io_ptr->state);
	if (io_ptr->dollar.zeof)
		op_halt();
	if (outofband)
	{
		outofband_action(FALSE);
		assert(FALSE);
	}
	tt_ptr = (d_tt_struct *)io_ptr->dev_sp;
	max_width = (io_ptr->width > tt_ptr->in_buf_sz) ? io_ptr->width : tt_ptr->in_buf_sz;
	assert(stringpool.free >= stringpool.base);
	assert(stringpool.free <= stringpool.top);
	ENSURE_STP_FREE_SPACE(max_width);
	active_device = io_ptr;
	index = 0;
	/* the following section of code puts the terminal in "easy of use" mode */
	status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE,
		&stat_blk, 0, 0, &s_mode, 12, 0, 0, 0, 0);
	if (SS$_NORMAL == status)
		status = stat_blk.status;
	if (SS$_NORMAL != status)
		rts_error(VARLSTCNT(1) status);
	if ((s_mode.ext_cap & TT2$M_PASTHRU) ||
		!(s_mode.ext_cap & TT2$M_EDITING) ||
		!(s_mode.term_char & TT$M_ESCAPE) ||
		!(s_mode.term_char & TT$M_TTSYNC))
	{
		s_mode.ext_cap &= (~TT2$M_PASTHRU);
		s_mode.ext_cap |= TT2$M_EDITING;
		s_mode.term_char |= (TT$M_ESCAPE | TT$M_TTSYNC);
		status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
			IO$_SETMODE, &stat_blk, 0, 0, &s_mode, 12, 0, 0, 0, 0);
		if (SS$_NORMAL == status)
			status = stat_blk.status;
		if (SS$_NORMAL != status)
			/* The following error is probably going to cause the terminal state to get mucked up */
			rts_error(VARLSTCNT(1) status);
		/* the following flag is normally used by iott_rdone, iott_readfl and iott_use but dm_read resets it when done */
		tt_ptr->term_chars_twisted = TRUE;
	}
	save_modifiers = (unsigned)tt_ptr->item_list[0].addr;
	tt_ptr->item_list[0].addr = (unsigned)tt_ptr->item_list[0].addr | TRM$M_TM_NORECALL & (~TRM$M_TM_NOECHO);
	tt_ptr->item_list[1].addr = NO_M_TIMEOUT;			/* reset key click timeout */
	save_term_msk = ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0];
	((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = TERM_MSK | (SHFT_MSK << CTRL_B) | (SHFT_MSK << CTRL_Z);
	tt_ptr->item_list[4].buf_len = (TREF(gtmprompt)).len;
	do
	{
		done = TRUE;
		assert(0 <= index && index <= MAX_RECALL + 1);
		cl = clmod(comline_index - index);
		if ((0 == index) || (MAX_RECALL + 1 == index))
			tt_ptr->item_list[5].buf_len	= 0;
		else
		{
			tt_ptr->item_list[5].buf_len	= comline_base[cl].len;
			tt_ptr->item_list[5].addr	= comline_base[cl].addr;
		}
		status = sys$qiow(EFN$C_ENF, tt_ptr->channel, tt_ptr->read_mask, &stat_blk, 0, 0,
			stringpool.free, tt_ptr->in_buf_sz, 0, 0, tt_ptr->item_list, 6 * SIZEOF(item_list_struct));
		if (outofband)
			break;
		if (SS$_NORMAL != status)
		{
			if (io_curr_device.in == io_std_device.in && io_curr_device.out == io_std_device.out)
			{
				if (prin_in_dev_failure)
					sys$exit(status);
				else
					prin_in_dev_failure = TRUE;
			}
			break;
		}
		if (stat_blk.term_length > ESC_LEN - 1)
		{
			stat_blk.term_length = ESC_LEN - 1;
			if (SS$_NORMAL == stat_blk.status)
				stat_blk.status = SS$_PARTESCAPE;
		}
		if (SS$_NORMAL != stat_blk.status)
		{
			if (ctrlu_occurred)
			{
				index = 0;
				done = FALSE;
				ctrlu_occurred = FALSE;
				iott_wtctrlu(stat_blk.char_ct + (TREF(gtmprompt)).len, io_ptr);
			} else
			{
				status = stat_blk.status;
				break;
			}
		} else
		{
			if ((CTRL_B == stat_blk.term_char) ||
				(stat_blk.term_length == tt_ptr->key_up_arrow.len &&
				!memcmp(tt_ptr->key_up_arrow.addr, stringpool.free + stat_blk.char_ct,
				tt_ptr->key_up_arrow.len)))
			{
				done = FALSE;
				if ((MAX_RECALL + 1 != index) && (comline_base[cl].len || !index))
					index++;
			} else
			{
				if (stat_blk.term_length == tt_ptr->key_down_arrow.len &&
					!memcmp(tt_ptr->key_down_arrow.addr, stringpool.free + stat_blk.char_ct,
					tt_ptr->key_down_arrow.len))
				{
					done = FALSE;
					if (index)
						--index;
				}
			}
			if (!done)
			{
				status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
					IO$_WRITEVBLK, &iosb, NULL, 0,
					tt_ptr->erase_to_end_line.addr, tt_ptr->erase_to_end_line.len,
					0, CCRECALL, 0, 0);
			} else
			{
				if (stat_blk.char_ct > 0
					&& (('R' == *stringpool.free) || ('r' == *stringpool.free)) &&
					(TRUE == m_recall(stat_blk.char_ct, stringpool.free, &index, tt_ptr->channel)))
				{
					assert(-1 <= index && index <= MAX_RECALL);
					done = FALSE;
					flush_pio();
					status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
						IO$_WRITEVBLK, &iosb, NULL, 0,
						0, 0, 0, CCPROMPT, 0, 0);
					if ((-1 == index) || (CTRL_Z == stat_blk.term_char))
						index = 0;
				}
			}
			if (!done)
			{
				if (SS$_NORMAL == status)
					status = iosb[0];
				if (SS$_NORMAL != status)
					break;
			} else
			{
				if (CTRL_Z == stat_blk.term_char)
					io_curr_device.in->dollar.zeof = TRUE;
			}
		}
	} while (!done);
	/* put the terminal back the way the user had it set up */
	tt_ptr->item_list[0].addr = save_modifiers;
	((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
	if (tt_ptr->term_chars_twisted)
	{
		s_mode.ext_cap &= (~TT2$M_PASTHRU & ~TT2$M_EDITING);
		s_mode.ext_cap |= (tt_ptr->ext_cap & (TT2$M_PASTHRU | TT2$M_EDITING));
		s_mode.term_char &= (~TT$M_ESCAPE);
		s_mode.term_char |= (tt_ptr->term_char & TT$M_ESCAPE);
		status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
			IO$_SETMODE, iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
		if (SS$_NORMAL == status)
			status = iosb[0];
		tt_ptr->term_chars_twisted = FALSE;
	}
	if (SS$_NORMAL != status)
		rts_error(VARLSTCNT(1) status);
	if (outofband)
	{
		/* outofband not going to help more than a error so it's checked 2nd */
		outofband_action(FALSE);
		assert(FALSE);
	}
	v->mvtype = MV_STR;
	v->str.len = stat_blk.char_ct;
	v->str.addr = stringpool.free;
	if (stat_blk.char_ct)
	{
		cl = clmod(comline_index - 1);
		if (stat_blk.char_ct != comline_base[cl].len || memcmp(comline_base[cl].addr, stringpool.free, stat_blk.char_ct))
		{
			comline_base[comline_index] = v->str;
			comline_index = clmod(comline_index + 1);
		}
		stringpool.free += stat_blk.char_ct;
	}
	assert(stringpool.free <= stringpool.top);
	if ((io_ptr->dollar.x += stat_blk.char_ct) > io_ptr->width && io_ptr->wrap)
	{
		/* dm_read doesn't maintain the other io status isv's,
		 but it does $x and $y so the user can find out where they wound up */
		io_ptr->dollar.y += io_ptr->dollar.x / io_ptr->width;
		if (io_ptr->length)
			io_ptr->dollar.y %= io_ptr->length;
		io_ptr->dollar.x %= io_ptr->width;
	}
	active_device = 0;
}
Example #23
0
/*
 * ----------------------------------------------------------
 * Fast path setpiece when delimiter is one (lit) char replacing
 * a single piece (last is same as first). Unicode flavor.
 *
 * Arguments:
 *	src	- source mval
 *	delim	- delimiter char
 *	expr	- expression string mval
 *	ind	- index in source mval to be set
 *	dst	- destination mval where the result is saved.
 *
 * Return:
 *	none
 * ----------------------------------------------------------
 */
void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst)
{
	size_t		str_len, delim_cnt;
	int		len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, pfx_scan_offset;
	int		dlmlen, cpy_cache_lines, mblen;
	unsigned char	*start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx;
	boolean_t	do_scan, delim_last_scan, valid_char;
	mval		dummymval;	/* It's value is not used but is part of the call to op_fnp1() */
	fnpc		*cfnpc, *pfnpc;
	delimfmt	ldelim;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gtm_utf8_mode);
	do_scan = FALSE;
	cpy_cache_lines = -1;
	ldelim.unichar_val = delim;
        if (!UTF8_VALID(ldelim.unibytes_val, (ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val)), dlmlen)
	    && !badchar_inhibit)
	{	/* The delimiter is a bad character so error out if badchar not inhibited */
		UTF8_BADCHAR(0, ldelim.unibytes_val, ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val), 0, NULL);
	}
	MV_FORCE_STR(expr);	/* Expression to put into piece place */
	if (MV_DEFINED(src))
	{
		/* We have 3 possible scenarios:
		 * 1) The source string is null. Nothing to do but proceed to building output.
		 * 2) If the requested piece is larger than can be cached by op_fnp1, call fnp1
		 *    for the maximum piece possible, use the cache info to "prime the pump" and
		 *    then process the rest of the string ourselves.
		 * 3) If the requested piece can be obtained from the cache, call op_fnp1 to validate
		 *    and rebuild the cache if necessary and then retrieve the necessary info from
		 *    the fnpc cache.
		 */
		MV_FORCE_STR(src);	/* Make sure is string prior to length check */
		if (0 == src->str.len)
		{	/* We have a null source string */
			pfx_str_len = sfx_str_len = sfx_start_offset = 0;
			delim_cnt = (0 < ind) ? (size_t)ind - 1 : 0;
		} else if (FNPC_ELEM_MAX >= ind)
		{	/* 3) Best of all possible cases. The op_fnp1 can do most of our work for us
			 *    and we can preload the cache on the new string to help its subsequent
			 *    uses along as well.
			 */
			SETWON;
			op_fnp1(src, delim, ind, &dummymval);
			SETWOFF;
			cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
			assert(cfnpc->last_str.addr == src->str.addr);
			assert(cfnpc->last_str.len == src->str.len);
			assert(cfnpc->delim == delim);
			assert(0 < cfnpc->npcs);
			/* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran
			 * out of text or #3 piece is beyond what can be cached
			 */
			if (cfnpc->npcs >= ind)
			{	/* #1 The piece we want is totally within the cache which is good news */
				pfx_str_len = cfnpc->pstart[ind - 1];
				delim_cnt = 0;
				sfx_start_offset = cfnpc->pstart[ind] - dlmlen;				/* Include delimiter */
				rep_str_len = cfnpc->pstart[ind] - cfnpc->pstart[ind - 1] - dlmlen;	/* Replace string length */
				sfx_str_len = src->str.len - pfx_str_len - rep_str_len;
				cpy_cache_lines = ind - 1;
			} else
			{	/* #2 The string was too short so the cache does not contain our string. This means
				 * that the prefix becomes any text that IS in the cache and we set the delim_cnt
				 * to be the number of missing pieces so the delimiters can be put in as part of the
				 * prefix when we build the new string.
				 */
				pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen;
				delim_cnt = (size_t)(ind - cfnpc->npcs);
				sfx_start_offset = 0;
				sfx_str_len = 0;
				cpy_cache_lines = cfnpc->npcs;
			}
		} else
		{	/* 2) We have a element that would not be able to be in the fnpc cache. Go ahead
			 *    and call op_fnp1 to get cache info up to the maximum and then we will continue
			 *    the scan on our own.
			 */
			SETWON;
			op_fnp1(src, delim, FNPC_ELEM_MAX, &dummymval);
			SETWOFF;
			cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
			assert(cfnpc->last_str.addr == src->str.addr);
			assert(cfnpc->last_str.len == src->str.len);
			assert(cfnpc->delim == delim);
			assert(0 < cfnpc->npcs);
			if (FNPC_ELEM_MAX > cfnpc->npcs)
			{	/* We ran out of text so the scan is complete. This is basically the same
				 * as case #2 above.
				 */
				pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen;
				delim_cnt = (size_t)(ind - cfnpc->npcs);
				sfx_start_offset = 0;
				sfx_str_len = 0;
				cpy_cache_lines = cfnpc->npcs;
			} else
			{	/* We have a case where the piece we want cannot be kept in cache. In the special
				 * case where there is no more text to handle, we don't need to scan further. Otherwise
				 * we prime the pump and continue the scan where the cache left off.
				 */
				if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len)	/* Note assignment */
					/* Normal case where we prime the pump */
					do_scan = TRUE;
				else
				{	/* Special case -- no more text to scan */
					pfx_str_len = cfnpc->pstart[FNPC_ELEM_MAX] - dlmlen;
					sfx_start_offset = 0;
					sfx_str_len = 0;
				}
				delim_cnt = (size_t)ind - FNPC_ELEM_MAX;
				cpy_cache_lines = FNPC_ELEM_MAX;
			}
		}
	} else
	{	/* Source is not defined -- treat as a null string */
		pfx_str_len = sfx_str_len = sfx_start_offset = 0;
		delim_cnt = (size_t)ind - 1;
	}
	/* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been
	 * set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters
	 * still need to be processed.
	 */
	if (do_scan)
	{	/* Scan the line isolating prefix piece, and end of the
		 * piece being replaced
		 */
		COUNT_EVENT(small);
		end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset;
		end_src = (unsigned char *)src->str.addr + src->str.len;
		/* The compiler would unroll this loop this way anyway but we want to
		 * adjust the start_sfx pointer after the loop but only if we have gone
		 * into it at least once.
		 */
		if ((0 < delim_cnt) && (start_sfx < end_src))
		{
			do
			{
				end_pfx = start_sfx;
				delim_last_scan = FALSE;		/* Whether delimiter is last character scanned */
				while (start_sfx < end_src)
				{
					valid_char = UTF8_VALID(start_sfx, end_src, mblen); /* Length of next char */
					if (!valid_char)
					{	/* Next character is not valid unicode. If badchar error is not inhibited,
						 * signal it now. If it is inhibited, just treat the character as a single
						 * character and continue.
						 */
						if (!badchar_inhibit)
							utf8_badchar(0, start_sfx, end_src, 0, NULL);
						assert(1 == mblen);
					}
					/* Getting mblen first allows us to do quick length compare before the
					 * heavier weight memcmp call.
					 */
					assert(0 < mblen);
					if (mblen == dlmlen && 0 == memcmp(start_sfx, ldelim.unibytes_val, dlmlen))
					{
						delim_last_scan = TRUE;
						break;
					}
					/* Increment ptrs by size of found char */
					start_sfx += mblen;
				}
				start_sfx += dlmlen;
				delim_cnt--;
			} while ((0 < delim_cnt) && (start_sfx < end_src));
			/* We have to backup up the suffix start pointer except under the condition
			 * that the last character in the buffer is the last delimiter we were looking
			 * for.
			 */
			if ((0 == delim_cnt) || (start_sfx < end_src) || !delim_last_scan)
				start_sfx -= dlmlen;			/* Back up suffix to include delimiter char */
			/* If we scanned to the end (no text left) and still have delimiters to
			 * find, the entire src text should be part of the prefix
			 */
			if ((start_sfx >= end_src) && (0 < delim_cnt))
			{
				end_pfx = start_sfx;
				if (delim_last_scan)			/* if last char was delim, reduce delim cnt */
					--delim_cnt;
			}
		} else
		{
			/* If not doing any token finding, then this count becomes the number
			 * of tokens to output. Adjust accordingly.
			 */
			if (0 < delim_cnt)
				--delim_cnt;
		}
		INCR_COUNT(small_pcs, (int)((size_t)ind - delim_cnt));
		/* Now having the following situation:
		 * end_pfx	-> end of the prefix piece including delimiter
		 * start_sfx	-> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none
		 */
		pfx_str_len = (int)(end_pfx - (unsigned char *)src->str.addr);
		if (0 > pfx_str_len)
			pfx_str_len = 0;
		sfx_start_offset = (int)(start_sfx - (unsigned char *)src->str.addr);
		sfx_str_len = src->str.len - sfx_start_offset;
		if (0 > sfx_str_len)
			sfx_str_len = 0;
	}
	/* Calculate total string len. delim_cnt has needed padding delimiters for null fields */
	str_len = (size_t)expr->str.len + (size_t)pfx_str_len + (delim_cnt * (size_t)dlmlen) + (size_t)sfx_str_len;
	if (MAX_STRLEN < str_len)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
	ENSURE_STP_FREE_SPACE((int)str_len);
	str_addr = stringpool.free;
	start_pfx = (unsigned char *)src->str.addr;
	/* copy prefix */
	if (0 < pfx_str_len)
	{
		memcpy(str_addr, src->str.addr, pfx_str_len);
		str_addr += pfx_str_len;
	}
	/* copy delimiters */
	while (0 < delim_cnt--)
	{
		memcpy(str_addr, ldelim.unibytes_val, dlmlen);
		str_addr += dlmlen;
	}
	/* copy expression */
	if (0 < expr->str.len)
	{
		memcpy(str_addr, expr->str.addr, expr->str.len);
		str_addr += expr->str.len;
	}
	/* copy suffix */
	if (0 < sfx_str_len)
	{
		memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len);
		str_addr += sfx_str_len;
	}
	assert(IS_AT_END_OF_STRINGPOOL(str_addr, -str_len));
	dst->mvtype = MV_STR;
	dst->str.len = INTCAST(str_addr - stringpool.free);
	dst->str.addr = (char *)stringpool.free;
	stringpool.free = str_addr;
	/* If available, update the cache information for this newly created mval to hopefully
	 * give it a head start on its next usage. Note that we can only copy over the cache info
	 * for the prefix. We cannot include information for the 'expression' except where it starts
	 * because the expression could itself contain delimiters that would be found on a rescan.
	 */
	if (0 < cpy_cache_lines)
	{
		pfnpc = cfnpc;				/* pointer for src mval's cache */
		do
		{
			cfnpc = (TREF(fnpca)).fnpcsteal;	/* Next cache element to steal */
			if ((TREF(fnpca)).fnpcmax < cfnpc)
				cfnpc = &(TREF(fnpca)).fnpcs[0];
			(TREF(fnpca)).fnpcsteal = cfnpc + 1;	/* -> next element to steal */
		} while (cfnpc == pfnpc);		/* Make sure we don't step on ourselves */
		cfnpc->last_str = dst->str;		/* Save validation info */
		cfnpc->delim = delim;
		cfnpc->npcs = cpy_cache_lines;
		dst->fnpc_indx = cfnpc->indx + 1;	/* Save where we are putting this element
							 * (1 based index in mval so 0 isn't so common)
							 */
		memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * SIZEOF(unsigned int));
	} else
Example #24
0
boolean_t gvcst_queryget2(mval *val, unsigned char *sn_ptr)
{
	blk_hdr_ptr_t	bp;
	boolean_t	found, two_histories;
	enum cdb_sc	status;
	int		rsiz, key_size, data_len;
	rec_hdr_ptr_t	rp;
	srch_blk_status	*bh;
	srch_hist	*rt_history;
	unsigned short	temp_ushort;
	int		tmp_cmpc;
	DEBUG_ONLY(unsigned char *save_strp = NULL);

	T_BEGIN_READ_NONTP_OR_TP(ERR_GVQUERYGETFAIL);
	assert((CDB_STAGNATE > t_tries) || cs_addrs->now_crit);	/* we better hold crit in the final retry (TP & non-TP) */
	for (;;)
	{
		two_histories = FALSE;
#if defined(DEBUG) && defined(UNIX)
			if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVQUERYGETFAIL == gtm_white_box_test_case_number))
			{
				status = cdb_sc_blknumerr;
				t_retry(status);
				continue;
			}
#endif
		if (cdb_sc_normal == (status = gvcst_search(gv_currkey, 0)))
		{
			found = TRUE;
			bh = &gv_target->hist.h[0];
			rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset);
			bp = (blk_hdr_ptr_t)bh->buffaddr;
			if (rp >= (rec_hdr_ptr_t)CST_TOB(bp))
			{
				two_histories = TRUE;
				rt_history = gv_target->alt_hist;
				status = gvcst_rtsib(rt_history, 0);
				if (cdb_sc_endtree == status)		/* end of tree */
				{
					found = FALSE;
					two_histories = FALSE;		/* second history not valid */
				} else  if (cdb_sc_normal != status)
				{
					t_retry(status);
					continue;
				} else
				{
					bh = &rt_history->h[0];
					if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh)))
					{
						t_retry(status);
						continue;
					}
					rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset);
					bp = (blk_hdr_ptr_t)bh->buffaddr;
				}
			}
			/* !found indicates that the end of tree has been reached (see call to
			 *  gvcst_rtsib).  If there is no more tree, don't bother doing expansion.
			 */
			if (found)
			{
				status = gvcst_expand_key((blk_hdr_ptr_t)bh->buffaddr, (int4)((sm_uc_ptr_t)rp - bh->buffaddr),
						gv_altkey);
				if (cdb_sc_normal != status)
				{
					t_retry(status);
					continue;
				}
				key_size = gv_altkey->end + 1;
				GET_RSIZ(rsiz, rp);
				data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size;
				if (data_len < 0  || (sm_uc_ptr_t)rp + rsiz > (sm_uc_ptr_t)bp + ((blk_hdr_ptr_t)bp)->bsiz)
				{
					assert(CDB_STAGNATE > t_tries);
					t_retry(cdb_sc_rmisalign1);
					continue;
				}
				ENSURE_STP_FREE_SPACE(data_len);
				DEBUG_ONLY (
				if (!save_strp)
					save_strp = stringpool.free);
				assert(stringpool.top - stringpool.free >= data_len);
				memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len);
				/* Assumption: t_end/tp_hist will never cause stp_gcol() call BYPASSOK */
			}
			if (!dollar_tlevel)
			{
				if ((trans_num)0 == t_end(&gv_target->hist, !two_histories ? NULL : rt_history, TN_NOT_SPECIFIED))
					continue;
			} else
			{
				status = tp_hist(!two_histories ? NULL : rt_history);
				if (cdb_sc_normal != status)
				{
					t_retry(status);
					continue;
				}
			}
			if (found)
			{
				DEBUG_ONLY(assert(save_strp == stringpool.free));
				/* Process val first. Already copied to string pool. */
				val->mvtype = MV_STR;
				val->str.addr = (char *)stringpool.free;
				val->str.len = data_len;
				stringpool.free += data_len;
				INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1);
			}
			return found;
		}
		t_retry(status);
	}
Example #25
0
void op_fnzdate(mval *src, mval *fmt, mval *mo_str, mval *day_str, mval *dst)
{
	unsigned char 	ch, *fmtptr, *fmttop, *i, *outptr, *outtop, *outpt1;
	int 		cent, day, dow, month, nlen, outlen, time, year;
	unsigned int	n;
	mval 		temp_mval;

	static readonly unsigned char montab[] = {31,28,31,30,31,30,31,31,30,31,30,31};
	static readonly unsigned char default1[] = DEFAULT1;
	static readonly unsigned char default2[] = DEFAULT2;
	static readonly unsigned char default3[] = DEFAULT3;
	static readonly unsigned char defmonlst[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
	static readonly unsigned char defdaylst[] = "SUNMONTUEWEDTHUFRISAT";
#if defined(BIGENDIAN)
	static readonly int  comma = (((int)',') << 24);
#else
	static readonly int  comma = ',';
#endif
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	MV_FORCE_NUM(src);
	MV_FORCE_STR(fmt);
	MV_FORCE_STR(mo_str);
	MV_FORCE_STR(day_str);
	ENSURE_STP_FREE_SPACE(ZDATE_MAX_LEN);
	time = 0;
	outlen = src->str.len;
	if ((src->mvtype & MV_STR) && (src->mvtype & MV_NUM_APPROX))
	{
		for (outptr = (unsigned char *)src->str.addr, outtop = outptr + outlen; outptr < outtop; )
		{
			if (',' == *outptr++)
			{
				outlen = outptr - (unsigned char *)src->str.addr - 1;
				temp_mval.mvtype = MV_STR;
				temp_mval.str.addr = (char *)outptr;
				temp_mval.str.len = INTCAST(outtop - outptr);
				s2n(&temp_mval);
				time = MV_FORCE_INTD(&temp_mval);
				if ((0 > time) || (MAX_TIME < time))
					rts_error(VARLSTCNT(4) ERR_ZDATEBADTIME, 2, temp_mval.str.len, temp_mval.str.addr);
				break;
			}
		}
	}
	day = (int)MV_FORCE_INTD(src);
	if ((MAX_DATE < day) || (MIN_DATE > day))
	{
		MV_FORCE_STR(src);
		rts_error(VARLSTCNT(4) ERR_ZDATEBADDATE, 2, outlen, src->str.addr);
	}
	day += DAYS_MOST_YEARS;
	dow = ((day + ADJUST_TO_1900) % DAYS_IN_WEEK) + 1;
	for (cent = DAYS_BASE_TO_1900, n = ADJUST_TO_1900; cent < day; cent += DAYS_IN_CENTURY, n++)
			day += (0 < (n % COMMON_LEAP_CYCLE));
	year = day / DAYS_IN_FOUR_YEARS;
	day = day - (year * DAYS_IN_FOUR_YEARS);
	year = (year * COMMON_LEAP_CYCLE) + BASE_YEAR;
	if (DAYS_BEFORE_LEAP == day)
	{
		day = MIN_DAYS_IN_MONTH + 1;
		month = 2;
	} else
	{
		if (DAYS_BEFORE_LEAP < day)
			day--;
		month = day / DAYS_MOST_YEARS;
		year += month;
		day -= (month * DAYS_MOST_YEARS);
		for (i = montab; day >= *i; day -= *i++)
			;
		month = (int)((i - montab)) + 1;
		day++;
		assert((0 < month) && (MONTHS_IN_YEAR >= month));
	}
	if ((0 == fmt->str.len) || ((1 == fmt->str.len) && ('1' == *fmt->str.addr)))
	{
		if (!TREF(zdate_form) || ((1 == TREF(zdate_form)) && (PIVOT_MILLENIUM > year)))
		{
			fmtptr = default1;
			fmttop = fmtptr + STR_LIT_LEN(DEFAULT1);
		} else
		{
			fmtptr = default3;
			fmttop = fmtptr + STR_LIT_LEN(DEFAULT3);
		}
	} else if ((1 == fmt->str.len) && ('2' == *fmt->str.addr))
	{
		fmtptr = default2;
		fmttop = fmtptr + STR_LIT_LEN(DEFAULT2);
	} else
	{
		fmtptr = (unsigned char *)fmt->str.addr;
		fmttop = fmtptr + fmt->str.len;
	}
	outlen = (int)(fmttop - fmtptr);
	if (outlen >= ZDATE_MAX_LEN)
		rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
	outptr = stringpool.free;
	outtop = outptr + ZDATE_MAX_LEN;
	temp_mval.mvtype = MV_STR;
	assert(0 <= time);
	nlen = 0;
	while (fmtptr < fmttop)
	{
		switch (ch = *fmtptr++)		/* NOTE assignment */
		{
		case '/':
		case ':':
		case '.':
		case ',':
		case '-':
		case ' ':
		case '*':
		case '+':
		case ';':
			*outptr++ = ch;
			continue;
		case 'M':
			ch = *fmtptr++;
			if ('M' == ch)
			{
				n = month;
				nlen = 2;
				break;
			}
			if (('O' != ch) || ('N' != *fmtptr++))
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			if (0 == mo_str->str.len)
			{
				temp_mval.str.addr = (char *)&defmonlst[(month - 1) * LEN_OF_3_CHAR_ABBREV];
				temp_mval.str.len = LEN_OF_3_CHAR_ABBREV;
				nlen = -LEN_OF_3_CHAR_ABBREV;
			} else
			{
				UNICODE_ONLY(gtm_utf8_mode ? op_fnp1(mo_str, comma, month, &temp_mval) :
					                     op_fnzp1(mo_str, comma, month, &temp_mval));
				VMS_ONLY(op_fnzp1(mo_str, comma, month, &temp_mval, TRUE));
				nlen = -temp_mval.str.len;
				outlen += - LEN_OF_3_CHAR_ABBREV - nlen;
				if (outlen >= ZDATE_MAX_LEN)
					rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			}
			break;
		case 'D':
			ch = *fmtptr++;
			if ('D' == ch)
			{
				n = day;
				nlen = 2;
				break;
			}
			if (('A' != ch) || ('Y' != *fmtptr++))
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			if (0 == day_str->str.len)
			{
				temp_mval.str.addr = (char *)&defdaylst[(dow - 1) * LEN_OF_3_CHAR_ABBREV];
				temp_mval.str.len = LEN_OF_3_CHAR_ABBREV;
				nlen = -LEN_OF_3_CHAR_ABBREV;
			} else
			{
				UNICODE_ONLY(gtm_utf8_mode ? op_fnp1(day_str, comma, dow, &temp_mval)
							   : op_fnzp1(day_str, comma, dow, &temp_mval));
				VMS_ONLY(op_fnzp1(day_str, comma, dow, &temp_mval, TRUE));
				nlen = -temp_mval.str.len;
				outlen += - LEN_OF_3_CHAR_ABBREV - nlen;
				if (outlen >= ZDATE_MAX_LEN)
					rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			}
			break;
		case 'Y':
			ch = *fmtptr++;
			n = year;
			if ('Y' == ch)
			{
				for (nlen = 2; (MAX_YEAR_DIGITS >=nlen) && fmtptr < fmttop; ++nlen, fmtptr++)
					if ('Y' != *fmtptr)
						break;
			} else
			{
				if (('E' != ch) || ('A' != *fmtptr++) || ('R' != *fmtptr++))
					rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
				nlen = 4;
			}
			break;
		case '1':
			if ('2' != *fmtptr++)
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			nlen = 2;
			n = time / SECONDS_PER_HOUR;
			n = ((n + HOURS_PER_AM_OR_PM - 1) % HOURS_PER_AM_OR_PM) + 1;
			break;
		case '2':
			if ('4' != *fmtptr++)
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			nlen = 2;
			n = time / SECONDS_PER_HOUR;
			break;
		case '6':
			if ('0' != *fmtptr++)
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			nlen = 2;
			n = time;
			n /= MINUTES_PER_HOUR;
			n %= MINUTES_PER_HOUR;
			break;
		case 'S':
			if ('S' != *fmtptr++)
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			nlen = 2;
			n = time % SECONDS_PER_MINUTE;
			break;
		case 'A':
			if ('M' != *fmtptr++)
				rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
			*outptr++ = (time < (HOURS_PER_AM_OR_PM * SECONDS_PER_HOUR)) ? 'A' : 'P';
			*outptr++ = 'M';
			continue;
		default:
			rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
		}
		if (nlen > 0)
		{
			outptr += nlen;
			outpt1 = outptr;
			while (nlen-- > 0)
			{
				*--outpt1 = '0' + (n % 10);
				n /= 10;
			}
		} else
		{
			outpt1 = (unsigned char *)temp_mval.str.addr;
			while (nlen++ < 0)
				*outptr++ = *outpt1++;
		}
	}
	if (fmtptr > fmttop)
		rts_error(VARLSTCNT(1) ERR_ZDATEFMT);
	dst->mvtype = MV_STR;
	dst->str.addr = (char *)stringpool.free;
	dst->str.len = INTCAST((char *)outptr - dst->str.addr);
	stringpool.free = outptr;
	return;
}
Example #26
0
void op_fnfnumber(mval *src, mval *fmt, mval *dst)
{
	mval		temp, *temp_p;
	unsigned char	fncode, sign, *ch, *cp, *ff, *ff_top, *t;
	int 		ct, x, y, z, xx;
	boolean_t	comma, paren;
	error_def(ERR_FNARGINC);
	error_def(ERR_FNUMARG);

	assert (stringpool.free >= stringpool.base);
	assert (stringpool.free <= stringpool.top);
	/* assure that there is adequate space for two string forms of a number
	   as a local version of the src must be operated upon in order to get
	   a canonical number
	*/
	ENSURE_STP_FREE_SPACE(MAX_NUM_SIZE * 2);
	/* operate on the src operand in a temp, so that
	   conversions are possible without destroying the source
	*/
	temp_p = &temp;
	*temp_p = *src;
	/* if the source operand is not a canonical number, force conversion
	*/
	MV_FORCE_STR(temp_p);
	MV_FORCE_STR(fmt);
	if (fmt->str.len == 0)
	{
		*dst = *temp_p;
		return;
	}
	temp_p->mvtype = MV_STR;
	ch = (unsigned char *)temp_p->str.addr;
	ct = temp_p->str.len;
	cp = stringpool.free;
	fncode = 0;
	for (ff = (unsigned char *)fmt->str.addr , ff_top = ff + fmt->str.len ; ff < ff_top ; )
	{
		switch(*ff++)
		{
			case '+':
				fncode |= PLUS;
				break;
			case  '-':
				fncode |= MINUS;
				break;
			case  ',':
				fncode |= COMMA;
				break;
			case  'T':
			case  't':
				fncode |= TRAIL;
				break;
			case  'P':
			case  'p':
				fncode |= PAREN;
				break;
			default:
				rts_error(VARLSTCNT(6) ERR_FNUMARG, 4, fmt->str.len, fmt->str.addr, 1, --ff);
			break;
		}
	}
	if (0 != (fncode & PAREN) && 0 != (fncode & FNERROR))
		rts_error(VARLSTCNT(4) ERR_FNARGINC, 2, fmt->str.len, fmt->str.addr);
	else
	{
		sign = 0;
		paren = FALSE;
		if ('-' == *ch)
		{
			sign = '-';
			ch++;
			ct--;
		}
		if (0 != (fncode & PAREN))
		{
			if ('-' == sign)
			{
				*cp++ = '(';
				sign = 0;
				paren = TRUE;
			}
			else *cp++ = ' ';
		}
		/* Only add '+' if > 0 */
		if (0 != (fncode & PLUS) && 0 == sign)
		{	/* Need to make into num and check for int 0 in case was preprocessed by op_fnj3() */
			MV_FORCE_NUM(temp_p);
			if (0 == (temp_p->mvtype & MV_INT) || 0 != temp_p->m[1])
				sign = '+';
		}
		if (0 != (fncode & MINUS) && '-' == sign)
			sign = 0;
		if (0 == (fncode & TRAIL) && 0 != sign)
			*cp++ = sign;
		if (0 != (fncode & COMMA))
		{
			comma = FALSE;
			for (x = 0, t = ch; '.' != *t && ++x < ct; t++) ;
			z = x;
			if ((y = x % 3) > 0)
			{
				while (y-- > 0)
					*cp++ = *ch++;
				comma = TRUE;
			}
			for ( ; x / 3 != 0 ; x -= 3, cp += 3, ch +=3)
			{
				if (comma)
					*cp++ = ',';
				else
					comma = TRUE;
				memcpy(cp, ch, 3);
			}
			if (z < ct)
			{
				xx = ct - z;
				memcpy(cp, ch, xx);
				cp += xx;
			}
		} else
		{
			memcpy(cp, ch, ct);
			cp += ct;
		}
		if (0 != (fncode & TRAIL))
		{
			if (sign != 0) *cp++ = sign;
			else *cp++ = ' ';
		}
		if (0 != (fncode & PAREN))
		{
			if (paren) *cp++ = ')';
			else *cp++ = ' ';
		}
		dst->mvtype = MV_STR;
		dst->str.addr = (char *)stringpool.free;
		dst->str.len = INTCAST(cp - stringpool.free);
		stringpool.free = cp;
		return;
	}
	GTMASSERT;
}
Example #27
0
void op_fngetjpi(mint jpid, mval *keyword, mval *ret)
{
	out_struct	out_quad;
	int4		out_long, jpi_code, pid;
	short		index, length, slot, last_slot, out_len;
	uint4		status;
	char		upcase[MAX_KEY_LEN];

	$DESCRIPTOR(out_string, "");
	error_def(ERR_BADJPIPARAM);

	assert (stringpool.free >= stringpool.base);
	assert (stringpool.top >= stringpool.free);
	ENSURE_STP_FREE_SPACE(MAX_JPI_STRLEN);
	MV_FORCE_STR(keyword);
	if (keyword->str.len == 0)
		rts_error(VARLSTCNT(4) ERR_BADJPIPARAM, 2, 4, "Null");
	if (keyword->str.len > MAX_KEY_LEN)
		rts_error(VARLSTCNT(4)  ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr );
	lower_to_upper((uchar_ptr_t)upcase, (uchar_ptr_t)keyword->str.addr, keyword->str.len);
	if ((index = upcase[0] - 'A') < MIN_INDEX || index > MAX_INDEX)
		rts_error(VARLSTCNT(4)  ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr );
	/* Before checking if it is a VMS JPI attribute, check if it is GT.M specific "ISPROCALIVE" attribute */
	if ((keyword->str.len == STR_LIT_LEN("ISPROCALIVE")) && !memcmp(upcase, "ISPROCALIVE", keyword->str.len))
	{
		out_long = (0 != jpid) ? is_proc_alive(jpid, 0) : 1;
		i2mval(ret, out_long);
		return;
	}
	/* Check if it is a VMS JPI attribute */
	slot = jpi_index_table[ index ].index;
	last_slot = jpi_index_table[ index ].len;
	jpi_code = 0;
	/* future enhancement:
	 * 	(i) since keywords are sorted, we can exit the for loop if 0 < memcmp.
	 * 	(ii) also, the current comparison relies on kwd->str.len which means a C would imply CPUTIM instead of CSTIME
	 * 		or CUTIME this ambiguity should probably be removed by asking for an exact match of the full keyword
	 */
	for ( ; slot < last_slot ; slot++ )
	{
		if (jpi_param_table[ slot ].len == keyword->str.len
			&& !(memcmp(jpi_param_table[ slot ].name, upcase, keyword->str.len)))
		{
			jpi_code = jpi_param_table[ slot ].item_code;
			break;
		}
	}
	if (!jpi_code)
		rts_error(VARLSTCNT(4)  ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr);
	assert (jpid >= 0);
	switch( jpi_code )
	{
	/* **** This is a fall through for all codes that require a string returned **** */
	case JPI$_ACCOUNT:
	case JPI$_AUTHPRIV:
	case JPI$_CLINAME:
	case JPI$_CURPRIV:
	case JPI$_IMAGNAME:
	case JPI$_IMAGPRIV:
	case JPI$_PRCNAM:
	case JPI$_PROCPRIV:
	case JPI$_TABLENAME:
	case JPI$_TERMINAL:
	case JPI$_USERNAME:
		out_string.dsc$a_pointer = stringpool.free;
		out_string.dsc$w_length = MAX_JPI_STRLEN;
		if ((status = lib$getjpi(	 &jpi_code
						,&jpid
						,0
						,0
						,&out_string
						,&out_len	)) != SS$_NORMAL)
		{	rts_error(VARLSTCNT(1)  status ); /* need a more specific GTM error message here and below */
		}
		ret->str.addr = stringpool.free;
		ret->str.len = out_len;
		ret->mvtype = MV_STR;
		stringpool.free += out_len;
		assert (stringpool.top >= stringpool.free);
		assert (stringpool.free >= stringpool.base);
		return;
	case JPI$_LOGINTIM:
	{	int4 days;
		int4 seconds;

		if ((status = lib$getjpi(	 &jpi_code
					,&jpid
					,0
					,&out_quad
					,0
					,0	)) != SS$_NORMAL)
		{	rts_error(VARLSTCNT(1)  status );
		}
		if ((status = lib$day(	 &days
					,&out_quad
					,&seconds)) != SS$_NORMAL)
		{	rts_error(VARLSTCNT(1)  status );
		}
		days += DAYS;
		seconds /= CENTISECONDS;
		ret->str.addr = stringpool.free;
		stringpool.free = i2s(&days);
		*stringpool.free++ = ',';
		stringpool.free = i2s(&seconds);
		ret->str.len = (char *) stringpool.free - ret->str.addr;
		ret->mvtype = MV_STR;
		return;
	}
	default:
		if ((status = lib$getjpi(	 &jpi_code
						,&jpid
						,0
						,&out_long
						,0
						,0	)) != SS$_NORMAL)
		{	rts_error(VARLSTCNT(1)  status );
		}
		i2mval(ret, out_long) ;
		return;
	}
}
Example #28
0
void op_zlink(mval *v, mval *quals)
{
	struct FAB		srcfab;
	struct NAM		srcnam, objnam;
	struct XABDAT		srcxab, objxab;
	boolean_t		compile, expdir, libr, obj_found, src_found;
	short			flen;
	unsigned short		type;
	unsigned char		srccom[MAX_FN_LEN], srcnamebuf[MAX_FN_LEN], objnamebuf[MAX_FN_LEN], objnamelen, srcnamelen,ver[6];
	unsigned char		objcom[MAX_FN_LEN], list_file[MAX_FN_LEN], ceprep_file[MAX_FN_LEN], *fname;
	zro_ent			*srcdir, *objdir;
	mstr			srcstr, objstr, version;
	mval			qualifier;
	unsigned		status, srcfnb;
	uint4			lcnt, librindx, qlf;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	MV_FORCE_STR(v);
	if (MAX_FN_LEN < v->str.len)
		rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, MIN(UCHAR_MAX, v->str.len), v->str.addr, ERR_FILENAMETOOLONG);
	version.len = 0;
	srcdir = objdir = 0;
	version.addr = ver;
	libr = FALSE;
	obj_fab = cc$rms_fab;
	if (quals)
	{
		MV_FORCE_STR(quals);
		srcfab = cc$rms_fab;
		srcfab.fab$l_fna = v->str.addr;
		srcfab.fab$b_fns = v->str.len;
		srcfab.fab$l_nam = &srcnam;
		srcnam = cc$rms_nam;
		srcnam.nam$l_esa = srcnamebuf;
		srcnam.nam$b_ess = SIZEOF(srcnamebuf);
		srcnam.nam$b_nop = NAM$M_SYNCHK;
		status = sys$parse(&srcfab);
		if (!(status & 1))
			rts_error(VARLSTCNT(9) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
				ERR_FILEPARSE, 2, v->str.len, v->str.addr, status);
		if (srcnam.nam$l_fnb & NAM$M_WILDCARD)
			rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
				ERR_WILDCARD, 2, v->str.len, v->str.addr);
		srcfnb = srcnam.nam$l_fnb;
		expdir = (srcfnb & (NAM$M_NODE | NAM$M_EXP_DEV | NAM$M_EXP_DIR));
		if (srcfnb & NAM$M_EXP_VER)
		{
			memcpy(version.addr, srcnam.nam$l_ver, srcnam.nam$b_ver);
			version.len = srcnam.nam$b_ver;
		}
		if (expdir)
		{
			if (version.len)
				flen = srcnam.nam$b_esl - srcnam.nam$b_type - version.len;
			else
				flen = srcnam.nam$b_esl - srcnam.nam$b_type - 1; /* semicolon is put in by default */
			fname = srcnam.nam$l_esa;
		} else
		{
			flen = srcnam.nam$b_name;
			fname = srcnam.nam$l_name;
		}
		ENSURE_STP_FREE_SPACE(flen);
		memcpy(stringpool.free, fname, flen);
		dollar_zsource.str.addr = stringpool.free;
		dollar_zsource.str.len = flen;
		stringpool.free += flen;
		if (srcfnb & NAM$M_EXP_TYPE)
		{
			if ((SIZEOF(DOTOBJ) - 1 == srcnam.nam$b_type) &&
				!MEMCMP_LIT(srcnam.nam$l_type, DOTOBJ))
			{
				type = OBJ;
				objstr.addr = srcnam.nam$l_esa;
				objstr.len = srcnam.nam$b_esl;
			} else
			{
				type = SRC;
				memcpy(srcnamebuf, dollar_zsource.str.addr, flen);
				memcpy(&srcnamebuf[flen], srcnam.nam$l_type, srcnam.nam$b_type);
				memcpy(&srcnamebuf[flen + srcnam.nam$b_type],
					version.addr, version.len);
				srcnamelen = flen + srcnam.nam$b_type + version.len;
				srcnamebuf[srcnamelen] = 0;
				srcstr.addr = srcnamebuf;
				srcstr.len = srcnamelen;
				memcpy(objnamebuf, dollar_zsource.str.addr, flen);
				memcpy(&objnamebuf[flen], DOTOBJ, SIZEOF(DOTOBJ));
				objnamelen = flen + SIZEOF(DOTOBJ) - 1;
				objstr.addr = objnamebuf;
				objstr.len = objnamelen;
			}
		} else
		{
			type = NOTYPE;
			memcpy(srcnamebuf, dollar_zsource.str.addr, flen);
			memcpy(&srcnamebuf[flen], DOTM, SIZEOF(DOTM));
			srcnamelen = flen + SIZEOF(DOTM) - 1;
			memcpy(objnamebuf, dollar_zsource.str.addr, flen);
			MEMCPY_LIT(&objnamebuf[flen], DOTOBJ);
			memcpy(&objnamebuf[flen + SIZEOF(DOTOBJ) - 1], version.addr, version.len);
			objnamelen = flen + SIZEOF(DOTOBJ) + version.len - 1;
			objnamebuf[objnamelen] = 0;
			srcstr.addr = srcnamebuf;
			srcstr.len = srcnamelen;
			objstr.addr = objnamebuf;
			objstr.len = objnamelen;
		}
		if (!expdir)
		{
			if (OBJ == type)
			{
				zro_search(&objstr, &objdir, 0, 0);
				if (!objdir)
					rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
						ERR_FILENOTFND, 2, dollar_zsource.str.len, dollar_zsource.str.addr);
			} else  if (SRC == type)
			{
				zro_search(&objstr, &objdir, &srcstr, &srcdir);
				if (!srcdir)
					rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf,
						ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
			} else
			{
				zro_search(&objstr, &objdir, &srcstr, &srcdir);
				if (!objdir && !srcdir)
					rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
						ERR_FILENOTFND, 2, dollar_zsource.str.len, dollar_zsource.str.addr);
			}
		}
	} else
	{
		expdir = FALSE;
		type = NOTYPE;
		flen = v->str.len;
		memcpy(srcnamebuf, v->str.addr, flen);
		MEMCPY_LIT(&srcnamebuf[flen], DOTM);
		srcnamelen = flen + SIZEOF(DOTM) - 1;
		if ('%' == srcnamebuf[0])
			srcnamebuf[0] = '_';
		memcpy(objnamebuf, srcnamebuf, flen);
		MEMCPY_LIT(&objnamebuf[flen], DOTOBJ);
		objnamelen = flen + SIZEOF(DOTOBJ) - 1;
		srcstr.addr = srcnamebuf;
		srcstr.len = srcnamelen;
		objstr.addr = objnamebuf;
		objstr.len = objnamelen;
		zro_search(&objstr, &objdir, &srcstr, &srcdir);
		if (!objdir && !srcdir)
			rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
				ERR_FILENOTFND, 2, v->str.len, v->str.addr);
		qualifier.mvtype = MV_STR;
		qualifier.str = TREF(dollar_zcompile);
		quals = &qualifier;
	}
	if (OBJ == type)
	{
		obj_fab.fab$b_fac = FAB$M_GET;
		obj_fab.fab$b_shr = FAB$M_SHRGET;
		if (NULL != objdir)
		{
			if (ZRO_TYPE_OBJLIB == objdir->type)
				libr = TRUE;
			else
			{
				srcfab.fab$l_dna = objdir->str.addr;
				srcfab.fab$b_dns = objdir->str.len;
			}
		}
		for (lcnt = 0;  lcnt < MAX_FILE_OPEN_TRIES;  lcnt++)
		{
			status = (FALSE == libr) ? sys$open(&srcfab): zl_olb(&objdir->str, &objstr, &librindx);
			if (RMS$_FLK != status)
				break;
			hiber_start(WAIT_FOR_FILE_TIME);
		}
		if (FALSE == (status & 1))
			rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, status);
		if (FALSE == ((FALSE == libr) ? incr_link(&srcfab, libr) : incr_link(&librindx, libr)))
			rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, ERR_VERSION);
		status = (FALSE == libr) ? sys$close(&srcfab) : lbr$close(&librindx);
		if (FALSE == (status & 1))
			rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, status);
	} else	/* either NO type or SOURCE type */
	{
		src_found = obj_found = compile = FALSE;
		srcfab = obj_fab = cc$rms_fab;
		obj_fab.fab$l_xab = &objxab;
		srcxab = objxab = cc$rms_xabdat;
		obj_fab.fab$l_nam = &objnam;
		srcnam = objnam = cc$rms_nam;
		obj_fab.fab$l_fna = objnamebuf;
		obj_fab.fab$b_fns = objnamelen;
		obj_fab.fab$b_fac = FAB$M_GET;
		obj_fab.fab$b_shr = FAB$M_SHRGET;
		objnam.nam$l_esa = objcom;
		objnam.nam$b_ess = SIZEOF(objcom);
		srcfab.fab$l_nam = &srcnam;
		srcfab.fab$l_xab = &srcxab;
		srcfab.fab$l_fna = srcnamebuf;
		srcfab.fab$b_fns = srcnamelen;
		srcfab.fab$b_fac = FAB$M_GET;
		srcfab.fab$b_shr = FAB$M_SHRGET;
		srcnam.nam$l_esa = srccom;
		srcnam.nam$b_ess = SIZEOF(srccom);
		cmd_qlf.object_file.str.addr = objcom;
		cmd_qlf.object_file.str.len = 255;
		cmd_qlf.list_file.str.addr = list_file;
		cmd_qlf.list_file.str.len = 255;
		cmd_qlf.ceprep_file.str.addr = ceprep_file;
		cmd_qlf.ceprep_file.str.len = 255;
		if (srcdir && srcdir->str.len)
		{
			srcfab.fab$l_dna = srcdir->str.addr;
			srcfab.fab$b_dns = srcdir->str.len;
		}
		if (objdir && objdir->str.len)
		{
			if (ZRO_TYPE_OBJLIB == objdir->type)
				libr = TRUE;
			else
			{
				obj_fab.fab$l_dna = objdir->str.addr;
				obj_fab.fab$b_dns = objdir->str.len;
			}
		}
		if (SRC != type)
		{
			if (!expdir && !objdir)
				obj_found = FALSE;
			else  if (!libr)
			{
				for (lcnt = 0;  lcnt < MAX_FILE_OPEN_TRIES;  lcnt++)
				{
					status = sys$open(&obj_fab);
					if (RMS$_FLK != status)
						break;
					hiber_start(WAIT_FOR_FILE_TIME);
				}
				if (!(status & 1))
				{
					if (RMS$_FNF == status)
						obj_found = FALSE;
					else
						rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, status);
				} else
					obj_found = TRUE;
			} else
			{
				status = zl_olb(&objdir->str, &objstr, &librindx);
				if (status)
					obj_found = TRUE;
			}
		} else
			compile = TRUE;
		if (!expdir && !srcdir)
			src_found = FALSE;
		else
		{
			for (lcnt = 0;  lcnt < MAX_FILE_OPEN_TRIES;  lcnt++)
			{
				status = sys$open(&srcfab);
				if (RMS$_FLK != status)
					break;
				hiber_start(WAIT_FOR_FILE_TIME);
			}
			if (!(status & 1))
			{
				if ((RMS$_FNF == status) && (SRC != type))
					src_found = FALSE;
				else
					rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
			} else
			{
				src_found = TRUE;
				if (SRC == type)
				{
					status = sys$close(&srcfab);
					if (!(status & 1))
						rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
				}
			}
		}
		if (SRC != type)
		{
			if (src_found)
			{
				if (obj_found)
				{
					if (QUADCMP(&srcxab.xab$q_rdt, &objxab.xab$q_rdt))
					{
						status = sys$close(&obj_fab);
						obj_fab = cc$rms_fab;
						if (!(status & 1))
							rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, status);
						compile = TRUE;
					}
				} else
					compile = TRUE;
				status = sys$close(&srcfab);
				if (!(status & 1))
					rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
			} else  if (!obj_found)
				rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
					ERR_FILENOTFND, 2, objnamelen, objnamebuf);
		}
		if (compile)
		{
			zl_cmd_qlf(&quals->str, &cmd_qlf);
			if (!MV_DEFINED(&cmd_qlf.object_file))
			{
				objnam.nam$b_nop = NAM$M_SYNCHK;
				status = sys$parse(&obj_fab);
				if (!(status & 1))
					rts_error(VARLSTCNT(4) ERR_FILEPARSE, 2, obj_fab.fab$b_fns, obj_fab.fab$l_fna);
				cmd_qlf.object_file.mvtype = MV_STR;
				cmd_qlf.object_file.str.len = objnam.nam$b_esl - objnam.nam$b_ver;
			}
			qlf = cmd_qlf.qlf;
			if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
			{
				cmd_qlf.qlf = glb_cmd_qlf.qlf;
				rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
			}
			zlcompile(srcnam.nam$b_esl, srcnam.nam$l_esa);
			if ((SRC == type) && !(qlf & CQ_OBJECT))
				return;
		}
		status = libr ? incr_link(&librindx, libr) : incr_link(&obj_fab, libr);
		if (!status)	/* due only to version mismatch, so recompile */
		{
			if (!libr)
			{
				status = sys$close(&obj_fab);
				obj_fab = cc$rms_fab;
			} else
				status = lbr$close(&librindx);
			if (!(status & 1))
				rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objstr.len, objstr.addr, status);
			if (compile)
				GTMASSERT;
			if (!src_found)
				rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_VERSION);
			zl_cmd_qlf(&quals->str, &cmd_qlf);
			if (!MV_DEFINED(&cmd_qlf.object_file))
			{
				objnam.nam$b_nop = NAM$M_SYNCHK;
				status = sys$parse(&obj_fab);
				if (!(status & 1))
					rts_error(VARLSTCNT(4) ERR_FILEPARSE, 2, obj_fab.fab$b_fns, obj_fab.fab$l_fna);
				cmd_qlf.object_file.mvtype = MV_STR;
				cmd_qlf.object_file.str.len = objnam.nam$b_esl - objnam.nam$b_ver;
			}
			if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
			{
				cmd_qlf.qlf = glb_cmd_qlf.qlf;
				rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
			}
			zlcompile(srcnam.nam$b_esl, srcnam.nam$l_esa);
			if (!incr_link(&obj_fab, libr))
				GTMASSERT;
		}
		if (!libr)
		{
			status = sys$close(&obj_fab);
			obj_fab = cc$rms_fab;
		} else
			status = lbr$close(&librindx);
		if (!(status & 1))
			rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objstr.len, objstr.addr, status);
	}
	return;
}
Example #29
0
void op_zprevious(mval *v)
{
	int4			n;
	int			min_reg_index, reg_index, res;
	mname_entry		gvname;
	mval			tmpmval, *datamval;
	enum db_acc_method	acc_meth;
	boolean_t		found, ok_to_change_currkey;
	gd_binding		*gd_map_start, *map, *prev_map;
	gd_addr			*gd_targ;
	gvnh_reg_t		*gvnh_reg;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(gv_currkey->prev || !TREF(gv_last_subsc_null));
	if (gv_currkey->prev)
	{	/* If last subscript is a NULL subscript, modify gv_currkey such that a gvcst_search of the resulting gv_currkey
		 * will find the last available subscript. But in case of dba_usr, (the custom implementation of $ZPREVIOUS which
		 * is overloaded for DDP now but could be more in the future) it is better to hand over gv_currkey as it is so
		 * the custom implementation can decide what to do with it.
		 */
		acc_meth = REG_ACC_METH(gv_cur_region);
		ok_to_change_currkey = (dba_usr != acc_meth);
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Replace the last subscript with the highest possible subscript value i.e. the byte sequence
			 * 	0xFF (STR_SUB_MAXVAL), 0xFF, 0xFF ...  as much as possible i.e. until gv_currkey->top permits.
			 * This subscript is guaranteed to be NOT present in the database since a user who tried to set this
			 * exact subscripted global would have gotten a GVSUBOFLOW error (because GT.M sets aside a few bytes
			 * of padding space). And yet this is guaranteed to collate AFTER any existing subscript. Therefore we
			 * can safely do a gvcst_zprevious on this key to get at the last existing key in the database.
			 *
			 * With    standard null collation, the last subscript will be 0x01
			 * Without standard null collation, the last subscript will be 0xFF
			 * Assert that is indeed the case as this will be used to restore the replaced subscript at the end.
			 */
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			assert(!gv_cur_region->std_null_coll || (SUBSCRIPT_STDCOL_NULL == gv_currkey->base[gv_currkey->prev]));
			assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->prev + 1]);
			assert(gv_currkey->end == gv_currkey->prev + 2);
			assert(gv_currkey->end < gv_currkey->top); /* need "<" (not "<=") to account for terminating 0x00 */
			GVZPREVIOUS_APPEND_MAX_SUBS_KEY(gv_currkey, gv_target);
		}
		if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
		{
			gvnh_reg = TREF(gd_targ_gvnh_reg);
			if (NULL == gvnh_reg)
				found = (gv_target->root ? gvcst_zprevious() : FALSE);
			else
				INVOKE_GVCST_SPR_XXX(gvnh_reg, found = gvcst_spr_zprevious());
		} else if (dba_cm == acc_meth)
			found = gvcmx_zprevious();
		else
			found = gvusr_zprevious();
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			gv_altkey->prev = gv_currkey->prev;
			if (!IS_STP_SPACE_AVAILABLE(MAX_KEY_SZ))
			{
				if ((0xFF != gv_altkey->base[gv_altkey->prev])
						&& (SUBSCRIPT_STDCOL_NULL != gv_altkey->base[gv_altkey->prev]))
					n = MAX_FORM_NUM_SUBLEN;
				else
				{
					n = gv_altkey->end - gv_altkey->prev;
					assert(n > 0);
				}
				v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this (BYPASSOK)
						 * to-be-overwritten mval */
				ENSURE_STP_FREE_SPACE(n);
			}
			v->str.addr = (char *)stringpool.free;
			v->str.len = MAX_KEY_SZ;
			stringpool.free = gvsub2str(&gv_altkey->base[gv_altkey->prev], &(v->str), FALSE);
			v->str.len = INTCAST((char *)stringpool.free - v->str.addr);
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		if (TREF(gv_last_subsc_null) && ok_to_change_currkey)
		{	/* Restore gv_currkey to what it was at function entry time */
			gv_currkey->base[gv_currkey->prev + 1] = KEY_DELIMITER;
			if (gv_cur_region->std_null_coll)
				gv_currkey->base[gv_currkey->prev] = SUBSCRIPT_STDCOL_NULL;
			assert(gv_cur_region->std_null_coll || (STR_SUB_PREFIX == gv_currkey->base[gv_currkey->prev]));
			gv_currkey->end = gv_currkey->prev + 2;
			gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
		}
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
	} else
	{	/* the following section is for $ZPREVIOUS(^gname) */
		assert(2 <= gv_currkey->end);
		assert(gv_currkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end]);
		assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
		gd_targ = TREF(gd_targ_addr);
		gd_map_start = gd_targ->maps;
		map = gv_srch_map(gd_targ, (char *)&gv_currkey->base[0], gv_currkey->end - 1);
		assert(map > (gd_map_start + 1));
		/* If ^gname starts at "map" start search from map-1 since $ZPREVIOUS(^gname) is sought */
		BACK_OFF_ONE_MAP_ENTRY_IF_EDGECASE(gv_currkey->base, gv_currkey->end - 1, map);
		found = FALSE;
		/* The first map entry corresponds to local locks. The second map entry does not contain any globals.
		 * Therefore, any search for globals needs to only look after these maps. Hence the "gd_map_start + 1" below.
		 */
		for ( ; map > gd_map_start + 1; map = prev_map)
		{
			prev_map = map - 1;
			gv_cur_region = map->reg.addr;
			if (!gv_cur_region->open)
				gv_init_reg(gv_cur_region);
			change_reg();
			acc_meth = REG_ACC_METH(gv_cur_region);
			/* search region, entries in directory tree could have empty GVT in which case move on to previous entry */
			for ( ; ; )
			{
				assert(0 == gv_currkey->prev);	/* or else gvcst_zprevious could get confused */
				if ((dba_bg == acc_meth) || (dba_mm == acc_meth))
				{
					gv_target = cs_addrs->dir_tree;
					found = gvcst_zprevious();
				} else  if (dba_cm == acc_meth)
					found = gvcmx_zprevious();
				else
					found = gvusr_zprevious();
				if ('#' == gv_altkey->base[0]) /* don't want to give any hidden ^#* global, e.g "^#t" */
					found = FALSE;
				if (!found)
					break;
				assert(1 < gv_altkey->end);
				assert(gv_altkey->end < (MAX_MIDENT_LEN + 2));	/* until names are not in midents */
				res = memcmp(gv_altkey->base, prev_map->gvkey.addr, gv_altkey->end);
				assert((0 != res) || (gv_altkey->end <= prev_map->gvkey_len));
				if (0 > res)
				{	/* The global name we found is less than the maximum value in the previous map
					 * so this name is not part of the current map for sure. Move on to previous map.
					 */
					found = FALSE;
					break;
				}
				gvname.var_name.addr = (char *)gv_altkey->base;
				gvname.var_name.len = gv_altkey->end - 1;
				if (dba_cm == acc_meth)
					break;
				COMPUTE_HASH_MNAME(&gvname);
				GV_BIND_NAME_AND_ROOT_SEARCH(gd_targ, &gvname, gvnh_reg);	/* updates "gv_currkey" */
				assert((NULL != gvnh_reg->gvspan) || (gv_cur_region == map->reg.addr));
				if (NULL != gvnh_reg->gvspan)
				{	/* gv_target would NOT have been initialized by GV_BIND_NAME in this case.
					 * So finish that initialization.
					 */
					datamval = &tmpmval;
					/* The below macro finishes the task of GV_BIND_NAME_AND_ROOT_SEARCH
					 * 	(e.g. setting gv_cur_region for spanning globals)
					 */
					GV_BIND_SUBSNAME_IF_GVSPAN(gvnh_reg, gd_targ, gv_currkey, gvnh_reg->gd_reg);
					op_gvdata(datamval);
					if (MV_FORCE_INT(datamval))
						break;
				} else
				{	/* else gv_target->root would have been initialized by GV_BIND_NAME_AND_ROOT_SEARCH */
					if ((0 != gv_target->root) && (0 != gvcst_data()))
						break;
				}
			}
			if (found)
				break;
			/* If previous map corresponding to a spanning global, then do not update gv_currkey as that would
			 * effectively cause the spanning global to be skipped. If gvkey_len == gvname_len + 1 it is NOT
			 * a spanning global map entry.
			 */
			assert(prev_map->gvkey_len >= (prev_map->gvname_len + 1));
			if ((prev_map > (gd_map_start + 1)) && (prev_map->gvkey_len == (prev_map->gvname_len + 1)))
			{
				assert(strlen(prev_map->gvkey.addr) == prev_map->gvname_len);
				gv_currkey->end = prev_map->gvname_len + 1;
				assert(gv_currkey->end <= (MAX_MIDENT_LEN + 1));
				memcpy(gv_currkey->base, prev_map->gvkey.addr, gv_currkey->end);
				assert(KEY_DELIMITER == gv_currkey->base[gv_currkey->end - 1]);
				gv_currkey->base[gv_currkey->end] = KEY_DELIMITER;
				assert(gv_currkey->top > gv_currkey->end);	/* ensure we are within allocated bounds */
			}
		}
		/* Reset gv_currkey as we have potentially skipped one or more regions so we no
		 * longer can expect gv_currkey/gv_cur_region/gv_target to match each other.
		 */
		gv_currkey->end = 0;
		gv_currkey->base[0] = KEY_DELIMITER;
		v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK)
				* by this to-be-overwritten mval */
		if (found)
		{
			if (!IS_STP_SPACE_AVAILABLE(gvname.var_name.len + 1))
			{
				v->str.len = 0;	/* so stp_gcol ignores otherwise incompletely setup mval (BYPASSOK) */
				INVOKE_STP_GCOL(gvname.var_name.len + 1);
			}
			v->str.addr = (char *)stringpool.free;
			*stringpool.free++ = '^';
			memcpy(stringpool.free, gvname.var_name.addr, gvname.var_name.len);
			stringpool.free += gvname.var_name.len;
			v->str.len = gvname.var_name.len + 1;
			assert(v->str.addr < (char *)stringpool.top && v->str.addr >= (char *)stringpool.base);
			assert(v->str.addr + v->str.len <= (char *)stringpool.top &&
				v->str.addr + v->str.len >= (char *)stringpool.base);
		} else
			v->str.len = 0;
		v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */
		/* No need to restore gv_currkey (to what it was at function entry) as it is already set to NULL */
	}
	return;
}
Example #30
0
int m_write(void)
{
	char	*cp;
	int	lnx;
	mval	lit;
	mstr	*msp;
	oprtype	*oprptr, x;
	triple	*litlst[128], **llptr, **ltop, **ptx, *ref, *t1;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	llptr = litlst;
	ltop = 0;
	*llptr = 0;
	for (;;)
	{
		devctlexp = FALSE;
		switch (TREF(window_token))
		{
		case TK_ASTERISK:
			advancewindow();
			if (EXPR_FAIL == expr(&x, MUMPS_INT))
				return FALSE;
			assert(TRIP_REF == x.oprclass);
			ref = newtriple(OC_WTONE);
			ref->operand[0] = x;
			STO_LLPTR((OC_ILIT == x.oprval.tref->opcode) ? ref : 0);
			break;
		case TK_QUESTION:
		case TK_EXCLAIMATION:
		case TK_HASH:
		case TK_SLASH:
			if (!rwformat())
				return FALSE;
			STO_LLPTR(0);
			break;
		default:
			switch (expr(&x, MUMPS_STR))
			{
			case EXPR_FAIL:
				return FALSE;
			case EXPR_GOOD:
				assert(TRIP_REF == x.oprclass);
				if (devctlexp)
				{
					ref = newtriple(OC_WRITE);
					ref->operand[0] = x;
					STO_LLPTR(0);
				} else if (x.oprval.tref->opcode == OC_CAT)
					wrtcatopt(x.oprval.tref, &llptr, LITLST_TOP);
				else
				{
					ref = newtriple(OC_WRITE);
					ref->operand[0] = x;
					STO_LLPTR((OC_LIT == x.oprval.tref->opcode) ? ref : 0);
				}
				break;
			case EXPR_INDR:
				make_commarg(&x, indir_write);
				STO_LLPTR(0);
				break;
			default:
				assert(FALSE);
			}
			break;
		}
		if (TK_COMMA != TREF(window_token))
			break;
		advancewindow();
		if (LITLST_TOP <= llptr)
		{
			*++llptr = 0;
			ltop = llptr;
			llptr = 0;
		}
	}
	STO_LLPTR(0);
	if (ltop)
		llptr = ltop;
	for (ptx = litlst ; ptx < llptr ; ptx++)
	{
		if (*ptx && *(ptx + 1))
		{
			lit.mvtype = MV_STR;
			lit.str.addr = cp = (char *)stringpool.free;
			CLEAR_MVAL_BITS(&lit);
			for (t1 = ref = *ptx++ ; ref ; ref = *ptx++)
			{
				if (OC_WRITE == ref->opcode)
				{
					msp = &(ref->operand[0].oprval.tref->operand[0].oprval.mlit->v.str);
					lnx = msp->len;
					ENSURE_STP_FREE_SPACE(lnx);
					memcpy(cp, msp->addr, lnx);
					cp += lnx;
				} else
				{
					assert(OC_WTONE == ref->opcode);
					ENSURE_STP_FREE_SPACE(1);
					*cp++ = ref->operand[0].oprval.tref->operand[0].oprval.ilit;
				}
				ref->operand[0].oprval.tref->opcode = OC_NOOP;
				ref->opcode = OC_NOOP;
				ref->operand[0].oprval.tref->operand[0].oprclass = NO_REF;
				ref->operand[0].oprclass = NO_REF;
			}
			ptx--;
			stringpool.free = (unsigned char *) cp;
			lit.str.len = INTCAST(cp - lit.str.addr);
			t1->opcode = OC_WRITE;
			t1->operand[0] = put_lit(&lit);
		}
	}
	return TRUE;
}