Skip to content

Commit d91d9ca

Browse files
committed
Support %n in scanf
* Support `ftell` for memfile * Keep file caches if `fseek` is called for current position
1 parent 7b311bd commit d91d9ca

6 files changed

Lines changed: 43 additions & 11 deletions

File tree

libsrc/stdio/_file.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,17 @@ int _fflush(FILE *fp) {
112112
return 0;
113113
}
114114

115-
int _fseek(void *cookie, off_t *offset, int origin) {
115+
int _fseek(void *cookie, off_t *poffset, int origin) {
116116
FILE *fp = cookie;
117-
off_t result = lseek(fp->fd, *offset, origin);
117+
off_t offset = *poffset;
118+
off_t result = lseek(fp->fd, offset, origin);
118119
if (result == -1)
119120
return -1;
120-
fp->flag &= ~FF_EOF;
121-
fp->rp = fp->rs = 0;
122-
fp->unget_char = EOF;
123-
*offset = result;
121+
if (offset != 0 || origin != SEEK_CUR) {
122+
fp->flag &= ~FF_EOF;
123+
fp->rp = fp->rs = 0;
124+
fp->unget_char = EOF;
125+
}
126+
*poffset = result;
124127
return 0;
125128
}

libsrc/stdio/fmemopen.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ static int _memseek(void *cookie, off_t *offset, int origin) {
7676
fp->wp = fp->wcapa + *offset;
7777
break;
7878
}
79-
fp->unget_char = EOF;
79+
if (fp->unget_char != EOF) {
80+
if (fp->wp > 0)
81+
--fp->wp;
82+
fp->unget_char = EOF;
83+
}
84+
*offset = 0;
8085
return 0;
8186
}
8287

libsrc/stdio/ftell.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#include "stdio.h"
2-
#include "unistd.h" // read
32

43
#include "./_file.h"
54

65
long ftell(FILE *fp) {
7-
off_t result = lseek(fp->fd, 0, SEEK_CUR);
8-
return result >= 0 ? result + fp->wp - (fp->rs - fp->rp) : result;
6+
off_t o = 0;
7+
ssize_t result = (fp->iof->seek)(fp, &o, SEEK_CUR);
8+
if (result >= 0) {
9+
result = o + fp->wp - (fp->rs - fp->rp);
10+
}
11+
return result;
912
}

libsrc/stdio/vfscanf.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ int vfscanf(FILE *restrict fp, const char *restrict format, va_list ap) {
206206
VaList va;
207207
va_copy(va.ap, ap);
208208
for (const unsigned char *p = (unsigned char*)format; (c = *p) != '\0'; ++p) {
209-
if ((c == '%' && p[1] != '%') || isspace(c)) {
209+
if ((c == '%' && (p[1] != '%' && p[1] != 'n')) || isspace(c)) {
210210
int c2;
211211
while (c2 = fgetc(fp), isspace(c2))
212212
;
@@ -271,6 +271,19 @@ int vfscanf(FILE *restrict fp, const char *restrict format, va_list ap) {
271271
continue;
272272
}
273273
break;
274+
case 'n':
275+
{
276+
long pos = ftell(fp);
277+
if (pos == -1) {
278+
// error
279+
} else {
280+
int *p = va_arg(va.ap, int*);
281+
*p = pos;
282+
// No need to increment the `count`.
283+
continue;
284+
}
285+
}
286+
break;
274287
default: // Unsupported.
275288
break;
276289
}

libsrc/tests/printf_test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@ TEST(fmemopen) {
4545
fp = fmemopen(buf, sizeof(buf), "w");
4646
if (EXPECT_NOT_NULL(fp)) {
4747
EXPECT_EQ(sizeof(str), fwrite(str, 1, sizeof(str), fp));
48+
EXPECT_EQ(sizeof(str), ftell(fp));
4849
fclose(fp);
4950
}
5051

5152
fp = fmemopen((void*)str, sizeof(str), "r");
5253
if (EXPECT_NOT_NULL(fp)) {
5354
EXPECT_EQ(sizeof(str), fread(buf, 1, sizeof(buf), fp));
55+
EXPECT_EQ(sizeof(str), ftell(fp));
5456
fclose(fp);
5557
EXPECT_EQ(0, memcmp(buf, str, sizeof(str)));
5658
}

libsrc/tests/scanf_test.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ TEST(sscanf) {
6060
int result = sscanf("auto-whiltespaces: \t\n 333", "auto-whiltespaces:%d", &i);
6161
EXPECT_TRUE(result == 1 && i == 333);
6262
}
63+
64+
{
65+
int i = -1, n = -1;
66+
int result = sscanf("pos: 123 ", "pos: %d%n", &i, &n);
67+
EXPECT_TRUE(result == 1 && i == 123 && n == 8);
68+
}
6369
}
6470

6571
XTEST_MAIN();

0 commit comments

Comments
 (0)