175 lines
4.0 KiB
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);
|
|
}
|