static long my_strntol_mb2_or_mb4()

in mysql_strings/ctype-ucs2.cc [94:187]


static long my_strntol_mb2_or_mb4(const CHARSET_INFO *cs, const char *nptr,
                                  size_t l, int base, const char **endptr,
                                  int *err) {
  int negative = 0;
  int overflow;
  int cnv;
  my_wc_t wc;
  unsigned int cutlim;
  uint32 cutoff;
  uint32 res;
  const uchar *s = (const uchar *)nptr;
  const uchar *e = (const uchar *)nptr + l;
  const uchar *save;

  *err = 0;
  do {
    if ((cnv = cs->cset->mb_wc(cs, &wc, s, e)) > 0) {
      switch (wc) {
        case ' ':
          break;
        case '\t':
          break;
        case '-':
          negative = !negative;
          break;
        case '+':
          break;
        default:
          goto bs;
      }
    } else /* No more characters or bad multibyte sequence */
    {
      if (endptr != nullptr) *endptr = pointer_cast<const char *>(s);
      err[0] = (cnv == MY_CS_ILSEQ) ? EILSEQ : EDOM;
      return 0;
    }
    s += cnv;
  } while (true);

bs:

  overflow = 0;
  res = 0;
  save = s;
  cutoff = ((uint32)~0L) / (uint32)base;
  cutlim = (uint)(((uint32)~0L) % (uint32)base);

  do {
    if ((cnv = cs->cset->mb_wc(cs, &wc, s, e)) > 0) {
      s += cnv;
      if (wc >= '0' && wc <= '9')
        wc -= '0';
      else if (wc >= 'A' && wc <= 'Z')
        wc = wc - 'A' + 10;
      else if (wc >= 'a' && wc <= 'z')
        wc = wc - 'a' + 10;
      else
        break;
      if ((int)wc >= base) break;
      if (res > cutoff || (res == cutoff && wc > cutlim))
        overflow = 1;
      else {
        res *= (uint32)base;
        res += wc;
      }
    } else if (cnv == MY_CS_ILSEQ) {
      if (endptr != nullptr) *endptr = pointer_cast<const char *>(s);
      err[0] = EILSEQ;
      return 0;
    } else {
      /* No more characters */
      break;
    }
  } while (true);

  if (endptr != nullptr) *endptr = pointer_cast<const char *>(s);

  if (s == save) {
    err[0] = EDOM;
    return 0L;
  }

  if (negative) {
    if (res > (uint32)INT_MIN32) overflow = 1;
  } else if (res > INT_MAX32)
    overflow = 1;

  if (overflow) {
    err[0] = ERANGE;
    return negative ? INT_MIN32 : INT_MAX32;
  }

  return (negative ? -((long)res) : (long)res);
}