Exemplo n.º 1
0
/*
 * Converts the value of the given double to a String, and places
 * The result into the destination String.
 * @return the given dest string
 */
void txDouble::toString(double aValue, nsAString& aDest)
{

    // check for special cases

    if (MOZ_DOUBLE_IS_NaN(aValue)) {
        aDest.AppendLiteral("NaN");
        return;
    }
    if (MOZ_DOUBLE_IS_INFINITE(aValue)) {
        if (aValue < 0)
            aDest.Append(PRUnichar('-'));
        aDest.AppendLiteral("Infinity");
        return;
    }

    // Mantissa length is 17, so this is plenty
    const int buflen = 20;
    char buf[buflen];

    int intDigits, sign;
    char* endp;
    PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);

    // compute length
    int32_t length = endp - buf;
    if (length > intDigits) {
        // decimal point needed
        ++length;
        if (intDigits < 1) {
            // leading zeros, -intDigits + 1
            length += 1 - intDigits;
        }
    }
    else {
        // trailing zeros, total length given by intDigits
        length = intDigits;
    }
    if (aValue < 0)
        ++length;
    // grow the string
    uint32_t oldlength = aDest.Length();
    if (!EnsureStringLength(aDest, oldlength + length))
        return; // out of memory
    nsAString::iterator dest;
    aDest.BeginWriting(dest).advance(int32_t(oldlength));
    if (aValue < 0) {
        *dest = '-'; ++dest;
    }
    int i;
    // leading zeros
    if (intDigits < 1) {
        *dest = '0'; ++dest;
        *dest = '.'; ++dest;
        for (i = 0; i > intDigits; --i) {
            *dest = '0'; ++dest;
        }
    }
    // mantissa
    int firstlen = std::min<size_t>(intDigits, endp - buf);
    for (i = 0; i < firstlen; i++) {
        *dest = buf[i]; ++dest;
    }
    if (i < endp - buf) {
        if (i > 0) {
            *dest = '.'; ++dest;
        }
        for (; i < endp - buf; i++) {
            *dest = buf[i]; ++dest;
        }
    }
    // trailing zeros
    for (; i < intDigits; i++) {
        *dest = '0'; ++dest;
    }
}
Exemplo n.º 2
0
/*
** Convert a double precision floating point number into its printable
** form.
*/
int
nsTextFormatter::cvt_f(SprintfStateStr* aState, double aDouble, int aWidth, int aPrec,
                       const char16_t aType, int aFlags)
{
  int    mode = 2;
  int    decpt;
  int    sign;
  char   buf[256];
  char*  bufp = buf;
  int    bufsz = 256;
  char   num[256];
  char*  nump;
  char*  endnum;
  int    numdigits = 0;
  char   exp = 'e';

  if (aPrec == -1) {
    aPrec = 6;
  } else if (aPrec > 50) {
    // limit precision to avoid PR_dtoa bug 108335
    // and to prevent buffers overflows
    aPrec = 50;
  }

  switch (aType) {
    case 'f':
      numdigits = aPrec;
      mode = 3;
      break;
    case 'E':
      exp = 'E';
      MOZ_FALLTHROUGH;
    case 'e':
      numdigits = aPrec + 1;
      mode = 2;
      break;
    case 'G':
      exp = 'E';
      MOZ_FALLTHROUGH;
    case 'g':
      if (aPrec == 0) {
        aPrec = 1;
      }
      numdigits = aPrec;
      mode = 2;
      break;
    default:
      NS_ERROR("invalid aType passed to cvt_f");
  }

  if (PR_dtoa(aDouble, mode, numdigits, &decpt, &sign,
              &endnum, num, bufsz) == PR_FAILURE) {
    buf[0] = '\0';
    return -1;
  }
  numdigits = endnum - num;
  nump = num;

  if (sign) {
    *bufp++ = '-';
  } else if (aFlags & _SIGNED) {
    *bufp++ = '+';
  }

  if (decpt == 9999) {
    while ((*bufp++ = *nump++)) {
    }
  } else {

    switch (aType) {

      case 'E':
      case 'e':

        *bufp++ = *nump++;
        if (aPrec > 0) {
          *bufp++ = '.';
          while (*nump) {
            *bufp++ = *nump++;
            aPrec--;
          }
          while (aPrec-- > 0) {
            *bufp++ = '0';
          }
        }
        *bufp++ = exp;

        ::snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt - 1);
        break;

      case 'f':

        if (decpt < 1) {
          *bufp++ = '0';
          if (aPrec > 0) {
            *bufp++ = '.';
            while (decpt++ && aPrec-- > 0) {
              *bufp++ = '0';
            }
            while (*nump && aPrec-- > 0) {
              *bufp++ = *nump++;
            }
            while (aPrec-- > 0) {
              *bufp++ = '0';
            }
          }
        } else {
          while (*nump && decpt-- > 0) {
            *bufp++ = *nump++;
          }
          while (decpt-- > 0) {
            *bufp++ = '0';
          }
          if (aPrec > 0) {
            *bufp++ = '.';
            while (*nump && aPrec-- > 0) {
              *bufp++ = *nump++;
            }
            while (aPrec-- > 0) {
              *bufp++ = '0';
            }
          }
        }
        *bufp = '\0';
        break;

      case 'G':
      case 'g':

        if ((decpt < -3) || ((decpt - 1) >= aPrec)) {
          *bufp++ = *nump++;
          numdigits--;
          if (numdigits > 0) {
            *bufp++ = '.';
            while (*nump) {
              *bufp++ = *nump++;
            }
          }
          *bufp++ = exp;
          ::snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt - 1);
        } else {
          if (decpt < 1) {
            *bufp++ = '0';
            if (aPrec > 0) {
              *bufp++ = '.';
              while (decpt++) {
                *bufp++ = '0';
              }
              while (*nump) {
                *bufp++ = *nump++;
              }
            }
          } else {
            while (*nump && decpt-- > 0) {
              *bufp++ = *nump++;
              numdigits--;
            }
            while (decpt-- > 0) {
              *bufp++ = '0';
            }
            if (numdigits > 0) {
              *bufp++ = '.';
              while (*nump) {
                *bufp++ = *nump++;
              }
            }
          }
          *bufp = '\0';
        }
    }
  }

  char16_t rbuf[256];
  char16_t* rbufp = rbuf;
  bufp = buf;
  // cast to char16_t
  while ((*rbufp++ = *bufp++)) {
  }
  *rbufp = '\0';

  return fill2(aState, rbuf, NS_strlen(rbuf), aWidth, aFlags);
}
Exemplo n.º 3
0
/**
 * This is a copy of |PR_cnvtf| with a bug fixed.  (The second argument
 * of PR_dtoa is 2 rather than 1.)
 *
 * XXX(darin): if this is the right thing, then why wasn't it fixed in NSPR?!?
 */
