Home > Back-end >  redirected stdin ends prematurely Lua for Windows
redirected stdin ends prematurely Lua for Windows

Time:02-01

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
  • Related