mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make fread() more consistent with glibc
This commit is contained in:
parent
1d532ba3f8
commit
8e14b27749
3 changed files with 57 additions and 24 deletions
|
@ -28,21 +28,27 @@
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
|
static ssize_t readvall(FILE *f, struct iovec *iov, int iovlen, size_t need) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
size_t got, toto;
|
size_t got, toto;
|
||||||
toto = 0;
|
for (toto = 0;;) {
|
||||||
do {
|
|
||||||
if ((rc = readv(fd, iov, iovlen)) == -1) {
|
// perform i/o
|
||||||
if (toto) {
|
if ((rc = readv(f->fd, iov, iovlen)) == -1) {
|
||||||
if (errno == EINTR)
|
f->state = errno;
|
||||||
continue;
|
if (toto)
|
||||||
return toto;
|
return toto;
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
got = rc;
|
got = rc;
|
||||||
toto += got;
|
toto += got;
|
||||||
|
if (!got) {
|
||||||
|
f->state = EOF;
|
||||||
|
return toto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// roll forward iov
|
||||||
|
// skip over empty elements
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!iov->iov_len) {
|
if (!iov->iov_len) {
|
||||||
--iovlen;
|
--iovlen;
|
||||||
|
@ -56,9 +62,14 @@ static ssize_t readvall(int fd, struct iovec *iov, int iovlen) {
|
||||||
iov->iov_len -= got;
|
iov->iov_len -= got;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!iovlen)
|
||||||
|
return toto;
|
||||||
}
|
}
|
||||||
} while (got && iovlen);
|
|
||||||
return toto;
|
// don't trigger eof condition if we're rolling greed to fill buffer
|
||||||
|
if (toto >= need)
|
||||||
|
return toto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,27 +145,16 @@ size_t fread_unlocked(void *buf, size_t stride, size_t count, FILE *f) {
|
||||||
iov[1].iov_base = NULL;
|
iov[1].iov_base = NULL;
|
||||||
iov[1].iov_len = 0;
|
iov[1].iov_len = 0;
|
||||||
}
|
}
|
||||||
if (f->bufmode == _IONBF) {
|
rc = readvall(f, iov, 2, need);
|
||||||
rc = readv(f->fd, iov, 2);
|
if (rc == -1)
|
||||||
} else {
|
|
||||||
rc = readvall(f->fd, iov, 2);
|
|
||||||
}
|
|
||||||
if (rc == -1) {
|
|
||||||
f->state = errno;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
got = rc;
|
got = rc;
|
||||||
|
|
||||||
// handle partial fulfillment
|
// handle partial fulfillment
|
||||||
if (got < need) {
|
if (got < need) {
|
||||||
got += m;
|
got += m;
|
||||||
if (got % stride) {
|
|
||||||
f->state = eio();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
f->beg = 0;
|
f->beg = 0;
|
||||||
f->end = 0;
|
f->end = 0;
|
||||||
f->state = EOF;
|
|
||||||
return got / stride;
|
return got / stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,13 @@ void SetUpOnce(void) {
|
||||||
TEST(fputc, test) {
|
TEST(fputc, test) {
|
||||||
ASSERT_NE(NULL, (f = fopen("hog", "w+")));
|
ASSERT_NE(NULL, (f = fopen("hog", "w+")));
|
||||||
EXPECT_EQ('h', fputc('h', f));
|
EXPECT_EQ('h', fputc('h', f));
|
||||||
|
EXPECT_FALSE(feof(f));
|
||||||
EXPECT_EQ(0xFF, fputc(-1, f));
|
EXPECT_EQ(0xFF, fputc(-1, f));
|
||||||
|
EXPECT_FALSE(feof(f));
|
||||||
EXPECT_NE(-1, fseek(f, 0, SEEK_SET));
|
EXPECT_NE(-1, fseek(f, 0, SEEK_SET));
|
||||||
|
EXPECT_FALSE(feof(f));
|
||||||
EXPECT_EQ('h', fgetc(f));
|
EXPECT_EQ('h', fgetc(f));
|
||||||
|
EXPECT_FALSE(feof(f));
|
||||||
EXPECT_EQ(0, fread(NULL, 0, 0, f));
|
EXPECT_EQ(0, fread(NULL, 0, 0, f));
|
||||||
EXPECT_FALSE(feof(f));
|
EXPECT_FALSE(feof(f));
|
||||||
EXPECT_EQ(0xFF, fgetc(f));
|
EXPECT_EQ(0xFF, fgetc(f));
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ TEST(fread, eofIsSticky) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fread, seekWithBuffer) {
|
TEST(fread, seekWithBuffer) {
|
||||||
FILE *f;
|
FILE* f;
|
||||||
char b[8] = "hellosup";
|
char b[8] = "hellosup";
|
||||||
char c[8] = {0};
|
char c[8] = {0};
|
||||||
char d[8] = {0};
|
char d[8] = {0};
|
||||||
|
@ -60,3 +61,31 @@ TEST(fread, seekWithBuffer) {
|
||||||
ASSERT_STREQ("ellos", d);
|
ASSERT_STREQ("ellos", d);
|
||||||
ASSERT_EQ(0, fclose(f));
|
ASSERT_EQ(0, fclose(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(fread, zero) {
|
||||||
|
FILE* f;
|
||||||
|
char buf[8] = {0};
|
||||||
|
ASSERT_NE(NULL, (f = fopen("foo", "w")));
|
||||||
|
ASSERT_EQ(2, fwrite("hi", 1, 2, f));
|
||||||
|
ASSERT_EQ(0, fclose(f));
|
||||||
|
ASSERT_NE(NULL, (f = fopen("foo", "r")));
|
||||||
|
ASSERT_EQ(0, fread(buf, 0, 0, f));
|
||||||
|
ASSERT_EQ(0, ferror(stdin));
|
||||||
|
ASSERT_EQ(0, feof(stdin));
|
||||||
|
ASSERT_STREQ("", buf);
|
||||||
|
ASSERT_EQ(0, fclose(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(fread, partial) {
|
||||||
|
FILE* f;
|
||||||
|
char buf[8] = {0};
|
||||||
|
ASSERT_NE(NULL, (f = fopen("foo", "w")));
|
||||||
|
ASSERT_EQ(2, fwrite("hi", 1, 2, f));
|
||||||
|
ASSERT_EQ(0, fclose(f));
|
||||||
|
ASSERT_NE(NULL, (f = fopen("foo", "r")));
|
||||||
|
ASSERT_EQ(0, fread(buf, 8, 1, f));
|
||||||
|
ASSERT_EQ(0, ferror(stdin));
|
||||||
|
ASSERT_EQ(0, feof(stdin));
|
||||||
|
ASSERT_EQ(0, fclose(f));
|
||||||
|
ASSERT_STREQ("hi", buf);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue