LCOV - code coverage report
Current view: top level - src - loslib.c Coverage Total Hit
Test: Lua 5.3.6 Lines: 95.1 % 143 136
Test Date: 2024-04-28 10:23:15
Legend: Lines: hit not hit

            Line data    Source code
       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            6 : static time_t l_checktime (lua_State *L, int arg) {
      70            6 :   lua_Integer t = luaL_checkinteger(L, arg);
      71              :   luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
      72            6 :   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            8 : static int os_execute (lua_State *L) {
     142            8 :   const char *cmd = luaL_optstring(L, 1, NULL);
     143            8 :   int stat = system(cmd);
     144            8 :   if (cmd != NULL)
     145            7 :     return luaL_execresult(L, stat);
     146              :   else {
     147            1 :     lua_pushboolean(L, stat);  /* true if there is a shell */
     148            1 :     return 1;
     149              :   }
     150              : }
     151              : 
     152              : 
     153           32 : static int os_remove (lua_State *L) {
     154           32 :   const char *filename = luaL_checkstring(L, 1);
     155           32 :   return luaL_fileresult(L, remove(filename) == 0, filename);
     156              : }
     157              : 
     158              : 
     159            2 : static int os_rename (lua_State *L) {
     160            2 :   const char *fromname = luaL_checkstring(L, 1);
     161            2 :   const char *toname = luaL_checkstring(L, 2);
     162            2 :   return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
     163              : }
     164              : 
     165              : 
     166            2 : static int os_tmpname (lua_State *L) {
     167              :   char buff[LUA_TMPNAMBUFSIZE];
     168              :   int err;
     169            2 :   lua_tmpnam(buff, err);
     170            2 :   if (err)
     171            0 :     return luaL_error(L, "unable to generate a unique filename");
     172            2 :   lua_pushstring(L, buff);
     173            2 :   return 1;
     174              : }
     175              : 
     176              : 
     177            2 : static int os_getenv (lua_State *L) {
     178            2 :   lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
     179            2 :   return 1;
     180              : }
     181              : 
     182              : 
     183            2 : static int os_clock (lua_State *L) {
     184            2 :   lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
     185            2 :   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           16 : static void setfield (lua_State *L, const char *key, int value) {
     198           16 :   lua_pushinteger(L, value);
     199           16 :   lua_setfield(L, -2, key);
     200           16 : }
     201              : 
     202            2 : static void setboolfield (lua_State *L, const char *key, int value) {
     203            2 :   if (value < 0)  /* undefined? */
     204            0 :     return;  /* does not set field */
     205            2 :   lua_pushboolean(L, value);
     206            2 :   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            2 : static void setallfields (lua_State *L, struct tm *stm) {
     214            2 :   setfield(L, "sec", stm->tm_sec);
     215            2 :   setfield(L, "min", stm->tm_min);
     216            2 :   setfield(L, "hour", stm->tm_hour);
     217            2 :   setfield(L, "day", stm->tm_mday);
     218            2 :   setfield(L, "month", stm->tm_mon + 1);
     219            2 :   setfield(L, "year", stm->tm_year + 1900);
     220            2 :   setfield(L, "wday", stm->tm_wday + 1);
     221            2 :   setfield(L, "yday", stm->tm_yday + 1);
     222            2 :   setboolfield(L, "isdst", stm->tm_isdst);
     223            2 : }
     224              : 
     225              : 
     226            1 : static int getboolfield (lua_State *L, const char *key) {
     227              :   int res;
     228            1 :   res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
     229            1 :   lua_pop(L, 1);
     230            1 :   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           18 : static int getfield (lua_State *L, const char *key, int d, int delta) {
     240              :   int isnum;
     241           18 :   int t = lua_getfield(L, -1, key);  /* get field and its type */
     242           18 :   lua_Integer res = lua_tointegerx(L, -1, &isnum);
     243           18 :   if (!isnum) {  /* field is not an integer? */
     244           12 :     if (t != LUA_TNIL)  /* some other value? */
     245            2 :       return luaL_error(L, "field '%s' is not an integer", key);
     246           10 :     else if (d < 0)  /* absent field; no default? */
     247            1 :       return luaL_error(L, "field '%s' missing in date table", key);
     248            9 :     res = d;
     249              :   }
     250              :   else {
     251            6 :     if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
     252            0 :       return luaL_error(L, "field '%s' is out-of-bound", key);
     253            6 :     res -= delta;
     254              :   }
     255           15 :   lua_pop(L, 1);
     256           15 :   return (int)res;
     257              : }
     258              : 
     259              : 
     260           11 : static const char *checkoption (lua_State *L, const char *conv,
     261              :                                 ptrdiff_t convlen, char *buff) {
     262           11 :   const char *option = LUA_STRFTIMEOPTIONS;
     263           11 :   int oplen = 1;  /* length of options being checked */
     264          282 :   for (; *option != '\0' && oplen <= convlen; option += oplen) {
     265          281 :     if (*option == '|')  /* next block? */
     266            2 :       oplen++;  /* will check options with next length (+1) */
     267          279 :     else if (memcmp(conv, option, oplen) == 0) {  /* match? */
     268           10 :       memcpy(buff, conv, oplen);  /* copy valid option to buffer */
     269           10 :       buff[oplen] = '\0';
     270           10 :       return conv + oplen;  /* return next item */
     271              :     }
     272              :   }
     273            1 :   luaL_argerror(L, 1,
     274              :     lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
     275            0 :   return conv;  /* to avoid warnings */
     276              : }
     277              : 
     278              : 
     279              : /* maximum size for an individual 'strftime' item */
     280              : #define SIZETIMEFMT     250
     281              : 
     282              : 
     283            5 : static int os_date (lua_State *L) {
     284              :   size_t slen;
     285            5 :   const char *s = luaL_optlstring(L, 1, "%c", &slen);
     286            5 :   time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
     287            5 :   const char *se = s + slen;  /* 's' end */
     288              :   struct tm tmr, *stm;
     289            5 :   if (*s == '!') {  /* UTC? */
     290            2 :     stm = l_gmtime(&t, &tmr);
     291            2 :     s++;  /* skip '!' */
     292              :   }
     293              :   else
     294            3 :     stm = l_localtime(&t, &tmr);
     295            5 :   if (stm == NULL)  /* invalid date? */
     296            0 :     return luaL_error(L,
     297              :                  "time result cannot be represented in this installation");
     298            5 :   if (strcmp(s, "*t") == 0) {
     299            1 :     lua_createtable(L, 0, 9);  /* 9 = number of fields */
     300            1 :     setallfields(L, stm);
     301              :   }
     302              :   else {
     303              :     char cc[4];  /* buffer for individual conversion specifiers */
     304              :     luaL_Buffer b;
     305            4 :     cc[0] = '%';
     306            4 :     luaL_buffinit(L, &b);
     307           21 :     while (s < se) {
     308           18 :       if (*s != '%')  /* not a conversion specifier? */
     309            7 :         luaL_addchar(&b, *s++);
     310              :       else {
     311              :         size_t reslen;
     312           11 :         char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
     313           11 :         s++;  /* skip '%' */
     314           11 :         s = checkoption(L, s, se - s, cc + 1);  /* copy specifier to 'cc' */
     315           10 :         reslen = strftime(buff, SIZETIMEFMT, cc, stm);
     316           10 :         luaL_addsize(&b, reslen);
     317              :       }
     318              :     }
     319            3 :     luaL_pushresult(&b);
     320              :   }
     321            4 :   return 1;
     322              : }
     323              : 
     324              : 
     325            6 : static int os_time (lua_State *L) {
     326              :   time_t t;
     327            6 :   if (lua_isnoneornil(L, 1))  /* called without args? */
     328            2 :     t = time(NULL);  /* get current time */
     329              :   else {
     330              :     struct tm ts;
     331            4 :     luaL_checktype(L, 1, LUA_TTABLE);
     332            4 :     lua_settop(L, 1);  /* make sure table is at the top */
     333            4 :     ts.tm_sec = getfield(L, "sec", 0, 0);
     334            4 :     ts.tm_min = getfield(L, "min", 0, 0);
     335            4 :     ts.tm_hour = getfield(L, "hour", 12, 0);
     336            4 :     ts.tm_mday = getfield(L, "day", -1, 0);
     337            1 :     ts.tm_mon = getfield(L, "month", -1, 1);
     338            1 :     ts.tm_year = getfield(L, "year", -1, 1900);
     339            1 :     ts.tm_isdst = getboolfield(L, "isdst");
     340            1 :     t = mktime(&ts);
     341            1 :     setallfields(L, &ts);  /* update fields with normalized values */
     342              :   }
     343            3 :   if (t != (time_t)(l_timet)t || t == (time_t)(-1))
     344            0 :     return luaL_error(L,
     345              :                   "time result cannot be represented in this installation");
     346            3 :   l_pushtime(L, t);
     347            3 :   return 1;
     348              : }
     349              : 
     350              : 
     351            1 : static int os_difftime (lua_State *L) {
     352            1 :   time_t t1 = l_checktime(L, 1);
     353            1 :   time_t t2 = l_checktime(L, 2);
     354            1 :   lua_pushnumber(L, (lua_Number)difftime(t1, t2));
     355            1 :   return 1;
     356              : }
     357              : 
     358              : /* }====================================================== */
     359              : 
     360              : 
     361            3 : 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            3 :   const char *l = luaL_optstring(L, 1, NULL);
     367            3 :   int op = luaL_checkoption(L, 2, "all", catnames);
     368            3 :   lua_pushstring(L, setlocale(cat[op], l));
     369            3 :   return 1;
     370              : }
     371              : 
     372              : 
     373           10 : static int os_exit (lua_State *L) {
     374              :   int status;
     375           10 :   if (lua_isboolean(L, 1))
     376            2 :     status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
     377              :   else
     378            8 :     status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
     379           10 :   if (lua_toboolean(L, 2))
     380            1 :     lua_close(L);
     381           10 :   if (L) exit(status);  /* 'if' to avoid warnings for unreachable 'return' */
     382            0 :   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           86 : LUAMOD_API int luaopen_os (lua_State *L) {
     406           86 :   luaL_newlib(L, syslib);
     407           86 :   return 1;
     408              : }
     409              : 
        

Generated by: LCOV version 2.0-1