PageRenderTime 41ms CodeModel.GetById 7ms RepoModel.GetById 1ms app.codeStats 0ms

/source/m_fcvt.cpp

https://bitbucket.org/ichera/autodoom
C++ | 231 lines | 138 code | 32 blank | 61 comment | 37 complexity | 266631e1e1c1e0b442c111020da61563 MD5 | raw file
Possible License(s): GPL-3.0, AGPL-3.0, LGPL-3.0, LGPL-2.1
  1. // Emacs style mode select -*- C++ -*-
  2. //-----------------------------------------------------------------------------
  3. //
  4. // Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details
  5. // Copyright (C) 2013 James Haley et al.
  6. //
  7. // This program is free software: you can redistribute it and/or modify
  8. // it under the terms of the GNU General Public License as published by
  9. // the Free Software Foundation, either version 3 of the License, or
  10. // (at your option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. // GNU General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public License
  18. // along with this program. If not, see http://www.gnu.org/licenses/
  19. //
  20. //--------------------------------------------------------------------------
  21. //
  22. // DESCRIPTION:
  23. // fcvt from DJGPP libc and supporting functions, to solve
  24. // problem with psnprintf. ::SIGH::
  25. //
  26. //-----------------------------------------------------------------------------
  27. #ifdef __FreeBSD__ // [Kate] Update as necessary
  28. #define NO_FCVT
  29. #endif
  30. #ifdef NO_FCVT
  31. // NOTE: Do not include z_zone.h into this file.
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <float.h>
  36. #include "m_fcvt.h"
  37. #ifndef DBL_MAX_10_EXP
  38. #define DBL_MAX_10_EXP 308
  39. #endif
  40. char *M_Fcvt(double value, int ndigits, int *decpt, int *sign)
  41. {
  42. static char fcvt_buf[2 * DBL_MAX_10_EXP + 10];
  43. return M_Fcvtbuf(value, ndigits, decpt, sign, fcvt_buf);
  44. }
  45. //
  46. // haleyjd: changes from DJGPP:
  47. //
  48. // * Changed alloca to malloc and added calls to free
  49. //
  50. char *M_Fcvtbuf(double value, int ndigits, int *decpt, int *sign, char *buf)
  51. {
  52. static char INFINITY[] = "Infinity";
  53. char decimal = '.';
  54. int digits = ndigits >= 0 ? ndigits : 0;
  55. char *cvtbuf = (char *)(malloc)(2*DBL_MAX_10_EXP + 16);
  56. char *s = cvtbuf;
  57. char *dot;
  58. sprintf(cvtbuf, "%-+#.*f", DBL_MAX_10_EXP + digits + 1, value);
  59. /* The sign. */
  60. if(*s++ == '-')
  61. *sign = 1;
  62. else
  63. *sign = 0;
  64. /* Where's the decimal point? */
  65. dot = strchr(s, decimal);
  66. if(dot)
  67. *decpt = dot - s;
  68. else
  69. *decpt = strlen(s);
  70. /* SunOS docs says if NDIGITS is 8 or more, produce "Infinity"
  71. instead of "Inf". */
  72. if(strncmp(s, "Inf", 3) == 0)
  73. {
  74. memcpy(buf, INFINITY, ndigits >= 8 ? 9 : 3);
  75. if(ndigits < 8)
  76. buf[3] = '\0';
  77. (free)(cvtbuf); /* haleyjd */
  78. return buf;
  79. }
  80. else if(ndigits < 0)
  81. {
  82. char *ret = M_Ecvtbuf(value, *decpt + ndigits, decpt, sign, buf);
  83. (free)(cvtbuf); /* haleyjd */
  84. return ret;
  85. }
  86. else if(*s == '0' && value != 0.0)
  87. {
  88. char *ret = M_Ecvtbuf(value, ndigits, decpt, sign, buf);
  89. (free)(cvtbuf); /* haleyjd */
  90. return ret;
  91. }
  92. else
  93. {
  94. memcpy(buf, s, *decpt);
  95. if(s[*decpt] == decimal)
  96. {
  97. memcpy(buf + *decpt, s + *decpt + 1, ndigits);
  98. buf[*decpt + ndigits] = '\0';
  99. }
  100. else
  101. buf[*decpt] = '\0';
  102. M_Ecvround(buf, buf + *decpt + ndigits - 1,
  103. s + *decpt + ndigits + 1, decpt);
  104. (free)(cvtbuf); /* haleyjd */
  105. return buf;
  106. }
  107. }
  108. void
  109. M_Ecvround(char *numbuf, char *last_digit, const char *after_last, int *decpt)
  110. {
  111. char *p;
  112. int carry = 0;
  113. /* Do we have at all to round the last digit? */
  114. if(*after_last > '4')
  115. {
  116. p = last_digit;
  117. carry = 1;
  118. /* Propagate the rounding through trailing '9' digits. */
  119. do
  120. {
  121. int sum = *p + carry;
  122. carry = sum > '9';
  123. *p-- = sum - carry * 10;
  124. } while(carry && p >= numbuf);
  125. /* We have 9999999... which needs to be rounded to 100000.. */
  126. if(carry && p == numbuf)
  127. {
  128. *p = '1';
  129. *decpt += 1;
  130. }
  131. }
  132. }
  133. //
  134. // haleyjd: changes from DJGPP:
  135. //
  136. // * Changed alloca to malloc and added calls to free
  137. //
  138. char *
  139. M_Ecvtbuf(double value, int ndigits, int *decpt, int *sign, char *buf)
  140. {
  141. static char INFINITY[] = "Infinity";
  142. char decimal = '.';
  143. char *cvtbuf = (char *)(malloc)(ndigits + 20); /* +3 for sign, dot, null; */
  144. /* two extra for rounding */
  145. /* 15 extra for alignment */
  146. char *s = cvtbuf, *d = buf;
  147. /* Produce two extra digits, so we could round properly. */
  148. sprintf(cvtbuf, "%-+.*E", ndigits + 2, value);
  149. *decpt = 0;
  150. /* The sign. */
  151. if(*s++ == '-')
  152. *sign = 1;
  153. else
  154. *sign = 0;
  155. /* Special values get special treatment. */
  156. if(strncmp (s, "Inf", 3) == 0)
  157. {
  158. /* SunOS docs says we have return "Infinity" for NDIGITS >= 8. */
  159. memcpy(buf, INFINITY, ndigits >= 8 ? 9 : 3);
  160. if(ndigits < 8)
  161. buf[3] = '\0';
  162. }
  163. else if(strcmp (s, "NaN") == 0)
  164. memcpy(buf, s, 4);
  165. else
  166. {
  167. char *last_digit, *digit_after_last;
  168. /* Copy (the single) digit before the decimal. */
  169. while(*s && *s != decimal && d - buf < ndigits)
  170. *d++ = *s++;
  171. /* If we don't see any exponent, here's our decimal point. */
  172. *decpt = d - buf;
  173. if(*s)
  174. s++;
  175. /* Copy the fraction digits. */
  176. while(*s && *s != 'E' && d - buf < ndigits)
  177. *d++ = *s++;
  178. /* Remember the last digit copied and the one after it. */
  179. last_digit = d > buf ? d - 1 : d;
  180. digit_after_last = s;
  181. /* Get past the E in exponent field. */
  182. while(*s && *s++ != 'E')
  183. ;
  184. /* Adjust the decimal point by the exponent value. */
  185. *decpt += atoi(s);
  186. /* Pad with zeroes if needed. */
  187. while(d - buf < ndigits)
  188. *d++ = '0';
  189. /* Zero-terminate. */
  190. *d = '\0';
  191. /* Round if necessary. */
  192. M_Ecvround(buf, last_digit, digit_after_last, decpt);
  193. }
  194. /* haleyjd */
  195. (free)(cvtbuf);
  196. return buf;
  197. }
  198. #endif
  199. // EOF