Skip to content

Commit 88a9e1b

Browse files
committed
printf/scanf now supports octal (%o)
1 parent 7b5081f commit 88a9e1b

3 files changed

Lines changed: 88 additions & 41 deletions

File tree

examples/stdlib.c

Lines changed: 78 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,8 @@ struct iovec
882882
#define WTERMSIG(status) ((status) & 0x7F)
883883
#define WIFSIGNALED(status) (WTERMSIG(status) != 0)
884884
#define WIFEXITED(status) (WTERMSIG(status) == 0)
885+
#define EXIT_SUCCESS 0
886+
#define EXIT_FAILURE 1
885887

886888
typedef size_t socklen_t;
887889
#define AF_UNSPEC 0
@@ -2481,6 +2483,11 @@ static int isxdigit(int c)
24812483
(c >= '0' && c <= '9');
24822484
}
24832485

2486+
static int isodigit(int c)
2487+
{
2488+
return (c >= '0' && c <= '7');
2489+
}
2490+
24842491
static int toupper(int c)
24852492
{
24862493
if (c >= 'a' && c <= 'z')
@@ -3731,18 +3738,19 @@ static long ftell(FILE *stream)
37313738
/* PRINTF */
37323739
/****************************************************************************/
37333740

3734-
#define PRINTF_FLAG_NEG 0x0001
3735-
#define PRINTF_FLAG_UPPER 0x0002
3736-
#define PRINTF_FLAG_HEX 0x0004
3737-
#define PRINTF_FLAG_PLUS 0x0008
3738-
#define PRINTF_FLAG_HASH 0x0010
3739-
#define PRINTF_FLAG_SPACE 0x0020
3740-
#define PRINTF_FLAG_RIGHT 0x0040
3741-
#define PRINTF_FLAG_ZERO 0x0080
3742-
#define PRINTF_FLAG_PRECISION 0x0100
3743-
#define PRINTF_FLAG_8 0x0200
3744-
#define PRINTF_FLAG_16 0x0400
3745-
#define PRINTF_FLAG_64 0x0800
3741+
#define PRINTF_FLAG_NEG 0x0001
3742+
#define PRINTF_FLAG_UPPER 0x0002
3743+
#define PRINTF_FLAG_OCTAL 0x0004
3744+
#define PRINTF_FLAG_HEX 0x0008
3745+
#define PRINTF_FLAG_PLUS 0x0010
3746+
#define PRINTF_FLAG_HASH 0x0020
3747+
#define PRINTF_FLAG_SPACE 0x0040
3748+
#define PRINTF_FLAG_RIGHT 0x0080
3749+
#define PRINTF_FLAG_ZERO 0x0100
3750+
#define PRINTF_FLAG_PRECISION 0x0200
3751+
#define PRINTF_FLAG_8 0x0400
3752+
#define PRINTF_FLAG_16 0x0800
3753+
#define PRINTF_FLAG_64 0x1000
37463754

37473755
static __attribute__((__noinline__)) size_t printf_put_char(char *str,
37483756
size_t size, size_t idx, char c)
@@ -3760,22 +3768,25 @@ static __attribute__((__noinline__)) size_t printf_put_num(char *str,
37603768
char prefix[2] = {'\0', '\0'};
37613769
char buf[32];
37623770
size_t i = 0;
3763-
if (flags & PRINTF_FLAG_HEX)
3771+
bool seen = false;
3772+
if (flags & (PRINTF_FLAG_HEX | PRINTF_FLAG_OCTAL))
37643773
{
37653774
if (flags & PRINTF_FLAG_HASH)
37663775
{
37673776
prefix[0] = '0';
3768-
prefix[1] = (flags & PRINTF_FLAG_UPPER? 'X': 'x');
3777+
if (flags & PRINTF_FLAG_HEX)
3778+
prefix[1] = (flags & PRINTF_FLAG_UPPER? 'X': 'x');
37693779
}
37703780
const char digs[] = "0123456789abcdef";
37713781
const char DIGS[] = "0123456789ABCDEF";
37723782
const char *ds = (flags & PRINTF_FLAG_UPPER? DIGS: digs);
3773-
int shift = (15 * 4);
3774-
bool seen = false;
3783+
int shift = (flags & PRINTF_FLAG_HEX? 60: 63),
3784+
dec = (flags & PRINTF_FLAG_HEX? 4: 3),
3785+
mask = (flags & PRINTF_FLAG_HEX? 0xF: 0x7);
37753786
while (shift >= 0)
37763787
{
3777-
char c = ds[(x >> shift) & 0xF];
3778-
shift -= 4;
3788+
char c = ds[(x >> shift) & mask];
3789+
shift -= dec;
37793790
if (!seen && c == '0')
37803791
continue;
37813792
seen = true;
@@ -3793,7 +3804,6 @@ static __attribute__((__noinline__)) size_t printf_put_num(char *str,
37933804
else if (flags & PRINTF_FLAG_SPACE)
37943805
prefix[0] = ' ';
37953806
unsigned long long r = 10000000000000000000ull;
3796-
bool seen = false;
37973807
while (r != 0)
37983808
{
37993809
char c = '0' + x / r;
@@ -3980,13 +3990,16 @@ static int vsnprintf(char *str, size_t size, const char *format, va_list ap)
39803990
idx = printf_put_num(str, size, idx, flags, width,
39813991
precision, (uint64_t)x);
39823992
break;
3993+
case 'o':
3994+
flags |= PRINTF_FLAG_OCTAL;
3995+
goto uint;
39833996
case 'X':
39843997
flags |= PRINTF_FLAG_UPPER;
39853998
// Fallthrough
39863999
case 'x':
39874000
flags |= PRINTF_FLAG_HEX;
39884001
// Fallthrough
3989-
case 'u':
4002+
case 'u': uint:
39904003
if (flags & PRINTF_FLAG_8)
39914004
y = (uint64_t)(uint8_t)va_arg(ap, unsigned);
39924005
else if (flags & PRINTF_FLAG_16)
@@ -4122,11 +4135,12 @@ static int printf_unlocked(const char *format, ...)
41224135

41234136
#define SCANF_FLAG_NEG 0x0001
41244137
#define SCANF_FLAG_DEC 0x0002
4125-
#define SCANF_FLAG_HEX 0x0004
4126-
#define SCANF_FLAG_8 0x0008
4127-
#define SCANF_FLAG_16 0x0010
4128-
#define SCANF_FLAG_64 0x0020
4129-
#define SCANF_FLAG_SIGNED 0x0040
4138+
#define SCANF_FLAG_OCT 0x0004
4139+
#define SCANF_FLAG_HEX 0x0008
4140+
#define SCANF_FLAG_8 0x0010
4141+
#define SCANF_FLAG_16 0x0020
4142+
#define SCANF_FLAG_64 0x0040
4143+
#define SCANF_FLAG_SIGNED 0x0080
41304144

41314145
struct scanf_stream_s
41324146
{
@@ -4209,6 +4223,30 @@ static __attribute__((__noinline__)) bool scanf_get_dec(
42094223
return true;
42104224
}
42114225

4226+
static __attribute__((__noinline__)) bool scanf_get_oct(
4227+
struct scanf_stream_s *in, size_t *width, uint64_t *p, bool *r)
4228+
{
4229+
char c = scanf_get_char_n(in, width);
4230+
if (!isodigit(c))
4231+
{
4232+
scanf_unget_char_n(c, in, width);
4233+
return false;
4234+
}
4235+
uint64_t i = 0;
4236+
do
4237+
{
4238+
i *= 8;
4239+
uint64_t d = (c - '0');
4240+
if (UINT64_MAX - i < d)
4241+
*r = true;
4242+
i = (UINT64_MAX - i < d? UINT64_MAX: i + d);
4243+
}
4244+
while (isodigit(c = scanf_get_char_n(in, width)));
4245+
scanf_unget_char_n(c, in, width);
4246+
*p = i;
4247+
return true;
4248+
}
4249+
42124250
static __attribute__((__noinline__)) bool scanf_get_hex(
42134251
struct scanf_stream_s *in, size_t *width, uint64_t *p, bool *r)
42144252
{
@@ -4251,24 +4289,22 @@ static __attribute__((__noinline__)) bool scanf_get_num(
42514289
c = scanf_get_char_n(in, &width);
42524290
uint64_t i = 0;
42534291
bool overflow = false;
4254-
if (c == '0' && (flags & SCANF_FLAG_HEX))
4292+
if (c == '0' && (flags & (SCANF_FLAG_OCT | SCANF_FLAG_HEX)))
42554293
{
42564294
c = scanf_get_char_n(in, &width);
4257-
if (c == 'x' || c == 'X')
4295+
if ((flags & SCANF_FLAG_HEX) && (c == 'x' || c == 'X'))
42584296
{
42594297
if (!scanf_get_hex(in, &width, &i, &overflow))
42604298
return false;
42614299
}
4262-
else if (flags & SCANF_FLAG_DEC)
4300+
else if (flags & SCANF_FLAG_OCT)
42634301
{
4264-
c = scanf_get_char_n(in, &width);
4265-
if (!isdigit(c))
4266-
i = 0;
4267-
else if (!scanf_get_dec(in, &width, &i, &overflow))
4302+
scanf_unget_char_n(c, in, &width);
4303+
if (!scanf_get_oct(in, &width, &i, &overflow))
42684304
return false;
42694305
}
42704306
else
4271-
return false;
4307+
scanf_unget_char_n(c, in, &width);
42724308
}
42734309
else if (flags & SCANF_FLAG_DEC)
42744310
{
@@ -4410,7 +4446,8 @@ static int scanf_impl(struct scanf_stream_s *in, const char *format, va_list ap)
44104446
while (isspace(c = scanf_get_char_n(in, &width)))
44114447
;
44124448
*ptr8++ = c;
4413-
while ((c = scanf_get_char_n(in, &width)) != EOF && !isspace(c))
4449+
while ((c = scanf_get_char_n(in, &width)) != EOF &&
4450+
!isspace(c))
44144451
*ptr8++ = c;
44154452
scanf_unget_char_n(c, in, &width);
44164453
*ptr8++ = '\0';
@@ -4425,13 +4462,19 @@ static int scanf_impl(struct scanf_stream_s *in, const char *format, va_list ap)
44254462
if (!scanf_get_num(in, width, flags, ptr))
44264463
return num;
44274464
break;
4465+
case 'o':
4466+
flags |= SCANF_FLAG_OCT;
4467+
if (!scanf_get_num(in, width, flags, ptr))
4468+
return num;
4469+
break;
44284470
case 'x': case 'X':
44294471
flags |= SCANF_FLAG_HEX;
44304472
if (!scanf_get_num(in, width, flags, ptr))
44314473
return num;
44324474
break;
44334475
case 'i':
4434-
flags |= SCANF_FLAG_DEC | SCANF_FLAG_HEX | SCANF_FLAG_SIGNED;
4476+
flags |= SCANF_FLAG_DEC | SCANF_FLAG_OCT | SCANF_FLAG_HEX |
4477+
SCANF_FLAG_SIGNED;
44354478
if (!scanf_get_num(in, width, flags, ptr))
44364479
return num;
44374480
break;

test/regtest/patch.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,9 @@ void test_stdio(intptr_t arg)
897897
FILE *stream = fopen("test.tmp", "w");
898898
if (stream == NULL)
899899
fprintf(stderr, "stream is NULL\n");
900-
int n = fprintf(stream, "%s %10d %zd -%#lx %p\n%u\t%4hu\t \t%c\n", "aaa",
901-
101, arg, arg, (void *)arg, (unsigned)arg, (uint16_t)arg, (char)arg);
900+
int n = fprintf(stream, "%s %10d %zd -%#lx %p\n%u\t%4hu\t \t%c 0%o\n",
901+
"aaa", 101, arg, arg, (void *)arg, (unsigned)arg, (uint16_t)arg,
902+
(char)arg, 0644);
902903
fprintf(stderr, "pos = %zd vs %d\n", ftell(stream), n);
903904
const char HELLO[] = "Hello World!";
904905
int r = fwrite(HELLO, sizeof(char), sizeof(HELLO)-1, stream);
@@ -946,9 +947,10 @@ void test_stdio(intptr_t arg)
946947
unsigned u;
947948
uint16_t h;
948949
char c;
950+
unsigned o;
949951
errno = 0;
950-
r = fscanf(stream, "%d %d\t\r\n%zd %li %p %u %hu %c", &i, &j, &x, &y,
951-
&p, &u, &h, &c);
952+
r = fscanf(stream, "%d %d\t\r\n%zd %li %p %u %hu %c %o", &i, &j, &x, &y,
953+
&p, &u, &h, &c, &o);
952954
fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno));
953955
fprintf(stderr, "r = %d\n", r);
954956
fprintf(stderr, "i = %d\n", i);
@@ -959,6 +961,7 @@ void test_stdio(intptr_t arg)
959961
fprintf(stderr, "u = %u\n", u);
960962
fprintf(stderr, "h = %hu\n", h);
961963
fprintf(stderr, "c = '%c'\n", c);
964+
fprintf(stderr, "o = %#o\n", o);
962965
getc(stream);
963966
char buf1[20] = {0};
964967
r = fread(buf1, sizeof(char), sizeof(buf1), stream);

test/regtest/stdio.exp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
arg = 0x2d9bfa6b1014f832
22
[0]
3-
pos = 94 vs 94
3+
pos = 99 vs 99
44
write = 12
55
getc() = -1
66
[1]
@@ -13,7 +13,7 @@ s = "XbBb"
1313
[2]
1414
c = ' '
1515
errno = 0 (Success)
16-
r = 8
16+
r = 9
1717
i = 7
1818
j = 101
1919
x = 0x2d9bfa6b1014f832
@@ -22,6 +22,7 @@ p = 0x2d9bfa6b1014f832
2222
u = 269809714
2323
h = 63538
2424
c = '2'
25+
o = 0644
2526
read = "Hello World!" (12)
2627
feof() = 1
2728
feof() = 0

0 commit comments

Comments
 (0)