static void 
Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval)
{
  PRIntn decpt, sign, numdigits;
  char *num, *nump;
  char *bufp = buf;
  char *endnum;

  /* If anything fails, we store an empty string in 'buf' */
  num = (char*)malloc(bufsz);
  if (num == NULL) {
    buf[0] = '\0';
    return;
  }
  if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz)
      == PR_FAILURE) {
    buf[0] = '\0';
    goto done;
  }
  numdigits = endnum - num;
  nump = num;

  /*
   * The NSPR code had a fancy way of checking that we weren't dealing
   * with -0.0 or -NaN, but I'll just use < instead.
   * XXX Should we check !isnan(fval) as well?  Is it portable?  We
   * probably don't need to bother since NAN isn't portable.
   */
  if (sign && fval < 0.0f) {
    *bufp++ = '-';
  }

  if (decpt == 9999) {
    while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
    goto done;
  }

  if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
    *bufp++ = *nump++;
    if (numdigits != 1) {
      *bufp++ = '.';
    }

    while (*nump != '\0') {
      *bufp++ = *nump++;
    }
    *bufp++ = 'e';
    PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
  }
  else if (decpt >= 0) {
    if (decpt == 0) {
      *bufp++ = '0';
    }
    else {
      while (decpt--) {
        if (*nump != '\0') {
          *bufp++ = *nump++;
        }
        else {
          *bufp++ = '0';
        }
      }
    }
    if (*nump != '\0') {
      *bufp++ = '.';
      while (*nump != '\0') {
        *bufp++ = *nump++;
      }
    }
    *bufp++ = '\0';
  }
  else if (decpt < 0) {
    *bufp++ = '0';
    *bufp++ = '.';
    while (decpt++) {
      *bufp++ = '0';
    }

    while (*nump != '\0') {
      *bufp++ = *nump++;
    }
    *bufp++ = '\0';
  }
