diff --git a/lib/libc/iconv/_strtol.h b/lib/libc/iconv/_strtol.h --- a/lib/libc/iconv/_strtol.h +++ b/lib/libc/iconv/_strtol.h @@ -91,6 +91,13 @@ 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); diff --git a/lib/libc/iconv/_strtoul.h b/lib/libc/iconv/_strtoul.h --- a/lib/libc/iconv/_strtoul.h +++ b/lib/libc/iconv/_strtoul.h @@ -87,6 +87,13 @@ 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); diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c --- a/lib/libc/locale/wcstoimax.c +++ b/lib/libc/locale/wcstoimax.c @@ -86,6 +86,13 @@ 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; diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c --- a/lib/libc/locale/wcstol.c +++ b/lib/libc/locale/wcstol.c @@ -80,6 +80,13 @@ 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; diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c --- a/lib/libc/locale/wcstoll.c +++ b/lib/libc/locale/wcstoll.c @@ -86,6 +86,13 @@ 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; diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c --- a/lib/libc/locale/wcstoul.c +++ b/lib/libc/locale/wcstoul.c @@ -80,6 +80,13 @@ 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; diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c --- a/lib/libc/locale/wcstoull.c +++ b/lib/libc/locale/wcstoull.c @@ -86,6 +86,13 @@ 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; diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c --- a/lib/libc/locale/wcstoumax.c +++ b/lib/libc/locale/wcstoumax.c @@ -86,6 +86,13 @@ 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; diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h --- a/lib/libc/stdio/printfcommon.h +++ b/lib/libc/stdio/printfcommon.h @@ -194,6 +194,13 @@ } 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 @@ } 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); diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -613,6 +613,19 @@ 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*/ diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c --- a/lib/libc/stdio/vfscanf.c +++ b/lib/libc/stdio/vfscanf.c @@ -353,13 +353,21 @@ 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': + /* 1 always legal */ + case '1': base = basefix[base]; flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; + /* 2 through 7 ok iff octal, decimal, or hex */ + case '2': case '3': case '4': + case '5': case '6': case '7': + base = basefix[base]; + if (base <= 2) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + /* digits 8 and 9 ok iff decimal or hex */ case '8': case '9': base = basefix[base]; @@ -368,10 +376,23 @@ flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; + /* + * b ok iff flag still set & 2nd char (or 3rd char if + * we have a sign). + */ + case 'b': case 'B': + if (flags & PFXOK && p == + buf + 1 + !!(flags & HAVESIGN)) { + base = 2; /* if %i */ + flags &= ~PFXOK; + goto ok; + } + /* FALLTHROUGH */ + /* letters ok iff hex */ - case 'A': case 'B': case 'C': + case 'A': case 'C': case 'D': case 'E': case 'F': - case 'a': case 'b': case 'c': + case 'a': case 'c': case 'd': case 'e': case 'f': /* no need to fix base here */ if (base <= 10) @@ -420,7 +441,7 @@ /* * 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'. + * back the x and treat it as [sign] '0'. Same for `b'. */ if (flags & NDIGITS) { if (p > buf) @@ -428,7 +449,7 @@ return (0); } c = ((u_char *)p)[-1]; - if (c == 'x' || c == 'X') { + if (c == 'x' || c == 'X' || c == 'b' || c == 'B') { --p; (void) __ungetc(c, fp); } @@ -554,6 +575,14 @@ /* * Conversions. */ + case 'B': + case 'b': + flags |= PFXOK; /* enable 0b prefixing */ + c = CT_INT; + flags |= UNSIGNED; + base = 2; + break; + case 'd': c = CT_INT; base = 10; diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -684,6 +684,19 @@ 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*/ diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c --- a/lib/libc/stdio/vfwscanf.c +++ b/lib/libc/stdio/vfwscanf.c @@ -336,13 +336,21 @@ 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': + /* 1 always legal */ + case '1': base = basefix[base]; flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; + /* 2 through 7 ok iff octal, decimal, or hex */ + case '2': case '3': case '4': + case '5': case '6': case '7': + base = basefix[base]; + if (base <= 2) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + /* digits 8 and 9 ok iff decimal or hex */ case '8': case '9': base = basefix[base]; @@ -351,10 +359,23 @@ flags &= ~(SIGNOK | PFXOK | NDIGITS); goto ok; + /* + * b ok iff flag still set & 2nd char (or 3rd char if + * we have a sign). + */ + case 'b': + if (flags & PFXOK && wcp == + buf + 1 + !!(flags & HAVESIGN)) { + base = 2; /* if %i */ + flags &= ~PFXOK; + goto ok; + } + /* FALLTHROUGH */ + /* letters ok iff hex */ - case 'A': case 'B': case 'C': + case 'A': case 'C': case 'D': case 'E': case 'F': - case 'a': case 'b': case 'c': + case 'a': case 'c': case 'd': case 'e': case 'f': /* no need to fix base here */ if (base <= 10) @@ -401,7 +422,7 @@ /* * 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'. + * back the x and treat it as [sign] '0'. Same for `b'. */ if (flags & NDIGITS) { if (wcp > buf) @@ -409,7 +430,7 @@ return (0); } c = wcp[-1]; - if (c == 'x' || c == 'X') { + if (c == 'x' || c == 'X' || c == 'b' || c == 'B') { --wcp; __ungetwc(c, fp, locale); } @@ -536,6 +557,14 @@ /* * Conversions. */ + case 'B': + case 'b': + flags |= PFXOK; /* enable 0b prefixing */ + c = CT_INT; + flags |= UNSIGNED; + base = 2; + break; + case 'd': c = CT_INT; base = 10; diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c --- a/lib/libc/stdlib/strtoimax.c +++ b/lib/libc/stdlib/strtoimax.c @@ -87,6 +87,13 @@ 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; diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c --- a/lib/libc/stdlib/strtol.c +++ b/lib/libc/stdlib/strtol.c @@ -87,6 +87,13 @@ 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; diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c --- a/lib/libc/stdlib/strtoll.c +++ b/lib/libc/stdlib/strtoll.c @@ -63,8 +63,9 @@ /* * 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 @@ 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; diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c --- a/lib/libc/stdlib/strtoul.c +++ b/lib/libc/stdlib/strtoul.c @@ -84,6 +84,13 @@ 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; diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c --- a/lib/libc/stdlib/strtoull.c +++ b/lib/libc/stdlib/strtoull.c @@ -85,6 +85,13 @@ 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; diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c --- a/lib/libc/stdlib/strtoumax.c +++ b/lib/libc/stdlib/strtoumax.c @@ -85,6 +85,13 @@ 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;