mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
415 lines
7.9 KiB
C++
415 lines
7.9 KiB
C++
|
|
/*
|
|
* M_APM - mapm_fpf.c
|
|
*
|
|
* Copyright (C) 2001 - 2007 Michael C. Ring
|
|
*
|
|
* Permission to use, copy, and distribute this software and its
|
|
* documentation for any purpose with or without fee is hereby granted,
|
|
* provided that the above copyright notice appear in all copies and
|
|
* that both that copyright notice and this permission notice appear
|
|
* in supporting documentation.
|
|
*
|
|
* Permission to modify the software is granted. Permission to distribute
|
|
* the modified code is granted. Modifications are to be distributed by
|
|
* using the file 'license.txt' as a template to modify the file header.
|
|
* 'license.txt' is available in the official MAPM distribution.
|
|
*
|
|
* This software is provided "as is" without express or implied warranty.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* This file contains the Fixed Point Formatting functions
|
|
*
|
|
*/
|
|
|
|
#include "pgAdmin3.h"
|
|
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
|
|
#include <ctype.h>
|
|
|
|
/****************************************************************************/
|
|
char *m_apm_to_fixpt_stringexp(int dplaces, M_APM atmp,
|
|
char ch_radx, char ch_sep, int ct_sep)
|
|
{
|
|
int places, xp, dl, ii;
|
|
char *cpr;
|
|
|
|
places = dplaces;
|
|
|
|
dl = atmp->m_apm_datalength;
|
|
xp = atmp->m_apm_exponent;
|
|
|
|
if (places < 0) /* show ALL digits */
|
|
{
|
|
if (xp < 0)
|
|
ii = dl - xp;
|
|
else
|
|
{
|
|
if (dl > xp)
|
|
ii = dl;
|
|
else
|
|
ii = xp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ii = places;
|
|
|
|
if (xp > 0)
|
|
ii += xp;
|
|
}
|
|
|
|
if (ct_sep != 0 && ch_sep != 0 && xp > 0)
|
|
ii += xp / ct_sep;
|
|
|
|
if ((cpr = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL)
|
|
return(NULL);
|
|
|
|
m_apm_to_fixpt_stringex(cpr, places, atmp, ch_radx, ch_sep, ct_sep);
|
|
|
|
return(cpr);
|
|
}
|
|
/****************************************************************************/
|
|
void m_apm_to_fixpt_stringex(char *s, int dplaces, M_APM atmp,
|
|
char ch_radix, char ch_sep, int count_sep)
|
|
{
|
|
M_APM btmp;
|
|
char ch, *cpd, *cps;
|
|
int ii, jj, kk, ct, dl, xp, no_sep_flg, places;
|
|
|
|
btmp = M_get_stack_var();
|
|
places = dplaces;
|
|
cpd = s;
|
|
no_sep_flg = FALSE;
|
|
|
|
m_apm_absolute_value(btmp, atmp); /* do conversion of positive number */
|
|
|
|
if (ch_sep == 0 || count_sep == 0) /* no separator char OR count */
|
|
no_sep_flg = TRUE;
|
|
|
|
/* determine how much memory to get for the temp string */
|
|
|
|
dl = btmp->m_apm_datalength;
|
|
xp = btmp->m_apm_exponent;
|
|
|
|
if (places < 0) /* show ALL digits */
|
|
{
|
|
if (xp < 0)
|
|
ii = dl - xp;
|
|
else
|
|
{
|
|
if (dl > xp)
|
|
ii = dl;
|
|
else
|
|
ii = xp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ii = places;
|
|
|
|
if (xp > 0)
|
|
ii += xp;
|
|
}
|
|
|
|
if ((cps = (char *)MAPM_MALLOC((ii + 32) * sizeof(char))) == NULL)
|
|
{
|
|
/* fatal, this does not return */
|
|
|
|
M_apm_log_error_msg(M_APM_FATAL,
|
|
"\'m_apm_to_fixpt_stringex\', Out of memory");
|
|
}
|
|
|
|
m_apm_to_fixpt_string(cps, places, btmp);
|
|
|
|
/*
|
|
* the converted string may be all 'zero', 0.0000...
|
|
* if so and the original number is negative,
|
|
* do NOT set the '-' sign of our output string.
|
|
*/
|
|
|
|
if (atmp->m_apm_sign == -1) /* if input number negative */
|
|
{
|
|
kk = 0;
|
|
jj = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
ch = cps[kk++];
|
|
if ((ch == '\0') || (jj != 0))
|
|
break;
|
|
|
|
if (isdigit((int)ch))
|
|
{
|
|
if (ch != '0')
|
|
jj = 1;
|
|
}
|
|
}
|
|
|
|
if (jj)
|
|
*cpd++ = '-';
|
|
}
|
|
|
|
ct = M_strposition(cps, (char *) "."); /* find the default (.) radix char */
|
|
|
|
if (ct == -1) /* if not found .. */
|
|
{
|
|
strcat(cps, "."); /* add one */
|
|
ct = M_strposition(cps, (char *) "."); /* and then find it */
|
|
}
|
|
|
|
if (places == 0) /* int format, terminate at radix char */
|
|
cps[ct] = '\0';
|
|
else
|
|
cps[ct] = ch_radix; /* assign the radix char */
|
|
|
|
/*
|
|
* if the number is small enough to not have any separator char's ...
|
|
*/
|
|
|
|
if (ct <= count_sep)
|
|
no_sep_flg = TRUE;
|
|
|
|
if (no_sep_flg)
|
|
{
|
|
strcpy(cpd, cps);
|
|
}
|
|
else
|
|
{
|
|
jj = 0;
|
|
kk = count_sep;
|
|
ii = ct / count_sep;
|
|
|
|
if ((ii = ct - ii * count_sep) == 0)
|
|
ii = count_sep;
|
|
|
|
while (TRUE) /* write out the first 1,2 */
|
|
{
|
|
/* (up to count_sep) digits */
|
|
*cpd++ = cps[jj++];
|
|
|
|
if (--ii == 0)
|
|
break;
|
|
}
|
|
|
|
while (TRUE) /* write rest of the string */
|
|
{
|
|
if (kk == count_sep) /* write a new separator char */
|
|
{
|
|
if (jj != ct) /* unless we're at the radix */
|
|
{
|
|
*cpd++ = ch_sep; /* note that this also disables */
|
|
kk = 0; /* the separator char AFTER */
|
|
} /* the radix char */
|
|
}
|
|
|
|
if ((*cpd++ = cps[jj++]) == '\0')
|
|
break;
|
|
|
|
kk++;
|
|
}
|
|
}
|
|
|
|
MAPM_FREE(cps);
|
|
M_restore_stack(1);
|
|
}
|
|
/****************************************************************************/
|
|
void m_apm_to_fixpt_string(char *ss, int dplaces, M_APM mtmp)
|
|
{
|
|
M_APM ctmp;
|
|
void *vp;
|
|
int places, i2, ii, jj, kk, xp, dl, numb;
|
|
UCHAR *ucp, numdiv, numrem;
|
|
char *cpw, *cpd, sbuf[128];
|
|
|
|
ctmp = M_get_stack_var();
|
|
vp = NULL;
|
|
cpd = ss;
|
|
places = dplaces;
|
|
|
|
/* just want integer portion if places == 0 */
|
|
|
|
if (places == 0)
|
|
{
|
|
if (mtmp->m_apm_sign >= 0)
|
|
m_apm_add(ctmp, mtmp, MM_0_5);
|
|
else
|
|
m_apm_subtract(ctmp, mtmp, MM_0_5);
|
|
|
|
m_apm_to_integer_string(cpd, ctmp);
|
|
|
|
M_restore_stack(1);
|
|
return;
|
|
}
|
|
|
|
if (places > 0)
|
|
M_apm_round_fixpt(ctmp, places, mtmp);
|
|
else
|
|
m_apm_copy(ctmp, mtmp); /* show ALL digits */
|
|
|
|
if (ctmp->m_apm_sign == 0) /* result is 0 */
|
|
{
|
|
if (places < 0)
|
|
{
|
|
cpd[0] = '0'; /* "0.0" */
|
|
cpd[1] = '.';
|
|
cpd[2] = '0';
|
|
cpd[3] = '\0';
|
|
}
|
|
else
|
|
{
|
|
memset(cpd, '0', (places + 2)); /* pre-load string with all '0' */
|
|
cpd[1] = '.';
|
|
cpd[places + 2] = '\0';
|
|
}
|
|
|
|
M_restore_stack(1);
|
|
return;
|
|
}
|
|
|
|
xp = ctmp->m_apm_exponent;
|
|
dl = ctmp->m_apm_datalength;
|
|
numb = (dl + 1) >> 1;
|
|
|
|
if (places < 0)
|
|
{
|
|
if (dl > xp)
|
|
jj = dl + 16;
|
|
else
|
|
jj = xp + 16;
|
|
}
|
|
else
|
|
{
|
|
jj = places + 16;
|
|
|
|
if (xp > 0)
|
|
jj += xp;
|
|
}
|
|
|
|
if (jj > 112)
|
|
{
|
|
if ((vp = (void *)MAPM_MALLOC((jj + 16) * sizeof(char))) == NULL)
|
|
{
|
|
/* fatal, this does not return */
|
|
|
|
M_apm_log_error_msg(M_APM_FATAL,
|
|
"\'m_apm_to_fixpt_string\', Out of memory");
|
|
}
|
|
|
|
cpw = (char *)vp;
|
|
}
|
|
else
|
|
{
|
|
cpw = sbuf;
|
|
}
|
|
|
|
/*
|
|
* at this point, the number is non-zero and the output
|
|
* string will contain at least 1 significant digit.
|
|
*/
|
|
|
|
if (ctmp->m_apm_sign == -1) /* negative number */
|
|
{
|
|
*cpd++ = '-';
|
|
}
|
|
|
|
ucp = ctmp->m_apm_data;
|
|
ii = 0;
|
|
|
|
/* convert MAPM num to ASCII digits and store in working char array */
|
|
|
|
while (TRUE)
|
|
{
|
|
M_get_div_rem_10((int)(*ucp++), &numdiv, &numrem);
|
|
|
|
cpw[ii++] = numdiv + '0';
|
|
cpw[ii++] = numrem + '0';
|
|
|
|
if (--numb == 0)
|
|
break;
|
|
}
|
|
|
|
i2 = ii; /* save for later */
|
|
|
|
if (places < 0) /* show ALL digits */
|
|
{
|
|
places = dl - xp;
|
|
|
|
if (places < 1)
|
|
places = 1;
|
|
}
|
|
|
|
/* pad with trailing zeros if needed */
|
|
|
|
kk = xp + places + 2 - ii;
|
|
|
|
if (kk > 0)
|
|
memset(&cpw[ii], '0', kk);
|
|
|
|
if (xp > 0) /* |num| >= 1, NO lead-in "0.nnn" */
|
|
{
|
|
ii = xp + places + 1;
|
|
jj = 0;
|
|
|
|
for (kk = 0; kk < ii; kk++)
|
|
{
|
|
if (kk == xp)
|
|
cpd[jj++] = '.';
|
|
|
|
cpd[jj++] = cpw[kk];
|
|
}
|
|
|
|
cpd[ii] = '\0';
|
|
}
|
|
else /* |num| < 1, have lead-in "0.nnn" */
|
|
{
|
|
jj = 2 - xp;
|
|
ii = 2 + places;
|
|
memset(cpd, '0', (ii + 1)); /* pre-load string with all '0' */
|
|
cpd[1] = '.'; /* assign decimal point */
|
|
|
|
for (kk = 0; kk < i2; kk++)
|
|
{
|
|
cpd[jj++] = cpw[kk];
|
|
}
|
|
|
|
cpd[ii] = '\0';
|
|
}
|
|
|
|
if (vp != NULL)
|
|
MAPM_FREE(vp);
|
|
|
|
M_restore_stack(1);
|
|
}
|
|
/****************************************************************************/
|
|
void M_apm_round_fixpt(M_APM btmp, int places, M_APM atmp)
|
|
{
|
|
int xp, ii;
|
|
|
|
xp = atmp->m_apm_exponent;
|
|
ii = xp + places - 1;
|
|
|
|
M_set_to_zero(btmp); /* assume number is too small so the net result is 0 */
|
|
|
|
if (ii >= 0)
|
|
{
|
|
m_apm_round(btmp, ii, atmp);
|
|
}
|
|
else
|
|
{
|
|
if (ii == -1) /* next digit is significant which may round up */
|
|
{
|
|
if (atmp->m_apm_data[0] >= 50) /* digit >= 5, round up */
|
|
{
|
|
m_apm_copy(btmp, atmp);
|
|
btmp->m_apm_data[0] = 10;
|
|
btmp->m_apm_exponent += 1;
|
|
btmp->m_apm_datalength = 1;
|
|
M_apm_normalize(btmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/****************************************************************************/
|
|
|