in mysql_strings/ctype-ucs2.cc [279:372]
static longlong my_strntoll_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;
ulonglong cutoff;
unsigned int cutlim;
ulonglong 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 = (~(ulonglong)0) / (unsigned long int)base;
cutlim = (uint)((~(ulonglong)0) % (unsigned long int)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 *= (ulonglong)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 > (ulonglong)LLONG_MIN) overflow = 1;
} else if (res > (ulonglong)LLONG_MAX)
overflow = 1;
if (overflow) {
err[0] = ERANGE;
return negative ? LLONG_MIN : LLONG_MAX;
}
return negative ? -res : res;
}