xref: /freebsd/contrib/lua/src/loslib.c (revision a9490b81b032b43cdb3c8c76b4d01bbad9ff82c1)
18e3e3a7aSWarner Losh /*
20495ed39SKyle Evans ** $Id: loslib.c $
38e3e3a7aSWarner Losh ** Standard Operating System library
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh 
78e3e3a7aSWarner Losh #define loslib_c
88e3e3a7aSWarner Losh #define LUA_LIB
98e3e3a7aSWarner Losh 
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh 
128e3e3a7aSWarner Losh 
138e3e3a7aSWarner Losh #include <errno.h>
148e3e3a7aSWarner Losh #include <locale.h>
158e3e3a7aSWarner Losh #include <stdlib.h>
168e3e3a7aSWarner Losh #include <string.h>
178e3e3a7aSWarner Losh #include <time.h>
188e3e3a7aSWarner Losh 
198e3e3a7aSWarner Losh #include "lua.h"
208e3e3a7aSWarner Losh 
218e3e3a7aSWarner Losh #include "lauxlib.h"
228e3e3a7aSWarner Losh #include "lualib.h"
238e3e3a7aSWarner Losh 
248e3e3a7aSWarner Losh 
258e3e3a7aSWarner Losh /*
268e3e3a7aSWarner Losh ** {==================================================================
278e3e3a7aSWarner Losh ** List of valid conversion specifiers for the 'strftime' function;
288e3e3a7aSWarner Losh ** options are grouped by length; group of length 2 start with '||'.
298e3e3a7aSWarner Losh ** ===================================================================
308e3e3a7aSWarner Losh */
318e3e3a7aSWarner Losh #if !defined(LUA_STRFTIMEOPTIONS)	/* { */
328e3e3a7aSWarner Losh 
338e3e3a7aSWarner Losh #if defined(LUA_USE_WINDOWS)
34*a9490b81SWarner Losh #define LUA_STRFTIMEOPTIONS  "aAbBcdHIjmMpSUwWxXyYzZ%" \
35*a9490b81SWarner Losh     "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* two-char options */
36*a9490b81SWarner Losh #elif defined(LUA_USE_C89)  /* ANSI C 89 (only 1-char options) */
37*a9490b81SWarner Losh #define LUA_STRFTIMEOPTIONS  "aAbBcdHIjmMpSUwWxXyYZ%"
388e3e3a7aSWarner Losh #else  /* C99 specification */
39*a9490b81SWarner Losh #define LUA_STRFTIMEOPTIONS  "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
40*a9490b81SWarner Losh     "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* two-char options */
418e3e3a7aSWarner Losh #endif
428e3e3a7aSWarner Losh 
438e3e3a7aSWarner Losh #endif					/* } */
448e3e3a7aSWarner Losh /* }================================================================== */
458e3e3a7aSWarner Losh 
468e3e3a7aSWarner Losh 
478e3e3a7aSWarner Losh /*
488e3e3a7aSWarner Losh ** {==================================================================
498e3e3a7aSWarner Losh ** Configuration for time-related stuff
508e3e3a7aSWarner Losh ** ===================================================================
518e3e3a7aSWarner Losh */
528e3e3a7aSWarner Losh 
538e3e3a7aSWarner Losh /*
548e3e3a7aSWarner Losh ** type to represent time_t in Lua
558e3e3a7aSWarner Losh */
560495ed39SKyle Evans #if !defined(LUA_NUMTIME)	/* { */
570495ed39SKyle Evans 
588e3e3a7aSWarner Losh #define l_timet			lua_Integer
598e3e3a7aSWarner Losh #define l_pushtime(L,t)		lua_pushinteger(L,(lua_Integer)(t))
600495ed39SKyle Evans #define l_gettime(L,arg)	luaL_checkinteger(L, arg)
618e3e3a7aSWarner Losh 
620495ed39SKyle Evans #else				/* }{ */
630495ed39SKyle Evans 
640495ed39SKyle Evans #define l_timet			lua_Number
650495ed39SKyle Evans #define l_pushtime(L,t)		lua_pushnumber(L,(lua_Number)(t))
660495ed39SKyle Evans #define l_gettime(L,arg)	luaL_checknumber(L, arg)
678e3e3a7aSWarner Losh 
688e3e3a7aSWarner Losh #endif				/* } */
698e3e3a7aSWarner Losh 
708e3e3a7aSWarner Losh 
718e3e3a7aSWarner Losh #if !defined(l_gmtime)		/* { */
728e3e3a7aSWarner Losh /*
738e3e3a7aSWarner Losh ** By default, Lua uses gmtime/localtime, except when POSIX is available,
748e3e3a7aSWarner Losh ** where it uses gmtime_r/localtime_r
758e3e3a7aSWarner Losh */
768e3e3a7aSWarner Losh 
778e3e3a7aSWarner Losh #if defined(LUA_USE_POSIX)	/* { */
788e3e3a7aSWarner Losh 
798e3e3a7aSWarner Losh #define l_gmtime(t,r)		gmtime_r(t,r)
808e3e3a7aSWarner Losh #define l_localtime(t,r)	localtime_r(t,r)
818e3e3a7aSWarner Losh 
828e3e3a7aSWarner Losh #else				/* }{ */
838e3e3a7aSWarner Losh 
848e3e3a7aSWarner Losh /* ISO C definitions */
858e3e3a7aSWarner Losh #define l_gmtime(t,r)		((void)(r)->tm_sec, gmtime(t))
868e3e3a7aSWarner Losh #define l_localtime(t,r)	((void)(r)->tm_sec, localtime(t))
878e3e3a7aSWarner Losh 
888e3e3a7aSWarner Losh #endif				/* } */
898e3e3a7aSWarner Losh 
908e3e3a7aSWarner Losh #endif				/* } */
918e3e3a7aSWarner Losh 
928e3e3a7aSWarner Losh /* }================================================================== */
938e3e3a7aSWarner Losh 
948e3e3a7aSWarner Losh 
958e3e3a7aSWarner Losh /*
968e3e3a7aSWarner Losh ** {==================================================================
978e3e3a7aSWarner Losh ** Configuration for 'tmpnam':
988e3e3a7aSWarner Losh ** By default, Lua uses tmpnam except when POSIX is available, where
998e3e3a7aSWarner Losh ** it uses mkstemp.
1008e3e3a7aSWarner Losh ** ===================================================================
1018e3e3a7aSWarner Losh */
1028e3e3a7aSWarner Losh #if !defined(lua_tmpnam)	/* { */
1038e3e3a7aSWarner Losh 
1048e3e3a7aSWarner Losh #if defined(LUA_USE_POSIX)	/* { */
1058e3e3a7aSWarner Losh 
1068e3e3a7aSWarner Losh #include <unistd.h>
1078e3e3a7aSWarner Losh 
1088e3e3a7aSWarner Losh #define LUA_TMPNAMBUFSIZE	32
1098e3e3a7aSWarner Losh 
1108e3e3a7aSWarner Losh #if !defined(LUA_TMPNAMTEMPLATE)
1118e3e3a7aSWarner Losh #define LUA_TMPNAMTEMPLATE	"/tmp/lua_XXXXXX"
1128e3e3a7aSWarner Losh #endif
1138e3e3a7aSWarner Losh 
1148e3e3a7aSWarner Losh #define lua_tmpnam(b,e) { \
1158e3e3a7aSWarner Losh         strcpy(b, LUA_TMPNAMTEMPLATE); \
1168e3e3a7aSWarner Losh         e = mkstemp(b); \
1178e3e3a7aSWarner Losh         if (e != -1) close(e); \
1188e3e3a7aSWarner Losh         e = (e == -1); }
1198e3e3a7aSWarner Losh 
1208e3e3a7aSWarner Losh #else				/* }{ */
1218e3e3a7aSWarner Losh 
1228e3e3a7aSWarner Losh /* ISO C definitions */
1238e3e3a7aSWarner Losh #define LUA_TMPNAMBUFSIZE	L_tmpnam
1248e3e3a7aSWarner Losh #define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }
1258e3e3a7aSWarner Losh 
1268e3e3a7aSWarner Losh #endif				/* } */
1278e3e3a7aSWarner Losh 
1288e3e3a7aSWarner Losh #endif				/* } */
1298e3e3a7aSWarner Losh /* }================================================================== */
1308e3e3a7aSWarner Losh 
1318e3e3a7aSWarner Losh 
132*a9490b81SWarner Losh #if !defined(l_system)
133*a9490b81SWarner Losh #if defined(LUA_USE_IOS)
134*a9490b81SWarner Losh /* Despite claiming to be ISO C, iOS does not implement 'system'. */
135*a9490b81SWarner Losh #define l_system(cmd) ((cmd) == NULL ? 0 : -1)
136*a9490b81SWarner Losh #else
137*a9490b81SWarner Losh #define l_system(cmd)	system(cmd)  /* default definition */
138*a9490b81SWarner Losh #endif
139*a9490b81SWarner Losh #endif
140*a9490b81SWarner Losh 
1418e3e3a7aSWarner Losh 
os_execute(lua_State * L)1428e3e3a7aSWarner Losh static int os_execute (lua_State *L) {
1438e3e3a7aSWarner Losh   const char *cmd = luaL_optstring(L, 1, NULL);
1440495ed39SKyle Evans   int stat;
1450495ed39SKyle Evans   errno = 0;
146*a9490b81SWarner Losh   stat = l_system(cmd);
1478e3e3a7aSWarner Losh   if (cmd != NULL)
1488e3e3a7aSWarner Losh     return luaL_execresult(L, stat);
1498e3e3a7aSWarner Losh   else {
1508e3e3a7aSWarner Losh     lua_pushboolean(L, stat);  /* true if there is a shell */
1518e3e3a7aSWarner Losh     return 1;
1528e3e3a7aSWarner Losh   }
1538e3e3a7aSWarner Losh }
1548e3e3a7aSWarner Losh 
1558e3e3a7aSWarner Losh 
os_remove(lua_State * L)1568e3e3a7aSWarner Losh static int os_remove (lua_State *L) {
1578e3e3a7aSWarner Losh   const char *filename = luaL_checkstring(L, 1);
1588e3e3a7aSWarner Losh   return luaL_fileresult(L, remove(filename) == 0, filename);
1598e3e3a7aSWarner Losh }
1608e3e3a7aSWarner Losh 
1618e3e3a7aSWarner Losh 
os_rename(lua_State * L)1628e3e3a7aSWarner Losh static int os_rename (lua_State *L) {
1638e3e3a7aSWarner Losh   const char *fromname = luaL_checkstring(L, 1);
1648e3e3a7aSWarner Losh   const char *toname = luaL_checkstring(L, 2);
1658e3e3a7aSWarner Losh   return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
1668e3e3a7aSWarner Losh }
1678e3e3a7aSWarner Losh 
1688e3e3a7aSWarner Losh 
os_tmpname(lua_State * L)1698e3e3a7aSWarner Losh static int os_tmpname (lua_State *L) {
1708e3e3a7aSWarner Losh   char buff[LUA_TMPNAMBUFSIZE];
1718e3e3a7aSWarner Losh   int err;
1728e3e3a7aSWarner Losh   lua_tmpnam(buff, err);
1738c784bb8SWarner Losh   if (l_unlikely(err))
1748e3e3a7aSWarner Losh     return luaL_error(L, "unable to generate a unique filename");
1758e3e3a7aSWarner Losh   lua_pushstring(L, buff);
1768e3e3a7aSWarner Losh   return 1;
1778e3e3a7aSWarner Losh }
1788e3e3a7aSWarner Losh 
1798e3e3a7aSWarner Losh 
os_getenv(lua_State * L)1808e3e3a7aSWarner Losh static int os_getenv (lua_State *L) {
1818e3e3a7aSWarner Losh   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
1828e3e3a7aSWarner Losh   return 1;
1838e3e3a7aSWarner Losh }
1848e3e3a7aSWarner Losh 
1858e3e3a7aSWarner Losh 
os_clock(lua_State * L)1868e3e3a7aSWarner Losh static int os_clock (lua_State *L) {
1878e3e3a7aSWarner Losh   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
1888e3e3a7aSWarner Losh   return 1;
1898e3e3a7aSWarner Losh }
1908e3e3a7aSWarner Losh 
1918e3e3a7aSWarner Losh 
1928e3e3a7aSWarner Losh /*
1938e3e3a7aSWarner Losh ** {======================================================
1948e3e3a7aSWarner Losh ** Time/Date operations
1958e3e3a7aSWarner Losh ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
1968e3e3a7aSWarner Losh **   wday=%w+1, yday=%j, isdst=? }
1978e3e3a7aSWarner Losh ** =======================================================
1988e3e3a7aSWarner Losh */
1998e3e3a7aSWarner Losh 
2000495ed39SKyle Evans /*
2010495ed39SKyle Evans ** About the overflow check: an overflow cannot occur when time
2020495ed39SKyle Evans ** is represented by a lua_Integer, because either lua_Integer is
2030495ed39SKyle Evans ** large enough to represent all int fields or it is not large enough
2040495ed39SKyle Evans ** to represent a time that cause a field to overflow.  However, if
2050495ed39SKyle Evans ** times are represented as doubles and lua_Integer is int, then the
2060495ed39SKyle Evans ** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900
2070495ed39SKyle Evans ** to compute the year.
2080495ed39SKyle Evans */
setfield(lua_State * L,const char * key,int value,int delta)2090495ed39SKyle Evans static void setfield (lua_State *L, const char *key, int value, int delta) {
2100495ed39SKyle Evans   #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
2118c784bb8SWarner Losh     if (l_unlikely(value > LUA_MAXINTEGER - delta))
2120495ed39SKyle Evans       luaL_error(L, "field '%s' is out-of-bound", key);
2130495ed39SKyle Evans   #endif
2140495ed39SKyle Evans   lua_pushinteger(L, (lua_Integer)value + delta);
2158e3e3a7aSWarner Losh   lua_setfield(L, -2, key);
2168e3e3a7aSWarner Losh }
2178e3e3a7aSWarner Losh 
2180495ed39SKyle Evans 
setboolfield(lua_State * L,const char * key,int value)2198e3e3a7aSWarner Losh static void setboolfield (lua_State *L, const char *key, int value) {
2208e3e3a7aSWarner Losh   if (value < 0)  /* undefined? */
2218e3e3a7aSWarner Losh     return;  /* does not set field */
2228e3e3a7aSWarner Losh   lua_pushboolean(L, value);
2238e3e3a7aSWarner Losh   lua_setfield(L, -2, key);
2248e3e3a7aSWarner Losh }
2258e3e3a7aSWarner Losh 
2268e3e3a7aSWarner Losh 
2278e3e3a7aSWarner Losh /*
2288e3e3a7aSWarner Losh ** Set all fields from structure 'tm' in the table on top of the stack
2298e3e3a7aSWarner Losh */
setallfields(lua_State * L,struct tm * stm)2308e3e3a7aSWarner Losh static void setallfields (lua_State *L, struct tm *stm) {
2310495ed39SKyle Evans   setfield(L, "year", stm->tm_year, 1900);
2320495ed39SKyle Evans   setfield(L, "month", stm->tm_mon, 1);
2330495ed39SKyle Evans   setfield(L, "day", stm->tm_mday, 0);
2340495ed39SKyle Evans   setfield(L, "hour", stm->tm_hour, 0);
2350495ed39SKyle Evans   setfield(L, "min", stm->tm_min, 0);
2360495ed39SKyle Evans   setfield(L, "sec", stm->tm_sec, 0);
2370495ed39SKyle Evans   setfield(L, "yday", stm->tm_yday, 1);
2380495ed39SKyle Evans   setfield(L, "wday", stm->tm_wday, 1);
2398e3e3a7aSWarner Losh   setboolfield(L, "isdst", stm->tm_isdst);
2408e3e3a7aSWarner Losh }
2418e3e3a7aSWarner Losh 
2428e3e3a7aSWarner Losh 
getboolfield(lua_State * L,const char * key)2438e3e3a7aSWarner Losh static int getboolfield (lua_State *L, const char *key) {
2448e3e3a7aSWarner Losh   int res;
2458e3e3a7aSWarner Losh   res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
2468e3e3a7aSWarner Losh   lua_pop(L, 1);
2478e3e3a7aSWarner Losh   return res;
2488e3e3a7aSWarner Losh }
2498e3e3a7aSWarner Losh 
2508e3e3a7aSWarner Losh 
getfield(lua_State * L,const char * key,int d,int delta)2518e3e3a7aSWarner Losh static int getfield (lua_State *L, const char *key, int d, int delta) {
2528e3e3a7aSWarner Losh   int isnum;
2538e3e3a7aSWarner Losh   int t = lua_getfield(L, -1, key);  /* get field and its type */
2548e3e3a7aSWarner Losh   lua_Integer res = lua_tointegerx(L, -1, &isnum);
2558e3e3a7aSWarner Losh   if (!isnum) {  /* field is not an integer? */
2568c784bb8SWarner Losh     if (l_unlikely(t != LUA_TNIL))  /* some other value? */
2578e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' is not an integer", key);
2588c784bb8SWarner Losh     else if (l_unlikely(d < 0))  /* absent field; no default? */
2598e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' missing in date table", key);
2608e3e3a7aSWarner Losh     res = d;
2618e3e3a7aSWarner Losh   }
2628e3e3a7aSWarner Losh   else {
263*a9490b81SWarner Losh     if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
2648e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' is out-of-bound", key);
2658e3e3a7aSWarner Losh     res -= delta;
2668e3e3a7aSWarner Losh   }
2678e3e3a7aSWarner Losh   lua_pop(L, 1);
2688e3e3a7aSWarner Losh   return (int)res;
2698e3e3a7aSWarner Losh }
2708e3e3a7aSWarner Losh 
2718e3e3a7aSWarner Losh 
checkoption(lua_State * L,const char * conv,ptrdiff_t convlen,char * buff)2728e3e3a7aSWarner Losh static const char *checkoption (lua_State *L, const char *conv,
2738e3e3a7aSWarner Losh                                 ptrdiff_t convlen, char *buff) {
2748e3e3a7aSWarner Losh   const char *option = LUA_STRFTIMEOPTIONS;
2758e3e3a7aSWarner Losh   int oplen = 1;  /* length of options being checked */
2768e3e3a7aSWarner Losh   for (; *option != '\0' && oplen <= convlen; option += oplen) {
2778e3e3a7aSWarner Losh     if (*option == '|')  /* next block? */
2788e3e3a7aSWarner Losh       oplen++;  /* will check options with next length (+1) */
2798e3e3a7aSWarner Losh     else if (memcmp(conv, option, oplen) == 0) {  /* match? */
2808e3e3a7aSWarner Losh       memcpy(buff, conv, oplen);  /* copy valid option to buffer */
2818e3e3a7aSWarner Losh       buff[oplen] = '\0';
2828e3e3a7aSWarner Losh       return conv + oplen;  /* return next item */
2838e3e3a7aSWarner Losh     }
2848e3e3a7aSWarner Losh   }
2858e3e3a7aSWarner Losh   luaL_argerror(L, 1,
2868e3e3a7aSWarner Losh     lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
2878e3e3a7aSWarner Losh   return conv;  /* to avoid warnings */
2888e3e3a7aSWarner Losh }
2898e3e3a7aSWarner Losh 
2908e3e3a7aSWarner Losh 
l_checktime(lua_State * L,int arg)2910495ed39SKyle Evans static time_t l_checktime (lua_State *L, int arg) {
2920495ed39SKyle Evans   l_timet t = l_gettime(L, arg);
2930495ed39SKyle Evans   luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
2940495ed39SKyle Evans   return (time_t)t;
2950495ed39SKyle Evans }
2960495ed39SKyle Evans 
2970495ed39SKyle Evans 
2988e3e3a7aSWarner Losh /* maximum size for an individual 'strftime' item */
2998e3e3a7aSWarner Losh #define SIZETIMEFMT	250
3008e3e3a7aSWarner Losh 
3018e3e3a7aSWarner Losh 
os_date(lua_State * L)3028e3e3a7aSWarner Losh static int os_date (lua_State *L) {
3038e3e3a7aSWarner Losh   size_t slen;
3048e3e3a7aSWarner Losh   const char *s = luaL_optlstring(L, 1, "%c", &slen);
3058e3e3a7aSWarner Losh   time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
3068e3e3a7aSWarner Losh   const char *se = s + slen;  /* 's' end */
3078e3e3a7aSWarner Losh   struct tm tmr, *stm;
3088e3e3a7aSWarner Losh   if (*s == '!') {  /* UTC? */
3098e3e3a7aSWarner Losh     stm = l_gmtime(&t, &tmr);
3108e3e3a7aSWarner Losh     s++;  /* skip '!' */
3118e3e3a7aSWarner Losh   }
3128e3e3a7aSWarner Losh   else
3138e3e3a7aSWarner Losh     stm = l_localtime(&t, &tmr);
3148e3e3a7aSWarner Losh   if (stm == NULL)  /* invalid date? */
315e112e9d2SKyle Evans     return luaL_error(L,
3160495ed39SKyle Evans                  "date result cannot be represented in this installation");
3178e3e3a7aSWarner Losh   if (strcmp(s, "*t") == 0) {
3188e3e3a7aSWarner Losh     lua_createtable(L, 0, 9);  /* 9 = number of fields */
3198e3e3a7aSWarner Losh     setallfields(L, stm);
3208e3e3a7aSWarner Losh   }
3218e3e3a7aSWarner Losh   else {
3228e3e3a7aSWarner Losh     char cc[4];  /* buffer for individual conversion specifiers */
3238e3e3a7aSWarner Losh     luaL_Buffer b;
3248e3e3a7aSWarner Losh     cc[0] = '%';
3258e3e3a7aSWarner Losh     luaL_buffinit(L, &b);
3268e3e3a7aSWarner Losh     while (s < se) {
3278e3e3a7aSWarner Losh       if (*s != '%')  /* not a conversion specifier? */
3288e3e3a7aSWarner Losh         luaL_addchar(&b, *s++);
3298e3e3a7aSWarner Losh       else {
3308e3e3a7aSWarner Losh         size_t reslen;
3318e3e3a7aSWarner Losh         char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
3328e3e3a7aSWarner Losh         s++;  /* skip '%' */
3338e3e3a7aSWarner Losh         s = checkoption(L, s, se - s, cc + 1);  /* copy specifier to 'cc' */
3348e3e3a7aSWarner Losh         reslen = strftime(buff, SIZETIMEFMT, cc, stm);
3358e3e3a7aSWarner Losh         luaL_addsize(&b, reslen);
3368e3e3a7aSWarner Losh       }
3378e3e3a7aSWarner Losh     }
3388e3e3a7aSWarner Losh     luaL_pushresult(&b);
3398e3e3a7aSWarner Losh   }
3408e3e3a7aSWarner Losh   return 1;
3418e3e3a7aSWarner Losh }
3428e3e3a7aSWarner Losh 
3438e3e3a7aSWarner Losh 
os_time(lua_State * L)3448e3e3a7aSWarner Losh static int os_time (lua_State *L) {
3458e3e3a7aSWarner Losh   time_t t;
3468e3e3a7aSWarner Losh   if (lua_isnoneornil(L, 1))  /* called without args? */
3478e3e3a7aSWarner Losh     t = time(NULL);  /* get current time */
3488e3e3a7aSWarner Losh   else {
3498e3e3a7aSWarner Losh     struct tm ts;
3508e3e3a7aSWarner Losh     luaL_checktype(L, 1, LUA_TTABLE);
3518e3e3a7aSWarner Losh     lua_settop(L, 1);  /* make sure table is at the top */
3528e3e3a7aSWarner Losh     ts.tm_year = getfield(L, "year", -1, 1900);
3530495ed39SKyle Evans     ts.tm_mon = getfield(L, "month", -1, 1);
3540495ed39SKyle Evans     ts.tm_mday = getfield(L, "day", -1, 0);
3550495ed39SKyle Evans     ts.tm_hour = getfield(L, "hour", 12, 0);
3560495ed39SKyle Evans     ts.tm_min = getfield(L, "min", 0, 0);
3570495ed39SKyle Evans     ts.tm_sec = getfield(L, "sec", 0, 0);
3588e3e3a7aSWarner Losh     ts.tm_isdst = getboolfield(L, "isdst");
3598e3e3a7aSWarner Losh     t = mktime(&ts);
3608e3e3a7aSWarner Losh     setallfields(L, &ts);  /* update fields with normalized values */
3618e3e3a7aSWarner Losh   }
3628e3e3a7aSWarner Losh   if (t != (time_t)(l_timet)t || t == (time_t)(-1))
363e112e9d2SKyle Evans     return luaL_error(L,
364e112e9d2SKyle Evans                   "time result cannot be represented in this installation");
3658e3e3a7aSWarner Losh   l_pushtime(L, t);
3668e3e3a7aSWarner Losh   return 1;
3678e3e3a7aSWarner Losh }
3688e3e3a7aSWarner Losh 
3698e3e3a7aSWarner Losh 
os_difftime(lua_State * L)3708e3e3a7aSWarner Losh static int os_difftime (lua_State *L) {
3718e3e3a7aSWarner Losh   time_t t1 = l_checktime(L, 1);
3728e3e3a7aSWarner Losh   time_t t2 = l_checktime(L, 2);
3738e3e3a7aSWarner Losh   lua_pushnumber(L, (lua_Number)difftime(t1, t2));
3748e3e3a7aSWarner Losh   return 1;
3758e3e3a7aSWarner Losh }
3768e3e3a7aSWarner Losh 
3778e3e3a7aSWarner Losh /* }====================================================== */
3788e3e3a7aSWarner Losh 
3798e3e3a7aSWarner Losh 
os_setlocale(lua_State * L)3808e3e3a7aSWarner Losh static int os_setlocale (lua_State *L) {
3818e3e3a7aSWarner Losh   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
3828e3e3a7aSWarner Losh                       LC_NUMERIC, LC_TIME};
3838e3e3a7aSWarner Losh   static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
3848e3e3a7aSWarner Losh      "numeric", "time", NULL};
3858e3e3a7aSWarner Losh   const char *l = luaL_optstring(L, 1, NULL);
3868e3e3a7aSWarner Losh   int op = luaL_checkoption(L, 2, "all", catnames);
3878e3e3a7aSWarner Losh   lua_pushstring(L, setlocale(cat[op], l));
3888e3e3a7aSWarner Losh   return 1;
3898e3e3a7aSWarner Losh }
3908e3e3a7aSWarner Losh 
3918e3e3a7aSWarner Losh 
os_exit(lua_State * L)3928e3e3a7aSWarner Losh static int os_exit (lua_State *L) {
3938e3e3a7aSWarner Losh   int status;
3948e3e3a7aSWarner Losh   if (lua_isboolean(L, 1))
3958e3e3a7aSWarner Losh     status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
3968e3e3a7aSWarner Losh   else
3978e3e3a7aSWarner Losh     status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
3988e3e3a7aSWarner Losh   if (lua_toboolean(L, 2))
3998e3e3a7aSWarner Losh     lua_close(L);
4008e3e3a7aSWarner Losh   if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */
4018e3e3a7aSWarner Losh   return 0;
4028e3e3a7aSWarner Losh }
4038e3e3a7aSWarner Losh 
4048e3e3a7aSWarner Losh 
4058e3e3a7aSWarner Losh static const luaL_Reg syslib[] = {
4068e3e3a7aSWarner Losh   {"clock",     os_clock},
4078e3e3a7aSWarner Losh   {"date",      os_date},
4088e3e3a7aSWarner Losh   {"difftime",  os_difftime},
4098e3e3a7aSWarner Losh   {"execute",   os_execute},
4108e3e3a7aSWarner Losh   {"exit",      os_exit},
4118e3e3a7aSWarner Losh   {"getenv",    os_getenv},
4128e3e3a7aSWarner Losh   {"remove",    os_remove},
4138e3e3a7aSWarner Losh   {"rename",    os_rename},
4148e3e3a7aSWarner Losh   {"setlocale", os_setlocale},
4158e3e3a7aSWarner Losh   {"time",      os_time},
4168e3e3a7aSWarner Losh   {"tmpname",   os_tmpname},
4178e3e3a7aSWarner Losh   {NULL, NULL}
4188e3e3a7aSWarner Losh };
4198e3e3a7aSWarner Losh 
4208e3e3a7aSWarner Losh /* }====================================================== */
4218e3e3a7aSWarner Losh 
4228e3e3a7aSWarner Losh 
4238e3e3a7aSWarner Losh 
luaopen_os(lua_State * L)4248e3e3a7aSWarner Losh LUAMOD_API int luaopen_os (lua_State *L) {
4258e3e3a7aSWarner Losh   luaL_newlib(L, syslib);
4268e3e3a7aSWarner Losh   return 1;
4278e3e3a7aSWarner Losh }
4288e3e3a7aSWarner Losh 
429