Opera 12.15 Source Code
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

stdlib_pi.cpp 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. **
  3. ** Copyright (C) 2006-2012 Opera Software ASA. All rights reserved.
  4. **
  5. ** This file is part of the Opera web browser. It may not be distributed
  6. ** under any circumstances.
  7. */
  8. /**
  9. Note: this file uses the option "no-pch", so it is compiled without
  10. pre-compiled header.
  11. On compiling this file COMPILING_STDLIB_PI is defined. The
  12. platform's system.h needs to provide the declaration of some stdlib
  13. functions in some cases. This could be implemented like
  14. @code
  15. // Example for a platform's system.h:
  16. // first define the system's capabilities:
  17. #define SYSTEM_SNPRINTF YES // or NO
  18. #define SYSTEM_SPRINTF YES // or NO
  19. #define SYSTEM_STRTOD YES // or NO
  20. #define SYSTEM_SSCANF YES // or NO
  21. ...
  22. #if defined(COMPILING_STDLIB_PI) && !defined(STDLIB_DTOA_CONVERSION)
  23. // If this platform doesn't use thirdparty dtoa code, the stdlib module
  24. // needs to implement the some functions in
  25. // modules/stdlib/stdlib_pi.cpp, so if we include this header file
  26. // while compiling the file stdlib_pi.cpp, we might need (depending
  27. // on the above system definitions) require some system functions:
  28. # if !SYSTEM_STRTOD && SYSTEM_SSCANF
  29. // stdlib's StdlibPi::StringToDouble() uses the system's sscanf()
  30. // (not op_sscanf()) which is provided by including <stdio.h>:
  31. # define INCLUDE_STDIO_H
  32. # else // SYSTEM_STRTOD || !SYSTEM_SSCANF
  33. // Either StdlibPi::StringToDouble() is not defined because
  34. // the system's strtod() can be used (SYSTEM_STRTOD == YES), or
  35. // stdlib's StdlibPi::StringToDouble() uses an approximate
  36. // implementation which does not need the system's sscanf() but is
  37. // good enough in many cases (SYSTEM_STRTOD == NO and
  38. // SYSTEM_SSCANF == NO)
  39. # endif // !SYSTEM_STRTOD && SYSTEM_SSCANF
  40. # if SYSTEM_SNPRINTF
  41. // stdlib's StdlibPI::SPrintfDouble() uses the system's snprintf()
  42. // to print a double, so include <stdio.h> to provide the
  43. // declaration of snprintf()
  44. # define INCLUDE_STDIO_H
  45. # elif SYSTEM_VSNPRINTF
  46. // stdlib's StdlibPI::SPrintfDouble() uses the system's va_list,
  47. // va_start(), va_end() and vsnprintf() to print a double, so
  48. // include <stdio.h> to provide the declaration of vsnprintf and
  49. // include <stdarg.h> to provide the declaration of va_start()
  50. // etc.
  51. # define INCLUDE_STDIO_H
  52. # define INCLUDE_STDARG_H
  53. # elif SYSTEM_SPRINTF
  54. // if there is no snprintf nor vsnprintf, stdlib's
  55. // StdlibPI::SPrintfDouble() uses the system's sprintf() to print a
  56. // double, so include <stdio.h> to provide the declaration of
  57. // sprintf()
  58. # define INCLUDE_STDIO_H
  59. # elif SYSTEM_VSPRINTF
  60. // if there is no snprintf nor vsnprintf, stdlib's
  61. // stdlib's StdlibPI::SPrintfDouble() uses the system's va_list,
  62. // va_start(), va_end() and vsprintf() to print a double, so
  63. // include <stdio.h> to provide the declaration of vsprintf and
  64. // include <stdarg.h> to provide the declaration of va_start()
  65. // etc.
  66. # define INCLUDE_STDIO_H
  67. # define INCLUDE_STDARG_H
  68. # else // !SYSTEM_S(N)PRINTF && !SYSTEM_VS(N)PRINTF
  69. // stdlib cannot provide an implementation for
  70. // StdlibPI::SprintfDouble(), so the platform must do it:
  71. # endif // !SYSTEM_S(N)PRINTF || !SYSTEM_VS(N)PRINTF
  72. #endif // COMPILING_STDLIB_PI && !STDLIB_DTOA_CONVERSION
  73. ...
  74. #ifdef INCLUDE_STDIO_H
  75. # include <stdio.h>
  76. #else !INCLUDE_STDIO_H
  77. // generate a compile error if anybody still uses the system stdio
  78. // functions instead of the op_... functions:
  79. # define sscanf dont_use_sscanf
  80. # define snprintf dont_use_snprintf
  81. # define sprintf dont_use_sprintf
  82. # define vsnprintf dont_use_vsnprintf
  83. # define vsprintf dont_use_vsprintf
  84. ...
  85. #endif // INCLUDE_STDIO_H
  86. #undef INCLUDE_STDIO_H
  87. #ifdef INCLUDE_STDARG_H
  88. # include <stdarg.h>
  89. #endif // INCLUDE_STDIO_H
  90. #undef INCLUDE_STDARG_H
  91. ...
  92. @endcode
  93. */
  94. #define COMPILING_STDLIB_PI
  95. #include "core/pch_system_includes.h"
  96. /* NOTE: The implementation of these functions MUST NOT call any op_ functions
  97. * that may end up parsing or printing floating point numbers.
  98. *
  99. * Occasionally setting the locale may not have the desired effect on producing
  100. * the right decimal point in the formatters. If that's so, then use the following
  101. * snippet to transform commas to decimal points.
  102. */
  103. #if 0 // Helper code, use as needed
  104. for ( char *b = buffer; *b ; ++b )
  105. if (*b == ',')
  106. *b = '.';
  107. #endif
  108. #ifndef STDLIB_DTOA_CONVERSION
  109. #include "modules/stdlib/stdlib_pi.h"
  110. #ifndef HAVE_STRTOD
  111. #ifdef HAVE_SSCANF // Normally you want some platform names here, too
  112. double
  113. StdlibPI::StringToDouble( const char* p, char** endp )
  114. {
  115. // FIXME! set endp!
  116. double d;
  117. char *oldlocale = op_setlocale( LC_NUMERIC, NULL );
  118. op_setlocale( LC_NUMERIC, "C" );
  119. sscanf(p, "%lf", &d); // Not op_sscanf!
  120. op_setlocale( LC_NUMERIC, oldlocale );
  121. return d;
  122. }
  123. #else // !HAVE_SSCANF
  124. /* This is approximate but good enough in many cases */
  125. double
  126. StdlibPI::StringToDouble( const char* p, char** endp )
  127. {
  128. double value = 0.0, fraction = 0.0;
  129. int divisor = 0;
  130. int exponent = 0;
  131. int exp_sign = 1;
  132. int int_sign = 1;
  133. BOOL has_start = FALSE;
  134. // Skip any initial whitespace
  135. for (; op_isspace(*reinterpret_cast<const unsigned char *>(p)); ++ p)
  136. /* nothing */;
  137. if (endp != NULL)
  138. *endp = const_cast<char*>(p);
  139. // Integer part
  140. if (*p == '+' || *p == '-')
  141. {
  142. int_sign = (*(p ++) == '-') ? -1 : 1;
  143. }
  144. // Handle infinity
  145. if (*p == 'i' || *p == 'I')
  146. {
  147. if (strni_eq(p, "INFINITY", 8))
  148. {
  149. if (endp != NULL)
  150. *endp = const_cast<char *>(p + 8);
  151. return int_sign == 1 ? g_opera->stdlib_module.m_infinity : g_opera->stdlib_module.m_negative_infinity;
  152. }
  153. }
  154. while (*p >= '0' && *p <= '9')
  155. {
  156. has_start = TRUE;
  157. value = value * 10.0 + (*p - '0');
  158. p++;
  159. }
  160. value *= int_sign;
  161. // Fractional part. Fractional part is optional; digits in fractional part
  162. // are optional if there was an integer part.
  163. if (*p == '.' && (p[1] >= '0' && p[1] <= '9' || has_start))
  164. {
  165. has_start = TRUE;
  166. p++;
  167. while (*p >= '0' && *p <= '9')
  168. {
  169. fraction = fraction * 10.0 + (*p - '0');
  170. divisor++;
  171. p++;
  172. }
  173. }
  174. // Exponent marker. Exponent marker is valid if there was an integer or
  175. // fractional part. The exponent must have at least one digit.
  176. if (has_start &&
  177. (*p == 'e' || *p == 'E') &&
  178. (((p[1] == '+' || p[1] == '-') && p[2] >= '0' && p[2] <= '9') ||
  179. (p[1] >= '0' && p[1] <= '9')))
  180. {
  181. p++;
  182. if (*p == '+')
  183. ++p;
  184. else if (*p == '-')
  185. {
  186. exp_sign = -1;
  187. ++p;
  188. }
  189. while (*p >= '0' && *p <= '9')
  190. {
  191. exponent = exponent*10 + (*p - '0');
  192. ++p;
  193. }
  194. }
  195. if (has_start)
  196. value = (value + fraction / op_pow(10.0, divisor)) * op_pow(10.0, (exponent*exp_sign)) ;
  197. if (endp != NULL)
  198. *endp = const_cast<char*>(p);
  199. return value;
  200. }
  201. #endif // HAVE_SSCANF && platform names
  202. #endif // !HAVE_STRTOD
  203. #if !defined HAVE_SNPRINTF && defined HAVE_VSNPRINTF
  204. /* Synthesize snprintf from vsnprintf if necessary and possible */
  205. static int snprintf(char* buf, size_t bufsiz, const char* fmt, ...)
  206. {
  207. va_list args;
  208. va_start(args, fmt);
  209. int res = vsnprintf(buf, bufsiz, fmt, args);
  210. va_end(args);
  211. return res;
  212. }
  213. #define HAVE_SNPRINTF
  214. #elif !defined HAVE_SPRINTF && defined HAVE_VSPRINTF
  215. /* Synthesize sprintf from vsprintf if necessary and possible */
  216. static int sprintf(char* buf, const char* fmt, ...)
  217. {
  218. va_list args;
  219. va_start(args, fmt);
  220. int res = vsprintf(buf, fmt, args);
  221. va_end(args);
  222. return res;
  223. }
  224. #define HAVE_SPRINTF
  225. #endif // !defined HAVE_SNPRINTF && defined HAVE_VSNPRINTF
  226. #if defined HAVE_SNPRINTF
  227. void
  228. StdlibPI::SPrintfDouble(char *buffer, int bufsiz, const char* fmt, double d)
  229. {
  230. char *oldlocale = op_setlocale( LC_NUMERIC, NULL );
  231. op_setlocale( LC_NUMERIC, "C" );
  232. snprintf(buffer, bufsiz-1, fmt, d); // Not op_snprintf!
  233. op_setlocale( LC_NUMERIC, oldlocale );
  234. }
  235. #elif defined HAVE_SPRINTF
  236. void
  237. StdlibPI::SPrintfDouble(char *buffer, int bufsiz, const char* fmt, double d)
  238. {
  239. //
  240. // A 64-bit IEEE 754-1985 'double' has a maximum value of
  241. // +/-1.7976931348623157*10^308, and has 15 decimal digits of precision,
  242. // so 350 characters should be plenty to hold a number written out
  243. // in full (i.e. a format without an exponent).
  244. //
  245. char localbuf[350]; // ARRAY OK 2012-03-13 peter
  246. OP_STATIC_ASSERT(sizeof(d) <= 8); // Give error for larger than 64-bit doubles
  247. #ifdef DEBUG_ENABLE_OPASSERT
  248. // Set up a guard when OP_ASSERT is enabled
  249. localbuf[349] = 0;
  250. #endif
  251. char *oldlocale = op_setlocale( LC_NUMERIC, NULL );
  252. op_setlocale( LC_NUMERIC, "C" );
  253. sprintf(localbuf, fmt, d); // Not op_sprintf!
  254. OP_ASSERT(localbuf[349] == 0); // Overflowed anyway! How?
  255. op_strncpy( buffer, localbuf, bufsiz );
  256. buffer[bufsiz-1] = 0;
  257. op_setlocale( LC_NUMERIC, oldlocale );
  258. }
  259. #else // !HAVE_SNPRINTF and !HAVE_SPRINTF
  260. // No code available, which means that we need platform code to implement
  261. // StdlibPI::SPrintfDouble(). There will be a link error.
  262. #endif // HAVE_SNPRINTF or HAVE_SPRINTF
  263. // LocaleSafeDTOA() and LocaleSafeETOA() must be implemented in platform
  264. // code. If you have no locale-safe dtoa() or etoa(), just make them
  265. // return FALSE, which means that the stdlib module will fall back on
  266. // StdlibPI::SPrintfDouble():
  267. //
  268. // /* static */ BOOL
  269. // StdlibPI::LocaleSafeDTOA( double d, char* b, int precision )
  270. // {
  271. // // If you have a locale-safe dtoa(), call it here
  272. // return FALSE; // Fall back on StdlibPI::SPrintfDouble
  273. // }
  274. //
  275. // /* static */ BOOL
  276. // StdlibPI::LocaleSafeETOA( double d, char* b, int precision )
  277. // {
  278. // // If you have a locale-safe etoa(), call it here
  279. // return FALSE; // Fall back on StdlibPI::SPrintfDouble
  280. // }
  281. #endif // !STDLIB_DTOA_CONVERSION