done:
  free(num);
}
Exemplo n.º 4
0
/**
 * This is a copy of |PR_cnvtf| with a bug fixed.  (The second argument
 * of PR_dtoa is 2 rather than 1.)
 *
 * XXX(darin): if this is the right thing, then why wasn't it fixed in NSPR?!?
 */
static void 
Modified_cnvtf(char (& buf)[40], int prcsn, double fval)
{
  int decpt, sign, numdigits;
  char num[40];
  char *nump;
  char *bufp = buf;
  char *endnum;

  if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, sizeof(num))
      == PR_FAILURE) {
    buf[0] = '\0';
    return;
  }
  numdigits = endnum - num;
  nump = num;

  /*
   * The NSPR code had a fancy way of checking that we weren't dealing
   * with -0.0 or -NaN, but I'll just use < instead.
   * XXX Should we check !isnan(fval) as well?  Is it portable?  We
   * probably don't need to bother since NAN isn't portable.
   */
  if (sign && fval < 0.0f) {
    *bufp++ = '-';
  }

  if (decpt == 9999) {
    while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
    return;
  }

  if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
    *bufp++ = *nump++;
    if (numdigits != 1) {
      *bufp++ = '.';
    }

    while (*nump != '\0') {
      *bufp++ = *nump++;
    }
    *bufp++ = 'e';
    PR_snprintf(bufp, sizeof(num) - (bufp - buf), "%+d", decpt-1);
  }
  else if (decpt >= 0) {
    if (decpt == 0) {
      *bufp++ = '0';
    }
    else {
      while (decpt--) {
        if (*nump != '\0') {
          *bufp++ = *nump++;
        }
        else {
          *bufp++ = '0';
        }
      }
    }
    if (*nump != '\0') {
      *bufp++ = '.';
      while (*nump != '\0') {
        *bufp++ = *nump++;
      }
    }
    *bufp++ = '\0';
  }
  else if (decpt < 0) {
    *bufp++ = '0';
    *bufp++ = '.';
    while (decpt++) {
      *bufp++ = '0';
    }

    while (*nump != '\0') {
      *bufp++ = *nump++;
    }
    *bufp++ = '\0';
  }
}
Exemplo n.º 5
0
/*
 * Evaluates this Expr based on the given context node and processor state
 * @param context the context node for evaluation of this Expr
 * @param cs the ContextState containing the stack information needed
 * for evaluation
 * @return the result of the evaluation
 */
