3 ** Standard Operating System library
4 ** See Copyright Notice in lua.h
26 ** {==================================================================
27 ** List of valid conversion specifiers for the 'strftime' function;
28 ** options are grouped by length; group of length 2 start with '||'.
29 ** ===================================================================
31 #if !defined(LUA_STRFTIMEOPTIONS) /* { */
33 #if defined(LUA_USE_WINDOWS)
34 #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
35 "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
36 #elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
37 #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
38 #else /* C99 specification */
39 #define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
40 "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
44 /* }================================================================== */
48 ** {==================================================================
49 ** Configuration for time-related stuff
50 ** ===================================================================
54 ** type to represent time_t in Lua
56 #if !defined(LUA_NUMTIME) /* { */
58 #define l_timet lua_Integer
59 #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
60 #define l_gettime(L,arg) luaL_checkinteger(L, arg)
64 #define l_timet lua_Number
65 #define l_pushtime(L,t) lua_pushnumber(L,(lua_Number)(t))
66 #define l_gettime(L,arg) luaL_checknumber(L, arg)
71 #if !defined(l_gmtime) /* { */
73 ** By default, Lua uses gmtime/localtime, except when POSIX is available,
74 ** where it uses gmtime_r/localtime_r
77 #if defined(LUA_USE_POSIX) /* { */
79 #define l_gmtime(t,r) gmtime_r(t,r)
80 #define l_localtime(t,r) localtime_r(t,r)
84 /* ISO C definitions */
85 #define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
86 #define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
92 /* }================================================================== */
96 ** {==================================================================
97 ** Configuration for 'tmpnam':
98 ** By default, Lua uses tmpnam except when POSIX is available, where
100 ** ===================================================================
102 #if !defined(lua_tmpnam) /* { */
104 #if defined(LUA_USE_POSIX) /* { */
108 #define LUA_TMPNAMBUFSIZE 32
110 #if !defined(LUA_TMPNAMTEMPLATE)
111 #define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX"
114 #define lua_tmpnam(b,e) { \
115 strcpy(b, LUA_TMPNAMTEMPLATE); \
117 if (e != -1) close(e); \
122 /* ISO C definitions */
123 #define LUA_TMPNAMBUFSIZE L_tmpnam
124 #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
129 /* }================================================================== */
132 #if !defined(l_system)
133 #if defined(LUA_USE_IOS)
134 /* Despite claiming to be ISO C, iOS does not implement 'system'. */
135 #define l_system(cmd) ((cmd) == NULL ? 0 : -1)
137 #define l_system(cmd) system(cmd) /* default definition */
142 static int os_execute(lua_State
*L
) {
143 const char *cmd
= luaL_optstring(L
, 1, NULL
);
146 stat
= l_system(cmd
);
148 return luaL_execresult(L
, stat
);
150 lua_pushboolean(L
, stat
); /* true if there is a shell */
156 static int os_remove(lua_State
*L
) {
157 const char *filename
= luaL_checkstring(L
, 1);
159 return luaL_fileresult(L
, remove(filename
) == 0, filename
);
163 static int os_rename(lua_State
*L
) {
164 const char *fromname
= luaL_checkstring(L
, 1);
165 const char *toname
= luaL_checkstring(L
, 2);
167 return luaL_fileresult(L
, rename(fromname
, toname
) == 0, NULL
);
171 static int os_tmpname(lua_State
*L
) {
172 char buff
[LUA_TMPNAMBUFSIZE
];
174 lua_tmpnam(buff
, err
);
176 return luaL_error(L
, "unable to generate a unique filename");
177 lua_pushstring(L
, buff
);
182 static int os_getenv(lua_State
*L
) {
183 lua_pushstring(L
, getenv(luaL_checkstring(L
, 1))); /* if NULL push nil */
188 static int os_clock(lua_State
*L
) {
189 lua_pushnumber(L
, ((lua_Number
)clock()) / (lua_Number
)CLOCKS_PER_SEC
);
195 ** {======================================================
196 ** Time/Date operations
197 ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
198 ** wday=%w+1, yday=%j, isdst=? }
199 ** =======================================================
203 ** About the overflow check: an overflow cannot occur when time
204 ** is represented by a lua_Integer, because either lua_Integer is
205 ** large enough to represent all int fields or it is not large enough
206 ** to represent a time that cause a field to overflow. However, if
207 ** times are represented as doubles and lua_Integer is int, then the
208 ** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900
209 ** to compute the year.
211 static void setfield(lua_State
*L
, const char *key
, int value
, int delta
) {
212 #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
213 if (l_unlikely(value
> LUA_MAXINTEGER
- delta
))
214 luaL_error(L
, "field '%s' is out-of-bound", key
);
216 lua_pushinteger(L
, (lua_Integer
)value
+ delta
);
217 lua_setfield(L
, -2, key
);
221 static void setboolfield(lua_State
*L
, const char *key
, int value
) {
222 if (value
< 0) /* undefined? */
223 return; /* does not set field */
224 lua_pushboolean(L
, value
);
225 lua_setfield(L
, -2, key
);
230 ** Set all fields from structure 'tm' in the table on top of the stack
232 static void setallfields(lua_State
*L
, struct tm
*stm
) {
233 setfield(L
, "year", stm
->tm_year
, 1900);
234 setfield(L
, "month", stm
->tm_mon
, 1);
235 setfield(L
, "day", stm
->tm_mday
, 0);
236 setfield(L
, "hour", stm
->tm_hour
, 0);
237 setfield(L
, "min", stm
->tm_min
, 0);
238 setfield(L
, "sec", stm
->tm_sec
, 0);
239 setfield(L
, "yday", stm
->tm_yday
, 1);
240 setfield(L
, "wday", stm
->tm_wday
, 1);
241 setboolfield(L
, "isdst", stm
->tm_isdst
);
245 static int getboolfield(lua_State
*L
, const char *key
) {
247 res
= (lua_getfield(L
, -1, key
) == LUA_TNIL
) ? -1 : lua_toboolean(L
, -1);
253 static int getfield(lua_State
*L
, const char *key
, int d
, int delta
) {
255 int t
= lua_getfield(L
, -1, key
); /* get field and its type */
256 lua_Integer res
= lua_tointegerx(L
, -1, &isnum
);
257 if (!isnum
) { /* field is not an integer? */
258 if (l_unlikely(t
!= LUA_TNIL
)) /* some other value? */
259 return luaL_error(L
, "field '%s' is not an integer", key
);
260 else if (l_unlikely(d
< 0)) /* absent field; no default? */
261 return luaL_error(L
, "field '%s' missing in date table", key
);
264 if (!(res
>= 0 ? res
- delta
<= INT_MAX
: INT_MIN
+ delta
<= res
))
265 return luaL_error(L
, "field '%s' is out-of-bound", key
);
273 static const char *checkoption(lua_State
*L
, const char *conv
,
274 ptrdiff_t convlen
, char *buff
) {
275 const char *option
= LUA_STRFTIMEOPTIONS
;
276 int oplen
= 1; /* length of options being checked */
277 for (; *option
!= '\0' && oplen
<= convlen
; option
+= oplen
) {
278 if (*option
== '|') /* next block? */
279 oplen
++; /* will check options with next length (+1) */
280 else if (memcmp(conv
, option
, oplen
) == 0) { /* match? */
281 memcpy(buff
, conv
, oplen
); /* copy valid option to buffer */
283 return conv
+ oplen
; /* return next item */
287 lua_pushfstring(L
, "invalid conversion specifier '%%%s'", conv
));
288 return conv
; /* to avoid warnings */
292 static time_t l_checktime(lua_State
*L
, int arg
) {
293 l_timet t
= l_gettime(L
, arg
);
294 luaL_argcheck(L
, (time_t)t
== t
, arg
, "time out-of-bounds");
299 /* maximum size for an individual 'strftime' item */
300 #define SIZETIMEFMT 250
303 static int os_date(lua_State
*L
) {
305 const char *s
= luaL_optlstring(L
, 1, "%c", &slen
);
306 time_t t
= luaL_opt(L
, l_checktime
, 2, time(NULL
));
307 const char *se
= s
+ slen
; /* 's' end */
309 if (*s
== '!') { /* UTC? */
310 stm
= l_gmtime(&t
, &tmr
);
313 stm
= l_localtime(&t
, &tmr
);
314 if (stm
== NULL
) /* invalid date? */
316 "date result cannot be represented in this installation");
317 if (strcmp(s
, "*t") == 0) {
318 lua_createtable(L
, 0, 9); /* 9 = number of fields */
319 setallfields(L
, stm
);
321 char cc
[4]; /* buffer for individual conversion specifiers */
324 luaL_buffinit(L
, &b
);
326 if (*s
!= '%') /* not a conversion specifier? */
327 luaL_addchar(&b
, *s
++);
330 char *buff
= luaL_prepbuffsize(&b
, SIZETIMEFMT
);
332 s
= checkoption(L
, s
, se
- s
, cc
+ 1); /* copy specifier to 'cc' */
333 reslen
= strftime(buff
, SIZETIMEFMT
, cc
, stm
);
334 luaL_addsize(&b
, reslen
);
343 static int os_time(lua_State
*L
) {
345 if (lua_isnoneornil(L
, 1)) /* called without args? */
346 t
= time(NULL
); /* get current time */
349 luaL_checktype(L
, 1, LUA_TTABLE
);
350 lua_settop(L
, 1); /* make sure table is at the top */
351 ts
.tm_year
= getfield(L
, "year", -1, 1900);
352 ts
.tm_mon
= getfield(L
, "month", -1, 1);
353 ts
.tm_mday
= getfield(L
, "day", -1, 0);
354 ts
.tm_hour
= getfield(L
, "hour", 12, 0);
355 ts
.tm_min
= getfield(L
, "min", 0, 0);
356 ts
.tm_sec
= getfield(L
, "sec", 0, 0);
357 ts
.tm_isdst
= getboolfield(L
, "isdst");
359 setallfields(L
, &ts
); /* update fields with normalized values */
361 if (t
!= (time_t)(l_timet
)t
|| t
== (time_t)(-1))
363 "time result cannot be represented in this installation");
369 static int os_difftime(lua_State
*L
) {
370 time_t t1
= l_checktime(L
, 1);
371 time_t t2
= l_checktime(L
, 2);
372 lua_pushnumber(L
, (lua_Number
)difftime(t1
, t2
));
376 /* }====================================================== */
379 static int os_setlocale(lua_State
*L
) {
380 static const int cat
[] = {LC_ALL
, LC_COLLATE
, LC_CTYPE
, LC_MONETARY
,
383 static const char *const catnames
[] = {"all", "collate", "ctype", "monetary",
384 "numeric", "time", NULL
386 const char *l
= luaL_optstring(L
, 1, NULL
);
387 int op
= luaL_checkoption(L
, 2, "all", catnames
);
388 lua_pushstring(L
, setlocale(cat
[op
], l
));
393 static int os_exit(lua_State
*L
) {
395 if (lua_isboolean(L
, 1))
396 status
= (lua_toboolean(L
, 1) ? EXIT_SUCCESS
: EXIT_FAILURE
);
398 status
= (int)luaL_optinteger(L
, 1, EXIT_SUCCESS
);
399 if (lua_toboolean(L
, 2))
401 if (L
) exit(status
); /* 'if' to avoid warnings for unreachable 'return' */
406 static const luaL_Reg syslib
[] = {
409 {"difftime", os_difftime
},
410 {"execute", os_execute
},
412 {"getenv", os_getenv
},
413 {"remove", os_remove
},
414 {"rename", os_rename
},
415 {"setlocale", os_setlocale
},
417 {"tmpname", os_tmpname
},
421 /* }====================================================== */
425 LUAMOD_API
int luaopen_os(lua_State
*L
) {
426 luaL_newlib(L
, syslib
);