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);
}