Skip to content

Commit 3f4f280

Browse files
committed
io.write returns number of written bytes on error
1 parent 93e347b commit 3f4f280

File tree

4 files changed

+65
-7
lines changed

4 files changed

+65
-7
lines changed

liolib.c

+11-7
Original file line numberDiff line numberDiff line change
@@ -662,24 +662,28 @@ static int io_readline (lua_State *L) {
662662

663663
static int g_write (lua_State *L, FILE *f, int arg) {
664664
int nargs = lua_gettop(L) - arg;
665-
int status = 1;
665+
size_t totalbytes = 0; /* total number of bytes written */
666666
errno = 0;
667-
for (; nargs--; arg++) {
667+
for (; nargs--; arg++) { /* for each argument */
668668
char buff[LUA_N2SBUFFSZ];
669669
const char *s;
670+
size_t numbytes; /* bytes written in one call to 'fwrite' */
670671
size_t len = lua_numbertocstring(L, arg, buff); /* try as a number */
671672
if (len > 0) { /* did conversion work (value was a number)? */
672673
s = buff;
673674
len--;
674675
}
675676
else /* must be a string */
676677
s = luaL_checklstring(L, arg, &len);
677-
status = status && (fwrite(s, sizeof(char), len, f) == len);
678+
numbytes = fwrite(s, sizeof(char), len, f);
679+
totalbytes += numbytes;
680+
if (numbytes < len) { /* write error? */
681+
int n = luaL_fileresult(L, 0, NULL);
682+
lua_pushinteger(L, cast_st2S(totalbytes));
683+
return n + 1; /* return fail, error msg., error code, and counter */
684+
}
678685
}
679-
if (l_likely(status))
680-
return 1; /* file handle already on stack top */
681-
else
682-
return luaL_fileresult(L, status, NULL);
686+
return 1; /* no errors; file handle already on stack top */
683687
}
684688

685689

ltests.c

+20
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,25 @@ static int coresume (lua_State *L) {
21062106
}
21072107
}
21082108

2109+
#if !defined(LUA_USE_POSIX)
2110+
2111+
#define nonblock NULL
2112+
2113+
#else
2114+
2115+
#include <unistd.h>
2116+
#include <fcntl.h>
2117+
2118+
static int nonblock (lua_State *L) {
2119+
FILE *f = cast(luaL_Stream*, luaL_checkudata(L, 1, LUA_FILEHANDLE))->f;
2120+
int fd = fileno(f);
2121+
int flags = fcntl(fd, F_GETFL, 0);
2122+
flags |= O_NONBLOCK;
2123+
fcntl(fd, F_SETFL, flags);
2124+
return 0;
2125+
}
2126+
#endif
2127+
21092128
/* }====================================================== */
21102129

21112130

@@ -2159,6 +2178,7 @@ static const struct luaL_Reg tests_funcs[] = {
21592178
{"upvalue", upvalue},
21602179
{"externKstr", externKstr},
21612180
{"externstr", externstr},
2181+
{"nonblock", nonblock},
21622182
{NULL, NULL}
21632183
};
21642184

manual/manual.of

+3
Original file line numberDiff line numberDiff line change
@@ -8699,6 +8699,9 @@ Writes the value of each of its arguments to @id{file}.
86998699
The arguments must be strings or numbers.
87008700

87018701
In case of success, this function returns @id{file}.
8702+
Otherwise, it returns four values:
8703+
@fail, the error message, the error code,
8704+
and the number of bytes it was able to write.
87028705

87038706
}
87048707

testes/files.lua

+31
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,37 @@ do
696696
end
697697

698698

699+
if T and T.nonblock then
700+
print("testing failed write")
701+
702+
-- unable to write anything to /dev/full
703+
local f = io.open("/dev/full", "w")
704+
assert(f:setvbuf("no"))
705+
local _, _, err, count = f:write("abcd")
706+
assert(err > 0 and count == 0)
707+
assert(f:close())
708+
709+
-- receiver will read a "few" bytes (enough to empty a large buffer)
710+
local receiver = [[
711+
lua -e 'assert(io.stdin:setvbuf("no")); assert(#io.read(1e4) == 1e4)' ]]
712+
713+
local f = io.popen(receiver, "w")
714+
assert(f:setvbuf("no"))
715+
T.nonblock(f)
716+
717+
-- able to write a few bytes
718+
assert(f:write(string.rep("a", 1e2)))
719+
720+
-- Unable to write more bytes than the pipe buffer supports.
721+
-- (In Linux, the pipe buffer size is 64K (2^16). Posix requires at
722+
-- least 512 bytes.)
723+
local _, _, err, count = f:write("abcd", string.rep("a", 2^17))
724+
assert(err > 0 and count >= 512 and count < 2^17)
725+
726+
assert(f:close())
727+
end
728+
729+
699730
if not _soft then
700731
print("testing large files (> BUFSIZ)")
701732
io.output(file)

0 commit comments

Comments
 (0)