740 lines
20 KiB
C
740 lines
20 KiB
C
|
/***
|
||
|
*cvt.c - C floating-point output conversions
|
||
|
*
|
||
|
* Copyright (c) 1987-89, Microsoft Corporation
|
||
|
*
|
||
|
*Purpose:
|
||
|
* contains routines for performing %e, %f, and %g output conversions
|
||
|
* for printf, etc.
|
||
|
*
|
||
|
* routines include _cfltcvt(), _cftoe(), _cftof(), _cftog(), _fassign(),
|
||
|
* _positive(), _cropzeros(), _forcdecpt()
|
||
|
*
|
||
|
*Revision History:
|
||
|
* 04-18-84 RN author
|
||
|
* 01-15-87 BCM corrected processing of %g formats (to handle precision
|
||
|
* as the maximum number of signifcant digits displayed)
|
||
|
* 03-24-87 BCM Evaluation Issues: (fccvt.obj version for ?LIBFA)
|
||
|
* ------------------
|
||
|
* SDS - no problem
|
||
|
* GD/TS :
|
||
|
* char g_fmt = 0; (local, initialized)
|
||
|
* int g_magnitude =0; (local, initialized)
|
||
|
* char g_round_expansion = 0; (local, initialized)
|
||
|
* STRFLT g_pflt; (local, uninitialized)
|
||
|
* other INIT :
|
||
|
* ALTMATH __fpmath() initialization (perhaps)
|
||
|
* TERM - nothing
|
||
|
* 10-22-87 BCM changes for OS/2 Support Library -
|
||
|
* including elimination of g_... static variables
|
||
|
* in favor of stack-based variables & function arguments
|
||
|
* under MTHREAD switch; changed interfaces to _cfto? routines
|
||
|
* 01-15-88 BCM remove IBMC20 switches; use only memmove, not memcpy;
|
||
|
* use just MTHREAD switch, not SS_NEQ_DGROUP
|
||
|
* 06-13-88 WAJ Fixed %.1g processing for small x
|
||
|
* 08-02-88 WAJ Made changes to _fassign() for new input().
|
||
|
* 03-09-89 WAJ Added some long double support.
|
||
|
* 06-05-89 WAJ Made changes for C6. LDOUBLE => long double
|
||
|
* 06-12-89 WAJ Renamed this file from cvtn.c to cvt.c
|
||
|
* 11-02-89 WAJ Removed register.h
|
||
|
* 06-28-90 WAJ Removed fars.
|
||
|
* 11-15-90 WAJ Added _cdecl where needed. Also "pascal" => "_pascal".
|
||
|
* 09-12-91 GDP _cdecl=>_CALLTYPE2 _pascal=>_CALLTYPE5 near=>_NEAR
|
||
|
* 04-30-92 GDP Removed floating point code. Instead used S/W routines
|
||
|
* (_atodbl, _atoflt _atoldbl), so that to avoid generation
|
||
|
* of IEEE exceptions from the lib code.
|
||
|
* 03-11-93 JWM Added minimal support for _INTL decimal point - one byte only!
|
||
|
* 07-16-93 SRW ALPHA Merge
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include <cv.h>
|
||
|
#include <nlsint.h>
|
||
|
|
||
|
#ifdef i386
|
||
|
// Uncomment this for enabling 10-byte long double string conversions
|
||
|
// #define LONG_DOUBLE
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* this routine resides in the crt32 tree */
|
||
|
extern void _fptostr(char *buf, int digits, STRFLT pflt);
|
||
|
|
||
|
|
||
|
static void _CALLTYPE5 _shift( char *s, int dist );
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
static char * _cftoe2( char * buf, int ndec, int caps, STRFLT pflt, char g_fmt );
|
||
|
static char * _cftof2( char * buf, int ndec, STRFLT pflt, char g_fmt );
|
||
|
|
||
|
#else /* not MTHREAD */
|
||
|
static char * _cftoe_g( double * pvalue, char * buf, int ndec, int caps );
|
||
|
static char * _cftof_g( double * pvalue, char * buf, int ndec );
|
||
|
#endif /* not MTHREAD */
|
||
|
|
||
|
/***
|
||
|
*_forcdecpt(buffer) - force a decimal point in floating-point output
|
||
|
*Purpose:
|
||
|
* force a decimal point in floating point output. we are only called if '#'
|
||
|
* flag is given and precision is 0; so we know the number has no '.'. insert
|
||
|
* the '.' and move everybody else back one position, until '\0' seen
|
||
|
*
|
||
|
* side effects: futzes around with the buffer, trying to insert a '.'
|
||
|
* after the initial string of digits. the first char can usually be
|
||
|
* skipped since it will be a digit or a '-'. but in the 0-precision case,
|
||
|
* the number could start with 'e' or 'E', so we'd want the '.' before the
|
||
|
* exponent in that case.
|
||
|
*
|
||
|
*Entry:
|
||
|
* buffer = (char *) pointer to buffer to modify
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns : (void)
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*******************************************************************************/
|
||
|
|
||
|
void _CALLTYPE2 _forcdecpt( char * buffer )
|
||
|
{
|
||
|
char holdchar;
|
||
|
char nextchar;
|
||
|
|
||
|
if (tolower(*buffer) != 'e'){
|
||
|
do {
|
||
|
buffer++;
|
||
|
}
|
||
|
while (isdigit(*buffer));
|
||
|
}
|
||
|
|
||
|
holdchar = *buffer;
|
||
|
|
||
|
#ifdef _INTL
|
||
|
*buffer++ = *_decimal_point;
|
||
|
#else
|
||
|
*buffer++ = '.';
|
||
|
#endif
|
||
|
|
||
|
do {
|
||
|
nextchar = *buffer;
|
||
|
*buffer = holdchar;
|
||
|
holdchar = nextchar;
|
||
|
}
|
||
|
|
||
|
while(*buffer++);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***
|
||
|
*_cropzeros(buffer) - removes trailing zeros from floating-point output
|
||
|
*Purpose:
|
||
|
* removes trailing zeros (after the '.') from floating-point output;
|
||
|
* called only when we're doing %g format, there's no '#' flag, and
|
||
|
* precision is non-zero. plays around with the buffer, looking for
|
||
|
* trailing zeros. when we find them, then we move everbody else forward
|
||
|
* so they overlay the zeros. if we eliminate the entire fraction part,
|
||
|
* then we overlay the decimal point ('.'), too.
|
||
|
*
|
||
|
* side effects: changes the buffer from
|
||
|
* [-] digit [digit...] [ . [digits...] [0...] ] [(exponent part)]
|
||
|
* to
|
||
|
* [-] digit [digit...] [ . digit [digits...] ] [(exponent part)]
|
||
|
* or
|
||
|
* [-] digit [digit...] [(exponent part)]
|
||
|
*
|
||
|
*Entry:
|
||
|
* buffer = (char *) pointer to buffer to modify
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns : (void)
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*******************************************************************************/
|
||
|
|
||
|
void _CALLTYPE2 _cropzeros( char * buf )
|
||
|
{
|
||
|
char *stop;
|
||
|
|
||
|
#ifdef _INTL
|
||
|
while (*buf && *buf != *_decimal_point)
|
||
|
#else
|
||
|
while (*buf && *buf != '.')
|
||
|
#endif
|
||
|
buf++;
|
||
|
|
||
|
if (*buf++) {
|
||
|
while (*buf && *buf != 'e' && *buf != 'E')
|
||
|
buf++;
|
||
|
|
||
|
stop = buf--;
|
||
|
|
||
|
while (*buf == '0')
|
||
|
buf--;
|
||
|
|
||
|
#ifdef _INTL
|
||
|
if (*buf == *_decimal_point)
|
||
|
#else
|
||
|
if (*buf == '.')
|
||
|
#endif
|
||
|
buf--;
|
||
|
|
||
|
while( (*++buf = *stop++) != '\0' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int _CALLTYPE2 _positive( double * arg )
|
||
|
{
|
||
|
return( (*arg >= 0.0) );
|
||
|
}
|
||
|
|
||
|
|
||
|
void _CALLTYPE2 _fassign( int flag, char * argument, char * number )
|
||
|
{
|
||
|
|
||
|
FLOAT floattemp;
|
||
|
DOUBLE doubletemp;
|
||
|
|
||
|
#ifdef LONG_DOUBLE
|
||
|
_LDOUBLE longtemp;
|
||
|
|
||
|
switch( flag ){
|
||
|
case 2:
|
||
|
_atoldbl(&longtemp, number );
|
||
|
*(_LDOUBLE UNALIGNED *)argument = longtemp;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
_atodbl( &doubletemp, number );
|
||
|
*(DOUBLE UNALIGNED *)argument = doubletemp;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
_atoflt( &floattemp, number );
|
||
|
*(FLOAT UNALIGNED *)argument = floattemp;
|
||
|
}
|
||
|
|
||
|
#else /* not LONG_DOUBLE */
|
||
|
if (flag) {
|
||
|
|
||
|
_atodbl( &doubletemp, number );
|
||
|
#if defined(_ALPHA_) && !defined(_MSC_VER)
|
||
|
/*
|
||
|
* Alpha acc does not support unaligned double yet.
|
||
|
*/
|
||
|
((long UNALIGNED *)argument)[0] = ((long *)&doubletemp)[0];
|
||
|
((long UNALIGNED *)argument)[1] = ((long *)&doubletemp)[1];
|
||
|
#else
|
||
|
*(DOUBLE UNALIGNED *)argument = doubletemp;
|
||
|
#endif
|
||
|
} else {
|
||
|
_atoflt( &floattemp, number );
|
||
|
#if defined(_ALPHA_) && !defined(_MSC_VER)
|
||
|
/*
|
||
|
* Alpha acc does not support unaligned float yet.
|
||
|
*/
|
||
|
*((long UNALIGNED *)argument) = *((long *)&floattemp);
|
||
|
#else
|
||
|
*(FLOAT UNALIGNED *)argument = floattemp;
|
||
|
#endif
|
||
|
}
|
||
|
#endif /* not LONG_DOUBLE */
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef MTHREAD
|
||
|
static char g_fmt = 0;
|
||
|
static int g_magnitude = 0;
|
||
|
static char g_round_expansion = 0;
|
||
|
static STRFLT g_pflt;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function name: _cftoe
|
||
|
*
|
||
|
* Arguments: pvalue - double * pointer
|
||
|
* buf - char * pointer
|
||
|
* ndec - int
|
||
|
* caps - int
|
||
|
*
|
||
|
* Description: _cftoe converts the double pointed to by pvalue to a null
|
||
|
* terminated string of ASCII digits in the c language
|
||
|
* printf %e format, nad returns a pointer to the result.
|
||
|
* This format has the form [-]d.ddde(+/-)ddd, where there
|
||
|
* will be ndec digits following the decimal point. If
|
||
|
* ndec <= 0, no decimal point will appear. The low order
|
||
|
* digit is rounded. If caps is nonzero then the exponent
|
||
|
* will appear as E(+/-)ddd.
|
||
|
*
|
||
|
* Side Effects: the buffer 'buf' is assumed to have a minimum length
|
||
|
* of CVTBUFSIZE (defined in cvt.h) and the routines will
|
||
|
* not write over this size.
|
||
|
*
|
||
|
* Copyright: written R.K. Wyss, Microsoft, Sept. 9, 1983
|
||
|
* copyright (c) Microsoft Corp. 1983
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
static char * _cftoe2( char * buf, int ndec, int caps, STRFLT pflt, char g_fmt )
|
||
|
#else
|
||
|
char * _CALLTYPE2 _cftoe( double * pvalue, char * buf, int ndec, int caps )
|
||
|
#endif
|
||
|
{
|
||
|
#ifndef MTHREAD
|
||
|
STRFLT pflt;
|
||
|
#endif
|
||
|
|
||
|
char *p;
|
||
|
int exp;
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
int g_magnitude = pflt->decpt - 1;
|
||
|
#endif
|
||
|
|
||
|
/* first convert the value */
|
||
|
|
||
|
/* place the output in the buffer and round. Leave space in the buffer
|
||
|
* for the '-' sign (if any) and the decimal point (if any)
|
||
|
*/
|
||
|
|
||
|
if (g_fmt) {
|
||
|
#ifndef MTHREAD
|
||
|
pflt = g_pflt;
|
||
|
#endif
|
||
|
/* shift it right one place if nec. for decimal point */
|
||
|
|
||
|
p = buf + (pflt->sign == '-');
|
||
|
_shift(p, (ndec > 0));
|
||
|
}
|
||
|
#ifndef MTHREAD
|
||
|
else {
|
||
|
pflt = _fltout(*pvalue);
|
||
|
_fptostr(buf + (pflt->sign == '-') + (ndec > 0), ndec + 1, pflt);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* now fix the number up to be in e format */
|
||
|
|
||
|
p = buf;
|
||
|
|
||
|
/* put in negative sign if needed */
|
||
|
|
||
|
if (pflt->sign == '-')
|
||
|
*p++ = '-';
|
||
|
|
||
|
/* put in decimal point if needed. Copy the first digit to the place
|
||
|
* left for it and put the decimal point in its place
|
||
|
*/
|
||
|
|
||
|
if (ndec > 0) {
|
||
|
*p = *(p+1);
|
||
|
#ifdef _INTL
|
||
|
*(++p) = *_decimal_point;
|
||
|
#else
|
||
|
*(++p) = '.';
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* find the end of the string and attach the exponent field */
|
||
|
|
||
|
p = strcpy(p+ndec+(!g_fmt), "e+000");
|
||
|
|
||
|
/* adjust exponent indicator according to caps flag and increment
|
||
|
* pointer to point to exponent sign
|
||
|
*/
|
||
|
|
||
|
if (caps)
|
||
|
*p = 'E';
|
||
|
|
||
|
p++;
|
||
|
|
||
|
/* if mantissa is zero, then the number is 0 and we are done; otherwise
|
||
|
* adjust the exponent sign (if necessary) and value.
|
||
|
*/
|
||
|
|
||
|
if (*pflt->mantissa != '0') {
|
||
|
|
||
|
/* check to see if exponent is negative; if so adjust exponent sign and
|
||
|
* exponent value.
|
||
|
*/
|
||
|
|
||
|
if( (exp = pflt->decpt - 1) < 0 ) {
|
||
|
exp = -exp;
|
||
|
*p = '-';
|
||
|
}
|
||
|
|
||
|
p++;
|
||
|
|
||
|
if (exp >= 100) {
|
||
|
*p += (char)(exp / 100);
|
||
|
exp %= 100;
|
||
|
}
|
||
|
p++;
|
||
|
|
||
|
if (exp >= 10) {
|
||
|
*p += (char)(exp / 10);
|
||
|
exp %= 10;
|
||
|
}
|
||
|
|
||
|
*++p += (char)exp;
|
||
|
}
|
||
|
|
||
|
return(buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
|
||
|
char * _CALLTYPE2 _cftoe( double * pvalue, char * buf, int ndec, int caps )
|
||
|
{
|
||
|
struct _strflt retstrflt;
|
||
|
char resstr[21];
|
||
|
STRFLT pflt = &retstrflt;
|
||
|
|
||
|
_fltout2(*pvalue, (struct _strflt *)&retstrflt,
|
||
|
(char *)resstr);
|
||
|
_fptostr(buf + (pflt->sign == '-') + (ndec > 0), ndec + 1, pflt);
|
||
|
_cftoe2(buf, ndec, caps, pflt, /* g_fmt = */ 0);
|
||
|
|
||
|
return( buf );
|
||
|
}
|
||
|
|
||
|
#else /* not MTHREAD */
|
||
|
|
||
|
static char * _cftoe_g( double * pvalue, char * buf, int ndec, int caps )
|
||
|
{
|
||
|
char *res;
|
||
|
g_fmt = 1;
|
||
|
res = _cftoe(pvalue, buf, ndec, caps);
|
||
|
g_fmt = 0;
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
#endif /* not MTHREAD */
|
||
|
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
static char * _cftof2( char * buf, int ndec, STRFLT pflt, char g_fmt )
|
||
|
|
||
|
#else
|
||
|
char * _CALLTYPE2 _cftof( double * pvalue, char * buf, int ndec )
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
#ifndef MTHREAD
|
||
|
STRFLT pflt;
|
||
|
#endif
|
||
|
|
||
|
char *p;
|
||
|
char addzero = 0;
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
int g_magnitude = pflt->decpt - 1;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* first convert the value */
|
||
|
|
||
|
/* place the output in the users buffer and round. Save space for
|
||
|
* the minus sign now if it will be needed
|
||
|
*/
|
||
|
|
||
|
if (g_fmt) {
|
||
|
#ifndef MTHREAD
|
||
|
pflt = g_pflt;
|
||
|
#endif
|
||
|
|
||
|
p = buf + (pflt->sign == '-');
|
||
|
if (g_magnitude == ndec) {
|
||
|
char *q = p + g_magnitude;
|
||
|
*q++ = '0';
|
||
|
*q = '\0';
|
||
|
/* allows for extra place-holding '0' in the exponent == precision
|
||
|
* case of the g format
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
#ifndef MTHREAD
|
||
|
else {
|
||
|
pflt = _fltout(*pvalue);
|
||
|
_fptostr(buf+(pflt->sign == '-'), ndec + pflt->decpt, pflt);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* now fix up the number to be in the correct f format */
|
||
|
|
||
|
p = buf;
|
||
|
|
||
|
/* put in negative sign, if necessary */
|
||
|
|
||
|
if (pflt->sign == '-')
|
||
|
*p++ = '-';
|
||
|
|
||
|
/* insert leading 0 for purely fractional values and position ourselves
|
||
|
* at the correct spot for inserting the decimal point
|
||
|
*/
|
||
|
|
||
|
if (pflt->decpt <= 0) {
|
||
|
_shift(p, 1);
|
||
|
*p++ = '0';
|
||
|
}
|
||
|
else
|
||
|
p += pflt->decpt;
|
||
|
|
||
|
/* put in decimal point if required and any zero padding needed */
|
||
|
|
||
|
if (ndec > 0) {
|
||
|
_shift(p, 1);
|
||
|
#ifdef _INTL
|
||
|
*p++ = *_decimal_point;
|
||
|
#else
|
||
|
*p++ = '.';
|
||
|
#endif
|
||
|
|
||
|
/* if the value is less than 1 then we may need to put 0's out in
|
||
|
* front of the first non-zero digit of the mantissa
|
||
|
*/
|
||
|
|
||
|
if (pflt->decpt < 0) {
|
||
|
if( g_fmt )
|
||
|
ndec = -pflt->decpt;
|
||
|
else
|
||
|
ndec = (ndec < -pflt->decpt ) ? ndec : -pflt->decpt;
|
||
|
_shift(p, ndec);
|
||
|
memset( p, '0', ndec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return( buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function name: _cftof
|
||
|
*
|
||
|
* Arguments: value - double * pointer
|
||
|
* buf - char * pointer
|
||
|
* ndec - int
|
||
|
*
|
||
|
* Description: _cftof converts the double pointed to by pvalue to a null
|
||
|
* terminated string of ASCII digits in the c language
|
||
|
* printf %f format, and returns a pointer to the result.
|
||
|
* This format has the form [-]ddddd.ddddd, where there will
|
||
|
* be ndec digits following the decimal point. If ndec <= 0,
|
||
|
* no decimal point will appear. The low order digit is
|
||
|
* rounded.
|
||
|
*
|
||
|
* Side Effects: the buffer 'buf' is assumed to have a minimum length
|
||
|
* of CVTBUFSIZE (defined in cvt.h) and the routines will
|
||
|
* not write over this size.
|
||
|
*
|
||
|
* Copyright: written R.K. Wyss, Microsoft, Sept. 9, 1983
|
||
|
* copyright (c) Microsoft Corp. 1983
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
|
||
|
char * _CALLTYPE2 _cftof( double * pvalue, char * buf, int ndec )
|
||
|
{
|
||
|
struct _strflt retstrflt;
|
||
|
char resstr[21];
|
||
|
STRFLT pflt = &retstrflt;
|
||
|
_fltout2(*pvalue, (struct _strflt *) &retstrflt,
|
||
|
(char *) resstr);
|
||
|
_fptostr(buf+(pflt->sign == '-'), ndec + pflt->decpt, pflt);
|
||
|
_cftof2(buf, ndec, pflt, /* g_fmt = */ 0);
|
||
|
|
||
|
return( buf );
|
||
|
}
|
||
|
|
||
|
#else /* not MTHREAD */
|
||
|
|
||
|
|
||
|
static char * _cftof_g( double * pvalue, char * buf, int ndec )
|
||
|
{
|
||
|
char *res;
|
||
|
g_fmt = 1;
|
||
|
res = _cftof(pvalue, buf, ndec);
|
||
|
g_fmt = 0;
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
#endif /* not MTHREAD */
|
||
|
|
||
|
/*
|
||
|
* Function name: _cftog
|
||
|
*
|
||
|
* Arguments: value - double * pointer
|
||
|
* buf - char * pointer
|
||
|
* ndec - int
|
||
|
*
|
||
|
* Description: _cftog converts the double pointed to by pvalue to a null
|
||
|
* terminated string of ASCII digits in the c language
|
||
|
* printf %g format, and returns a pointer to the result.
|
||
|
* The form used depends on the value converted. The printf
|
||
|
* %e form will be used if the magnitude of valude is less
|
||
|
* than -4 or is greater than ndec, otherwise printf %f will
|
||
|
* be used. ndec always specifies the number of digits
|
||
|
* following the decimal point. The low order digit is
|
||
|
* appropriately rounded.
|
||
|
*
|
||
|
* Side Effects: the buffer 'buf' is assumed to have a minimum length
|
||
|
* of CVTBUFSIZE (defined in cvt.h) and the routines will
|
||
|
* not write over this size.
|
||
|
*
|
||
|
* Copyright: written R.K. Wyss, Microsoft, Sept. 9, 1983
|
||
|
* copyright (c) Microsoft Corp. 1983
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
char * _CALLTYPE2 _cftog( double * pvalue, char * buf, int ndec, int caps )
|
||
|
{
|
||
|
char *p;
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
char g_round_expansion = 0;
|
||
|
STRFLT g_pflt;
|
||
|
int g_magnitude;
|
||
|
struct _strflt retstrflt;
|
||
|
char resstr[21];
|
||
|
|
||
|
/* first convert the number */
|
||
|
|
||
|
g_pflt = &retstrflt;
|
||
|
_fltout2(*pvalue, (struct _strflt *)&retstrflt,
|
||
|
(char *)resstr);
|
||
|
|
||
|
#else /* not MTHREAD */
|
||
|
|
||
|
/* first convert the number */
|
||
|
|
||
|
g_pflt = _fltout(*pvalue);
|
||
|
#endif /* not MTHREAD */
|
||
|
|
||
|
g_magnitude = g_pflt->decpt - 1;
|
||
|
p = buf + (g_pflt->sign == '-');
|
||
|
|
||
|
_fptostr(p, ndec, g_pflt);
|
||
|
g_round_expansion = (char)(g_magnitude < (g_pflt->decpt-1));
|
||
|
|
||
|
|
||
|
/* compute the magnitude of value */
|
||
|
|
||
|
g_magnitude = g_pflt->decpt - 1;
|
||
|
|
||
|
/* convert value to the c language g format */
|
||
|
|
||
|
if (g_magnitude < -4 || g_magnitude >= ndec){ /* use e format */
|
||
|
/* (g_round_expansion ==>
|
||
|
* extra digit will be overwritten by 'e+xxx')
|
||
|
*/
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
return(_cftoe2(buf, ndec, caps, g_pflt, /* g_fmt = */ 1));
|
||
|
#else
|
||
|
return(_cftoe_g(pvalue, buf, ndec, caps));
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
else { /* use f format */
|
||
|
if (g_round_expansion) {
|
||
|
/* throw away extra final digit from expansion */
|
||
|
while (*p++);
|
||
|
*(p-2) = '\0';
|
||
|
}
|
||
|
|
||
|
#ifdef MTHREAD
|
||
|
return(_cftof2(buf, ndec, g_pflt, /* g_fmt = */ 1));
|
||
|
#else
|
||
|
return(_cftof_g(pvalue, buf, ndec));
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*_cfltcvt(arg, buf, format, precision, caps) - convert floating-point output
|
||
|
*Purpose:
|
||
|
*
|
||
|
*Entry:
|
||
|
* arg = (double *) pointer to double-precision floating-point number
|
||
|
* buf = (char *) pointer to buffer into which to put the converted
|
||
|
* ASCII form of the number
|
||
|
* format = (int) 'e', 'f', or 'g'
|
||
|
* precision = (int) giving number of decimal places for %e and %f formats,
|
||
|
* and giving maximum number of significant digits for
|
||
|
* %g format
|
||
|
* caps = (int) flag indicating whether 'E' in exponent should be capatilized
|
||
|
* (for %E and %G formats only)
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns : (void)
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*******************************************************************************/
|
||
|
/*
|
||
|
* Function name: _cfltcvt
|
||
|
*
|
||
|
* Arguments: arg - double * pointer
|
||
|
* buf - char * pointer
|
||
|
* format - int
|
||
|
* ndec - int
|
||
|
* caps - int
|
||
|
*
|
||
|
* Description: _cfltcvt determines from the format, what routines to
|
||
|
* call to generate the correct floating point format
|
||
|
*
|
||
|
* Side Effects: none
|
||
|
*
|
||
|
* Author: Dave Weil, Jan 12, 1985
|
||
|
*
|
||
|
* Copyright: Copyright (C) Microsoft Corp. 1985
|
||
|
*/
|
||
|
|
||
|
void _CALLTYPE2 _cfltcvt( double * arg, char * buffer, int format, int precision, int caps )
|
||
|
{
|
||
|
if (format == 'e' || format == 'E')
|
||
|
_cftoe(arg, buffer, precision, caps);
|
||
|
else if (format == 'f')
|
||
|
_cftof(arg, buffer, precision);
|
||
|
else
|
||
|
_cftog(arg, buffer, precision, caps);
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*_shift(s, dist) - shift a null-terminated string in memory (internal routine)
|
||
|
*Purpose:
|
||
|
* _shift is a helper routine that shifts a null-terminated string
|
||
|
* in memory, e.g., moves part of a buffer used for floating-point output
|
||
|
*
|
||
|
* modifies memory locations (s+dist) through (s+dist+strlen(s))
|
||
|
*
|
||
|
*Entry:
|
||
|
* s = (char *) pointer to string to move
|
||
|
* dist = (int) distance to move the string to the right (if negative, to left)
|
||
|
*
|
||
|
*Exit:
|
||
|
* returns : (void)
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*******************************************************************************/
|
||
|
|
||
|
static void _CALLTYPE5 _shift( char *s, int dist )
|
||
|
{
|
||
|
if( dist )
|
||
|
memmove(s+dist, s, strlen(s)+1);
|
||
|
}
|