fis-gtm/sr_port/op_fnfnumber.c

175 lines
4.0 KiB
C

/****************************************************************
* *
* Copyright 2001, 2012 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_string.h"
#include "stringpool.h"
#include "op.h"
#define PLUS 1
#define MINUS 2
#define TRAIL 4
#define COMMA 8
#define PAREN 16
#define FNERROR 7
GBLREF spdesc stringpool;
LITREF mval literal_zero;
error_def(ERR_FNARGINC);
error_def(ERR_FNUMARG);
void op_fnfnumber(mval *src, mval *fmt, boolean_t use_fract, int fract, mval *dst)
{
boolean_t comma, paren;
int ct, x, xx, y, z;
mval t_src, *t_src_p;
unsigned char *ch, *cp, *ff, *ff_top, fncode, sign, *t;
if (!MV_DEFINED(fmt)) /* catch this up front so noundef mode can't cause trouble - so fmt no empty context */
rts_error(VARLSTCNT(2) ERR_FNUMARG, 0);
t_src_p = &t_src; /* operate on src in a temp, so conversions are possible without modifying src */
*t_src_p = *src;
if (use_fract)
op_fnj3(t_src_p, 0, fract, t_src_p);
else if (MV_DEFINED(t_src_p))
{ /* if the source operand is not a canonical number, force conversion */
MV_FORCE_NUM(t_src_p);
MV_FORCE_CANONICAL(t_src_p);
} else
t_src_p = underr(t_src_p);
assert (stringpool.free >= stringpool.base);
assert (stringpool.free <= stringpool.top);
/* assure 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);
MV_FORCE_STR(fmt);
MV_FORCE_STR(t_src_p);
if (0 == fmt->str.len)
{
*dst = *t_src_p;
return;
}
ch = (unsigned char *)t_src_p->str.addr;
ct = t_src_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(t_src_p);
if ((0 == (t_src_p->mvtype & MV_INT)) || (0 != t_src_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 ( ; (0 != (x / 3)); 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;
}
assertpro(FALSE);
}