#define loslib_c
#define LUA_LIB
#include "lprefix.h"
#include <errno.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \
{
"aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%"
,
""
, \
"E"
,
"cCxXyY"
, \
"O"
,
"deHImMSuUVwWy"
}
#endif
#endif /* } */
#if !defined(l_time_t) /* { */
#define l_timet lua_Integer
#define l_pushtime(L,t) marpa_lua_pushinteger(L,(lua_Integer)(t))
static
time_t
l_checktime (lua_State *L,
int
arg) {
lua_Integer t = marpa_luaL_checkinteger(L, arg);
marpa_luaL_argcheck(L, (
time_t
)t == t, arg,
"time out-of-bounds"
);
return
(
time_t
)t;
}
#endif /* } */
#if !defined(l_gmtime) /* { */
#if defined(LUA_USE_POSIX) /* { */
#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)
#else /* }{ */
#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
#endif /* } */
#endif /* } */
#if !defined(lua_tmpnam) /* { */
#if defined(LUA_USE_POSIX) /* { */
#include <unistd.h>
#define LUA_TMPNAMBUFSIZE 32
#if !defined(LUA_TMPNAMTEMPLATE)
#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX"
#endif
#define lua_tmpnam(b,e) { \
strcpy
(b, LUA_TMPNAMTEMPLATE); \
e = mkstemp(b); \
if
(e != -1) close(e); \
e = (e == -1); }
#else /* }{ */
#define LUA_TMPNAMBUFSIZE L_tmpnam
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
#endif /* } */
#endif /* } */
static
int
os_execute (lua_State *L) {
const
char
*cmd = marpa_luaL_optstring(L, 1, NULL);
int
stat =
system
(cmd);
if
(cmd != NULL)
return
marpa_luaL_execresult(L, stat);
else
{
marpa_lua_pushboolean(L, stat);
return
1;
}
}
static
int
os_remove (lua_State *L) {
const
char
*filename = marpa_luaL_checkstring(L, 1);
return
marpa_luaL_fileresult(L,
remove
(filename) == 0, filename);
}
static
int
os_rename (lua_State *L) {
const
char
*fromname = marpa_luaL_checkstring(L, 1);
const
char
*toname = marpa_luaL_checkstring(L, 2);
return
marpa_luaL_fileresult(L,
rename
(fromname, toname) == 0, NULL);
}
static
int
os_tmpname (lua_State *L) {
char
buff[LUA_TMPNAMBUFSIZE];
int
err;
lua_tmpnam(buff, err);
if
(err)
return
marpa_luaL_error(L,
"unable to generate a unique filename"
);
marpa_lua_pushstring(L, buff);
return
1;
}
static
int
os_getenv (lua_State *L) {
marpa_lua_pushstring(L,
getenv
(marpa_luaL_checkstring(L, 1)));
return
1;
}
static
int
os_clock (lua_State *L) {
marpa_lua_pushnumber(L, ((lua_Number)
clock
())/(lua_Number)CLOCKS_PER_SEC);
return
1;
}
static
void
setfield (lua_State *L,
const
char
*key,
int
value) {
marpa_lua_pushinteger(L, value);
marpa_lua_setfield(L, -2, key);
}
static
void
setboolfield (lua_State *L,
const
char
*key,
int
value) {
if
(value < 0)
return
;
marpa_lua_pushboolean(L, value);
marpa_lua_setfield(L, -2, key);
}
static
int
getboolfield (lua_State *L,
const
char
*key) {
int
res;
res = (marpa_lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : marpa_lua_toboolean(L, -1);
marpa_lua_pop(L, 1);
return
res;
}
#if !defined(L_MAXDATEFIELD)
#define L_MAXDATEFIELD (INT_MAX / 2)
#endif
static
int
getfield (lua_State *L,
const
char
*key,
int
d,
int
delta) {
int
isnum;
int
t = marpa_lua_getfield(L, -1, key);
lua_Integer res = marpa_lua_tointegerx(L, -1, &isnum);
if
(!isnum) {
if
(t != LUA_TNIL)
return
marpa_luaL_error(L,
"field '%s' not an integer"
, key);
else
if
(d < 0)
return
marpa_luaL_error(L,
"field '%s' missing in date table"
, key);
res = d;
}
else
{
if
(!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return
marpa_luaL_error(L,
"field '%s' out-of-bounds"
, key);
res -= delta;
}
marpa_lua_pop(L, 1);
return
(
int
)res;
}
static
const
char
*checkoption (lua_State *L,
const
char
*conv,
char
*buff) {
static
const
char
*
const
options[] = LUA_STRFTIMEOPTIONS;
unsigned
int
i;
for
(i = 0; i <
sizeof
(options)/
sizeof
(options[0]); i += 2) {
if
(*conv !=
'\0'
&&
strchr
(options[i], *conv) != NULL) {
buff[1] = *conv;
if
(*options[i + 1] ==
'\0'
) {
buff[2] =
'\0'
;
return
conv + 1;
}
else
if
(*(conv + 1) !=
'\0'
&&
strchr
(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1);
buff[3] =
'\0'
;
return
conv + 2;
}
}
}
marpa_luaL_argerror(L, 1,
marpa_lua_pushfstring(L,
"invalid conversion specifier '%%%s'"
, conv));
return
conv;
}
#define SIZETIMEFMT 250
static
int
os_date (lua_State *L) {
const
char
*s = marpa_luaL_optstring(L, 1,
"%c"
);
time_t
t = marpa_luaL_opt(L, l_checktime, 2,
time
(NULL));
struct
tm
tmr, *stm;
if
(*s ==
'!'
) {
stm = l_gmtime(&t, &tmr);
s++;
}
else
stm = l_localtime(&t, &tmr);
if
(stm == NULL)
marpa_luaL_error(L,
"time result cannot be represented in this installation"
);
if
(
strcmp
(s,
"*t"
) == 0) {
marpa_lua_createtable(L, 0, 9);
setfield(L,
"sec"
, stm->tm_sec);
setfield(L,
"min"
, stm->tm_min);
setfield(L,
"hour"
, stm->tm_hour);
setfield(L,
"day"
, stm->tm_mday);
setfield(L,
"month"
, stm->tm_mon+1);
setfield(L,
"year"
, stm->tm_year+1900);
setfield(L,
"wday"
, stm->tm_wday+1);
setfield(L,
"yday"
, stm->tm_yday+1);
setboolfield(L,
"isdst"
, stm->tm_isdst);
}
else
{
char
cc[4];
luaL_Buffer b;
cc[0] =
'%'
;
marpa_luaL_buffinit(L, &b);
while
(*s) {
if
(*s !=
'%'
)
marpa_luaL_addchar(&b, *s++);
else
{
size_t
reslen;
char
*buff = marpa_luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc);
reslen =
strftime
(buff, SIZETIMEFMT, cc, stm);
marpa_luaL_addsize(&b, reslen);
}
}
marpa_luaL_pushresult(&b);
}
return
1;
}
static
int
os_time (lua_State *L) {
time_t
t;
if
(marpa_lua_isnoneornil(L, 1))
t =
time
(NULL);
else
{
struct
tm
ts;
marpa_luaL_checktype(L, 1, LUA_TTABLE);
marpa_lua_settop(L, 1);
ts.tm_sec = getfield(L,
"sec"
, 0, 0);
ts.tm_min = getfield(L,
"min"
, 0, 0);
ts.tm_hour = getfield(L,
"hour"
, 12, 0);
ts.tm_mday = getfield(L,
"day"
, -1, 0);
ts.tm_mon = getfield(L,
"month"
, -1, 1);
ts.tm_year = getfield(L,
"year"
, -1, 1900);
ts.tm_isdst = getboolfield(L,
"isdst"
);
t =
mktime
(&ts);
}
if
(t != (
time_t
)(l_timet)t || t == (
time_t
)(-1))
marpa_luaL_error(L,
"time result cannot be represented in this installation"
);
l_pushtime(L, t);
return
1;
}
static
int
os_difftime (lua_State *L) {
time_t
t1 = l_checktime(L, 1);
time_t
t2 = l_checktime(L, 2);
marpa_lua_pushnumber(L, (lua_Number)
difftime
(t1, t2));
return
1;
}
static
int
os_setlocale (lua_State *L) {
static
const
int
cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
LC_NUMERIC, LC_TIME};
static
const
char
*
const
catnames[] = {
"all"
,
"collate"
,
"ctype"
,
"monetary"
,
"numeric"
,
"time"
, NULL};
const
char
*l = marpa_luaL_optstring(L, 1, NULL);
int
op = marpa_luaL_checkoption(L, 2,
"all"
, catnames);
marpa_lua_pushstring(L,
setlocale
(cat[op], l));
return
1;
}
static
int
os_exit (lua_State *L) {
int
status;
if
(marpa_lua_isboolean(L, 1))
status = (marpa_lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
else
status = (
int
)marpa_luaL_optinteger(L, 1, EXIT_SUCCESS);
if
(marpa_lua_toboolean(L, 2))
marpa_lua_close(L);
if
(L)
exit
(status);
return
0;
}
static
const
luaL_Reg syslib[] = {
{
"clock"
, os_clock},
{
"date"
, os_date},
{
"difftime"
, os_difftime},
{
"execute"
, os_execute},
{
"exit"
, os_exit},
{
"getenv"
, os_getenv},
{
"remove"
, os_remove},
{
"rename"
, os_rename},
{
"setlocale"
, os_setlocale},
{
"time"
, os_time},
{
"tmpname"
, os_tmpname},
{NULL, NULL}
};
LUAMOD_API
int
marpa_luaopen_os (lua_State *L) {
marpa_luaL_newlib(L, syslib);
return
1;
}