diff options
Diffstat (limited to 'lua/loslib.c')
-rw-r--r-- | lua/loslib.c | 185 |
1 files changed, 125 insertions, 60 deletions
diff --git a/lua/loslib.c b/lua/loslib.c index 052ba17..7dae533 100644 --- a/lua/loslib.c +++ b/lua/loslib.c @@ -1,9 +1,14 @@ /* -** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + #include <errno.h> #include <locale.h> @@ -11,9 +16,6 @@ #include <string.h> #include <time.h> -#define loslib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -21,60 +23,108 @@ /* +** {================================================================== ** list of valid conversion specifiers for the 'strftime' function +** =================================================================== */ -#if !defined(LUA_STRFTIMEOPTIONS) +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ -#if !defined(LUA_USE_POSIX) +#if defined(LUA_USE_C89) #define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } -#else +#else /* C99 specification */ #define LUA_STRFTIMEOPTIONS \ - { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ - "", "E", "cCxXyY", \ + { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ + "E", "cCxXyY", \ "O", "deHImMSuUVwWy" } #endif -#endif - +#endif /* } */ +/* }================================================================== */ /* -** By default, Lua uses tmpnam except when POSIX is available, where it -** uses mkstemp. +** {================================================================== +** Configuration for time-related stuff +** =================================================================== */ -#if defined(LUA_USE_MKSTEMP) -#include <unistd.h> -#define LUA_TMPNAMBUFSIZE 32 -#define lua_tmpnam(b,e) { \ - strcpy(b, "/tmp/lua_XXXXXX"); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } -#elif !defined(lua_tmpnam) +#if !defined(l_time_t) /* { */ +/* +** type to represent time_t in Lua +*/ +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +static time_t l_checktime (lua_State *L, int arg) { + lua_Integer t = luaL_checkinteger(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} -#endif +#endif /* } */ +#if !defined(l_gmtime) /* { */ /* ** By default, Lua uses gmtime/localtime, except when POSIX is available, ** where it uses gmtime_r/localtime_r */ -#if defined(LUA_USE_GMTIME_R) + +#if defined(LUA_USE_POSIX) /* { */ #define l_gmtime(t,r) gmtime_r(t,r) #define l_localtime(t,r) localtime_r(t,r) -#elif !defined(l_gmtime) +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + -#define l_gmtime(t,r) ((void)r, gmtime(t)) -#define l_localtime(t,r) ((void)r, localtime(t)) +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#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 /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + static int os_execute (lua_State *L) { @@ -147,24 +197,35 @@ static void setboolfield (lua_State *L, const char *key, int value) { static int getboolfield (lua_State *L, const char *key) { int res; - lua_getfield(L, -1, key); - res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } -static int getfield (lua_State *L, const char *key, int d) { - int res, isnum; - lua_getfield(L, -1, key); - res = (int)lua_tointegerx(L, -1, &isnum); - if (!isnum) { - if (d < 0) - return luaL_error(L, "field " LUA_QS " missing in date table", key); +/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ +#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 = lua_getfield(L, -1, key); + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not a number? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); res = d; } + else { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' out-of-bounds", key); + res -= delta; + } lua_pop(L, 1); - return res; + return (int)res; } @@ -192,19 +253,23 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { } +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); - s++; /* skip `!' */ + s++; /* skip '!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { + luaL_error(L, "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); @@ -222,14 +287,14 @@ static int os_date (lua_State *L) { cc[0] = '%'; luaL_buffinit(L, &b); while (*s) { - if (*s != '%') /* no conversion specifier? */ + if (*s != '%') /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; - char buff[200]; /* should be big enough for any conversion result */ + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); s = checkoption(L, s + 1, cc); - reslen = strftime(buff, sizeof(buff), cc, stm); - luaL_addlstring(&b, buff, reslen); + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); } } luaL_pushresult(&b); @@ -246,26 +311,26 @@ static int os_time (lua_State *L) { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -1); - ts.tm_mon = getfield(L, "month", -1) - 1; - ts.tm_year = getfield(L, "year", -1) - 1900; + 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)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, (lua_Number)t); + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + luaL_error(L, "time result cannot be represented in this installation"); + l_pushtime(L, t); return 1; } static int os_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); return 1; } @@ -289,7 +354,7 @@ static int os_exit (lua_State *L) { if (lua_isboolean(L, 1)) status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); else - status = luaL_optint(L, 1, EXIT_SUCCESS); + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ |