I'm using Lua in a cmd window under Windows. I use "cat" (from UnxUtils) to feed a file to a Lua script. The script uses "io.read(1)" to read one byte at a time.
local b, n ;
n = -1 ;
b = true ;
while b do
n = n 1 ;
b = io.read(1) ;
end ;
print( n, "bytes read" ) ;
When I feed the script a 333K .EXE file, it claims "24025 bytes read". Feed the same .EXE to "wc" (another UnxUtils), and wc correctly says 333008.
> cat "Firefox Installer.exe" | lua count.lua
24025 bytes read
cat: write error: Invalid argument
> cat "Firefox Installer.exe" | wc
1408 8674 333008
Since I get the expected answer when I "cat | wc", I don't think there's anything wrong with the "cat" program, or with Windows' implementation of redirection.
I am not looking for advice on how to make the Lua script more efficient. I do not need advice on how to make the script read directly from a file (that works as expected). I am looking for a clue as to where to look for the reason I can't use Lua to write a filter (and be able to trust the results).
I have looked at the input file to see if a Ctrl-Z or Ctrl-D was the reason for the early shut-off -- they occur very early in the file.
I tried reading after "io.read()" returned "false": the script admitted to seeing more bytes, but still no more than 45K of the 333K input file.
CodePudding user response:
Copied from my comments:
Likely to be a Windows issue (see e.g. this answer). Windows treats binary and text "streams" / files differently. I would assume that your program's stdin is a text stream by default; it isn't possible to change the mode of stdin to binary later on using plain Lua, you'll need a library for that. Something like lfs = require("lfs"); lfs.setmode(io.stdin, "binary")
might work (using the LuaFileSystem library).
You could also try to fix your script invocation to set the correct mode using a script which changes stdin
to binary mode before invoking your Lua script:
./stdbin.c
:
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
int main(int argc, char** argv) {
if (argc < 1) {
printf("Arguments: <program> {args}\n");
return 1;
}
// See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?redirectedfrom=MSDN&view=msvc-170
if (_setmode(_fileno(stdin), _O_BINARY) == -1)
perror("_setmode failed");
execvp("lua", argv);
// execvp only returns if there is an error
perror("execvp failed");
return 1;
}
Note: Untested. Usage: ./stdbin lua count.lua
.
CodePudding user response:
(This is an addition to LMD's answer)
In LuaJIT no external libraries and executables are needed:
local ffi = require"ffi"
ffi.cdef"int _setmode(int,int)"
ffi.C._setmode(0, 0x8000)
-- Now io.read() will return binary data