static longlong my_strtoll10_mb2()

in mysql_strings/ctype-ucs2.cc [621:782]


static longlong my_strtoll10_mb2(const CHARSET_INFO *cs, const char *nptr,
                                 const char **endptr, int *error) {
  const char *s, *end, *start, *n_end, *true_end;
  uchar c;
  unsigned long i, j, k;
  ulonglong li;
  int negative;
  ulong cutoff, cutoff2, cutoff3;
  my_wc_t wc;
  int res;

  s = nptr;
  /* If fixed length string */
  if (endptr) {
    /*
      Make sure string length is even.
      Odd length indicates a bug in the caller.
      Assert in debug, round in production.
    */
    assert((*endptr - s) % 2 == 0);
    end = s + ((*endptr - s) / 2) * 2;

    for (;;) /* Skip leading spaces and tabs */
    {
      res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
      if (res <= 0) goto no_conv;
      s += res;
      if (wc != ' ' && wc != '\t') break;
    }
  } else {
    /* We don't support null terminated strings in UCS2 */
    goto no_conv;
  }

  /* Check for a sign. */
  negative = 0;
  if (wc == '-') {
    *error = -1; /* Mark as negative number */
    negative = 1;
    res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
    if (res <= 0) goto no_conv;
    s += res;
    cutoff = MAX_NEGATIVE_NUMBER / LFACTOR2;
    cutoff2 = (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
    cutoff3 = MAX_NEGATIVE_NUMBER % 100;
  } else {
    *error = 0;
    if (wc == '+') {
      res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
      if (res <= 0) goto no_conv;
      s += res;
    }
    cutoff = ULONGLONG_MAX / LFACTOR2;
    cutoff2 = ULONGLONG_MAX % LFACTOR2 / 100;
    cutoff3 = ULONGLONG_MAX % 100;
  }

  /* Handle case where we have a lot of pre-zero */
  if (wc == '0') {
    i = 0;
    for (;; s += res) {
      if (s == end) goto end_i; /* Return 0 */
      res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
      if (res <= 0) goto no_conv;
      if (wc != '0') break;
    }
    while (wc == '0')
      ;
    n_end = s + 2 * INIT_CNT;
  } else {
    /* Read first digit to check that it's a valid number */
    if ((c = (wc - '0')) > 9) goto no_conv;
    i = c;
    n_end = s + 2 * (INIT_CNT - 1);
  }

  /* Handle first 9 digits and store them in i */
  if (n_end > end) n_end = end;
  for (;;) {
    res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)n_end);
    if (res <= 0) break;
    if ((c = (wc - '0')) > 9) goto end_i;
    s += res;
    i = i * 10 + c;
  }
  if (s == end) goto end_i;

  /* Handle next 9 digits and store them in j */
  j = 0;
  start = s; /* Used to know how much to shift i */
  n_end = true_end = s + 2 * INIT_CNT;
  if (n_end > end) n_end = end;
  do {
    res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
    if (res <= 0) goto no_conv;
    if ((c = (wc - '0')) > 9) goto end_i_and_j;
    s += res;
    j = j * 10 + c;
  } while (s != n_end);
  if (s == end) {
    if (s != true_end) goto end_i_and_j;
    goto end3;
  }
  res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
  if (res <= 0) goto no_conv;
  if ((c = (wc - '0')) > 9) goto end3;
  s += res;

  /* Handle the next 1 or 2 digits and store them in k */
  k = c;
  if (s == end) goto end4;
  res = cs->cset->mb_wc(cs, &wc, (const uchar *)s, (const uchar *)end);
  if (res <= 0) goto no_conv;
  if ((c = (wc - '0')) > 9) goto end4;
  s += res;
  k = k * 10 + c;
  *endptr = s;

  /* number string should have ended here */
  if (s != end && (c = (wc - '0')) <= 9) goto overflow;

  /* Check that we didn't get an overflow with the last digit */
  if (i > cutoff ||
      (i == cutoff && ((j > cutoff2 || j == cutoff2) && k > cutoff3)))
    goto overflow;
  li = i * LFACTOR2 + (ulonglong)j * 100 + k;
  return (longlong)li;

overflow: /* *endptr is set here */
  *error = MY_ERRNO_ERANGE;
  return negative ? LLONG_MIN : (longlong)ULONGLONG_MAX;

end_i:
  *endptr = s;
  return (negative ? ((longlong) - (long)i) : (longlong)i);

end_i_and_j:
  li = (ulonglong)i * lfactor[(size_t)(s - start) / 2] + j;
  *endptr = s;
  return (negative ? -((longlong)li) : (longlong)li);

end3:
  li = (ulonglong)i * LFACTOR + (ulonglong)j;
  *endptr = s;
  return (negative ? -((longlong)li) : (longlong)li);

end4:
  li = (ulonglong)i * LFACTOR1 + (ulonglong)j * 10 + k;
  *endptr = s;
  if (negative) {
    if (li > MAX_NEGATIVE_NUMBER) goto overflow;
    if (li == MAX_NEGATIVE_NUMBER) return LLONG_MIN;
    return -((longlong)li);
  }
  return (longlong)li;

no_conv:
  /* There was no number to convert.  */
  *error = MY_ERRNO_EDOM;
  *endptr = nptr;
  return 0;
}