lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


When reading lines from a binary file, functions io.lines(...)
and file:read("*l") can read multiple lines at once and produce
strings that are not contained in the file.

Here is a test case:
  local fname = "temp.tmp"
  local f = io.open(fname, "wb")
  f:write( "H\0orse\nA\0pple\nT\0ree" )
  f:close()
  for l in io.lines(fname) do print(#l, l) end

It prints:
  3	HAT

We can see that only 1 line is detected in the file, and
that the extracted string "HAT" is not present in the file.

It seems that it'd be more reasonable to see:
  6	H
  6	A
  5	T

The modified function read_line (see below) corrects that behavior
due to using memchr rather than strlen. Unfortunately, it seems to
be about 25% slower than the original function.

static int read_line (lua_State *L, FILE *f) {
  luaL_Buffer b;
  luaL_buffinit(L, &b);
  for (;;) {
    char *q, *p = luaL_prepbuffer(&b);
    memset(p, '\n', LUAL_BUFFERSIZE);
    if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
      luaL_pushresult(&b);  /* close buffer */
      return (lua_objlen(L, -1) > 0);  /* check whether read something */
    }
    if (!(q = memchr(p, '\n', LUAL_BUFFERSIZE-1)))
      luaL_addsize(&b, LUAL_BUFFERSIZE-1);
    else if (q[1])
      luaL_addsize(&b, q-p-1);
    else {
      luaL_addsize(&b, q-p);
      luaL_pushresult(&b);  /* close buffer */
      return 1;  /* read at least an `eol' */
    }
  }
}

--
Shmuel