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