nsresult
txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
                                     txAExprResult** aResult)
{
    *aResult = nullptr;
    if (!requireParams(2, 3, aContext))
        return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

    // Get number and format
    double value;
    txExpandedName formatName;

    nsresult rv = evaluateToNumber(mParams[0], aContext, &value);
    NS_ENSURE_SUCCESS(rv, rv);

    nsAutoString formatStr;
    rv = mParams[1]->evaluateToString(aContext, formatStr);
    NS_ENSURE_SUCCESS(rv, rv);

    if (mParams.Length() == 3) {
        nsAutoString formatQName;
        rv = mParams[2]->evaluateToString(aContext, formatQName);
        NS_ENSURE_SUCCESS(rv, rv);

        rv = formatName.init(formatQName, mMappings, false);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    txDecimalFormat* format = mStylesheet->getDecimalFormat(formatName);
    if (!format) {
        nsAutoString err(NS_LITERAL_STRING("unknown decimal format"));
#ifdef TX_TO_STRING
        err.AppendLiteral(" for: ");
        toString(err);
#endif
        aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG);
        return NS_ERROR_XPATH_INVALID_ARG;
    }

    // Special cases
    if (mozilla::IsNaN(value)) {
        return aContext->recycler()->getStringResult(format->mNaN, aResult);
    }

    if (value == mozilla::PositiveInfinity<double>()) {
        return aContext->recycler()->getStringResult(format->mInfinity,
                                                     aResult);
    }

    if (value == mozilla::NegativeInfinity<double>()) {
        nsAutoString res;
        res.Append(format->mMinusSign);
        res.Append(format->mInfinity);
        return aContext->recycler()->getStringResult(res, aResult);
    }

    // Value is a normal finite number
    nsAutoString prefix;
    nsAutoString suffix;
    int minIntegerSize=0;
    int minFractionSize=0;
    int maxFractionSize=0;
    int multiplier=1;
    int groupSize=-1;

    uint32_t pos = 0;
    uint32_t formatLen = formatStr.Length();
    bool inQuote;

    // Get right subexpression
    inQuote = false;
    if (mozilla::IsNegative(value)) {
        while (pos < formatLen &&
               (inQuote ||
                formatStr.CharAt(pos) != format->mPatternSeparator)) {
            if (formatStr.CharAt(pos) == FORMAT_QUOTE)
                inQuote = !inQuote;
            pos++;
        }

        if (pos == formatLen) {
            pos = 0;
            prefix.Append(format->mMinusSign);
        }
        else
            pos++;
    }

    // Parse the format string
    FormatParseState pState = Prefix;
    inQuote = false;

    char16_t c = 0;
    while (pos < formatLen && pState != Finished) {
        c=formatStr.CharAt(pos++);

        switch (pState) {

        case Prefix:
        case Suffix:
            if (!inQuote) {
                if (c == format->mPercent) {
                    if (multiplier == 1)
                        multiplier = 100;
                    else {
                        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
                        err.AppendLiteral(": ");
                        toString(err);
#endif
                        aContext->receiveError(err,
                                               NS_ERROR_XPATH_INVALID_ARG);
                        return NS_ERROR_XPATH_INVALID_ARG;
                    }
                }
                else if (c == format->mPerMille) {
                    if (multiplier == 1)
                        multiplier = 1000;
                    else {
                        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
                        err.AppendLiteral(": ");
                        toString(err);
#endif
                        aContext->receiveError(err,
                                               NS_ERROR_XPATH_INVALID_ARG);
                        return NS_ERROR_XPATH_INVALID_ARG;
                    }
                }
                else if (c == format->mDecimalSeparator ||
                         c == format->mGroupingSeparator ||
                         c == format->mZeroDigit ||
                         c == format->mDigit ||
                         c == format->mPatternSeparator) {
                    pState = pState == Prefix ? IntDigit : Finished;
                    pos--;
                    break;
                }
            }

            if (c == FORMAT_QUOTE)
                inQuote = !inQuote;
            else if (pState == Prefix)
                prefix.Append(c);
            else
                suffix.Append(c);
            break;

        case IntDigit:
            if (c == format->mGroupingSeparator)
                groupSize=0;
            else if (c == format->mDigit) {
                if (groupSize >= 0)
                    groupSize++;
            }
            else {
                pState = IntZero;
                pos--;
            }
            break;

        case IntZero:
            if (c == format->mGroupingSeparator)
                groupSize = 0;
            else if (c == format->mZeroDigit) {
                if (groupSize >= 0)
                    groupSize++;
                minIntegerSize++;
            }
            else if (c == format->mDecimalSeparator) {
                pState = FracZero;
            }
            else {
                pState = Suffix;
                pos--;
            }
            break;

        case FracZero:
            if (c == format->mZeroDigit) {
                maxFractionSize++;
                minFractionSize++;
            }
            else {
                pState = FracDigit;
                pos--;
            }
            break;

        case FracDigit:
            if (c == format->mDigit)
                maxFractionSize++;
            else {
                pState = Suffix;
                pos--;
            }
            break;

        case Finished:
            break;
        }
    }

    // Did we manage to parse the entire formatstring and was it valid
    if ((c != format->mPatternSeparator && pos < formatLen) ||
        inQuote ||
        groupSize == 0) {
        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
        err.AppendLiteral(": ");
        toString(err);
#endif
        aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG);
        return NS_ERROR_XPATH_INVALID_ARG;
    }


    /*
     * FINALLY we're done with the parsing
     * now build the result string
     */

    value = fabs(value) * multiplier;

    // Prefix
    nsAutoString res(prefix);

    int bufsize;
    if (value > 1)
        bufsize = (int)log10(value) + 30;
    else
        bufsize = 1 + 30;

    char* buf = new char[bufsize];
    NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);

    int bufIntDigits, sign;
    char* endp;
    PR_dtoa(value, 0, 0, &bufIntDigits, &sign, &endp, buf, bufsize-1);

    int buflen = endp - buf;
    int intDigits;
    intDigits = bufIntDigits > minIntegerSize ? bufIntDigits : minIntegerSize;

    if (groupSize < 0)
        groupSize = intDigits + 10; //to simplify grouping

    // XXX We shouldn't use SetLength.
    res.SetLength(res.Length() +
                  intDigits +               // integer digits
                  1 +                       // decimal separator
                  maxFractionSize +         // fractions
                  (intDigits-1)/groupSize); // group separators

    int32_t i = bufIntDigits + maxFractionSize - 1;
    bool carry = (0 <= i+1) && (i+1 < buflen) && (buf[i+1] >= '5');
    bool hasFraction = false;

    uint32_t resPos = res.Length()-1;

    // Fractions
    for (; i >= bufIntDigits; --i) {
        int digit;
        if (i >= buflen || i < 0) {
            digit = 0;
        }
        else {
            digit = buf[i] - '0';
        }
        
        if (carry) {
            digit = (digit + 1) % 10;
            carry = digit == 0;
        }

        if (hasFraction || digit != 0 || i < bufIntDigits+minFractionSize) {
            hasFraction = true;
            res.SetCharAt((char16_t)(digit + format->mZeroDigit),
                          resPos--);
        }
        else {
            res.Truncate(resPos--);
        }
    }

    // Decimal separator
    if (hasFraction) {
        res.SetCharAt(format->mDecimalSeparator, resPos--);
    }
    else {
        res.Truncate(resPos--);
    }

    // Integer digits
    for (i = 0; i < intDigits; ++i) {
        int digit;
        if (bufIntDigits-i-1 >= buflen || bufIntDigits-i-1 < 0) {
            digit = 0;
        }
        else {
            digit = buf[bufIntDigits-i-1] - '0';
        }
        
        if (carry) {
            digit = (digit + 1) % 10;
            carry = digit == 0;
        }

        if (i != 0 && i%groupSize == 0) {
            res.SetCharAt(format->mGroupingSeparator, resPos--);
        }

        res.SetCharAt((char16_t)(digit + format->mZeroDigit), resPos--);
    }

    if (carry) {
        if (i%groupSize == 0) {
            res.Insert(format->mGroupingSeparator, resPos + 1);
        }
        res.Insert((char16_t)(1 + format->mZeroDigit), resPos + 1);
    }

    if (!hasFraction && !intDigits && !carry) {
        // If we havn't added any characters we add a '0'
        // This can only happen for formats like '##.##'
        res.Append(format->mZeroDigit);
    }

    delete [] buf;

    // Build suffix
    res.Append(suffix);

    return aContext->recycler()->getStringResult(res, aResult);
} //-- evaluate