Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.0 KiB

  1. /***
  2. *fcvt.c - convert floating point value to string
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Converts a floating point value to a string.
  8. *
  9. *Revision History:
  10. * 09-09-83 RKW written
  11. * 09-14-84 DFW fixed problems with buffer overflow and
  12. * streamlined the code
  13. * 11-09-87 BCM different interface under ifdef MTHREAD
  14. * 11-19-87 WAJ fcvt now uses emulator data area for buffer
  15. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  16. * 05-24-88 PHG Merged DLL and normal versions
  17. * 10-04-88 JCR 386: Removed 'far' keyword
  18. * 10-20-88 JCR Changed 'DOUBLE' to 'double' for 386
  19. * 03-02-90 GJF Added #include <cruntime.h>. Removed some (now) useless
  20. * preprocessor directives. Also, fixed copyright.
  21. * 03-06-90 GJF Fixed calling type, removed some leftover 16-bit
  22. * support.
  23. * 03-23-90 GJF Made _fpcvt() _CALLTYPE4 and removed prototype for
  24. * _fptostr() (now in struct.h).
  25. * 08-01-90 SBM Renamed <struct.h> to <fltintrn.h>
  26. * 09-27-90 GJF New-style function declarators.
  27. * 01-21-91 GJF ANSI naming.
  28. * 10-03-91 JCR Fixed mthread buffer allocation
  29. * 02-16-93 GJF Changed for new _getptd().
  30. * 04-06-93 SKS Replace _CRTAPI* with _cdecl
  31. * 08-05-94 JWM Insure that _ecvt returns no more than ndigits.
  32. * 09-06-94 CFW Remove Cruiser support.
  33. * 09-06-94 CFW Replace MTHREAD with _MT.
  34. * 01-10-95 CFW Debug CRT allocs.
  35. * 09-05-00 GB Changed the defination of fltout functions. Use DOUBLE
  36. * instead of double
  37. *
  38. *******************************************************************************/
  39. #include <cruntime.h>
  40. #include <fltintrn.h>
  41. #include <cvt.h>
  42. #include <mtdll.h>
  43. #include <stdlib.h>
  44. #include <dbgint.h>
  45. /*
  46. * The static character array buf[CVTBUFSIZE] is used by the _fpcvt routine
  47. * (the workhorse for _ecvt and _fcvt) for storage of its output. The routine
  48. * gcvt expects the user to have set up their own storage. CVTBUFSIZE is set
  49. * large enough to accomodate the largest double precision number plus 40
  50. * decimal places (even though you only have 16 digits of accuracy in a
  51. * double precision IEEE number, the user may ask for more to effect 0
  52. * padding; but there has to be a limit somewhere).
  53. */
  54. /*
  55. * define a maximum size for the conversion buffer. It should be at least
  56. * as long as the number of digits in the largest double precision value
  57. * (?.?e308 in IEEE arithmetic). We will use the same size buffer as is
  58. * used in the printf support routine (_output)
  59. */
  60. #ifdef _MT
  61. char * __cdecl _fpcvt(STRFLT, int, int *, int *);
  62. #else
  63. static char * __cdecl _fpcvt(STRFLT, int, int *, int *);
  64. static char buf[CVTBUFSIZE];
  65. #endif
  66. /***
  67. *char *_fcvt(value, ndec, decpr, sign) - convert floating point to char string
  68. *
  69. *Purpose:
  70. * _fcvt like _ecvt converts the value to a null terminated
  71. * string of ASCII digits, and returns a pointer to the
  72. * result. The routine prepares data for Fortran F-format
  73. * output with the number of digits following the decimal
  74. * point specified by ndec. The position of the decimal
  75. * point relative to the beginning of the string is returned
  76. * indirectly through decpt. The correct digit for Fortran
  77. * F-format is rounded.
  78. * NOTE - to avoid the possibility of generating floating
  79. * point instructions in this code we fool the compiler
  80. * about the type of the 'value' parameter using a struct.
  81. * This is OK since all we do is pass it off as a
  82. * parameter.
  83. *
  84. *Entry:
  85. * double value - number to be converted
  86. * int ndec - number of digits after decimal point
  87. *
  88. *Exit:
  89. * returns pointer to the character string representation of value.
  90. * also, the output is written into the static char array buf.
  91. * int *decpt - pointer to int with pos. of dec. point
  92. * int *sign - pointer to int with sign (0 = pos, non-0 = neg)
  93. *
  94. *Exceptions:
  95. *
  96. *******************************************************************************/
  97. char * __cdecl _fcvt (
  98. double value,
  99. int ndec,
  100. int *decpt,
  101. int *sign
  102. )
  103. {
  104. REG1 STRFLT pflt;
  105. DOUBLE *pdvalue = (DOUBLE *)&value;
  106. #ifdef _MT
  107. struct _strflt strfltstruct;
  108. char resultstring[21];
  109. /* ok to take address of stack struct here; fltout2 knows to use ss */
  110. pflt = _fltout2( *pdvalue, &strfltstruct, resultstring );
  111. #else
  112. pflt = _fltout( *pdvalue );
  113. #endif
  114. return( _fpcvt( pflt, pflt->decpt + ndec, decpt, sign ) );
  115. }
  116. /***
  117. *char *_ecvt( value, ndigit, decpt, sign ) - convert floating point to string
  118. *
  119. *Purpose:
  120. * _ecvt converts value to a null terminated string of
  121. * ASCII digits, and returns a pointer to the result.
  122. * The position of the decimal point relative to the
  123. * begining of the string is stored indirectly through
  124. * decpt, where negative means to the left of the returned
  125. * digits. If the sign of the result is negative, the
  126. * word pointed to by sign is non zero, otherwise it is
  127. * zero. The low order digit is rounded.
  128. *
  129. *Entry:
  130. * double value - number to be converted
  131. * int ndigit - number of digits after decimal point
  132. *
  133. *Exit:
  134. * returns pointer to the character representation of value.
  135. * also the output is written into the statuc char array buf.
  136. * int *decpt - pointer to int with position of decimal point
  137. * int *sign - pointer to int with sign in it (0 = pos, non-0 = neg)
  138. *
  139. *Exceptions:
  140. *
  141. *******************************************************************************/
  142. char * __cdecl _ecvt (
  143. double value,
  144. int ndigit,
  145. int *decpt,
  146. int *sign
  147. )
  148. {
  149. char *retbuf;
  150. DOUBLE *pdvalue = (DOUBLE *)&value;
  151. #ifdef _MT
  152. REG1 STRFLT pflt;
  153. struct _strflt strfltstruct; /* temporary buffers */
  154. char resultstring[21];
  155. /* ok to take address of stack struct here; fltout2 knows to use ss */
  156. pflt = _fltout2( *pdvalue, &strfltstruct, resultstring );
  157. retbuf = _fpcvt( pflt, ndigit, decpt, sign );
  158. #else
  159. retbuf = _fpcvt( _fltout(*pdvalue), ndigit, decpt, sign );
  160. #endif
  161. /* _fptostr() occasionally returns an extra character in the buffer ... */
  162. if (retbuf[ndigit])
  163. retbuf[ndigit] = '\0';
  164. return( retbuf );
  165. }
  166. /***
  167. *char *_fpcvt() - gets final string and sets decpt and sign [STATIC]
  168. *
  169. *Purpose:
  170. * This is a small common routine used by [ef]cvt. It calls fptostr
  171. * to get the final string and sets the decpt and sign indicators.
  172. *
  173. *Entry:
  174. *
  175. *Exit:
  176. *
  177. *Exceptions:
  178. *
  179. *******************************************************************************/
  180. #ifdef _MT
  181. char * __cdecl _fpcvt (
  182. #else
  183. static char * __cdecl _fpcvt (
  184. #endif
  185. REG2 STRFLT pflt,
  186. REG3 int digits,
  187. int *decpt,
  188. int *sign
  189. )
  190. {
  191. #ifdef _MT
  192. /* use a per-thread buffer */
  193. char *buf;
  194. _ptiddata ptd;
  195. ptd = _getptd();
  196. if ( ptd->_cvtbuf == NULL )
  197. if ( (ptd->_cvtbuf = _malloc_crt(CVTBUFSIZE)) == NULL )
  198. return(NULL);
  199. buf = ptd->_cvtbuf;
  200. #endif /* _MT */
  201. /* make sure we don't overflow the buffer size. If the user asks for
  202. * more digits than the buffer can handle, truncate it to the maximum
  203. * size allowed in the buffer. The maximum size is CVTBUFSIZE - 2
  204. * since we useone character for overflow and one for the terminating
  205. * null character.
  206. */
  207. _fptostr(buf, (digits > CVTBUFSIZE - 2) ? CVTBUFSIZE - 2 : digits, pflt);
  208. /* set the sign flag and decimal point position */
  209. *sign = (pflt->sign == '-') ? 1 : 0;
  210. *decpt = pflt->decpt;
  211. return(buf);
  212. }