io.c 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397
  1. /*
  2. * Copyright (c) 2008-2010 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. #include <errno.h>
  35. #include <locale.h>
  36. #include "bits.h"
  37. #include "constants.h"
  38. #include "memory.h"
  39. #include "typearith.h"
  40. #include "io.h"
  41. /*
  42. * Work around the behavior of tolower() and strcasecmp() in certain
  43. * locales. For example, in tr_TR.utf8:
  44. *
  45. * tolower((unsigned char)'I') == 'I'
  46. *
  47. * u is the exact uppercase version of l; n is strlen(l) or strlen(l)+1
  48. */
  49. static inline int
  50. _mpd_strneq(const char *s, const char *l, const char *u, size_t n)
  51. {
  52. while (--n != SIZE_MAX) {
  53. if (*s != *l && *s != *u) {
  54. return 0;
  55. }
  56. s++; u++; l++;
  57. }
  58. return 1;
  59. }
  60. static mpd_ssize_t
  61. strtoexp(const char *s)
  62. {
  63. char *end;
  64. mpd_ssize_t retval;
  65. errno = 0;
  66. retval = mpd_strtossize(s, &end, 10);
  67. if (errno == 0 && !(*s != '\0' && *end == '\0'))
  68. errno = EINVAL;
  69. return retval;
  70. }
  71. /*
  72. * Scan 'len' words. The most significant word contains 'r' digits,
  73. * the remaining words are full words. Skip dpoint. The string 's' must
  74. * consist of digits and an optional single decimal point at 'dpoint'.
  75. */
  76. static void
  77. string_to_coeff(mpd_uint_t *data, const char *s, const char *dpoint, int r,
  78. size_t len)
  79. {
  80. int j;
  81. if (r > 0) {
  82. data[--len] = 0;
  83. for (j = 0; j < r; j++, s++) {
  84. if (s == dpoint) s++;
  85. data[len] = 10 * data[len] + (*s - '0');
  86. }
  87. }
  88. while (--len != SIZE_MAX) {
  89. data[len] = 0;
  90. for (j = 0; j < MPD_RDIGITS; j++, s++) {
  91. if (s == dpoint) s++;
  92. data[len] = 10 * data[len] + (*s - '0');
  93. }
  94. }
  95. }
  96. /*
  97. * Scan for at most one decimal point and at most one indicator.
  98. * Remove unneeded zeros before and after the decimal point.
  99. * The first relevant digit will be the start of the coefficient.
  100. * A decimal point may occur before an indicator.
  101. * Plus or minus may occur directly after the indicator.
  102. * The rest of the characters must be decimal digits.
  103. *
  104. * Return start of the coefficient or NULL or error. The end of
  105. * the string is stored in 'end'.
  106. */
  107. static const char *
  108. scan_dpoint_exp(const char *s, const char **dpoint, const char **exp,
  109. const char **end)
  110. {
  111. const char *coeff = NULL;
  112. *dpoint = NULL;
  113. *exp = NULL;
  114. for (; *s != '\0'; s++) {
  115. switch (*s) {
  116. case '.':
  117. if (*dpoint != NULL || *exp != NULL)
  118. return NULL;
  119. *dpoint = s;
  120. break;
  121. case 'E': case 'e':
  122. if (*exp != NULL)
  123. return NULL;
  124. *exp = s;
  125. if (*(s+1) == '+' || *(s+1) == '-')
  126. s++;
  127. break;
  128. default:
  129. if (!isdigit((uchar)*s))
  130. return NULL;
  131. if (coeff == NULL && *exp == NULL) {
  132. if (*s == '0') {
  133. if (!isdigit((uchar)*(s+1)))
  134. if (!(*(s+1) == '.' &&
  135. isdigit((uchar)*(s+2))))
  136. coeff = s;
  137. }
  138. else {
  139. coeff = s;
  140. }
  141. }
  142. break;
  143. }
  144. }
  145. *end = s;
  146. return coeff;
  147. }
  148. /* scan the payload of a NaN */
  149. static const char *
  150. scan_payload(const char *s, const char **end)
  151. {
  152. const char *coeff;
  153. while (*s == '0')
  154. s++;
  155. coeff = s;
  156. while (isdigit((uchar)*s))
  157. s++;
  158. *end = s;
  159. return (*s == '\0') ? coeff : NULL;
  160. }
  161. /* convert a character string to a decimal */
  162. void
  163. mpd_qset_string(mpd_t *dec, const char *s, const mpd_context_t *ctx,
  164. uint32_t *status)
  165. {
  166. mpd_ssize_t q, r, len;
  167. const char *coeff, *end;
  168. const char *dpoint = NULL, *exp = NULL;
  169. size_t digits;
  170. uint8_t sign = MPD_POS;
  171. mpd_set_flags(dec, 0);
  172. dec->len = 0;
  173. dec->exp = 0;
  174. /* [flags] */
  175. if (*s == '+') {
  176. s++;
  177. }
  178. else if (*s == '-') {
  179. mpd_set_negative(dec);
  180. sign = MPD_NEG;
  181. s++;
  182. }
  183. if (_mpd_strneq(s, "nan", "NAN", 3)) { /* NaN */
  184. s += 3;
  185. mpd_setspecial(dec, sign, MPD_NAN);
  186. if (*s == '\0')
  187. return;
  188. /* only digits for the diagnostic code */
  189. if ((coeff = scan_payload(s, &end)) == NULL)
  190. goto conversion_error;
  191. /* payload consists entirely of zeros */
  192. if (*coeff == '\0')
  193. return;
  194. digits = end - coeff;
  195. /* prec >= 1, clamp is 0 or 1 */
  196. if (digits > (size_t)(ctx->prec-ctx->clamp))
  197. goto conversion_error;
  198. } /* sNaN */
  199. else if (_mpd_strneq(s, "snan", "SNAN", 4)) {
  200. s += 4;
  201. mpd_setspecial(dec, sign, MPD_SNAN);
  202. if (*s == '\0')
  203. return;
  204. /* only digits for the diagnostic code */
  205. if ((coeff = scan_payload(s, &end)) == NULL)
  206. goto conversion_error;
  207. /* payload consists entirely of zeros */
  208. if (*coeff == '\0')
  209. return;
  210. digits = end - coeff;
  211. if (digits > (size_t)(ctx->prec-ctx->clamp))
  212. goto conversion_error;
  213. }
  214. else if (_mpd_strneq(s, "inf", "INF", 3)) {
  215. s += 3;
  216. if (*s == '\0' || _mpd_strneq(s, "inity", "INITY", 6)) {
  217. /* numeric-value: infinity */
  218. mpd_setspecial(dec, sign, MPD_INF);
  219. return;
  220. }
  221. goto conversion_error;
  222. }
  223. else {
  224. /* scan for start of coefficient, decimal point, indicator, end */
  225. if ((coeff = scan_dpoint_exp(s, &dpoint, &exp, &end)) == NULL)
  226. goto conversion_error;
  227. /* numeric-value: [exponent-part] */
  228. if (exp) {
  229. /* exponent-part */
  230. end = exp; exp++;
  231. dec->exp = strtoexp(exp);
  232. if (errno) {
  233. if (!(errno == ERANGE &&
  234. (dec->exp == MPD_SSIZE_MAX ||
  235. dec->exp == MPD_SSIZE_MIN)))
  236. goto conversion_error;
  237. }
  238. }
  239. digits = end - coeff;
  240. if (dpoint) {
  241. size_t fracdigits = end-dpoint-1;
  242. if (dpoint > coeff) digits--;
  243. if (fracdigits > MPD_MAX_PREC) {
  244. goto conversion_error;
  245. }
  246. if (dec->exp < (MPD_SSIZE_MIN+1)+(mpd_ssize_t)fracdigits) {
  247. dec->exp = MPD_SSIZE_MIN+1;
  248. }
  249. else {
  250. dec->exp -= (mpd_ssize_t)fracdigits;
  251. }
  252. }
  253. if (digits > MPD_MAX_PREC) {
  254. goto conversion_error;
  255. }
  256. if (dec->exp > MPD_EXP_INF) {
  257. dec->exp = MPD_EXP_INF;
  258. }
  259. }
  260. _mpd_idiv_word(&q, &r, (mpd_ssize_t)digits, MPD_RDIGITS);
  261. len = (r == 0) ? q : q+1;
  262. if (len == 0) {
  263. goto conversion_error; /* GCOV_NOT_REACHED */
  264. }
  265. if (!mpd_qresize(dec, len, status)) {
  266. mpd_seterror(dec, MPD_Malloc_error, status);
  267. return;
  268. }
  269. dec->len = len;
  270. string_to_coeff(dec->data, coeff, dpoint, (int)r, len);
  271. mpd_setdigits(dec);
  272. mpd_qfinalize(dec, ctx, status);
  273. return;
  274. conversion_error:
  275. /* standard wants a positive NaN */
  276. mpd_seterror(dec, MPD_Conversion_syntax, status);
  277. }
  278. /* print the exponent to a string */
  279. static inline char *
  280. exp_to_string(char *s, mpd_ssize_t x)
  281. {
  282. mpd_ssize_t q, d;
  283. char sign = '+';
  284. int j;
  285. if (x < 0) {
  286. sign = '-';
  287. x = -x;
  288. }
  289. *s++ = sign;
  290. j = mpd_exp_digits(x) - 1;
  291. for (; j != 0; --j) {
  292. d = mpd_pow10[j];
  293. q = x / d;
  294. x -= d * q;
  295. *s++ = '0' + (char)q;
  296. }
  297. *s++ = '0' + (char)x;
  298. return s;
  299. }
  300. /* print coefficient to string, len(dec) > 0 */
  301. static inline char *
  302. coeff_to_string(char *s, const mpd_t *dec)
  303. {
  304. mpd_uint_t x, q, d;
  305. mpd_ssize_t i;
  306. int j;
  307. /* most significant word */
  308. x = mpd_msword(dec);
  309. j = mpd_word_digits(x) - 1;
  310. for (; j != 0; --j) {
  311. d = mpd_pow10[j];
  312. q = x / d;
  313. x -= d * q;
  314. *s++ = '0' + (char)q;
  315. }
  316. *s++ = '0' + (char)x;
  317. /* remaining full words */
  318. for (i=dec->len-2; i >= 0; --i) {
  319. x = dec->data[i];
  320. for (j=MPD_RDIGITS-1; j != 0; --j) {
  321. d = mpd_pow10[j];
  322. q = x / d;
  323. x -= d * q;
  324. *s++ = '0' + (char)q;
  325. }
  326. *s++ = '0' + (char)x;
  327. }
  328. return s;
  329. }
  330. /* print coefficient to string, len(dec) > 0 */
  331. static inline char *
  332. coeff_to_string_dot(char *s, char *dot, const mpd_t *dec)
  333. {
  334. mpd_uint_t x, q, d;
  335. mpd_ssize_t i;
  336. int j;
  337. /* most significant word */
  338. x = mpd_msword(dec);
  339. j = mpd_word_digits(x) - 1;
  340. for (; j >= 0; --j) {
  341. if (s == dot)
  342. *s++ = '.';
  343. d = mpd_pow10[j];
  344. q = x / d;
  345. x -= d * q;
  346. *s++ = '0' + (char)q;
  347. }
  348. /* remaining full words */
  349. for (i=dec->len-2; i >= 0; --i) {
  350. x = dec->data[i];
  351. for (j=MPD_RDIGITS-1; j >= 0; --j) {
  352. if (s == dot)
  353. *s++ = '.';
  354. d = mpd_pow10[j];
  355. q = x / d;
  356. x -= d * q;
  357. *s++ = '0' + (char)q;
  358. }
  359. }
  360. return s;
  361. }
  362. /* Format type */
  363. #define MPD_FMT_LOWER 0x00000000
  364. #define MPD_FMT_UPPER 0x00000001
  365. #define MPD_FMT_TOSCI 0x00000002
  366. #define MPD_FMT_TOENG 0x00000004
  367. #define MPD_FMT_EXP 0x00000008
  368. #define MPD_FMT_FIXED 0x00000010
  369. #define MPD_FMT_PERCENT 0x00000020
  370. #define MPD_FMT_SIGN_SPACE 0x00000040
  371. #define MPD_FMT_SIGN_PLUS 0x00000080
  372. /*
  373. * Return the string representation of a decimal. Formatting is done according
  374. * to 'flags'. A return value of NULL indicates MPD_Malloc_error.
  375. *
  376. * To allow formatting like [0e15, '.6e' -> 0.000000e-9], 'zeroexp' is used
  377. * in combination with MPD_FMT_FIXED (see mpd_qformat for details).
  378. */
  379. static char *
  380. _mpd_to_string(const mpd_t *dec, int flags, mpd_ssize_t zeroexp)
  381. {
  382. char *decstring = NULL, *cp = NULL;
  383. mpd_ssize_t ldigits, dplace;
  384. mpd_ssize_t mem = 0, k;
  385. if (mpd_isspecial(dec)) {
  386. mem = sizeof "-Infinity";
  387. if (mpd_isnan(dec) && dec->len > 0) {
  388. /* diagnostic code */
  389. mem += dec->digits;
  390. }
  391. cp = decstring = mpd_alloc(mem, sizeof *decstring);
  392. if (cp == NULL) {
  393. return NULL;
  394. }
  395. if (mpd_isnegative(dec)) {
  396. *cp++ = '-';
  397. }
  398. else if (flags&MPD_FMT_SIGN_SPACE) {
  399. *cp++ = ' ';
  400. }
  401. else if (flags&MPD_FMT_SIGN_PLUS) {
  402. *cp++ = '+';
  403. }
  404. if (mpd_isnan(dec)) {
  405. if (mpd_isqnan(dec)) {
  406. strcpy(cp, "NaN");
  407. cp += 3;
  408. }
  409. else {
  410. strcpy(cp, "sNaN");
  411. cp += 4;
  412. }
  413. if (dec->len > 0) { /* diagnostic code */
  414. cp = coeff_to_string(cp, dec);
  415. }
  416. }
  417. else if (mpd_isinfinite(dec)) {
  418. strcpy(cp, "Infinity");
  419. cp += 8;
  420. }
  421. else { /* debug */
  422. abort(); /* GCOV_NOT_REACHED */
  423. }
  424. }
  425. else {
  426. assert(dec->len > 0);
  427. /*
  428. * ldigits: Digits to the left of the decimal point, as if the
  429. * number was written without exponent notation.
  430. *
  431. * dplace: Position of the decimal point relative to the first
  432. * member of the coefficient.
  433. *
  434. * 0.00000_.____._____000000.
  435. * ^ ^ ^ ^
  436. * | | | |
  437. * | | | `- dplace in the last position
  438. * | | `- dplace in the middle of the coefficient
  439. * | ` dplace = 1 (after the first coefficient digit)
  440. * `- dplace is negative
  441. */
  442. ldigits = dec->digits + dec->exp;
  443. dplace = 1; /* default for MPD_FMT_TOSCI, MPD_FMT_EXP */
  444. if (flags&MPD_FMT_EXP) {
  445. ;
  446. }
  447. else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) {
  448. /* MPD_FMT_FIXED: always use fixed point notation.
  449. * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range,
  450. * override exponent notation. */
  451. dplace = ldigits;
  452. }
  453. else if (flags&MPD_FMT_TOENG) {
  454. if (mpd_iszero(dec)) {
  455. /* If the exponent is divisible by three,
  456. * dplace = 1. Otherwise, move dplace one
  457. * or two places to the left. */
  458. dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3);
  459. }
  460. else { /* ldigits-1 is the adjusted exponent, which
  461. * should be divisible by three. If not, move
  462. * dplace one or two places to the right. */
  463. dplace += mod_mpd_ssize_t(ldigits-1, 3);
  464. }
  465. }
  466. /*
  467. * Basic space requirements:
  468. *
  469. * [-][.][coeffdigits][E][-][expdigits+1][%]['\0']
  470. *
  471. * If the decimal point lies outside of the coefficient digits,
  472. * space is adjusted accordingly.
  473. */
  474. if (dplace <= 0) {
  475. mem = -dplace + dec->digits + 2;
  476. }
  477. else if (dplace >= dec->digits) {
  478. mem = dplace;
  479. }
  480. else {
  481. mem = dec->digits;
  482. }
  483. mem += (MPD_EXPDIGITS+1+6);
  484. cp = decstring = mpd_alloc(mem, sizeof *decstring);
  485. if (cp == NULL) {
  486. return NULL;
  487. }
  488. if (mpd_isnegative(dec)) {
  489. *cp++ = '-';
  490. }
  491. else if (flags&MPD_FMT_SIGN_SPACE) {
  492. *cp++ = ' ';
  493. }
  494. else if (flags&MPD_FMT_SIGN_PLUS) {
  495. *cp++ = '+';
  496. }
  497. if (dplace <= 0) {
  498. /* space: -dplace+dec->digits+2 */
  499. *cp++ = '0';
  500. *cp++ = '.';
  501. for (k = 0; k < -dplace; k++) {
  502. *cp++ = '0';
  503. }
  504. cp = coeff_to_string(cp, dec);
  505. }
  506. else if (dplace >= dec->digits) {
  507. /* space: dplace */
  508. cp = coeff_to_string(cp, dec);
  509. for (k = 0; k < dplace-dec->digits; k++) {
  510. *cp++ = '0';
  511. }
  512. }
  513. else {
  514. /* space: dec->digits+1 */
  515. cp = coeff_to_string_dot(cp, cp+dplace, dec);
  516. }
  517. /*
  518. * Conditions for printing an exponent:
  519. *
  520. * MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace
  521. * MPD_FMT_FIXED: never (ldigits == dplace)
  522. * MPD_FMT_EXP: always
  523. * MPD_FMT_FIXED with zeroexp: always
  524. */
  525. if (ldigits != dplace || flags&MPD_FMT_EXP || zeroexp != MPD_SSIZE_MAX) {
  526. /* space: expdigits+2 */
  527. mpd_ssize_t x = (zeroexp != MPD_SSIZE_MAX) ? zeroexp : ldigits-dplace;
  528. *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e';
  529. cp = exp_to_string(cp, x);
  530. }
  531. if (flags&MPD_FMT_PERCENT) {
  532. *cp++ = '%';
  533. }
  534. }
  535. assert(cp < decstring+mem);
  536. *cp = '\0';
  537. return decstring;
  538. }
  539. char *
  540. mpd_to_sci(const mpd_t *dec, int fmt)
  541. {
  542. int flags = MPD_FMT_TOSCI;
  543. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  544. return _mpd_to_string(dec, flags, MPD_SSIZE_MAX);
  545. }
  546. char *
  547. mpd_to_eng(const mpd_t *dec, int fmt)
  548. {
  549. int flags = MPD_FMT_TOENG;
  550. flags |= fmt ? MPD_FMT_UPPER : MPD_FMT_LOWER;
  551. return _mpd_to_string(dec, flags, MPD_SSIZE_MAX);
  552. }
  553. /* Copy a single UTF-8 char to dest. */
  554. static int
  555. _mpd_copy_utf8(char dest[5], const char *s)
  556. {
  557. const uchar *cp = (const uchar *)s;
  558. uchar lb, ub;
  559. int count, i;
  560. if (*cp == 0) {
  561. /* empty string */
  562. dest[0] = '\0';
  563. return 0;
  564. }
  565. else if (*cp <= 0x7f) {
  566. /* ascii */
  567. dest[0] = *cp;
  568. dest[1] = '\0';
  569. return 1;
  570. }
  571. else if (0xc2 <= *cp && *cp <= 0xdf) {
  572. lb = 0x80; ub = 0xbf;
  573. count = 2;
  574. }
  575. else if (*cp == 0xe0) {
  576. lb = 0xa0; ub = 0xbf;
  577. count = 3;
  578. }
  579. else if (*cp <= 0xec) {
  580. lb = 0x80; ub = 0xbf;
  581. count = 3;
  582. }
  583. else if (*cp == 0xed) {
  584. lb = 0x80; ub = 0x9f;
  585. count = 3;
  586. }
  587. else if (*cp <= 0xef) {
  588. lb = 0x80; ub = 0xbf;
  589. count = 3;
  590. }
  591. else if (*cp == 0xf0) {
  592. lb = 0x90; ub = 0xbf;
  593. count = 4;
  594. }
  595. else if (*cp <= 0xf3) {
  596. lb = 0x80; ub = 0xbf;
  597. count = 4;
  598. }
  599. else if (*cp == 0xf4) {
  600. lb = 0x80; ub = 0x8f;
  601. count = 4;
  602. }
  603. else {
  604. /* invalid */
  605. goto error;
  606. }
  607. dest[0] = *cp++;
  608. if (*cp < lb || ub < *cp) {
  609. goto error;
  610. }
  611. dest[1] = *cp++;
  612. for (i = 2; i < count; i++) {
  613. if (*cp < 0x80 || 0xbf < *cp) {
  614. goto error;
  615. }
  616. dest[i] = *cp++;
  617. }
  618. dest[i] = '\0';
  619. return count;
  620. error:
  621. dest[0] = '\0';
  622. return -1;
  623. }
  624. int
  625. mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps)
  626. {
  627. char *cp = (char *)fmt;
  628. int have_align = 0, n;
  629. /* defaults */
  630. spec->min_width = 0;
  631. spec->prec = -1;
  632. spec->type = caps ? 'G' : 'g';
  633. spec->align = '>';
  634. spec->sign = '-';
  635. spec->dot = "";
  636. spec->sep = "";
  637. spec->grouping = "";
  638. /* presume that the first character is a UTF-8 fill character */
  639. if ((n = _mpd_copy_utf8(spec->fill, cp)) < 0) {
  640. return 0;
  641. }
  642. /* alignment directive, prefixed by a fill character */
  643. if (*cp && (*(cp+n) == '<' || *(cp+n) == '>' ||
  644. *(cp+n) == '=' || *(cp+n) == '^')) {
  645. cp += n;
  646. spec->align = *cp++;
  647. have_align = 1;
  648. } /* alignment directive */
  649. else {
  650. /* default fill character */
  651. spec->fill[0] = ' ';
  652. spec->fill[1] = '\0';
  653. if (*cp == '<' || *cp == '>' ||
  654. *cp == '=' || *cp == '^') {
  655. spec->align = *cp++;
  656. have_align = 1;
  657. }
  658. }
  659. /* sign formatting */
  660. if (*cp == '+' || *cp == '-' || *cp == ' ') {
  661. spec->sign = *cp++;
  662. }
  663. /* zero padding */
  664. if (*cp == '0') {
  665. /* zero padding implies alignment, which should not be
  666. * specified twice. */
  667. if (have_align) {
  668. return 0;
  669. }
  670. spec->align = 'z';
  671. spec->fill[0] = *cp++;
  672. spec->fill[1] = '\0';
  673. }
  674. /* minimum width */
  675. if (isdigit((uchar)*cp)) {
  676. if (*cp == '0') {
  677. return 0;
  678. }
  679. errno = 0;
  680. spec->min_width = mpd_strtossize(cp, &cp, 10);
  681. if (errno == ERANGE || errno == EINVAL) {
  682. return 0;
  683. }
  684. }
  685. /* thousands separator */
  686. if (*cp == ',') {
  687. spec->dot = ".";
  688. spec->sep = ",";
  689. spec->grouping = "\003\003";
  690. cp++;
  691. }
  692. /* fraction digits or significant digits */
  693. if (*cp == '.') {
  694. cp++;
  695. if (!isdigit((uchar)*cp)) {
  696. return 0;
  697. }
  698. errno = 0;
  699. spec->prec = mpd_strtossize(cp, &cp, 10);
  700. if (errno == ERANGE || errno == EINVAL) {
  701. return 0;
  702. }
  703. }
  704. /* type */
  705. if (*cp == 'E' || *cp == 'e' || *cp == 'F' || *cp == 'f' ||
  706. *cp == 'G' || *cp == 'g' || *cp == '%') {
  707. spec->type = *cp++;
  708. }
  709. else if (*cp == 'N' || *cp == 'n') {
  710. /* locale specific conversion */
  711. struct lconv *lc;
  712. spec->type = *cp++;
  713. /* separator has already been specified */
  714. if (*spec->sep) return 0;
  715. spec->type = (spec->type == 'N') ? 'G' : 'g';
  716. lc = localeconv();
  717. spec->dot = lc->decimal_point;
  718. spec->sep = lc->thousands_sep;
  719. spec->grouping = lc->grouping;
  720. }
  721. /* check correctness */
  722. if (*cp != '\0') {
  723. return 0;
  724. }
  725. return 1;
  726. }
  727. /*
  728. * The following functions assume that spec->min_width <= MPD_MAX_PREC, which
  729. * is made sure in mpd_qformat_spec. Then, even with a spec that inserts a
  730. * four-byte separator after each digit, nbytes in the following struct
  731. * cannot overflow.
  732. */
  733. /* Multibyte string */
  734. typedef struct {
  735. mpd_ssize_t nbytes; /* length in bytes */
  736. mpd_ssize_t nchars; /* length in chars */
  737. mpd_ssize_t cur; /* current write index */
  738. char *data;
  739. } mpd_mbstr_t;
  740. static inline void
  741. _mpd_bcopy(char *dest, const char *src, mpd_ssize_t n)
  742. {
  743. while (--n >= 0) {
  744. dest[n] = src[n];
  745. }
  746. }
  747. static inline void
  748. _mbstr_copy_char(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
  749. {
  750. dest->nbytes += n;
  751. dest->nchars += 1;
  752. dest->cur -= n;
  753. if (dest->data != NULL) {
  754. _mpd_bcopy(dest->data+dest->cur, src, n);
  755. }
  756. }
  757. static inline void
  758. _mbstr_copy_ascii(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n)
  759. {
  760. dest->nbytes += n;
  761. dest->nchars += n;
  762. dest->cur -= n;
  763. if (dest->data != NULL) {
  764. _mpd_bcopy(dest->data+dest->cur, src, n);
  765. }
  766. }
  767. static inline void
  768. _mbstr_copy_pad(mpd_mbstr_t *dest, mpd_ssize_t n)
  769. {
  770. dest->nbytes += n;
  771. dest->nchars += n;
  772. dest->cur -= n;
  773. if (dest->data != NULL) {
  774. char*cp = dest->data + dest->cur;
  775. while (--n >= 0) {
  776. cp[n] = '0';
  777. }
  778. }
  779. }
  780. /*
  781. * Copy the decimal to dest, adding separators according to
  782. * spec->grouping. If leading zero padding is enabled and the
  783. * result is smaller than spec->min_width, continue adding zeros
  784. * and separators until min_width is reached.
  785. */
  786. static void
  787. _mpd_add_sep_dot(mpd_mbstr_t *dest,
  788. const char *src, mpd_ssize_t n_src, /* integer part and length */
  789. const char *sign, const char *dot, const char *rest,
  790. mpd_spec_t *spec)
  791. {
  792. mpd_ssize_t n_sep, n_sign, consume;
  793. const char *g;
  794. int pad = 0;
  795. n_sign = sign ? 1 : 0;
  796. n_sep = (mpd_ssize_t)strlen(spec->sep);
  797. g = spec->grouping;
  798. dest->cur = dest->nbytes;
  799. dest->nbytes = dest->nchars = 0;
  800. /* rest <= MPD_MAX_PREC */
  801. _mbstr_copy_ascii(dest, rest, (mpd_ssize_t)strlen(rest));
  802. if (dot) {
  803. _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot));
  804. }
  805. consume = *g;
  806. while (1) {
  807. if (*g == 0 || *g == CHAR_MAX || consume > n_src) {
  808. consume = n_src;
  809. }
  810. n_src -= consume;
  811. if (pad) {
  812. _mbstr_copy_pad(dest, consume);
  813. }
  814. else {
  815. _mbstr_copy_ascii(dest, src+n_src, consume);
  816. }
  817. if (n_src == 0) {
  818. if (spec->align == 'z' &&
  819. dest->nchars + n_sign < spec->min_width) {
  820. n_src = spec->min_width - (dest->nchars + n_sign);
  821. consume = *g - consume;
  822. pad = 1;
  823. continue;
  824. }
  825. break;
  826. }
  827. if (n_sep > 0) {
  828. if (pad && n_src > 1) n_src -= 1;
  829. _mbstr_copy_char(dest, spec->sep, n_sep);
  830. }
  831. if (*g && *(g+1)) g++;
  832. consume = *g;
  833. }
  834. if (sign) {
  835. _mbstr_copy_ascii(dest, sign, 1);
  836. }
  837. if (dest->data) {
  838. dest->data[dest->nbytes] = '\0';
  839. }
  840. }
  841. /* Change decstring to locale-specific appearance. */
  842. static void
  843. _mpd_apply_lconv(mpd_mbstr_t *result, char *decstring, mpd_spec_t *spec,
  844. uint32_t *status)
  845. {
  846. const char *sign = NULL, *intpart = NULL;
  847. const char *dot = NULL, *rest = NULL;
  848. const char *dp;
  849. mpd_ssize_t n_int;
  850. assert(result->data == NULL);
  851. dp = decstring;
  852. n_int = 0;
  853. if (!isdigit((uchar)*dp)) {
  854. sign = dp++;
  855. }
  856. if (isdigit((uchar)*dp)) {
  857. intpart = dp++;
  858. while (isdigit((uchar)*dp)) {
  859. dp++;
  860. }
  861. n_int = (mpd_ssize_t)(dp-intpart);
  862. }
  863. if (*dp == '.') {
  864. if (*spec->dot == '\0') {
  865. /* decimal point must be present */
  866. *status |= MPD_Invalid_operation; /* GCOV_NOT_REACHED */
  867. mpd_free(decstring); /* GCOV_NOT_REACHED */
  868. return; /* GCOV_NOT_REACHED */
  869. }
  870. dp++; dot = spec->dot;
  871. }
  872. rest = dp;
  873. if (!dot && !(intpart && *spec->sep && *spec->grouping)) {
  874. result->data = decstring;
  875. result->nbytes = result->nchars = (mpd_ssize_t)strlen(decstring);
  876. return;
  877. }
  878. /* Get the size of the new decimal string after inserting dot and
  879. * separators. */
  880. _mpd_add_sep_dot(result, intpart, n_int, sign, dot, rest, spec);
  881. if ((result->data = mpd_alloc(result->nbytes+1, 1)) == NULL) {
  882. *status |= MPD_Malloc_error;
  883. mpd_free(decstring);
  884. return;
  885. }
  886. /* Perform actual writes. */
  887. _mpd_add_sep_dot(result, intpart, n_int, sign, dot, rest, spec);
  888. mpd_free(decstring);
  889. }
  890. /* Add padding to the formatted string if necessary. */
  891. static void
  892. _mpd_add_pad(mpd_mbstr_t *result, mpd_spec_t *spec, uint32_t *status)
  893. {
  894. if (result->nchars < spec->min_width) {
  895. mpd_ssize_t add_chars, add_bytes;
  896. size_t lpad = 0, rpad = 0;
  897. size_t n_fill, len, i, j;
  898. uint8_t err = 0;
  899. char *cp;
  900. n_fill = strlen(spec->fill);
  901. add_chars = (spec->min_width - result->nchars);
  902. /* max value: MPD_MAX_PREC * 4 */
  903. add_bytes = add_chars * (mpd_ssize_t)n_fill;
  904. cp = result->data = mpd_realloc(result->data,
  905. result->nbytes+add_bytes+1,
  906. sizeof *result->data, &err);
  907. if (err) {
  908. *status |= MPD_Malloc_error;
  909. mpd_free(result->data);
  910. result->data = NULL;
  911. return;
  912. }
  913. if (spec->align == 'z') {
  914. spec->align = '=';
  915. }
  916. if (spec->align == '<') {
  917. rpad = add_chars;
  918. }
  919. else if (spec->align == '>' || spec->align == '=') {
  920. lpad = add_chars;
  921. }
  922. else { /* align == '^' */
  923. lpad = add_chars/2;
  924. rpad = add_chars-lpad;
  925. }
  926. len = result->nbytes;
  927. if (spec->align == '=' && (*cp == '-' || *cp == '+' ||
  928. *cp == ' ')) {
  929. /* leave sign in the leading position */
  930. cp++; len--;
  931. }
  932. memmove(cp+n_fill*lpad, cp, len);
  933. for (i = 0; i < lpad; i++) {
  934. for (j = 0; j < n_fill; j++) {
  935. cp[i*n_fill+j] = spec->fill[j];
  936. }
  937. }
  938. cp += (n_fill*lpad + len);
  939. for (i = 0; i < rpad; i++) {
  940. for (j = 0; j < n_fill; j++) {
  941. cp[i*n_fill+j] = spec->fill[j];
  942. }
  943. }
  944. result->nbytes += add_bytes;
  945. result->nchars += add_chars;
  946. result->data[result->nbytes] = '\0';
  947. }
  948. }
  949. /*
  950. * Return the string representation of an mpd_t, formatted according to 'spec'.
  951. * 'spec' is modified. The format specification is assumed to be valid. Memory
  952. * errors are indicated as usual. This function is quiet.
  953. */
  954. char *
  955. mpd_qformat_spec(const mpd_t *dec, mpd_spec_t *spec, const mpd_context_t *ctx,
  956. uint32_t *status)
  957. {
  958. mpd_context_t workctx;
  959. mpd_uint_t dt[MPD_MINALLOC_MAX];
  960. mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
  961. mpd_ssize_t prec, fracdigits, exp;
  962. mpd_ssize_t zeroexp = MPD_SSIZE_MAX;
  963. mpd_mbstr_t result;
  964. char *decstring;
  965. int flags = 0;
  966. if (spec->min_width > MPD_MAX_PREC) {
  967. *status |= MPD_Invalid_operation;
  968. return NULL;
  969. }
  970. if (!mpd_qcopy(&tmp, dec, status)) {
  971. return NULL;
  972. }
  973. if (spec->type == '%') {
  974. tmp.exp += 2;
  975. spec->type = 'f';
  976. flags |= MPD_FMT_PERCENT;
  977. }
  978. if (isupper((uchar)spec->type)) {
  979. spec->type = tolower((uchar)spec->type);
  980. flags |= MPD_FMT_UPPER;
  981. }
  982. if (spec->sign == ' ') {
  983. flags |= MPD_FMT_SIGN_SPACE;
  984. }
  985. else if (spec->sign == '+') {
  986. flags |= MPD_FMT_SIGN_PLUS;
  987. }
  988. mpd_maxcontext_plus(&workctx, ctx);
  989. workctx.round = ctx->round;
  990. if (mpd_isspecial(&tmp)) {
  991. /* no percent formatting */
  992. flags |= MPD_FMT_TOSCI;
  993. if (spec->align == 'z') {
  994. spec->fill[0] = ' ';
  995. spec->fill[1] = '\0';
  996. spec->align = '>';
  997. }
  998. }
  999. else if (spec->type == 'g') {
  1000. /* spec->prec: significant digits */
  1001. prec = (spec->prec < 0) ? dec->digits : spec->prec;
  1002. workctx.prec = (prec == 0) ? 1 : prec;
  1003. flags |= MPD_FMT_TOSCI;
  1004. mpd_qfinalize(&tmp, &workctx, &workctx.status);
  1005. }
  1006. else {
  1007. /* spec->prec: fraction digits */
  1008. if (spec->type == 'e') {
  1009. fracdigits = (spec->prec < 0) ? tmp.digits-1 : spec->prec;
  1010. if (mpd_iszero(&tmp)) {
  1011. zeroexp = tmp.exp+fracdigits;
  1012. exp = -fracdigits;
  1013. flags |= MPD_FMT_FIXED;
  1014. }
  1015. else {
  1016. exp = tmp.exp + tmp.digits-(fracdigits+1);
  1017. flags |= MPD_FMT_EXP;
  1018. }
  1019. }
  1020. else { /* 'f' */
  1021. fracdigits = spec->prec;
  1022. if (fracdigits < 0) {
  1023. fracdigits = (tmp.exp < 0) ? -tmp.exp : 0;
  1024. }
  1025. exp = -fracdigits;
  1026. fracdigits += (tmp.exp+tmp.digits);
  1027. fracdigits = (fracdigits < 0) ? 0 : fracdigits;
  1028. flags |= MPD_FMT_FIXED;
  1029. }
  1030. workctx.prec = fracdigits+1;
  1031. mpd_qrescale(&tmp, &tmp, exp, &workctx, &workctx.status);
  1032. if (tmp.digits > workctx.prec) {
  1033. mpd_qfinalize(&tmp, &workctx, &workctx.status);
  1034. }
  1035. }
  1036. if ((decstring = _mpd_to_string(&tmp, flags, zeroexp)) == NULL) {
  1037. *status |= MPD_Malloc_error;
  1038. mpd_del(&tmp);
  1039. return NULL;
  1040. }
  1041. result.data = decstring;
  1042. result.nbytes = result.nchars = 0;
  1043. if (!mpd_isspecial(&tmp) && *spec->dot != '\0') {
  1044. result.data = NULL;
  1045. _mpd_apply_lconv(&result, decstring, spec, status);
  1046. if (result.data == NULL) {
  1047. goto finish;
  1048. }
  1049. }
  1050. if (spec->min_width) {
  1051. if (result.nbytes == 0) {
  1052. result.nbytes = result.nchars =
  1053. (mpd_ssize_t)strlen(result.data);
  1054. }
  1055. _mpd_add_pad(&result, spec, status);
  1056. }
  1057. finish:
  1058. mpd_del(&tmp);
  1059. return result.data;
  1060. }
  1061. char *
  1062. mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx,
  1063. uint32_t *status)
  1064. {
  1065. mpd_spec_t spec;
  1066. if (!mpd_parse_fmt_str(&spec, fmt, 1)) {
  1067. *status |= MPD_Invalid_operation;
  1068. return NULL;
  1069. }
  1070. return mpd_qformat_spec(dec, &spec, ctx, status);
  1071. }
  1072. /*
  1073. * The specification has a *condition* called Invalid_operation and an
  1074. * IEEE *signal* called Invalid_operation. The former corresponds to
  1075. * MPD_Invalid_operation, the latter to MPD_IEEE_Invalid_operation.
  1076. * MPD_IEEE_Invalid_operation comprises the following conditions:
  1077. *
  1078. * [MPD_Conversion_syntax, MPD_Division_impossible, MPD_Division_undefined,
  1079. * MPD_Fpu_error, MPD_Invalid_context, MPD_Invalid_operation,
  1080. * MPD_Malloc_error]
  1081. *
  1082. * In the following functions, 'flag' denotes the condition, 'signal'
  1083. * denotes the IEEE signal.
  1084. */
  1085. static const char *mpd_flag_string[MPD_NUM_FLAGS] = {
  1086. "Clamped",
  1087. "Conversion_syntax",
  1088. "Division_by_zero",
  1089. "Division_impossible",
  1090. "Division_undefined",
  1091. "Fpu_error",
  1092. "Inexact",
  1093. "Invalid_context",
  1094. "Invalid_operation",
  1095. "Malloc_error",
  1096. "Not_implemented",
  1097. "Overflow",
  1098. "Rounded",
  1099. "Subnormal",
  1100. "Underflow",
  1101. };
  1102. static const char *mpd_signal_string[MPD_NUM_FLAGS] = {
  1103. "Clamped",
  1104. "IEEE_Invalid_operation",
  1105. "Division_by_zero",
  1106. "IEEE_Invalid_operation",
  1107. "IEEE_Invalid_operation",
  1108. "IEEE_Invalid_operation",
  1109. "Inexact",
  1110. "IEEE_Invalid_operation",
  1111. "IEEE_Invalid_operation",
  1112. "IEEE_Invalid_operation",
  1113. "Not_implemented",
  1114. "Overflow",
  1115. "Rounded",
  1116. "Subnormal",
  1117. "Underflow",
  1118. };
  1119. /* print conditions to buffer, separated by spaces */
  1120. int
  1121. mpd_snprint_flags(char *dest, int nmemb, uint32_t flags)
  1122. {
  1123. char *cp;
  1124. int n, j;
  1125. assert(nmemb >= MPD_MAX_FLAG_STRING);
  1126. *dest = '\0'; cp = dest;
  1127. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1128. if (flags & (1U<<j)) {
  1129. n = snprintf(cp, nmemb, "%s ", mpd_flag_string[j]);
  1130. if (n < 0 || n >= nmemb) return -1;
  1131. cp += n; nmemb -= n;
  1132. }
  1133. }
  1134. if (cp != dest) {
  1135. *(--cp) = '\0';
  1136. }
  1137. return (int)(cp-dest);
  1138. }
  1139. /* print conditions to buffer, in list form */
  1140. int
  1141. mpd_lsnprint_flags(char *dest, int nmemb, uint32_t flags, const char *flag_string[])
  1142. {
  1143. char *cp;
  1144. int n, j;
  1145. assert(nmemb >= MPD_MAX_FLAG_LIST);
  1146. if (flag_string == NULL) {
  1147. flag_string = mpd_flag_string;
  1148. }
  1149. *dest = '[';
  1150. *(dest+1) = '\0';
  1151. cp = dest+1;
  1152. --nmemb;
  1153. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1154. if (flags & (1U<<j)) {
  1155. n = snprintf(cp, nmemb, "%s, ", flag_string[j]);
  1156. if (n < 0 || n >= nmemb) return -1;
  1157. cp += n; nmemb -= n;
  1158. }
  1159. }
  1160. /* erase the last ", " */
  1161. if (cp != dest+1) {
  1162. cp -= 2;
  1163. }
  1164. *cp++ = ']';
  1165. *cp = '\0';
  1166. return (int)(cp-dest); /* strlen, without NUL terminator */
  1167. }
  1168. /* print signals to buffer, in list form */
  1169. int
  1170. mpd_lsnprint_signals(char *dest, int nmemb, uint32_t flags, const char *signal_string[])
  1171. {
  1172. char *cp;
  1173. int n, j;
  1174. int ieee_invalid_done = 0;
  1175. assert(nmemb >= MPD_MAX_SIGNAL_LIST);
  1176. if (signal_string == NULL) {
  1177. signal_string = mpd_signal_string;
  1178. }
  1179. *dest = '[';
  1180. *(dest+1) = '\0';
  1181. cp = dest+1;
  1182. --nmemb;
  1183. for (j = 0; j < MPD_NUM_FLAGS; j++) {
  1184. uint32_t f = flags & (1U<<j);
  1185. if (f) {
  1186. if (f&MPD_IEEE_Invalid_operation) {
  1187. if (ieee_invalid_done) {
  1188. continue;
  1189. }
  1190. ieee_invalid_done = 1;
  1191. }
  1192. n = snprintf(cp, nmemb, "%s, ", signal_string[j]);
  1193. if (n < 0 || n >= nmemb) return -1;
  1194. cp += n; nmemb -= n;
  1195. }
  1196. }
  1197. /* erase the last ", " */
  1198. if (cp != dest+1) {
  1199. cp -= 2;
  1200. }
  1201. *cp++ = ']';
  1202. *cp = '\0';
  1203. return (int)(cp-dest); /* strlen, without NUL terminator */
  1204. }
  1205. /* The following two functions are mainly intended for debugging. */
  1206. void
  1207. mpd_fprint(FILE *file, const mpd_t *dec)
  1208. {
  1209. char *decstring;
  1210. decstring = mpd_to_sci(dec, 1);
  1211. if (decstring != NULL) {
  1212. fprintf(file, "%s\n", decstring);
  1213. mpd_free(decstring);
  1214. }
  1215. else {
  1216. fputs("mpd_fprint: output error\n", file); /* GCOV_NOT_REACHED */
  1217. }
  1218. }
  1219. void
  1220. mpd_print(const mpd_t *dec)
  1221. {
  1222. char *decstring;
  1223. decstring = mpd_to_sci(dec, 1);
  1224. if (decstring != NULL) {
  1225. printf("%s\n", decstring);
  1226. mpd_free(decstring);
  1227. }
  1228. else {
  1229. fputs("mpd_fprint: output error\n", stderr); /* GCOV_NOT_REACHED */
  1230. }
  1231. }