xref: /freebsd-src/contrib/lua/src/loslib.c (revision e112e9d255e25e8377d107841b263eefab2f13a0)
18e3e3a7aSWarner Losh /*
2*e112e9d2SKyle Evans ** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $
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 /* options for ANSI C 89 (only 1-char options) */
348e3e3a7aSWarner Losh #define L_STRFTIMEC89		"aAbBcdHIjmMpSUwWxXyYZ%"
358e3e3a7aSWarner Losh 
368e3e3a7aSWarner Losh /* options for ISO C 99 and POSIX */
378e3e3a7aSWarner Losh #define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
388e3e3a7aSWarner Losh     "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* two-char options */
398e3e3a7aSWarner Losh 
408e3e3a7aSWarner Losh /* options for Windows */
418e3e3a7aSWarner Losh #define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
428e3e3a7aSWarner Losh     "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* two-char options */
438e3e3a7aSWarner Losh 
448e3e3a7aSWarner Losh #if defined(LUA_USE_WINDOWS)
458e3e3a7aSWarner Losh #define LUA_STRFTIMEOPTIONS	L_STRFTIMEWIN
468e3e3a7aSWarner Losh #elif defined(LUA_USE_C89)
478e3e3a7aSWarner Losh #define LUA_STRFTIMEOPTIONS	L_STRFTIMEC89
488e3e3a7aSWarner Losh #else  /* C99 specification */
498e3e3a7aSWarner Losh #define LUA_STRFTIMEOPTIONS	L_STRFTIMEC99
508e3e3a7aSWarner Losh #endif
518e3e3a7aSWarner Losh 
528e3e3a7aSWarner Losh #endif					/* } */
538e3e3a7aSWarner Losh /* }================================================================== */
548e3e3a7aSWarner Losh 
558e3e3a7aSWarner Losh 
568e3e3a7aSWarner Losh /*
578e3e3a7aSWarner Losh ** {==================================================================
588e3e3a7aSWarner Losh ** Configuration for time-related stuff
598e3e3a7aSWarner Losh ** ===================================================================
608e3e3a7aSWarner Losh */
618e3e3a7aSWarner Losh 
628e3e3a7aSWarner Losh #if !defined(l_time_t)		/* { */
638e3e3a7aSWarner Losh /*
648e3e3a7aSWarner Losh ** type to represent time_t in Lua
658e3e3a7aSWarner Losh */
668e3e3a7aSWarner Losh #define l_timet			lua_Integer
678e3e3a7aSWarner Losh #define l_pushtime(L,t)		lua_pushinteger(L,(lua_Integer)(t))
688e3e3a7aSWarner Losh 
698e3e3a7aSWarner Losh static time_t l_checktime (lua_State *L, int arg) {
708e3e3a7aSWarner Losh   lua_Integer t = luaL_checkinteger(L, arg);
718e3e3a7aSWarner Losh   luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
728e3e3a7aSWarner Losh   return (time_t)t;
738e3e3a7aSWarner Losh }
748e3e3a7aSWarner Losh 
758e3e3a7aSWarner Losh #endif				/* } */
768e3e3a7aSWarner Losh 
778e3e3a7aSWarner Losh 
788e3e3a7aSWarner Losh #if !defined(l_gmtime)		/* { */
798e3e3a7aSWarner Losh /*
808e3e3a7aSWarner Losh ** By default, Lua uses gmtime/localtime, except when POSIX is available,
818e3e3a7aSWarner Losh ** where it uses gmtime_r/localtime_r
828e3e3a7aSWarner Losh */
838e3e3a7aSWarner Losh 
848e3e3a7aSWarner Losh #if defined(LUA_USE_POSIX)	/* { */
858e3e3a7aSWarner Losh 
868e3e3a7aSWarner Losh #define l_gmtime(t,r)		gmtime_r(t,r)
878e3e3a7aSWarner Losh #define l_localtime(t,r)	localtime_r(t,r)
888e3e3a7aSWarner Losh 
898e3e3a7aSWarner Losh #else				/* }{ */
908e3e3a7aSWarner Losh 
918e3e3a7aSWarner Losh /* ISO C definitions */
928e3e3a7aSWarner Losh #define l_gmtime(t,r)		((void)(r)->tm_sec, gmtime(t))
938e3e3a7aSWarner Losh #define l_localtime(t,r)  	((void)(r)->tm_sec, localtime(t))
948e3e3a7aSWarner Losh 
958e3e3a7aSWarner Losh #endif				/* } */
968e3e3a7aSWarner Losh 
978e3e3a7aSWarner Losh #endif				/* } */
988e3e3a7aSWarner Losh 
998e3e3a7aSWarner Losh /* }================================================================== */
1008e3e3a7aSWarner Losh 
1018e3e3a7aSWarner Losh 
1028e3e3a7aSWarner Losh /*
1038e3e3a7aSWarner Losh ** {==================================================================
1048e3e3a7aSWarner Losh ** Configuration for 'tmpnam':
1058e3e3a7aSWarner Losh ** By default, Lua uses tmpnam except when POSIX is available, where
1068e3e3a7aSWarner Losh ** it uses mkstemp.
1078e3e3a7aSWarner Losh ** ===================================================================
1088e3e3a7aSWarner Losh */
1098e3e3a7aSWarner Losh #if !defined(lua_tmpnam)	/* { */
1108e3e3a7aSWarner Losh 
1118e3e3a7aSWarner Losh #if defined(LUA_USE_POSIX)	/* { */
1128e3e3a7aSWarner Losh 
1138e3e3a7aSWarner Losh #include <unistd.h>
1148e3e3a7aSWarner Losh 
1158e3e3a7aSWarner Losh #define LUA_TMPNAMBUFSIZE	32
1168e3e3a7aSWarner Losh 
1178e3e3a7aSWarner Losh #if !defined(LUA_TMPNAMTEMPLATE)
1188e3e3a7aSWarner Losh #define LUA_TMPNAMTEMPLATE	"/tmp/lua_XXXXXX"
1198e3e3a7aSWarner Losh #endif
1208e3e3a7aSWarner Losh 
1218e3e3a7aSWarner Losh #define lua_tmpnam(b,e) { \
1228e3e3a7aSWarner Losh         strcpy(b, LUA_TMPNAMTEMPLATE); \
1238e3e3a7aSWarner Losh         e = mkstemp(b); \
1248e3e3a7aSWarner Losh         if (e != -1) close(e); \
1258e3e3a7aSWarner Losh         e = (e == -1); }
1268e3e3a7aSWarner Losh 
1278e3e3a7aSWarner Losh #else				/* }{ */
1288e3e3a7aSWarner Losh 
1298e3e3a7aSWarner Losh /* ISO C definitions */
1308e3e3a7aSWarner Losh #define LUA_TMPNAMBUFSIZE	L_tmpnam
1318e3e3a7aSWarner Losh #define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }
1328e3e3a7aSWarner Losh 
1338e3e3a7aSWarner Losh #endif				/* } */
1348e3e3a7aSWarner Losh 
1358e3e3a7aSWarner Losh #endif				/* } */
1368e3e3a7aSWarner Losh /* }================================================================== */
1378e3e3a7aSWarner Losh 
1388e3e3a7aSWarner Losh 
1398e3e3a7aSWarner Losh 
1408e3e3a7aSWarner Losh 
1418e3e3a7aSWarner Losh static int os_execute (lua_State *L) {
1428e3e3a7aSWarner Losh   const char *cmd = luaL_optstring(L, 1, NULL);
1438e3e3a7aSWarner Losh   int stat = system(cmd);
1448e3e3a7aSWarner Losh   if (cmd != NULL)
1458e3e3a7aSWarner Losh     return luaL_execresult(L, stat);
1468e3e3a7aSWarner Losh   else {
1478e3e3a7aSWarner Losh     lua_pushboolean(L, stat);  /* true if there is a shell */
1488e3e3a7aSWarner Losh     return 1;
1498e3e3a7aSWarner Losh   }
1508e3e3a7aSWarner Losh }
1518e3e3a7aSWarner Losh 
1528e3e3a7aSWarner Losh 
1538e3e3a7aSWarner Losh static int os_remove (lua_State *L) {
1548e3e3a7aSWarner Losh   const char *filename = luaL_checkstring(L, 1);
1558e3e3a7aSWarner Losh   return luaL_fileresult(L, remove(filename) == 0, filename);
1568e3e3a7aSWarner Losh }
1578e3e3a7aSWarner Losh 
1588e3e3a7aSWarner Losh 
1598e3e3a7aSWarner Losh static int os_rename (lua_State *L) {
1608e3e3a7aSWarner Losh   const char *fromname = luaL_checkstring(L, 1);
1618e3e3a7aSWarner Losh   const char *toname = luaL_checkstring(L, 2);
1628e3e3a7aSWarner Losh   return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
1638e3e3a7aSWarner Losh }
1648e3e3a7aSWarner Losh 
1658e3e3a7aSWarner Losh 
1668e3e3a7aSWarner Losh static int os_tmpname (lua_State *L) {
1678e3e3a7aSWarner Losh   char buff[LUA_TMPNAMBUFSIZE];
1688e3e3a7aSWarner Losh   int err;
1698e3e3a7aSWarner Losh   lua_tmpnam(buff, err);
1708e3e3a7aSWarner Losh   if (err)
1718e3e3a7aSWarner Losh     return luaL_error(L, "unable to generate a unique filename");
1728e3e3a7aSWarner Losh   lua_pushstring(L, buff);
1738e3e3a7aSWarner Losh   return 1;
1748e3e3a7aSWarner Losh }
1758e3e3a7aSWarner Losh 
1768e3e3a7aSWarner Losh 
1778e3e3a7aSWarner Losh static int os_getenv (lua_State *L) {
1788e3e3a7aSWarner Losh   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
1798e3e3a7aSWarner Losh   return 1;
1808e3e3a7aSWarner Losh }
1818e3e3a7aSWarner Losh 
1828e3e3a7aSWarner Losh 
1838e3e3a7aSWarner Losh static int os_clock (lua_State *L) {
1848e3e3a7aSWarner Losh   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
1858e3e3a7aSWarner Losh   return 1;
1868e3e3a7aSWarner Losh }
1878e3e3a7aSWarner Losh 
1888e3e3a7aSWarner Losh 
1898e3e3a7aSWarner Losh /*
1908e3e3a7aSWarner Losh ** {======================================================
1918e3e3a7aSWarner Losh ** Time/Date operations
1928e3e3a7aSWarner Losh ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
1938e3e3a7aSWarner Losh **   wday=%w+1, yday=%j, isdst=? }
1948e3e3a7aSWarner Losh ** =======================================================
1958e3e3a7aSWarner Losh */
1968e3e3a7aSWarner Losh 
1978e3e3a7aSWarner Losh static void setfield (lua_State *L, const char *key, int value) {
1988e3e3a7aSWarner Losh   lua_pushinteger(L, value);
1998e3e3a7aSWarner Losh   lua_setfield(L, -2, key);
2008e3e3a7aSWarner Losh }
2018e3e3a7aSWarner Losh 
2028e3e3a7aSWarner Losh static void setboolfield (lua_State *L, const char *key, int value) {
2038e3e3a7aSWarner Losh   if (value < 0)  /* undefined? */
2048e3e3a7aSWarner Losh     return;  /* does not set field */
2058e3e3a7aSWarner Losh   lua_pushboolean(L, value);
2068e3e3a7aSWarner Losh   lua_setfield(L, -2, key);
2078e3e3a7aSWarner Losh }
2088e3e3a7aSWarner Losh 
2098e3e3a7aSWarner Losh 
2108e3e3a7aSWarner Losh /*
2118e3e3a7aSWarner Losh ** Set all fields from structure 'tm' in the table on top of the stack
2128e3e3a7aSWarner Losh */
2138e3e3a7aSWarner Losh static void setallfields (lua_State *L, struct tm *stm) {
2148e3e3a7aSWarner Losh   setfield(L, "sec", stm->tm_sec);
2158e3e3a7aSWarner Losh   setfield(L, "min", stm->tm_min);
2168e3e3a7aSWarner Losh   setfield(L, "hour", stm->tm_hour);
2178e3e3a7aSWarner Losh   setfield(L, "day", stm->tm_mday);
2188e3e3a7aSWarner Losh   setfield(L, "month", stm->tm_mon + 1);
2198e3e3a7aSWarner Losh   setfield(L, "year", stm->tm_year + 1900);
2208e3e3a7aSWarner Losh   setfield(L, "wday", stm->tm_wday + 1);
2218e3e3a7aSWarner Losh   setfield(L, "yday", stm->tm_yday + 1);
2228e3e3a7aSWarner Losh   setboolfield(L, "isdst", stm->tm_isdst);
2238e3e3a7aSWarner Losh }
2248e3e3a7aSWarner Losh 
2258e3e3a7aSWarner Losh 
2268e3e3a7aSWarner Losh static int getboolfield (lua_State *L, const char *key) {
2278e3e3a7aSWarner Losh   int res;
2288e3e3a7aSWarner Losh   res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
2298e3e3a7aSWarner Losh   lua_pop(L, 1);
2308e3e3a7aSWarner Losh   return res;
2318e3e3a7aSWarner Losh }
2328e3e3a7aSWarner Losh 
2338e3e3a7aSWarner Losh 
2348e3e3a7aSWarner Losh /* maximum value for date fields (to avoid arithmetic overflows with 'int') */
2358e3e3a7aSWarner Losh #if !defined(L_MAXDATEFIELD)
2368e3e3a7aSWarner Losh #define L_MAXDATEFIELD	(INT_MAX / 2)
2378e3e3a7aSWarner Losh #endif
2388e3e3a7aSWarner Losh 
2398e3e3a7aSWarner Losh static int getfield (lua_State *L, const char *key, int d, int delta) {
2408e3e3a7aSWarner Losh   int isnum;
2418e3e3a7aSWarner Losh   int t = lua_getfield(L, -1, key);  /* get field and its type */
2428e3e3a7aSWarner Losh   lua_Integer res = lua_tointegerx(L, -1, &isnum);
2438e3e3a7aSWarner Losh   if (!isnum) {  /* field is not an integer? */
2448e3e3a7aSWarner Losh     if (t != LUA_TNIL)  /* some other value? */
2458e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' is not an integer", key);
2468e3e3a7aSWarner Losh     else if (d < 0)  /* absent field; no default? */
2478e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' missing in date table", key);
2488e3e3a7aSWarner Losh     res = d;
2498e3e3a7aSWarner Losh   }
2508e3e3a7aSWarner Losh   else {
2518e3e3a7aSWarner Losh     if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
2528e3e3a7aSWarner Losh       return luaL_error(L, "field '%s' is out-of-bound", key);
2538e3e3a7aSWarner Losh     res -= delta;
2548e3e3a7aSWarner Losh   }
2558e3e3a7aSWarner Losh   lua_pop(L, 1);
2568e3e3a7aSWarner Losh   return (int)res;
2578e3e3a7aSWarner Losh }
2588e3e3a7aSWarner Losh 
2598e3e3a7aSWarner Losh 
2608e3e3a7aSWarner Losh static const char *checkoption (lua_State *L, const char *conv,
2618e3e3a7aSWarner Losh                                 ptrdiff_t convlen, char *buff) {
2628e3e3a7aSWarner Losh   const char *option = LUA_STRFTIMEOPTIONS;
2638e3e3a7aSWarner Losh   int oplen = 1;  /* length of options being checked */
2648e3e3a7aSWarner Losh   for (; *option != '\0' && oplen <= convlen; option += oplen) {
2658e3e3a7aSWarner Losh     if (*option == '|')  /* next block? */
2668e3e3a7aSWarner Losh       oplen++;  /* will check options with next length (+1) */
2678e3e3a7aSWarner Losh     else if (memcmp(conv, option, oplen) == 0) {  /* match? */
2688e3e3a7aSWarner Losh       memcpy(buff, conv, oplen);  /* copy valid option to buffer */
2698e3e3a7aSWarner Losh       buff[oplen] = '\0';
2708e3e3a7aSWarner Losh       return conv + oplen;  /* return next item */
2718e3e3a7aSWarner Losh     }
2728e3e3a7aSWarner Losh   }
2738e3e3a7aSWarner Losh   luaL_argerror(L, 1,
2748e3e3a7aSWarner Losh     lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
2758e3e3a7aSWarner Losh   return conv;  /* to avoid warnings */
2768e3e3a7aSWarner Losh }
2778e3e3a7aSWarner Losh 
2788e3e3a7aSWarner Losh 
2798e3e3a7aSWarner Losh /* maximum size for an individual 'strftime' item */
2808e3e3a7aSWarner Losh #define SIZETIMEFMT	250
2818e3e3a7aSWarner Losh 
2828e3e3a7aSWarner Losh 
2838e3e3a7aSWarner Losh static int os_date (lua_State *L) {
2848e3e3a7aSWarner Losh   size_t slen;
2858e3e3a7aSWarner Losh   const char *s = luaL_optlstring(L, 1, "%c", &slen);
2868e3e3a7aSWarner Losh   time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
2878e3e3a7aSWarner Losh   const char *se = s + slen;  /* 's' end */
2888e3e3a7aSWarner Losh   struct tm tmr, *stm;
2898e3e3a7aSWarner Losh   if (*s == '!') {  /* UTC? */
2908e3e3a7aSWarner Losh     stm = l_gmtime(&t, &tmr);
2918e3e3a7aSWarner Losh     s++;  /* skip '!' */
2928e3e3a7aSWarner Losh   }
2938e3e3a7aSWarner Losh   else
2948e3e3a7aSWarner Losh     stm = l_localtime(&t, &tmr);
2958e3e3a7aSWarner Losh   if (stm == NULL)  /* invalid date? */
296*e112e9d2SKyle Evans     return luaL_error(L,
297*e112e9d2SKyle Evans                  "time result cannot be represented in this installation");
2988e3e3a7aSWarner Losh   if (strcmp(s, "*t") == 0) {
2998e3e3a7aSWarner Losh     lua_createtable(L, 0, 9);  /* 9 = number of fields */
3008e3e3a7aSWarner Losh     setallfields(L, stm);
3018e3e3a7aSWarner Losh   }
3028e3e3a7aSWarner Losh   else {
3038e3e3a7aSWarner Losh     char cc[4];  /* buffer for individual conversion specifiers */
3048e3e3a7aSWarner Losh     luaL_Buffer b;
3058e3e3a7aSWarner Losh     cc[0] = '%';
3068e3e3a7aSWarner Losh     luaL_buffinit(L, &b);
3078e3e3a7aSWarner Losh     while (s < se) {
3088e3e3a7aSWarner Losh       if (*s != '%')  /* not a conversion specifier? */
3098e3e3a7aSWarner Losh         luaL_addchar(&b, *s++);
3108e3e3a7aSWarner Losh       else {
3118e3e3a7aSWarner Losh         size_t reslen;
3128e3e3a7aSWarner Losh         char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
3138e3e3a7aSWarner Losh         s++;  /* skip '%' */
3148e3e3a7aSWarner Losh         s = checkoption(L, s, se - s, cc + 1);  /* copy specifier to 'cc' */
3158e3e3a7aSWarner Losh         reslen = strftime(buff, SIZETIMEFMT, cc, stm);
3168e3e3a7aSWarner Losh         luaL_addsize(&b, reslen);
3178e3e3a7aSWarner Losh       }
3188e3e3a7aSWarner Losh     }
3198e3e3a7aSWarner Losh     luaL_pushresult(&b);
3208e3e3a7aSWarner Losh   }
3218e3e3a7aSWarner Losh   return 1;
3228e3e3a7aSWarner Losh }
3238e3e3a7aSWarner Losh 
3248e3e3a7aSWarner Losh 
3258e3e3a7aSWarner Losh static int os_time (lua_State *L) {
3268e3e3a7aSWarner Losh   time_t t;
3278e3e3a7aSWarner Losh   if (lua_isnoneornil(L, 1))  /* called without args? */
3288e3e3a7aSWarner Losh     t = time(NULL);  /* get current time */
3298e3e3a7aSWarner Losh   else {
3308e3e3a7aSWarner Losh     struct tm ts;
3318e3e3a7aSWarner Losh     luaL_checktype(L, 1, LUA_TTABLE);
3328e3e3a7aSWarner Losh     lua_settop(L, 1);  /* make sure table is at the top */
3338e3e3a7aSWarner Losh     ts.tm_sec = getfield(L, "sec", 0, 0);
3348e3e3a7aSWarner Losh     ts.tm_min = getfield(L, "min", 0, 0);
3358e3e3a7aSWarner Losh     ts.tm_hour = getfield(L, "hour", 12, 0);
3368e3e3a7aSWarner Losh     ts.tm_mday = getfield(L, "day", -1, 0);
3378e3e3a7aSWarner Losh     ts.tm_mon = getfield(L, "month", -1, 1);
3388e3e3a7aSWarner Losh     ts.tm_year = getfield(L, "year", -1, 1900);
3398e3e3a7aSWarner Losh     ts.tm_isdst = getboolfield(L, "isdst");
3408e3e3a7aSWarner Losh     t = mktime(&ts);
3418e3e3a7aSWarner Losh     setallfields(L, &ts);  /* update fields with normalized values */
3428e3e3a7aSWarner Losh   }
3438e3e3a7aSWarner Losh   if (t != (time_t)(l_timet)t || t == (time_t)(-1))
344*e112e9d2SKyle Evans     return luaL_error(L,
345*e112e9d2SKyle Evans                   "time result cannot be represented in this installation");
3468e3e3a7aSWarner Losh   l_pushtime(L, t);
3478e3e3a7aSWarner Losh   return 1;
3488e3e3a7aSWarner Losh }
3498e3e3a7aSWarner Losh 
3508e3e3a7aSWarner Losh 
3518e3e3a7aSWarner Losh static int os_difftime (lua_State *L) {
3528e3e3a7aSWarner Losh   time_t t1 = l_checktime(L, 1);
3538e3e3a7aSWarner Losh   time_t t2 = l_checktime(L, 2);
3548e3e3a7aSWarner Losh   lua_pushnumber(L, (lua_Number)difftime(t1, t2));
3558e3e3a7aSWarner Losh   return 1;
3568e3e3a7aSWarner Losh }
3578e3e3a7aSWarner Losh 
3588e3e3a7aSWarner Losh /* }====================================================== */
3598e3e3a7aSWarner Losh 
3608e3e3a7aSWarner Losh 
3618e3e3a7aSWarner Losh static int os_setlocale (lua_State *L) {
3628e3e3a7aSWarner Losh   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
3638e3e3a7aSWarner Losh                       LC_NUMERIC, LC_TIME};
3648e3e3a7aSWarner Losh   static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
3658e3e3a7aSWarner Losh      "numeric", "time", NULL};
3668e3e3a7aSWarner Losh   const char *l = luaL_optstring(L, 1, NULL);
3678e3e3a7aSWarner Losh   int op = luaL_checkoption(L, 2, "all", catnames);
3688e3e3a7aSWarner Losh   lua_pushstring(L, setlocale(cat[op], l));
3698e3e3a7aSWarner Losh   return 1;
3708e3e3a7aSWarner Losh }
3718e3e3a7aSWarner Losh 
3728e3e3a7aSWarner Losh 
3738e3e3a7aSWarner Losh static int os_exit (lua_State *L) {
3748e3e3a7aSWarner Losh   int status;
3758e3e3a7aSWarner Losh   if (lua_isboolean(L, 1))
3768e3e3a7aSWarner Losh     status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
3778e3e3a7aSWarner Losh   else
3788e3e3a7aSWarner Losh     status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
3798e3e3a7aSWarner Losh   if (lua_toboolean(L, 2))
3808e3e3a7aSWarner Losh     lua_close(L);
3818e3e3a7aSWarner Losh   if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */
3828e3e3a7aSWarner Losh   return 0;
3838e3e3a7aSWarner Losh }
3848e3e3a7aSWarner Losh 
3858e3e3a7aSWarner Losh 
3868e3e3a7aSWarner Losh static const luaL_Reg syslib[] = {
3878e3e3a7aSWarner Losh   {"clock",     os_clock},
3888e3e3a7aSWarner Losh   {"date",      os_date},
3898e3e3a7aSWarner Losh   {"difftime",  os_difftime},
3908e3e3a7aSWarner Losh   {"execute",   os_execute},
3918e3e3a7aSWarner Losh   {"exit",      os_exit},
3928e3e3a7aSWarner Losh   {"getenv",    os_getenv},
3938e3e3a7aSWarner Losh   {"remove",    os_remove},
3948e3e3a7aSWarner Losh   {"rename",    os_rename},
3958e3e3a7aSWarner Losh   {"setlocale", os_setlocale},
3968e3e3a7aSWarner Losh   {"time",      os_time},
3978e3e3a7aSWarner Losh   {"tmpname",   os_tmpname},
3988e3e3a7aSWarner Losh   {NULL, NULL}
3998e3e3a7aSWarner Losh };
4008e3e3a7aSWarner Losh 
4018e3e3a7aSWarner Losh /* }====================================================== */
4028e3e3a7aSWarner Losh 
4038e3e3a7aSWarner Losh 
4048e3e3a7aSWarner Losh 
4058e3e3a7aSWarner Losh LUAMOD_API int luaopen_os (lua_State *L) {
4068e3e3a7aSWarner Losh   luaL_newlib(L, syslib);
4078e3e3a7aSWarner Losh   return 1;
4088e3e3a7aSWarner Losh }
4098e3e3a7aSWarner Losh 
410