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.

500 lines
11 KiB

  1. /***
  2. *strgtold.c - conversion of a string into a long double
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose: convert a fp constant into a 10 byte long double (IEEE format)
  7. *
  8. *Revision History:
  9. * 07-17-91 GDP Initial version (ported from assembly)
  10. * 04-03-92 GDP Preserve sign of -0
  11. * 04-30-92 GDP Now returns _LDBL12 instead of _LDOUBLE
  12. * 06-17-92 GDP Added __strgtold entry point again (68k code uses it)
  13. * 06-22-92 GDP Use scale, decpt and implicit_E for FORTRAN support
  14. * 11-06-92 GDP Made char-to-int conversions usnigned for 'isdigit'
  15. * 03-11-93 JWM Added minimal support for _INTL decimal point - one byte only!
  16. * 07-01-93 GJF Made buf[] a local array, rather than static array of
  17. * local scope (static is evil in multi-thread!).
  18. * 09-15-93 SKS Change _decimal_point to __decimal_point for CFW.
  19. * 09-06-94 CFW Remove _INTL switch.
  20. *
  21. *******************************************************************************/
  22. #include <ctype.h> /* for 'isdigit' macro */
  23. #include <cv.h>
  24. #include <nlsint.h>
  25. /* local macros */
  26. #define ISNZDIGIT(x) ((x)>='1' && (x)<='9' )
  27. #define ISWHITE(x) ((x)==' ' || (x)=='\t' || (x)=='\n' || (x)=='\r' )
  28. /****
  29. *unsigned int __strgtold12( _LDBL12 *pld12,
  30. * char * * pEndPtr,
  31. * char * str,
  32. * int Mult12,
  33. * int scale,
  34. * int decpt,
  35. * int implicit_E)
  36. *
  37. *Purpose:
  38. * converts a character string into a 12byte long double (_LDBL12)
  39. * This has the same format as a 10byte long double plus two extra
  40. * bytes for the mantissa
  41. *
  42. *Entry:
  43. * pld12 - pointer to the _LDBL12 where the result should go.
  44. * pEndStr - pointer to a far pointer that will be set to the end of string.
  45. * str - pointer to the string to be converted.
  46. * Mult12 - set to non zero if the _LDBL12 multiply should be used instead of
  47. * the long double mulitiply.
  48. * scale - FORTRAN scale factor (0 for C)
  49. * decpt - FORTRAN decimal point factor (0 for C)
  50. * implicit_E - if true, E, e, D, d can be implied (FORTRAN syntax)
  51. *
  52. *Exit:
  53. * Returns the SLD_* flags or'ed together.
  54. *
  55. *Uses:
  56. *
  57. *Exceptions:
  58. *
  59. ********************************************************************************/
  60. unsigned int
  61. __strgtold12(_LDBL12 *pld12,
  62. const char * *p_end_ptr,
  63. const char * str,
  64. int mult12,
  65. int scale,
  66. int decpt,
  67. int implicit_E)
  68. {
  69. typedef enum {
  70. S_INIT, /* initial state */
  71. S_EAT0L, /* eat 0's at the left of mantissa */
  72. S_SIGNM, /* just read sign of mantissa */
  73. S_GETL, /* get integer part of mantissa */
  74. S_GETR, /* get decimal part of mantissa */
  75. S_POINT, /* just found decimal point */
  76. S_E, /* just found 'E', or 'e', etc */
  77. S_SIGNE, /* just read sign of exponent */
  78. S_EAT0E, /* eat 0's at the left of exponent */
  79. S_GETE, /* get exponent */
  80. S_END, /* final state */
  81. S_E_IMPLICIT /* check for implicit exponent */
  82. } state_t;
  83. /* this will accomodate the digits of the mantissa in BCD form*/
  84. char buf[LD_MAX_MAN_LEN1];
  85. char *manp = buf;
  86. /* a temporary _LDBL12 */
  87. _LDBL12 tmpld12;
  88. u_short man_sign = 0; /* to be ORed with result */
  89. int exp_sign = 1; /* default sign of exponent (values: +1 or -1)*/
  90. /* number of decimal significant mantissa digits so far*/
  91. unsigned manlen = 0;
  92. int found_digit = 0;
  93. int found_decpoint = 0;
  94. int found_exponent = 0;
  95. int overflow = 0;
  96. int underflow = 0;
  97. int pow = 0;
  98. int exp_adj = 0; /* exponent adjustment */
  99. u_long ul0,ul1;
  100. u_short u,uexp;
  101. unsigned int result_flags = 0;
  102. state_t state = S_INIT;
  103. char c; /* the current input symbol */
  104. const char *p; /* a pointer to the next input symbol */
  105. const char *savedp;
  106. for(savedp=p=str;ISWHITE(*p);p++); /* eat up white space */
  107. while (state != S_END) {
  108. c = *p++;
  109. switch (state) {
  110. case S_INIT:
  111. if (ISNZDIGIT(c)) {
  112. state = S_GETL;
  113. p--;
  114. }
  115. else if (c == *__decimal_point)
  116. state = S_POINT;
  117. else
  118. switch (c) {
  119. case '0':
  120. state = S_EAT0L;
  121. break;
  122. case '+':
  123. state = S_SIGNM;
  124. man_sign = 0x0000;
  125. break;
  126. case '-':
  127. state = S_SIGNM;
  128. man_sign = 0x8000;
  129. break;
  130. default:
  131. state = S_END;
  132. p--;
  133. break;
  134. }
  135. break;
  136. case S_EAT0L:
  137. found_digit = 1;
  138. if (ISNZDIGIT(c)) {
  139. state = S_GETL;
  140. p--;
  141. }
  142. else if (c == *__decimal_point)
  143. state = S_GETR;
  144. else
  145. switch (c) {
  146. case '0':
  147. state = S_EAT0L;
  148. break;
  149. case 'E':
  150. case 'e':
  151. case 'D':
  152. case 'd':
  153. state = S_E;
  154. break;
  155. case '+':
  156. case '-':
  157. p--;
  158. state = S_E_IMPLICIT;
  159. break;
  160. default:
  161. state = S_END;
  162. p--;
  163. }
  164. break;
  165. case S_SIGNM:
  166. if (ISNZDIGIT(c)) {
  167. state = S_GETL;
  168. p--;
  169. }
  170. else if (c == *__decimal_point)
  171. state = S_POINT;
  172. else
  173. switch (c) {
  174. case '0':
  175. state = S_EAT0L;
  176. break;
  177. default:
  178. state = S_END;
  179. p = savedp;
  180. }
  181. break;
  182. case S_GETL:
  183. found_digit = 1;
  184. for (;isdigit((int)(unsigned char)c);c=*p++) {
  185. if (manlen < LD_MAX_MAN_LEN+1){
  186. manlen++;
  187. *manp++ = c - (char)'0';
  188. }
  189. else
  190. exp_adj++;
  191. }
  192. if (c == *__decimal_point)
  193. state = S_GETR;
  194. else
  195. switch (c) {
  196. case 'E':
  197. case 'e':
  198. case 'D':
  199. case 'd':
  200. state = S_E;
  201. break;
  202. case '+':
  203. case '-':
  204. p--;
  205. state = S_E_IMPLICIT;
  206. break;
  207. default:
  208. state = S_END;
  209. p--;
  210. }
  211. break;
  212. case S_GETR:
  213. found_digit = 1;
  214. found_decpoint = 1;
  215. if (manlen == 0)
  216. for (;c=='0';c=*p++)
  217. exp_adj--;
  218. for(;isdigit((int)(unsigned char)c);c=*p++){
  219. if (manlen < LD_MAX_MAN_LEN+1){
  220. manlen++;
  221. *manp++ = c - (char)'0';
  222. exp_adj--;
  223. }
  224. }
  225. switch (c){
  226. case 'E':
  227. case 'e':
  228. case 'D':
  229. case 'd':
  230. state = S_E;
  231. break;
  232. case '+':
  233. case '-':
  234. p--;
  235. state = S_E_IMPLICIT;
  236. break;
  237. default:
  238. state = S_END;
  239. p--;
  240. }
  241. break;
  242. case S_POINT:
  243. found_decpoint = 1;
  244. if (isdigit((int)(unsigned char)c)){
  245. state = S_GETR;
  246. p--;
  247. }
  248. else{
  249. state = S_END;
  250. p = savedp;
  251. }
  252. break;
  253. case S_E:
  254. savedp = p-2; /* savedp points to 'E' */
  255. if (ISNZDIGIT(c)){
  256. state = S_GETE;
  257. p--;
  258. }
  259. else
  260. switch (c){
  261. case '0':
  262. state = S_EAT0E;
  263. break;
  264. case '-':
  265. state = S_SIGNE;
  266. exp_sign = -1;
  267. break;
  268. case '+':
  269. state = S_SIGNE;
  270. break;
  271. default:
  272. state = S_END;
  273. p = savedp;
  274. }
  275. break;
  276. case S_EAT0E:
  277. found_exponent = 1;
  278. for(;c=='0';c=*p++);
  279. if (ISNZDIGIT(c)){
  280. state = S_GETE;
  281. p--;
  282. }
  283. else {
  284. state = S_END;
  285. p--;
  286. }
  287. break;
  288. case S_SIGNE:
  289. if (ISNZDIGIT(c)){
  290. state = S_GETE;
  291. p--;
  292. }
  293. else
  294. switch (c){
  295. case '0':
  296. state = S_EAT0E;
  297. break;
  298. default:
  299. state = S_END;
  300. p = savedp;
  301. }
  302. break;
  303. case S_GETE:
  304. found_exponent = 1;
  305. {
  306. long longpow=0; /* TMAX10*10 should fit in a long */
  307. for(;isdigit((int)(unsigned char)c);c=*p++){
  308. longpow = longpow*10 + (c - '0');
  309. if (longpow > TMAX10){
  310. longpow = TMAX10+1; /* will force overflow */
  311. break;
  312. }
  313. }
  314. pow = (int)longpow;
  315. }
  316. for(;isdigit((int)(unsigned char)c);c=*p++); /* eat up remaining digits */
  317. state = S_END;
  318. p--;
  319. break;
  320. case S_E_IMPLICIT:
  321. if (implicit_E) {
  322. savedp = p-1; /* savedp points to whatever precedes sign */
  323. switch (c){
  324. case '-':
  325. state = S_SIGNE;
  326. exp_sign = -1;
  327. break;
  328. case '+':
  329. state = S_SIGNE;
  330. break;
  331. default:
  332. state = S_END;
  333. p = savedp;
  334. }
  335. }
  336. else {
  337. state = S_END;
  338. p--;
  339. }
  340. break;
  341. } /* switch */
  342. } /* while */
  343. *p_end_ptr = p; /* set end pointer */
  344. /*
  345. * Compute result
  346. */
  347. if (found_digit && !overflow && !underflow) {
  348. if (manlen>LD_MAX_MAN_LEN){
  349. if (buf[LD_MAX_MAN_LEN-1]>=5) {
  350. /*
  351. * Round mantissa to MAX_MAN_LEN digits
  352. * It's ok to round 9 to 0ah
  353. */
  354. buf[LD_MAX_MAN_LEN-1]++;
  355. }
  356. manlen = LD_MAX_MAN_LEN;
  357. manp--;
  358. exp_adj++;
  359. }
  360. if (manlen>0) {
  361. /*
  362. * Remove trailing zero's from mantissa
  363. */
  364. for(manp--;*manp==0;manp--) {
  365. /* there is at least one non-zero digit */
  366. manlen--;
  367. exp_adj++;
  368. }
  369. __mtold12(buf,manlen,&tmpld12);
  370. if (exp_sign < 0)
  371. pow = -pow;
  372. pow += exp_adj;
  373. /* new code for FORTRAN support */
  374. if (!found_exponent) {
  375. pow += scale;
  376. }
  377. if (!found_decpoint) {
  378. pow -= decpt;
  379. }
  380. if (pow > TMAX10)
  381. overflow = 1;
  382. else if (pow < TMIN10)
  383. underflow = 1;
  384. else {
  385. __multtenpow12(&tmpld12,pow,mult12);
  386. u = *U_XT_12(&tmpld12);
  387. ul0 =*UL_MANLO_12(&tmpld12);
  388. ul1 = *UL_MANHI_12(&tmpld12);
  389. uexp = *U_EXP_12(&tmpld12);
  390. }
  391. }
  392. else {
  393. /* manlen == 0, so return 0 */
  394. u = (u_short)0;
  395. ul0 = ul1 = uexp = 0;
  396. }
  397. }
  398. if (!found_digit) {
  399. /* return 0 */
  400. u = (u_short)0;
  401. ul0 = ul1 = uexp = 0;
  402. result_flags |= SLD_NODIGITS;
  403. }
  404. else if (overflow) {
  405. /* return +inf or -inf */
  406. uexp = (u_short)0x7fff;
  407. ul1 = 0x80000000;
  408. ul0 = 0;
  409. u = (u_short)0;
  410. result_flags |= SLD_OVERFLOW;
  411. }
  412. else if (underflow) {
  413. /* return 0 */
  414. u = (u_short)0;
  415. ul0 = ul1 = uexp = 0;
  416. result_flags |= SLD_UNDERFLOW;
  417. }
  418. /*
  419. * Assemble result
  420. */
  421. *U_XT_12(pld12) = u;
  422. *UL_MANLO_12(pld12) = ul0;
  423. *UL_MANHI_12(pld12) = ul1;
  424. *U_EXP_12(pld12) = uexp | man_sign;
  425. return result_flags;
  426. }
  427. /****
  428. *unsigned int _CALLTYPE5 __stringtold( LDOUBLE *pLd,
  429. * char * * pEndPtr,
  430. * char * str,
  431. * int Mult12 )
  432. *
  433. *Purpose:
  434. * converts a character string into a long double
  435. *
  436. *Entry:
  437. * pLD - pointer to the long double where the result should go.
  438. * pEndStr - pointer to a pointer that will be set to the end of string.
  439. * str - pointer to the string to be converted.
  440. * Mult12 - set to non zero if the _LDBL12 multiply should be used instead of
  441. * the long double mulitiply.
  442. *
  443. *Exit:
  444. * Returns the SLD_* flags or'ed together.
  445. *
  446. *Uses:
  447. *
  448. *Exceptions:
  449. *
  450. ********************************************************************************/
  451. unsigned int _CALLTYPE5
  452. __STRINGTOLD(_LDOUBLE *pld,
  453. const char * *p_end_ptr,
  454. const char *str,
  455. int mult12)
  456. {
  457. unsigned int retflags;
  458. INTRNCVT_STATUS intrncvt;
  459. _LDBL12 ld12;
  460. retflags = __strgtold12(&ld12, p_end_ptr, str, mult12, 0, 0, 0);
  461. intrncvt = _ld12told(&ld12, pld);
  462. if (intrncvt == INTRNCVT_OVERFLOW) {
  463. retflags |= SLD_OVERFLOW;
  464. }
  465. return retflags;
  466. }