#define liolib_c
#define LUA_LIB
#include "lprefix.h"
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#if !defined(l_checkmode)
#if !defined(L_MODEEXT)
#define L_MODEEXT "b"
#endif
#define l_checkmode(mode) \
(*mode !=
'\0'
&&
strchr
(
"rwa"
, *(mode++)) != NULL && \
(*mode !=
'+'
|| (++mode, 1)) &&
\
(
strspn
(mode, L_MODEEXT) ==
strlen
(mode)))
#endif
#if !defined(l_popen) /* { */
#if defined(LUA_USE_POSIX) /* { */
#define l_popen(L,c,m) (fflush(NULL), popen(c,m))
#define l_pclose(L,file) (pclose(file))
#elif defined(LUA_USE_WINDOWS) /* }{ */
#define l_popen(L,c,m) (_popen(c,m))
#define l_pclose(L,file) (_pclose(file))
#else /* }{ */
#define l_popen(L,c,m) \
((
void
)((
void
)c, m), \
marpa_luaL_error(L,
"'popen' not supported"
), \
(
FILE
*)0)
#define l_pclose(L,file) ((void)L, (void)file, -1)
#endif /* } */
#endif /* } */
#if !defined(l_getc) /* { */
#if defined(LUA_USE_POSIX)
#define l_getc(f) getc_unlocked(f)
#define l_lockfile(f) flockfile(f)
#define l_unlockfile(f) funlockfile(f)
#else
#define l_getc(f) getc(f)
#define l_lockfile(f) ((void)0)
#define l_unlockfile(f) ((void)0)
#endif
#endif /* } */
#if !defined(l_fseek) /* { */
#if defined(LUA_USE_POSIX) /* { */
#include <sys/types.h>
#define l_fseek(f,o,w) fseeko(f,o,w)
#define l_ftell(f) ftello(f)
#define l_seeknum off_t
#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400)
#define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64
#else /* }{ */
#define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f)
#define l_seeknum long
#endif /* } */
#endif /* } */
#define IO_PREFIX "_IO_"
#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1)
#define IO_INPUT (IO_PREFIX "input")
#define IO_OUTPUT (IO_PREFIX "output")
typedef
luaL_Stream LStream;
#define tolstream(L) ((LStream *)marpa_luaL_checkudata(L, 1, LUA_FILEHANDLE))
#define isclosed(p) ((p)->closef == NULL)
static
int
io_type (lua_State *L) {
LStream *p;
marpa_luaL_checkany(L, 1);
p = (LStream *)marpa_luaL_testudata(L, 1, LUA_FILEHANDLE);
if
(p == NULL)
marpa_lua_pushnil(L);
else
if
(isclosed(p))
marpa_lua_pushliteral(L,
"closed file"
);
else
marpa_lua_pushliteral(L,
"file"
);
return
1;
}
static
int
f_tostring (lua_State *L) {
LStream *p = tolstream(L);
if
(isclosed(p))
marpa_lua_pushliteral(L,
"file (closed)"
);
else
marpa_lua_pushfstring(L,
"file (%p)"
, p->f);
return
1;
}
static
FILE
*tofile (lua_State *L) {
LStream *p = tolstream(L);
if
(isclosed(p))
marpa_luaL_error(L,
"attempt to use a closed file"
);
lua_assert(p->f);
return
p->f;
}
static
LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)marpa_lua_newuserdata(L,
sizeof
(LStream));
p->closef = NULL;
marpa_luaL_setmetatable(L, LUA_FILEHANDLE);
return
p;
}
static
int
aux_close (lua_State *L) {
LStream *p = tolstream(L);
volatile
lua_CFunction cf = p->closef;
p->closef = NULL;
return
(*cf)(L);
}
static
int
io_close (lua_State *L) {
if
(marpa_lua_isnone(L, 1))
marpa_lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT);
tofile(L);
return
aux_close(L);
}
static
int
f_gc (lua_State *L) {
LStream *p = tolstream(L);
if
(!isclosed(p) && p->f != NULL)
aux_close(L);
return
0;
}
static
int
io_fclose (lua_State *L) {
LStream *p = tolstream(L);
int
res =
fclose
(p->f);
return
marpa_luaL_fileresult(L, (res == 0), NULL);
}
static
LStream *newfile (lua_State *L) {
LStream *p = newprefile(L);
p->f = NULL;
p->closef = &io_fclose;
return
p;
}
static
void
opencheck (lua_State *L,
const
char
*fname,
const
char
*mode) {
LStream *p = newfile(L);
p->f =
fopen
(fname, mode);
if
(p->f == NULL)
marpa_luaL_error(L,
"cannot open file '%s' (%s)"
, fname,
strerror
(
errno
));
}
static
int
io_open (lua_State *L) {
const
char
*filename = marpa_luaL_checkstring(L, 1);
const
char
*mode = marpa_luaL_optstring(L, 2,
"r"
);
LStream *p = newfile(L);
const
char
*md = mode;
marpa_luaL_argcheck(L, l_checkmode(md), 2,
"invalid mode"
);
p->f =
fopen
(filename, mode);
return
(p->f == NULL) ? marpa_luaL_fileresult(L, 0, filename) : 1;
}
static
int
io_pclose (lua_State *L) {
LStream *p = tolstream(L);
return
marpa_luaL_execresult(L, l_pclose(L, p->f));
}
static
int
io_popen (lua_State *L) {
const
char
*filename = marpa_luaL_checkstring(L, 1);
const
char
*mode = marpa_luaL_optstring(L, 2,
"r"
);
LStream *p = newprefile(L);
p->f = l_popen(L, filename, mode);
p->closef = &io_pclose;
return
(p->f == NULL) ? marpa_luaL_fileresult(L, 0, filename) : 1;
}
static
int
io_tmpfile (lua_State *L) {
LStream *p = newfile(L);
p->f =
tmpfile
();
return
(p->f == NULL) ? marpa_luaL_fileresult(L, 0, NULL) : 1;
}
static
FILE
*getiofile (lua_State *L,
const
char
*findex) {
LStream *p;
marpa_lua_getfield(L, LUA_REGISTRYINDEX, findex);
p = (LStream *)marpa_lua_touserdata(L, -1);
if
(isclosed(p))
marpa_luaL_error(L,
"standard %s file is closed"
, findex + IOPREF_LEN);
return
p->f;
}
static
int
g_iofile (lua_State *L,
const
char
*f,
const
char
*mode) {
if
(!marpa_lua_isnoneornil(L, 1)) {
const
char
*filename = marpa_lua_tostring(L, 1);
if
(filename)
opencheck(L, filename, mode);
else
{
tofile(L);
marpa_lua_pushvalue(L, 1);
}
marpa_lua_setfield(L, LUA_REGISTRYINDEX, f);
}
marpa_lua_getfield(L, LUA_REGISTRYINDEX, f);
return
1;
}
static
int
io_input (lua_State *L) {
return
g_iofile(L, IO_INPUT,
"r"
);
}
static
int
io_output (lua_State *L) {
return
g_iofile(L, IO_OUTPUT,
"w"
);
}
static
int
io_readline (lua_State *L);
#define MAXARGLINE 250
static
void
aux_lines (lua_State *L,
int
toclose) {
int
n = marpa_lua_gettop(L) - 1;
marpa_luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2,
"too many arguments"
);
marpa_lua_pushinteger(L, n);
marpa_lua_pushboolean(L, toclose);
marpa_lua_rotate(L, 2, 2);
marpa_lua_pushcclosure(L, io_readline, 3 + n);
}
static
int
f_lines (lua_State *L) {
tofile(L);
aux_lines(L, 0);
return
1;
}
static
int
io_lines (lua_State *L) {
int
toclose;
if
(marpa_lua_isnone(L, 1)) marpa_lua_pushnil(L);
if
(marpa_lua_isnil(L, 1)) {
marpa_lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT);
marpa_lua_replace(L, 1);
tofile(L);
toclose = 0;
}
else
{
const
char
*filename = marpa_luaL_checkstring(L, 1);
opencheck(L, filename,
"r"
);
marpa_lua_replace(L, 1);
toclose = 1;
}
aux_lines(L, toclose);
return
1;
}
#define MAXRN 200
typedef
struct
{
FILE
*f;
int
c;
int
n;
char
buff[MAXRN + 1];
} RN;
static
int
nextc (RN *rn) {
if
(rn->n >= MAXRN) {
rn->buff[0] =
'\0'
;
return
0;
}
else
{
rn->buff[rn->n++] = rn->c;
rn->c = l_getc(rn->f);
return
1;
}
}
static
int
test2 (RN *rn,
const
char
*set) {
if
(rn->c == set[0] || (rn->c == set[1] && rn->c !=
'\0'
))
return
nextc(rn);
else
return
0;
}
static
int
readdigits (RN *rn,
int
hex) {
int
count = 0;
while
((hex ?
isxdigit
(rn->c) :
isdigit
(rn->c)) && nextc(rn))
count++;
return
count;
}
static
int
read_number (lua_State *L,
FILE
*f) {
RN rn;
int
count = 0;
int
hex = 0;
char
decp[2];
rn.f = f; rn.n = 0;
decp[0] = marpa_lua_getlocaledecpoint();
decp[1] =
'\0'
;
l_lockfile(rn.f);
do
{ rn.c = l_getc(rn.f); }
while
(
isspace
(rn.c));
test2(&rn,
"-+"
);
if
(test2(&rn,
"0"
)) {
if
(test2(&rn,
"xX"
)) hex = 1;
else
count = 1;
}
count += readdigits(&rn, hex);
if
(test2(&rn, decp))
count += readdigits(&rn, hex);
if
(count > 0 && test2(&rn, (hex ?
"pP"
:
"eE"
))) {
test2(&rn,
"-+"
);
readdigits(&rn, 0);
}
ungetc
(rn.c, rn.f);
l_unlockfile(rn.f);
rn.buff[rn.n] =
'\0'
;
if
(marpa_lua_stringtonumber(L, rn.buff))
return
1;
else
{
marpa_lua_pushnil(L);
return
0;
}
}
static
int
test_eof (lua_State *L,
FILE
*f) {
int
c =
getc
(f);
ungetc
(c, f);
marpa_lua_pushliteral(L,
""
);
return
(c != EOF);
}
static
int
read_line (lua_State *L,
FILE
*f,
int
chop) {
luaL_Buffer b;
int
c =
'\0'
;
marpa_luaL_buffinit(L, &b);
while
(c != EOF && c !=
'\n'
) {
char
*buff = marpa_luaL_prepbuffer(&b);
int
i = 0;
l_lockfile(f);
while
(i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c !=
'\n'
)
buff[i++] = c;
l_unlockfile(f);
marpa_luaL_addsize(&b, i);
}
if
(!chop && c ==
'\n'
)
marpa_luaL_addchar(&b, c);
marpa_luaL_pushresult(&b);
return
(c ==
'\n'
|| marpa_lua_rawlen(L, -1) > 0);
}
static
void
read_all (lua_State *L,
FILE
*f) {
size_t
nr;
luaL_Buffer b;
marpa_luaL_buffinit(L, &b);
do
{
char
*p = marpa_luaL_prepbuffer(&b);
nr =
fread
(p,
sizeof
(
char
), LUAL_BUFFERSIZE, f);
marpa_luaL_addsize(&b, nr);
}
while
(nr == LUAL_BUFFERSIZE);
marpa_luaL_pushresult(&b);
}
static
int
read_chars (lua_State *L,
FILE
*f,
size_t
n) {
size_t
nr;
char
*p;
luaL_Buffer b;
marpa_luaL_buffinit(L, &b);
p = marpa_luaL_prepbuffsize(&b, n);
nr =
fread
(p,
sizeof
(
char
), n, f);
marpa_luaL_addsize(&b, nr);
marpa_luaL_pushresult(&b);
return
(nr > 0);
}
static
int
g_read (lua_State *L,
FILE
*f,
int
first) {
int
nargs = marpa_lua_gettop(L) - 1;
int
success;
int
n;
clearerr
(f);
if
(nargs == 0) {
success = read_line(L, f, 1);
n = first+1;
}
else
{
marpa_luaL_checkstack(L, nargs+LUA_MINSTACK,
"too many arguments"
);
success = 1;
for
(n = first; nargs-- && success; n++) {
if
(marpa_lua_type(L, n) == LUA_TNUMBER) {
size_t
l = (
size_t
)marpa_luaL_checkinteger(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
}
else
{
const
char
*p = marpa_luaL_checkstring(L, n);
if
(*p ==
'*'
) p++;
switch
(*p) {
case
'n'
:
success = read_number(L, f);
break
;
case
'l'
:
success = read_line(L, f, 1);
break
;
case
'L'
:
success = read_line(L, f, 0);
break
;
case
'a'
:
read_all(L, f);
success = 1;
break
;
default
:
return
marpa_luaL_argerror(L, n,
"invalid format"
);
}
}
}
}
if
(
ferror
(f))
return
marpa_luaL_fileresult(L, 0, NULL);
if
(!success) {
marpa_lua_pop(L, 1);
marpa_lua_pushnil(L);
}
return
n - first;
}
static
int
io_read (lua_State *L) {
return
g_read(L, getiofile(L, IO_INPUT), 1);
}
static
int
f_read (lua_State *L) {
return
g_read(L, tofile(L), 2);
}
static
int
io_readline (lua_State *L) {
LStream *p = (LStream *)marpa_lua_touserdata(L, marpa_lua_upvalueindex(1));
int
i;
int
n = (
int
)marpa_lua_tointeger(L, marpa_lua_upvalueindex(2));
if
(isclosed(p))
return
marpa_luaL_error(L,
"file is already closed"
);
marpa_lua_settop(L , 1);
marpa_luaL_checkstack(L, n,
"too many arguments"
);
for
(i = 1; i <= n; i++)
marpa_lua_pushvalue(L, marpa_lua_upvalueindex(3 + i));
n = g_read(L, p->f, 2);
lua_assert(n > 0);
if
(marpa_lua_toboolean(L, -n))
return
n;
else
{
if
(n > 1) {
return
marpa_luaL_error(L,
"%s"
, marpa_lua_tostring(L, -n + 1));
}
if
(marpa_lua_toboolean(L, marpa_lua_upvalueindex(3))) {
marpa_lua_settop(L, 0);
marpa_lua_pushvalue(L, marpa_lua_upvalueindex(1));
aux_close(L);
}
return
0;
}
}
static
int
g_write (lua_State *L,
FILE
*f,
int
arg) {
int
nargs = marpa_lua_gettop(L) - arg;
int
status = 1;
for
(; nargs--; arg++) {
if
(marpa_lua_type(L, arg) == LUA_TNUMBER) {
int
len = marpa_lua_isinteger(L, arg)
?
fprintf
(f, LUA_INTEGER_FMT, marpa_lua_tointeger(L, arg))
:
fprintf
(f, LUA_NUMBER_FMT, marpa_lua_tonumber(L, arg));
status = status && (len > 0);
}
else
{
size_t
l;
const
char
*s = marpa_luaL_checklstring(L, arg, &l);
status = status && (
fwrite
(s,
sizeof
(
char
), l, f) == l);
}
}
if
(status)
return
1;
else
return
marpa_luaL_fileresult(L, status, NULL);
}
static
int
io_write (lua_State *L) {
return
g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static
int
f_write (lua_State *L) {
FILE
*f = tofile(L);
marpa_lua_pushvalue(L, 1);
return
g_write(L, f, 2);
}
static
int
f_seek (lua_State *L) {
static
const
int
mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static
const
char
*
const
modenames[] = {
"set"
,
"cur"
,
"end"
, NULL};
FILE
*f = tofile(L);
int
op = marpa_luaL_checkoption(L, 2,
"cur"
, modenames);
lua_Integer p3 = marpa_luaL_optinteger(L, 3, 0);
l_seeknum offset = (l_seeknum)p3;
marpa_luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range"
);
op = l_fseek(f, offset, mode[op]);
if
(op)
return
marpa_luaL_fileresult(L, 0, NULL);
else
{
marpa_lua_pushinteger(L, (lua_Integer)l_ftell(f));
return
1;
}
}
static
int
f_setvbuf (lua_State *L) {
static
const
int
mode[] = {_IONBF, _IOFBF, _IOLBF};
static
const
char
*
const
modenames[] = {
"no"
,
"full"
,
"line"
, NULL};
FILE
*f = tofile(L);
int
op = marpa_luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = marpa_luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int
res =
setvbuf
(f, NULL, mode[op], (
size_t
)sz);
return
marpa_luaL_fileresult(L, res == 0, NULL);
}
static
int
io_flush (lua_State *L) {
return
marpa_luaL_fileresult(L,
fflush
(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static
int
f_flush (lua_State *L) {
return
marpa_luaL_fileresult(L,
fflush
(tofile(L)) == 0, NULL);
}
static
const
luaL_Reg iolib[] = {
{
"close"
, io_close},
{
"flush"
, io_flush},
{
"input"
, io_input},
{
"lines"
, io_lines},
{
"open"
, io_open},
{
"output"
, io_output},
{
"popen"
, io_popen},
{
"read"
, io_read},
{
"tmpfile"
, io_tmpfile},
{
"type"
, io_type},
{
"write"
, io_write},
{NULL, NULL}
};
static
const
luaL_Reg flib[] = {
{
"close"
, io_close},
{
"flush"
, f_flush},
{
"lines"
, f_lines},
{
"read"
, f_read},
{
"seek"
, f_seek},
{
"setvbuf"
, f_setvbuf},
{
"write"
, f_write},
{
"__gc"
, f_gc},
{
"__tostring"
, f_tostring},
{NULL, NULL}
};
static
void
createmeta (lua_State *L) {
marpa_luaL_newmetatable(L, LUA_FILEHANDLE);
marpa_lua_pushvalue(L, -1);
marpa_lua_setfield(L, -2,
"__index"
);
marpa_luaL_setfuncs(L, flib, 0);
marpa_lua_pop(L, 1);
}
static
int
io_noclose (lua_State *L) {
LStream *p = tolstream(L);
p->closef = &io_noclose;
marpa_lua_pushnil(L);
marpa_lua_pushliteral(L,
"cannot close standard file"
);
return
2;
}
static
void
createstdfile (lua_State *L,
FILE
*f,
const
char
*k,
const
char
*fname) {
LStream *p = newprefile(L);
p->f = f;
p->closef = &io_noclose;
if
(k != NULL) {
marpa_lua_pushvalue(L, -1);
marpa_lua_setfield(L, LUA_REGISTRYINDEX, k);
}
marpa_lua_setfield(L, -2, fname);
}
LUAMOD_API
int
marpa_luaopen_io (lua_State *L) {
marpa_luaL_newlib(L, iolib);
createmeta(L);
createstdfile(L, stdin, IO_INPUT,
"stdin"
);
createstdfile(L, stdout, IO_OUTPUT,
"stdout"
);
createstdfile(L, stderr, NULL,
"stderr"
);
return
1;
}