Leaked source code of windows server 2003
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.

708 lines
18 KiB

  1. /***
  2. *cvt.c - C floating-point output conversions
  3. *
  4. * Copyright (c) 1983-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * contains routines for performing %e, %f, and %g output conversions
  8. * for printf, etc.
  9. *
  10. * routines include _cfltcvt(), _cftoe(), _cftof(), _cftog(),
  11. * _fassign(), _positive(), _cropzeros(), _forcdecpt()
  12. *
  13. *Revision History:
  14. * 04-18-84 RN author
  15. * 01-15-87 BCM corrected processing of %g formats (to handle precision
  16. * as the maximum number of signifcant digits displayed)
  17. * 03-24-87 BCM Evaluation Issues: (fccvt.obj version for ?LIBFA)
  18. * ------------------
  19. * SDS - no problem
  20. * GD/TS :
  21. * char g_fmt = 0; (local, initialized)
  22. * int g_magnitude =0; (local, initialized)
  23. * char g_round_expansion = 0; (local, initialized)
  24. * STRFLT g_pflt; (local, uninitialized)
  25. * other INIT :
  26. * ALTMATH __fpmath() initialization (perhaps)
  27. * TERM - nothing
  28. * 10-22-87 BCM changes for OS/2 Support Library -
  29. * including elimination of g_... static variables
  30. * in favor of stack-based variables & function arguments
  31. * under MTHREAD switch; changed interfaces to _cfto? routines
  32. * 01-15-88 BCM remove IBMC20 switches; use only memmove, not memcpy;
  33. * use just MTHREAD switch, not SS_NEQ_DGROUP
  34. * 06-13-88 WAJ Fixed %.1g processing for small x
  35. * 08-02-88 WAJ Made changes to _fassign() for new input().
  36. * 03-09-89 WAJ Added some long double support.
  37. * 06-05-89 WAJ Made changes for C6. LDOUBLE => long double
  38. * 06-12-89 WAJ Renamed this file from cvtn.c to cvt.c
  39. * 11-02-89 WAJ Removed register.h
  40. * 06-28-90 WAJ Removed fars.
  41. * 11-15-90 WAJ Added _cdecl where needed. Also "pascal" => "_pascal".
  42. * 09-12-91 GDP _cdecl=>_CALLTYPE2 _pascal=>_CALLTYPE5 near=>_NEAR
  43. * 04-30-92 GDP Removed floating point code. Instead used S/W routines
  44. * (_atodbl, _atoflt _atoldbl), so that to avoid
  45. * generation of IEEE exceptions from the lib code.
  46. * 03-11-93 JWM Added minimal support for _INTL decimal point - one byte only!
  47. * 04-06-93 SKS Replace _CALLTYPE* with __cdecl
  48. * 07-16-93 SRW ALPHA Merge
  49. * 11-15-93 GJF Merged in NT SDK version ("ALPHA merge" stuff). Also,
  50. * dropped support of Alpha acc compier, replaced i386
  51. * with _M_IX86, replaced MTHREAD with _MT.
  52. * 09-06-94 CFW Remove _INTL switch.
  53. * 09-05-00 GB Changed the defination of fltout functions. Use DOUBLE
  54. * instead of double
  55. *
  56. *******************************************************************************/
  57. #include <ctype.h>
  58. #include <string.h>
  59. #include <math.h>
  60. #include <cv.h>
  61. #include <nlsint.h>
  62. #ifdef _M_IX86
  63. /* Uncomment this for enabling 10-byte long double string conversions */
  64. /* #define LONG_DOUBLE */
  65. #endif
  66. /* this routine resides in the crt32 tree */
  67. extern void _fptostr(char *buf, int digits, STRFLT pflt);
  68. static void _CALLTYPE5 _shift( char *s, int dist );
  69. #ifdef _MT
  70. static char * _cftoe2( char * buf, int ndec, int caps, STRFLT pflt, char g_fmt );
  71. static char * _cftof2( char * buf, int ndec, STRFLT pflt, char g_fmt );
  72. #else /* not _MT */
  73. static char * _cftoe_g( double * pvalue, char * buf, int ndec, int caps );
  74. static char * _cftof_g( double * pvalue, char * buf, int ndec );
  75. #endif /* not _MT */
  76. /***
  77. *_forcdecpt(buffer) - force a decimal point in floating-point output
  78. *Purpose:
  79. * force a decimal point in floating point output. we are only called if '#'
  80. * flag is given and precision is 0; so we know the number has no '.'. insert
  81. * the '.' and move everybody else back one position, until '\0' seen
  82. *
  83. * side effects: futzes around with the buffer, trying to insert a '.'
  84. * after the initial string of digits. the first char can usually be
  85. * skipped since it will be a digit or a '-'. but in the 0-precision case,
  86. * the number could start with 'e' or 'E', so we'd want the '.' before the
  87. * exponent in that case.
  88. *
  89. *Entry:
  90. * buffer = (char *) pointer to buffer to modify
  91. *
  92. *Exit:
  93. * returns : (void)
  94. *
  95. *Exceptions:
  96. *******************************************************************************/
  97. void __cdecl _forcdecpt( char * buffer )
  98. {
  99. char holdchar;
  100. char nextchar;
  101. if (tolower(*buffer) != 'e'){
  102. do {
  103. buffer++;
  104. }
  105. while (isdigit(*buffer));
  106. }
  107. holdchar = *buffer;
  108. *buffer++ = *__decimal_point;
  109. do {
  110. nextchar = *buffer;
  111. *buffer = holdchar;
  112. holdchar = nextchar;
  113. }
  114. while(*buffer++);
  115. }
  116. /***
  117. *_cropzeros(buffer) - removes trailing zeros from floating-point output
  118. *Purpose:
  119. * removes trailing zeros (after the '.') from floating-point output;
  120. * called only when we're doing %g format, there's no '#' flag, and
  121. * precision is non-zero. plays around with the buffer, looking for
  122. * trailing zeros. when we find them, then we move everbody else forward
  123. * so they overlay the zeros. if we eliminate the entire fraction part,
  124. * then we overlay the decimal point ('.'), too.
  125. *
  126. * side effects: changes the buffer from
  127. * [-] digit [digit...] [ . [digits...] [0...] ] [(exponent part)]
  128. * to
  129. * [-] digit [digit...] [ . digit [digits...] ] [(exponent part)]
  130. * or
  131. * [-] digit [digit...] [(exponent part)]
  132. *
  133. *Entry:
  134. * buffer = (char *) pointer to buffer to modify
  135. *
  136. *Exit:
  137. * returns : (void)
  138. *
  139. *Exceptions:
  140. *******************************************************************************/
  141. void __cdecl _cropzeros( char * buf )
  142. {
  143. char *stop;
  144. while (*buf && *buf != *__decimal_point)
  145. buf++;
  146. if (*buf++) {
  147. while (*buf && *buf != 'e' && *buf != 'E')
  148. buf++;
  149. stop = buf--;
  150. while (*buf == '0')
  151. buf--;
  152. if (*buf == *__decimal_point)
  153. buf--;
  154. while( (*++buf = *stop++) != '\0' );
  155. }
  156. }
  157. int __cdecl _positive( double * arg )
  158. {
  159. return( (*arg >= 0.0) );
  160. }
  161. void __cdecl _fassign( int flag, char * argument, char * number )
  162. {
  163. FLOAT floattemp;
  164. DOUBLE doubletemp;
  165. #ifdef LONG_DOUBLE
  166. _LDOUBLE longtemp;
  167. switch( flag ){
  168. case 2:
  169. _atoldbl( &longtemp, number );
  170. *(_LDOUBLE UNALIGNED *)argument = longtemp;
  171. break;
  172. case 1:
  173. _atodbl( &doubletemp, number );
  174. *(DOUBLE UNALIGNED *)argument = doubletemp;
  175. break;
  176. default:
  177. _atoflt( &floattemp, number );
  178. *(FLOAT UNALIGNED *)argument = floattemp;
  179. }
  180. #else /* not LONG_DOUBLE */
  181. if (flag) {
  182. _atodbl( &doubletemp, number );
  183. *(DOUBLE UNALIGNED *)argument = doubletemp;
  184. } else {
  185. _atoflt( &floattemp, number );
  186. *(FLOAT UNALIGNED *)argument = floattemp;
  187. }
  188. #endif /* not LONG_DOUBLE */
  189. }
  190. #ifndef _MT
  191. static char g_fmt = 0;
  192. static int g_magnitude = 0;
  193. static char g_round_expansion = 0;
  194. static STRFLT g_pflt;
  195. #endif
  196. /*
  197. * Function name: _cftoe
  198. *
  199. * Arguments: pvalue - double * pointer
  200. * buf - char * pointer
  201. * ndec - int
  202. * caps - int
  203. *
  204. * Description: _cftoe converts the double pointed to by pvalue to a null
  205. * terminated string of ASCII digits in the c language
  206. * printf %e format, nad returns a pointer to the result.
  207. * This format has the form [-]d.ddde(+/-)ddd, where there
  208. * will be ndec digits following the decimal point. If
  209. * ndec <= 0, no decimal point will appear. The low order
  210. * digit is rounded. If caps is nonzero then the exponent
  211. * will appear as E(+/-)ddd.
  212. *
  213. * Side Effects: the buffer 'buf' is assumed to have a minimum length
  214. * of CVTBUFSIZE (defined in cvt.h) and the routines will
  215. * not write over this size.
  216. *
  217. * Author: written R.K. Wyss, Microsoft, Sept. 9, 1983
  218. *
  219. * History:
  220. *
  221. */
  222. #ifdef _MT
  223. static char * _cftoe2( char * buf, int ndec, int caps, STRFLT pflt, char g_fmt )
  224. #else
  225. char * __cdecl _cftoe( double * pvalue, char * buf, int ndec, int caps )
  226. #endif
  227. {
  228. #ifndef _MT
  229. STRFLT pflt;
  230. DOUBLE *pdvalue = (DOUBLE *)pvalue;
  231. #endif
  232. char *p;
  233. int exp;
  234. /* first convert the value */
  235. /* place the output in the buffer and round. Leave space in the buffer
  236. * for the '-' sign (if any) and the decimal point (if any)
  237. */
  238. if (g_fmt) {
  239. #ifndef _MT
  240. pflt = g_pflt;
  241. #endif
  242. /* shift it right one place if nec. for decimal point */
  243. p = buf + (pflt->sign == '-');
  244. _shift(p, (ndec > 0));
  245. }
  246. #ifndef _MT
  247. else {
  248. pflt = _fltout(*pdvalue);
  249. _fptostr(buf + (pflt->sign == '-') + (ndec > 0), ndec + 1, pflt);
  250. }
  251. #endif
  252. /* now fix the number up to be in e format */
  253. p = buf;
  254. /* put in negative sign if needed */
  255. if (pflt->sign == '-')
  256. *p++ = '-';
  257. /* put in decimal point if needed. Copy the first digit to the place
  258. * left for it and put the decimal point in its place
  259. */
  260. if (ndec > 0) {
  261. *p = *(p+1);
  262. *(++p) = *__decimal_point;
  263. }
  264. /* find the end of the string and attach the exponent field */
  265. p = strcpy(p+ndec+(!g_fmt), "e+000");
  266. /* adjust exponent indicator according to caps flag and increment
  267. * pointer to point to exponent sign
  268. */
  269. if (caps)
  270. *p = 'E';
  271. p++;
  272. /* if mantissa is zero, then the number is 0 and we are done; otherwise
  273. * adjust the exponent sign (if necessary) and value.
  274. */
  275. if (*pflt->mantissa != '0') {
  276. /* check to see if exponent is negative; if so adjust exponent sign and
  277. * exponent value.
  278. */
  279. if( (exp = pflt->decpt - 1) < 0 ) {
  280. exp = -exp;
  281. *p = '-';
  282. }
  283. p++;
  284. if (exp >= 100) {
  285. *p += (char)(exp / 100);
  286. exp %= 100;
  287. }
  288. p++;
  289. if (exp >= 10) {
  290. *p += (char)(exp / 10);
  291. exp %= 10;
  292. }
  293. *++p += (char)exp;
  294. }
  295. return(buf);
  296. }
  297. #ifdef _MT
  298. char * __cdecl _cftoe( double * pvalue, char * buf, int ndec, int caps )
  299. {
  300. struct _strflt retstrflt;
  301. char resstr[21];
  302. DOUBLE *pdvalue = (DOUBLE *)pvalue;
  303. STRFLT pflt = &retstrflt;
  304. _fltout2(*pdvalue, (struct _strflt *)&retstrflt,
  305. (char *)resstr);
  306. _fptostr(buf + (pflt->sign == '-') + (ndec > 0), ndec + 1, pflt);
  307. _cftoe2(buf, ndec, caps, pflt, /* g_fmt = */ 0);
  308. return( buf );
  309. }
  310. #else /* not _MT */
  311. static char * _cftoe_g( double * pvalue, char * buf, int ndec, int caps )
  312. {
  313. char *res;
  314. g_fmt = 1;
  315. res = _cftoe(pvalue, buf, ndec, caps);
  316. g_fmt = 0;
  317. return (res);
  318. }
  319. #endif /* not _MT */
  320. #ifdef _MT
  321. static char * _cftof2( char * buf, int ndec, STRFLT pflt, char g_fmt )
  322. #else
  323. char * __cdecl _cftof( double * pvalue, char * buf, int ndec )
  324. #endif
  325. {
  326. #ifndef _MT
  327. STRFLT pflt;
  328. DOUBLE *pdvalue = (DOUBLE *)pvalue;
  329. #endif
  330. char *p;
  331. #ifdef _MT
  332. int g_magnitude = pflt->decpt - 1;
  333. #endif
  334. /* first convert the value */
  335. /* place the output in the users buffer and round. Save space for
  336. * the minus sign now if it will be needed
  337. */
  338. if (g_fmt) {
  339. #ifndef _MT
  340. pflt = g_pflt;
  341. #endif
  342. p = buf + (pflt->sign == '-');
  343. if (g_magnitude == ndec) {
  344. char *q = p + g_magnitude;
  345. *q++ = '0';
  346. *q = '\0';
  347. /* allows for extra place-holding '0' in the exponent == precision
  348. * case of the g format
  349. */
  350. }
  351. }
  352. #ifndef _MT
  353. else {
  354. pflt = _fltout(*pdvalue);
  355. _fptostr(buf+(pflt->sign == '-'), ndec + pflt->decpt, pflt);
  356. }
  357. #endif
  358. /* now fix up the number to be in the correct f format */
  359. p = buf;
  360. /* put in negative sign, if necessary */
  361. if (pflt->sign == '-')
  362. *p++ = '-';
  363. /* insert leading 0 for purely fractional values and position ourselves
  364. * at the correct spot for inserting the decimal point
  365. */
  366. if (pflt->decpt <= 0) {
  367. _shift(p, 1);
  368. *p++ = '0';
  369. }
  370. else
  371. p += pflt->decpt;
  372. /* put in decimal point if required and any zero padding needed */
  373. if (ndec > 0) {
  374. _shift(p, 1);
  375. *p++ = *__decimal_point;
  376. /* if the value is less than 1 then we may need to put 0's out in
  377. * front of the first non-zero digit of the mantissa
  378. */
  379. if (pflt->decpt < 0) {
  380. if( g_fmt )
  381. ndec = -pflt->decpt;
  382. else
  383. ndec = (ndec < -pflt->decpt ) ? ndec : -pflt->decpt;
  384. _shift(p, ndec);
  385. memset( p, '0', ndec);
  386. }
  387. }
  388. return( buf);
  389. }
  390. /*
  391. * Function name: _cftof
  392. *
  393. * Arguments: value - double * pointer
  394. * buf - char * pointer
  395. * ndec - int
  396. *
  397. * Description: _cftof converts the double pointed to by pvalue to a null
  398. * terminated string of ASCII digits in the c language
  399. * printf %f format, and returns a pointer to the result.
  400. * This format has the form [-]ddddd.ddddd, where there will
  401. * be ndec digits following the decimal point. If ndec <= 0,
  402. * no decimal point will appear. The low order digit is
  403. * rounded.
  404. *
  405. * Side Effects: the buffer 'buf' is assumed to have a minimum length
  406. * of CVTBUFSIZE (defined in cvt.h) and the routines will
  407. * not write over this size.
  408. *
  409. * Author: written R.K. Wyss, Microsoft, Sept. 9, 1983
  410. *
  411. * History:
  412. *
  413. */
  414. #ifdef _MT
  415. char * __cdecl _cftof( double * pvalue, char * buf, int ndec )
  416. {
  417. struct _strflt retstrflt;
  418. char resstr[21];
  419. DOUBLE *pdvalue = (DOUBLE *)pvalue;
  420. STRFLT pflt = &retstrflt;
  421. _fltout2(*pdvalue, (struct _strflt *) &retstrflt,
  422. (char *) resstr);
  423. _fptostr(buf+(pflt->sign == '-'), ndec + pflt->decpt, pflt);
  424. _cftof2(buf, ndec, pflt, /* g_fmt = */ 0);
  425. return( buf );
  426. }
  427. #else /* not _MT */
  428. static char * _cftof_g( double * pvalue, char * buf, int ndec )
  429. {
  430. char *res;
  431. g_fmt = 1;
  432. res = _cftof(pvalue, buf, ndec);
  433. g_fmt = 0;
  434. return (res);
  435. }
  436. #endif /* not _MT */
  437. /*
  438. * Function name: _cftog
  439. *
  440. * Arguments: value - double * pointer
  441. * buf - char * pointer
  442. * ndec - int
  443. *
  444. * Description: _cftog converts the double pointed to by pvalue to a null
  445. * terminated string of ASCII digits in the c language
  446. * printf %g format, and returns a pointer to the result.
  447. * The form used depends on the value converted. The printf
  448. * %e form will be used if the magnitude of valude is less
  449. * than -4 or is greater than ndec, otherwise printf %f will
  450. * be used. ndec always specifies the number of digits
  451. * following the decimal point. The low order digit is
  452. * appropriately rounded.
  453. *
  454. * Side Effects: the buffer 'buf' is assumed to have a minimum length
  455. * of CVTBUFSIZE (defined in cvt.h) and the routines will
  456. * not write over this size.
  457. *
  458. * Author: written R.K. Wyss, Microsoft, Sept. 9, 1983
  459. *
  460. * History:
  461. *
  462. */
  463. char * __cdecl _cftog( double * pvalue, char * buf, int ndec, int caps )
  464. {
  465. char *p;
  466. DOUBLE *pdvalue = (DOUBLE *)pvalue;
  467. #ifdef _MT
  468. char g_round_expansion = 0;
  469. STRFLT g_pflt;
  470. int g_magnitude;
  471. struct _strflt retstrflt;
  472. char resstr[21];
  473. /* first convert the number */
  474. g_pflt = &retstrflt;
  475. _fltout2(*pdvalue, (struct _strflt *)&retstrflt,
  476. (char *)resstr);
  477. #else /* not _MT */
  478. /* first convert the number */
  479. g_pflt = _fltout(*pdvalue);
  480. #endif /* not _MT */
  481. g_magnitude = g_pflt->decpt - 1;
  482. p = buf + (g_pflt->sign == '-');
  483. _fptostr(p, ndec, g_pflt);
  484. g_round_expansion = (char)(g_magnitude < (g_pflt->decpt-1));
  485. /* compute the magnitude of value */
  486. g_magnitude = g_pflt->decpt - 1;
  487. /* convert value to the c language g format */
  488. if (g_magnitude < -4 || g_magnitude >= ndec){ /* use e format */
  489. /* (g_round_expansion ==>
  490. * extra digit will be overwritten by 'e+xxx')
  491. */
  492. #ifdef _MT
  493. return(_cftoe2(buf, ndec, caps, g_pflt, /* g_fmt = */ 1));
  494. #else
  495. return(_cftoe_g(pvalue, buf, ndec, caps));
  496. #endif
  497. }
  498. else { /* use f format */
  499. if (g_round_expansion) {
  500. /* throw away extra final digit from expansion */
  501. while (*p++);
  502. *(p-2) = '\0';
  503. }
  504. #ifdef _MT
  505. return(_cftof2(buf, ndec, g_pflt, /* g_fmt = */ 1));
  506. #else
  507. return(_cftof_g(pvalue, buf, ndec));
  508. #endif
  509. }
  510. }
  511. /***
  512. *_cfltcvt(arg, buf, format, precision, caps) - convert floating-point output
  513. *Purpose:
  514. *
  515. *Entry:
  516. * arg = (double *) pointer to double-precision floating-point number
  517. * buf = (char *) pointer to buffer into which to put the converted
  518. * ASCII form of the number
  519. * format = (int) 'e', 'f', or 'g'
  520. * precision = (int) giving number of decimal places for %e and %f formats,
  521. * and giving maximum number of significant digits for
  522. * %g format
  523. * caps = (int) flag indicating whether 'E' in exponent should be capatilized
  524. * (for %E and %G formats only)
  525. *
  526. *Exit:
  527. * returns : (void)
  528. *
  529. *Exceptions:
  530. *******************************************************************************/
  531. /*
  532. * Function name: _cfltcvt
  533. *
  534. * Arguments: arg - double * pointer
  535. * buf - char * pointer
  536. * format - int
  537. * ndec - int
  538. * caps - int
  539. *
  540. * Description: _cfltcvt determines from the format, what routines to
  541. * call to generate the correct floating point format
  542. *
  543. * Side Effects: none
  544. *
  545. * Author: Dave Weil, Jan 12, 1985
  546. */
  547. void __cdecl _cfltcvt( double * arg, char * buffer, int format, int precision, int caps )
  548. {
  549. if (format == 'e' || format == 'E')
  550. _cftoe(arg, buffer, precision, caps);
  551. else if (format == 'f')
  552. _cftof(arg, buffer, precision);
  553. else
  554. _cftog(arg, buffer, precision, caps);
  555. }
  556. /***
  557. *_shift(s, dist) - shift a null-terminated string in memory (internal routine)
  558. *Purpose:
  559. * _shift is a helper routine that shifts a null-terminated string
  560. * in memory, e.g., moves part of a buffer used for floating-point output
  561. *
  562. * modifies memory locations (s+dist) through (s+dist+strlen(s))
  563. *
  564. *Entry:
  565. * s = (char *) pointer to string to move
  566. * dist = (int) distance to move the string to the right (if negative, to left)
  567. *
  568. *Exit:
  569. * returns : (void)
  570. *
  571. *Exceptions:
  572. *******************************************************************************/
  573. static void _CALLTYPE5 _shift( char *s, int dist )
  574. {
  575. if( dist )
  576. memmove(s+dist, s, strlen(s)+1);
  577. }