Skip to content

Commit 18e005d

Browse files
authored
Merge pull request #169 from DrXiao/fix-libc
Ensure correctness of formatted output conversion
2 parents 861d7d2 + b310322 commit 18e005d

File tree

4 files changed

+184
-76
lines changed

4 files changed

+184
-76
lines changed

lib/c.c

+61-74
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,31 @@ void __str_base10(char *pb, int val)
166166

167167
void __str_base8(char *pb, int val)
168168
{
169-
int c = INT_BUF_LEN - 1;
170-
while (c > 0) {
171-
int v = val & 0x7;
169+
int c = INT_BUF_LEN - 1, v;
170+
/*
171+
* Because every 3 binary digits can be converted
172+
* to 1 octal digit, here performs the conversion
173+
* 10 times, derived from 32 divided by 3.
174+
*
175+
* Finally, the remaining 2 bits are processed after
176+
* the loop.
177+
* */
178+
int times = (sizeof(int) << 3) / 3;
179+
for (int i = 0; i < times; i++) {
180+
v = val & 0x7;
172181
pb[c] = '0' + v;
173182
val = val >> 3;
174183
c--;
175184
}
185+
v = val & 0x3;
186+
pb[c] = '0' + v;
176187
}
177188

178189
void __str_base16(char *pb, int val)
179190
{
180191
int c = INT_BUF_LEN - 1;
181-
while (c > 0) {
192+
int times = sizeof(int) << 1;
193+
for (int i = 0; i < times; i++) {
182194
int v = val & 0xf;
183195
if (v < 10)
184196
pb[c] = '0' + v;
@@ -202,37 +214,13 @@ int __format(char *buffer,
202214
{
203215
int bi = 0;
204216
char pb[INT_BUF_LEN];
205-
int pbi = 0;
206-
207-
if (alternate_form == 1) {
208-
switch (base) {
209-
case 8:
210-
/* octal */
211-
buffer[0] = '0';
212-
bi = 1;
213-
width -= 1;
214-
break;
215-
case 16:
216-
/* hex */
217-
buffer[0] = '0';
218-
buffer[1] = 'x';
219-
bi = 2;
220-
width -= 2;
221-
break;
222-
default:
223-
/* decimal */
224-
/* do nothing */
225-
break;
226-
}
227-
if (width < 0)
228-
width = 0;
229-
}
217+
int pbi;
230218

231219
/* set to zeroes */
232-
while (pbi < INT_BUF_LEN) {
220+
for (pbi = 0; pbi < INT_BUF_LEN; pbi++)
233221
pb[pbi] = '0';
234-
pbi++;
235-
}
222+
223+
pbi = 0;
236224

237225
switch (base) {
238226
case 8:
@@ -249,53 +237,52 @@ int __format(char *buffer,
249237
break;
250238
}
251239

252-
while (width > INT_BUF_LEN) {
253-
/* need to add extra padding */
254-
if (zeropad == 1)
255-
buffer[bi] = '0';
256-
else
257-
buffer[bi] = ' ';
258-
bi++;
259-
width--;
260-
}
240+
while (pb[pbi] == '0' && pbi < INT_BUF_LEN - 1)
241+
pbi++;
261242

262-
/* no padding */
263-
if (width == 0) {
264-
int c = 0;
265-
int started = 0;
266-
267-
/* output from first digit */
268-
while (c < INT_BUF_LEN) {
269-
if (pb[c] != '0')
270-
started = 1;
271-
if (started) {
272-
buffer[bi] = pb[c];
273-
bi++;
274-
}
275-
c++;
243+
switch (base) {
244+
case 8:
245+
if (alternate_form) {
246+
if (width && zeropad && pb[pbi] != '0') {
247+
buffer[bi++] = '0';
248+
width -= 1;
249+
} else if (pb[pbi] != '0')
250+
pb[--pbi] = '0';
276251
}
277-
/* special case - zero */
278-
if (started == 0) {
279-
buffer[bi] = '0';
280-
bi++;
252+
break;
253+
case 10:
254+
if (width && zeropad && pb[pbi] == '-') {
255+
buffer[bi++] = '-';
256+
pbi++;
257+
width--;
281258
}
282-
} else {
283-
/* padding */
284-
int c = INT_BUF_LEN - width;
285-
int started = 0;
286-
while (c < INT_BUF_LEN) {
287-
if (pb[c] != '0')
288-
started = 1;
289-
if (started)
290-
buffer[bi] = pb[c];
291-
else if (zeropad == 1)
292-
buffer[bi] = '0';
293-
else
294-
buffer[bi] = ' ';
295-
bi++;
296-
c++;
259+
break;
260+
case 16:
261+
if (alternate_form) {
262+
if (width && zeropad && pb[pbi] != '0') {
263+
buffer[bi++] = '0';
264+
buffer[bi++] = 'x';
265+
width -= 2;
266+
} else if (pb[pbi] != '0') {
267+
pb[--pbi] = 'x';
268+
pb[--pbi] = '0';
269+
}
297270
}
271+
break;
298272
}
273+
274+
width -= (INT_BUF_LEN - pbi);
275+
if (width < 0)
276+
width = 0;
277+
278+
while (width) {
279+
buffer[bi++] = zeropad ? '0' : ' ';
280+
width--;
281+
}
282+
283+
for (; pbi < INT_BUF_LEN; pbi++)
284+
buffer[bi++] = pb[pbi];
285+
299286
return bi;
300287
}
301288

tests/driver.sh

+121
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,127 @@ int main() {
630630
}
631631
EOF
632632

633+
fmt_ans="0x0000000000000000000000ff00cde1
634+
0xff00cde1
635+
000000000000000000000000ff00cde1
636+
ff00cde1
637+
0xff00cde1
638+
ff00cde1
639+
0x00ff00cde1
640+
0xff00cde1
641+
0000ff00cde1
642+
ff00cde1
643+
00000000000000000000037700146741
644+
037700146741
645+
00000000000000000000037700146741
646+
37700146741
647+
037700146741
648+
37700146741
649+
037700146741
650+
037700146741
651+
037700146741
652+
37700146741
653+
-0000000000000000000000016724511
654+
-16724511
655+
-16724511
656+
-00016724511
657+
-16724511
658+
0x0000000000000000000000fffff204
659+
0xfffff204
660+
000000000000000000000000fffff204
661+
fffff204
662+
0xfffff204
663+
fffff204
664+
0x00fffff204
665+
0xfffff204
666+
0000fffff204
667+
fffff204
668+
00000000000000000000037777771004
669+
037777771004
670+
00000000000000000000037777771004
671+
37777771004
672+
037777771004
673+
37777771004
674+
037777771004
675+
037777771004
676+
037777771004
677+
37777771004
678+
-0000000000000000000000000003580
679+
-3580
680+
-3580
681+
-00000003580
682+
-3580
683+
0x00000000000000000000000001000c
684+
0x1000c
685+
0000000000000000000000000001000c
686+
1000c
687+
0x1000c
688+
1000c
689+
0x000001000c
690+
0x1000c
691+
00000001000c
692+
1000c
693+
00000000000000000000000000200014
694+
0200014
695+
00000000000000000000000000200014
696+
200014
697+
0200014
698+
200014
699+
000000200014
700+
0200014
701+
000000200014
702+
200014
703+
00000000000000000000000000065548
704+
65548
705+
65548
706+
000000065548
707+
65548
708+
00000000000000000000000000000000
709+
0
710+
00000000000000000000000000000000
711+
0
712+
0
713+
0
714+
000000000000
715+
0
716+
000000000000
717+
0
718+
00000000000000000000000000000000
719+
0
720+
00000000000000000000000000000000
721+
0
722+
0
723+
0
724+
000000000000
725+
0
726+
000000000000
727+
0
728+
00000000000000000000000000000000
729+
0
730+
0
731+
000000000000
732+
0"
733+
734+
try_output 0 "$fmt_ans" << EOF
735+
void printf_conversion(int num) {
736+
printf("%#032x\n%#32x\n%032x\n%32x\n%#x\n%x\n", num, num, num, num, num, num);
737+
printf("%#012x\n%#12x\n%012x\n%12x\n", num, num, num, num);
738+
printf("%#032o\n%#32o\n%032o\n%32o\n%#o\n%o\n", num, num, num, num, num, num);
739+
printf("%#012o\n%#12o\n%012o\n%12o\n", num, num, num, num);
740+
printf("%032d\n%32d\n%d\n", num, num, num);
741+
printf("%012d\n%12d\n", num, num);
742+
}
743+
744+
int main() {
745+
int a = 0xFF00CDE1, b = 0xFFFFF204, c = 65548, d = 0;
746+
printf_conversion(a);
747+
printf_conversion(b);
748+
printf_conversion(c);
749+
printf_conversion(d);
750+
return 0;
751+
}
752+
EOF
753+
633754
try_ 0 << EOF
634755
int main() {
635756
return '\0';

tests/snapshots/fib.json

+1-1
Large diffs are not rendered by default.

tests/snapshots/hello.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)