diff options
Diffstat (limited to 'loslib.c')
-rw-r--r-- | loslib.c | 76 |
1 files changed, 48 insertions, 28 deletions
@@ -58,18 +58,20 @@ | |||
58 | ** =================================================================== | 58 | ** =================================================================== |
59 | */ | 59 | */ |
60 | 60 | ||
61 | #if !defined(l_time_t) /* { */ | ||
62 | /* | 61 | /* |
63 | ** type to represent time_t in Lua | 62 | ** type to represent time_t in Lua |
64 | */ | 63 | */ |
64 | #if !defined(LUA_NUMTIME) /* { */ | ||
65 | |||
65 | #define l_timet lua_Integer | 66 | #define l_timet lua_Integer |
66 | #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) | 67 | #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) |
68 | #define l_gettime(L,arg) luaL_checkinteger(L, arg) | ||
67 | 69 | ||
68 | static time_t l_checktime (lua_State *L, int arg) { | 70 | #else /* }{ */ |
69 | lua_Integer t = luaL_checkinteger(L, arg); | 71 | |
70 | luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); | 72 | #define l_timet lua_Number |
71 | return (time_t)t; | 73 | #define l_pushtime(L,t) lua_pushnumber(L,(lua_Number)(t)) |
72 | } | 74 | #define l_gettime(L,arg) luaL_checknumber(L, arg) |
73 | 75 | ||
74 | #endif /* } */ | 76 | #endif /* } */ |
75 | 77 | ||
@@ -193,11 +195,25 @@ static int os_clock (lua_State *L) { | |||
193 | ** ======================================================= | 195 | ** ======================================================= |
194 | */ | 196 | */ |
195 | 197 | ||
196 | static void setfield (lua_State *L, const char *key, int value) { | 198 | /* |
197 | lua_pushinteger(L, value); | 199 | ** About the overflow check: an overflow cannot occurr when time |
200 | ** is represented by a lua_Integer, because either lua_Integer is | ||
201 | ** large enough to represent all int fields or it is not large enough | ||
202 | ** to represent a time that cause a field to overflow. However, if | ||
203 | ** times are represented as doubles and lua_Integer is int, then the | ||
204 | ** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900 | ||
205 | ** to compute the year. | ||
206 | */ | ||
207 | static void setfield (lua_State *L, const char *key, int value, int delta) { | ||
208 | #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) | ||
209 | if (value > LUA_MAXINTEGER - delta) | ||
210 | luaL_error(L, "field '%s' is out-of-bound", key); | ||
211 | #endif | ||
212 | lua_pushinteger(L, (lua_Integer)value + delta); | ||
198 | lua_setfield(L, -2, key); | 213 | lua_setfield(L, -2, key); |
199 | } | 214 | } |
200 | 215 | ||
216 | |||
201 | static void setboolfield (lua_State *L, const char *key, int value) { | 217 | static void setboolfield (lua_State *L, const char *key, int value) { |
202 | if (value < 0) /* undefined? */ | 218 | if (value < 0) /* undefined? */ |
203 | return; /* does not set field */ | 219 | return; /* does not set field */ |
@@ -210,14 +226,14 @@ static void setboolfield (lua_State *L, const char *key, int value) { | |||
210 | ** Set all fields from structure 'tm' in the table on top of the stack | 226 | ** Set all fields from structure 'tm' in the table on top of the stack |
211 | */ | 227 | */ |
212 | static void setallfields (lua_State *L, struct tm *stm) { | 228 | static void setallfields (lua_State *L, struct tm *stm) { |
213 | setfield(L, "sec", stm->tm_sec); | 229 | setfield(L, "year", stm->tm_year, 1900); |
214 | setfield(L, "min", stm->tm_min); | 230 | setfield(L, "month", stm->tm_mon, 1); |
215 | setfield(L, "hour", stm->tm_hour); | 231 | setfield(L, "day", stm->tm_mday, 0); |
216 | setfield(L, "day", stm->tm_mday); | 232 | setfield(L, "hour", stm->tm_hour, 0); |
217 | setfield(L, "month", stm->tm_mon + 1); | 233 | setfield(L, "min", stm->tm_min, 0); |
218 | setfield(L, "year", stm->tm_year + 1900); | 234 | setfield(L, "sec", stm->tm_sec, 0); |
219 | setfield(L, "wday", stm->tm_wday + 1); | 235 | setfield(L, "yday", stm->tm_yday, 1); |
220 | setfield(L, "yday", stm->tm_yday + 1); | 236 | setfield(L, "wday", stm->tm_wday, 1); |
221 | setboolfield(L, "isdst", stm->tm_isdst); | 237 | setboolfield(L, "isdst", stm->tm_isdst); |
222 | } | 238 | } |
223 | 239 | ||
@@ -230,11 +246,6 @@ static int getboolfield (lua_State *L, const char *key) { | |||
230 | } | 246 | } |
231 | 247 | ||
232 | 248 | ||
233 | /* maximum value for date fields (to avoid arithmetic overflows with 'int') */ | ||
234 | #if !defined(L_MAXDATEFIELD) | ||
235 | #define L_MAXDATEFIELD (INT_MAX / 2) | ||
236 | #endif | ||
237 | |||
238 | static int getfield (lua_State *L, const char *key, int d, int delta) { | 249 | static int getfield (lua_State *L, const char *key, int d, int delta) { |
239 | int isnum; | 250 | int isnum; |
240 | int t = lua_getfield(L, -1, key); /* get field and its type */ | 251 | int t = lua_getfield(L, -1, key); /* get field and its type */ |
@@ -247,7 +258,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { | |||
247 | res = d; | 258 | res = d; |
248 | } | 259 | } |
249 | else { | 260 | else { |
250 | if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) | 261 | /* unsigned avoids overflow when lua_Integer has 32 bits */ |
262 | if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta | ||
263 | : (lua_Integer)INT_MIN + delta <= res)) | ||
251 | return luaL_error(L, "field '%s' is out-of-bound", key); | 264 | return luaL_error(L, "field '%s' is out-of-bound", key); |
252 | res -= delta; | 265 | res -= delta; |
253 | } | 266 | } |
@@ -275,6 +288,13 @@ static const char *checkoption (lua_State *L, const char *conv, | |||
275 | } | 288 | } |
276 | 289 | ||
277 | 290 | ||
291 | static time_t l_checktime (lua_State *L, int arg) { | ||
292 | l_timet t = l_gettime(L, arg); | ||
293 | luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); | ||
294 | return (time_t)t; | ||
295 | } | ||
296 | |||
297 | |||
278 | /* maximum size for an individual 'strftime' item */ | 298 | /* maximum size for an individual 'strftime' item */ |
279 | #define SIZETIMEFMT 250 | 299 | #define SIZETIMEFMT 250 |
280 | 300 | ||
@@ -293,7 +313,7 @@ static int os_date (lua_State *L) { | |||
293 | stm = l_localtime(&t, &tmr); | 313 | stm = l_localtime(&t, &tmr); |
294 | if (stm == NULL) /* invalid date? */ | 314 | if (stm == NULL) /* invalid date? */ |
295 | return luaL_error(L, | 315 | return luaL_error(L, |
296 | "time result cannot be represented in this installation"); | 316 | "date result cannot be represented in this installation"); |
297 | if (strcmp(s, "*t") == 0) { | 317 | if (strcmp(s, "*t") == 0) { |
298 | lua_createtable(L, 0, 9); /* 9 = number of fields */ | 318 | lua_createtable(L, 0, 9); /* 9 = number of fields */ |
299 | setallfields(L, stm); | 319 | setallfields(L, stm); |
@@ -329,12 +349,12 @@ static int os_time (lua_State *L) { | |||
329 | struct tm ts; | 349 | struct tm ts; |
330 | luaL_checktype(L, 1, LUA_TTABLE); | 350 | luaL_checktype(L, 1, LUA_TTABLE); |
331 | lua_settop(L, 1); /* make sure table is at the top */ | 351 | lua_settop(L, 1); /* make sure table is at the top */ |
332 | ts.tm_sec = getfield(L, "sec", 0, 0); | ||
333 | ts.tm_min = getfield(L, "min", 0, 0); | ||
334 | ts.tm_hour = getfield(L, "hour", 12, 0); | ||
335 | ts.tm_mday = getfield(L, "day", -1, 0); | ||
336 | ts.tm_mon = getfield(L, "month", -1, 1); | ||
337 | ts.tm_year = getfield(L, "year", -1, 1900); | 352 | ts.tm_year = getfield(L, "year", -1, 1900); |
353 | ts.tm_mon = getfield(L, "month", -1, 1); | ||
354 | ts.tm_mday = getfield(L, "day", -1, 0); | ||
355 | ts.tm_hour = getfield(L, "hour", 12, 0); | ||
356 | ts.tm_min = getfield(L, "min", 0, 0); | ||
357 | ts.tm_sec = getfield(L, "sec", 0, 0); | ||
338 | ts.tm_isdst = getboolfield(L, "isdst"); | 358 | ts.tm_isdst = getboolfield(L, "isdst"); |
339 | t = mktime(&ts); | 359 | t = mktime(&ts); |
340 | setallfields(L, &ts); /* update fields with normalized values */ | 360 | setallfields(L, &ts); /* update fields with normalized values */ |