aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--liolib.c18
-rw-r--r--ltests.c20
-rw-r--r--manual/manual.of3
-rw-r--r--testes/files.lua31
4 files changed, 65 insertions, 7 deletions
diff --git a/liolib.c b/liolib.c
index a0988db0..3225ed5f 100644
--- a/liolib.c
+++ b/liolib.c
@@ -662,11 +662,12 @@ static int io_readline (lua_State *L) {
662 662
663static int g_write (lua_State *L, FILE *f, int arg) { 663static int g_write (lua_State *L, FILE *f, int arg) {
664 int nargs = lua_gettop(L) - arg; 664 int nargs = lua_gettop(L) - arg;
665 int status = 1; 665 size_t totalbytes = 0; /* total number of bytes written */
666 errno = 0; 666 errno = 0;
667 for (; nargs--; arg++) { 667 for (; nargs--; arg++) { /* for each argument */
668 char buff[LUA_N2SBUFFSZ]; 668 char buff[LUA_N2SBUFFSZ];
669 const char *s; 669 const char *s;
670 size_t numbytes; /* bytes written in one call to 'fwrite' */
670 size_t len = lua_numbertocstring(L, arg, buff); /* try as a number */ 671 size_t len = lua_numbertocstring(L, arg, buff); /* try as a number */
671 if (len > 0) { /* did conversion work (value was a number)? */ 672 if (len > 0) { /* did conversion work (value was a number)? */
672 s = buff; 673 s = buff;
@@ -674,12 +675,15 @@ static int g_write (lua_State *L, FILE *f, int arg) {
674 } 675 }
675 else /* must be a string */ 676 else /* must be a string */
676 s = luaL_checklstring(L, arg, &len); 677 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 }
678 } 685 }
679 if (l_likely(status)) 686 return 1; /* no errors; file handle already on stack top */
680 return 1; /* file handle already on stack top */
681 else
682 return luaL_fileresult(L, status, NULL);
683} 687}
684 688
685 689
diff --git a/ltests.c b/ltests.c
index 6a638d05..1517aa88 100644
--- a/ltests.c
+++ b/ltests.c
@@ -2106,6 +2106,25 @@ static int coresume (lua_State *L) {
2106 } 2106 }
2107} 2107}
2108 2108
2109#if !defined(LUA_USE_POSIX)
2110
2111#define nonblock NULL
2112
2113#else
2114
2115#include <unistd.h>
2116#include <fcntl.h>
2117
2118static 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
2109/* }====================================================== */ 2128/* }====================================================== */
2110 2129
2111 2130
@@ -2159,6 +2178,7 @@ static const struct luaL_Reg tests_funcs[] = {
2159 {"upvalue", upvalue}, 2178 {"upvalue", upvalue},
2160 {"externKstr", externKstr}, 2179 {"externKstr", externKstr},
2161 {"externstr", externstr}, 2180 {"externstr", externstr},
2181 {"nonblock", nonblock},
2162 {NULL, NULL} 2182 {NULL, NULL}
2163}; 2183};
2164 2184
diff --git a/manual/manual.of b/manual/manual.of
index c1a9c138..7cd0d4db 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -8699,6 +8699,9 @@ Writes the value of each of its arguments to @id{file}.
8699The arguments must be strings or numbers. 8699The arguments must be strings or numbers.
8700 8700
8701In case of success, this function returns @id{file}. 8701In case of success, this function returns @id{file}.
8702Otherwise, it returns four values:
8703@fail, the error message, the error code,
8704and the number of bytes it was able to write.
8702 8705
8703} 8706}
8704 8707
diff --git a/testes/files.lua b/testes/files.lua
index 05fae49b..2c802047 100644
--- a/testes/files.lua
+++ b/testes/files.lua
@@ -696,6 +696,37 @@ do
696end 696end
697 697
698 698
699if 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())
727end
728
729
699if not _soft then 730if not _soft then
700 print("testing large files (> BUFSIZ)") 731 print("testing large files (> BUFSIZ)")
701 io.output(file) 732 io.output(file)