示例#1
0
文件: gvsub2str.c 项目: 5HT/mumps
/*
 * -----------------------------------------------------
 * Convert a string subscript to MUMPS string
 * Save result in a buffer pointed by targ.
 *
 * Entry:
 *	sub	- input string in subscript format
 *	targ	- output string buffer
 *	xlat_flg- translate flag.
 *		  If true convert string to MUMPS format
 * Return:
 *	(pointer to the last char.
 *	converted in the targ string) + 1.
 * -----------------------------------------------------
 */
unsigned char *gvsub2str(unsigned char *sub, unsigned char *targ, bool xlat_flg)
{
	unsigned char	buf1[MAX_KEY_SZ + 1], ch, *ptr, trail_ch;
	unsigned short	*tbl_ptr;
	int		expon, in_length, length, tmp;
	mstr		mstr_ch, mstr_targ;

	ch = *sub++;

	if (STR_SUB_PREFIX == ch || (SUBSCRIPT_STDCOL_NULL == ch && KEY_DELIMITER == *sub))
	{	/* If this is a string */
		if (xlat_flg)
			return gvstrsub(sub, targ);
		else
		{
			in_length = 0;
			ptr = targ;
			while ((ch = *sub++))
			{	/* Copy string to targ, xlating each char */
				in_length++;
				if (STR_SUB_ESCAPE == ch)
				/* if this is an escape, demote next char */
					ch = (*sub++ - 1);
				*targ++ = ch;
			}

			if (transform && gv_target && gv_target->collseq)
			{
				mstr_ch.len = in_length;
				mstr_ch.addr = (char *)ptr;
				mstr_targ.len = sizeof(buf1);
				mstr_targ.addr = (char *)buf1;
				do_xform(gv_target->collseq, XBACK, &mstr_ch, &mstr_targ, &length);
				memcpy(ptr, mstr_targ.addr, length); /* mstr_targ.addr is used just in case it is
								        reallocated by the XBACK routine */
				targ = ptr + length;
			}
		}
	} else
	{	/* Number */
		if (SUBSCRIPT_ZERO == ch)
			*targ++ = '0';
		else
		{
			tbl_ptr = (unsigned short *)&dpos[0] - 1;
			trail_ch = KEY_DELIMITER;
			if ((signed char)ch >= 0)
			{	/* Bit 7 of the exponent is set for positive numbers; must be negative */
				trail_ch = NEG_MNTSSA_END;
				tbl_ptr = (unsigned short *)dneg;
				ch = ~ch;
				*targ++ = '-';
			}
			ch -= (SUBSCRIPT_BIAS - 1);	/* Unbias the exponent */
			expon = ch;
			if ((signed char)ch <= 0)
			{	/* number is a fraction */
				ch = -(signed char)ch;
					/* Save decimal point */
				*targ++ = '.';
					/* generate leading 0's */
				do *targ++ = '0';
				while ((signed char)ch-- > 0)
					;
					/* make expon. really large to avoid
					 * generating extra dots */
				expon = LARGE_EXP;
			}
			while ((ch = *sub++) && ch != trail_ch)
			{	/* Convert digits loop */
					/* adjust dcm. point */
				if ((expon -= 2) <= 0)
				{
					if (0 != expon)
					{
						*targ++ = '.';
						expon = LARGE_EXP;
						PUT_USHORT(targ, tbl_ptr[ch]);
						targ += sizeof(short);
					} else
					{	/* Insert dot between digits */
						PUT_USHORT(targ, tbl_ptr[ch]);
						targ += sizeof(short);
						*targ = *(targ - 1);
						*(targ - 1) = '.';
						targ++;
						expon = LARGE_EXP;
					}
				} else
				{
					PUT_USHORT(targ, tbl_ptr[ch]);
					targ += sizeof(short);
				}
			}
			if (expon > (LARGE_EXP - 100))
			{
				if ('0' == *(targ - 1))
					targ--;
				if ('.' == *(targ - 1))
					targ--;
			} else
				while (--expon > 0)
					*targ++ = '0';
		}
	}
	return (targ);
}
示例#2
0
void op_fnorder(lv_val *src, mval *key, mval *dst)
{
	mval		tmp_sbs;
	int             length;
	boolean_t	is_canonical, is_fnnext, get_first;
	lvTree		*lvt;
	lvTreeNode	*node;
	uint4		mvt;	/* Local copy of mvtype, bit ands use a int4, so do conversion once */
	mstr		*str;
	int4		intval;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	is_fnnext = TREF(in_op_fnnext);
	TREF(in_op_fnnext) = FALSE;
	if (src && (lvt = LV_GET_CHILD(src)))	/* caution: assignment */
	{
		MV_FORCE_DEFINED(key);
		/* If last subscript is null, $ORDER returns the first subscript in that level.
		 * With the obsoleted $NEXT function, a subscript of -1 also triggers the same behavior.
		 */
		get_first = FALSE;
		if (MV_IS_STRING(key) && (0 == key->str.len))
			get_first = TRUE;
		else if (is_fnnext)
		{
			mvt = key->mvtype;
			if (!(mvt & (MV_NM | MV_NUM_APPROX)))
			{	/* Not currently in numeric form.  Is it cannonical? */
				if (val_iscan(key))
				{	/* Yes, convert it to numeric */
					(void)s2n(key);
					mvt = key->mvtype;
					if (!(mvt & MV_NM))
						rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
				} else	/* No, not numeric.  Note the fact for future reference */
					mvt = key->mvtype |= MV_NUM_APPROX;
			}
			if (MV_IS_TRUEINT(key, &intval) && (MINUS_ONE == key->m[1]))
				get_first = TRUE;
		}
		if (get_first)
			node = lvAvlTreeFirst(lvt);
		else
		{
			is_canonical = MV_IS_CANONICAL(key);
			if (!is_canonical)
			{
				assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype));
				if (TREF(local_collseq))
				{
					ALLOC_XFORM_BUFF(key->str.len);
					tmp_sbs.mvtype = MV_STR;
					tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz);
					assert(NULL != TREF(lcl_coll_xform_buff));
					tmp_sbs.str.addr = TREF(lcl_coll_xform_buff);
					do_xform(TREF(local_collseq), XFORM, &key->str, &tmp_sbs.str, &length);
					tmp_sbs.str.len = length;
					s2pool(&(tmp_sbs.str));
					key = &tmp_sbs;
				}
			} else
			{	/* Need to set canonical bit before calling tree search functions.
				 * But input mval could be read-only so cannot modify that even if temporarily.
				 * So take a copy of the mval and modify that instead.
				 */
				tmp_sbs = *key;
				key = &tmp_sbs;
				MV_FORCE_NUM(key);
				TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(key);	/* used by the lvTreeKeyNext function */
			}
			node = lvAvlTreeKeyNext(lvt, key);
		}
		/* If STDNULLCOLL, skip to the next subscript should the current subscript be "" */
		if (TREF(local_collseq_stdnull) && (NULL != node) && LV_NODE_KEY_IS_NULL_SUBS(node))
		{
			assert(LVNULLSUBS_OK == TREF(lv_null_subs));
			node = lvAvlTreeNext(node);
		}
	} else
		node = NULL;
	if (NULL == node)
	{
		if (!is_fnnext)
		{
			dst->mvtype = MV_STR;
			dst->str.len = 0;
		} else
			MV_FORCE_MVAL(dst, -1);
	} else
	{
		LV_NODE_GET_KEY(node, dst); /* Get node key into "dst" depending on the structure type of "node" */
		/* Code outside lv_tree.c does not currently know to make use of MV_CANONICAL bit so reset it
		 * until the entire codebase gets fixed to maintain MV_CANONICAL bit accurately at which point,
		 * this RESET can be removed */
		TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(dst);
		if (TREF(local_collseq) && MV_IS_STRING(dst))
		{
			ALLOC_XFORM_BUFF(dst->str.len);
			assert(NULL != TREF(lcl_coll_xform_buff));
			tmp_sbs.str.addr = TREF(lcl_coll_xform_buff);
			tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz);
			do_xform(TREF(local_collseq), XBACK, &dst->str, &tmp_sbs.str, &length);
			tmp_sbs.str.len = length;
			s2pool(&(tmp_sbs.str));
			dst->str = tmp_sbs.str;
		}
	}
}
示例#3
0
文件: op_fnorder.c 项目: 5HT/mumps
void op_fnorder(lv_val *src, mval *key, mval *dst)
{
	int			cur_subscr;
	mval			tmp_sbs;
	int             	length;
	sbs_blk			*num, *str;
	boolean_t		found, is_neg;
	int4			i;
	lv_val			**lv;
	lv_sbs_tbl		*tbl;
	sbs_search_status	status;
	boolean_t		is_fnnext;

	is_fnnext = in_op_fnnext;
	in_op_fnnext = FALSE;
	found = FALSE;
	if (src)
	{
		if (tbl = src->ptrs.val_ent.children)
		{
			MV_FORCE_DEFINED(key);
			num = tbl->num;
			str = tbl->str;
			assert(tbl->ident == MV_SBS);
			if ((MV_IS_STRING(key) && key->str.len == 0) || (is_fnnext && MV_IS_INT(key) && key->m[1] == MINUS_ONE))
			{ /* With GT.M collation , if last subscript is null, $o returns the first subscript in that level */
				if (tbl->int_flag)
				{
					assert(num);
					for (i = 0, lv = &num->ptr.lv[0]; i < SBS_NUM_INT_ELE; i++, lv++)
					{
						if (*lv)
						{
							MV_FORCE_MVAL(dst,i);
							found = TRUE;
							break;
						}
					}
				} else if (num)
				{
					assert(num->cnt);
					MV_ASGN_FLT2MVAL((*dst),num->ptr.sbs_flt[0].flt);
					found = TRUE;
				}
			} else
			{
				if (MV_IS_CANONICAL(key))
				{
					MV_FORCE_NUM(key);
					if (tbl->int_flag)
					{
						assert(num);
						is_neg = (key->mvtype & MV_INT) ? key->m[1] < 0 : key->sgn;
						if (is_neg)
							i = 0;
						else
						{
							if (!is_fnnext && (1 == numcmp(key, (mval *)&SBS_MVAL_INT_ELE)))
								i = SBS_NUM_INT_ELE;
							else
							{
								i =  MV_FORCE_INT(key);
								i++;
							}
						}
						for (lv = &num->ptr.lv[i]; i < SBS_NUM_INT_ELE; i++, lv++)
						{
							if (*lv)
							{
								MV_FORCE_MVAL(dst,i);
								found = TRUE;
								break;
							}
						}
					} else if (num && lv_nxt_num_inx(num, key, &status))
					{
						MV_ASGN_FLT2MVAL((*dst),((sbs_flt_struct*)status.ptr)->flt);
						found = TRUE;
					}
				} else
				{
					if (local_collseq)
					{
						ALLOC_XFORM_BUFF(&key->str);
						tmp_sbs.mvtype = MV_STR;
						tmp_sbs.str.len = max_lcl_coll_xform_bufsiz;
						assert(NULL != lcl_coll_xform_buff);
						tmp_sbs.str.addr = lcl_coll_xform_buff;
						do_xform(local_collseq, XFORM, &key->str,
								&tmp_sbs.str, &length);
						tmp_sbs.str.len = length;
						s2pool(&(tmp_sbs.str));
						key = &tmp_sbs;
					}
					if (str && lv_nxt_str_inx(str, &key->str, &status))
					{
						dst->mvtype = MV_STR;
						dst->str = ((sbs_str_struct *)status.ptr)->str;
					} else
					{
						if (!is_fnnext)
						{
							dst->mvtype = MV_STR;
							dst->str.len = 0;
						} else
							MV_FORCE_MVAL(dst, -1);
					}
					found = TRUE;
				}
			}
			if (!found && str)
			{	/* We are here because
				 * a. key is "" and there is no numeric subscript, OR
				 * b. key is numeric and it is >= the largest numeric subscript at this level implying a switch from
				 *    numeric to string subscripts
				 * Either case, return the first string subscript. However, for STDNULLCOLL, skip to the next
				 * subscript should the first subscript be ""
				 */
				assert(str->cnt);
				dst->mvtype = MV_STR;
				dst->str = str->ptr.sbs_str[0].str;
				found = TRUE;
				if (local_collseq_stdnull && 0 == dst->str.len)
				{
					assert(lv_null_subs);
					if (lv_nxt_str_inx(str, &dst->str, &status))
					{
						dst->str = ((sbs_str_struct*)status.ptr)->str;
					} else
						found = FALSE;
				}
			}
		}
	}
	if (!found)
	{
		if (!is_fnnext)
		{
			dst->mvtype = MV_STR;
			dst->str.len = 0;
		} else
			MV_FORCE_MVAL(dst, -1);
	} else if (dst->mvtype == MV_STR && local_collseq)
	{
		ALLOC_XFORM_BUFF(&dst->str);
		assert(NULL != lcl_coll_xform_buff);
		tmp_sbs.str.addr = lcl_coll_xform_buff;
		tmp_sbs.str.len = max_lcl_coll_xform_bufsiz;
		do_xform(local_collseq, XBACK,
				&dst->str, &tmp_sbs.str, &length);
		tmp_sbs.str.len = length;
		s2pool(&(tmp_sbs.str));
		dst->str = tmp_sbs.str;
	}
}
示例#4
0
void op_fnzprevious(lv_val *src, mval *key, mval *dst)
{
	int		cur_subscr, length;
	mval		tmp_sbs;
	lvTreeNode	*node;
	lvTree		*lvt;
	boolean_t	is_canonical, get_last;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (src && (lvt = LV_GET_CHILD(src)))	/* caution: assignment */
	{
		MV_FORCE_DEFINED(key);
		/* If last subscript is null, $zprev returns the last subscript in that level. */
		get_last = FALSE;
		if (MV_IS_STRING(key) && (0 == key->str.len))
			get_last = TRUE;
		if (get_last)
			node = lvAvlTreeLast(lvt);
		else
		{
			is_canonical = MV_IS_CANONICAL(key);
			if (!is_canonical)
			{
				assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype));
				if (TREF(local_collseq))
				{
					ALLOC_XFORM_BUFF(key->str.len);
					tmp_sbs.mvtype = MV_STR;
					tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz);
					assert(NULL != TREF(lcl_coll_xform_buff));
					tmp_sbs.str.addr = TREF(lcl_coll_xform_buff);
					do_xform(TREF(local_collseq), XFORM, &key->str, &tmp_sbs.str, &length);
					tmp_sbs.str.len = length;
					s2pool(&(tmp_sbs.str));
					key = &tmp_sbs;
				}
			} else
			{	/* Need to set canonical bit before calling tree search functions.
				 * But input mval could be read-only so cannot modify that even if temporarily.
				 * So take a copy of the mval and modify that instead.
				 */
				tmp_sbs = *key;
				key = &tmp_sbs;
				MV_FORCE_NUM(key);
				TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(key);	/* used by the lvAvlTreeKeyPrev function */
			}
			node = lvAvlTreeKeyPrev(lvt, key);
		}
		/* If STDNULLCOLL, skip to the previous subscript should the current subscript be "" */
		if (TREF(local_collseq_stdnull) && (NULL != node) && LV_NODE_KEY_IS_NULL_SUBS(node))
		{
			assert(LVNULLSUBS_OK == TREF(lv_null_subs));
			node = lvAvlTreePrev(node);
		}
	} else
		node = NULL;
	if (NULL == node)
	{
		dst->mvtype = MV_STR;
		dst->str.len = 0;
	} else
	{
		LV_NODE_GET_KEY(node, dst); /* Get node key into "dst" depending on the structure type of "node" */
		/* Code outside lv_tree.c does not currently know to make use of MV_CANONICAL bit so reset it
		 * until the entire codebase gets fixed to maintain MV_CANONICAL bit accurately at which point,
		 * this RESET can be removed */
		TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(dst);
		if (TREF(local_collseq) && MV_IS_STRING(dst))
		{
			ALLOC_XFORM_BUFF(dst->str.len);
			assert(NULL != TREF(lcl_coll_xform_buff));
			tmp_sbs.str.addr = TREF(lcl_coll_xform_buff);
			tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz);
			do_xform(TREF(local_collseq), XBACK, &dst->str, &tmp_sbs.str, &length);
			tmp_sbs.str.len = length;
			s2pool(&(tmp_sbs.str));
			dst->str = tmp_sbs.str;
		}
	}
	return;
}
示例#5
0
unsigned char *mval2subsc(mval *in_val, gv_key *out_key, boolean_t std_null_coll)
{
	boolean_t	is_negative;
	unsigned char	buf1[MAX_KEY_SZ + 1], ch, *cvt_table, *in_ptr, *out_ptr;
	unsigned char	*tm, temp_mantissa[NUM_DEC_DG_2L / 2 + 3];	/* Need 1 byte for each two digits.  Add 3 bytes slop */
	mstr		mstr_ch, mstr_buf1;
	int4		mt, mw, mx;
	uint4		mvt;	/* Local copy of mvtype, bit ands use a int4, so do conversion once */
	unsigned int	digs, exp_val;
	int		tmp_len, avail_bytes;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	/* The below assert is an attempt to catch between some and many of the cases where the mvtype is
	 * not an accurate representation of the content. This can happen (and has) when there is a bug in
	 * op_svput() where only the string portion of an mval is set without (re)setting the type leading
	 * to numeric or num-approx values that do not represent reality and causing trouble especially with
	 * subscripts. In that example, "-1" was left as a string with MV_NUM_APPROX on which caused a lot
	 * of trouble with $ORDER in a database when -1 was treated as a string. This assert is not a 100%
	 * catchall of invalid settings but it provides at least some barrier. A full barrier would require
	 * complete conversion which is a bit expensive to always re-do at this point - even in a dbg version.
	 * There is an exception though and that is if the caller is op_fnview. In that case, it could set
	 * MV_NUM_APPROX to indicate a number needs to be treated as a string subscript. Skip that in the assert.
	 */
	assert(!(MV_NUM_APPROX & in_val->mvtype) || (NUM_DEC_DG_2L < in_val->str.len) || !val_iscan(in_val)
		|| TREF(skip_mv_num_approx_assert));
	out_ptr = out_key->base + out_key->end;
	if (TREF(transform) && gv_target->nct)
	{
		MV_FORCE_STR(in_val);
		mvt = in_val->mvtype | MV_NUM_APPROX;
	} else
		mvt = (uint4)in_val->mvtype;
	if (!(mvt & (MV_NM | MV_NUM_APPROX)))
	{	/* Not currently in numeric form.  Is it cannonical? */
		if (val_iscan(in_val))
		{	/* Yes, convert it to numeric */
			(void)s2n(in_val);
			mvt = in_val->mvtype;
			assert(mvt & MV_NM);
		} else
		{	/* No, not numeric.  Note the fact for future reference */
			mvt = in_val->mvtype |= MV_NUM_APPROX;
		}
	}
	if (mvt & MV_NUM_APPROX)
	{	/* It's a string */
		in_ptr = (unsigned char *)in_val->str.addr;
		tmp_len = in_val->str.len;
		if (TREF(transform) && gv_target->collseq)
		{
			mstr_ch.len = tmp_len;
			mstr_ch.addr = (char *)in_ptr;
			mstr_buf1.len = SIZEOF(buf1);
			mstr_buf1.addr = (char *)buf1;
			do_xform(gv_target->collseq, XFORM, &mstr_ch, &mstr_buf1, &tmp_len);
			in_ptr = (unsigned char*)mstr_buf1.addr; /* mstr_buf1.addr is used just in case it is
								    reallocated by the XFORM routine */
		}
		/* Find out how much space is needed at a minimum to store the subscript representation of this string.
		 * That would be STR_SUB_PREFIX + input string + at most TWO KEY_DELIMITER.
		 * Assuming this, compute how much space would still be available in the out_key before reaching the top.
		 * If this is negative, we have to signal a GVSUBOFLOW error.
		 * If this is positive and the input string contains 0x00 or 0x01, we would need additional bytes to
		 * 	store the STR_SUB_ESCAPE byte. Decrement the available space until it becomes zero
		 *	at which point issue a GVSUBOFLOW error as well.
		 */
		avail_bytes = out_key->top - (out_key->end + tmp_len + 3);
		if (0 > avail_bytes)
			ISSUE_GVSUBOFLOW_ERROR(out_key, KEY_COMPLETE_FALSE);
		if (0 < tmp_len)
		{
			*out_ptr++ = STR_SUB_PREFIX;
			do
			{
				ch = *in_ptr++;
				if (ch <= 1)
				{
					*out_ptr++ = STR_SUB_ESCAPE;
					if (0 > --avail_bytes)
					{
						/* Ensure input key to format_targ_key is double null terminated */
						assert(STR_SUB_PREFIX == out_key->base[out_key->end]);
						out_key->base[out_key->end] = KEY_DELIMITER;
						ISSUE_GVSUBOFLOW_ERROR(out_key, KEY_COMPLETE_FALSE);
					}
					ch++;	/* promote character */
				}
				*out_ptr++ = ch;
			} while (--tmp_len > 0);
		} else
			*out_ptr++ = (0 == std_null_coll) ? STR_SUB_PREFIX : SUBSCRIPT_STDCOL_NULL;
		goto ALLDONE;
	}
	/* Its a number, is it an integer? But before this assert that we have enough allocated space in the key
	 * to store the maximum possible numeric subscript and two terminating 0s at the end of the key */
	assert((MAX_GVKEY_PADDING_LEN + 1) <= (int)(out_key->top - out_key->end));
	if (mvt & MV_INT)
	{	/* Yes, its an integer, convert it */
		is_negative = FALSE;
		cvt_table = pos_code;
		if (0 > (mt = in_val->m[1]))
		{
			is_negative = TRUE;
			cvt_table = neg_code;
			mt = -mt;
		} else  if (0 == mt)
		{
			*out_ptr++ = SUBSCRIPT_ZERO;
			goto ALLDONE;
		}
		if (10 > mt)
		{
			*out_ptr++ = is_negative ? ~(SUBSCRIPT_BIAS - 2) : (SUBSCRIPT_BIAS - 2);
			*out_ptr++ = cvt_table[mt * 10];
			goto FINISH_NUMBER;
		}
		if (100 > mt)
		{
			*out_ptr++ = is_negative ? ~(SUBSCRIPT_BIAS - 1) : (SUBSCRIPT_BIAS - 1);
			*out_ptr++ = cvt_table[mt];
			goto FINISH_NUMBER;
		}
		tm = temp_mantissa;
		if (1000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS;
			goto ODD_INTEGER;
		}
		if (10000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS + 1;
			goto EVEN_INTEGER;
		}
		if (100000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS + 2;
			goto ODD_INTEGER;
		}
		if (1000000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS + 3;
			goto EVEN_INTEGER;
		}
		if (10000000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS + 4;
			goto ODD_INTEGER;
		}
		if (100000000 > mt)
		{
			exp_val = SUBSCRIPT_BIAS + 5;
			goto EVEN_INTEGER;
		}
		exp_val = SUBSCRIPT_BIAS + 6;
ODD_INTEGER:
		*out_ptr++ = is_negative ? ~(exp_val) : (exp_val);
		mw = mx = mt / 10;
		mw *= 10;
		mw = mt - mw;
		mt = mx;
		if (mw)
		{
			*tm++ = cvt_table[mw * 10];
			goto FINISH_INTEGERS;
		}
		goto KEEP_STRIPING;
EVEN_INTEGER:
		*out_ptr++ = is_negative ? ~(exp_val) : (exp_val);
KEEP_STRIPING:
		while (mt)
		{
			mw = mx = mt / 100;
			mw *= 100;
			mw = mt - mw;
			mt = mx;
			if (mw)
			{
				*tm++ = cvt_table[mw];
				break;
			}
		}
FINISH_INTEGERS:
		while (mt)
		{
			mw = mx = mt / 100;
			mw *= 100;
			mw = mt - mw;
			*tm++ = cvt_table[mw];
			mt = mx;
		}
		while (tm > temp_mantissa)
			*out_ptr++ = *--tm;
		goto FINISH_NUMBER;
	}
	/* Convert 18 digit number */
	cvt_table = pos_code;
	if (0 != (is_negative = in_val->sgn))
		cvt_table = neg_code;
	*out_ptr++ = is_negative ? ~(in_val->e - MV_XBIAS + SUBSCRIPT_BIAS) : (in_val->e - MV_XBIAS + SUBSCRIPT_BIAS);
	mt = in_val->m[1];
	mw = in_val->m[0];
	/* Strip top two digits */
	mx = mt / (MANT_HI / 100);
	*out_ptr++ = cvt_table[mx];
	mt = (mt - (mx * (MANT_HI / 100))) * 100;
	/*
	 * The two msd's have now been converted.  The maximum number of
	 * data remaining is 7 digits in "mt" and 9 digits in "mw".
	 * If mw is zero, then we should just grind out mt till we are done
	 */
	if (0 == mw)
		goto LAST_LONGWORD;
	/* there are more than 7 digits left.  First, we will put 8 digits in mt, (leaving 8 digits in mw) */
	mx = mw / (MANT_HI / 10);
	mt += mx * 10;
	mw = (mw - (mx * (MANT_HI / 10))) * 10;
	if (0 == mw)
		goto LAST_LONGWORD;
	for (digs = 0;  digs < 4;  digs++)
	{
		mx = mt / (MANT_HI / 100);
		*out_ptr++ = cvt_table[mx];
		mt = (mt - (mx * (MANT_HI / 100))) * 100;
	}
	mt = mw;
LAST_LONGWORD:
	while (mt)
	{
		mx = mt / (MANT_HI / 100);
		*out_ptr++ = cvt_table[mx];
		mt = (mt - (mx * (MANT_HI / 100))) * 100;
	}
FINISH_NUMBER:
	if (is_negative)
		*out_ptr++ = NEG_MNTSSA_END;
ALLDONE:
	*out_ptr++ = KEY_DELIMITER;
	*out_ptr = KEY_DELIMITER;
	out_key->prev = out_key->end;
	out_key->end = out_ptr - out_key->base;
	/* Check if after adding the current subscript and the second terminating NULL byte, there is still
	 * MAX_GVKEY_PADDING_LEN bytes (allocated additionally as part of the DBKEYSIZE macro) left at the end.
	 * If not, we have overflown the original max-key-size length. Issue error.
	 */
	if ((MAX_GVKEY_PADDING_LEN + 1) > (int)(out_key->top - out_key->end))
		ISSUE_GVSUBOFLOW_ERROR(out_key, KEY_COMPLETE_FALSE);
	return out_ptr;
}