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 :
|