?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2. ** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $
  3. ** Standard Operating System library
  4. ** See Copyright Notice in lua.h
  5. */
  6.  
  7. #define loslib_c
  8. #define LUA_LIB
  9.  
  10. #include "lprefix.h"
  11.  
  12.  
  13. #include <errno.h>
  14. #include <locale.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <time.h>
  18.  
  19. #include "lua.h"
  20.  
  21. #include "lauxlib.h"
  22. #include "lualib.h"
  23.  
  24.  
  25. /*
  26. ** {==================================================================
  27. ** List of valid conversion specifiers for the 'strftime' function;
  28. ** options are grouped by length; group of length 2 start with '||'.
  29. ** ===================================================================
  30. */
  31. #if !defined(LUA_STRFTIMEOPTIONS)       /* { */
  32.  
  33. /* options for ANSI C 89 (only 1-char options) */
  34. #define L_STRFTIMEC89           "aAbBcdHIjmMpSUwWxXyYZ%"
  35.  
  36. /* options for ISO C 99 and POSIX */
  37. #define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
  38.     "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"  /* two-char options */
  39.  
  40. /* options for Windows */
  41. #define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
  42.     "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"  /* two-char options */
  43.  
  44. #if defined(LUA_USE_WINDOWS)
  45. #define LUA_STRFTIMEOPTIONS     L_STRFTIMEWIN
  46. #elif defined(LUA_USE_C89)
  47. #define LUA_STRFTIMEOPTIONS     L_STRFTIMEC89
  48. #else  /* C99 specification */
  49. #define LUA_STRFTIMEOPTIONS     L_STRFTIMEC99
  50. #endif
  51.  
  52. #endif                                  /* } */
  53. /* }================================================================== */
  54.  
  55.  
  56. /*
  57. ** {==================================================================
  58. ** Configuration for time-related stuff
  59. ** ===================================================================
  60. */
  61.  
  62. #if !defined(l_time_t)          /* { */
  63. /*
  64. ** type to represent time_t in Lua
  65. */
  66. #define l_timet                 lua_Integer
  67. #define l_pushtime(L,t)         lua_pushinteger(L,(lua_Integer)(t))
  68.  
  69. static time_t l_checktime (lua_State *L, int arg) {
  70.   lua_Integer t = luaL_checkinteger(L, arg);
  71.   luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
  72.   return (time_t)t;
  73. }
  74.  
  75. #endif                          /* } */
  76.  
  77.  
  78. #if !defined(l_gmtime)          /* { */
  79. /*
  80. ** By default, Lua uses gmtime/localtime, except when POSIX is available,
  81. ** where it uses gmtime_r/localtime_r
  82. */
  83.  
  84. #if defined(LUA_USE_POSIX)      /* { */
  85.  
  86. #define l_gmtime(t,r)           gmtime_r(t,r)
  87. #define l_localtime(t,r)        localtime_r(t,r)
  88.  
  89. #else                           /* }{ */
  90.  
  91. /* ISO C definitions */
  92. #define l_gmtime(t,r)           ((void)(r)->tm_sec, gmtime(t))
  93. #define l_localtime(t,r)        ((void)(r)->tm_sec, localtime(t))
  94.  
  95. #endif                          /* } */
  96.  
  97. #endif                          /* } */
  98.  
  99. /* }================================================================== */
  100.  
  101.  
  102. /*
  103. ** {==================================================================
  104. ** Configuration for 'tmpnam':
  105. ** By default, Lua uses tmpnam except when POSIX is available, where
  106. ** it uses mkstemp.
  107. ** ===================================================================
  108. */
  109. #if !defined(lua_tmpnam)        /* { */
  110.  
  111. #if defined(LUA_USE_POSIX)      /* { */
  112.  
  113. #include <unistd.h>
  114.  
  115. #define LUA_TMPNAMBUFSIZE       32
  116.  
  117. #if !defined(LUA_TMPNAMTEMPLATE)
  118. #define LUA_TMPNAMTEMPLATE      "/tmp/lua_XXXXXX"
  119. #endif
  120.  
  121. #define lua_tmpnam(b,e) { \
  122.         strcpy(b, LUA_TMPNAMTEMPLATE); \
  123.         e = mkstemp(b); \
  124.         if (e != -1) close(e); \
  125.         e = (e == -1); }
  126.  
  127. #else                           /* }{ */
  128.  
  129. /* ISO C definitions */
  130. #define LUA_TMPNAMBUFSIZE       L_tmpnam
  131. #define lua_tmpnam(b,e)         { e = (tmpnam(b) == NULL); }
  132.  
  133. #endif                          /* } */
  134.  
  135. #endif                          /* } */
  136. /* }================================================================== */
  137.  
  138.  
  139.  
  140.  
  141. static int os_execute (lua_State *L) {
  142.   const char *cmd = luaL_optstring(L, 1, NULL);
  143.   int stat = system(cmd);
  144.   if (cmd != NULL)
  145.     return luaL_execresult(L, stat);
  146.   else {
  147.     lua_pushboolean(L, stat);  /* true if there is a shell */
  148.     return 1;
  149.   }
  150. }
  151.  
  152.  
  153. static int os_remove (lua_State *L) {
  154.   const char *filename = luaL_checkstring(L, 1);
  155.   return luaL_fileresult(L, remove(filename) == 0, filename);
  156. }
  157.  
  158.  
  159. static int os_rename (lua_State *L) {
  160.   const char *fromname = luaL_checkstring(L, 1);
  161.   const char *toname = luaL_checkstring(L, 2);
  162.   return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
  163. }
  164.  
  165.  
  166. static int os_tmpname (lua_State *L) {
  167.   char buff[LUA_TMPNAMBUFSIZE];
  168.   int err;
  169.   lua_tmpnam(buff, err);
  170.   if (err)
  171.     return luaL_error(L, "unable to generate a unique filename");
  172.   lua_pushstring(L, buff);
  173.   return 1;
  174. }
  175.  
  176.  
  177. static int os_getenv (lua_State *L) {
  178.   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
  179.   return 1;
  180. }
  181.  
  182.  
  183. static int os_clock (lua_State *L) {
  184.   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
  185.   return 1;
  186. }
  187.  
  188.  
  189. /*
  190. ** {======================================================
  191. ** Time/Date operations
  192. ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
  193. **   wday=%w+1, yday=%j, isdst=? }
  194. ** =======================================================
  195. */
  196.  
  197. static void setfield (lua_State *L, const char *key, int value) {
  198.   lua_pushinteger(L, value);
  199.   lua_setfield(L, -2, key);
  200. }
  201.  
  202. static void setboolfield (lua_State *L, const char *key, int value) {
  203.   if (value < 0)  /* undefined? */
  204.     return;  /* does not set field */
  205.   lua_pushboolean(L, value);
  206.   lua_setfield(L, -2, key);
  207. }
  208.  
  209.  
  210. /*
  211. ** Set all fields from structure 'tm' in the table on top of the stack
  212. */
  213. static void setallfields (lua_State *L, struct tm *stm) {
  214.   setfield(L, "sec", stm->tm_sec);
  215.   setfield(L, "min", stm->tm_min);
  216.   setfield(L, "hour", stm->tm_hour);
  217.   setfield(L, "day", stm->tm_mday);
  218.   setfield(L, "month", stm->tm_mon + 1);
  219.   setfield(L, "year", stm->tm_year + 1900);
  220.   setfield(L, "wday", stm->tm_wday + 1);
  221.   setfield(L, "yday", stm->tm_yday + 1);
  222.   setboolfield(L, "isdst", stm->tm_isdst);
  223. }
  224.  
  225.  
  226. static int getboolfield (lua_State *L, const char *key) {
  227.   int res;
  228.   res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
  229.   lua_pop(L, 1);
  230.   return res;
  231. }
  232.  
  233.  
  234. /* maximum value for date fields (to avoid arithmetic overflows with 'int') */
  235. #if !defined(L_MAXDATEFIELD)
  236. #define L_MAXDATEFIELD  (INT_MAX / 2)
  237. #endif
  238.  
  239. static int getfield (lua_State *L, const char *key, int d, int delta) {
  240.   int isnum;
  241.   int t = lua_getfield(L, -1, key);  /* get field and its type */
  242.   lua_Integer res = lua_tointegerx(L, -1, &isnum);
  243.   if (!isnum) {  /* field is not an integer? */
  244.     if (t != LUA_TNIL)  /* some other value? */
  245.       return luaL_error(L, "field '%s' is not an integer", key);
  246.     else if (d < 0)  /* absent field; no default? */
  247.       return luaL_error(L, "field '%s' missing in date table", key);
  248.     res = d;
  249.   }
  250.   else {
  251.     if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
  252.       return luaL_error(L, "field '%s' is out-of-bound", key);
  253.     res -= delta;
  254.   }
  255.   lua_pop(L, 1);
  256.   return (int)res;
  257. }
  258.  
  259.  
  260. static const char *checkoption (lua_State *L, const char *conv,
  261.                                 ptrdiff_t convlen, char *buff) {
  262.   const char *option = LUA_STRFTIMEOPTIONS;
  263.   int oplen = 1;  /* length of options being checked */
  264.   for (; *option != '\0' && oplen <= convlen; option += oplen) {
  265.     if (*option == '|')  /* next block? */
  266.       oplen++;  /* will check options with next length (+1) */
  267.     else if (memcmp(conv, option, oplen) == 0) {  /* match? */
  268.       memcpy(buff, conv, oplen);  /* copy valid option to buffer */
  269.       buff[oplen] = '\0';
  270.       return conv + oplen;  /* return next item */
  271.     }
  272.   }
  273.   luaL_argerror(L, 1,
  274.     lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
  275.   return conv;  /* to avoid warnings */
  276. }
  277.  
  278.  
  279. /* maximum size for an individual 'strftime' item */
  280. #define SIZETIMEFMT     250
  281.  
  282.  
  283. static int os_date (lua_State *L) {
  284.   size_t slen;
  285.   const char *s = luaL_optlstring(L, 1, "%c", &slen);
  286.   time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
  287.   const char *se = s + slen;  /* 's' end */
  288.   struct tm tmr, *stm;
  289.   if (*s == '!') {  /* UTC? */
  290.     stm = l_gmtime(&t, &tmr);
  291.     s++;  /* skip '!' */
  292.   }
  293.   else
  294.     stm = l_localtime(&t, &tmr);
  295.   if (stm == NULL)  /* invalid date? */
  296.     return luaL_error(L,
  297.                  "time result cannot be represented in this installation");
  298.   if (strcmp(s, "*t") == 0) {
  299.     lua_createtable(L, 0, 9);  /* 9 = number of fields */
  300.     setallfields(L, stm);
  301.   }
  302.   else {
  303.     char cc[4];  /* buffer for individual conversion specifiers */
  304.     luaL_Buffer b;
  305.     cc[0] = '%';
  306.     luaL_buffinit(L, &b);
  307.     while (s < se) {
  308.       if (*s != '%')  /* not a conversion specifier? */
  309.         luaL_addchar(&b, *s++);
  310.       else {
  311.         size_t reslen;
  312.         char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
  313.         s++;  /* skip '%' */
  314.         s = checkoption(L, s, se - s, cc + 1);  /* copy specifier to 'cc' */
  315.         reslen = strftime(buff, SIZETIMEFMT, cc, stm);
  316.         luaL_addsize(&b, reslen);
  317.       }
  318.     }
  319.     luaL_pushresult(&b);
  320.   }
  321.   return 1;
  322. }
  323.  
  324.  
  325. static int os_time (lua_State *L) {
  326.   time_t t;
  327.   if (lua_isnoneornil(L, 1))  /* called without args? */
  328.     t = time(NULL);  /* get current time */
  329.   else {
  330.     struct tm ts;
  331.     luaL_checktype(L, 1, LUA_TTABLE);
  332.     lua_settop(L, 1);  /* make sure table is at the top */
  333.     ts.tm_sec = getfield(L, "sec", 0, 0);
  334.     ts.tm_min = getfield(L, "min", 0, 0);
  335.     ts.tm_hour = getfield(L, "hour", 12, 0);
  336.     ts.tm_mday = getfield(L, "day", -1, 0);
  337.     ts.tm_mon = getfield(L, "month", -1, 1);
  338.     ts.tm_year = getfield(L, "year", -1, 1900);
  339.     ts.tm_isdst = getboolfield(L, "isdst");
  340.     t = mktime(&ts);
  341.     setallfields(L, &ts);  /* update fields with normalized values */
  342.   }
  343.   if (t != (time_t)(l_timet)t || t == (time_t)(-1))
  344.     return luaL_error(L,
  345.                   "time result cannot be represented in this installation");
  346.   l_pushtime(L, t);
  347.   return 1;
  348. }
  349.  
  350.  
  351. static int os_difftime (lua_State *L) {
  352.   time_t t1 = l_checktime(L, 1);
  353.   time_t t2 = l_checktime(L, 2);
  354.   lua_pushnumber(L, (lua_Number)difftime(t1, t2));
  355.   return 1;
  356. }
  357.  
  358. /* }====================================================== */
  359.  
  360.  
  361. static int os_setlocale (lua_State *L) {
  362.   static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
  363.                       LC_NUMERIC, LC_TIME};
  364.   static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
  365.      "numeric", "time", NULL};
  366.   const char *l = luaL_optstring(L, 1, NULL);
  367.   int op = luaL_checkoption(L, 2, "all", catnames);
  368.   lua_pushstring(L, setlocale(cat[op], l));
  369.   return 1;
  370. }
  371.  
  372.  
  373. static int os_exit (lua_State *L) {
  374.   int status;
  375.   if (lua_isboolean(L, 1))
  376.     status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
  377.   else
  378.     status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
  379.   if (lua_toboolean(L, 2))
  380.     lua_close(L);
  381.   if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */
  382.   return 0;
  383. }
  384.  
  385.  
  386. static const luaL_Reg syslib[] = {
  387.   {"clock",     os_clock},
  388.   {"date",      os_date},
  389.   {"difftime",  os_difftime},
  390.   {"execute",   os_execute},
  391.   {"exit",      os_exit},
  392.   {"getenv",    os_getenv},
  393.   {"remove",    os_remove},
  394.   {"rename",    os_rename},
  395.   {"setlocale", os_setlocale},
  396.   {"time",      os_time},
  397.   {"tmpname",   os_tmpname},
  398.   {NULL, NULL}
  399. };
  400.  
  401. /* }====================================================== */
  402.  
  403.  
  404.  
  405. LUAMOD_API int luaopen_os (lua_State *L) {
  406.   luaL_newlib(L, syslib);
  407.   return 1;
  408. }
  409.  
  410.