io.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  1. /*
  2. * Copyright (c) 2008-2016 Stefan Krah. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include "mpdecimal.h"
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <limits.h>
  33. #include <assert.h>
  34. #ifdef _WIN32_WCE
  35. static int errno = 0;
  36. #define EINVAL -1
  37. #else
  38. #include <errno.h>
  39. #include <locale.h>
  40. #endif
  41. #include "bits.h"
  42. #include "constants.h"
  43. #include "memory.h"
  44. #include "typearith.h"
  45. #include "io.h"
  46. /* This file contains functions for decimal <-> string conversions, including
  47. PEP-3101 formatting for numeric types. */
  48. /*
  49. * Work around the behavior of tolower() and strcasecmp() in certain
  50. * locales. For example, in tr_TR.utf8:
  51. *
  52. * tolower((unsigned char)'I') == 'I'
  53. *
  54. * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1
  55. */
  56. static inline int
  57. _mpd_strneq(const char *s, const char *l, const char *u, size_t n)
  58. {
  59. while (--n != SIZE_MAX) {
  60. if (*s != *l && *s != *u) {
  61. return 0;
  62. }
  63. s++; u++; l++;
  64. }
  65. return 1;
  66. }
  67. static mpd_ssize_t
  68. strtoexp(const char *s)
  69. {
  70. char *end;
  71. mpd_ssize_t retval;
  72. errno = 0;
  73. retval = mpd_strtossize(s, &end, 10);
  74. if (errno == 0 && !(*s != '\0' && *end == '\0'))
  75. errno = EINVAL;
  76. return retval;
  77. }
  78. /*
  79. * Scan 'len' words. The most significant word contains 'r' digits,
  80. * the remaining words are full words. Skip dpoint. The string 's' must
  81. * consist of digits and an optional single decimal point at 'dpoint'.
  82. */
  83. static void
  84. string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r,
  85. size_t len)
  86. {
  87. int j;
  88. if (r > 0) {
  89. data[--len] = 0;
  90. for (j = 0; j < r; j++, s++) {
  91. if (s == dpoint) s++;
  92. data[len] = 10 * data[len] + (*s - '0');
  93. }
  94. }
  95. while (--len != SIZE_MAX) {
  96. data[len] = 0;
  97. for (j = 0; j < MPD_RDIGITS; j++, s++) {
  98. if (s == dpoint) s++;
  99. data[len] = 10 * data[len] + (*s - '0');
  100. }
  101. }
  102. }
  103. /*
  104. * Partially verify a numeric string of the form:
  105. *
  106. * [cdigits][.][cdigits][eE][+-][edigits]
  107. *
  108. * If successful, return a pointer to the location of the first
  109. * relevant coefficient digit. This digit is either non-zero or
  110. * part of one of the following patterns:
  111. *
  112. * ["0\x00", "0.\x00", "0.E", "0.e", "0E", "0e"]
  113. *
  114. * The locations of a single optional dot or indicator are stored
  115. * in 'dpoint' and 'exp'.
  116. *
  117. * The end of the string is stored in 'end'. If an indicator [eE]
  118. * occurs without trailing [edigits], the condition is caught
  119. * later by strtoexp().
  120. */
  121. static const char *
  122. scan_dpoint_exp(const char *s, const char **dpoint, const char **exp,
  123. const char **end)
  124. {
  125. const char *coeff = NULL;
  126. *dpoint = NULL;
  127. *exp = NULL;
  128. for (; *s != '\0'; s++) {
  129. switch (*s) {
  130. case '.':
  131. if (*dpoint != NULL || *exp != NULL)
  132. return NULL;
  133. *dpoint = s;
  134. break;
  135. case 'E': case 'e':
  136. if (*exp != NULL)
  137. return NULL;
  138. *exp = s;
  139. if (*(s+1) == '+' || *(s+1) == '-')
  140. s++;
  141. break;
  142. default:
  143. if (!isdigit((uchar)*s))
  144. return NULL;
  145. if (coeff == NULL && *exp == NULL) {
  146. if (*s == '0') {
  147. if (!isdigit((uchar)*(s+1)))
  148. if (!(*(s+1) == '.' &&
  149. isdigit((uchar)*(s+2))))
  150. coeff = s;
  151. }
  152. else {
  153. coeff = s;
  154. }
  155. }
  156. break;
  157. }
  158. }
  159. *end = s;
  160. return coeff;
  161. }
  162. /* scan the payload of a NaN */
  163. static const char *
  164. scan_payload(const char *s, const char **end)
  165. {
  166. const char *coeff;
  167. while (*s == '0')
  168. s++;
  169. coeff = s;
  170. while (isdigit((uchar)*s))
  171. s++;
  172. *end = s;
  173. return (*s == '\0') ? coeff : NULL;
  174. }
  175. /* convert a character string to a decimal */
  176. void
  177. mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx,
  178. uint32_t *status)
  179. {
  180. mpd_ssize_t q, r, len;
  181. const char *coeff, *end;
  182. const char *dpoint = NULL, *exp = NULL;
  183. size_t digits;
  184. uint8_t sign = MPD_POS;
  185. mpd_set_flags(dec, 0);
  186. dec->len = 0;
  187. dec->exp = 0;
  188. /* sign */
  189. if (*s == '+') {
  190. s++;
  191. }
  192. else if (*s == '-') {
  193. mpd_set_negative(dec);
  194. sign = MPD_NEG;
  195. s++;
  196. }
  197. if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */
  198. s += 3;
  199. mpd_setspecial(dec, sign, MPD_NAN);
  200. if (*s == '\0')
  201. return;
  202. /* validate payload: digits only */
  203. if ((coeff = scan_payload(s, &end)) == NULL)
  204. goto conversion_error;
  205. /* payload consists entirely of zeros */
  206. if (*coeff == '\0')
  207. return;
  208. digits = end - coeff;
  209. /* prec >= 1, clamp is 0 or 1 */
  210. if (digits > (size_t)(ctx->prec-ctx->clamp))
  211. goto conversion_error;
  212. } /* sNaN */
  213. else if (_mpd_strneq(s, "snan", "SNAN", 4)) {
  214. s += 4;
  215. mpd_setspecial(dec, sign, MPD_SNAN);
  216. if (*s == '\0')
  217. return;
  218. /* validate payload: digits only */
  219. if ((coeff = scan_payload(s, &end)) == NULL)
  220. goto conversion_error;
  221. /* payload consists entirely of zeros */
  222. if (*coeff == '\0')
  223. return;
  224. digits = end - coeff;
  225. if (digits > (size_t)(ctx->prec-ctx->clamp))
  226. goto conversion_error;
  227. }
  228. else if (_mpd_strneq(s, "inf", "INF", 3)) {
  229. s += 3;
  230. if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) {
  231. /* numeric-value: infinity */
  232. mpd_setspecial(dec, sign, MPD_INF);
  233. return;
  234. }
  235. goto conversion_error;
  236. }
  237. else {
  238. /* scan for start of coefficient, decimal point, indicator, end */
  239. if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL)
  240. goto conversion_error;
  241. /* numeric-value: [exponent-part] */
  242. if (exp) {
  243. /* exponent-part */
  244. end = exp; exp++;
  245. dec->exp = strtoexp(exp);
  246. if (errno) {
  247. if (!(errno == ERANGE &&
  248. (dec->exp == MPD_SSIZE_MAX ||
  249. dec->exp == MPD_SSIZE_MIN)))
  250. goto conversion_error;
  251. }
  252. }
  253. digits = end - coeff;
  254. if (dpoint) {
  255. size_t fracdigits = end-dpoint-1;
  256. if (dpoint > coeff) digits--;
  257. if (fracdigits > MPD_MAX_PREC) {
  258. goto conversion_error;
  259. }
  260. if (dec->exp < MPD_SSIZE_MIN+(mpd_ssize_t)fracdigits) {
  261. dec->exp = MPD_SSIZE_MIN;
  262. }
  263. else {
  264. dec->exp -= (mpd_ssize_t)fracdigits;
  265. }
  266. }
  267. if (digits > MPD_MAX_PREC) {
  268. goto conversion_error;
  269. }
  270. if (dec->exp > MPD_EXP_INF) {
  271. dec->exp = MPD_EXP_INF;
  272. }
  273. if (dec->exp == MPD_SSIZE_MIN) {
  274. dec->exp = MPD_SSIZE_MIN+1;
  275. }
  276. }
  277. _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS);
  278. len = (r == 0) ? q : q+1;
  279. if (len == 0) {
  280. goto conversion_error; /* GCOV_NOT_REACHED */
  281. }
  282. if (!mpd_qresize(dec, len, status)) {
  283. mpd_seterror(dec, MPD_Malloc_error, status);
  284. return;
  285. }
  286. dec->len = len;
  287. string_to_coeff(dec->data, coeff, dpoint, (int)r, len);
  288. mpd_setdigits(dec);
  289. mpd_qfinalize(dec, ctx, status);
  290. return;
  291. conversion_error:
  292. /* standard wants a positive NaN */
  293. mpd_seterror(dec, MPD_Conversion_syntax, status);
  294. }
  295. /* Print word x with n decimal digits to string s. dot is either NULL
  296. or the location of a decimal point. */
  297. #define EXTRACT_DIGIT(s, x, d, dot) \
  298. if (s == dot) *s++ = '.'; *s++ = '0' + (char)(x / d); x %= d
  299. static inline char *
  300. word_to_string(char *s, mpd_uint_t x, int n, char *dot)
  301. {
  302. switch(n) {
  303. #ifdef CONFIG_64
  304. case 20: EXTRACT_DIGIT(s, x, 10000000000000000000ULL, dot); /* GCOV_NOT_REACHED */
  305. case 19: EXTRACT_DIGIT(s, x, 1000000000000000000ULL, dot);
  306. case 18: EXTRACT_DIGIT(s, x, 100000000000000000ULL, dot);
  307. case 17: EXTRACT_DIGIT(s, x, 10000000000000000ULL, dot);
  308. case 16: EXTRACT_DIGIT(s, x, 1000000000000000ULL, dot);
  309. case 15: EXTRACT_DIGIT(s, x, 100000000000000ULL, dot);
  310. case 14: EXTRACT_DIGIT(s, x, 10000000000000ULL, dot);
  311. case 13: EXTRACT_DIGIT(s, x, 1000000000000ULL, dot);
  312. case 12: EXTRACT_DIGIT(s, x, 100000000000ULL, dot);
  313. case 11: EXTRACT_DIGIT(s, x, 10000000000ULL, dot);
  314. #endif
  315. case 10: EXTRACT_DIGIT(s, x, 1000000000UL, dot);
  316. case 9: EXTRACT_DIGIT(s, x, 100000000UL, dot);
  317. case 8: EXTRACT_DIGIT(s, x, 10000000UL, dot);
  318. case 7: EXTRACT_DIGIT(s, x, 1000000UL, dot);
  319. case 6: EXTRACT_DIGIT(s, x, 100000UL, dot);
  320. case 5: EXTRACT_DIGIT(s, x, 10000UL, dot);
  321. case 4: EXTRACT_DIGIT(s, x, 1000UL, dot);
  322. case 3: EXTRACT_DIGIT(s, x, 100UL, dot);
  323. case 2: EXTRACT_DIGIT(s, x, 10UL, dot);
  324. default: if (s == dot) *s++ = '.'; *s++ = '0' + (char)x;
  325. }
  326. *s = '\0';
  327. return s;
  328. }
  329. /* Print exponent x to string s. Undefined for MPD_SSIZE_MIN. */
  330. static inline char *
  331. exp_to_string(char *s, mpd_ssize_t x)
  332. {
  333. char sign = '+';
  334. if (x < 0) {
  335. sign = '-';
  336. x = -x;
  337. }
  338. *s++ = sign;
  339. return word_to_string(s, x, mpd_word_digits(x), NULL);
  340. }
  341. /* Print the coefficient of dec to string s. len(dec) > 0. */
  342. static inline char *
  343. coeff_to_string(char *s, const mpd_t *dec)
  344. {
  345. mpd_uint_t x;
  346. mpd_ssize_t i;
  347. /* most significant word */
  348. x = mpd_msword(dec);
  349. s = word_to_string(s, x, mpd_word_digits(x), NULL);
  350. /* remaining full words */
  351. for (i=dec->len-2; i >= 0; --i) {
  352. x = dec->data[i];
  353. s = word_to_string(s, x, MPD_RDIGITS, NULL);
  354. }
  355. return s;
  356. }
  357. /* Print the coefficient of dec to string s. len(dec) > 0. dot is either
  358. NULL or a pointer to the location of a decimal point. */
  359. static inline char *
  360. coeff_to_string_dot(char *s, char *dot, const mpd_t *dec)
  361. {
  362. mpd_uint_t x;
  363. mpd_ssize_t i;
  364. /* most significant word */
  365. x = mpd_msword(dec);
  366. s = word_to_string(s, x, mpd_word_digits(x), dot);
  367. /* remaining full words */
  368. for (i=dec->len-2; i >= 0; --i) {
  369. x = dec->data[i];
  370. s = word_to_string(s, x, MPD_RDIGITS, dot);
  371. }
  372. return s;
  373. }
  374. /* Format type */
  375. #define MPD_FMT_LOWER 0x00000000
  376. #define MPD_FMT_UPPER 0x00000001
  377. #define MPD_FMT_TOSCI 0x00000002
  378. #define MPD_FMT_TOENG 0x00000004
  379. #define MPD_FMT_EXP 0x00000008
  380. #define MPD_FMT_FIXED 0x00000010
  381. #define MPD_FMT_PERCENT 0x00000020
  382. #define MPD_FMT_SIGN_SPACE 0x00000040
  383. #define MPD_FMT_SIGN_PLUS 0x00000080
  384. /* Default place of the decimal point for MPD_FMT_TOSCI, MPD_FMT_EXP */
  385. #define MPD_DEFAULT_DOTPLACE 1
  386. /*
  387. * Set *result to the string representation of a decimal. Return the length
  388. * of *result, not including the terminating '\0' character.
  389. *
  390. * Formatting is done according to 'flags'. A return value of -1 with *result
  391. * set to NULL indicates MPD_Malloc_error.
  392. *
  393. * 'dplace' is the default place of the decimal point. It is always set to
  394. * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP.
  395. */
  396. static mpd_ssize_t
  397. _mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace)
  398. {
  399. char *decstring = NULL, *cp = NULL;
  400. mpd_ssize_t ldigits;
  401. mpd_ssize_t mem = 0, k;
  402. if (mpd_isspecial(dec)) {
  403. mem = sizeof "-Infinity%";
  404. if (mpd_isnan(dec) && dec->len > 0) {
  405. /* diagnostic code */
  406. mem += dec->digits;
  407. }
  408. cp = decstring = mpd_alloc(mem, sizeof *decstring);
  409. if (cp == NULL) {
  410. *result = NULL;
  411. return -1;
  412. }
  413. if (mpd_isnegative(dec)) {
  414. *cp++ = '-';
  415. }
  416. else if (flags&MPD_FMT_SIGN_SPACE) {
  417. *cp++ = ' ';
  418. }
  419. else if (flags&MPD_FMT_SIGN_PLUS) {
  420. *cp++ = '+';
  421. }
  422. if (mpd_isnan(dec)) {
  423. if (mpd_isqnan(dec)) {
  424. strcpy(cp, "NaN");
  425. cp += 3;
  426. }
  427. else {
  428. strcpy(cp, "sNaN");
  429. cp += 4;
  430. }
  431. if (dec->len > 0) { /* diagnostic code */
  432. cp = coeff_to_string(cp, dec);
  433. }
  434. }
  435. else if (mpd_isinfinite(dec)) {
  436. strcpy(cp, "Infinity");
  437. cp += 8;
  438. }
  439. else { /* debug */
  440. abort(); /* GCOV_NOT_REACHED */
  441. }
  442. }
  443. else {
  444. assert(dec->len > 0);
  445. /*
  446. * For easier manipulation of the decimal point's location
  447. * and the exponent that is finally printed, the number is
  448. * rescaled to a virtual representation with exp = 0. Here
  449. * ldigits denotes the number of decimal digits to the left
  450. * of the decimal point and remains constant once initialized.
  451. *
  452. * dplace is the location of the decimal point relative to
  453. * the start of the coefficient. Note that 3) always holds
  454. * when dplace is shifted.
  455. *
  456. * 1) ldigits := dec->digits - dec->exp
  457. * 2) dplace := ldigits (initially)
  458. * 3) exp := ldigits - dplace (initially exp = 0)
  459. *
  460. * 0.00000_.____._____000000.
  461. * ^ ^ ^ ^
  462. * | | | |
  463. * | | | `- dplace >= digits
  464. * | | `- dplace in the middle of the coefficient
  465. * | ` dplace = 1 (after the first coefficient digit)
  466. * `- dplace <= 0
  467. */
  468. ldigits = dec->digits + dec->exp;
  469. if (flags&MPD_FMT_EXP) {
  470. ;
  471. }
  472. else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) {
  473. /* MPD_FMT_FIXED: always use fixed point notation.
  474. * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range,
  475. * override exponent notation. */
  476. dplace = ldigits;
  477. }
  478. else if (flags&MPD_FMT_TOENG) {
  479. if (mpd_iszero(dec)) {
  480. /* If the exponent is divisible by three,
  481. * dplace = 1. Otherwise, move dplace one
  482. * or two places to the left. */
  483. dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3);
  484. }
  485. else { /* ldigits-1 is the adjusted exponent, which
  486. * should be divisible by three. If not, move
  487. * dplace one or two places to the right. */
  488. dplace += mod_mpd_ssize_t(ldigits-1, 3);
  489. }
  490. }
  491. /*
  492. * Basic space requirements:
  493. *
  494. * [-][.][coeffdigits][E][-][expdigits+1][%]['\0']
  495. *
  496. * If the decimal point lies outside of the coefficient digits,
  497. * space is adjusted accordingly.
  498. */
  499. if (dplace <= 0) {
  500. mem = -dplace + dec->digits + 2;
  501. }
  502. else if (dplace >= dec->digits) {
  503. mem = dplace;
  504. }
  505. else {
  506. mem = dec->digits;
  507. }
  508. mem += (MPD_EXPDIGITS+1+6);
  509. cp = decstring = mpd_alloc(mem, sizeof *decstring);
  510. if (cp == NULL) {
  511. *result = NULL;
  512. return -1;
  513. }
  514. if (mpd_isnegative(dec)) {
  515. *cp++ = '-';
  516. }
  517. else if (flags&MPD_FMT_SIGN_SPACE) {
  518. *cp++ = ' ';
  519. }
  520. else if (flags&MPD_FMT_SIGN_PLUS) {
  521. *cp++ = '+';
  522. }
  523. if (dplace <= 0) {
  524. /* space: -dplace+dec->digits+2 */
  525. *cp++ = '0';
  526. *cp++ = '.';
  527. for (k = 0; k < -dplace; k++) {
  528. *cp++ = '0';
  529. }
  530. cp = coeff_to_string(cp, dec);
  531. }
  532. else if (dplace >= dec->digits) {
  533. /* space: dplace */
  534. cp = coeff_to_string(cp, dec);
  535. for (k = 0; k < dplace-dec->digits; k++) {
  536. *cp++ = '0';
  537. }
  538. }
  539. else {
  540. /* space: dec->digits+1 */
  541. cp = coeff_to_string_dot(cp, cp+dplace, dec);
  542. }
  543. /*
  544. * Conditions for printing an exponent:
  545. *
  546. * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace
  547. * MPD_FMT_FIXED: never (ldigits == dplace)
  548. * MPD_FMT_EXP: always
  549. */
  550. if (ldigits != dplace || flags&MPD_FMT_EXP) {
  551. /* space: expdigits+2 */
  552. *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e';
  553. cp = exp_to_string(cp, ldigits-dplace);
  554. }
  555. }
  556. if (flags&MPD_FMT_PERCENT) {
  557. *cp++ = '%';
  558. }
  559. assert(cp < decstring+mem);
  560. assert(cp-decstring < MPD_SSIZE_MAX);
  561. *cp = '\0';
  562. *result = decstring;
  563. return (mpd_ssize_t)(cp-decstring);
  564. }
  565. char *
  566. mpd_to_sci(const mpd_t *dec, int fmt)
  567. {
  568. char *res;
  569. int flags = MPD_FMT_TOSCI;
  570. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  571. (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE);
  572. return res;
  573. }
  574. char *
  575. mpd_to_eng(const mpd_t *dec, int fmt)
  576. {
  577. char *res;
  578. int flags = MPD_FMT_TOENG;
  579. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  580. (void)_mpd_to_string(&res, dec, flags, MPD_DEFAULT_DOTPLACE);
  581. return res;
  582. }
  583. mpd_ssize_t
  584. mpd_to_sci_size(char **res, const mpd_t *dec, int fmt)
  585. {
  586. int flags = MPD_FMT_TOSCI;
  587. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  588. return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE);
  589. }
  590. mpd_ssize_t
  591. mpd_to_eng_size(char **res, const mpd_t *dec, int fmt)
  592. {
  593. int flags = MPD_FMT_TOENG;
  594. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  595. return _mpd_to_string(res, dec, flags, MPD_DEFAULT_DOTPLACE);
  596. }
  597. /* Copy a single UTF-8 char to dest. See: The Unicode Standard, version 5.2,
  598. chapter 3.9: Well-formed UTF-8 byte sequences. */
  599. static int
  600. _mpd_copy_utf8(char dest[5], const char *s)
  601. {
  602. const uchar *cp = (const uchar *)s;
  603. uchar lb, ub;
  604. int count, i;
  605. if (*cp == 0) {
  606. /* empty string */
  607. dest[0] = '\0';
  608. return 0;
  609. }
  610. else if (*cp <= 0x7f) {
  611. /* ascii */
  612. dest[0] = *cp;
  613. dest[1] = '\0';
  614. return 1;
  615. }
  616. else if (0xc2 <= *cp && *cp <= 0xdf) {
  617. lb = 0x80; ub = 0xbf;
  618. count = 2;
  619. }
  620. else if (*cp == 0xe0) {
  621. lb = 0xa0; ub = 0xbf;
  622. count = 3;
  623. }
  624. else if (*cp <= 0xec) {
  625. lb = 0x80; ub = 0xbf;
  626. count = 3;
  627. }
  628. else if (*cp == 0xed) {
  629. lb = 0x80; ub = 0x9f;
  630. count = 3;
  631. }
  632. else if (*cp <= 0xef) {
  633. lb = 0x80; ub = 0xbf;
  634. count = 3;
  635. }
  636. else if (*cp == 0xf0) {
  637. lb = 0x90; ub = 0xbf;
  638. count = 4;
  639. }
  640. else if (*cp <= 0xf3) {
  641. lb = 0x80; ub = 0xbf;
  642. count = 4;
  643. }
  644. else if (*cp == 0xf4) {
  645. lb = 0x80; ub = 0x8f;
  646. count = 4;
  647. }
  648. else {
  649. /* invalid */
  650. goto error;
  651. }
  652. dest[0] = *cp++;
  653. if (*cp < lb || ub < *cp) {
  654. goto error;
  655. }
  656. dest[1] = *cp++;
  657. for (i = 2; i < count; i++) {
  658. if (*cp < 0x80 || 0xbf < *cp) {
  659. goto error;
  660. }
  661. dest[i] = *cp++;
  662. }
  663. dest[i] = '\0';
  664. return count;
  665. error:
  666. dest[0] = '\0';
  667. return -1;
  668. }
  669. int
  670. mpd_validate_lconv(mpd_spec_t *spec)
  671. {
  672. size_t n;
  673. #if CHAR_MAX == SCHAR_MAX
  674. const char *cp = spec->grouping;
  675. while (*cp != '\0') {
  676. if (*cp++ < 0) {
  677. return -1;
  678. }
  679. }
  680. #endif
  681. n = strlen(spec->dot);
  682. if (n == 0 || n > 4) {
  683. return -1;
  684. }
  685. if (strlen(spec->sep) > 4) {
  686. return -1;
  687. }
  688. return 0;
  689. }
  690. int
  691. mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps)
  692. {
  693. char *cp = (char *)fmt;
  694. int have_align = 0, n;
  695. /* defaults */
  696. spec->min_width = 0;
  697. spec->prec = -1;
  698. spec->type = caps ? 'G' : 'g';
  699. spec->align = '>';
  700. spec->sign = '-';
  701. spec->dot = "";
  702. spec->sep = "";
  703. spec->grouping = "";
  704. /* presume that the first character is a UTF-8 fill character */
  705. if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) {
  706. return 0;
  707. }
  708. /* alignment directive, prefixed by a fill character */
  709. if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' ||
  710. *(cp+n) == '=' || *(cp+n) == '^')) {
  711. cp += n;
  712. spec->align = *cp++;
  713. have_align = 1;
  714. } /* alignment directive */
  715. else {
  716. /* default fill character */
  717. spec->fill[0] = ' ';
  718. spec->fill[1] = '\0';
  719. if (*cp == '<' || *cp == '>' ||
  720. *cp == '=' || *cp == '^') {
  721. spec->align = *cp++;
  722. have_align = 1;
  723. }
  724. }
  725. /* sign formatting */
  726. if (*cp == '+' || *cp == '-' || *cp == ' ') {
  727. spec->sign = *cp++;
  728. }
  729. /* zero padding */
  730. if (*cp == '0') {
  731. /* zero padding implies alignment, which should not be
  732. * specified twice. */
  733. if (have_align) {
  734. return 0;
  735. }
  736. spec->align = 'z';
  737. spec->fill[0] = *cp++;
  738. spec->fill[1] = '\0';
  739. }
  740. /* minimum width */
  741. if (isdigit((uchar)*cp)) {
  742. if (*cp == '0') {
  743. return 0;
  744. }
  745. errno = 0;
  746. spec->min_width = mpd_strtossize(cp, &cp, 10);
  747. if (errno == ERANGE || errno == EINVAL) {
  748. return 0;
  749. }
  750. }
  751. /* thousands separator */
  752. if (*cp == ',') {
  753. spec->dot = ".";
  754. spec->sep = ",";
  755. spec->grouping = "\003\003";
  756. cp++;
  757. }
  758. /* fraction digits or significant digits */
  759. if (*cp == '.') {
  760. cp++;
  761. if (!isdigit((uchar)*cp)) {
  762. return 0;
  763. }
  764. errno = 0;
  765. spec->prec = mpd_strtossize(cp, &cp, 10);
  766. if (errno == ERANGE || errno == EINVAL) {
  767. return 0;
  768. }
  769. }
  770. /* type */
  771. if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' ||
  772. *cp == 'G' || *cp == 'g' || *cp == '%') {
  773. spec->type = *cp++;
  774. }
  775. else if (*cp == 'N' || *cp == 'n') {
  776. /* locale specific conversion */
  777. struct lconv *lc;
  778. /* separator has already been specified */
  779. if (*spec->sep) {
  780. return 0;
  781. }
  782. spec->type = *cp++;
  783. spec->type = (spec->type == 'N') ? 'G' : 'g';
  784. lc = localeconv();
  785. spec->dot = lc->decimal_point;
  786. spec->sep = lc->thousands_sep;
  787. spec->grouping = lc->grouping;
  788. if (mpd_validate_lconv(spec) < 0) {
  789. return 0; /* GCOV_NOT_REACHED */
  790. }
  791. }
  792. /* check correctness */
  793. if (*cp != '\0') {
  794. return 0;
  795. }
  796. return 1;
  797. }
  798. /*
  799. * The following functions assume that spec->min_width <= MPD_MAX_PREC, which
  800. * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a
  801. * four-byte separator after each digit, nbytes in the following struct
  802. * cannot overflow.
  803. */
  804. /* Multibyte string */
  805. typedef struct {
  806. mpd_ssize_t nbytes; /* length in bytes */
  807. mpd_ssize_t nchars; /* length in chars */
  808. mpd_ssize_t cur; /* current write index */
  809. char *data;
  810. } mpd_mbstr_t;
  811. static inline void
  812. _mpd_bcopy(char *dest, const char *src, mpd_ssize_t n)
  813. {
  814. while (--n >= 0) {
  815. dest[n] = src[n];
  816. }
  817. }
  818. static inline void
  819. _mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
  820. {
  821. dest->nbytes += n;
  822. dest->nchars += (n > 0 ? 1 : 0);
  823. dest->cur -= n;
  824. if (dest->data != NULL) {
  825. _mpd_bcopy(dest->data+dest->cur, src, n);
  826. }
  827. }
  828. static inline void
  829. _mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
  830. {
  831. dest->nbytes += n;
  832. dest->nchars += n;
  833. dest->cur -= n;
  834. if (dest->data != NULL) {
  835. _mpd_bcopy(dest->data+dest->cur, src, n);
  836. }
  837. }
  838. static inline void
  839. _mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n)
  840. {
  841. dest->nbytes += n;
  842. dest->nchars += n;
  843. dest->cur -= n;
  844. if (dest->data != NULL) {
  845. char *cp = dest->data + dest->cur;
  846. while (--n >= 0) {
  847. cp[n] = '0';
  848. }
  849. }
  850. }
  851. /*
  852. * Copy a numeric string to dest->data, adding separators in the integer
  853. * part according to spec->grouping. If leading zero padding is enabled
  854. * and the result is smaller than spec->min_width, continue adding zeros
  855. * and separators until the minimum width is reached.
  856. *
  857. * The final length of dest->data is stored in dest->nbytes. The number
  858. * of UTF-8 characters is stored in dest->nchars.
  859. *
  860. * First run (dest->data == NULL): determine the length of the result
  861. * string and store it in dest->nbytes.
  862. *
  863. * Second run (write to dest->data): data is written in chunks and in
  864. * reverse order, starting with the rest of the numeric string.
  865. */
  866. static void
  867. _mpd_add_sep_dot(mpd_mbstr_t *dest,
  868. const char *sign, /* location of optional sign */
  869. const char *src, mpd_ssize_t n_src, /* integer part and length */
  870. const char *dot, /* location of optional decimal point */
  871. const char *rest, mpd_ssize_t n_rest, /* remaining part and length */
  872. const mpd_spec_t *spec)
  873. {
  874. mpd_ssize_t n_sep, n_sign, consume;
  875. const char *g;
  876. int pad = 0;
  877. n_sign = sign ? 1 : 0;
  878. n_sep = (mpd_ssize_t)strlen(spec->sep);
  879. /* Initial write index: set to location of '\0' in the output string.
  880. * Irrelevant for the first run. */
  881. dest->cur = dest->nbytes;
  882. dest->nbytes = dest->nchars = 0;
  883. _mbstr_copy_ascii(dest, rest, n_rest);
  884. if (dot) {
  885. _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot));
  886. }
  887. g = spec->grouping;
  888. consume = *g;
  889. while (1) {
  890. /* If the group length is 0 or CHAR_MAX or greater than the
  891. * number of source bytes, consume all remaining bytes. */
  892. if (*g == 0 || *g == CHAR_MAX || consume > n_src) {
  893. consume = n_src;
  894. }
  895. n_src -= consume;
  896. if (pad) {
  897. _mbstr_copy_pad(dest, consume);
  898. }
  899. else {
  900. _mbstr_copy_ascii(dest, src+n_src, consume);
  901. }
  902. if (n_src == 0) {
  903. /* Either the real source of intpart digits or the virtual
  904. * source of padding zeros is exhausted. */
  905. if (spec->align == 'z' &&
  906. dest->nchars + n_sign < spec->min_width) {
  907. /* Zero padding is set and length < min_width:
  908. * Generate n_src additional characters. */
  909. n_src = spec->min_width - (dest->nchars + n_sign);
  910. /* Next iteration:
  911. * case *g == 0 || *g == CHAR_MAX:
  912. * consume all padding characters
  913. * case consume < g*:
  914. * fill remainder of current group
  915. * case consume == g*
  916. * copying is a no-op */
  917. consume = *g - consume;
  918. /* Switch on virtual source of zeros. */
  919. pad = 1;
  920. continue;
  921. }
  922. break;
  923. }
  924. if (n_sep > 0) {
  925. /* If padding is switched on, separators are counted
  926. * as padding characters. This rule does not apply if
  927. * the separator would be the first character of the
  928. * result string. */
  929. if (pad && n_src > 1) n_src -= 1;
  930. _mbstr_copy_char(dest, spec->sep, n_sep);
  931. }
  932. /* If non-NUL, use the next value for grouping. */
  933. if (*g && *(g+1)) g++;
  934. consume = *g;
  935. }
  936. if (sign) {
  937. _mbstr_copy_ascii(dest, sign, 1);
  938. }
  939. if (dest->data) {
  940. dest->data[dest->nbytes] = '\0';
  941. }
  942. }
  943. /*
  944. * Convert a numeric-string to its locale-specific appearance.
  945. * The string must have one of these forms:
  946. *
  947. * 1) [sign] digits [exponent-part]
  948. * 2) [sign] digits '.' [digits] [exponent-part]
  949. *
  950. * Not allowed, since _mpd_to_string() never returns this form:
  951. *
  952. * 3) [sign] '.' digits [exponent-part]
  953. *
  954. * Input: result->data := original numeric string (ASCII)
  955. * result->bytes := strlen(result->data)
  956. * result->nchars := strlen(result->data)
  957. *
  958. * Output: result->data := modified or original string
  959. * result->bytes := strlen(result->data)
  960. * result->nchars := number of characters (possibly UTF-8)
  961. */
  962. static int
  963. _mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status)
  964. {
  965. const char *sign = NULL, *intpart = NULL, *dot = NULL;
  966. const char *rest, *dp;
  967. char *decstring;
  968. mpd_ssize_t n_int, n_rest;
  969. /* original numeric string */
  970. dp = result->data;
  971. /* sign */
  972. if (*dp == '+' || *dp == '-' || *dp == ' ') {
  973. sign = dp++;
  974. }
  975. /* integer part */
  976. assert(isdigit((uchar)*dp));
  977. intpart = dp++;
  978. while (isdigit((uchar)*dp)) {
  979. dp++;
  980. }
  981. n_int = (mpd_ssize_t)(dp-intpart);
  982. /* decimal point */
  983. if (*dp == '.') {
  984. dp++; dot = spec->dot;
  985. }
  986. /* rest */
  987. rest = dp;
  988. n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data);
  989. if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) {
  990. /* _mpd_add_sep_dot() would not change anything */
  991. return 1;
  992. }
  993. /* Determine the size of the new decimal string after inserting the
  994. * decimal point, optional separators and optional padding. */
  995. decstring = result->data;
  996. result->data = NULL;
  997. _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
  998. rest, n_rest, spec);
  999. result->data = mpd_alloc(result->nbytes+1, 1);
  1000. if (result->data == NULL) {
  1001. *status |= MPD_Malloc_error;
  1002. mpd_free(decstring);
  1003. return 0;
  1004. }
  1005. /* Perform actual writes. */
  1006. _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
  1007. rest, n_rest, spec);
  1008. mpd_free(decstring);
  1009. return 1;
  1010. }
  1011. /* Add padding to the formatted string if necessary. */
  1012. static int
  1013. _mpd_add_pad(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status)
  1014. {
  1015. if (result->nchars < spec->min_width) {
  1016. mpd_ssize_t add_chars, add_bytes;
  1017. size_t lpad = 0, rpad = 0;
  1018. size_t n_fill, len, i, j;
  1019. char align = spec->align;
  1020. uint8_t err = 0;
  1021. char *cp;
  1022. n_fill = strlen(spec->fill);
  1023. add_chars = (spec->min_width - result->nchars);
  1024. /* max value: MPD_MAX_PREC * 4 */
  1025. add_bytes = add_chars * (mpd_ssize_t)n_fill;
  1026. cp = result->data = mpd_realloc(result->data,
  1027. result->nbytes+add_bytes+1,
  1028. sizeof *result->data, &err);
  1029. if (err) {
  1030. *status |= MPD_Malloc_error;
  1031. mpd_free(result->data);
  1032. return 0;
  1033. }
  1034. if (align == 'z') {
  1035. align = '=';
  1036. }
  1037. if (align == '<') {
  1038. rpad = add_chars;
  1039. }
  1040. else if (align == '>' || align == '=') {
  1041. lpad = add_chars;
  1042. }
  1043. else { /* align == '^' */
  1044. lpad = add_chars/2;
  1045. rpad = add_chars-lpad;
  1046. }
  1047. len = result->nbytes;
  1048. if (align == '=' && (*cp == '-' || *cp == '+' || *cp == ' ')) {
  1049. /* leave sign in the leading position */
  1050. cp++; len--;
  1051. }
  1052. memmove(cp+n_fill*lpad, cp, len);
  1053. for (i = 0; i < lpad; i++) {
  1054. for (j = 0; j < n_fill; j++) {
  1055. cp[i*n_fill+j] = spec->fill[j];
  1056. }
  1057. }
  1058. cp += (n_fill*lpad + len);
  1059. for (i = 0; i < rpad; i++) {
  1060. for (j = 0; j < n_fill; j++) {
  1061. cp[i*n_fill+j] = spec->fill[j];
  1062. }
  1063. }
  1064. result->nbytes += add_bytes;
  1065. result->nchars += add_chars;
  1066. result->data[result->nbytes] = '\0';
  1067. }
  1068. return 1;
  1069. }
  1070. /* Round a number to prec digits. The adjusted exponent stays the same
  1071. or increases by one if rounding up crosses a power of ten boundary.
  1072. If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation
  1073. is set and the result is NaN. */
  1074. static inline void
  1075. _mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec,
  1076. const mpd_context_t *ctx, uint32_t *status)
  1077. {
  1078. mpd_ssize_t exp = a->exp + a->digits - prec;
  1079. if (prec <= 0) {
  1080. mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */
  1081. return; /* GCOV_NOT_REACHED */
  1082. }
  1083. if (mpd_isspecial(a) || mpd_iszero(a)) {
  1084. mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */
  1085. return; /* GCOV_NOT_REACHED */
  1086. }
  1087. mpd_qrescale_fmt(result, a, exp, ctx, status);
  1088. if (result->digits > prec) {
  1089. mpd_qrescale_fmt(result, result, exp+1, ctx, status);
  1090. }
  1091. }
  1092. /*
  1093. * Return the string representation of an mpd_t, formatted according to 'spec'.
  1094. * The format specification is assumed to be valid. Memory errors are indicated
  1095. * as usual. This function is quiet.
  1096. */
  1097. char *
  1098. mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec,
  1099. const mpd_context_t *ctx, uint32_t *status)
  1100. {
  1101. mpd_uint_t dt[MPD_MINALLOC_MAX];
  1102. mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
  1103. mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE;
  1104. mpd_mbstr_t result;
  1105. mpd_spec_t stackspec;
  1106. char type = spec->type;
  1107. int flags = 0;
  1108. if (spec->min_width > MPD_MAX_PREC) {
  1109. *status |= MPD_Invalid_operation;
  1110. return NULL;
  1111. }
  1112. if (isupper((uchar)type)) {
  1113. type = tolower((uchar)type);
  1114. flags |= MPD_FMT_UPPER;
  1115. }
  1116. if (spec->sign == ' ') {
  1117. flags |= MPD_FMT_SIGN_SPACE;
  1118. }
  1119. else if (spec->sign == '+') {
  1120. flags |= MPD_FMT_SIGN_PLUS;
  1121. }
  1122. if (mpd_isspecial(dec)) {
  1123. if (spec->align == 'z') {
  1124. stackspec = *spec;
  1125. stackspec.fill[0] = ' ';
  1126. stackspec.fill[1] = '\0';
  1127. stackspec.align = '>';
  1128. spec = &stackspec;
  1129. }
  1130. if (type == '%') {
  1131. flags |= MPD_FMT_PERCENT;
  1132. }
  1133. }
  1134. else {
  1135. uint32_t workstatus = 0;
  1136. mpd_ssize_t prec;
  1137. switch (type) {
  1138. case 'g': flags |= MPD_FMT_TOSCI; break;
  1139. case 'e': flags |= MPD_FMT_EXP; break;
  1140. case '%': flags |= MPD_FMT_PERCENT;
  1141. if (!mpd_qcopy(&tmp, dec, status)) {
  1142. return NULL;
  1143. }
  1144. tmp.exp += 2;
  1145. dec = &tmp;
  1146. type = 'f'; /* fall through */
  1147. case 'f': flags |= MPD_FMT_FIXED; break;
  1148. default: abort(); /* debug: GCOV_NOT_REACHED */
  1149. }
  1150. if (spec->prec >= 0) {
  1151. if (spec->prec > MPD_MAX_PREC) {
  1152. *status |= MPD_Invalid_operation;
  1153. goto error;
  1154. }
  1155. switch (type) {
  1156. case 'g':
  1157. prec = (spec->prec == 0) ? 1 : spec->prec;
  1158. if (dec->digits > prec) {
  1159. _mpd_round(&tmp, dec, prec, ctx,
  1160. &workstatus);
  1161. dec = &tmp;
  1162. }
  1163. break;
  1164. case 'e':
  1165. if (mpd_iszero(dec)) {
  1166. dplace = 1-spec->prec;
  1167. }
  1168. else {
  1169. _mpd_round(&tmp, dec, spec->prec+1, ctx,
  1170. &workstatus);
  1171. dec = &tmp;
  1172. }
  1173. break;
  1174. case 'f':
  1175. mpd_qrescale(&tmp, dec, -spec->prec, ctx,
  1176. &workstatus);
  1177. dec = &tmp;
  1178. break;
  1179. }
  1180. }
  1181. if (type == 'f') {
  1182. if (mpd_iszero(dec) && dec->exp > 0) {
  1183. mpd_qrescale(&tmp, dec, 0, ctx, &workstatus);
  1184. dec = &tmp;
  1185. }
  1186. }
  1187. if (workstatus&MPD_Errors) {
  1188. *status |= (workstatus&MPD_Errors);
  1189. goto error;
  1190. }
  1191. }
  1192. /*
  1193. * At this point, for all scaled or non-scaled decimals:
  1194. * 1) 1 <= digits <= MAX_PREC+1
  1195. * 2) adjexp(scaled) = adjexp(orig) [+1]
  1196. * 3) case 'g': MIN_ETINY <= exp <= MAX_EMAX+1
  1197. * case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1
  1198. * case 'f': MIN_ETINY <= exp <= MAX_EMAX+1
  1199. * 4) max memory alloc in _mpd_to_string:
  1200. * case 'g': MAX_PREC+36
  1201. * case 'e': MAX_PREC+36
  1202. * case 'f': 2*MPD_MAX_PREC+30
  1203. */
  1204. result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace);
  1205. result.nchars = result.nbytes;
  1206. if (result.nbytes < 0) {
  1207. *status |= MPD_Malloc_error;
  1208. goto error;
  1209. }
  1210. if (*spec->dot != '\0' && !mpd_isspecial(dec)) {
  1211. if (result.nchars > MPD_MAX_PREC+36) {
  1212. /* Since a group length of one is not explicitly
  1213. * disallowed, ensure that it is always possible to
  1214. * insert a four byte separator after each digit. */
  1215. *status |= MPD_Invalid_operation;
  1216. mpd_free(result.data);
  1217. goto error;
  1218. }
  1219. if (!_mpd_apply_lconv(&result, spec, status)) {
  1220. goto error;
  1221. }
  1222. }
  1223. if (spec->min_width) {
  1224. if (!_mpd_add_pad(&result, spec, status)) {
  1225. goto error;
  1226. }
  1227. }
  1228. mpd_del(&tmp);
  1229. return result.data;
  1230. error:
  1231. mpd_del(&tmp);
  1232. return NULL;
  1233. }
  1234. char *
  1235. mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx,
  1236. uint32_t *status)
  1237. {
  1238. mpd_spec_t spec;
  1239. if (!mpd_parse_fmt_str(&spec, fmt, 1)) {
  1240. *status |= MPD_Invalid_operation;
  1241. return NULL;
  1242. }
  1243. return mpd_qformat_spec(dec, &spec, ctx, status);
  1244. }
  1245. /*
  1246. * The specification has a *condition* called Invalid_operation and an
  1247. * IEEE *signal* called Invalid_operation. The former corresponds to
  1248. * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation.
  1249. * MPD_IEEE_Invalid_operation comprises the following conditions:
  1250. *
  1251. * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined,
  1252. * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation,
  1253. * MPD_Malloc_error]
  1254. *
  1255. * In the following functions, 'flag' denotes the condition, 'signal'
  1256. * denotes the IEEE signal.
  1257. */
  1258. static const char *mpd_flag_string[MPD_NUM_FLAGS] = {
  1259. "Clamped",
  1260. "Conversion_syntax",
  1261. "Division_by_zero",
  1262. "Division_impossible",
  1263. "Division_undefined",
  1264. "Fpu_error",
  1265. "Inexact",
  1266. "Invalid_context",
  1267. "Invalid_operation",
  1268. "Malloc_error",
  1269. "Not_implemented",
  1270. "Overflow",
  1271. "Rounded",
  1272. "Subnormal",
  1273. "Underflow",
  1274. };
  1275. static const char *mpd_signal_string[MPD_NUM_FLAGS] = {
  1276. "Clamped",
  1277. "IEEE_Invalid_operation",
  1278. "Division_by_zero",
  1279. "IEEE_Invalid_operation",
  1280. "IEEE_Invalid_operation",
  1281. "IEEE_Invalid_operation",
  1282. "Inexact",
  1283. "IEEE_Invalid_operation",
  1284. "IEEE_Invalid_operation",
  1285. "IEEE_Invalid_operation",
  1286. "Not_implemented",
  1287. "Overflow",
  1288. "Rounded",
  1289. "Subnormal",
  1290. "Underflow",
  1291. };
  1292. /* print conditions to buffer, separated by spaces */
  1293. int
  1294. mpd_snprint_flags(char *dest, int nmemb, uint32_t flags)
  1295. {
  1296. char *cp;
  1297. int n, j;
  1298. assert(nmemb >= MPD_MAX_FLAG_STRING);
  1299. *dest = '\0'; cp = dest;
  1300. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1301. if (flags & (1U<<j)) {
  1302. n = snprintf(cp, nmemb, "%s ", mpd_flag_string[j]);
  1303. if (n < 0 || n >= nmemb) return -1;
  1304. cp += n; nmemb -= n;
  1305. }
  1306. }
  1307. if (cp != dest) {
  1308. *(--cp) = '\0';
  1309. }
  1310. return (int)(cp-dest);
  1311. }
  1312. /* print conditions to buffer, in list form */
  1313. int
  1314. mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[])
  1315. {
  1316. char *cp;
  1317. int n, j;
  1318. assert(nmemb >= MPD_MAX_FLAG_LIST);
  1319. if (flag_string == NULL) {
  1320. flag_string = mpd_flag_string;
  1321. }
  1322. *dest = '[';
  1323. *(dest+1) = '\0';
  1324. cp = dest+1;
  1325. --nmemb;
  1326. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1327. if (flags & (1U<<j)) {
  1328. n = snprintf(cp, nmemb, "%s, ", flag_string[j]);
  1329. if (n < 0 || n >= nmemb) return -1;
  1330. cp += n; nmemb -= n;
  1331. }
  1332. }
  1333. /* erase the last ", " */
  1334. if (cp != dest+1) {
  1335. cp -= 2;
  1336. }
  1337. *cp++ = ']';
  1338. *cp = '\0';
  1339. return (int)(cp-dest); /* strlen, without NUL terminator */
  1340. }
  1341. /* print signals to buffer, in list form */
  1342. int
  1343. mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[])
  1344. {
  1345. char *cp;
  1346. int n, j;
  1347. int ieee_invalid_done = 0;
  1348. assert(nmemb >= MPD_MAX_SIGNAL_LIST);
  1349. if (signal_string == NULL) {
  1350. signal_string = mpd_signal_string;
  1351. }
  1352. *dest = '[';
  1353. *(dest+1) = '\0';
  1354. cp = dest+1;
  1355. --nmemb;
  1356. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1357. uint32_t f = flags & (1U<<j);
  1358. if (f) {
  1359. if (f&MPD_IEEE_Invalid_operation) {
  1360. if (ieee_invalid_done) {
  1361. continue;
  1362. }
  1363. ieee_invalid_done = 1;
  1364. }
  1365. n = snprintf(cp, nmemb, "%s, ", signal_string[j]);
  1366. if (n < 0 || n >= nmemb) return -1;
  1367. cp += n; nmemb -= n;
  1368. }
  1369. }
  1370. /* erase the last ", " */
  1371. if (cp != dest+1) {
  1372. cp -= 2;
  1373. }
  1374. *cp++ = ']';
  1375. *cp = '\0';
  1376. return (int)(cp-dest); /* strlen, without NUL terminator */
  1377. }
  1378. /* The following two functions are mainly intended for debugging. */
  1379. void
  1380. mpd_fprint(FILE *file, const mpd_t *dec)
  1381. {
  1382. char *decstring;
  1383. decstring = mpd_to_sci(dec, 1);
  1384. if (decstring != NULL) {
  1385. fprintf(file, "%s\n", decstring);
  1386. mpd_free(decstring);
  1387. }
  1388. else {
  1389. fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */
  1390. }
  1391. }
  1392. void
  1393. mpd_print(const mpd_t *dec)
  1394. {
  1395. char *decstring;
  1396. decstring = mpd_to_sci(dec, 1);
  1397. if (decstring != NULL) {
  1398. printf("%s\n", decstring);
  1399. mpd_free(decstring);
  1400. }
  1401. else {
  1402. fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */
  1403. }
  1404. }