libc: Implement N2630.
This adds formatted input/output of binary integer numbers to the printf(), scanf(), and strtol() families, including their wide-character counterparts. Reviewed by: imp, emaste Differential Revision: https://reviews.freebsd.org/D41511
This commit is contained in:
parent
2964804ef9
commit
d9dc1603d6
|
@ -91,6 +91,13 @@ _FUNCNAME(const char *nptr, char **endptr, int base)
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = (c == '0' ? 8 : 10);
|
||||
|
||||
|
|
|
@ -87,6 +87,13 @@ _FUNCNAME(const char *nptr, char **endptr, int base)
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = (c == '0' ? 8 : 10);
|
||||
|
||||
|
|
|
@ -86,6 +86,13 @@ wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -80,6 +80,13 @@ wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -86,6 +86,13 @@ wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -80,6 +80,13 @@ wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -86,6 +86,13 @@ wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -86,6 +86,13 @@ wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == L'0' && (*s == L'b' || *s == L'B') &&
|
||||
(s[1] >= L'0' && s[1] <= L'1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == L'0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -194,6 +194,13 @@ __ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
|
|||
} while (sval != 0);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
do {
|
||||
*--cp = to_char(val & 1);
|
||||
val >>= 1;
|
||||
} while (val);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
do {
|
||||
*--cp = to_char(val & 7);
|
||||
|
@ -244,6 +251,13 @@ __ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
|
|||
} while (sval != 0);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
do {
|
||||
*--cp = to_char(val & 1);
|
||||
val >>= 1;
|
||||
} while (val);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
do {
|
||||
*--cp = to_char(val & 7);
|
||||
|
|
|
@ -613,6 +613,19 @@ reswitch: switch (ch) {
|
|||
case 'z':
|
||||
flags |= SIZET;
|
||||
goto rflag;
|
||||
case 'B':
|
||||
case 'b':
|
||||
if (flags & INTMAX_SIZE)
|
||||
ujval = UJARG();
|
||||
else
|
||||
ulval = UARG();
|
||||
base = 2;
|
||||
/* leading 0b/B only if non-zero */
|
||||
if (flags & ALT &&
|
||||
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
|
||||
ox[1] = ch;
|
||||
goto nosign;
|
||||
break;
|
||||
case 'C':
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
*
|
||||
* Copyright (c) 2023 Dag-Erling Smørgrav
|
||||
*
|
||||
* Portions of this software were developed by David Chisnall
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
|
@ -80,16 +82,6 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
|
|||
#define SHORTSHORT 0x4000 /* hh: char */
|
||||
#define UNSIGNED 0x8000 /* %[oupxX] conversions */
|
||||
|
||||
/*
|
||||
* The following are used in integral conversions only:
|
||||
* SIGNOK, NDIGITS, PFXOK, and NZDIGITS
|
||||
*/
|
||||
#define SIGNOK 0x40 /* +/- is (still) legal */
|
||||
#define NDIGITS 0x80 /* no digits detected */
|
||||
#define PFXOK 0x100 /* 0x prefix is (still) legal */
|
||||
#define NZDIGITS 0x200 /* no zero digits detected */
|
||||
#define HAVESIGN 0x10000 /* sign detected */
|
||||
|
||||
/*
|
||||
* Conversion types.
|
||||
*/
|
||||
|
@ -307,129 +299,160 @@ convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
|
|||
return (n);
|
||||
}
|
||||
|
||||
enum parseint_state {
|
||||
begin,
|
||||
havesign,
|
||||
havezero,
|
||||
haveprefix,
|
||||
any,
|
||||
};
|
||||
|
||||
static __inline int
|
||||
parseint_fsm(int c, enum parseint_state *state, int *base)
|
||||
{
|
||||
switch (c) {
|
||||
case '+':
|
||||
case '-':
|
||||
if (*state == begin) {
|
||||
*state = havesign;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
if (*state == begin || *state == havesign) {
|
||||
*state = havezero;
|
||||
} else {
|
||||
*state = any;
|
||||
}
|
||||
return 1;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
if (*state == havezero && *base == 0) {
|
||||
*base = 8;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case '8':
|
||||
case '9':
|
||||
if (*state == begin ||
|
||||
*state == havesign) {
|
||||
if (*base == 0) {
|
||||
*base = 10;
|
||||
}
|
||||
}
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - '0') {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 2) {
|
||||
*state = haveprefix;
|
||||
*base = 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case 'a':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - 'a' + 10) {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 2) {
|
||||
*state = haveprefix;
|
||||
*base = 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case 'A':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - 'A' + 10) {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 16) {
|
||||
*state = haveprefix;
|
||||
*base = 16;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an integer, storing it in buf. The only relevant bit in the
|
||||
* flags argument is PFXOK.
|
||||
* Read an integer, storing it in buf.
|
||||
*
|
||||
* Return 0 on a match failure, and the number of characters read
|
||||
* otherwise.
|
||||
*/
|
||||
static __inline int
|
||||
parseint(FILE *fp, char * __restrict buf, int width, int base, int flags)
|
||||
parseint(FILE *fp, char * __restrict buf, int width, int base)
|
||||
{
|
||||
/* `basefix' is used to avoid `if' tests */
|
||||
static const short basefix[17] =
|
||||
{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||
enum parseint_state state = begin;
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
flags |= SIGNOK | NDIGITS | NZDIGITS;
|
||||
for (p = buf; width; width--) {
|
||||
c = *fp->_p;
|
||||
/*
|
||||
* Switch on the character; `goto ok' if we accept it
|
||||
* as a part of number.
|
||||
*/
|
||||
switch (c) {
|
||||
|
||||
/*
|
||||
* The digit 0 is always legal, but is special. For
|
||||
* %i conversions, if no digits (zero or nonzero) have
|
||||
* been scanned (only signs), we will have base==0.
|
||||
* In that case, we should set it to 8 and enable 0x
|
||||
* prefixing. Also, if we have not scanned zero
|
||||
* digits before this, do not turn off prefixing
|
||||
* (someone else will turn it off if we have scanned
|
||||
* any nonzero digits).
|
||||
*/
|
||||
case '0':
|
||||
if (base == 0) {
|
||||
base = 8;
|
||||
flags |= PFXOK;
|
||||
}
|
||||
if (flags & NZDIGITS)
|
||||
flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
|
||||
else
|
||||
flags &= ~(SIGNOK|PFXOK|NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* 1 through 7 always legal */
|
||||
case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
base = basefix[base];
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* digits 8 and 9 ok iff decimal or hex */
|
||||
case '8': case '9':
|
||||
base = basefix[base];
|
||||
if (base <= 8)
|
||||
break; /* not legal here */
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* letters ok iff hex */
|
||||
case 'A': case 'B': case 'C':
|
||||
case 'D': case 'E': case 'F':
|
||||
case 'a': case 'b': case 'c':
|
||||
case 'd': case 'e': case 'f':
|
||||
/* no need to fix base here */
|
||||
if (base <= 10)
|
||||
break; /* not legal here */
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* sign ok only as first character */
|
||||
case '+': case '-':
|
||||
if (flags & SIGNOK) {
|
||||
flags &= ~SIGNOK;
|
||||
flags |= HAVESIGN;
|
||||
goto ok;
|
||||
}
|
||||
c = __sgetc(fp);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
/*
|
||||
* x ok iff flag still set & 2nd char (or 3rd char if
|
||||
* we have a sign).
|
||||
*/
|
||||
case 'x': case 'X':
|
||||
if (flags & PFXOK && p ==
|
||||
buf + 1 + !!(flags & HAVESIGN)) {
|
||||
base = 16; /* if %i */
|
||||
flags &= ~PFXOK;
|
||||
goto ok;
|
||||
}
|
||||
if (!parseint_fsm(c, &state, &base))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got here, c is not a legal character for a
|
||||
* number. Stop accumulating digits.
|
||||
*/
|
||||
break;
|
||||
ok:
|
||||
/*
|
||||
* c is legal: store it and look at the next.
|
||||
*/
|
||||
*p++ = c;
|
||||
if (--fp->_r > 0)
|
||||
fp->_p++;
|
||||
else if (__srefill(fp))
|
||||
break; /* EOF */
|
||||
}
|
||||
/*
|
||||
* If we had only a sign, it is no good; push back the sign.
|
||||
* If the number ends in `x', it was [sign] '0' 'x', so push
|
||||
* back the x and treat it as [sign] '0'.
|
||||
* If we only had a sign, push it back. If we only had a 0b or 0x
|
||||
* prefix (possibly preceded by a sign), we view it as "0" and
|
||||
* push back the letter. In all other cases, if we stopped
|
||||
* because we read a non-number character, push it back.
|
||||
*/
|
||||
if (flags & NDIGITS) {
|
||||
if (p > buf)
|
||||
(void) __ungetc(*(u_char *)--p, fp);
|
||||
return (0);
|
||||
}
|
||||
c = ((u_char *)p)[-1];
|
||||
if (c == 'x' || c == 'X') {
|
||||
--p;
|
||||
if (state == havesign) {
|
||||
p--;
|
||||
(void) __ungetc(*(u_char *)p, fp);
|
||||
} else if (state == haveprefix) {
|
||||
p--;
|
||||
(void) __ungetc(c, fp);
|
||||
} else if (c != EOF) {
|
||||
(void) __ungetc(c, fp);
|
||||
}
|
||||
return (p - buf);
|
||||
|
@ -554,6 +577,13 @@ literal:
|
|||
/*
|
||||
* Conversions.
|
||||
*/
|
||||
case 'B':
|
||||
case 'b':
|
||||
c = CT_INT;
|
||||
flags |= UNSIGNED;
|
||||
base = 2;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
c = CT_INT;
|
||||
base = 10;
|
||||
|
@ -578,7 +608,6 @@ literal:
|
|||
|
||||
case 'X':
|
||||
case 'x':
|
||||
flags |= PFXOK; /* enable 0x prefixing */
|
||||
c = CT_INT;
|
||||
flags |= UNSIGNED;
|
||||
base = 16;
|
||||
|
@ -613,7 +642,7 @@ literal:
|
|||
break;
|
||||
|
||||
case 'p': /* pointer format is like hex */
|
||||
flags |= POINTER | PFXOK;
|
||||
flags |= POINTER;
|
||||
c = CT_INT; /* assumes sizeof(uintmax_t) */
|
||||
flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
|
||||
base = 16;
|
||||
|
@ -738,7 +767,7 @@ literal:
|
|||
width = sizeof(buf) - 2;
|
||||
width++;
|
||||
#endif
|
||||
nr = parseint(fp, buf, width, base, flags);
|
||||
nr = parseint(fp, buf, width, base);
|
||||
if (nr == 0)
|
||||
goto match_failure;
|
||||
if ((flags & SUPPRESS) == 0) {
|
||||
|
|
|
@ -684,6 +684,19 @@ reswitch: switch (ch) {
|
|||
case 'z':
|
||||
flags |= SIZET;
|
||||
goto rflag;
|
||||
case 'B':
|
||||
case 'b':
|
||||
if (flags & INTMAX_SIZE)
|
||||
ujval = UJARG();
|
||||
else
|
||||
ulval = UARG();
|
||||
base = 2;
|
||||
/* leading 0b/B only if non-zero */
|
||||
if (flags & ALT &&
|
||||
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
|
||||
ox[1] = ch;
|
||||
goto nosign;
|
||||
break;
|
||||
case 'C':
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
*
|
||||
* Copyright (c) 2023 Dag-Erling Smørgrav
|
||||
*
|
||||
* Portions of this software were developed by David Chisnall
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
|
@ -78,16 +80,6 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
|
|||
#define SHORTSHORT 0x4000 /* hh: char */
|
||||
#define UNSIGNED 0x8000 /* %[oupxX] conversions */
|
||||
|
||||
/*
|
||||
* The following are used in integral conversions only:
|
||||
* SIGNOK, NDIGITS, PFXOK, and NZDIGITS
|
||||
*/
|
||||
#define SIGNOK 0x40 /* +/- is (still) legal */
|
||||
#define NDIGITS 0x80 /* no digits detected */
|
||||
#define PFXOK 0x100 /* 0x prefix is (still) legal */
|
||||
#define NZDIGITS 0x200 /* no zero digits detected */
|
||||
#define HAVESIGN 0x10000 /* sign detected */
|
||||
|
||||
/*
|
||||
* Conversion types.
|
||||
*/
|
||||
|
@ -289,128 +281,161 @@ convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
|
|||
return (nread);
|
||||
}
|
||||
|
||||
enum parseint_state {
|
||||
begin,
|
||||
havesign,
|
||||
havezero,
|
||||
haveprefix,
|
||||
any,
|
||||
};
|
||||
|
||||
static __inline int
|
||||
parseint_fsm(wchar_t c, enum parseint_state *state, int *base)
|
||||
{
|
||||
switch (c) {
|
||||
case '+':
|
||||
case '-':
|
||||
if (*state == begin) {
|
||||
*state = havesign;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
if (*state == begin || *state == havesign) {
|
||||
*state = havezero;
|
||||
} else {
|
||||
*state = any;
|
||||
}
|
||||
return 1;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
if (*state == havezero && *base == 0) {
|
||||
*base = 8;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case '8':
|
||||
case '9':
|
||||
if (*state == begin ||
|
||||
*state == havesign) {
|
||||
if (*base == 0) {
|
||||
*base = 10;
|
||||
}
|
||||
}
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - '0') {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 2) {
|
||||
*state = haveprefix;
|
||||
*base = 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case 'a':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - 'a' + 10) {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 2) {
|
||||
*state = haveprefix;
|
||||
*base = 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case 'A':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
if (*state == begin ||
|
||||
*state == havesign ||
|
||||
*state == havezero ||
|
||||
*state == haveprefix ||
|
||||
*state == any) {
|
||||
if (*base > c - 'A' + 10) {
|
||||
*state = any;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (*state == havezero) {
|
||||
if (*base == 0 || *base == 16) {
|
||||
*state = haveprefix;
|
||||
*base = 16;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an integer, storing it in buf. The only relevant bit in the
|
||||
* flags argument is PFXOK.
|
||||
* Read an integer, storing it in buf.
|
||||
*
|
||||
* Return 0 on a match failure, and the number of characters read
|
||||
* otherwise.
|
||||
*/
|
||||
static __inline int
|
||||
parseint(FILE *fp, wchar_t *buf, int width, int base, int flags,
|
||||
parseint(FILE *fp, wchar_t * __restrict buf, int width, int base,
|
||||
locale_t locale)
|
||||
{
|
||||
/* `basefix' is used to avoid `if' tests */
|
||||
static const short basefix[17] =
|
||||
{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||
enum parseint_state state = begin;
|
||||
wchar_t *wcp;
|
||||
int c;
|
||||
|
||||
flags |= SIGNOK | NDIGITS | NZDIGITS;
|
||||
for (wcp = buf; width; width--) {
|
||||
c = __fgetwc(fp, locale);
|
||||
/*
|
||||
* Switch on the character; `goto ok' if we accept it
|
||||
* as a part of number.
|
||||
*/
|
||||
switch (c) {
|
||||
|
||||
/*
|
||||
* The digit 0 is always legal, but is special. For
|
||||
* %i conversions, if no digits (zero or nonzero) have
|
||||
* been scanned (only signs), we will have base==0.
|
||||
* In that case, we should set it to 8 and enable 0x
|
||||
* prefixing. Also, if we have not scanned zero
|
||||
* digits before this, do not turn off prefixing
|
||||
* (someone else will turn it off if we have scanned
|
||||
* any nonzero digits).
|
||||
*/
|
||||
case '0':
|
||||
if (base == 0) {
|
||||
base = 8;
|
||||
flags |= PFXOK;
|
||||
}
|
||||
if (flags & NZDIGITS)
|
||||
flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
|
||||
else
|
||||
flags &= ~(SIGNOK|PFXOK|NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* 1 through 7 always legal */
|
||||
case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
base = basefix[base];
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* digits 8 and 9 ok iff decimal or hex */
|
||||
case '8': case '9':
|
||||
base = basefix[base];
|
||||
if (base <= 8)
|
||||
break; /* not legal here */
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* letters ok iff hex */
|
||||
case 'A': case 'B': case 'C':
|
||||
case 'D': case 'E': case 'F':
|
||||
case 'a': case 'b': case 'c':
|
||||
case 'd': case 'e': case 'f':
|
||||
/* no need to fix base here */
|
||||
if (base <= 10)
|
||||
break; /* not legal here */
|
||||
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||
goto ok;
|
||||
|
||||
/* sign ok only as first character */
|
||||
case '+': case '-':
|
||||
if (flags & SIGNOK) {
|
||||
flags &= ~SIGNOK;
|
||||
flags |= HAVESIGN;
|
||||
goto ok;
|
||||
}
|
||||
if (c == WEOF)
|
||||
break;
|
||||
|
||||
/*
|
||||
* x ok iff flag still set & 2nd char (or 3rd char if
|
||||
* we have a sign).
|
||||
*/
|
||||
case 'x': case 'X':
|
||||
if (flags & PFXOK && wcp ==
|
||||
buf + 1 + !!(flags & HAVESIGN)) {
|
||||
base = 16; /* if %i */
|
||||
flags &= ~PFXOK;
|
||||
goto ok;
|
||||
}
|
||||
if (!parseint_fsm(c, &state, &base))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we got here, c is not a legal character for a
|
||||
* number. Stop accumulating digits.
|
||||
*/
|
||||
if (c != WEOF)
|
||||
__ungetwc(c, fp, locale);
|
||||
break;
|
||||
ok:
|
||||
/*
|
||||
* c is legal: store it and look at the next.
|
||||
*/
|
||||
*wcp++ = (wchar_t)c;
|
||||
}
|
||||
/*
|
||||
* If we had only a sign, it is no good; push back the sign.
|
||||
* If the number ends in `x', it was [sign] '0' 'x', so push
|
||||
* back the x and treat it as [sign] '0'.
|
||||
* If we only had a sign, push it back. If we only had a 0b or 0x
|
||||
* prefix (possibly preceded by a sign), we view it as "0" and
|
||||
* push back the letter. In all other cases, if we stopped
|
||||
* because we read a non-number character, push it back.
|
||||
*/
|
||||
if (flags & NDIGITS) {
|
||||
if (wcp > buf)
|
||||
__ungetwc(*--wcp, fp, locale);
|
||||
return (0);
|
||||
}
|
||||
c = wcp[-1];
|
||||
if (c == 'x' || c == 'X') {
|
||||
--wcp;
|
||||
if (state == havesign) {
|
||||
wcp--;
|
||||
__ungetwc(*wcp, fp, locale);
|
||||
} else if (state == haveprefix) {
|
||||
wcp--;
|
||||
__ungetwc(c, fp, locale);
|
||||
} else if (c != WEOF) {
|
||||
__ungetwc(c, fp, locale);
|
||||
}
|
||||
return (wcp - buf);
|
||||
|
@ -536,6 +561,13 @@ literal:
|
|||
/*
|
||||
* Conversions.
|
||||
*/
|
||||
case 'B':
|
||||
case 'b':
|
||||
c = CT_INT;
|
||||
flags |= UNSIGNED;
|
||||
base = 2;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
c = CT_INT;
|
||||
base = 10;
|
||||
|
@ -560,7 +592,6 @@ literal:
|
|||
|
||||
case 'X':
|
||||
case 'x':
|
||||
flags |= PFXOK; /* enable 0x prefixing */
|
||||
c = CT_INT;
|
||||
flags |= UNSIGNED;
|
||||
base = 16;
|
||||
|
@ -606,7 +637,7 @@ literal:
|
|||
break;
|
||||
|
||||
case 'p': /* pointer format is like hex */
|
||||
flags |= POINTER | PFXOK;
|
||||
flags |= POINTER;
|
||||
c = CT_INT; /* assumes sizeof(uintmax_t) */
|
||||
flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
|
||||
base = 16;
|
||||
|
@ -716,7 +747,7 @@ literal:
|
|||
sizeof(*buf) - 1)
|
||||
width = sizeof(buf) / sizeof(*buf) - 1;
|
||||
|
||||
nr = parseint(fp, buf, width, base, flags, locale);
|
||||
nr = parseint(fp, buf, width, base, locale);
|
||||
if (nr == 0)
|
||||
goto match_failure;
|
||||
if ((flags & SUPPRESS) == 0) {
|
||||
|
|
|
@ -87,6 +87,13 @@ strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -87,6 +87,13 @@ strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -63,8 +63,9 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
|
||||
/*
|
||||
* Skip white space and pick up leading +/- sign if any.
|
||||
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||
* assume decimal; if base is already 16, allow 0x.
|
||||
* If base is 0, allow 0b for binary, 0x for hex, and 0 for
|
||||
* octal, else assume decimal; if base is already 2, allow
|
||||
* 0b; if base is already 16, allow 0x.
|
||||
*/
|
||||
s = nptr;
|
||||
do {
|
||||
|
@ -87,6 +88,13 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -84,6 +84,13 @@ strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, loc
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -85,6 +85,13 @@ strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
|
@ -85,6 +85,13 @@ strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
|
|||
s += 2;
|
||||
base = 16;
|
||||
}
|
||||
if ((base == 0 || base == 2) &&
|
||||
c == '0' && (*s == 'b' || *s == 'B') &&
|
||||
(s[1] >= '0' && s[1] <= '1')) {
|
||||
c = s[1];
|
||||
s += 2;
|
||||
base = 2;
|
||||
}
|
||||
if (base == 0)
|
||||
base = c == '0' ? 8 : 10;
|
||||
acc = any = 0;
|
||||
|
|
Loading…
Reference in New Issue